From d7730685516d6ed6fc278a6ea74f7a5cf12e0042 Mon Sep 17 00:00:00 2001 From: Gluzskiy Alexandr Date: Mon, 5 Apr 2010 19:30:17 +0300 Subject: dos2unix --- spamcheck.c | 1364 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 682 insertions(+), 682 deletions(-) (limited to 'spamcheck.c') diff --git a/spamcheck.c b/spamcheck.c index 7078941..e5a0168 100644 --- a/spamcheck.c +++ b/spamcheck.c @@ -1,683 +1,683 @@ -/* - -"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/Services -HANDLE hHookDbContactAdded = NULL; -HANDLE hHookDbEventFilterAdd = NULL; - - -// ----------------------------------------- - -static int SpamCheckProtoRecv(WPARAM wParam, LPARAM lParam) -{ - CCSDATA* pccsd = (CCSDATA*)lParam; - BOOL bNotOnList; - SPAMCHECKDATA scd; - DWORD dwSpamResult; - int iReturn; - - ZeroMemory(&scd, sizeof(scd)); - Netlib_Logf(NULL, "Spam Filter: Catching MS_PROTO_CHAINRECV"); - - // Message already marked as read (skipping spam check) - if (((PROTORECVEVENT*)pccsd->lParam)->flags&PREF_CREATEREAD) - { - Netlib_Logf(NULL, "Spam Filter: Already marked as read (skipping spam check)"); - return CallService(MS_PROTO_CHAINRECV, wParam, lParam); - } - - if (StrCmpA(pccsd->szProtoService, PSR_URL) == 0) - { - PROTORECVEVENT* ppre = ((PROTORECVEVENT*)pccsd->lParam); - - scd.hContact = pccsd->hContact; - - // Interpret blob (ignore url itself, only description) - scd.pszMsgText = ppre->szMessage; - - scd.pszMsgTypeName = SFMT_URL; - - } else if (StrCmpA(pccsd->szProtoService, PSR_AUTH) == 0) - { - PROTORECVEVENT* ppre = ((PROTORECVEVENT*)pccsd->lParam); - - scd.hContact = (*((PHANDLE)(ppre->szMessage+sizeof(DWORD)))); - - // Check if stored hContact is still valid - if (!CallService(MS_DB_CONTACT_IS, (WPARAM)scd.hContact, 0)) - { - Netlib_Logf(NULL, "Spam Filter: Contact invalid (skipping spam check)"); - - // Continue the chain - return CallService(MS_PROTO_CHAINRECV, wParam, lParam); - } - - // Interpret blob (only use reason text) - scd.pszMsgText = (char*)(ppre->szMessage+sizeof(DWORD)+sizeof(HANDLE)); // uin, hcontact, nick - scd.pszMsgText = scd.pszMsgText+(lstrlenA(scd.pszMsgText)+1)*sizeof(char); // first - scd.pszMsgText = scd.pszMsgText+(lstrlenA(scd.pszMsgText)+1)*sizeof(char); // last - scd.pszMsgText = scd.pszMsgText+(lstrlenA(scd.pszMsgText)+1)*sizeof(char); // email - scd.pszMsgText = scd.pszMsgText+(lstrlenA(scd.pszMsgText)+1)*sizeof(char); // reason - - // If no reason text is given deactivate the text checking - if (strlen(scd.pszMsgText) <= 0) - scd.pszMsgText = NULL; - - scd.pszMsgTypeName = SFMT_AUTHREQUEST; - - } else if (StrCmpA(pccsd->szProtoService, PSR_MESSAGE) == 0) - { - PROTORECVEVENT* ppre = ((PROTORECVEVENT*)pccsd->lParam); - - scd.hContact = pccsd->hContact; - - // Interpret blob (use all message) - if (ppre->flags&PREF_UNICODE) { - scd.dwFlags |= SCDF_UNICODE; - scd.pszMsgText = ppre->szMessage+lstrlenA(ppre->szMessage)+1; - } else { - scd.pszMsgText = ppre->szMessage; - } - - scd.pszMsgTypeName = SFMT_MESSAGE; - - } else if (StrCmpA(pccsd->szProtoService, PSR_FILE) == 0) - { - PROTORECVFILE* pprf = ((PROTORECVFILE*)pccsd->lParam); - - scd.hContact = pccsd->hContact; - - // Interpret blob (only use description text) - scd.pszMsgText = pprf->szDescription; - - scd.pszMsgTypeName = SFMT_FILE; - - } else if (StrCmpA(pccsd->szProtoService, PSR_CONTACTS) == 0) - { - scd.hContact = pccsd->hContact; - - // Does not have any text to filter only contact names: nick, first, last, email - scd.pszMsgText = NULL; - - scd.pszMsgTypeName = SFMT_CONTACTS; - - } else { - Netlib_Logf(NULL, "Spam Filter: Format unknown (skipping spam check)"); - - // Continue the chain - return CallService(MS_PROTO_CHAINRECV, wParam, lParam); - } - - scd.cbSize = sizeof(scd); - scd.pszMsgTypeSection = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)scd.hContact, 0); - - // If message is from "Unknown Contact" (very unlikely) -> MS_PROTO_GETCONTACTBASEPROTO returns NULL - if (!scd.pszMsgTypeSection) - { - Netlib_Logf(NULL, "Spam Filter Result: No base protocol (skipping spam check)"); - return CallService(MS_PROTO_CHAINRECV, wParam, lParam); - } - - Netlib_Logf(NULL, "Spam Filter: Type = %s_%s", scd.pszMsgTypeSection, scd.pszMsgTypeName); - - // Result check - bNotOnList = (DBGetContactSettingByte(scd.hContact, "CList", "NotOnList", 0) ? TRUE : FALSE); - if (bNotOnList) - { - // If message is from test passed contact - if(DBGetContactSettingByte(scd.hContact, DB_MODULE_NAME, DB_SETTING_ROBOT_TESTPASSED, (BYTE)FALSE)) - { - Netlib_Logf(NULL, "Spam Filter: Result = Already passed robot test (no spam)"); - return CallService(MS_PROTO_CHAINRECV, wParam, lParam); - } - - Netlib_Logf(NULL, "Spam Filter: Running MS_SPAMFILTER_ADVERTISMENTCHECK"); - dwSpamResult = CallService(MS_SPAMFILTER_ADVERTISMENTCHECK, (WPARAM)&scd, 0); - if (dwSpamResult&SFF_ISNORMAL) - { - Netlib_Logf(NULL, "Spam Filter: Running MS_SPAMFILTER_ROBOTCHECK"); - dwSpamResult = CallService(MS_SPAMFILTER_ROBOTCHECK, (WPARAM)&scd, 0); - } - - } else { - Netlib_Logf(NULL, "Spam Filter: Running MS_SPAMFILTER_DISLIKEDMESSAGESCHECK"); - dwSpamResult = CallService(MS_SPAMFILTER_DISLIKEDMESSAGESCHECK, (WPARAM)&scd, 0); - } - - if (dwSpamResult&SFF_ISNORMAL) { - Netlib_Logf(NULL, "Spam Filter: Recognition = No-Spam"); - } else { - Netlib_Logf(NULL, "Spam Filter: Recognition = Spam!"); - } - - - // Message handling - if (dwSpamResult&SFF_DELETE) - { - Netlib_Logf(NULL, "Spam Filter: Result = Event suppressed (stopping recv chain)"); - - // Cache chain (see reply messages) - iReturn = 1; // Stop processing the chain - - } else if (dwSpamResult&SFF_MARKREAD) - { - (((PROTORECVEVENT*)pccsd->lParam)->flags) |= PREF_CREATEREAD; - Netlib_Logf(NULL, "Spam Filter: Result = PREF_CREATEREAD flag set (continuing recv chain)"); - - // Cache chain (see reply messages) - iReturn = CallService(MS_PROTO_CHAINRECV, wParam, lParam); - - } else { - Netlib_Logf(NULL, "Spam Filter: Result = Event accepted (continuing recv chain)"); - - // Cache chain (see reply messages) - iReturn = CallService(MS_PROTO_CHAINRECV, wParam, lParam); - } - - - // IMPORTANT!: The following is done *after* the call to MS_PROTO_CHAINRECV so that - // the protocol has had the chance to add the recved event to the db. - // The events to be sent are then ordered correctly in db. - - // The contact might have been deleted etc. by another filter protcol in recv chain - // -> just a safety check - if (!CallService(MS_DB_CONTACT_IS, (WPARAM)scd.hContact, 0)) - { - Netlib_Logf(NULL, "Spam Filter: Contact deleted by other filter (stopping processing)"); - return iReturn; - } - - // Remember test passed (robot filter) - if (dwSpamResult&SFF_TESTPASSED) - { - Netlib_Logf(NULL, "Spam Filter: Action = SFF_TESTPASSED (restoring contact)"); - - // Mark contact as answered - DBWriteContactSettingByte(scd.hContact, DB_MODULE_NAME, DB_SETTING_ROBOT_TESTPASSED, (BYTE)TRUE); - DBDeleteContactSetting(scd.hContact, "CList", "Hidden"); - - // Show the old events again - MarkAllContactEventsUnRead(scd.hContact); - } - - // Contact handling - if (dwSpamResult&SFF_IGNORE) - { - Netlib_Logf(NULL, "Spam Filter: Action = SFF_IGNORE (ignoring contact)"); - AddContactToIgnoreList(scd.hContact, (dwSpamResult&SFF_MARKREAD), TRUE, FALSE); - } - if (dwSpamResult&SFF_HIDE) - { - Netlib_Logf(NULL, "Spam Filter: Action = SFF_HIDE (hiding contact)"); - DBWriteContactSettingByte(scd.hContact, "CList", "Hidden", 1); - } - - // Reply messages - if (dwSpamResult&SFF_SENDMSG_NOTIFY) - { - WCHAR* pszMsgText = (WCHAR*)CallService(MS_SPAMFILTER_GETSPAMCHECKINFO, (WPARAM)SFSCI_MSGTEXT_NOTIFY, (LPARAM)&scd); - BOOL bAddToHistory = (BOOL)CallService(MS_SPAMFILTER_GETSPAMCHECKINFO, (WPARAM)SFSCI_ADD_TO_HISTORY, (LPARAM)SFSCI_MSGTEXT_NOTIFY); - - Netlib_Logf(NULL, "Spam Filter: Action = SFF_SENDMSG_NOTIFY (sending reply)"); - if (!SendContactAutomatedMessage(scd.hContact, pszMsgText, bAddToHistory)) - CallService(MS_SPAMFILTER_SHOWERROR, (WPARAM)SFSE_SEND_FAILED, (LPARAM)&scd); - - if (pszMsgText) mir_free(pszMsgText); - } - - if (dwSpamResult&SFF_SENDMSG_INSTRUCTION) - { - WCHAR* pszMsgText = (WCHAR*)CallService(MS_SPAMFILTER_GETSPAMCHECKINFO, (WPARAM)SFSCI_MSGTEXT_INSTRUCTION, (LPARAM)&scd); - BOOL bAddToHistory = (BOOL)CallService(MS_SPAMFILTER_GETSPAMCHECKINFO, (WPARAM)SFSCI_ADD_TO_HISTORY, (LPARAM)SFSCI_MSGTEXT_INSTRUCTION); - - Netlib_Logf(NULL, "Spam Filter: Action = SFF_SENDMSG_INSTRUCTION (sending reply)"); - if (!SendContactAutomatedMessage(scd.hContact, pszMsgText, bAddToHistory)) - CallService(MS_SPAMFILTER_SHOWERROR, (WPARAM)SFSE_SEND_FAILED, (LPARAM)&scd); - - if (pszMsgText) mir_free(pszMsgText); - } - - if (dwSpamResult&SFF_SENDMSG_CONFIRMATION) - { - WCHAR* pszMsgText = (WCHAR*)CallService(MS_SPAMFILTER_GETSPAMCHECKINFO, (WPARAM)SFSCI_MSGTEXT_CONFIRMATION, (LPARAM)&scd); - BOOL bAddToHistory = (BOOL)CallService(MS_SPAMFILTER_GETSPAMCHECKINFO, (WPARAM)SFSCI_ADD_TO_HISTORY, (LPARAM)SFSCI_MSGTEXT_CONFIRMATION); - - Netlib_Logf(NULL, "Spam Filter: Action = SFF_SENDMSG_CONFIRMATION (sending reply)"); - if (!SendContactAutomatedMessage(scd.hContact, pszMsgText, bAddToHistory)) - CallService(MS_SPAMFILTER_SHOWERROR, (WPARAM)SFSE_SEND_FAILED, (LPARAM)&scd); - - if (pszMsgText) mir_free(pszMsgText); - } - - - // Contact handling - if ((dwSpamResult&SFF_DELETE) && !(dwSpamResult&SFF_IGNORE)) - { - if (bNotOnList && !(dwSpamResult&SFF_TESTPASSED) && (CallService(MS_DB_EVENT_GETCOUNT, (WPARAM)scd.hContact, 0) == 0) ) - { - Netlib_Logf(NULL, "Spam Filter: Action = SFF_DELETE (deleting contact)"); - CallService(MS_DB_CONTACT_DELETE, (WPARAM)scd.hContact, 0); - } - } - - // return queue value - return iReturn; -} - - -static int DbEventFilterAdd(WPARAM wParam, LPARAM lParam) -{ - DBEVENTINFO* pdbei = (DBEVENTINFO*)lParam; - HANDLE hContact = (HANDLE)wParam; - - // Filtring events that don't have any protorecv service - // -> hacky workaround: filtering db adds - - // Only filter incoming events - if (!pdbei || !pdbei->pBlob || - (pdbei->flags&DBEF_SENT) || (pdbei->flags&DBEF_READ) ) - return 0; // continue adding the event - - - // Only filter following events - if ( (pdbei->eventType != EVENTTYPE_ADDED) && - (pdbei->eventType != ICQEVENTTYPE_EMAILEXPRESS) && - (pdbei->eventType != ICQEVENTTYPE_WEBPAGER) && - (pdbei->eventType != ICQEVENTTYPE_SMS) ) - return 0; - - { - BOOL bNotOnList; - BOOL bAlsoDoRobotCheck; - SPAMCHECKDATA scd; - DWORD dwSpamResult; - - Netlib_Logf(NULL, "Spam Filter: Catching ME_DB_EVENT_FILTER_ADD"); - - // Collecting data out of blob - ZeroMemory(&scd, sizeof(scd)); - switch (pdbei->eventType) - { - case EVENTTYPE_ADDED: - { - // Blob: uin(DWORD), hcontact(HANDLE), nick(ASCIIZ), first(ASCIIZ), last(ASCIIZ), email(ASCIIZ) - if (hContact) - scd.hContact = hContact; - else - scd.hContact = *((PHANDLE)(pdbei->pBlob+sizeof(DWORD))); - - // Check if stored hContact is still valid - if (!CallService(MS_DB_CONTACT_IS, (WPARAM)scd.hContact, 0)) - { - Netlib_Logf(NULL, "Spam Filter: Contact invalid (skipping spam check)"); - - return 0; // continue adding the event - } - - // No text to be checked available - scd.pszMsgText = NULL; - - scd.pszMsgTypeName = SFMT_ADDED; - - bAlsoDoRobotCheck = TRUE; - break; - } - - case ICQEVENTTYPE_EMAILEXPRESS: // (ICQ only) - { - // Blob: text, usually "Sender IP: xxx.xxx.xxx.xxx\r\n%s"(ASCIIZ), name(ASCIIZ), email(ASCIIZ) - - // Interpret blob (get sender name) - if (hContact) { - scd.hContact = hContact; - } else { - scd.pszUserName = (char*)pdbei->pBlob; // text - scd.pszUserName = scd.pszUserName+lstrlenA(scd.pszUserName)+1; // name - - scd.dwFlags = SCDF_NO_CONTACT|SCDF_NO_AUTOIGNORE; - } - - // Interpret blob (only use message text) - scd.pszMsgText = (char*)pdbei->pBlob; // text - - scd.pszMsgTypeName = "EmailExpress"; - - bAlsoDoRobotCheck = FALSE; - break; - } - - case ICQEVENTTYPE_WEBPAGER: // (ICQ only) - { - // Blob: text, usually "Subject: %s\r\n%s"(ASCIIZ), name(ASCIIZ), email(ASCIIZ) - - if (hContact) { - scd.hContact = hContact; - } else { - // Interpret blob (get sender name) - scd.pszUserName = (char*)pdbei->pBlob; // text - scd.pszUserName = scd.pszUserName+lstrlenA(scd.pszUserName)+1; // name - - scd.dwFlags = SCDF_NO_CONTACT|SCDF_NO_AUTOIGNORE; - } - - // Interpret blob (only use message text) - scd.pszMsgText = (char*)pdbei->pBlob; // text - - scd.pszMsgTypeName = "WebPager"; - - bAlsoDoRobotCheck = FALSE; - break; - } - - default: - return 0; - } - - scd.pszMsgTypeSection = pdbei->szModule; - if (!scd.pszMsgTypeSection) - { - Netlib_Logf(NULL, "Spam Filter: No base protocol (skipping spam check)"); - return 0; // continue adding the event - } - - scd.cbSize = sizeof(scd); - - Netlib_Logf(NULL, "Spam Filter: Type = %s_%s", scd.pszMsgTypeSection, scd.pszMsgTypeName); - - // Result check - bNotOnList = !bAlsoDoRobotCheck || (DBGetContactSettingByte(scd.hContact, "CList", "NotOnList", 0) ? TRUE : FALSE); - if (bNotOnList) - { - if (bAlsoDoRobotCheck) - { - // If message is from test passed contact - if(DBGetContactSettingByte(scd.hContact, DB_MODULE_NAME, DB_SETTING_ROBOT_TESTPASSED, (BYTE)FALSE)) - { - Netlib_Logf(NULL, "Spam Filter: Result = Already passed robot test (no spam)"); - return 0; // continue adding the event - } - } - - Netlib_Logf(NULL, "Spam Filter: Running MS_SPAMFILTER_ADVERTISMENTCHECK"); - dwSpamResult = CallService(MS_SPAMFILTER_ADVERTISMENTCHECK, (WPARAM)&scd, 0); - if (dwSpamResult&SFF_ISNORMAL) - { - if (bAlsoDoRobotCheck) - { - Netlib_Logf(NULL, "Spam Filter: Running MS_SPAMFILTER_ROBOTCHECK"); - dwSpamResult = CallService(MS_SPAMFILTER_ROBOTCHECK, (WPARAM)&scd, 0); - } - } - - } else { - Netlib_Logf(NULL, "Spam Filter: Running MS_SPAMFILTER_DISLIKEDMESSAGESCHECK"); - dwSpamResult = CallService(MS_SPAMFILTER_DISLIKEDMESSAGESCHECK, (WPARAM)&scd, 0); - } - - if (dwSpamResult&SFF_ISNORMAL) { - Netlib_Logf(NULL, "Spam Filter: Recognition = No-Spam"); - } else { - Netlib_Logf(NULL, "Spam Filter: Recognition = Spam!"); - } - - // Remember test passed (robot filter) - if (dwSpamResult&SFF_TESTPASSED) - { - Netlib_Logf(NULL, "Spam Filter: Action = SFF_TESTPASSED (restoring contact)"); - - // Mark contact as answered - DBWriteContactSettingByte(scd.hContact, DB_MODULE_NAME, DB_SETTING_ROBOT_TESTPASSED, (BYTE)TRUE); - DBDeleteContactSetting(scd.hContact, "CList", "Hidden"); - - // Show the old events again - MarkAllContactEventsUnRead(scd.hContact); - } - - // Contact handling - if (dwSpamResult&SFF_IGNORE) - { - Netlib_Logf(NULL, "Spam Filter: Action = SFF_IGNORE (ignoring contact)"); - AddContactToIgnoreList(scd.hContact, (dwSpamResult&SFF_MARKREAD), TRUE, FALSE); - } - if (dwSpamResult&SFF_HIDE) - { - Netlib_Logf(NULL, "Spam Filter: Action = SFF_HIDE (hiding contact)"); - DBWriteContactSettingByte(scd.hContact, "CList", "Hidden", 1); - } - - // Reply messages - if (dwSpamResult&SFF_SENDMSG_NOTIFY) - { - WCHAR* pszMsgText = (WCHAR*)CallService(MS_SPAMFILTER_GETSPAMCHECKINFO, (WPARAM)SFSCI_MSGTEXT_NOTIFY, (LPARAM)&scd); - BOOL bAddToHistory = (BOOL)CallService(MS_SPAMFILTER_GETSPAMCHECKINFO, (WPARAM)SFSCI_ADD_TO_HISTORY, (LPARAM)SFSCI_MSGTEXT_NOTIFY); - - Netlib_Logf(NULL, "Spam Filter: Action = SFF_SENDMSG_NOTIFY (sending reply)"); - if (!SendContactAutomatedMessage(scd.hContact, pszMsgText, bAddToHistory)) - CallService(MS_SPAMFILTER_SHOWERROR, (WPARAM)SFSE_SEND_FAILED, (LPARAM)&scd); - - if (pszMsgText) mir_free(pszMsgText); - } - - if (dwSpamResult&SFF_SENDMSG_INSTRUCTION) - { - WCHAR* pszMsgText = (WCHAR*)CallService(MS_SPAMFILTER_GETSPAMCHECKINFO, (WPARAM)SFSCI_MSGTEXT_INSTRUCTION, (LPARAM)&scd); - BOOL bAddToHistory = (BOOL)CallService(MS_SPAMFILTER_GETSPAMCHECKINFO, (WPARAM)SFSCI_ADD_TO_HISTORY, (LPARAM)SFSCI_MSGTEXT_INSTRUCTION); - - Netlib_Logf(NULL, "Spam Filter: Action = SFF_SENDMSG_INSTRUCTION (sending reply)"); - if (!SendContactAutomatedMessage(scd.hContact, pszMsgText, bAddToHistory)) - CallService(MS_SPAMFILTER_SHOWERROR, (WPARAM)SFSE_SEND_FAILED, (LPARAM)&scd); - - if (pszMsgText) mir_free(pszMsgText); - } - - if (dwSpamResult&SFF_SENDMSG_CONFIRMATION) - { - WCHAR* pszMsgText = (WCHAR*)CallService(MS_SPAMFILTER_GETSPAMCHECKINFO, (WPARAM)SFSCI_MSGTEXT_CONFIRMATION, (LPARAM)&scd); - BOOL bAddToHistory = (BOOL)CallService(MS_SPAMFILTER_GETSPAMCHECKINFO, (WPARAM)SFSCI_ADD_TO_HISTORY, (LPARAM)SFSCI_MSGTEXT_CONFIRMATION); - - Netlib_Logf(NULL, "Spam Filter: Action = SFF_SENDMSG_CONFIRMATION (sending reply)"); - if (!SendContactAutomatedMessage(scd.hContact, pszMsgText, bAddToHistory)) - CallService(MS_SPAMFILTER_SHOWERROR, (WPARAM)SFSE_SEND_FAILED, (LPARAM)&scd); - - if (pszMsgText) mir_free(pszMsgText); - } - - // Contact handling - if ((dwSpamResult&SFF_DELETE) && !(dwSpamResult&SFF_IGNORE)) - { - if (bNotOnList && !(dwSpamResult&SFF_TESTPASSED) && (CallService(MS_DB_EVENT_GETCOUNT, (WPARAM)scd.hContact, 0) == 0) ) - { - Netlib_Logf(NULL, "Spam Filter: Action = SFF_DELETE (deleting contact)"); - CallService(MS_DB_CONTACT_DELETE, (WPARAM)scd.hContact, 0); - } - } - - // Message handling - if (dwSpamResult&SFF_DELETE) - { - Netlib_Logf(NULL, "Spam Filter: Result = Event add prevented"); - return 1; // Stop adding the event - - } else if (dwSpamResult&SFF_MARKREAD) - { - pdbei->flags |= DBEF_READ; - Netlib_Logf(NULL, "Spam Filter: Result = DBEF_READ flag set (continuing add)"); - return 0; - - } else { - Netlib_Logf(NULL, "Spam Filter: Result = Event accepted (continuing add)"); - return 0; - } - } -} - - - -// ---------------------------------- - - -static int SpamCheckProtoGetCaps(WPARAM wParam, LPARAM lParam) -{ - // Non-network-access modules should return flags - // to represent the things they actually actively use - - switch (wParam) - { - case PFLAGNUM_1: - return PF1_IMSEND|PF1_IMRECV|PF1_URLRECV|PF1_FILERECV|PF1_CONTACTRECV|PF1_AUTHREQ|PF1_ADDED; - default: - return 0; - } -} - - -#if defined(UNICODE) -static int SpamCheckProtoGetNameW(WPARAM wParam, LPARAM lParam) -{ - int cchName = (int)wParam; - WCHAR* pszName = (WCHAR*)lParam; - - if (pszName && (cchName > 0)) { - mir_sntprintf(pszName, cchName, _T("%s"), TranslateT("Spam Filter")); - return 0; - } - - return 1; -} -#endif - - -static int SpamCheckProtoGetName(WPARAM wParam, LPARAM lParam) -{ - int cchName = (int)wParam; - char* pszName = (char*)lParam; - - if (pszName && (cchName > 0)) - { - mir_snprintf(pszName, cchName, "%s", Translate("Spam Filter")); - return 0; - } - - return 1; -} - - -static int DbContactAdded(WPARAM wParam, LPARAM lParam) -{ - // Error here is very very unlikely - if (CallService(MS_PROTO_ADDTOCONTACT, wParam, (LPARAM)DB_MODULE_NAME) == 0) - Netlib_Logf(NULL, "Spam Filter: Protocol filter attached to contact \"%s\" (%i)", (WCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)wParam, (LPARAM)GCDNF_UNICODE), wParam); - else - CallService(MS_SPAMFILTER_SHOWERROR, SFSE_CRITICAL_ERROR, 0); - - return 0; -} - - -// ---------------------------------- - - -void AssignAllContacts(void) -{ - HANDLE hContact; - - // MS_PROTO_ADDTOCONTACT needs to be call in AllModulesLoaded! - // Bug-Tracker #787: - // If MS_PROTO_ADDTOCONTACT is called when some plugin mentioned - // in modules chain isn't loaded, the chain will be sorted incorrectly, - // because the call to Proto_IsProtocolLoaded in service Proto_AddToContact - // returns NULL pointer to PROTOCOLDESCRIPTOR and the service can't determine the order. - - for (hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); hContact; hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0)) - if (!CallService(MS_PROTO_ISPROTOONCONTACT, (WPARAM)hContact, (LPARAM)DB_MODULE_NAME)) - { - if (CallService(MS_PROTO_ADDTOCONTACT, (WPARAM)hContact, (LPARAM)DB_MODULE_NAME) == 0) - Netlib_Logf(NULL, "Spam Filter: Protocol filter attached to contact \"%s\" (%i)", (WCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, (LPARAM)GCDNF_UNICODE), hContact); - else - CallService(MS_SPAMFILTER_SHOWERROR, SFSE_CRITICAL_ERROR, 0); - } -} - - -void InitSpamCheck(void) -{ - BOOL bSuccess; - PROTOCOLDESCRIPTOR pd; - - ZeroMemory(&pd, sizeof(pd)); - pd.cbSize = sizeof(pd); - pd.szName = DB_MODULE_NAME; - pd.type = PROTOTYPE_IGNORE+100; // Ignore module = PROTOTYPE_IGNORE (old: PROTOTYPE_FILTER-100) - - if (CallService(MS_PROTO_REGISTERMODULE, 0, (LPARAM)&pd) == 0) - { - bSuccess = TRUE; - - // General protocol functions - CreateProtoServiceFunction(pd.szName, PS_GETNAME, SpamCheckProtoGetName); - CreateProtoServiceFunction(pd.szName, PS_GETCAPS, SpamCheckProtoGetCaps); - #if defined(UNICODE) - CreateProtoServiceFunction(pd.szName, PS_GETNAME"W", SpamCheckProtoGetNameW); - #endif - - // Recv chain functions - if (!CreateProtoServiceFunction(pd.szName, PSR_AUTH, SpamCheckProtoRecv)) - bSuccess = FALSE; - if (!CreateProtoServiceFunction(pd.szName, PSR_MESSAGE, SpamCheckProtoRecv)) - bSuccess = FALSE; - if (!CreateProtoServiceFunction(pd.szName, PSR_URL, SpamCheckProtoRecv)) - bSuccess = FALSE; - if (!CreateProtoServiceFunction(pd.szName, PSR_FILE, SpamCheckProtoRecv)) - bSuccess = FALSE; - if (!CreateProtoServiceFunction(pd.szName, PSR_CONTACTS, SpamCheckProtoRecv)) - bSuccess = FALSE; - - // Register for events not added via recv chain - hHookDbEventFilterAdd = HookEvent(ME_DB_EVENT_FILTER_ADD, DbEventFilterAdd); - if (!hHookDbEventFilterAdd) bSuccess = FALSE; - - // Add filter protocol to all contacts - hHookDbContactAdded = HookEvent(ME_DB_CONTACT_ADDED, DbContactAdded); - if (!hHookDbContactAdded) bSuccess = FALSE; - - } else { - bSuccess = FALSE; - } - - // Error here is very very unlikely - if (bSuccess) - Netlib_Logf(NULL, "Spam Filter: Protocol filter initialized (%hs)", DB_MODULE_NAME); - else - CallService(MS_SPAMFILTER_SHOWERROR, SFSE_CRITICAL_ERROR, 0); -} - - -void UninitSpamCheck(void) -{ - if (hHookDbContactAdded) UnhookEvent(hHookDbContactAdded); - if (hHookDbEventFilterAdd) UnhookEvent(hHookDbEventFilterAdd); - - Netlib_Logf(NULL, "Spam Filter: Protocol filter uninitialized (%hs)", DB_MODULE_NAME); +/* + +"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/Services +HANDLE hHookDbContactAdded = NULL; +HANDLE hHookDbEventFilterAdd = NULL; + + +// ----------------------------------------- + +static int SpamCheckProtoRecv(WPARAM wParam, LPARAM lParam) +{ + CCSDATA* pccsd = (CCSDATA*)lParam; + BOOL bNotOnList; + SPAMCHECKDATA scd; + DWORD dwSpamResult; + int iReturn; + + ZeroMemory(&scd, sizeof(scd)); + Netlib_Logf(NULL, "Spam Filter: Catching MS_PROTO_CHAINRECV"); + + // Message already marked as read (skipping spam check) + if (((PROTORECVEVENT*)pccsd->lParam)->flags&PREF_CREATEREAD) + { + Netlib_Logf(NULL, "Spam Filter: Already marked as read (skipping spam check)"); + return CallService(MS_PROTO_CHAINRECV, wParam, lParam); + } + + if (StrCmpA(pccsd->szProtoService, PSR_URL) == 0) + { + PROTORECVEVENT* ppre = ((PROTORECVEVENT*)pccsd->lParam); + + scd.hContact = pccsd->hContact; + + // Interpret blob (ignore url itself, only description) + scd.pszMsgText = ppre->szMessage; + + scd.pszMsgTypeName = SFMT_URL; + + } else if (StrCmpA(pccsd->szProtoService, PSR_AUTH) == 0) + { + PROTORECVEVENT* ppre = ((PROTORECVEVENT*)pccsd->lParam); + + scd.hContact = (*((PHANDLE)(ppre->szMessage+sizeof(DWORD)))); + + // Check if stored hContact is still valid + if (!CallService(MS_DB_CONTACT_IS, (WPARAM)scd.hContact, 0)) + { + Netlib_Logf(NULL, "Spam Filter: Contact invalid (skipping spam check)"); + + // Continue the chain + return CallService(MS_PROTO_CHAINRECV, wParam, lParam); + } + + // Interpret blob (only use reason text) + scd.pszMsgText = (char*)(ppre->szMessage+sizeof(DWORD)+sizeof(HANDLE)); // uin, hcontact, nick + scd.pszMsgText = scd.pszMsgText+(lstrlenA(scd.pszMsgText)+1)*sizeof(char); // first + scd.pszMsgText = scd.pszMsgText+(lstrlenA(scd.pszMsgText)+1)*sizeof(char); // last + scd.pszMsgText = scd.pszMsgText+(lstrlenA(scd.pszMsgText)+1)*sizeof(char); // email + scd.pszMsgText = scd.pszMsgText+(lstrlenA(scd.pszMsgText)+1)*sizeof(char); // reason + + // If no reason text is given deactivate the text checking + if (strlen(scd.pszMsgText) <= 0) + scd.pszMsgText = NULL; + + scd.pszMsgTypeName = SFMT_AUTHREQUEST; + + } else if (StrCmpA(pccsd->szProtoService, PSR_MESSAGE) == 0) + { + PROTORECVEVENT* ppre = ((PROTORECVEVENT*)pccsd->lParam); + + scd.hContact = pccsd->hContact; + + // Interpret blob (use all message) + if (ppre->flags&PREF_UNICODE) { + scd.dwFlags |= SCDF_UNICODE; + scd.pszMsgText = ppre->szMessage+lstrlenA(ppre->szMessage)+1; + } else { + scd.pszMsgText = ppre->szMessage; + } + + scd.pszMsgTypeName = SFMT_MESSAGE; + + } else if (StrCmpA(pccsd->szProtoService, PSR_FILE) == 0) + { + PROTORECVFILE* pprf = ((PROTORECVFILE*)pccsd->lParam); + + scd.hContact = pccsd->hContact; + + // Interpret blob (only use description text) + scd.pszMsgText = pprf->szDescription; + + scd.pszMsgTypeName = SFMT_FILE; + + } else if (StrCmpA(pccsd->szProtoService, PSR_CONTACTS) == 0) + { + scd.hContact = pccsd->hContact; + + // Does not have any text to filter only contact names: nick, first, last, email + scd.pszMsgText = NULL; + + scd.pszMsgTypeName = SFMT_CONTACTS; + + } else { + Netlib_Logf(NULL, "Spam Filter: Format unknown (skipping spam check)"); + + // Continue the chain + return CallService(MS_PROTO_CHAINRECV, wParam, lParam); + } + + scd.cbSize = sizeof(scd); + scd.pszMsgTypeSection = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)scd.hContact, 0); + + // If message is from "Unknown Contact" (very unlikely) -> MS_PROTO_GETCONTACTBASEPROTO returns NULL + if (!scd.pszMsgTypeSection) + { + Netlib_Logf(NULL, "Spam Filter Result: No base protocol (skipping spam check)"); + return CallService(MS_PROTO_CHAINRECV, wParam, lParam); + } + + Netlib_Logf(NULL, "Spam Filter: Type = %s_%s", scd.pszMsgTypeSection, scd.pszMsgTypeName); + + // Result check + bNotOnList = (DBGetContactSettingByte(scd.hContact, "CList", "NotOnList", 0) ? TRUE : FALSE); + if (bNotOnList) + { + // If message is from test passed contact + if(DBGetContactSettingByte(scd.hContact, DB_MODULE_NAME, DB_SETTING_ROBOT_TESTPASSED, (BYTE)FALSE)) + { + Netlib_Logf(NULL, "Spam Filter: Result = Already passed robot test (no spam)"); + return CallService(MS_PROTO_CHAINRECV, wParam, lParam); + } + + Netlib_Logf(NULL, "Spam Filter: Running MS_SPAMFILTER_ADVERTISMENTCHECK"); + dwSpamResult = CallService(MS_SPAMFILTER_ADVERTISMENTCHECK, (WPARAM)&scd, 0); + if (dwSpamResult&SFF_ISNORMAL) + { + Netlib_Logf(NULL, "Spam Filter: Running MS_SPAMFILTER_ROBOTCHECK"); + dwSpamResult = CallService(MS_SPAMFILTER_ROBOTCHECK, (WPARAM)&scd, 0); + } + + } else { + Netlib_Logf(NULL, "Spam Filter: Running MS_SPAMFILTER_DISLIKEDMESSAGESCHECK"); + dwSpamResult = CallService(MS_SPAMFILTER_DISLIKEDMESSAGESCHECK, (WPARAM)&scd, 0); + } + + if (dwSpamResult&SFF_ISNORMAL) { + Netlib_Logf(NULL, "Spam Filter: Recognition = No-Spam"); + } else { + Netlib_Logf(NULL, "Spam Filter: Recognition = Spam!"); + } + + + // Message handling + if (dwSpamResult&SFF_DELETE) + { + Netlib_Logf(NULL, "Spam Filter: Result = Event suppressed (stopping recv chain)"); + + // Cache chain (see reply messages) + iReturn = 1; // Stop processing the chain + + } else if (dwSpamResult&SFF_MARKREAD) + { + (((PROTORECVEVENT*)pccsd->lParam)->flags) |= PREF_CREATEREAD; + Netlib_Logf(NULL, "Spam Filter: Result = PREF_CREATEREAD flag set (continuing recv chain)"); + + // Cache chain (see reply messages) + iReturn = CallService(MS_PROTO_CHAINRECV, wParam, lParam); + + } else { + Netlib_Logf(NULL, "Spam Filter: Result = Event accepted (continuing recv chain)"); + + // Cache chain (see reply messages) + iReturn = CallService(MS_PROTO_CHAINRECV, wParam, lParam); + } + + + // IMPORTANT!: The following is done *after* the call to MS_PROTO_CHAINRECV so that + // the protocol has had the chance to add the recved event to the db. + // The events to be sent are then ordered correctly in db. + + // The contact might have been deleted etc. by another filter protcol in recv chain + // -> just a safety check + if (!CallService(MS_DB_CONTACT_IS, (WPARAM)scd.hContact, 0)) + { + Netlib_Logf(NULL, "Spam Filter: Contact deleted by other filter (stopping processing)"); + return iReturn; + } + + // Remember test passed (robot filter) + if (dwSpamResult&SFF_TESTPASSED) + { + Netlib_Logf(NULL, "Spam Filter: Action = SFF_TESTPASSED (restoring contact)"); + + // Mark contact as answered + DBWriteContactSettingByte(scd.hContact, DB_MODULE_NAME, DB_SETTING_ROBOT_TESTPASSED, (BYTE)TRUE); + DBDeleteContactSetting(scd.hContact, "CList", "Hidden"); + + // Show the old events again + MarkAllContactEventsUnRead(scd.hContact); + } + + // Contact handling + if (dwSpamResult&SFF_IGNORE) + { + Netlib_Logf(NULL, "Spam Filter: Action = SFF_IGNORE (ignoring contact)"); + AddContactToIgnoreList(scd.hContact, (dwSpamResult&SFF_MARKREAD), TRUE, FALSE); + } + if (dwSpamResult&SFF_HIDE) + { + Netlib_Logf(NULL, "Spam Filter: Action = SFF_HIDE (hiding contact)"); + DBWriteContactSettingByte(scd.hContact, "CList", "Hidden", 1); + } + + // Reply messages + if (dwSpamResult&SFF_SENDMSG_NOTIFY) + { + WCHAR* pszMsgText = (WCHAR*)CallService(MS_SPAMFILTER_GETSPAMCHECKINFO, (WPARAM)SFSCI_MSGTEXT_NOTIFY, (LPARAM)&scd); + BOOL bAddToHistory = (BOOL)CallService(MS_SPAMFILTER_GETSPAMCHECKINFO, (WPARAM)SFSCI_ADD_TO_HISTORY, (LPARAM)SFSCI_MSGTEXT_NOTIFY); + + Netlib_Logf(NULL, "Spam Filter: Action = SFF_SENDMSG_NOTIFY (sending reply)"); + if (!SendContactAutomatedMessage(scd.hContact, pszMsgText, bAddToHistory)) + CallService(MS_SPAMFILTER_SHOWERROR, (WPARAM)SFSE_SEND_FAILED, (LPARAM)&scd); + + if (pszMsgText) mir_free(pszMsgText); + } + + if (dwSpamResult&SFF_SENDMSG_INSTRUCTION) + { + WCHAR* pszMsgText = (WCHAR*)CallService(MS_SPAMFILTER_GETSPAMCHECKINFO, (WPARAM)SFSCI_MSGTEXT_INSTRUCTION, (LPARAM)&scd); + BOOL bAddToHistory = (BOOL)CallService(MS_SPAMFILTER_GETSPAMCHECKINFO, (WPARAM)SFSCI_ADD_TO_HISTORY, (LPARAM)SFSCI_MSGTEXT_INSTRUCTION); + + Netlib_Logf(NULL, "Spam Filter: Action = SFF_SENDMSG_INSTRUCTION (sending reply)"); + if (!SendContactAutomatedMessage(scd.hContact, pszMsgText, bAddToHistory)) + CallService(MS_SPAMFILTER_SHOWERROR, (WPARAM)SFSE_SEND_FAILED, (LPARAM)&scd); + + if (pszMsgText) mir_free(pszMsgText); + } + + if (dwSpamResult&SFF_SENDMSG_CONFIRMATION) + { + WCHAR* pszMsgText = (WCHAR*)CallService(MS_SPAMFILTER_GETSPAMCHECKINFO, (WPARAM)SFSCI_MSGTEXT_CONFIRMATION, (LPARAM)&scd); + BOOL bAddToHistory = (BOOL)CallService(MS_SPAMFILTER_GETSPAMCHECKINFO, (WPARAM)SFSCI_ADD_TO_HISTORY, (LPARAM)SFSCI_MSGTEXT_CONFIRMATION); + + Netlib_Logf(NULL, "Spam Filter: Action = SFF_SENDMSG_CONFIRMATION (sending reply)"); + if (!SendContactAutomatedMessage(scd.hContact, pszMsgText, bAddToHistory)) + CallService(MS_SPAMFILTER_SHOWERROR, (WPARAM)SFSE_SEND_FAILED, (LPARAM)&scd); + + if (pszMsgText) mir_free(pszMsgText); + } + + + // Contact handling + if ((dwSpamResult&SFF_DELETE) && !(dwSpamResult&SFF_IGNORE)) + { + if (bNotOnList && !(dwSpamResult&SFF_TESTPASSED) && (CallService(MS_DB_EVENT_GETCOUNT, (WPARAM)scd.hContact, 0) == 0) ) + { + Netlib_Logf(NULL, "Spam Filter: Action = SFF_DELETE (deleting contact)"); + CallService(MS_DB_CONTACT_DELETE, (WPARAM)scd.hContact, 0); + } + } + + // return queue value + return iReturn; +} + + +static int DbEventFilterAdd(WPARAM wParam, LPARAM lParam) +{ + DBEVENTINFO* pdbei = (DBEVENTINFO*)lParam; + HANDLE hContact = (HANDLE)wParam; + + // Filtring events that don't have any protorecv service + // -> hacky workaround: filtering db adds + + // Only filter incoming events + if (!pdbei || !pdbei->pBlob || + (pdbei->flags&DBEF_SENT) || (pdbei->flags&DBEF_READ) ) + return 0; // continue adding the event + + + // Only filter following events + if ( (pdbei->eventType != EVENTTYPE_ADDED) && + (pdbei->eventType != ICQEVENTTYPE_EMAILEXPRESS) && + (pdbei->eventType != ICQEVENTTYPE_WEBPAGER) && + (pdbei->eventType != ICQEVENTTYPE_SMS) ) + return 0; + + { + BOOL bNotOnList; + BOOL bAlsoDoRobotCheck; + SPAMCHECKDATA scd; + DWORD dwSpamResult; + + Netlib_Logf(NULL, "Spam Filter: Catching ME_DB_EVENT_FILTER_ADD"); + + // Collecting data out of blob + ZeroMemory(&scd, sizeof(scd)); + switch (pdbei->eventType) + { + case EVENTTYPE_ADDED: + { + // Blob: uin(DWORD), hcontact(HANDLE), nick(ASCIIZ), first(ASCIIZ), last(ASCIIZ), email(ASCIIZ) + if (hContact) + scd.hContact = hContact; + else + scd.hContact = *((PHANDLE)(pdbei->pBlob+sizeof(DWORD))); + + // Check if stored hContact is still valid + if (!CallService(MS_DB_CONTACT_IS, (WPARAM)scd.hContact, 0)) + { + Netlib_Logf(NULL, "Spam Filter: Contact invalid (skipping spam check)"); + + return 0; // continue adding the event + } + + // No text to be checked available + scd.pszMsgText = NULL; + + scd.pszMsgTypeName = SFMT_ADDED; + + bAlsoDoRobotCheck = TRUE; + break; + } + + case ICQEVENTTYPE_EMAILEXPRESS: // (ICQ only) + { + // Blob: text, usually "Sender IP: xxx.xxx.xxx.xxx\r\n%s"(ASCIIZ), name(ASCIIZ), email(ASCIIZ) + + // Interpret blob (get sender name) + if (hContact) { + scd.hContact = hContact; + } else { + scd.pszUserName = (char*)pdbei->pBlob; // text + scd.pszUserName = scd.pszUserName+lstrlenA(scd.pszUserName)+1; // name + + scd.dwFlags = SCDF_NO_CONTACT|SCDF_NO_AUTOIGNORE; + } + + // Interpret blob (only use message text) + scd.pszMsgText = (char*)pdbei->pBlob; // text + + scd.pszMsgTypeName = "EmailExpress"; + + bAlsoDoRobotCheck = FALSE; + break; + } + + case ICQEVENTTYPE_WEBPAGER: // (ICQ only) + { + // Blob: text, usually "Subject: %s\r\n%s"(ASCIIZ), name(ASCIIZ), email(ASCIIZ) + + if (hContact) { + scd.hContact = hContact; + } else { + // Interpret blob (get sender name) + scd.pszUserName = (char*)pdbei->pBlob; // text + scd.pszUserName = scd.pszUserName+lstrlenA(scd.pszUserName)+1; // name + + scd.dwFlags = SCDF_NO_CONTACT|SCDF_NO_AUTOIGNORE; + } + + // Interpret blob (only use message text) + scd.pszMsgText = (char*)pdbei->pBlob; // text + + scd.pszMsgTypeName = "WebPager"; + + bAlsoDoRobotCheck = FALSE; + break; + } + + default: + return 0; + } + + scd.pszMsgTypeSection = pdbei->szModule; + if (!scd.pszMsgTypeSection) + { + Netlib_Logf(NULL, "Spam Filter: No base protocol (skipping spam check)"); + return 0; // continue adding the event + } + + scd.cbSize = sizeof(scd); + + Netlib_Logf(NULL, "Spam Filter: Type = %s_%s", scd.pszMsgTypeSection, scd.pszMsgTypeName); + + // Result check + bNotOnList = !bAlsoDoRobotCheck || (DBGetContactSettingByte(scd.hContact, "CList", "NotOnList", 0) ? TRUE : FALSE); + if (bNotOnList) + { + if (bAlsoDoRobotCheck) + { + // If message is from test passed contact + if(DBGetContactSettingByte(scd.hContact, DB_MODULE_NAME, DB_SETTING_ROBOT_TESTPASSED, (BYTE)FALSE)) + { + Netlib_Logf(NULL, "Spam Filter: Result = Already passed robot test (no spam)"); + return 0; // continue adding the event + } + } + + Netlib_Logf(NULL, "Spam Filter: Running MS_SPAMFILTER_ADVERTISMENTCHECK"); + dwSpamResult = CallService(MS_SPAMFILTER_ADVERTISMENTCHECK, (WPARAM)&scd, 0); + if (dwSpamResult&SFF_ISNORMAL) + { + if (bAlsoDoRobotCheck) + { + Netlib_Logf(NULL, "Spam Filter: Running MS_SPAMFILTER_ROBOTCHECK"); + dwSpamResult = CallService(MS_SPAMFILTER_ROBOTCHECK, (WPARAM)&scd, 0); + } + } + + } else { + Netlib_Logf(NULL, "Spam Filter: Running MS_SPAMFILTER_DISLIKEDMESSAGESCHECK"); + dwSpamResult = CallService(MS_SPAMFILTER_DISLIKEDMESSAGESCHECK, (WPARAM)&scd, 0); + } + + if (dwSpamResult&SFF_ISNORMAL) { + Netlib_Logf(NULL, "Spam Filter: Recognition = No-Spam"); + } else { + Netlib_Logf(NULL, "Spam Filter: Recognition = Spam!"); + } + + // Remember test passed (robot filter) + if (dwSpamResult&SFF_TESTPASSED) + { + Netlib_Logf(NULL, "Spam Filter: Action = SFF_TESTPASSED (restoring contact)"); + + // Mark contact as answered + DBWriteContactSettingByte(scd.hContact, DB_MODULE_NAME, DB_SETTING_ROBOT_TESTPASSED, (BYTE)TRUE); + DBDeleteContactSetting(scd.hContact, "CList", "Hidden"); + + // Show the old events again + MarkAllContactEventsUnRead(scd.hContact); + } + + // Contact handling + if (dwSpamResult&SFF_IGNORE) + { + Netlib_Logf(NULL, "Spam Filter: Action = SFF_IGNORE (ignoring contact)"); + AddContactToIgnoreList(scd.hContact, (dwSpamResult&SFF_MARKREAD), TRUE, FALSE); + } + if (dwSpamResult&SFF_HIDE) + { + Netlib_Logf(NULL, "Spam Filter: Action = SFF_HIDE (hiding contact)"); + DBWriteContactSettingByte(scd.hContact, "CList", "Hidden", 1); + } + + // Reply messages + if (dwSpamResult&SFF_SENDMSG_NOTIFY) + { + WCHAR* pszMsgText = (WCHAR*)CallService(MS_SPAMFILTER_GETSPAMCHECKINFO, (WPARAM)SFSCI_MSGTEXT_NOTIFY, (LPARAM)&scd); + BOOL bAddToHistory = (BOOL)CallService(MS_SPAMFILTER_GETSPAMCHECKINFO, (WPARAM)SFSCI_ADD_TO_HISTORY, (LPARAM)SFSCI_MSGTEXT_NOTIFY); + + Netlib_Logf(NULL, "Spam Filter: Action = SFF_SENDMSG_NOTIFY (sending reply)"); + if (!SendContactAutomatedMessage(scd.hContact, pszMsgText, bAddToHistory)) + CallService(MS_SPAMFILTER_SHOWERROR, (WPARAM)SFSE_SEND_FAILED, (LPARAM)&scd); + + if (pszMsgText) mir_free(pszMsgText); + } + + if (dwSpamResult&SFF_SENDMSG_INSTRUCTION) + { + WCHAR* pszMsgText = (WCHAR*)CallService(MS_SPAMFILTER_GETSPAMCHECKINFO, (WPARAM)SFSCI_MSGTEXT_INSTRUCTION, (LPARAM)&scd); + BOOL bAddToHistory = (BOOL)CallService(MS_SPAMFILTER_GETSPAMCHECKINFO, (WPARAM)SFSCI_ADD_TO_HISTORY, (LPARAM)SFSCI_MSGTEXT_INSTRUCTION); + + Netlib_Logf(NULL, "Spam Filter: Action = SFF_SENDMSG_INSTRUCTION (sending reply)"); + if (!SendContactAutomatedMessage(scd.hContact, pszMsgText, bAddToHistory)) + CallService(MS_SPAMFILTER_SHOWERROR, (WPARAM)SFSE_SEND_FAILED, (LPARAM)&scd); + + if (pszMsgText) mir_free(pszMsgText); + } + + if (dwSpamResult&SFF_SENDMSG_CONFIRMATION) + { + WCHAR* pszMsgText = (WCHAR*)CallService(MS_SPAMFILTER_GETSPAMCHECKINFO, (WPARAM)SFSCI_MSGTEXT_CONFIRMATION, (LPARAM)&scd); + BOOL bAddToHistory = (BOOL)CallService(MS_SPAMFILTER_GETSPAMCHECKINFO, (WPARAM)SFSCI_ADD_TO_HISTORY, (LPARAM)SFSCI_MSGTEXT_CONFIRMATION); + + Netlib_Logf(NULL, "Spam Filter: Action = SFF_SENDMSG_CONFIRMATION (sending reply)"); + if (!SendContactAutomatedMessage(scd.hContact, pszMsgText, bAddToHistory)) + CallService(MS_SPAMFILTER_SHOWERROR, (WPARAM)SFSE_SEND_FAILED, (LPARAM)&scd); + + if (pszMsgText) mir_free(pszMsgText); + } + + // Contact handling + if ((dwSpamResult&SFF_DELETE) && !(dwSpamResult&SFF_IGNORE)) + { + if (bNotOnList && !(dwSpamResult&SFF_TESTPASSED) && (CallService(MS_DB_EVENT_GETCOUNT, (WPARAM)scd.hContact, 0) == 0) ) + { + Netlib_Logf(NULL, "Spam Filter: Action = SFF_DELETE (deleting contact)"); + CallService(MS_DB_CONTACT_DELETE, (WPARAM)scd.hContact, 0); + } + } + + // Message handling + if (dwSpamResult&SFF_DELETE) + { + Netlib_Logf(NULL, "Spam Filter: Result = Event add prevented"); + return 1; // Stop adding the event + + } else if (dwSpamResult&SFF_MARKREAD) + { + pdbei->flags |= DBEF_READ; + Netlib_Logf(NULL, "Spam Filter: Result = DBEF_READ flag set (continuing add)"); + return 0; + + } else { + Netlib_Logf(NULL, "Spam Filter: Result = Event accepted (continuing add)"); + return 0; + } + } +} + + + +// ---------------------------------- + + +static int SpamCheckProtoGetCaps(WPARAM wParam, LPARAM lParam) +{ + // Non-network-access modules should return flags + // to represent the things they actually actively use + + switch (wParam) + { + case PFLAGNUM_1: + return PF1_IMSEND|PF1_IMRECV|PF1_URLRECV|PF1_FILERECV|PF1_CONTACTRECV|PF1_AUTHREQ|PF1_ADDED; + default: + return 0; + } +} + + +#if defined(UNICODE) +static int SpamCheckProtoGetNameW(WPARAM wParam, LPARAM lParam) +{ + int cchName = (int)wParam; + WCHAR* pszName = (WCHAR*)lParam; + + if (pszName && (cchName > 0)) { + mir_sntprintf(pszName, cchName, _T("%s"), TranslateT("Spam Filter")); + return 0; + } + + return 1; +} +#endif + + +static int SpamCheckProtoGetName(WPARAM wParam, LPARAM lParam) +{ + int cchName = (int)wParam; + char* pszName = (char*)lParam; + + if (pszName && (cchName > 0)) + { + mir_snprintf(pszName, cchName, "%s", Translate("Spam Filter")); + return 0; + } + + return 1; +} + + +static int DbContactAdded(WPARAM wParam, LPARAM lParam) +{ + // Error here is very very unlikely + if (CallService(MS_PROTO_ADDTOCONTACT, wParam, (LPARAM)DB_MODULE_NAME) == 0) + Netlib_Logf(NULL, "Spam Filter: Protocol filter attached to contact \"%s\" (%i)", (WCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)wParam, (LPARAM)GCDNF_UNICODE), wParam); + else + CallService(MS_SPAMFILTER_SHOWERROR, SFSE_CRITICAL_ERROR, 0); + + return 0; +} + + +// ---------------------------------- + + +void AssignAllContacts(void) +{ + HANDLE hContact; + + // MS_PROTO_ADDTOCONTACT needs to be call in AllModulesLoaded! + // Bug-Tracker #787: + // If MS_PROTO_ADDTOCONTACT is called when some plugin mentioned + // in modules chain isn't loaded, the chain will be sorted incorrectly, + // because the call to Proto_IsProtocolLoaded in service Proto_AddToContact + // returns NULL pointer to PROTOCOLDESCRIPTOR and the service can't determine the order. + + for (hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); hContact; hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0)) + if (!CallService(MS_PROTO_ISPROTOONCONTACT, (WPARAM)hContact, (LPARAM)DB_MODULE_NAME)) + { + if (CallService(MS_PROTO_ADDTOCONTACT, (WPARAM)hContact, (LPARAM)DB_MODULE_NAME) == 0) + Netlib_Logf(NULL, "Spam Filter: Protocol filter attached to contact \"%s\" (%i)", (WCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, (LPARAM)GCDNF_UNICODE), hContact); + else + CallService(MS_SPAMFILTER_SHOWERROR, SFSE_CRITICAL_ERROR, 0); + } +} + + +void InitSpamCheck(void) +{ + BOOL bSuccess; + PROTOCOLDESCRIPTOR pd; + + ZeroMemory(&pd, sizeof(pd)); + pd.cbSize = sizeof(pd); + pd.szName = DB_MODULE_NAME; + pd.type = PROTOTYPE_IGNORE+100; // Ignore module = PROTOTYPE_IGNORE (old: PROTOTYPE_FILTER-100) + + if (CallService(MS_PROTO_REGISTERMODULE, 0, (LPARAM)&pd) == 0) + { + bSuccess = TRUE; + + // General protocol functions + CreateProtoServiceFunction(pd.szName, PS_GETNAME, SpamCheckProtoGetName); + CreateProtoServiceFunction(pd.szName, PS_GETCAPS, SpamCheckProtoGetCaps); + #if defined(UNICODE) + CreateProtoServiceFunction(pd.szName, PS_GETNAME"W", SpamCheckProtoGetNameW); + #endif + + // Recv chain functions + if (!CreateProtoServiceFunction(pd.szName, PSR_AUTH, SpamCheckProtoRecv)) + bSuccess = FALSE; + if (!CreateProtoServiceFunction(pd.szName, PSR_MESSAGE, SpamCheckProtoRecv)) + bSuccess = FALSE; + if (!CreateProtoServiceFunction(pd.szName, PSR_URL, SpamCheckProtoRecv)) + bSuccess = FALSE; + if (!CreateProtoServiceFunction(pd.szName, PSR_FILE, SpamCheckProtoRecv)) + bSuccess = FALSE; + if (!CreateProtoServiceFunction(pd.szName, PSR_CONTACTS, SpamCheckProtoRecv)) + bSuccess = FALSE; + + // Register for events not added via recv chain + hHookDbEventFilterAdd = HookEvent(ME_DB_EVENT_FILTER_ADD, DbEventFilterAdd); + if (!hHookDbEventFilterAdd) bSuccess = FALSE; + + // Add filter protocol to all contacts + hHookDbContactAdded = HookEvent(ME_DB_CONTACT_ADDED, DbContactAdded); + if (!hHookDbContactAdded) bSuccess = FALSE; + + } else { + bSuccess = FALSE; + } + + // Error here is very very unlikely + if (bSuccess) + Netlib_Logf(NULL, "Spam Filter: Protocol filter initialized (%hs)", DB_MODULE_NAME); + else + CallService(MS_SPAMFILTER_SHOWERROR, SFSE_CRITICAL_ERROR, 0); +} + + +void UninitSpamCheck(void) +{ + if (hHookDbContactAdded) UnhookEvent(hHookDbContactAdded); + if (hHookDbEventFilterAdd) UnhookEvent(hHookDbEventFilterAdd); + + Netlib_Logf(NULL, "Spam Filter: Protocol filter uninitialized (%hs)", DB_MODULE_NAME); } \ No newline at end of file -- cgit v1.2.3