summaryrefslogtreecommitdiff
path: root/spamfilter/spamcheck.c
diff options
context:
space:
mode:
authorGluzskiy Alexandr <sss123next@list.ru>2009-10-13 05:04:06 +0300
committerGluzskiy Alexandr <sss123next@list.ru>2009-10-13 05:04:06 +0300
commit227022d9ed977c75196725502847e0b371e4e879 (patch)
tree6fe79f5ae836fe4a974db459553eb6b46a1bf8eb /spamfilter/spamcheck.c
parent23d6d3e482927c13294f204b34ce23c6f445e8ac (diff)
spamfilter branchHEADmaster
Diffstat (limited to 'spamfilter/spamcheck.c')
-rw-r--r--spamfilter/spamcheck.c683
1 files changed, 683 insertions, 0 deletions
diff --git a/spamfilter/spamcheck.c b/spamfilter/spamcheck.c
new file mode 100644
index 0000000..7078941
--- /dev/null
+++ b/spamfilter/spamcheck.c
@@ -0,0 +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);
+} \ No newline at end of file