/* "Spam Filter"-Plugin for Miranda IM Copyright 2003-2006 Heiko Herkenrath This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program ("SpamFilter-License.txt"); if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // -- Includes #include "common.h" // -- Variables: Events/Hooks HANDLE hEventPreRegisterMessageType = NULL; HANDLE hEventOkToSpamCheck = NULL; HANDLE hEventOkToSpamDetection = NULL; HANDLE hEventSpamReceived = NULL; HANDLE hEventModuleLoaded = NULL; HANDLE hEventContactSpammerStateChanged = NULL; // -- Variables: Services HANDLE* hServices[19] = {NULL}; // ----------------------------------------- // Service: MS_SPAMFILTER_GETHANDLE static int ServiceGetHandle(WPARAM wParam, LPARAM lParam) { switch ((UINT)wParam) { //case 1: return NULL; // hInstance was removed in v2.5.1.0 case SFHT_HWND_PLUGIN_OPTIONS: return IsWindow(hwndSpamFilterOpt) ? (int)hwndSpamFilterOpt : (int)NULL; case SFHT_HWND_ADVERTISMENT_FILTER: return IsWindow(hwndAdvertismentFilter) ? (int)hwndAdvertismentFilter : (int)NULL; case SFHT_HWND_ROBOT_FILTER: return IsWindow(hwndRobotFilter) ? (int)hwndRobotFilter : (int)NULL; case SFHT_HWND_DISLIKEDMESSAGES_FILTER: return IsWindow(hwndDislikedMessagesFilter) ? (int)hwndDislikedMessagesFilter : (int)NULL; case SFHT_HWND_SPAMDEFINITIONS_INFO: return IsWindow(hwndSpamDefinitionsInfo) ? (int)hwndSpamDefinitionsInfo : (int)NULL; case SFHT_HWND_SPAMMERS_INFO: return IsWindow(hwndSpammersInfo) ? (int)hwndSpammersInfo : (int)NULL; case SFHT_HICON_SPAM: return (int)LoadImage(hInstance, MAKEINTRESOURCE(IDI_DEFAULT), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0); case SFHT_HICON_SPAM_LARGE: return (int)LoadImage(hInstance, MAKEINTRESOURCE(IDI_DEFAULT_LARGE), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); case SFHT_HICON_SPAM_LAYER: return (int)LoadImage(hInstance, MAKEINTRESOURCE(IDI_SPAM_LAYER), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0); case 100: // backward compatibility #if defined(UNICODE) case SFHT_BOOL_IS_UNICODE: return TRUE; #else case SFHT_BOOL_IS_UNICODE: return FALSE; #endif default: return (int)NULL; } } // Service: MS_SPAMFILTER_SHOWERROR static int ServiceShowError(WPARAM wParam, LPARAM lParam) { switch ((UINT)wParam) { case SFSE_CRITICAL_ERROR: { ShowInfoMessage(NIIF_ERROR, TranslateW("Spam Filter Critical Error"), TranslateW("A very critical internal error was detected!\r\nProbably the filter will not work at all.\r\n\r\nPlease update to the most current version if this problem persists."), 0); return 0; } case SFSE_SEND_FAILED: { WCHAR* pszUserName; if (lParam && (((SPAMCHECKDATA*)lParam)->cbSize < sizeof(SPAMCHECKDATA))) return 1; pszUserName = lParam?SCD_GetContactCustomDisplayName((SPAMCHECKDATA*)lParam):NULL; ShowInfoMessage(NIIF_WARNING, TranslateW("Spam Filter Error"), TranslateW("Spam Filter was not able to send an automated message to the user \"%s\"."), pszUserName?lstrlen(pszUserName):0, pszUserName?pszUserName:_T("")); if (pszUserName) mir_free(pszUserName); return 0; } default: return 1; } } // Service: MS_SPAMFILTER_COPYSPAMCHECKDATA static int ServiceCopySpamCheckData(WPARAM wParam, LPARAM lParam) { SPAMCHECKDATA* to = (SPAMCHECKDATA*)wParam; SPAMCHECKDATA* from = (SPAMCHECKDATA*)lParam; if (!from || !to || (from && (from->cbSize < sizeof(SPAMCHECKDATA))) ) { if (to) to->cbSize = sizeof(SPAMCHECKDATA); return 1; } CopyMemory(to, from, from->cbSize); if (to->pszMsgTypeName) to->pszMsgTypeName = mir_strdup(to->pszMsgTypeName); if (to->pszMsgTypeSection) to->pszMsgTypeSection = mir_strdup(to->pszMsgTypeSection); if (to->pszMsgText) { if (to->dwFlags&SCDF_UNICODE) to->pszMsgText = mir_strdup(to->pszMsgText); else to->pwszMsgText = mir_wstrdup(to->pwszMsgText); } if ((to->dwFlags&SCDF_NO_CONTACT) && to->pszUserName) { if (to->dwFlags&SCDF_UNICODE) to->pszUserName = mir_strdup(to->pszUserName); else to->pwszUserName = mir_wstrdup(to->pwszUserName); } to->cbSize = sizeof(SPAMCHECKDATA); return 0; } // Service: MS_SPAMFILTER_FREESPAMCHECKDATA static int ServiceFreeSpamCheckData(WPARAM wParam, LPARAM lParam) { SPAMCHECKDATA* pscd = (SPAMCHECKDATA*)wParam; if (!pscd || (pscd->cbSize < sizeof(SPAMCHECKDATA))) return 1; if (pscd->pszMsgTypeName) mir_free(pscd->pszMsgTypeName); if (pscd->pszMsgTypeSection) mir_free(pscd->pszMsgTypeSection); if (pscd->ptszMsgText) mir_free(pscd->ptszMsgText); if ((pscd->dwFlags&SCDF_NO_CONTACT) && pscd->ptszUserName) mir_free(pscd->ptszUserName); return 0; } // Service: MS_SPAMFILTER_SHOWFILTERDIALOG static int ServiceShowFilterDialog(WPARAM wParam, LPARAM lParam) { HWND hwndParent = (HWND)wParam; DWORD dwFilterType = (DWORD)lParam; if (dwFilterType&SFTEXF_SPAMDEFINITIONS_INFO) { INITCOMMONCONTROLSEX icc; dwFilterType ^= SFTEXF_SPAMDEFINITIONS_INFO; if ((dwFilterType != SFT_ADVERTISMENT_FILTER) && (dwFilterType != SFT_DISLIKEDMESSAGES_FILTER)) return 1; if (IsWindow(hwndSpamDefinitionsInfo)) { PostMessage(hwndSpamDefinitionsInfo, SFM_REFRESH_SPAMDEFINITIONS, (WPARAM)FALSE, (LPARAM)dwFilterType); SetForegroundWindow(hwndSpamDefinitionsInfo); return 0; } // Ensure the needed common controls are loaded ZeroMemory(&icc, sizeof(icc)); icc.dwSize = sizeof(icc); icc.dwICC = ICC_TAB_CLASSES|ICC_LISTVIEW_CLASSES; InitCommonControlsEx(&icc); if (hwndParent) { // hwndSpamDefinitionsInfo will be set on WM_INITDIALOG and set to NULL on WM_DESTROY // *** using ANSI version here because Hyperlink control of Miranda doesn't support Unicode *** //return (DialogBoxParamA(hInstance, MAKEINTRESOURCEA(IDD_INFO_SPAMDEFINITIONS), hwndParent, DlgProcSpamDefinitionsInfo, dwFilterType)>0) ? 0 : 1; return (DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_INFO_SPAMDEFINITIONS), hwndParent, DlgProcSpamDefinitionsInfo, dwFilterType)>0) ? 0 : 1; } else { // *** using ANSI version here because Hyperlink control of Miranda doesn't (yet) support Unicode *** //hwndSpamDefinitionsInfo = CreateDialogParamA(hInstance, MAKEINTRESOURCEA(IDD_INFO_SPAMDEFINITIONS), (HWND)NULL, DlgProcSpamDefinitionsInfo, dwFilterType); hwndSpamDefinitionsInfo = CreateDialogParam(hInstance, MAKEINTRESOURCE(IDD_INFO_SPAMDEFINITIONS), (HWND)NULL, DlgProcSpamDefinitionsInfo, dwFilterType); return (hwndSpamDefinitionsInfo ? 0 : 1); } } else if (dwFilterType&SFTEXF_SPAMMERS_INFO) { dwFilterType ^= SFTEXF_SPAMMERS_INFO; if (dwFilterType != SFTEX_OPTIONS_PAGE) return 1; if (IsWindow(hwndSpammersInfo)) { SetForegroundWindow(hwndSpammersInfo); return 0; } if (hwndParent) { // hwndSpammersInfo will be set on WM_INITDIALOG and set to NULL on WM_DESTROY return (DialogBox(hInstance, MAKEINTRESOURCE(IDD_INFO_SPAMMERS), hwndParent, DlgProcSpammersInfo)>0) ? 0 : 1; } else { hwndSpammersInfo = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_INFO_SPAMMERS), (HWND)NULL, DlgProcSpammersInfo); return (hwndSpammersInfo ? 0 : 1); } } else { switch (dwFilterType) { case SFTEX_OPTIONS_PAGE: { OPENOPTIONSDIALOG ood; ZeroMemory(&ood, sizeof(ood)); ood.cbSize = sizeof(ood); ood.pszGroup = Translate("Events"); ood.pszPage = Translate("Spam Filter"); return CallService(MS_OPT_OPENOPTIONS, 0, (LPARAM)&ood); } case SFT_DISLIKEDMESSAGES_FILTER: { if (IsWindow(hwndDislikedMessagesFilter)) { SetForegroundWindow(hwndDislikedMessagesFilter); return 0; } if (hwndParent) { // hwndDislikedMessagesFilter will be set on WM_INITDIALOG and set to NULL on WM_DESTROY return (DialogBox(hInstance, MAKEINTRESOURCE(IDD_OPTIONS_CONFIGURE_DISLIKEDMESSAGEFILTER), hwndParent, DlgProcConfigureDislikedMessagesFilter)>0) ? 0 : 1; } else { hwndDislikedMessagesFilter = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_OPTIONS_CONFIGURE_DISLIKEDMESSAGEFILTER), (HWND)NULL, DlgProcConfigureDislikedMessagesFilter); return (hwndDislikedMessagesFilter ? 0 : 1); } } case SFT_ADVERTISMENT_FILTER: { INITCOMMONCONTROLSEX icc; if (IsWindow(hwndAdvertismentFilter)) { SetForegroundWindow(hwndAdvertismentFilter); return 0; } // Ensure the needed common controls are loaded ZeroMemory(&icc, sizeof(icc)); icc.dwSize = sizeof(icc); icc.dwICC = ICC_UPDOWN_CLASS; InitCommonControlsEx(&icc); if (hwndParent) { // hwndAdvertismentFilter will be set on WM_INITDIALOG and set to NULL on WM_DESTROY return (DialogBox(hInstance, MAKEINTRESOURCE(IDD_OPTIONS_CONFIGURE_ADVERTISMENTFILTER), hwndParent, DlgProcConfigureAdvertismentFilter)>0) ? 0 : 1; } else { hwndAdvertismentFilter = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_OPTIONS_CONFIGURE_ADVERTISMENTFILTER), (HWND)NULL, DlgProcConfigureAdvertismentFilter); return (hwndAdvertismentFilter ? 0 : 1); } } case SFT_ROBOT_FILTER: { if (IsWindow(hwndRobotFilter)) { SetForegroundWindow(hwndRobotFilter); return 0; } if (hwndParent) { // hwndRobotFilter will be set on WM_INITDIALOG and set to NULL on WM_DESTROY return (DialogBox(hInstance, MAKEINTRESOURCE(IDD_OPTIONS_CONFIGURE_ROBOTFILTER), hwndParent, DlgProcConfigureRobotFilter)>0) ? 0 : 1; } else { hwndRobotFilter = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_OPTIONS_CONFIGURE_ROBOTFILTER), (HWND)NULL, DlgProcConfigureRobotFilter); return (hwndRobotFilter ? 0 : 1); } } default: return 1; } } } // Service: MS_SPAMFILTER_RESETAUTOIGNORE static int EnumAutoIgnoreSettingsProc(const char* pszSetting, LPARAM lParam) { WCHAR* pszBuf; mir_utf8decode((char*)pszSetting,&pszBuf); if (pszBuf) { SLAddItem((STRINGLIST*)lParam, pszBuf); mir_free(pszBuf); } return 0; } static int ServiceResetAutoIgnore(WPARAM wParam, LPARAM lParam) { BOOL bOnlyCount = (BOOL)wParam; int iReturn; DBCONTACTENUMSETTINGS dbces; STRINGLIST* pslSettings = SLNewList(); int i; #if defined(UNICODE) char* pszBuf; #endif // Enum settings dbces.szModule = DB_MODULE_NAME_PRESPAMMERS; dbces.pfnEnumProc = EnumAutoIgnoreSettingsProc; dbces.lParam = (LPARAM)pslSettings; CallService(MS_DB_CONTACT_ENUMSETTINGS, (WPARAM)NULL, (LPARAM)&dbces); // Delete settings if (!bOnlyCount) { iReturn = 0; for (i=SL_MIN_POS; i<=SLGetMaxPos(pslSettings); i++) { #if defined(UNICODE) pszBuf = mir_utf8encodeW(SLGetItem(pslSettings, i)); if (pszBuf) { if (DBDeleteContactSetting(NULL, dbces.szModule, pszBuf) != 0) iReturn++; } #else if (DBDeleteContactSetting(NULL, dbces.szModule, SLGetItem(pslSettings, i)) != 0) iReturn++; #endif } } else { iReturn = SLGetItemCount(pslSettings); } // Free memory SLFreeList(pslSettings); return iReturn; } // Service: MS_SPAMFILTER_CONTACT_SETASSPAMMER static int ServiceContactSetAsSpammer(WPARAM wParam, LPARAM lParam) { HANDLE hContact = (HANDLE)wParam; DWORD dwFlags = (DWORD)lParam; if (!hContact || (hContact == INVALID_HANDLE_VALUE)) return 1; if (dwFlags & SCASF_NO_NOTIFY) { if (dwFlags & SCASF_USE_ROBOT_SOUND) SkinPlaySound(DB_SOUND_ROBOT_SETTING); else SkinPlaySound(DB_SOUND_ADVERTISMENT_SETTING); } // Add contact to spammer list AddContactToIgnoreList(hContact, !(dwFlags&SCASF_NO_REMOVE_HISTORY), !(dwFlags&SCASF_NO_DENY_AUTHREQUESTS), (dwFlags & SCASF_NO_NOTIFY)); // Remove pre-spammer flag if exists (now is real spammer) { SPAMCHECKDATA scd; ZeroMemory(&scd, sizeof(scd)); scd.cbSize = sizeof(scd); scd.hContact = hContact; RemovePreSpammerCount(&scd); } return 0; } // Service: MS_SPAMFILTER_CONTACT_SHOWSETASSPAMMERDIALOG static int ServiceContactShowSetAsSpammerDialog(WPARAM wParam, LPARAM lParam) { HANDLE hContact = (HANDLE)wParam; HWND hwndParent = (HWND)lParam; BOOL bDlgOK; WCHAR* pszFmt; WCHAR* pszUserName; MSGBOXPARAMS mbp; if (!hContact || (hContact == INVALID_HANDLE_VALUE)) return 1; // Correct wrong call (backward compatibility) if (hwndParent == INVALID_HANDLE_VALUE) hwndParent = NULL; ZeroMemory(&mbp, sizeof(mbp)); mbp.cbSize = sizeof(mbp); mbp.dwLanguageId = LANGIDFROMLCID(GetThreadLocale()); // Current system language: MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT); mbp.hwndOwner = hwndParent; mbp.hInstance = hInstance; mbp.lpszIcon = MAKEINTRESOURCE(IDI_DEFAULT_LARGE); mbp.dwStyle = MB_USERICON|MB_YESNO|MB_DEFBUTTON1|MB_SETFOREGROUND|MB_TASKMODAL; // MB_RTLREADING works also on non-arabic systems (Win 2000/XP) mbp.lpszCaption = TranslateW("Mark Contact as Spammer"); pszUserName = (WCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, (LPARAM)GCDNF_UNICODE); pszFmt = TranslateW("Are you sure that the contact \"%s\" shall be marked as spammer?\r\n\r\nMarking a contact as spammer means that all associated messages will be recognized as spam and the contact will be completely ignored in the future.\r\n\r\nA contact that was marked as spammer can be restored using the options dialog."); mbp.lpszText = (WCHAR*)mir_alloc((lstrlen(pszFmt)+(pszUserName?lstrlen(pszUserName):0)+1)*sizeof(WCHAR)); mir_sntprintf((WCHAR*)mbp.lpszText, (lstrlen(pszFmt) + (pszUserName?lstrlen(pszUserName):0) + 1), pszFmt, pszUserName?pszUserName:_T("")); bDlgOK = (MessageBoxIndirect(&mbp) == IDYES); if ((char*)mbp.lpszText) mir_free((char*)mbp.lpszText); if (bDlgOK) { BOOL bNoLog; BOOL bKeepHistory; // Get mark-read / delete setting bKeepHistory = ((DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_BEHAVIOUR, DEFAULT_SETTING_BEHAVIOUR) == 1) ? TRUE : FALSE); // Check id ctrl key is pressed to manually cancel logging if (GetAsyncKeyState(VK_CONTROL)&0x8000) bNoLog = FALSE; else bNoLog = TRUE; SkinPlaySound(DB_SOUND_ADVERTISMENT_SETTING); // Add contact to spammer list AddContactToIgnoreList(hContact, bKeepHistory, TRUE, bNoLog); // Remove pre-spammer flag (now is real spammer) { SPAMCHECKDATA scd; ZeroMemory(&scd, sizeof(scd)); scd.cbSize = sizeof(scd); scd.hContact = hContact; RemovePreSpammerCount(&scd); } } return (int)bDlgOK; } // Service: MS_SPAMFILTER_CONTACT_ISSPAMMER static int ServiceContactIsSpammer(WPARAM wParam, LPARAM lParam) { return (BYTE)(DBGetContactSettingByte((HANDLE)wParam, DB_MODULE_NAME, DB_SETTING_ISSPAMMER, (BYTE)FALSE)?TRUE:FALSE); } // Service: MS_SPAMFILTER_CONTACT_UNSETSPAMMER static int ServiceContactUnSetSpammer(WPARAM wParam, LPARAM lParam) { // Internal note: lParam is hwndParent when used as menu item service if ((HANDLE)wParam && ((HANDLE)wParam != INVALID_HANDLE_VALUE) ) return RemoveContactFromIgnoreList((HANDLE)wParam) ? 0 : 1; else return 1; } // Service: MS_SPAMFILTER_CHANGEFILTERACTIVATION static int ServiceChangeFilterActivation(WPARAM wParam, LPARAM lParam) { BOOL bNewStatus = (BOOL)lParam; DWORD dwFilterType = (DWORD)wParam; switch (dwFilterType) { case SFT_DISLIKEDMESSAGES_FILTER: { if (IsWindow(hwndSpamFilterOpt)) CheckDlgButton(hwndSpamFilterOpt, IDC_CHECKBOX_DISLIKEDMESSAGEFILTER, (bNewStatus ? BST_CHECKED : BST_UNCHECKED)); return DBWriteContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_DISLIKEDMESSAGEFILTER, (BYTE)bNewStatus); } case SFT_ADVERTISMENT_FILTER: { if (IsWindow(hwndSpamFilterOpt)) CheckDlgButton(hwndSpamFilterOpt, IDC_CHECKBOX_ADVERTISMENTFILTER, (bNewStatus ? BST_CHECKED : BST_UNCHECKED)); return DBWriteContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_ADVERTISMENTFILTER, (BYTE)bNewStatus); } case SFT_ROBOT_FILTER: { if (IsWindow(hwndSpamFilterOpt)) CheckDlgButton(hwndSpamFilterOpt, IDC_CHECKBOX_ROBOTFILTER, (bNewStatus ? BST_CHECKED : BST_UNCHECKED)); return DBWriteContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_ROBOTFILTER, (BYTE)bNewStatus); } default: return 1; } } // Service: MS_SPAMFILTER_GETSPAMCHECKINFO static int ServiceGetSpamCheckInfo(WPARAM wParam, LPARAM lParam) { DWORD dwInfoType = (DWORD)wParam; switch (dwInfoType) { case SFSCI_ACTIVATION_FILTER: { switch ((DWORD)lParam) { case SFT_DISLIKEDMESSAGES_FILTER: return (DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_DISLIKEDMESSAGEFILTER, DEFAULT_SETTING_DISLIKEDMESSAGEFILTER)?TRUE:FALSE); case SFT_ADVERTISMENT_FILTER: return (DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_ADVERTISMENTFILTER, DEFAULT_SETTING_ADVERTISMENTFILTER)?TRUE:FALSE); case SFT_ROBOT_FILTER: return (DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_ROBOTFILTER, DEFAULT_SETTING_ROBOTFILTER)?TRUE:FALSE); } break; } case SFSCI_ADD_TO_HISTORY: { switch ((DWORD)lParam) { // Disliked Messages Filter case SFSCI_MSGTEXT_NOTIFYA: case SFSCI_MSGTEXT_NOTIFYW: return (DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_DISLIKEDMESSAGE_ADDTOHISTORY, DEFAULT_SETTING_DISLIKEDMESSAGE_ADDTOHISTORY)?TRUE:FALSE); // Robot Filter case SFSCI_MSGTEXT_INSTRUCTIONA: case SFSCI_MSGTEXT_INSTRUCTIONW: return (DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_ROBOT_ADDTOHISTORY, DEFAULT_SETTING_ROBOT_ADDTOHISTORY)?TRUE:FALSE); case SFSCI_MSGTEXT_CONFIRMATIONA: case SFSCI_MSGTEXT_CONFIRMATIONW: return (DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_ROBOT_ADDTOHISTORY, DEFAULT_SETTING_ROBOT_ADDTOHISTORY)?TRUE:FALSE); } } case SFSCI_MSGTEXT_NOTIFYA: case SFSCI_MSGTEXT_INSTRUCTIONA: case SFSCI_MSGTEXT_CONFIRMATIONA: case SFSCI_MSGTEXT_NOTIFYW: case SFSCI_MSGTEXT_INSTRUCTIONW: case SFSCI_MSGTEXT_CONFIRMATIONW: { SPAMCHECKDATA* pscd = (SPAMCHECKDATA*)lParam; char* pszSetting; WCHAR* pszBuf; WCHAR* pReturn; DBVARIANT dbv; STRINGLIST* pslFromTo; if (!pscd || (pscd->cbSize < sizeof(SPAMCHECKDATA)) || !SCD_IsUserValid(pscd)) break; switch (dwInfoType) { // Disliked Messages Filter case SFSCI_MSGTEXT_NOTIFYA: case SFSCI_MSGTEXT_NOTIFYW: pszSetting = DB_SETTING_DISLIKEDMESSAGE_RETURNMESSAGE; // readonly allocated break; // Robot Filter case SFSCI_MSGTEXT_INSTRUCTIONA: case SFSCI_MSGTEXT_INSTRUCTIONW: pszSetting = DB_SETTING_ROBOT_INSTRUCTION; // readonly allocated break; case SFSCI_MSGTEXT_CONFIRMATIONA: case SFSCI_MSGTEXT_CONFIRMATIONW: pszSetting = DB_SETTING_ROBOT_CONFIRMATION; // readonly allocated break; default: pszSetting = NULL; } if (pszSetting) { WCHAR* pszVariablesOut = NULL; pslFromTo = SLNewList(); if ((dwInfoType != SFSCI_MSGTEXT_NOTIFYA) && (dwInfoType != SFSCI_MSGTEXT_NOTIFYW)) { // %securitycode% if (DBGetContactSettingTString(NULL, DB_MODULE_NAME, DB_SETTING_ROBOT_ANSWER, &dbv) == 0) { SLAddItemPair(pslFromTo, _T("%securitycode%"), dbv.ptszVal); DBFreeVariant(&dbv); } else { WCHAR szRnd[RANDOM_ANSWER_LENGTH+1]; GetRandomString(szRnd, ARRAYSIZE(szRnd)); DBWriteContactSettingTString(NULL, DB_MODULE_NAME, DB_SETTING_ROBOT_ANSWER, szRnd); SLAddItemPair(pslFromTo, _T("%securitycode%"), szRnd); } // %triesleft% if (DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_AUTOADDSPAMMERS, DEFAULT_SETTING_AUTOADDSPAMMERS)) { WCHAR szTriesLeft[MAX_INT_LENGTH+1]; mir_sntprintf(szTriesLeft, ARRAYSIZE(szTriesLeft), _T("%u"), DBGetContactSettingWord(NULL, DB_MODULE_NAME, DB_SETTING_ALLOWEDSPAMMESSAGES, DEFAULT_SETTING_ALLOWEDSPAMMESSAGES)-GetPreSpammerCount(pscd)+1); SLAddItemPair(pslFromTo, _T("%triesleft%"), szTriesLeft); } else { SLAddItemPair(pslFromTo, _T("%triesleft%"), TranslateW("unlimited")); } } // %message% #if defined(UNICODE) if (pscd->dwFlags&SCDF_UNICODE) pszBuf = pscd->ptszMsgText; else pszBuf = (WCHAR*)mir_utf8encodeW((WCHAR*)pscd->pszMsgText); SLAddItemPair(pslFromTo, _T("%message%"), pszBuf); if (pszBuf && !(pscd->dwFlags&SCDF_UNICODE)) mir_free(pszBuf); #else if (pscd->dwFlags&SCDF_UNICODE) pszBuf = UnicodeToAnsi(pscd->pwszMsgText); else pszBuf = pscd->ptszMsgText; SLAddItemPair(pslFromTo, _T("%message%"), pszBuf); if ((pscd->dwFlags&SCDF_UNICODE) && pszBuf) mir_free(pszBuf); #endif // %sender% pszBuf = SCD_GetContactName(pscd, FALSE); SLAddItemPair(pslFromTo, _T("%sender%"), pszBuf); if (pszBuf) mir_free(pszBuf); // Retrieve message text if (DBGetContactSettingTString(NULL, DB_MODULE_NAME, pszSetting, &dbv) == 0) { pszBuf = ReplaceSubStringWithStringMultiple(dbv.ptszVal, pslFromTo, TRUE, FALSE, NULL); DBFreeVariant(&dbv); } else { pszBuf = NULL; } // Retrieve message text if (DBGetContactSettingTString(NULL, DB_MODULE_NAME, pszSetting, &dbv) == 0) { pszBuf = ReplaceSubStringWithStringMultiple(dbv.ptszVal, pslFromTo, TRUE, FALSE, NULL); DBFreeVariant(&dbv); } else { pszBuf = NULL; } SLFreeList(pslFromTo); // Support for "Variables" plugin if (ServiceExists(MS_VARS_FORMATSTRING)) { FORMATINFO fi; ZeroMemory(&fi, sizeof(fi)); fi.cbSize = sizeof(fi); fi.flags = FIF_UNICODE; fi.tszFormat = pszBuf; fi.tszExtraText = pscd->ptszMsgText; // %message% variable is handled earlier by Spam Filter itself fi.hContact = (pscd->dwFlags&SCDF_NO_CONTACT)?NULL:pscd->hContact; pszVariablesOut = (WCHAR*)CallService(MS_VARS_FORMATSTRING, (WPARAM)&fi, 0); } // Convert return value pReturn = NULL; if (pszVariablesOut?pszVariablesOut:pszBuf) { switch (dwInfoType) { case SFSCI_MSGTEXT_NOTIFYA: case SFSCI_MSGTEXT_INSTRUCTIONA: case SFSCI_MSGTEXT_CONFIRMATIONA: { #if defined(UNICODE) // UnicodeToAnsi uses mir_alloc mir_utf8decode((char*)pszVariablesOut?(char*)pszVariablesOut:(char*)pszBuf,&pReturn); #else // AnsiDup uses mir_alloc pReturn = (PBYTE)mir_strdup(pszVariablesOut?pszVariablesOut:pszBuf); #endif break; } case SFSCI_MSGTEXT_NOTIFYW: case SFSCI_MSGTEXT_INSTRUCTIONW: case SFSCI_MSGTEXT_CONFIRMATIONW: { #if defined(UNICODE) // UnicodeDup uses mir_alloc pReturn = mir_wstrdup(pszVariablesOut?pszVariablesOut:pszBuf); #else // mir_utf8encodeW uses mir_alloc pReturn = (PBYTE)mir_utf8encodeW(pszVariablesOut?pszVariablesOut:pszBuf); #endif break; } } } if (pszBuf) SLFreeReturn(pszBuf); // Support for "Variables" plugin if (pszVariablesOut) CallService(MS_VARS_FREEMEMORY, (WPARAM)pszVariablesOut, 0); return (int)pReturn; } break; } } return 0; } // Service: MS_SPAMFILTER_REGISTERMESSAGETYPE static int ServiceRegisterMessageType(WPARAM wParam, LPARAM lParam) { MESSAGETYPEDESC* pmtdNew = (MESSAGETYPEDESC*)lParam; if (!pmtdNew->pszName || !pmtdNew->pszSection || (pmtdNew->cbSize < MESSAGETYPEDESC_V2000_SIZE)) return 1; // Do not add if already added EnterCriticalSection(&csMsgTypes); // thread safety if (GetMsgTypeID(pmtdNew->pszSection, pmtdNew->pszName) >= 0) { LeaveCriticalSection(&csMsgTypes); // thread safety return 1; } LeaveCriticalSection(&csMsgTypes); // thread safety // outside critical section: // Hand out event (asking other plugins if default data is ok) if (NotifyEventHooks(hEventPreRegisterMessageType, (WPARAM)wParam, (LPARAM)lParam) == 1) { OutputDebugString(_T("Spam Filter: Adding message type denied (by event).\r\n")); return 1; } // Do not add if already added (check again) EnterCriticalSection(&csMsgTypes); // thread safety if (GetMsgTypeID(pmtdNew->pszSection, pmtdNew->pszName) >= 0) { LeaveCriticalSection(&csMsgTypes); // thread safety return 1; } // Resize list array { MESSAGETYPEDESC* pamtdMsgTypesBuf; pamtdMsgTypesBuf = (MESSAGETYPEDESC*)mir_realloc(pamtdMsgTypes, (uMsgTypesCount+1)*sizeof(MESSAGETYPEDESC)); if (pamtdMsgTypesBuf) { pamtdMsgTypes = pamtdMsgTypesBuf; } else { // Fatal error: list was not reallocated, insufficient memory (old data still valid) LeaveCriticalSection(&csMsgTypes); // thread safety return 1; } } pamtdMsgTypes[uMsgTypesCount].cbSize = sizeof(MESSAGETYPEDESC); pamtdMsgTypes[uMsgTypesCount].dwFlags = pmtdNew->dwFlags; // Backward compatibility (struct extended in v2.1.1.0) if (pmtdNew->cbSize > MESSAGETYPEDESC_V2000_SIZE) { pamtdMsgTypes[uMsgTypesCount].iPosition = pmtdNew->iPosition; pamtdMsgTypes[uMsgTypesCount].iSectionPosition = pmtdNew->iSectionPosition; } else { pamtdMsgTypes[uMsgTypesCount].iPosition = 0; pamtdMsgTypes[uMsgTypesCount].iSectionPosition = pmtdNew->iSectionPosition; } pamtdMsgTypes[uMsgTypesCount].pszSection = mir_strdup(pmtdNew->pszSection); pamtdMsgTypes[uMsgTypesCount].pszName = mir_strdup(pmtdNew->pszName); #if defined(UNICODE) if (pmtdNew->dwFlags&MTDF_UNICODE) { pamtdMsgTypes[uMsgTypesCount].ptszSectionDescription = pmtdNew->pwszSectionDescription ? mir_wstrdup(pmtdNew->pwszSectionDescription) : (WCHAR*)mir_utf8encodeW((WCHAR*)Translate((WCHAR*)pmtdNew->pszSection)); pamtdMsgTypes[uMsgTypesCount].ptszDescription = pmtdNew->pwszDescription ? mir_wstrdup(pmtdNew->pwszDescription) : (WCHAR*)mir_utf8encodeW((WCHAR*)Translate((WCHAR*)pmtdNew->pszName)); } else { pamtdMsgTypes[uMsgTypesCount].dwFlags |= MTDF_UNICODE; pamtdMsgTypes[uMsgTypesCount].ptszSectionDescription = pmtdNew->pszSectionDescription ? (WCHAR*)mir_utf8encodeW((WCHAR*)pmtdNew->pszSectionDescription) : (WCHAR*)mir_utf8encodeW((WCHAR*)Translate((WCHAR*)pmtdNew->pszSection)); pamtdMsgTypes[uMsgTypesCount].ptszDescription = pmtdNew->pszDescription ? (WCHAR*)mir_utf8encodeW((WCHAR*)pmtdNew->pszDescription) : (WCHAR*)mir_utf8encodeW((WCHAR*)Translate((WCHAR*)pmtdNew->pszName)); } #else if (pmtdNew->dwFlags&MTDF_UNICODE) { pamtdMsgTypes[uMsgTypesCount].dwFlags ^= MTDF_UNICODE; pamtdMsgTypes[uMsgTypesCount].ptszSectionDescription = pmtdNew->pwszSectionDescription ? UnicodeToAnsi(pmtdNew->pwszSectionDescription) : mir_strdup(Translate(pmtdNew->pszSection)); pamtdMsgTypes[uMsgTypesCount].ptszDescription = pmtdNew->pwszDescription ? UnicodeToAnsi(pmtdNew->pwszDescription) : mir_strdup(Translate(pmtdNew->pszName)); } else { pamtdMsgTypes[uMsgTypesCount].ptszSectionDescription = pmtdNew->pszSectionDescription ? AnsiDup(pmtdNew->pszSectionDescription) : AnsiDup(Translate(pmtdNew->pszSection)); pamtdMsgTypes[uMsgTypesCount].ptszDescription = pmtdNew->pszDescription ? AnsiDup(pmtdNew->ptszDescription) : AnsiDup(Translate(pmtdNew->pszName)); } #endif // Fatal error (strings were not allocated, insufficient memory) if (!pamtdMsgTypes[uMsgTypesCount].pszSection || !pamtdMsgTypes[uMsgTypesCount].pszSectionDescription || !pamtdMsgTypes[uMsgTypesCount].pszName || !pamtdMsgTypes[uMsgTypesCount].pszDescription) { if (pamtdMsgTypes[uMsgTypesCount].pszSection) mir_free(pamtdMsgTypes[uMsgTypesCount].pszSection); if (pamtdMsgTypes[uMsgTypesCount].pszSectionDescription) mir_free(pamtdMsgTypes[uMsgTypesCount].pszSectionDescription); if (pamtdMsgTypes[uMsgTypesCount].pszName) mir_free(pamtdMsgTypes[uMsgTypesCount].pszName); if (pamtdMsgTypes[uMsgTypesCount].pszDescription) mir_free(pamtdMsgTypes[uMsgTypesCount].pszDescription); LeaveCriticalSection(&csMsgTypes); // thread safety return 1; } pamtdMsgTypes[uMsgTypesCount].hSectionIcon = pmtdNew->hSectionIcon ? (HICON)CopyImage(pmtdNew->hSectionIcon, IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_COPYFROMRESOURCE) : NULL; if ((int)pmtdNew->hIcon < 0) // if is miranda skinned icon constant pamtdMsgTypes[uMsgTypesCount].hIcon = pmtdNew->hIcon; else pamtdMsgTypes[uMsgTypesCount].hIcon = pmtdNew->hIcon ? (HICON)CopyImage(pmtdNew->hIcon, IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_COPYFROMRESOURCE) : NULL; uMsgTypesCount++; LeaveCriticalSection(&csMsgTypes); // thread safety // Refresh shown list if (IsWindow(hwndSpamFilterOpt)) SendMessage(hwndSpamFilterOpt, SFM_REBUILD_MSGTYPES, 0, 0); return 0; } // Service: MS_SPAMFILTER_REMOVEMESSAGETYPE static int ServiceRemoveMessageType(WPARAM wParam, LPARAM lParam) { char* pszMsgTypeSection = (char*)wParam; char* pszMsgTypeName = (char*)lParam; MESSAGETYPEDESC* pamtdMsgTypesBuf; int iReturn; char* pszSetting; unsigned int u; if (!pszMsgTypeName || !pszMsgTypeSection) return 1; iReturn = 1; EnterCriticalSection(&csMsgTypes); // thread safety // Remove array item if (pamtdMsgTypes) { for (u=0; u Item to remove found // Delete database setting pszSetting = GetMsgTypeSettingName(pamtdMsgTypes[u].pszSection, pamtdMsgTypes[u].pszName); if (pszSetting) { DBDeleteContactSetting(NULL, DB_MODULE_NAME_MSGTYPES, pszSetting); mir_free(pszSetting); } // Free array item memory if (pamtdMsgTypes[u].pszSection) mir_free(pamtdMsgTypes[u].pszSection); if (pamtdMsgTypes[u].pszName) mir_free(pamtdMsgTypes[u].pszName); if (pamtdMsgTypes[u].ptszSectionDescription) mir_free(pamtdMsgTypes[u].ptszSectionDescription); if (pamtdMsgTypes[u].ptszDescription) mir_free(pamtdMsgTypes[u].ptszDescription); if (pamtdMsgTypes[u].hIcon && ((int)pamtdMsgTypes[u].hIcon > 0)) DestroyIcon(pamtdMsgTypes[u].hIcon); if (pamtdMsgTypes[u].hSectionIcon) DestroyIcon(pamtdMsgTypes[u].hSectionIcon); // Move other array items (if not last item) if ((u+1) < uMsgTypesCount) MoveMemory(&pamtdMsgTypes[u], &pamtdMsgTypes[u+1], ((uMsgTypesCount-u-1)*sizeof(MESSAGETYPEDESC))); // Resize array pamtdMsgTypesBuf = (MESSAGETYPEDESC*)mir_realloc(pamtdMsgTypes, (uMsgTypesCount-1)*sizeof(MESSAGETYPEDESC)); if (pamtdMsgTypesBuf) pamtdMsgTypes = pamtdMsgTypesBuf; // Decrase list count uMsgTypesCount--; iReturn = 0; break; } } } } LeaveCriticalSection(&csMsgTypes); // thread safety // Refresh shown list if (IsWindow(hwndSpamFilterOpt)) SendMessage(hwndSpamFilterOpt, SFM_REBUILD_MSGTYPES, 0, 0); return iReturn; } // Service: MS_SPAMFILTER_ISMESSAGETYPEACTIVATED static int ServiceIsMessageTypeActivated(WPARAM wParam, LPARAM lParam) { int iMsgType; BOOL bReturn = FALSE; EnterCriticalSection(&csMsgTypes); // thread safety iMsgType = GetMsgTypeID((const char*)wParam, (const char*)lParam); if (iMsgType != -1) if (pamtdMsgTypes[iMsgType].dwFlags&MTDF_HIDDEN) { bReturn = !(pamtdMsgTypes[iMsgType].dwFlags&MTDF_DEFAULTDISABLED); } else { char* pszSetting = GetMsgTypeSettingName(pamtdMsgTypes[iMsgType].pszSection, pamtdMsgTypes[iMsgType].pszName); if (pszSetting) { bReturn = DBGetContactSettingByte(NULL, DB_MODULE_NAME_MSGTYPES, pszSetting, (BYTE)!(pamtdMsgTypes[iMsgType].dwFlags&MTDF_DEFAULTDISABLED)); mir_free(pszSetting); } } LeaveCriticalSection(&csMsgTypes); // thread safety return (int)bReturn; } // Service: MS_SPAMFILTER_ROBOTCHECK static int ServiceRobotCheck(WPARAM wParam, LPARAM lParam) // wParam = SPAMCHECKDATA, lParam = 0 { SPAMCHECKDATA* pscd = (SPAMCHECKDATA*)wParam; if (!pscd || !pscd->pszMsgTypeSection || !pscd->pszMsgTypeName || (pscd->cbSize < sizeof(SPAMCHECKDATA)) || !SCD_IsUserValid(pscd)) return SFF_ISNORMAL; // Check id ctrl key is pressed to manually cancel spam check if (!(pscd->dwFlags&SCDF_NO_CANCEL) && (GetAsyncKeyState(VK_CONTROL)&0x8000)) return SFF_ISNORMAL; if ( !CallService(MS_SPAMFILTER_ISMESSAGETYPEACTIVATED, (WPARAM)pscd->pszMsgTypeSection, (LPARAM)pscd->pszMsgTypeName) || !CallService(MS_SPAMFILTER_GETSPAMCHECKINFO, (WPARAM)SFSCI_ACTIVATION_FILTER, (LPARAM)SFT_ROBOT_FILTER) ) return SFF_ISNORMAL; if (NotifyEventHooks(hEventOkToSpamCheck, (WPARAM)pscd, (LPARAM)SFT_ROBOT_FILTER) == 1) { OutputDebugString(_T("Spam Filter: Spam check denied (by event).\r\n")); return SFF_ISNORMAL; } { WCHAR* pszNormalMsgText; WCHAR* pszClearedMsgText = NULL; DWORD dwReturn = SFF_ISNORMAL; // Buffer the msg content if (pscd->ptszMsgText) { #if defined(UNICODE) if (pscd->dwFlags&SCDF_UNICODE) pszNormalMsgText = pscd->ptszMsgText; else pszNormalMsgText = (WCHAR*)mir_utf8encodeW((WCHAR*)pscd->pszMsgText); #else if (pscd->dwFlags&SCDF_UNICODE) pszNormalMsgText = UnicodeToAnsi(pscd->pwszMsgText); else pszNormalMsgText = pscd->ptszMsgText; #endif } else { pszNormalMsgText = NULL; } pszClearedMsgText = mir_wstrdup(pszNormalMsgText); if (pszClearedMsgText) RemoveWhiteSpaces(pszClearedMsgText, FALSE, TRUE); else pszClearedMsgText = NULL; if (pszClearedMsgText) { DBVARIANT dbv; if (DBGetContactSettingTString(NULL, DB_MODULE_NAME, DB_SETTING_ROBOT_ANSWER, &dbv) == 0) { // If message contains correct answer RemoveWhiteSpaces(dbv.ptszVal, FALSE, TRUE); if ((StrCmp(pszClearedMsgText, dbv.ptszVal) == 0) || // or allow for quotes (below) (StrCmpN(&pszClearedMsgText[1], dbv.ptszVal, lstrlen(pszClearedMsgText)-2) == 0)) dwReturn |= SFF_SENDMSG_CONFIRMATION|SFF_TESTPASSED|(DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_ROBOT_ADDTOHISTORY, DEFAULT_SETTING_ROBOT_ADDTOHISTORY) ? SFF_MARKREAD : SFF_DELETE); DBFreeVariant(&dbv); } } if (pszClearedMsgText) mir_free(pszClearedMsgText); #if defined(UNICODE) if (!(pscd->dwFlags&SCDF_UNICODE)) if (pszNormalMsgText) mir_free(pszNormalMsgText); #else if ((pscd->dwFlags&SCDF_UNICODE)) if (pszNormalMsgText) mir_free(pszNormalMsgText); #endif // Kick out spam if ( (!(dwReturn&SFF_TESTPASSED)) && (NotifyEventHooks(hEventOkToSpamDetection, (WPARAM)pscd, (LPARAM)SFT_ROBOT_FILTER) == 0)) { dwReturn = SFF_ISSPAM|((DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_BEHAVIOUR, DEFAULT_SETTING_BEHAVIOUR) == 1) ? SFF_MARKREAD : SFF_DELETE); // Add user to ignore list if (!(pscd->dwFlags&SCDF_NO_AUTOIGNORE) && DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_AUTOADDSPAMMERS, DEFAULT_SETTING_AUTOADDSPAMMERS) ) { if (IncreasePreSpammerCount(pscd) > DBGetContactSettingWord(NULL, DB_MODULE_NAME, DB_SETTING_ALLOWEDSPAMMESSAGES, DEFAULT_SETTING_ALLOWEDSPAMMESSAGES)) { RemovePreSpammerCount(pscd); dwReturn |= SFF_IGNORE; } } // Do not send question message when next messages will be ignored if (!(dwReturn&SFF_IGNORE)) { dwReturn |= SFF_SENDMSG_INSTRUCTION; if (DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_ROBOT_HIDEUSERS, (BYTE)DEFAULT_SETTING_ROBOT_HIDEUSERS)) dwReturn |= SFF_HIDE; } if (!(pscd->dwFlags&SCDF_NO_NOTIFY)) { // Play sound file SkinPlaySound(DB_SOUND_ROBOT_SETTING); // Show Popup if (DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_POPUP, DEFAULT_SETTING_POPUP)) { WCHAR* pszDisplayName = SCD_GetContactCustomDisplayName(pscd); ShowSpamPopup(pscd->pszMsgTypeSection, pscd->pszMsgTypeName, pszDisplayName, (pscd->dwFlags&SCDF_NO_CONTACT)?NULL:pscd->hContact, SFT_ROBOT_FILTER); if (pszDisplayName) mir_free(pszDisplayName); } // Append to log file if (DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_LOGGING, DEFAULT_SETTING_LOGGING)) { STRINGLIST* pslRecognition = SLNewList(); WCHAR* pszUserName = SCD_GetContactName(pscd, TRUE); SLAddItem(pslRecognition, TranslateW("Robot message")); WriteToLogFile(pscd->pszMsgTypeSection, pscd->pszMsgTypeName, pszUserName, pszNormalMsgText, pslRecognition, dwReturn); if (pszUserName) mir_free(pszUserName); SLFreeList(pslRecognition); } // Hand out event NotifyEventHooks(hEventSpamReceived, (WPARAM)pscd, (LPARAM)SFT_ROBOT_FILTER); // Trigger Plugin Support TriggerIncomingSpam(); } } else { if (!(pscd->dwFlags&SCDF_NO_AUTOIGNORE)) RemovePreSpammerCount(pscd); // Message is normal } return dwReturn; } } // Service: MS_SPAMFILTER_DISLIKEDMESSAGECHECK static int ServiceDislikedMessageCheck(WPARAM wParam, LPARAM lParam) // wParam = SPAMCHECKDATA, lParam = 0 { SPAMCHECKDATA* pscd = (SPAMCHECKDATA*)wParam; if (!pscd || !pscd->pszMsgTypeSection || !pscd->pszMsgTypeName || (pscd->cbSize < sizeof(SPAMCHECKDATA)) || !SCD_IsUserValid(pscd)) return SFF_ISNORMAL; // Check id ctrl key is pressed to manually cancel spam check if (!(pscd->dwFlags&SCDF_NO_CANCEL) && (GetAsyncKeyState(VK_CONTROL)&0x8000)) return SFF_ISNORMAL; if ( !CallService(MS_SPAMFILTER_ISMESSAGETYPEACTIVATED, (WPARAM)pscd->pszMsgTypeSection, (LPARAM)pscd->pszMsgTypeName) || !CallService(MS_SPAMFILTER_GETSPAMCHECKINFO, (WPARAM)SFSCI_ACTIVATION_FILTER, (LPARAM)SFT_DISLIKEDMESSAGES_FILTER) ) return SFF_ISNORMAL; if (NotifyEventHooks(hEventOkToSpamCheck, (WPARAM)pscd, (LPARAM)SFT_DISLIKEDMESSAGES_FILTER) == 1) { OutputDebugString(_T("Spam Filter: Spam check denied (by event).\r\n")); return SFF_ISNORMAL; } { BOOL bDoLog = ( (!(pscd->dwFlags&SCDF_NO_NOTIFY)) && DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_LOGGING, DEFAULT_SETTING_LOGGING) ); BOOL bKickOut = FALSE; int i; WCHAR* pszNormalMsgText; WCHAR* pszClearedMsgText; STRINGLIST* pslRecognition = NULL; // Create recognition texts list if (bDoLog) pslRecognition = SLNewList(); // Buffer the msg content if (pscd->pszMsgText) { #if defined(UNICODE) if (pscd->dwFlags&SCDF_UNICODE) pszNormalMsgText = pscd->ptszMsgText; else pszNormalMsgText = (WCHAR*)mir_utf8encodeW((WCHAR*)pscd->pszMsgText); #else if (pscd->dwFlags&SCDF_UNICODE) pszNormalMsgText = UnicodeToAnsi(pscd->pwszMsgText); else pszNormalMsgText = pscd->ptszMsgText; #endif pszClearedMsgText = mir_wstrdup(pszNormalMsgText); if (pszClearedMsgText) RemoveWhiteSpaces(pszClearedMsgText, TRUE, TRUE); } else { pszNormalMsgText = NULL; pszClearedMsgText = NULL; } // -SPAMCHECKS- // Customized indicating words if (pszClearedMsgText && DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_DISLIKEDMESSAGE_CUSTOMIZEDWORDS, (BYTE)TRUE)) { STRINGLIST* pslChainWords = SLNewList(); unsigned int uFoundChainWords = 0; GetSpamDefinitionData(pslChainWords, SDID_CUSTOM_DISLIKEDWORDS); // Check how many words exist in the message for (i=0; i<=SLGetMaxPos(pslChainWords); i++) if (RegExpExistsInString(pszClearedMsgText, SLGetItem(pslChainWords, i), FALSE, NULL)) uFoundChainWords++; SLFreeList(pslChainWords); if (uFoundChainWords > 0) { if (bDoLog) SLItemPrintf(pslRecognition, SLAddItem(pslRecognition, TranslateW("Contains %u disliked indicating phrase(s)/pattern(s)")), MAX_INT_LENGTH, uFoundChainWords); bKickOut = TRUE; if (!bDoLog) goto DislikedMessageResult; } } // Multiple message check if (pszNormalMsgText && DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_DISLIKEDMESSAGE_MULTIPLEMESSAGES, DEFAULT_SETTING_DISLIKEDMESSAGE_MULTIPLEMESSAGES)) { DBVARIANT dbv; BOOL bFound; WCHAR* pszSender; pszSender = SCD_GetContactUniqueStr(pscd, FALSE); bFound = FALSE; if (DBGetContactSettingTString(NULL, DB_MODULE_NAME, DB_SETTING_DISLIKEDMESSAGE_LASTMESSAGE, &dbv) == 0) { if (StrCmp(pszNormalMsgText, dbv.ptszVal) == 0) { DBFreeVariant(&dbv); if (pszSender) { if (DBGetContactSettingTString(NULL, DB_MODULE_NAME, DB_SETTING_DISLIKEDMESSAGE_LASTSENDER, &dbv) == 0) if (StrCmp(pszSender, dbv.ptszVal) == 0) bFound = TRUE; } else { bFound = TRUE; } } DBFreeVariant(&dbv); } // Always save current msg content DBWriteContactSettingTString(NULL, DB_MODULE_NAME, DB_SETTING_DISLIKEDMESSAGE_LASTMESSAGE, pszNormalMsgText); if (pszSender) DBWriteContactSettingTString(NULL, DB_MODULE_NAME, DB_SETTING_DISLIKEDMESSAGE_LASTSENDER, pszSender); else DBDeleteContactSetting(NULL, DB_MODULE_NAME, DB_SETTING_DISLIKEDMESSAGE_LASTSENDER); if (pszSender) mir_free(pszSender); if (bFound) { if (bDoLog) SLAddItem(pslRecognition, TranslateW("Is multiple")); bKickOut = TRUE; if (!bDoLog) goto DislikedMessageResult; } } else if (!pszNormalMsgText) { DBDeleteContactSetting(NULL, DB_MODULE_NAME, DB_SETTING_DISLIKEDMESSAGE_LASTMESSAGE); } // Default hoax texts if (pszClearedMsgText && DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_DISLIKEDMESSAGE_HOAXTEXTS, DEFAULT_SETTING_DISLIKEDMESSAGE_HOAXTEXTS)) { STRINGLIST* pslHoaxTexts = SLNewList(); BOOL bFound; // Load hoax texts GetSpamDefinitionData(pslHoaxTexts, SDID_HOAXTEXTS); bFound = FALSE; for (i=SL_MIN_POS; i<=SLGetMaxPos(pslHoaxTexts); i++) if (StrCmpI(pszClearedMsgText, SLGetItem(pslHoaxTexts, i)) == 0) { bFound = TRUE; break; } SLFreeList(pslHoaxTexts); if (bFound) { if (bDoLog) SLAddItem(pslRecognition, TranslateW("Is hoax text")); bKickOut = TRUE; if (!bDoLog) goto DislikedMessageResult; } } DislikedMessageResult: if (pszClearedMsgText) mir_free(pszClearedMsgText); #if defined(UNICODE) if (!(pscd->dwFlags&SCDF_UNICODE) && pszNormalMsgText) if (pszNormalMsgText) mir_free(pszNormalMsgText); #else if ((pscd->dwFlags&SCDF_UNICODE) && pszNormalMsgText) mir_free(pszNormalMsgText); #endif // Kick out spam if ( bKickOut && (NotifyEventHooks(hEventOkToSpamDetection, (WPARAM)pscd, (LPARAM)SFT_DISLIKEDMESSAGES_FILTER) == 0)) { DWORD dwReturn = SFF_ISSPAM|((DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_BEHAVIOUR, DEFAULT_SETTING_BEHAVIOUR) == 1) ? SFF_MARKREAD : SFF_DELETE); // Add user to ignore list if (!(pscd->dwFlags&SCDF_NO_AUTOIGNORE) && DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_AUTOADDSPAMMERS, DEFAULT_SETTING_AUTOADDSPAMMERS) ) { if (IncreasePreSpammerCount(pscd) > DBGetContactSettingWord(NULL, DB_MODULE_NAME, DB_SETTING_ALLOWEDSPAMMESSAGES, DEFAULT_SETTING_ALLOWEDSPAMMESSAGES)) { RemovePreSpammerCount(pscd); dwReturn |= SFF_IGNORE; } } // Reply to sender if (DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_DISLIKEDMESSAGE_NOTIFYSENDER, DEFAULT_SETTING_DISLIKEDMESSAGE_NOTIFYSENDER)) dwReturn |= SFF_SENDMSG_NOTIFY; if (!(pscd->dwFlags&SCDF_NO_NOTIFY)) { // Play sound file SkinPlaySound(DB_SOUND_DISLIKEDMESSAGE_SETTING); // Show Popup if (DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_POPUP, DEFAULT_SETTING_POPUP)) { WCHAR* pszDisplayName = SCD_GetContactCustomDisplayName(pscd); ShowSpamPopup(pscd->pszMsgTypeSection, pscd->pszMsgTypeName, pszDisplayName, (pscd->dwFlags&SCDF_NO_CONTACT)?NULL:pscd->hContact, SFT_DISLIKEDMESSAGES_FILTER); if (pszDisplayName) mir_free(pszDisplayName); } // Hand out event NotifyEventHooks(hEventSpamReceived, (WPARAM)pscd, (LPARAM)SFT_DISLIKEDMESSAGES_FILTER); // Trigger Plugin Support TriggerIncomingSpam(); } // Append to log file if (bDoLog) { WCHAR* pszUserName = SCD_GetContactName(pscd, TRUE); WriteToLogFile(pscd->pszMsgTypeSection, pscd->pszMsgTypeName, pszUserName, pszNormalMsgText, pslRecognition, dwReturn); if (pszUserName) mir_free(pszUserName); SLFreeList(pslRecognition); } return dwReturn; } else { if (bDoLog) SLFreeList(pslRecognition); if (!(pscd->dwFlags&SCDF_NO_AUTOIGNORE)) RemovePreSpammerCount(pscd); // count can be removed here // Message is normal return SFF_ISNORMAL; } } } // Service : MS_SPAMFILTER_ADVERTISMENTCHECK static int ServiceAdvertismentCheck(WPARAM wParam, LPARAM lParam) // wParam = SPAMCHECKDATA, lParam = 0 { SPAMCHECKDATA* pscd = (SPAMCHECKDATA*)wParam; if (!pscd || !pscd->pszMsgTypeSection || !pscd->pszMsgTypeName || (pscd->cbSize < sizeof(SPAMCHECKDATA)) || !SCD_IsUserValid(pscd)) return SFF_ISNORMAL; // Check id ctrl key is pressed to manually cancel spam check if (!(pscd->dwFlags&SCDF_NO_CANCEL) && (GetAsyncKeyState(VK_CONTROL)&0x8000)) return SFF_ISNORMAL; if ( !CallService(MS_SPAMFILTER_ISMESSAGETYPEACTIVATED, (WPARAM)pscd->pszMsgTypeSection, (LPARAM)pscd->pszMsgTypeName) || !CallService(MS_SPAMFILTER_GETSPAMCHECKINFO, (WPARAM)SFSCI_ACTIVATION_FILTER, (LPARAM)SFT_ADVERTISMENT_FILTER) ) return SFF_ISNORMAL; if (NotifyEventHooks(hEventOkToSpamCheck, (WPARAM)pscd, (LPARAM)SFT_ADVERTISMENT_FILTER) == 1) { OutputDebugString(_T("Spam Filter: Spam check denied (by event).\r\n")); return SFF_ISNORMAL; } { BOOL bDoLog = ( (!(pscd->dwFlags&SCDF_NO_NOTIFY)) && DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_LOGGING, DEFAULT_SETTING_LOGGING) ); BOOL bIsKnownSpammer = FALSE; BOOL bKickOut = FALSE; BOOL bFound; int i; WCHAR* pszNormalMsgText; WCHAR* pszClearedMsgText; WCHAR* pszFormatedMsgText; STRINGLIST* pslRecognition = NULL; // Create recognition texts list if (bDoLog) pslRecognition = SLNewList(); // Buffer the msg content if (pscd->pszMsgText) { #if defined(UNICODE) if (pscd->dwFlags&SCDF_UNICODE) pszNormalMsgText = pscd->ptszMsgText; else pszNormalMsgText = (WCHAR*)mir_utf8encodeW((WCHAR*)pscd->pszMsgText); #else if (pscd->dwFlags&SCDF_UNICODE) pszNormalMsgText = UnicodeToAnsi(pscd->pwszMsgText); else pszNormalMsgText = pscd->ptszMsgText; #endif pszClearedMsgText = mir_wstrdup(pszNormalMsgText); if (pszClearedMsgText) RemoveWhiteSpaces(pszClearedMsgText, TRUE, TRUE); } else { pszNormalMsgText = NULL; pszClearedMsgText = NULL; } // Create different format check text if (pszClearedMsgText && DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_ADVERTISMENT_FORMATING, DEFAULT_SETTING_ADVERTISMENT_FORMATING)) { pszFormatedMsgText = mir_wstrdup(pszClearedMsgText); if (pszFormatedMsgText) { STRINGLIST* pslFormat = SLNewList(); // Some words may have special chars in between the chars GetSpamDefinitionData(pslFormat, SDID_SPECIALCHARS_SEPARATORS); for (i=SL_MIN_POS; i<=SLGetMaxPos(pslFormat); i++) ReplaceSubStringWithStringBuf(pszFormatedMsgText, 0, SLGetItem(pslFormat, i), _T(" "), TRUE, FALSE); SLClearList(pslFormat); // Translate some chars GetSpamDefinitionData(pslFormat, SDID_SPECIALCHARS_REPLACE_TEXT); ReplaceSubStringWithStringMultipleBuf(pszFormatedMsgText, 0, pslFormat, TRUE, FALSE); SLFreeList(pslFormat); } } else { pszFormatedMsgText = NULL; } // -SPAMCHECKS- // Multiple message check if (pszNormalMsgText && DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_ADVERTISMENT_MULTIPLEMESSAGES, DEFAULT_SETTING_ADVERTISMENT_MULTIPLEMESSAGES)) { DBVARIANT dbv; bFound = FALSE; // Do not consider sender of NotOnList messages if (DBGetContactSettingTString(NULL, DB_MODULE_NAME, DB_SETTING_ADVERTISMENT_LASTMESSAGE, &dbv) == 0) { if (StrCmp(pszNormalMsgText, dbv.ptszVal) == 0) bFound = TRUE; DBFreeVariant(&dbv); } // Always save current msg content DBWriteContactSettingTString(NULL, DB_MODULE_NAME, DB_SETTING_ADVERTISMENT_LASTMESSAGE, pszNormalMsgText); if (bFound) { if (bDoLog) SLAddItem(pslRecognition, TranslateW("Is multiple")); bKickOut = TRUE; if (!bDoLog) goto AdvertismentResult; } } else if (!pszNormalMsgText) { DBDeleteContactSetting(NULL, DB_MODULE_NAME, DB_SETTING_ADVERTISMENT_LASTMESSAGE); } // Empty message? if (pszClearedMsgText && DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_ADVERTISMENT_EMPTY, DEFAULT_SETTING_ADVERTISMENT_EMPTY)) { if (lstrlen(pszClearedMsgText) <= 0) { if (bDoLog) SLAddItem(pslRecognition, TranslateW("Is empty")); bKickOut = TRUE; if (!bDoLog) goto AdvertismentResult; } } // Message capitalized? if (pszClearedMsgText && DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_ADVERTISMENT_CAPITALIZED, DEFAULT_SETTING_ADVERTISMENT_CAPITALIZED)) { bFound = TRUE; for (i=0; i<(int)lstrlen(pszClearedMsgText); i++) if (IsCharLower(pszClearedMsgText[i])) { bFound = FALSE; break; } if (bFound) { if (bDoLog) SLAddItem(pslRecognition, TranslateW("Is capitalized")); bKickOut = TRUE; if (!bDoLog) goto AdvertismentResult; } } // Sender is default spammer? if (DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_ADVERTISMENT_DEFAULTSPAMMERS, DEFAULT_SETTING_ADVERTISMENT_DEFAULTSPAMMERS)) { STRINGLIST* psl = SLNewList(); WCHAR* pszUnique; // Load spammers definitions GetSpamDefinitionData(psl, SDID_SPAMMERS); // Check if unique user id is listed in def file pszUnique = SCD_GetContactUniqueStr(pscd, FALSE); if (pszUnique) { bFound = SLIsItem(psl, pszUnique, TRUE); mir_free(pszUnique); } else { bFound = FALSE; } // Check if nickname is listed in def file if (!bFound) { pszUnique = SCD_GetContactUniqueStr(pscd, TRUE); if (pszUnique) { bFound = SLIsItem(psl, pszUnique, TRUE); mir_free(pszUnique); } } SLFreeList(psl); if (bFound) { if (bDoLog) SLAddItem(pslRecognition, TranslateW("User is known as spammer")); bKickOut = bIsKnownSpammer = TRUE; if (!bDoLog) goto AdvertismentResult; } } // Teaser Message? if (pszClearedMsgText && DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_ADVERTISMENT_TEASERMESSAGES, DEFAULT_SETTING_ADVERTISMENT_TEASERMESSAGES)) { STRINGLIST* pslTeasers = SLNewList(); bFound = FALSE; // Load teasers GetSpamDefinitionData(pslTeasers, SDID_TEASERTEXTS); for (i=SL_MIN_POS; i<=SLGetMaxPos(pslTeasers); i++) if (StrCmp(pszClearedMsgText, SLGetItem(pslTeasers, i)) == 0) { bFound = TRUE; break; } SLFreeList(pslTeasers); if (bFound) { if (bDoLog) SLAddItem(pslRecognition, TranslateW("Is teaser")); bKickOut = TRUE; if (!bDoLog) goto AdvertismentResult; } } // Message containing URLs? if (pszClearedMsgText && DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_ADVERTISMENT_URL, DEFAULT_SETTING_ADVERTISMENT_URL)) { STRINGLIST* psl = SLNewList(); WCHAR* pszModUrlInd = NULL; bFound = FALSE; // Load url definition files GetSpamDefinitionData(psl, SDID_URLTLDS); for (i=SL_MIN_POS; i<=SLGetMaxPos(psl); i++) { // Different formated check? if (pszFormatedMsgText) pszModUrlInd = InsertSubStrEveryNChars(SLGetItem(psl, i), 1, _T(" "), FALSE, FALSE); // check for words with spaces/linefeeds/slashes between each char if (StrStrI(pszClearedMsgText, SLGetItem(psl, i)) || ((pszModUrlInd && pszFormatedMsgText) ? StrStrI(pszFormatedMsgText, pszModUrlInd) : FALSE) ) { bFound = TRUE; break; } if (pszModUrlInd) { mir_free(pszModUrlInd); pszModUrlInd = NULL; } } SLFreeList(psl); if (bFound) { if (bDoLog) SLAddItem(pslRecognition, TranslateW("Contains URL address")); bKickOut = TRUE; if (!bDoLog) goto AdvertismentResult; } } // Message containing phone numbers? if (pszClearedMsgText && DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_ADVERTISMENT_PHONENUMBERS, DEFAULT_SETTING_ADVERTISMENT_PHONENUMBERS)) { STRINGLIST* psl = SLNewList(); WCHAR* pszModContent; bFound = FALSE; // Load localized phonenumbers GetSpamDefinitionData(psl, SDID_PHONENUMBERS); pszModContent = mir_wstrdup(pszClearedMsgText); if (pszModContent) { // Check for normal formated phonennumbers { // Remove spaces ReplaceSubStringWithStringBuf(pszModContent, 0, _T(" "), NULL, TRUE, FALSE); // Replace wrong slashs ReplaceSubStringWithStringBuf(pszModContent, 0, _T("\\"), _T("/"), TRUE, FALSE); // Replace numbers ReplaceSubStringWithStringBuf(pszModContent, 0, _T("0"), _T("#"), TRUE, FALSE); ReplaceSubStringWithStringBuf(pszModContent, 0, _T("1"), _T("#"), TRUE, FALSE); ReplaceSubStringWithStringBuf(pszModContent, 0, _T("2"), _T("#"), TRUE, FALSE); ReplaceSubStringWithStringBuf(pszModContent, 0, _T("3"), _T("#"), TRUE, FALSE); ReplaceSubStringWithStringBuf(pszModContent, 0, _T("4"), _T("#"), TRUE, FALSE); ReplaceSubStringWithStringBuf(pszModContent, 0, _T("5"), _T("#"), TRUE, FALSE); ReplaceSubStringWithStringBuf(pszModContent, 0, _T("6"), _T("#"), TRUE, FALSE); ReplaceSubStringWithStringBuf(pszModContent, 0, _T("7"), _T("#"), TRUE, FALSE); ReplaceSubStringWithStringBuf(pszModContent, 0, _T("8"), _T("#"), TRUE, FALSE); ReplaceSubStringWithStringBuf(pszModContent, 0, _T("9"), _T("#"), TRUE, FALSE); for (i=SL_MIN_POS; i<=SLGetMaxPos(psl); i++) if (StrStrI(pszModContent, SLGetItem(psl, i))) { bFound = TRUE; break; } } // Check different formated phone numbers if (!bFound && pszFormatedMsgText) { WCHAR* pszNumberFormatedMsgText = mir_wstrdup(pszClearedMsgText); if (pszNumberFormatedMsgText) { // -- Create number formated text STRINGLIST* pslFormat = SLNewList(); // Some words may have special chars in between the chars GetSpamDefinitionData(pslFormat, SDID_SPECIALCHARS_SEPARATORS); for (i=SL_MIN_POS; i<=SLGetMaxPos(pslFormat); i++) ReplaceSubStringWithStringBuf(pszNumberFormatedMsgText, 0, SLGetItem(pslFormat, i), _T(" "), TRUE, FALSE); SLClearList(pslFormat); // Translate some chars GetSpamDefinitionData(pslFormat, SDID_SPECIALCHARS_REPLACE_NUMBERS); ReplaceSubStringWithStringMultipleBuf(pszNumberFormatedMsgText, 0, pslFormat, TRUE, FALSE); SLFreeList(pslFormat); //-- Check the text // Remove spaces ReplaceSubStringWithStringBuf(pszModContent, 0, _T(" "), NULL, TRUE, FALSE); // Replace wrong slashs ReplaceSubStringWithStringBuf(pszModContent, 0, _T("\\"), _T("/"), TRUE, FALSE); // Replace numbers ReplaceSubStringWithStringBuf(pszModContent, 0, _T("0"), _T("#"), TRUE, FALSE); ReplaceSubStringWithStringBuf(pszModContent, 0, _T("1"), _T("#"), TRUE, FALSE); ReplaceSubStringWithStringBuf(pszModContent, 0, _T("2"), _T("#"), TRUE, FALSE); ReplaceSubStringWithStringBuf(pszModContent, 0, _T("3"), _T("#"), TRUE, FALSE); ReplaceSubStringWithStringBuf(pszModContent, 0, _T("4"), _T("#"), TRUE, FALSE); ReplaceSubStringWithStringBuf(pszModContent, 0, _T("5"), _T("#"), TRUE, FALSE); ReplaceSubStringWithStringBuf(pszModContent, 0, _T("6"), _T("#"), TRUE, FALSE); ReplaceSubStringWithStringBuf(pszModContent, 0, _T("7"), _T("#"), TRUE, FALSE); ReplaceSubStringWithStringBuf(pszModContent, 0, _T("8"), _T("#"), TRUE, FALSE); ReplaceSubStringWithStringBuf(pszModContent, 0, _T("9"), _T("#"), TRUE, FALSE); for (i=SL_MIN_POS; i<=SLGetMaxPos(psl); i++) if (StrStrI(pszModContent, SLGetItem(psl, i))) { bFound = TRUE; break; } } } mir_free(pszModContent); } SLFreeList(psl); if (bFound) { if (bDoLog) SLAddItem(pslRecognition, TranslateW("Contains phone number")); bKickOut = TRUE; if (!bDoLog) goto AdvertismentResult; } } // Message contains bad words and/or formated bad words? if (pszClearedMsgText && DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_ADVERTISMENT_CUSTOMIZEDBADWORDS, (BYTE)TRUE) || DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_ADVERTISMENT_DEFAULTBADWORDS, DEFAULT_SETTING_ADVERTISMENT_DEFAULTBADWORDS) ) { STRINGLIST* psl = SLNewList(); unsigned int uFoundBadWords = 0; unsigned int uFoundFormatedWords = 0; BOOL bRegExpMalformed; unsigned int uRegExpErrors; // Load cutomized bad words if activated if (DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_ADVERTISMENT_CUSTOMIZEDBADWORDS, (BYTE)TRUE) ) GetSpamDefinitionData(psl, SDID_CUSTOM_BADWORDS); // Check customized bad words... for (i=SL_MIN_POS; i<=SLGetMaxPos(psl); i++) if (RegExpExistsInString(pszClearedMsgText, SLGetItem(psl, i), FALSE, NULL)) uFoundBadWords++; // Load all default bad words files if activated SLClearList(psl); if (DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_ADVERTISMENT_DEFAULTBADWORDS, DEFAULT_SETTING_ADVERTISMENT_DEFAULTBADWORDS) ) GetSpamDefinitionData(psl, SDID_BADWORDS); // Check default bad words... uRegExpErrors = 0; for (i=SL_MIN_POS; i<=SLGetMaxPos(psl); i++) { if (RegExpExistsInString(pszClearedMsgText, SLGetItem(psl, i), FALSE, &bRegExpMalformed)) uFoundBadWords++; if (bRegExpMalformed) uRegExpErrors++; } if (uRegExpErrors > 0) ShowInfoMessage(NIIF_WARNING, TranslateW("Spam Filter Warning"), TranslateW("The filter has detected %u malformed Regular Expression(s) in the default bad words!\r\n\r\nPlease update your installed Spam Definitions to the latest versions to resolve this problem.\r\nThis problem might also be caused by Spam Definitions that are not compatible with your system codepage."), MAX_INT_LENGTH, uRegExpErrors); // Check different formated bad words... if (pszFormatedMsgText) { WCHAR* pszDiffWord; // AGAIN!: Load cutomized bad words again if activated if (DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_ADVERTISMENT_CUSTOMIZEDBADWORDS, (BYTE)TRUE) ) GetSpamDefinitionData(psl, SDID_CUSTOM_BADWORDS); // Check again for bad words for (i=SL_MIN_POS; i<=SLGetMaxPos(psl); i++) { pszDiffWord = InsertSubStrEveryNChars(SLGetItem(psl, i), 1, _T(" "), FALSE, FALSE); // check for words with spaces/linefeeds between each char if (RegExpExistsInString(pszFormatedMsgText, SLGetItem(psl, i), FALSE, NULL)) { uFoundFormatedWords++; } else { pszDiffWord = InsertSubStrEveryNChars(SLGetItem(psl, i), 1, _T(" "), FALSE, FALSE); // check for words with spaces/linefeeds between each char if (pszDiffWord) { if (StrStrI(pszFormatedMsgText, pszDiffWord)) uFoundFormatedWords++; mir_free(pszDiffWord); } } } // Calculate diff uFoundFormatedWords = (uFoundFormatedWords > uFoundBadWords) ? uFoundFormatedWords = uFoundFormatedWords-uFoundBadWords : 0; } SLFreeList(psl); // Enough bad words for spam found? if (uFoundBadWords > DBGetContactSettingWord(NULL, DB_MODULE_NAME, DB_SETTING_ADVERTISMENT_ALLOWEDBADWORDS, DEFAULT_SETTING_ADVERTISMENT_ALLOWEDBADWORDS)) { if (bDoLog) SLItemPrintf(pslRecognition, SLAddItem(pslRecognition, TranslateW("Contains %u bad phrase(s)/pattern(s)")) , MAX_INT_LENGTH, uFoundBadWords); bKickOut = TRUE; } // Enough formated bad words found? if (uFoundFormatedWords > DBGetContactSettingWord(NULL, DB_MODULE_NAME, DB_SETTING_ADVERTISMENT_ALLOWEDFORMATEDWORDS, DEFAULT_SETTING_ADVERTISMENT_ALLOWEDFORMATEDWORDS)) { if (bDoLog) SLItemPrintf(pslRecognition, SLAddItem(pslRecognition, TranslateW("Contains %u differently formated bad phrase(s)/pattern(s)")), MAX_INT_LENGTH, uFoundFormatedWords); bKickOut = TRUE; } if (bKickOut && !bDoLog) goto AdvertismentResult; } // Good words check if (pszClearedMsgText && DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_ADVERTISMENT_CUSTOMIZEDGOODWORDS, (BYTE)TRUE) ) { STRINGLIST* psl = SLNewList(); unsigned int uFoundGoodWords = 0; // Load customized good words GetSpamDefinitionData(psl, SDID_CUSTOM_GOODWORDS); for (i=SL_MIN_POS; i<=SLGetMaxPos(psl); i++) if (RegExpExistsInString(pszClearedMsgText, SLGetItem(psl, i), FALSE, NULL)) uFoundGoodWords++; SLFreeList(psl); // Enough good words for non-spam found? if (uFoundGoodWords > DBGetContactSettingWord(NULL, DB_MODULE_NAME, DB_SETTING_ADVERTISMENT_ALLOWEDGOODWORDS, DEFAULT_SETTING_ADVERTISMENT_ALLOWEDGOODWORDS)) { if (bDoLog) SLItemPrintf(pslRecognition, SLAddItem(pslRecognition, TranslateW("Contains %u good phrase(s)/pattern(s)")), MAX_INT_LENGTH, uFoundGoodWords); bKickOut = FALSE; if (!bDoLog) goto AdvertismentResult; } } AdvertismentResult: if (pszClearedMsgText) mir_free(pszClearedMsgText); if (pszFormatedMsgText) mir_free(pszFormatedMsgText); #if defined(UNICODE) if (!(pscd->dwFlags&SCDF_UNICODE) && pszNormalMsgText) mir_free(pszNormalMsgText); #else if ((pscd->dwFlags&SCDF_UNICODE) && pszNormalMsgText) mir_free(pszNormalMsgText); #endif // Kick out spam if ( bKickOut && (NotifyEventHooks(hEventOkToSpamDetection, (WPARAM)pscd, (LPARAM)SFT_ADVERTISMENT_FILTER) == 0)) { DWORD dwReturn = SFF_ISSPAM | ((DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_BEHAVIOUR, DEFAULT_SETTING_BEHAVIOUR) == 1) ? SFF_MARKREAD : SFF_DELETE); if (!(pscd->dwFlags&SCDF_NO_NOTIFY)) { // Play sound file SkinPlaySound(DB_SOUND_ADVERTISMENT_SETTING); // Show Popup if (DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_POPUP, DEFAULT_SETTING_POPUP)) { WCHAR* pszDisplayName = SCD_GetContactCustomDisplayName(pscd); ShowSpamPopup(pscd->pszMsgTypeSection, pscd->pszMsgTypeName, pszDisplayName, (pscd->dwFlags&SCDF_NO_CONTACT)?NULL:pscd->hContact, SFT_ADVERTISMENT_FILTER); if (pszDisplayName) mir_free(pszDisplayName); } // Hand out event NotifyEventHooks(hEventSpamReceived, (WPARAM)pscd, (LPARAM)SFT_ADVERTISMENT_FILTER); // Trigger Plugin Support TriggerIncomingSpam(); } // Append to log file if (bDoLog) { WCHAR* pszUserName = SCD_GetContactName(pscd, TRUE); WriteToLogFile(pscd->pszMsgTypeSection, pscd->pszMsgTypeName, pszUserName, pszNormalMsgText, pslRecognition, dwReturn); if (pszUserName) mir_free(pszUserName); SLFreeList(pslRecognition); } // Add user to ignore list if (!(pscd->dwFlags&SCDF_NO_AUTOIGNORE) && DBGetContactSettingByte(NULL, DB_MODULE_NAME, DB_SETTING_AUTOADDSPAMMERS, DEFAULT_SETTING_AUTOADDSPAMMERS) ) { if (IncreasePreSpammerCount(pscd) > DBGetContactSettingWord(NULL, DB_MODULE_NAME, DB_SETTING_ALLOWEDSPAMMESSAGES, DEFAULT_SETTING_ALLOWEDSPAMMESSAGES)) { RemovePreSpammerCount(pscd); dwReturn |= SFF_IGNORE; } } return dwReturn; } else { if (bDoLog) SLFreeList(pslRecognition); //if (!(pscd->dwFlags&SCDF_NO_AUTOIGNORE)) // RemovePreSpammerCount(scd); // do not remove count here! (will cause problems) // Message is normal return SFF_ISNORMAL; } } } // -------------------------------- int GetMsgTypeID(const char* pszSection, const char* pszName) { unsigned int u; EnterCriticalSection(&csMsgTypes); // thread safety if (pszSection && pszName && pamtdMsgTypes) for (u=0; u 0)) DestroyIcon(pamtdMsgTypes[u].hIcon); if (pamtdMsgTypes[u].hSectionIcon) DestroyIcon(pamtdMsgTypes[u].hSectionIcon); } mir_free(pamtdMsgTypes); } uMsgTypesCount = 0; pamtdMsgTypes = NULL; LeaveCriticalSection(&csMsgTypes); // thread safety DeleteCriticalSection(&csMsgTypes); // thread safety }