diff options
Diffstat (limited to 'spamcheck.c')
-rw-r--r-- | spamcheck.c | 1364 |
1 files changed, 682 insertions, 682 deletions
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 |