diff options
Diffstat (limited to 'plugins/Spamotron/src')
-rw-r--r-- | plugins/Spamotron/src/bayes.cpp | 387 | ||||
-rw-r--r-- | plugins/Spamotron/src/common.h | 159 | ||||
-rw-r--r-- | plugins/Spamotron/src/options.cpp | 594 | ||||
-rw-r--r-- | plugins/Spamotron/src/popups.cpp | 241 | ||||
-rw-r--r-- | plugins/Spamotron/src/resource.h | 90 | ||||
-rw-r--r-- | plugins/Spamotron/src/spamotron.cpp | 588 | ||||
-rw-r--r-- | plugins/Spamotron/src/utils.cpp | 521 |
7 files changed, 2580 insertions, 0 deletions
diff --git a/plugins/Spamotron/src/bayes.cpp b/plugins/Spamotron/src/bayes.cpp new file mode 100644 index 0000000000..a0a2eab194 --- /dev/null +++ b/plugins/Spamotron/src/bayes.cpp @@ -0,0 +1,387 @@ +#include "common.h"
+#include "io.h"
+
+#define DELIMS " ,.;!?@-\\/+&\x0D\x0A"
+
+sqlite3 *bayesdb;
+#ifdef _DEBUG
+sqlite3 *bayesdbg;
+#endif
+HANDLE hBayesFolder;
+
+int CheckBayes()
+{
+ FOLDERSGETDATA fgd = {0};
+ char bayesdb_fullpath[MAX_PATH];
+ char bayesdb_tmp[MAX_PATH];
+
+ char* tmp = Utils_ReplaceVars("%miranda_userdata%");
+ if (tmp[strlen(tmp)-1] == '\\')
+ tmp[strlen(tmp)-1] = 0;
+ sprintf(bayesdb_tmp, "%s\\%s", tmp, BAYESDB_PATH);
+ mir_free(tmp);
+
+ if (ServiceExists(MS_FOLDERS_REGISTER_PATH)) {
+ hBayesFolder = FoldersRegisterCustomPath(PLUGIN_NAME, Translate("Bayes database path"), bayesdb_tmp);
+ } else hBayesFolder = 0;
+
+ if (hBayesFolder)
+ FoldersGetCustomPath(hBayesFolder, bayesdb_fullpath, MAX_PATH, bayesdb_tmp);
+ else
+ sprintf(bayesdb_fullpath, "%s", bayesdb_tmp);
+
+ strcat(bayesdb_fullpath, "\\"BAYESDB_FILENAME);
+ if (_access(bayesdb_fullpath,0) == 0)
+ return 1;
+
+ return 0;
+}
+
+int OpenBayes()
+{
+ char bayesdb_fullpath[MAX_PATH];
+ char *bayesdb_fullpath_utf8;
+ char *errmsg, *tmp;
+ sqlite3_stmt *stmt;
+
+ if (hBayesFolder) {
+ FoldersGetCustomPath(hBayesFolder, bayesdb_fullpath, MAX_PATH, "");
+ }
+ else {
+ tmp = Utils_ReplaceVars("%miranda_userdata%");
+ if (tmp[strlen(tmp)-1] == '\\')
+ tmp[strlen(tmp)-1] = 0;
+ strcpy(bayesdb_fullpath, tmp);
+ strcat(bayesdb_fullpath, "\\"BAYESDB_PATH);
+ mir_free(tmp);
+ }
+
+ CallService(MS_UTILS_CREATEDIRTREE, 0, (LPARAM)bayesdb_fullpath);
+
+ strcat(bayesdb_fullpath, "\\"BAYESDB_FILENAME);
+ bayesdb_fullpath_utf8 = mir_utf8encode(bayesdb_fullpath);
+
+ if (sqlite3_open(bayesdb_fullpath_utf8, &bayesdb) == SQLITE_OK)
+ {
+ sqlite3_exec(bayesdb, "CREATE TABLE IF NOT EXISTS spam (token blob(16), num int)", NULL, NULL, &errmsg);
+ sqlite3_exec(bayesdb, "CREATE TABLE IF NOT EXISTS ham (token blob(16), num int)", NULL, NULL, &errmsg);
+ sqlite3_exec(bayesdb, "CREATE TABLE IF NOT EXISTS stats (key varchar(32), value int)", NULL, NULL, &errmsg);
+ sqlite3_exec(bayesdb, "CREATE TABLE IF NOT EXISTS queue (contact int, msgtime int, message text)", NULL, NULL, &errmsg);
+ sqlite3_prepare_v2(bayesdb, "SELECT count(1) FROM stats WHERE key='spam_msgcount' OR key='ham_msgcount'", -1, &stmt, NULL);
+ if (sqlite3_step(stmt) == SQLITE_ROW)
+ if (sqlite3_column_int(stmt, 0) != 2) {
+ sqlite3_exec(bayesdb, "INSERT INTO stats VALUES ('spam_msgcount', 0)", NULL, NULL, NULL);
+ sqlite3_exec(bayesdb, "INSERT INTO stats VALUES ('ham_msgcount', 0)", NULL, NULL, NULL);
+ }
+ } else {
+ MessageBoxA(NULL, bayesdb_fullpath_utf8, "Can't open database", MB_OK);
+ }
+
+ mir_free(bayesdb_fullpath_utf8);
+
+#ifdef _DEBUG
+ tmp = Utils_ReplaceVars("%miranda_userdata%");
+ if (tmp[strlen(tmp)-1] == '\\')
+ tmp[strlen(tmp)-1] = 0;
+ sprintf(bayesdb_fullpath, "%s\\%s\\%s", tmp, BAYESDB_PATH, BAYESDBG_FILENAME);
+ mir_free(tmp);
+ bayesdb_fullpath_utf8 = mir_utf8encode(bayesdb_fullpath);
+ if (sqlite3_open(bayesdb_fullpath_utf8, &bayesdbg) == SQLITE_OK)
+ {
+ sqlite3_exec(bayesdbg, "CREATE TABLE spam (token varchar(50), num int)", NULL, NULL, &errmsg);
+ sqlite3_exec(bayesdbg, "CREATE TABLE ham (token varchar(50), num int)", NULL, NULL, &errmsg);
+ }
+ mir_free(bayesdb_fullpath_utf8);
+#endif
+
+ return 0;
+}
+
+char *tokenhash(const char *token, mir_md5_byte_t *digest)
+{
+ mir_md5_hash((mir_md5_byte_t *)token, (int)strlen(token), digest);
+ return (char*)digest;
+}
+
+int get_token_count(int type)
+{
+ char q[200];
+ int count = 0;
+ sqlite3_stmt *stmt;
+
+ if (bayesdb == NULL)
+ return 0;
+ sprintf(q, "SELECT COUNT(1) FROM %s", type == SPAM ? "spam" : "ham");
+ sqlite3_prepare_v2(bayesdb, q, -1, &stmt, NULL);
+ if (sqlite3_step(stmt) == SQLITE_ROW) {
+ count = sqlite3_column_int(stmt, 0);
+ }
+ sqlite3_finalize(stmt);
+ return count;
+}
+
+int get_msg_count(int type)
+{
+ int count = 0;
+ sqlite3_stmt *stmt;
+
+ if (bayesdb == NULL)
+ return 0;
+ sqlite3_prepare_v2(bayesdb, "SELECT value FROM stats WHERE key=?", -1, &stmt, NULL);
+ sqlite3_bind_text(stmt, 1, type == SPAM ? "spam_msgcount" : "ham_msgcount", type == SPAM ? 13 : 12, NULL);
+ if (sqlite3_step(stmt) == SQLITE_ROW) {
+ count = sqlite3_column_int(stmt, 0);
+ }
+ sqlite3_finalize(stmt);
+ return count;
+}
+
+BOOL is_token_valid(char *token)
+{
+ unsigned int i;
+ // skip digits only tokens
+ for (i = 0; i < strlen(token); i++) {
+ if ((unsigned char)token[i] >= 48 && (unsigned char)token[i] <= 57)
+ return FALSE;
+ }
+
+ // skip 1- and 2-character tokens
+ if (strlen(token) < 3)
+ return FALSE;
+
+ // skip "www", "com", "org", etc.
+ if (!strcmp(token, "www") || !strcmp(token, "com") || !strcmp(token, "org") || !strcmp(token, "edu") ||
+ !strcmp(token, "net") || !strcmp(token, "biz") || !strcmp(token, "http") || !strcmp(token, "ftp"))
+ return FALSE;
+
+ return TRUE;
+}
+
+int get_token_score(int type, char *token)
+{
+ char sql[200];
+ int score = 0;
+ mir_md5_byte_t digest[16];
+ sqlite3_stmt *stmt;
+
+ if (bayesdb == NULL)
+ return 0;
+ sprintf(sql, "SELECT num FROM %s WHERE token=?", type == SPAM ? "spam" : "ham");
+ tokenhash(token, digest);
+ sqlite3_prepare_v2(bayesdb, sql, -1, &stmt, NULL);
+ sqlite3_bind_blob(stmt, 1, digest, 16, NULL);
+
+ if (sqlite3_step(stmt) == SQLITE_ROW) {
+ score = sqlite3_column_int(stmt, 0);
+ }
+ sqlite3_finalize(stmt);
+ return score;
+}
+
+double get_msg_score(TCHAR *msg)
+{
+ char *message, *token;
+ double spam_prob, ham_prob, tmp1 = 1, tmp2 = 1;
+ double *scores = NULL;
+ int spam_msgcount, ham_msgcount, n = 0, i;
+
+ if (bayesdb == NULL)
+ return 0;
+
+ message = mir_u2a(msg);
+ spam_msgcount = get_msg_count(SPAM);
+ ham_msgcount = get_msg_count(HAM);
+ token = strtok(message, DELIMS);
+ while (token)
+ {
+ if (!is_token_valid(token)) {
+ token = strtok(NULL, DELIMS);
+ continue;
+ }
+ scores = (double*)realloc(scores, sizeof(double)*(n + 1));
+ spam_prob = spam_msgcount == 0 ? 0 : (double)get_token_score(SPAM, token) / (double)spam_msgcount;
+ ham_prob = ham_msgcount == 0 ? 0 : (double)get_token_score(HAM, token) / (double)ham_msgcount;
+ if (ham_prob == 0 && spam_prob == 0) {
+ spam_prob = 0.4; ham_prob = 0.6;
+ }
+ spam_prob = spam_prob > 1.0 ? 1.0 : (spam_prob < 0.01 ? 0.01 : spam_prob);
+ ham_prob = ham_prob > 1.0 ? 1.0 : (ham_prob < 0.01 ? 0.01 : ham_prob);
+ scores[n++] = spam_prob / (spam_prob + ham_prob);
+
+ token = strtok(NULL, DELIMS);
+ }
+
+ for (i = 0; i < n; i++) {
+ tmp1 *= scores[i];
+ tmp2 *= 1-scores[i];
+ }
+
+ mir_free(message);
+ free(scores);
+ return tmp1 / (tmp1 + tmp2);
+}
+
+void queue_message(HANDLE hContact, DWORD msgtime, TCHAR *message)
+{
+ char *tmp;
+ sqlite3_stmt *stmt;
+
+ if (!_getOptB("BayesAutolearnApproved", defaultBayesAutolearnApproved) &&
+ !_getOptB("BayesAutolearnNotApproved", defaultBayesAutolearnNotApproved))
+ return;
+
+ if (_getOptB("BayesEnabled", defaultBayesEnabled) == 0)
+ return;
+ if (bayesdb == NULL)
+ OpenBayes();
+
+ sqlite3_prepare_v2(bayesdb, "INSERT INTO queue VALUES(?,?,?)", -1, &stmt, NULL);
+ sqlite3_bind_int(stmt, 1, (DWORD)hContact);
+ sqlite3_bind_int(stmt, 2, msgtime);
+ tmp = mir_u2a(message);
+ sqlite3_bind_text(stmt, 3, tmp, (int)strlen(tmp), NULL);
+ sqlite3_step(stmt);
+ mir_free(tmp);
+ sqlite3_finalize(stmt);
+}
+
+void bayes_approve_contact(HANDLE hContact)
+{
+ const char *message;
+ TCHAR *messageW;
+ int d = 0;
+ sqlite3_stmt *stmt;
+
+ if (bayesdb == NULL)
+ return;
+
+ sqlite3_prepare_v2(bayesdb, "SELECT message FROM queue WHERE contact=?", -1, &stmt, NULL);
+ sqlite3_bind_int(stmt, 1, (DWORD)hContact);
+ while (sqlite3_step(stmt) == SQLITE_ROW)
+ {
+ d = 1;
+ message = (char*)sqlite3_column_text(stmt, 0);
+ messageW = mir_a2u(message);
+ learn_ham(messageW);
+ mir_free(messageW);
+ }
+ sqlite3_finalize(stmt);
+ if (d) {
+ sqlite3_prepare_v2(bayesdb, "DELETE FROM queue WHERE contact=?", -1, &stmt, NULL);
+ sqlite3_bind_int(stmt, 1, (DWORD)hContact);
+ sqlite3_step(stmt);
+ sqlite3_finalize(stmt);
+ }
+
+}
+
+void dequeue_messages()
+{
+ time_t t = time(NULL);
+ sqlite3_stmt *stmt;
+ const char *message;
+ TCHAR *messageW;
+ int d = 0;
+
+ if (bayesdb == NULL)
+ return;
+
+ sqlite3_prepare_v2(bayesdb, "SELECT message FROM queue WHERE msgtime + ? < ?", -1, &stmt, NULL);
+ sqlite3_bind_int(stmt, 1, _getOptD("BayesWaitApprove", defaultBayesWaitApprove)*86400);
+ sqlite3_bind_int(stmt, 2, (DWORD)t);
+ while (sqlite3_step(stmt) == SQLITE_ROW) {
+ d = 1;
+ message = (char*)sqlite3_column_text(stmt, 0);
+ messageW = mir_a2u(message);
+ learn_spam(messageW);
+ mir_free(messageW);
+ }
+ sqlite3_finalize(stmt);
+ if (d) {
+ sqlite3_prepare_v2(bayesdb, "DELETE FROM queue WHERE msgtime + ? < ?", -1, &stmt, NULL);
+ sqlite3_bind_int(stmt, 1, _getOptD("BayesWaitApprove", defaultBayesWaitApprove)*86400);
+ sqlite3_bind_int(stmt, 2, (DWORD)t);
+ sqlite3_step(stmt);
+ sqlite3_finalize(stmt);
+ }
+}
+
+/* Learn one message as either SPAM or HAM as specified in type parameter */
+void learn(int type, TCHAR *msg)
+{
+ char *tok, *message;
+ mir_md5_byte_t digest[16];
+ char sql_select[200], sql_update[200], sql_insert[200], sql_counter[200];
+ sqlite3_stmt *stmt;
+#ifdef _DEBUG
+ sqlite3_stmt *stmtdbg;
+#endif
+
+ if (_getOptB("BayesEnabled", defaultBayesEnabled) == 0)
+ return;
+ if (bayesdb == NULL)
+ OpenBayes();
+
+ message = mir_u2a(msg);
+ tok = strtok(message, DELIMS);
+ sprintf(sql_counter, "UPDATE stats SET value=value+1 WHERE key='%s'", type == SPAM ? "spam_msgcount" : "ham_msgcount");
+ sprintf(sql_select, "SELECT 1 FROM %s WHERE token=?", type == SPAM ? "spam" : "ham");
+ sprintf(sql_update, "UPDATE %s SET num=num+1 WHERE token=?", type ? "spam" : "ham");
+ sprintf(sql_insert, "INSERT INTO %s VALUES(?, 1)", type ? "spam" : "ham");
+#ifdef _DEBUG
+ sqlite3_exec(bayesdbg, "BEGIN", NULL, NULL, NULL);
+#endif
+ sqlite3_exec(bayesdb, "BEGIN", NULL, NULL, NULL);
+ while (tok) {
+ if (!is_token_valid(tok)) {
+ tok = strtok(NULL, DELIMS);
+ continue;
+ }
+ tokenhash(tok, digest);
+ sqlite3_prepare_v2(bayesdb, sql_select, -1, &stmt, NULL);
+ sqlite3_bind_blob(stmt, 1, digest, 16, SQLITE_STATIC);
+ if (SQLITE_ROW == sqlite3_step(stmt)) {
+ sqlite3_finalize(stmt);
+ sqlite3_prepare_v2(bayesdb, sql_update, -1, &stmt, NULL);
+ } else {
+ sqlite3_finalize(stmt);
+ sqlite3_prepare_v2(bayesdb, sql_insert, -1, &stmt, NULL);
+ }
+ sqlite3_bind_blob(stmt, 1, digest, 16, SQLITE_STATIC);
+ sqlite3_step(stmt);
+ sqlite3_finalize(stmt);
+
+#ifdef _DEBUG
+ sqlite3_prepare_v2(bayesdbg, sql_select, -1, &stmtdbg, NULL);
+ sqlite3_bind_text(stmtdbg, 1, tok, strlen(tok), NULL);
+ if (SQLITE_ROW == sqlite3_step(stmtdbg)) {
+ sqlite3_finalize(stmtdbg);
+ sqlite3_prepare_v2(bayesdbg, sql_update, -1, &stmtdbg, NULL);
+ } else {
+ sqlite3_finalize(stmtdbg);
+ sqlite3_prepare_v2(bayesdbg, sql_insert, -1, &stmtdbg, NULL);
+ }
+ sqlite3_bind_text(stmtdbg, 1, tok, strlen(tok), SQLITE_STATIC);
+ sqlite3_step(stmtdbg);
+ sqlite3_finalize(stmtdbg);
+#endif
+
+ tok = strtok(NULL, DELIMS);
+ }
+ sqlite3_exec(bayesdb, sql_counter, NULL, NULL, NULL);
+ sqlite3_exec(bayesdb, "COMMIT", NULL, NULL, NULL);
+#ifdef _DEBUG
+ sqlite3_exec(bayesdbg, "COMMIT", NULL, NULL, NULL);
+#endif
+ mir_free(message);
+}
+
+void learn_ham(TCHAR *msg)
+{
+ learn(0, msg);
+}
+
+void learn_spam(TCHAR *msg)
+{
+ learn(1, msg);
+}
\ No newline at end of file diff --git a/plugins/Spamotron/src/common.h b/plugins/Spamotron/src/common.h new file mode 100644 index 0000000000..8cb5e81202 --- /dev/null +++ b/plugins/Spamotron/src/common.h @@ -0,0 +1,159 @@ +#include <windows.h>
+#include <commctrl.h>
+#include <stdlib.h>
+#include <time.h>
+#define MIRANDA_VER 0x0A00
+
+#include <newpluginapi.h>
+#include <m_database.h>
+#include <m_system.h>
+#include <m_utils.h>
+#include <m_clist.h>
+#include <m_options.h>
+#include <m_protocols.h>
+#include <m_skin.h>
+#include <m_popup.h>
+#include <m_langpack.h>
+#include <m_protosvc.h>
+
+//#include "m_updater.h"
+#include "m_folders.h"
+#include "../pcre/pcre.h"
+
+#include "resource.h"
+
+#define PLUGIN_NAME "Spam-o-tron"
+
+#define SPAMOTRON_MODE_PLAIN 0
+#define SPAMOTRON_MODE_MATH 1
+#define SPAMOTRON_MODE_ROTATE 2
+#define SPAMOTRON_MODE_RANDOM 3
+
+#define MAX_BUFFER_LENGTH 1024
+
+#define _getCOptB(a,b,c) db_get_b(a, PLUGIN_NAME, b, c)
+#define _setCOptB(a,b,c) db_set_b(a, PLUGIN_NAME, b, c)
+#define _getCOptD(a,b,c) db_get_dw(a, PLUGIN_NAME, b, c)
+#define _setCOptD(a,b,c) db_set_dw(a, PLUGIN_NAME, b, c)
+#define _getOptB(a,b) _getCOptB(NULL, a, b)
+#define _setOptB(a,b) _setCOptB(NULL, a, b)
+#define _getOptD(a,b) _getCOptD(NULL, a, b)
+#define _setOptD(a,b) _setCOptD(NULL, a, b)
+
+TCHAR* _getCOptS(TCHAR *buf, unsigned int buflen, HANDLE hContact, const char* option, const TCHAR *def);
+#define _getOptS(a,b,c,d) _getCOptS(a, b, NULL, c, d)
+#define _setCOptTS(a,b,c) db_set_ts(a, PLUGIN_NAME, b, c)
+#define _setCOptS(a,b,c) db_set_s(a, PLUGIN_NAME, b, c)
+#define _setOptTS(a,b) _setCOptTS(NULL, a, b)
+
+#define defaultMode SPAMOTRON_MODE_PLAIN
+#define defaultChallenge TranslateT("Spam-o-tron needs to verify you're not a bot. Reply with \"%response%\" without quotes.")
+#define defaultChallengeMath TranslateT("Spam-o-tron needs to verify you're not a bot. Reply with a result of expression %mathexpr%.")
+#define defaultResponse _T("no-spam")
+#define defaultResponseCC TRUE
+#define defaultSuccessResponse TranslateT("Verified.")
+#define defaultAuthChallenge TranslateT("Spam-o-tron delayed authorization request. First reply with \"%response%\" without quotes.")
+#define defaultAuthChallengeMath TranslateT("Spam-o-tron delayed authorization request. First reply with a result of expression %mathexpr%.")
+#define defaultReplyOnSuccess TRUE
+#define defaultReplyOnAuth TRUE
+#define defaultReplyOnMsg TRUE
+#define defaultApproveOnMsgOut TRUE
+#define defaultApproveOnMsgIn FALSE
+#define defaultAddPermanently FALSE
+#define defaultHideUnverified TRUE
+#define defaultKeepBlockedMsg TRUE
+#define defaultMarkMsgUnreadOnApproval FALSE
+#define defaultLogActions TRUE
+#define defaultNotifyPopup FALSE
+#define defaultDontReplySameMsg TRUE
+#define defaultDontReplyMsg TRUE
+#define defaultApproveOnMsgInWordlist _T("")
+#define defaultDontReplyMsgWordlist _T("Spam-o-tron, StopSpam, Anti-Spam")
+#define defaultMaxMsgContactCountPerDay 3
+#define defaultMaxSameMsgCountPerDay 2
+
+#define defaultNotifyPopupBlocked TRUE
+#define defaultNotifyPopupApproved TRUE
+#define defaultNotifyPopupChallenge TRUE
+#define defaultPopupDefaultColors FALSE
+#define defaultPopupWindowsColors FALSE
+#define defaultPopupDefaultTimeout TRUE
+#define defaultPopupBlockedTimeout 2
+#define defaultPopupApprovedTimeout 2
+#define defaultPopupChallengeTimeout 2
+#define defaultPopupBlockedForeground RGB(0, 0, 0)
+#define defaultPopupBlockedBackground RGB(240, 128, 128)
+#define defaultPopupApprovedForeground RGB(0, 0, 0)
+#define defaultPopupApprovedBackground RGB(128, 240, 128)
+#define defaultPopupChallengeForeground RGB(0, 0, 0)
+#define defaultPopupChallengeBackground RGB(180, 210, 240)
+
+#define _NOTIFYP _getOptB("NotifyPopup", defaultNotifyPopup)
+
+TCHAR* ReplaceVars(TCHAR *dst, unsigned int len);
+TCHAR* ReplaceVarsNum(TCHAR *dst, unsigned int len, int num);
+TCHAR* ReplaceVar(TCHAR *dst, unsigned int len, const TCHAR *var, const TCHAR *rvar);
+int get_response_id(const TCHAR *strvar);
+int get_response_num(const TCHAR *str);
+TCHAR* get_response(TCHAR* dst, unsigned int dstlen, int num);
+
+TCHAR* _tcsstr_cc(TCHAR* str, TCHAR* strSearch, BOOL cc);
+BOOL _isregex(TCHAR* strSearch);
+BOOL _isvalidregex(TCHAR* strSearch);
+BOOL _regmatch(TCHAR* str, TCHAR* strSearch);
+BOOL Contains(TCHAR* dst, TCHAR* src);
+BOOL isOneDay(DWORD timestamp1, DWORD timestamp2);
+void MarkUnread(HANDLE hContact);
+
+int ShowPopup(HANDLE hContact, BYTE popupType, TCHAR *line1, TCHAR *line2);
+int ShowPopupPreview(HWND optDlg, BYTE popupType, TCHAR *line1, TCHAR *line2);
+int _notify(HANDLE hContact, BYTE type, TCHAR *message, TCHAR *origmessage);
+int LogToSystemHistory(char *message, char *origmessage);
+#define POPUP_DEFAULT 0
+#define POPUP_BLOCKED 1
+#define POPUP_APPROVED 2
+#define POPUP_CHALLENGE 3
+
+#ifdef _UNICODE
+#define CONTACT_NAME(a) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)a, GCDNF_NOMYHANDLE | GCDNF_UNICODE | GCDNF_NOCACHE)
+#else
+#define CONTACT_NAME(a) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)a, GCDNF_NOMYHANDLE | GCDNF_NOCACHE)
+#endif
+
+
+/* bayes.c */
+
+#include "../sqlite3/sqlite3.h"
+extern sqlite3 *bayesdb;
+#define BAYESDB_PATH "spamotron"
+#define BAYESDB_FILENAME "bayes.db"
+#define defaultBayesEnabled TRUE
+#define defaultBayesBlockMsg FALSE
+#define defaultBayesAutoApprove FALSE
+#define defaultBayesAutolearnApproved TRUE
+#define defaultBayesAutolearnAutoApproved FALSE
+#define defaultBayesAutolearnNotApproved TRUE
+#define defaultBayesAutolearnOutgoing FALSE
+#define defaultBayesWaitApprove 2
+#define SCORE_C 0.0001
+#define defaultBayesSpamScore 9500
+#define defaultBayesHamScore 500
+#define HAM 0
+#define SPAM 1
+
+int OpenBayes();
+int CheckBayes();
+void learn(int type, TCHAR *msg);
+void learn_ham(TCHAR *msg);
+void learn_spam(TCHAR *msg);
+int get_token_count(int type);
+int get_msg_count(int type);
+double get_msg_score(TCHAR *msg);
+void queue_message(HANDLE hContact, DWORD msgtime, TCHAR *message);
+void bayes_approve_contact(HANDLE hContact);
+void dequeue_messages();
+
+#ifdef _DEBUG
+extern sqlite3 *bayesdbg;
+#define BAYESDBG_FILENAME "bayes.dbg"
+#endif
\ No newline at end of file diff --git a/plugins/Spamotron/src/options.cpp b/plugins/Spamotron/src/options.cpp new file mode 100644 index 0000000000..ca7c78317a --- /dev/null +++ b/plugins/Spamotron/src/options.cpp @@ -0,0 +1,594 @@ +#include "common.h"
+
+TCHAR currentResponse[256] = {0};
+
+TCHAR* _getCOptS(TCHAR *buf, unsigned int buflen, HANDLE hContact, const char* option, const TCHAR *def)
+{
+ DBVARIANT dbv = {0};
+ _tcsnset(buf, 0, buflen);
+ if (db_get_ts(hContact, PLUGIN_NAME, option, &dbv) != 0)
+ _tcsncpy(buf, def, min(buflen, _tcslen(def)+1));
+ else if (dbv.type == DBVT_TCHAR) {
+ _tcsncpy(buf, dbv.ptszVal, min(buflen, _tcslen(dbv.ptszVal)+1));
+ }
+ db_free(&dbv);
+ return buf;
+}
+TCHAR* _getMOptS(TCHAR *buf, unsigned int buflen, const char* module, const char* option, const TCHAR *def)
+{
+ TCHAR* tmp;
+ DBVARIANT dbv = {0};
+ _tcsnset(buf, 0, buflen);
+ if (db_get_s(NULL, module, option, &dbv) != 0)
+ _tcsncpy(buf, def, min(buflen, _tcslen(def)+1));
+ else if (dbv.type == DBVT_TCHAR) {
+ _tcsncpy(buf, dbv.ptszVal, min(buflen, _tcslen(dbv.ptszVal)+1));
+ } else {
+ tmp = mir_a2u(dbv.pszVal);
+ _tcsncpy(buf, tmp, min(buflen, _tcslen(tmp)+1));
+ mir_free(tmp);
+ }
+ db_free(&dbv);
+ return buf;
+}
+
+
+BOOL _saveDlgItemText(HWND hDialog, int controlID, char* option)
+{
+ int len;
+ TCHAR *tmp;
+ len = GetWindowTextLength(GetDlgItem(hDialog, controlID));
+ tmp = (TCHAR *)malloc((len + 1)*sizeof(TCHAR));
+ GetDlgItemText(hDialog, controlID, tmp, len + 1);
+ _setOptTS(option, tmp);
+ free(tmp);
+ return TRUE;
+}
+int _saveDlgItemResponse(HWND hDialog, int controlID, char* option)
+{
+ int ret = 0;
+ int isRegex = 0;
+ int len;
+ TCHAR *tmp;
+ len = GetWindowTextLength(GetDlgItem(hDialog, controlID));
+ tmp = (TCHAR*)malloc((len+1)*sizeof(TCHAR));
+ GetDlgItemText(hDialog, controlID, tmp, len+1);
+ isRegex = _isregex(tmp);
+ if (!isRegex)
+ ret = _saveDlgItemText(hDialog, controlID, option) ? 1 : 0;
+ else {
+ if (_isvalidregex(tmp))
+ ret = _saveDlgItemText(hDialog, controlID, option) ? 1 : 0;
+ else
+ ret = -1;
+ }
+ free(tmp);
+ return ret;
+}
+BOOL _saveDlgItemInt(HWND hDialog, int controlID, char* option)
+{
+ int len;
+ TCHAR *tmp;
+ len = GetWindowTextLength(GetDlgItem(hDialog, controlID));
+ tmp = (TCHAR *)malloc((len + 1)*sizeof(TCHAR));
+ GetDlgItemText(hDialog, controlID, tmp, len + 1);
+ _setOptD(option, _ttoi(tmp));
+ free(tmp);
+ return TRUE;
+}
+BOOL _saveDlgItemScore(HWND hDialog, int controlID, char* option)
+{
+ int len;
+ TCHAR *tmp;
+ len = GetWindowTextLength(GetDlgItem(hDialog, controlID));
+ tmp = (TCHAR *)malloc((len + 1)*sizeof(TCHAR));
+ GetDlgItemText(hDialog, controlID, tmp, len + 1);
+ _setOptD(option, _tcstod(tmp, NULL)/SCORE_C);
+ return TRUE;
+}
+
+extern HINSTANCE hInst;
+
+BOOL CALLBACK DlgProcOptionsMain(HWND optDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static int bInitializing = 0, i, j, numProtocols;
+ PROTOCOLDESCRIPTOR** pd;
+ TCHAR pName[200] = {0};
+ char protoOption[256] = {0};
+ char protoName[256] = {0};
+ HWND hProtocolsList = GetDlgItem(optDlg, IDC_OPT_PROTOCOLS);
+ LVITEM lvi = {0};
+ LVCOLUMN lvc = {0};
+ TCHAR *buf;
+ int buflen = 500;
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(optDlg);
+ bInitializing = 1;
+
+ ///Main enable switch
+ SendDlgItemMessage(optDlg, IDC_OPT_OUT_MSG_APPROVE, BM_SETCHECK, _getOptB("ApproveOnMsgOut", defaultApproveOnMsgOut), 0);
+ SendDlgItemMessage(optDlg, IDC_OPT_IN_MSG_APPROVE, BM_SETCHECK, _getOptB("ApproveOnMsgIn", defaultApproveOnMsgIn), 0);
+ SendDlgItemMessage(optDlg, IDC_OPT_DONT_REPLY_SAME_MSG, BM_SETCHECK, _getOptB("DontReplySameMsg", defaultDontReplySameMsg), 0);
+ SendDlgItemMessage(optDlg, IDC_OPT_DONT_REPLY_MSG, BM_SETCHECK, _getOptB("DontReplyMsg", defaultDontReplyMsg), 0);
+ SendDlgItemMessage(optDlg, IDC_OPT_HIDE_UNTIL_VERIFIED, BM_SETCHECK, _getOptB("HideUnverified", defaultHideUnverified), 0);
+ SendDlgItemMessage(optDlg, IDC_OPT_ADD_PERMANENTLY, BM_SETCHECK, _getOptB("AddPermanently", defaultAddPermanently), 0);
+ SendDlgItemMessage(optDlg, IDC_OPT_LOG_ACTIONS, BM_SETCHECK, _getOptB("LogActions", defaultLogActions), 0);
+ buf = (TCHAR *)mir_alloc(buflen*sizeof(TCHAR));
+ SetDlgItemText(optDlg, IDC_OPT_IN_MSG_APPROVE_WORDLIST, _getOptS(buf, buflen, "ApproveOnMsgInWordlist", defaultApproveOnMsgInWordlist));
+ SetDlgItemText(optDlg, IDC_OPT_MAX_MSG_CONTACT, _itot((unsigned int)_getOptD("MaxMsgContactCountPerDay", defaultMaxMsgContactCountPerDay), buf, 10));
+ SetDlgItemText(optDlg, IDC_OPT_MAX_SAME_MSG, _itot((unsigned int)_getOptD("MaxSameMsgCountPerDay", defaultMaxSameMsgCountPerDay), buf, 10));
+ SetDlgItemText(optDlg, IDC_OPT_DONT_REPLY_MSG_WORDLIST, _getOptS(buf, buflen, "DontReplyMsgWordlist", defaultDontReplyMsgWordlist));
+ mir_free(buf);
+
+ ///Individual protocols list
+ ListView_SetExtendedListViewStyle(hProtocolsList, LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT);
+ lvc.mask = LVCF_WIDTH;
+ lvc.cx = 120;
+ ListView_InsertColumn(hProtocolsList, 0, &lvc);
+ lvi.mask = LVIF_TEXT | LVIF_STATE;
+ CallService(MS_PROTO_ENUMACCOUNTS, (LPARAM)&numProtocols, (WPARAM)&pd);
+ for (i = 0, j = 0; i < numProtocols; i++)
+ {
+ lvi.iItem = i;
+ _getMOptS(pName, 200*sizeof(TCHAR), pd[i]->szName, "AM_BaseProto", _T(""));
+ if (_tcscmp(pName, _T("ICQ")) != 0)
+ continue;
+ lvi.pszText = mir_a2u(pd[i]->szName);
+ ListView_InsertItem(hProtocolsList, &lvi);
+ ZeroMemory(protoOption, 256);
+ strcat(protoOption, "proto_");
+ strcat(protoOption, pd[i]->szName);
+ ListView_SetCheckState(hProtocolsList, j++, _getOptB(protoOption, 0));
+ }
+
+ bInitializing = 0;
+ return TRUE;
+
+ case WM_COMMAND:
+ if (bInitializing)
+ return FALSE;
+ switch (LOWORD(wParam)) {
+ case IDC_OPT_OUT_MSG_APPROVE:
+ case IDC_OPT_IN_MSG_APPROVE:
+ case IDC_OPT_DONT_REPLY_SAME_MSG:
+ case IDC_OPT_DONT_REPLY_MSG:
+ case IDC_OPT_ADD_PERMANENTLY:
+ case IDC_OPT_HIDE_UNTIL_VERIFIED:
+ case IDC_OPT_LOG_ACTIONS:
+ if (HIWORD(wParam) != BN_CLICKED)
+ return FALSE;
+ break;
+ case IDC_OPT_IN_MSG_APPROVE_WORDLIST:
+ case IDC_OPT_MAX_MSG_CONTACT:
+ case IDC_OPT_MAX_SAME_MSG:
+ case IDC_OPT_DONT_REPLY_MSG_WORDLIST:
+ if (HIWORD(wParam) != EN_CHANGE)
+ return FALSE;
+ break;
+ }
+ SendMessage(GetParent(optDlg), PSM_CHANGED, 0, 0);
+ break;
+ case WM_NOTIFY:
+ if (bInitializing)
+ return FALSE;
+ switch (LOWORD(wParam)) {
+ case IDC_OPT_PROTOCOLS:
+ if (
+ ((LPNMHDR)lParam)->code == LVN_ITEMCHANGED &&
+ ((LPNMLISTVIEW)lParam)->uChanged & LVIF_STATE &&
+ (((LPNMLISTVIEW)lParam)->uOldState & LVIS_STATEIMAGEMASK) != \
+ (((LPNMLISTVIEW)lParam)->uNewState & LVIS_STATEIMAGEMASK)
+ )
+ SendMessage(GetParent(optDlg), PSM_CHANGED, 0, 0);
+ break;
+ }
+ switch (((NMHDR*)lParam)->code) {
+ case PSN_APPLY:
+ _setOptB("ApproveOnMsgOut", SendDlgItemMessage(optDlg, IDC_OPT_OUT_MSG_APPROVE, BM_GETCHECK, 0, 0));
+ _setOptB("ApproveOnMsgIn", SendDlgItemMessage(optDlg, IDC_OPT_IN_MSG_APPROVE, BM_GETCHECK, 0, 0));
+ _setOptB("DontReplySameMsg", SendDlgItemMessage(optDlg, IDC_OPT_DONT_REPLY_SAME_MSG, BM_GETCHECK, 0, 0));
+ _setOptB("DontReplyMsg", SendDlgItemMessage(optDlg, IDC_OPT_DONT_REPLY_MSG, BM_GETCHECK, 0, 0));
+ _setOptB("AddPermanently", SendDlgItemMessage(optDlg, IDC_OPT_ADD_PERMANENTLY, BM_GETCHECK, 0, 0));
+ _setOptB("HideUnverified", SendDlgItemMessage(optDlg, IDC_OPT_HIDE_UNTIL_VERIFIED, BM_GETCHECK, 0, 0));
+ _setOptB("LogActions", SendDlgItemMessage(optDlg, IDC_OPT_LOG_ACTIONS, BM_GETCHECK, 0, 0));
+ _saveDlgItemText(optDlg, IDC_OPT_IN_MSG_APPROVE_WORDLIST, "ApproveOnMsgInWordlist");
+ _saveDlgItemText(optDlg, IDC_OPT_DONT_REPLY_MSG_WORDLIST, "DontReplyMsgWordlist");
+ _saveDlgItemInt(optDlg, IDC_OPT_MAX_MSG_CONTACT, "MaxMsgContactCountPerDay");
+ _saveDlgItemInt(optDlg, IDC_OPT_MAX_SAME_MSG, "MaxSameMsgCountPerDay");
+ numProtocols = ListView_GetItemCount(hProtocolsList);
+ buf = (TCHAR *)malloc(256*sizeof(TCHAR *));
+ for (i = 0; i < numProtocols; i++) {
+ ListView_GetItemText(hProtocolsList, i, 0, buf, 256);
+ //wcstombs(protoName, buf, 256);
+ ZeroMemory(protoOption, 256);
+ strcat(protoOption, "proto_");
+ strcat(protoOption, mir_u2a(buf));
+ _setOptB(protoOption, ListView_GetCheckState(hProtocolsList, i));
+ }
+ free(buf);
+ return TRUE;
+ }
+ break;
+ case WM_DESTROY:
+ break;
+ }
+ return FALSE;
+}
+
+BOOL CALLBACK DlgProcOptionsQuestion(HWND optDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static int bInitializing = 0;
+ int i, selectedMode;
+ HWND ht;
+ TCHAR *buf;
+ unsigned int buflen = 500;
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(optDlg);
+ bInitializing = 1;
+
+ ht = GetDlgItem(optDlg, IDC_OPT_MODE);
+ SendMessage(ht, CB_ADDSTRING, 0, (LPARAM)TranslateT("Simple"));
+ SendMessage(ht, CB_SETITEMDATA, 0, SPAMOTRON_MODE_PLAIN);
+ SendMessage(ht, CB_ADDSTRING, 0, (LPARAM)TranslateT("Math expression"));
+ SendMessage(ht, CB_SETITEMDATA, 1, SPAMOTRON_MODE_MATH);
+ SendMessage(ht, CB_ADDSTRING, 0, (LPARAM)TranslateT("Round-robin"));
+ SendMessage(ht, CB_SETITEMDATA, 2, SPAMOTRON_MODE_ROTATE);
+ SendMessage(ht, CB_ADDSTRING, 0, (LPARAM)TranslateT("Random"));
+ SendMessage(ht, CB_SETITEMDATA, 3, SPAMOTRON_MODE_RANDOM);
+
+ selectedMode = _getOptB("Mode", defaultMode);
+ for (i = 0; i < SendMessage(ht, CB_GETCOUNT, 0, 0); i++) {
+ if (SendMessage(ht, CB_GETITEMDATA, i, 0) == selectedMode) {
+ SendMessage(ht, CB_SETCURSEL, i, 0);
+ break;
+ }
+ }
+ SetDlgItemText(optDlg, IDC_OPT_MATH_RESPONSE, TranslateT("Will be automatically evaluated from %mathexpr%"));
+ buf = (TCHAR *)malloc(buflen*sizeof(TCHAR));
+ switch (selectedMode) {
+ case SPAMOTRON_MODE_PLAIN:
+ case SPAMOTRON_MODE_ROTATE:
+ case SPAMOTRON_MODE_RANDOM:
+ ShowWindow(GetDlgItem(optDlg, IDC_STATIC_MODEMSG), 0);
+ ShowWindow(GetDlgItem(optDlg, IDC_OPT_MATH_RESPONSE), 0);
+ ShowWindow(GetDlgItem(optDlg, IDC_OPT_RESPONSE), 1);
+ ShowWindow(GetDlgItem(optDlg, IDC_OPT_CCRESPONSE), 1);
+ EnableWindow(GetDlgItem(optDlg, IDC_OPT_RESPONSE), TRUE);
+ SetDlgItemText(optDlg, IDC_OPT_CHALLENGE, _getOptS(buf, buflen, "Challenge", defaultChallenge));
+ SetDlgItemText(optDlg, IDC_OPT_AUTH_CHALLENGE, _getOptS(buf, buflen, "AuthChallenge", defaultAuthChallenge));
+ break;
+ case SPAMOTRON_MODE_MATH:
+ ShowWindow(GetDlgItem(optDlg, IDC_STATIC_MODEMSG), 1);
+ ShowWindow(GetDlgItem(optDlg, IDC_OPT_MATH_RESPONSE), 1);
+ ShowWindow(GetDlgItem(optDlg, IDC_OPT_RESPONSE), 0);
+ ShowWindow(GetDlgItem(optDlg, IDC_OPT_CCRESPONSE), 0);
+ EnableWindow(GetDlgItem(optDlg, IDC_OPT_RESPONSE), FALSE);
+ SetDlgItemText(optDlg, IDC_OPT_CHALLENGE, _getOptS(buf, buflen, "ChallengeMath", defaultChallengeMath));
+ SetDlgItemText(optDlg, IDC_OPT_AUTH_CHALLENGE, _getOptS(buf, buflen, "AuthChallengeMath", defaultAuthChallengeMath));
+ break;
+ }
+ SendDlgItemMessage(optDlg, IDC_OPT_REPLY_ON_SUCCESS, BM_SETCHECK, _getOptB("ReplyOnSuccess", defaultReplyOnSuccess), 0);
+ SendDlgItemMessage(optDlg, IDC_OPT_REPLY_ON_AUTH, BM_SETCHECK, _getOptB("ReplyOnAuth", defaultReplyOnAuth), 0);
+ SendDlgItemMessage(optDlg, IDC_OPT_REPLY_ON_MSG, BM_SETCHECK, _getOptB("ReplyOnMsg", defaultReplyOnMsg), 0);
+ SendDlgItemMessage(optDlg, IDC_OPT_KEEP_BLOCKED_MSG, BM_SETCHECK, _getOptB("KeepBlockedMsg", defaultKeepBlockedMsg), 0);
+ SendDlgItemMessage(optDlg, IDC_OPT_MARK_MSG_UNREAD_ON_APPROVAL, BM_SETCHECK, _getOptB("MarkMsgUnreadOnApproval", defaultMarkMsgUnreadOnApproval), 0);
+ EnableWindow(GetDlgItem(optDlg, IDC_OPT_MARK_MSG_UNREAD_ON_APPROVAL), _getOptB("KeepBlockedMsg", defaultKeepBlockedMsg));
+ SendDlgItemMessage(optDlg, IDC_OPT_CCRESPONSE, BM_SETCHECK, _getOptB("ResponseCC", defaultResponseCC), 0);
+ SetDlgItemText(optDlg, IDC_OPT_RESPONSE, _getOptS(buf, buflen, "Response", defaultResponse));
+ SetDlgItemText(optDlg, IDC_OPT_SUCCESS_RESPONSE, _getOptS(buf, buflen, "SuccessResponse", defaultSuccessResponse));
+ free(buf);
+
+ bInitializing = 0;
+ return TRUE;
+
+ case WM_COMMAND:
+ if (bInitializing)
+ return FALSE;
+ switch (LOWORD(wParam)) {
+ case IDC_OPT_MODE:
+ if (HIWORD(wParam) != CBN_SELCHANGE)
+ return FALSE;
+ i = SendMessage(GetDlgItem(optDlg, IDC_OPT_MODE), CB_GETCURSEL, 0, 0);
+ selectedMode = SendMessage(GetDlgItem(optDlg, IDC_OPT_MODE), CB_GETITEMDATA, i, 0);
+ buf = (TCHAR*)malloc(buflen*sizeof(TCHAR));
+ switch (selectedMode) {
+ case SPAMOTRON_MODE_PLAIN:
+ case SPAMOTRON_MODE_ROTATE:
+ case SPAMOTRON_MODE_RANDOM:
+ ShowWindow(GetDlgItem(optDlg, IDC_STATIC_MODEMSG), 0);
+ ShowWindow(GetDlgItem(optDlg, IDC_OPT_MATH_RESPONSE), 0);
+ ShowWindow(GetDlgItem(optDlg, IDC_OPT_RESPONSE), 1);
+ ShowWindow(GetDlgItem(optDlg, IDC_OPT_CCRESPONSE), 1);
+ EnableWindow(GetDlgItem(optDlg, IDC_OPT_RESPONSE), TRUE);
+ SetDlgItemText(optDlg, IDC_OPT_CHALLENGE, _getOptS(buf, buflen, "Challenge", defaultChallenge));
+ SetDlgItemText(optDlg, IDC_OPT_AUTH_CHALLENGE, _getOptS(buf, buflen, "AuthChallenge", defaultAuthChallenge));
+ break;
+ case SPAMOTRON_MODE_MATH:
+ ShowWindow(GetDlgItem(optDlg, IDC_STATIC_MODEMSG), 1);
+ ShowWindow(GetDlgItem(optDlg, IDC_OPT_MATH_RESPONSE), 1);
+ ShowWindow(GetDlgItem(optDlg, IDC_OPT_RESPONSE), 0);
+ ShowWindow(GetDlgItem(optDlg, IDC_OPT_CCRESPONSE), 0);
+ EnableWindow(GetDlgItem(optDlg, IDC_OPT_RESPONSE), FALSE);
+ SetDlgItemText(optDlg, IDC_OPT_CHALLENGE, _getOptS(buf, buflen, "ChallengeMath", defaultChallengeMath));
+ SetDlgItemText(optDlg, IDC_OPT_AUTH_CHALLENGE, _getOptS(buf, buflen, "AuthChallengeMath", defaultAuthChallengeMath));
+ break;
+ }
+ free(buf);
+ break;
+ case IDC_OPT_REPLY_ON_SUCCESS:
+ case IDC_OPT_REPLY_ON_AUTH:
+ case IDC_OPT_REPLY_ON_MSG:
+ case IDC_OPT_KEEP_BLOCKED_MSG:
+ case IDC_OPT_MARK_MSG_UNREAD_ON_APPROVAL:
+ case IDC_OPT_CCRESPONSE:
+ EnableWindow(GetDlgItem(optDlg, IDC_OPT_MARK_MSG_UNREAD_ON_APPROVAL), SendDlgItemMessage(optDlg, IDC_OPT_KEEP_BLOCKED_MSG, BM_GETCHECK, 0, 0));
+ if (HIWORD(wParam) != BN_CLICKED)
+ return FALSE;
+ break;
+ case IDC_OPT_CHALLENGE:
+ case IDC_OPT_RESPONSE:
+ case IDC_OPT_SUCCESS_RESPONSE:
+ case IDC_OPT_AUTH_CHALLENGE:
+ if (HIWORD(wParam) != EN_CHANGE)
+ return FALSE;
+ break;
+ case IDC_DEFAULTS:
+ SetDlgItemText(optDlg, IDC_STATIC_MODEMSG, _T(""));
+ ShowWindow(GetDlgItem(optDlg, IDC_OPT_MATH_RESPONSE), 0);
+ ShowWindow(GetDlgItem(optDlg, IDC_OPT_RESPONSE), 1);
+ EnableWindow(GetDlgItem(optDlg, IDC_OPT_RESPONSE), TRUE);
+ SendDlgItemMessage(optDlg, IDC_OPT_MODE, CB_SETCURSEL, 0, 0);
+ SendDlgItemMessage(optDlg, IDC_OPT_CCRESPONSE, BM_SETCHECK, defaultResponseCC, 0);
+ SetDlgItemText(optDlg, IDC_OPT_CHALLENGE, defaultChallenge);
+ SetDlgItemText(optDlg, IDC_OPT_RESPONSE, defaultResponse);
+ SetDlgItemText(optDlg, IDC_OPT_SUCCESS_RESPONSE, defaultSuccessResponse);
+ SetDlgItemText(optDlg, IDC_OPT_AUTH_CHALLENGE, defaultAuthChallenge);
+ SendDlgItemMessage(optDlg, IDC_OPT_REPLY_ON_SUCCESS, BM_SETCHECK, defaultReplyOnSuccess, 0);
+ SendDlgItemMessage(optDlg, IDC_OPT_REPLY_ON_AUTH, BM_SETCHECK, defaultReplyOnAuth, 0);
+ SendDlgItemMessage(optDlg, IDC_OPT_REPLY_ON_MSG, BM_SETCHECK, defaultReplyOnMsg, 0);
+ SendDlgItemMessage(optDlg, IDC_OPT_KEEP_BLOCKED_MSG, BM_SETCHECK, defaultKeepBlockedMsg, 0);
+ SendDlgItemMessage(optDlg, IDC_OPT_MARK_MSG_UNREAD_ON_APPROVAL, BM_SETCHECK, defaultMarkMsgUnreadOnApproval, 0);
+ break;
+ }
+ SendMessage(GetParent(optDlg), PSM_CHANGED, 0, 0);
+ break;
+ case WM_NOTIFY:
+ switch (((NMHDR*)lParam)->code) {
+ case PSN_APPLY:
+ i = SendMessage(GetDlgItem(optDlg, IDC_OPT_MODE), CB_GETCURSEL, 0, 0);
+ selectedMode = SendMessage(GetDlgItem(optDlg, IDC_OPT_MODE), CB_GETITEMDATA, i, 0);
+ _setOptB("Mode", selectedMode);
+ _setOptB("ReplyOnSuccess", SendDlgItemMessage(optDlg, IDC_OPT_REPLY_ON_SUCCESS, BM_GETCHECK, 0, 0));
+ _setOptB("ReplyOnAuth", SendDlgItemMessage(optDlg, IDC_OPT_REPLY_ON_AUTH, BM_GETCHECK, 0, 0));
+ _setOptB("ReplyOnMsg", SendDlgItemMessage(optDlg, IDC_OPT_REPLY_ON_MSG, BM_GETCHECK, 0, 0));
+ _setOptB("KeepBlockedMsg", SendDlgItemMessage(optDlg, IDC_OPT_KEEP_BLOCKED_MSG, BM_GETCHECK, 0, 0));
+ _setOptB("MarkMsgUnreadOnApproval", SendDlgItemMessage(optDlg, IDC_OPT_MARK_MSG_UNREAD_ON_APPROVAL, BM_GETCHECK, 0, 0));
+ _setOptB("ResponseCC", SendDlgItemMessage(optDlg, IDC_OPT_CCRESPONSE, BM_GETCHECK, 0, 0));
+ switch (selectedMode) {
+ case SPAMOTRON_MODE_PLAIN:
+ _saveDlgItemText(optDlg, IDC_OPT_CHALLENGE, "Challenge");
+ _saveDlgItemText(optDlg, IDC_OPT_AUTH_CHALLENGE, "AuthChallenge");
+ break;
+ case SPAMOTRON_MODE_MATH:
+ _saveDlgItemText(optDlg, IDC_OPT_CHALLENGE, "ChallengeMath");
+ _saveDlgItemText(optDlg, IDC_OPT_AUTH_CHALLENGE, "AuthChallengeMath");
+ break;
+ }
+ if (_saveDlgItemResponse(optDlg, IDC_OPT_RESPONSE, "Response") == -1) {
+ MessageBox(NULL, TranslateT("Invalid regular expression.\nKeeping previous value."), L"Error", MB_OK);
+ return FALSE;
+ }
+ _saveDlgItemText(optDlg, IDC_OPT_SUCCESS_RESPONSE, "SuccessResponse");
+
+ return TRUE;
+ }
+ break;
+ case WM_DESTROY:
+ break;
+ }
+ return FALSE;
+}
+
+
+void EnableControlsBayes(HWND hwnd, BOOL enable)
+{
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_FILTERING_GROUP), enable);
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_LEARNING_GROUP), enable);
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_BAYES_BLOCK_MSG), enable);
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_BAYES_SPAM_SCORE), enable);
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_BAYES_AUTO_APPROVE), enable);
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_BAYES_HAM_SCORE), enable);
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_BAYES_AUTOLEARN_APPROVED), enable);
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_BAYES_AUTOLEARN_AUTOAPPROVED), enable &&
+ SendDlgItemMessage(hwnd, IDC_OPT_BAYES_AUTO_APPROVE, BM_GETCHECK, 0, 0));
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_BAYES_AUTOLEARN_NOT_APPROVED), enable);
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_BAYES_WAIT_APPROVE), enable);
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_BAYES_AUTOLEARN_NOT_APPROVED2), enable);
+ EnableWindow(GetDlgItem(hwnd, IDC_STATIC_DAYSASSPAM), enable);
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_BAYES_AUTOLEARN_OUTGOING), enable);
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_BAYES_LEARNBOX), enable);
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_BAYES_SPAM), enable);
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_BAYES_HAM), enable);
+ EnableWindow(GetDlgItem(hwnd, IDC_CHECK_MSG), enable);
+ EnableWindow(GetDlgItem(hwnd, IDC_STATIC_SPAM_COUNT), enable);
+ EnableWindow(GetDlgItem(hwnd, IDC_STATIC_HAM_COUNT), enable);
+ EnableWindow(GetDlgItem(hwnd, IDC_STATIC_SPAMCOUNT_LABEL), enable);
+ EnableWindow(GetDlgItem(hwnd, IDC_STATIC_HAMCOUNT_LABEL), enable);
+}
+
+BOOL CALLBACK DlgProcOptionsBayes(HWND optDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static int bInitializing = 0, len;
+ BOOL bEnabled;
+ TCHAR *dbuf;
+ TCHAR buf[MAX_BUFFER_LENGTH];
+ char cbuf[MAX_BUFFER_LENGTH];
+ switch (msg) {
+ case WM_INITDIALOG:
+ bInitializing = 1;
+ TranslateDialogDefault(optDlg);
+ bEnabled = _getOptB("BayesEnabled", defaultBayesEnabled);
+ SendDlgItemMessage(optDlg, IDC_OPT_BAYES_ENABLED, BM_SETCHECK, bEnabled, 0);
+ SendDlgItemMessage(optDlg, IDC_OPT_BAYES_BLOCK_MSG, BM_SETCHECK, _getOptB("BayesBlockMsg", defaultBayesBlockMsg), 0);
+ SendDlgItemMessage(optDlg, IDC_OPT_BAYES_AUTO_APPROVE, BM_SETCHECK, _getOptB("BayesAutoApprove", defaultBayesAutoApprove), 0);
+ SendDlgItemMessage(optDlg, IDC_OPT_BAYES_AUTOLEARN_APPROVED, BM_SETCHECK, _getOptB("BayesAutolearnApproved", defaultBayesAutolearnApproved), 0);
+ SendDlgItemMessage(optDlg, IDC_OPT_BAYES_AUTOLEARN_AUTOAPPROVED, BM_SETCHECK, _getOptB("BayesAutolearnAutoApproved", defaultBayesAutolearnAutoApproved), 0);
+ SendDlgItemMessage(optDlg, IDC_OPT_BAYES_AUTOLEARN_NOT_APPROVED, BM_SETCHECK, _getOptB("BayesAutolearnNotApproved", defaultBayesAutolearnNotApproved), 0);
+ SendDlgItemMessage(optDlg, IDC_OPT_BAYES_AUTOLEARN_OUTGOING, BM_SETCHECK, _getOptB("BayesAutolearnOutgoing", defaultBayesAutolearnOutgoing), 0);
+
+ EnableControlsBayes(optDlg, bEnabled);
+
+ mir_sntprintf(buf, MAX_BUFFER_LENGTH, _T("%0.02f"), (double)_getOptD("BayesSpamScore", defaultBayesSpamScore)*SCORE_C);
+ SetDlgItemText(optDlg, IDC_OPT_BAYES_SPAM_SCORE, buf);
+ mir_sntprintf(buf, MAX_BUFFER_LENGTH, _T("%.02f"), (double)_getOptD("BayesHamScore", defaultBayesHamScore)*SCORE_C);
+ SetDlgItemText(optDlg, IDC_OPT_BAYES_HAM_SCORE, buf);
+ mir_sntprintf(buf, MAX_BUFFER_LENGTH, _T("%d"), _getOptD("BayesWaitApprove", defaultBayesWaitApprove));
+ SetDlgItemText(optDlg, IDC_OPT_BAYES_WAIT_APPROVE, buf);
+
+ if (bEnabled) {
+ mir_sntprintf(buf, MAX_BUFFER_LENGTH, _T("%d"), get_msg_count(SPAM));
+ SetDlgItemText(optDlg, IDC_STATIC_SPAM_COUNT, buf);
+ mir_sntprintf(buf, MAX_BUFFER_LENGTH, _T("%d"), get_msg_count(HAM));
+ SetDlgItemText(optDlg, IDC_STATIC_HAM_COUNT, buf);
+ }
+
+ bInitializing = 0;
+ break;
+ case WM_COMMAND:
+ if (bInitializing)
+ return FALSE;
+ switch (LOWORD(wParam)) {
+ case IDC_OPT_BAYES_ENABLED:
+ bEnabled = SendDlgItemMessage(optDlg, IDC_OPT_BAYES_ENABLED, BM_GETCHECK, 0, 0);
+ EnableControlsBayes(optDlg, bEnabled);
+ case IDC_OPT_BAYES_AUTO_APPROVE:
+ bEnabled = SendDlgItemMessage(optDlg, IDC_OPT_BAYES_ENABLED, BM_GETCHECK, 0, 0);
+ EnableWindow(GetDlgItem(optDlg, IDC_OPT_BAYES_AUTOLEARN_AUTOAPPROVED),
+ bEnabled && SendDlgItemMessage(optDlg, IDC_OPT_BAYES_AUTO_APPROVE, BM_GETCHECK, 0, 0));
+ case IDC_OPT_BAYES_BLOCK_MSG:
+ case IDC_OPT_BAYES_AUTOLEARN_APPROVED:
+ case IDC_OPT_BAYES_AUTOLEARN_AUTOAPPROVED:
+ case IDC_OPT_BAYES_AUTOLEARN_NOT_APPROVED:
+ case IDC_OPT_BAYES_AUTOLEARN_OUTGOING:
+ if (HIWORD(wParam) != BN_CLICKED)
+ return FALSE;
+ break;
+ case IDC_OPT_BAYES_SPAM_SCORE:
+ case IDC_OPT_BAYES_HAM_SCORE:
+ case IDC_OPT_BAYES_WAIT_APPROVE:
+ if (HIWORD(wParam) != EN_CHANGE)
+ return FALSE;
+ break;
+ case IDC_OPT_BAYES_LEARNBOX:
+ return FALSE;
+ case IDC_OPT_BAYES_HAM:
+ // Learn ham from learnbox
+ len = GetWindowTextLength(GetDlgItem(optDlg, IDC_OPT_BAYES_LEARNBOX))+1;
+ dbuf = (TCHAR *)malloc(len*sizeof(TCHAR));
+ if (!dbuf)
+ return FALSE;
+ GetDlgItemText(optDlg, IDC_OPT_BAYES_LEARNBOX, dbuf, len);
+ learn_ham(dbuf);
+ SetDlgItemText(optDlg, IDC_OPT_BAYES_LEARNBOX, _T(""));
+ free(dbuf);
+
+ mir_sntprintf(buf, MAX_BUFFER_LENGTH, _T("%d"), get_msg_count(SPAM));
+ SetDlgItemText(optDlg, IDC_STATIC_SPAM_COUNT, buf);
+ mir_sntprintf(buf, MAX_BUFFER_LENGTH, _T("%d"), get_msg_count(HAM));
+ SetDlgItemText(optDlg, IDC_STATIC_HAM_COUNT, buf);
+ return FALSE;
+
+ case IDC_OPT_BAYES_SPAM:
+ // Learn spam from learnbox
+ len = GetWindowTextLength(GetDlgItem(optDlg, IDC_OPT_BAYES_LEARNBOX))+1;
+ dbuf = (TCHAR *)malloc(len*sizeof(TCHAR));
+ if (!dbuf)
+ return FALSE;
+ GetDlgItemText(optDlg, IDC_OPT_BAYES_LEARNBOX, dbuf, len);
+ learn_spam(dbuf);
+ SetDlgItemText(optDlg, IDC_OPT_BAYES_LEARNBOX, _T(""));
+ free(dbuf);
+
+ mir_sntprintf(buf, MAX_BUFFER_LENGTH, _T("%d"), get_msg_count(SPAM));
+ SetDlgItemText(optDlg, IDC_STATIC_SPAM_COUNT, buf);
+ mir_sntprintf(buf, MAX_BUFFER_LENGTH, _T("%d"), get_msg_count(HAM));
+ SetDlgItemText(optDlg, IDC_STATIC_HAM_COUNT, buf);
+ return FALSE;
+
+ case IDC_CHECK_MSG:
+ len = GetWindowTextLength(GetDlgItem(optDlg, IDC_OPT_BAYES_LEARNBOX))+1;
+ dbuf = (TCHAR *)malloc((len)*sizeof(TCHAR));
+ if (!dbuf)
+ return FALSE;
+ GetDlgItemText(optDlg, IDC_OPT_BAYES_LEARNBOX, dbuf, len);
+ sprintf(cbuf, "%0.04f", get_msg_score(dbuf));
+ SetDlgItemText(optDlg, IDC_OPT_BAYES_LEARNBOX, _T(""));
+ MessageBoxA(NULL, cbuf, Translate("Message score"), MB_OK);
+ free(dbuf);
+ return FALSE;
+
+ }
+ SendMessage(GetParent(optDlg), PSM_CHANGED, 0, 0);
+ break;
+ case WM_NOTIFY:
+ switch (((NMHDR*)lParam)->code) {
+ case PSN_APPLY:
+ _setOptB("BayesEnabled", SendDlgItemMessage(optDlg, IDC_OPT_BAYES_ENABLED, BM_GETCHECK, 0, 0));
+ _setOptB("BayesBlockMsg", SendDlgItemMessage(optDlg, IDC_OPT_BAYES_BLOCK_MSG, BM_GETCHECK, 0, 0));
+ _setOptB("BayesAutoApprove", SendDlgItemMessage(optDlg, IDC_OPT_BAYES_AUTO_APPROVE, BM_GETCHECK, 0, 0));
+ _setOptB("BayesAutolearnApproved", SendDlgItemMessage(optDlg, IDC_OPT_BAYES_AUTOLEARN_APPROVED, BM_GETCHECK, 0, 0));
+ _setOptB("BayesAutolearnAutoApproved", SendDlgItemMessage(optDlg, IDC_OPT_BAYES_AUTOLEARN_AUTOAPPROVED, BM_GETCHECK, 0, 0));
+ _setOptB("BayesAutolearnNotApproved", SendDlgItemMessage(optDlg, IDC_OPT_BAYES_AUTOLEARN_NOT_APPROVED, BM_GETCHECK, 0, 0));
+ _setOptB("BayesAutolearnOutgoing", SendDlgItemMessage(optDlg, IDC_OPT_BAYES_AUTOLEARN_OUTGOING, BM_GETCHECK, 0, 0));
+ _saveDlgItemScore(optDlg, IDC_OPT_BAYES_SPAM_SCORE, "BayesSpamScore");
+ _saveDlgItemScore(optDlg, IDC_OPT_BAYES_HAM_SCORE, "BayesHamScore");
+ _saveDlgItemInt(optDlg, IDC_OPT_BAYES_WAIT_APPROVE, "BayesWaitApprove");
+ break;
+ }
+ break;
+ case WM_DESTROY:
+ break;
+ }
+ return FALSE;
+}
+
+extern BOOL CALLBACK DlgProcOptionsPopups(HWND optDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+int OnOptInitialize(WPARAM wParam, LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp = {0};
+ odp.cbSize = sizeof(odp);
+ odp.position = 0;
+ odp.hInstance = hInst;
+ odp.ptszGroup = _T("Message Sessions");
+ odp.ptszTitle = _T(PLUGIN_NAME);
+ odp.flags = ODPF_TCHAR | ODPF_BOLDGROUPS;
+
+ odp.ptszTab = _T("Settings");
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_SPAMOTRON_MAIN);
+ odp.pfnDlgProc = (DLGPROC)DlgProcOptionsMain;
+ Options_AddPage(wParam, &odp);
+
+ odp.ptszTab = _T("Messages");
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_SPAMOTRON_Q);
+ odp.pfnDlgProc = (DLGPROC)DlgProcOptionsQuestion;
+ Options_AddPage(wParam, &odp);
+
+ odp.ptszTab = _T("Bayes");
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_SPAMOTRON_BAYES);
+ odp.pfnDlgProc = (DLGPROC)DlgProcOptionsBayes;
+ Options_AddPage(wParam, &odp);
+
+ if (ServiceExists(MS_POPUP_ADDPOPUP)) {
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_SPAMOTRON_POPUPS);
+ odp.pfnDlgProc = (DLGPROC)DlgProcOptionsPopups;
+ odp.ptszGroup = _T("Popups");
+ odp.ptszTab = NULL;
+ Options_AddPage(wParam, &odp);
+ }
+
+ return 0;
+}
diff --git a/plugins/Spamotron/src/popups.cpp b/plugins/Spamotron/src/popups.cpp new file mode 100644 index 0000000000..60784891bb --- /dev/null +++ b/plugins/Spamotron/src/popups.cpp @@ -0,0 +1,241 @@ +#include "common.h"
+
+extern BOOL _saveDlgItemInt(HWND hDialog, int controlID, char* option);
+
+void EnablePopupControls(HWND hwnd, BOOL enable)
+{
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_POPUPS_NOTIFY_BLOCKED), enable);
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_POPUPS_NOTIFY_APPROVED), enable);
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_POPUPS_NOTIFY_CHALLENGE), enable);
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_POPUPS_BLOCKED_FOREGROUND), enable);
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_POPUPS_BLOCKED_BACKGROUND), enable);
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_POPUPS_APPROVED_FOREGROUND), enable);
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_POPUPS_APPROVED_BACKGROUND), enable);
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_POPUPS_CHALLENGE_FOREGROUND), enable);
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_POPUPS_CHALLENGE_BACKGROUND), enable);
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_POPUPS_BLOCKED_TIMEOUT), enable);
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_POPUPS_APPROVED_TIMEOUT), enable);
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_POPUPS_CHALLENGE_TIMEOUT), enable);
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_POPUPS_DEFAULT_COLORS), enable);
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_POPUPS_WINDOWS_COLORS), enable);
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_POPUPS_DEFAULT_TIMEOUT), enable);
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_POPUPS_PREVIEW), enable);
+}
+
+void EnablePopupColors(HWND hwnd, BOOL enableDefault, BOOL enableWindows)
+{
+ BOOL enable, bEnabled;
+ bEnabled = SendDlgItemMessage(hwnd, IDC_OPT_POPUPS_ENABLED, BM_GETCHECK, 0, 0);
+ enable = enableDefault || enableWindows;
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_POPUPS_BLOCKED_FOREGROUND), !enable && bEnabled);
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_POPUPS_BLOCKED_BACKGROUND), !enable && bEnabled);
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_POPUPS_APPROVED_FOREGROUND), !enable && bEnabled);
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_POPUPS_APPROVED_BACKGROUND), !enable && bEnabled);
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_POPUPS_CHALLENGE_FOREGROUND), !enable && bEnabled);
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_POPUPS_CHALLENGE_BACKGROUND), !enable && bEnabled);
+
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_POPUPS_WINDOWS_COLORS), !enableDefault && bEnabled);
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_POPUPS_DEFAULT_COLORS), !enableWindows && bEnabled);
+}
+
+void EnablePopupTimeouts(HWND hwnd, BOOL enable)
+{
+ BOOL bEnabled = SendDlgItemMessage(hwnd, IDC_OPT_POPUPS_ENABLED, BM_GETCHECK, 0, 0);
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_POPUPS_BLOCKED_TIMEOUT), !enable && bEnabled);
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_POPUPS_APPROVED_TIMEOUT), !enable && bEnabled);
+ EnableWindow(GetDlgItem(hwnd, IDC_OPT_POPUPS_CHALLENGE_TIMEOUT), !enable && bEnabled);
+}
+
+BOOL CALLBACK DlgProcOptionsPopups(HWND optDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ BOOL bEnabled;
+ static int bInitializing = 0;
+ switch (msg) {
+ case WM_INITDIALOG:
+ bInitializing = 1;
+ TranslateDialogDefault(optDlg);
+ bEnabled = _getOptB("NotifyPopup", defaultNotifyPopup);
+ SendDlgItemMessage(optDlg, IDC_OPT_POPUPS_ENABLED, BM_SETCHECK, bEnabled, 0);
+ EnablePopupControls(optDlg, bEnabled);
+
+ SendDlgItemMessage(optDlg, IDC_OPT_POPUPS_NOTIFY_BLOCKED, BM_SETCHECK, _getOptB("NotifyPopupBlocked", defaultNotifyPopupBlocked), 0);
+ SendDlgItemMessage(optDlg, IDC_OPT_POPUPS_NOTIFY_APPROVED, BM_SETCHECK, _getOptB("NotifyPopupApproved", defaultNotifyPopupApproved), 0);
+ SendDlgItemMessage(optDlg, IDC_OPT_POPUPS_NOTIFY_CHALLENGE, BM_SETCHECK, _getOptB("NotifyPopupChallenge", defaultNotifyPopupChallenge), 0);
+ SendDlgItemMessage(optDlg, IDC_OPT_POPUPS_DEFAULT_COLORS, BM_SETCHECK, _getOptB("PopupDefaultColors", defaultPopupDefaultColors), 0);
+ SendDlgItemMessage(optDlg, IDC_OPT_POPUPS_WINDOWS_COLORS, BM_SETCHECK, _getOptB("PopupWindowsColors", defaultPopupWindowsColors), 0);
+ SendDlgItemMessage(optDlg, IDC_OPT_POPUPS_DEFAULT_TIMEOUT, BM_SETCHECK, _getOptB("PopupDefaultTimeout", defaultPopupDefaultTimeout), 0);
+ SetDlgItemInt(optDlg, IDC_OPT_POPUPS_BLOCKED_TIMEOUT, _getOptD("PopupBlockedTimeout", defaultPopupBlockedTimeout), FALSE);
+ SetDlgItemInt(optDlg, IDC_OPT_POPUPS_APPROVED_TIMEOUT, _getOptD("PopupApprovedTimeout", defaultPopupApprovedTimeout), FALSE);
+ SetDlgItemInt(optDlg, IDC_OPT_POPUPS_CHALLENGE_TIMEOUT, _getOptD("PopupChallengeTimeout", defaultPopupChallengeTimeout), FALSE);
+ SendDlgItemMessage(optDlg, IDC_OPT_POPUPS_BLOCKED_FOREGROUND, CPM_SETCOLOUR, 0, _getOptD("PopupBlockedForeground", defaultPopupBlockedForeground));
+ SendDlgItemMessage(optDlg, IDC_OPT_POPUPS_BLOCKED_BACKGROUND, CPM_SETCOLOUR, 0, _getOptD("PopupBlockedBackground", defaultPopupBlockedBackground));
+ SendDlgItemMessage(optDlg, IDC_OPT_POPUPS_APPROVED_FOREGROUND, CPM_SETCOLOUR, 0, _getOptD("PopupApprovedForeground", defaultPopupApprovedForeground));
+ SendDlgItemMessage(optDlg, IDC_OPT_POPUPS_APPROVED_BACKGROUND, CPM_SETCOLOUR, 0, _getOptD("PopupApprovedBackground", defaultPopupApprovedBackground));
+ SendDlgItemMessage(optDlg, IDC_OPT_POPUPS_CHALLENGE_FOREGROUND, CPM_SETCOLOUR, 0, _getOptD("PopupChallengeForeground", defaultPopupChallengeForeground));
+ SendDlgItemMessage(optDlg, IDC_OPT_POPUPS_CHALLENGE_BACKGROUND, CPM_SETCOLOUR, 0, _getOptD("PopupChallengeBackground", defaultPopupChallengeBackground));
+ EnablePopupTimeouts(optDlg, SendDlgItemMessage(optDlg, IDC_OPT_POPUPS_DEFAULT_TIMEOUT, BM_GETCHECK, 0, 0));
+ EnablePopupColors(optDlg,
+ _getOptB("PopupDefaultColors", defaultPopupDefaultColors),
+ _getOptB("PopupWindowsColors", defaultPopupWindowsColors));
+
+ bInitializing = 0;
+ break;
+ case WM_COMMAND:
+ if (bInitializing)
+ return FALSE;
+ switch (LOWORD(wParam)) {
+ case IDC_OPT_POPUPS_ENABLED:
+ bEnabled = SendDlgItemMessage(optDlg, IDC_OPT_POPUPS_ENABLED, BM_GETCHECK, 0, 0);
+ EnablePopupControls(optDlg, bEnabled);
+ case IDC_OPT_POPUPS_NOTIFY_BLOCKED:
+ case IDC_OPT_POPUPS_NOTIFY_APPROVED:
+ case IDC_OPT_POPUPS_NOTIFY_CHALLENGE:
+ case IDC_OPT_POPUPS_DEFAULT_COLORS:
+ case IDC_OPT_POPUPS_WINDOWS_COLORS:
+ case IDC_OPT_POPUPS_DEFAULT_TIMEOUT:
+ EnablePopupColors(optDlg,
+ SendDlgItemMessage(optDlg, IDC_OPT_POPUPS_DEFAULT_COLORS, BM_GETCHECK, 0, 0),
+ SendDlgItemMessage(optDlg, IDC_OPT_POPUPS_WINDOWS_COLORS, BM_GETCHECK, 0, 0));
+ EnablePopupTimeouts(optDlg, SendDlgItemMessage(optDlg, IDC_OPT_POPUPS_DEFAULT_TIMEOUT, BM_GETCHECK, 0, 0));
+
+ if (HIWORD(wParam) != BN_CLICKED)
+ return FALSE;
+ break;
+ case IDC_OPT_POPUPS_BLOCKED_TIMEOUT:
+ case IDC_OPT_POPUPS_APPROVED_TIMEOUT:
+ case IDC_OPT_POPUPS_CHALLENGE_TIMEOUT:
+ if (HIWORD(wParam) != EN_CHANGE)
+ return FALSE;
+ break;
+ case IDC_OPT_POPUPS_PREVIEW:
+ ShowPopupPreview(optDlg, POPUP_BLOCKED, NULL, _T("Message blocked due to preview action"));
+ ShowPopupPreview(optDlg, POPUP_APPROVED, NULL, _T("Message approved due to preview action"));
+ ShowPopupPreview(optDlg, POPUP_CHALLENGE, NULL, _T("Challenge sent to preview contact"));
+ return FALSE;
+ }
+ SendMessage(GetParent(optDlg), PSM_CHANGED, 0, 0);
+ break;
+ case WM_NOTIFY:
+ switch (((NMHDR*)lParam)->code) {
+ case PSN_APPLY:
+ _setOptB("NotifyPopup", SendDlgItemMessage(optDlg, IDC_OPT_POPUPS_ENABLED, BM_GETCHECK, 0, 0));
+ _setOptB("NotifyPopupBlocked", SendDlgItemMessage(optDlg, IDC_OPT_POPUPS_NOTIFY_BLOCKED, BM_GETCHECK, 0, 0));
+ _setOptB("NotifyPopupApproved", SendDlgItemMessage(optDlg, IDC_OPT_POPUPS_NOTIFY_APPROVED, BM_GETCHECK, 0, 0));
+ _setOptB("NotifyPopupChallenge", SendDlgItemMessage(optDlg, IDC_OPT_POPUPS_NOTIFY_CHALLENGE, BM_GETCHECK, 0, 0));
+ _setOptB("PopupDefaultColors", SendDlgItemMessage(optDlg, IDC_OPT_POPUPS_DEFAULT_COLORS, BM_GETCHECK, 0, 0));
+ _setOptB("PopupWindowsColors", SendDlgItemMessage(optDlg, IDC_OPT_POPUPS_WINDOWS_COLORS, BM_GETCHECK, 0, 0));
+ _setOptB("PopupDefaultTimeout", SendDlgItemMessage(optDlg, IDC_OPT_POPUPS_DEFAULT_TIMEOUT, BM_GETCHECK, 0, 0));
+ _saveDlgItemInt(optDlg, IDC_OPT_POPUPS_BLOCKED_TIMEOUT, "PopupBlockedTimeout");
+ _saveDlgItemInt(optDlg, IDC_OPT_POPUPS_APPROVED_TIMEOUT, "PopupApprovedTimeout");
+ _saveDlgItemInt(optDlg, IDC_OPT_POPUPS_CHALLENGE_TIMEOUT, "PopupChallengeTimeout");
+ _setOptD("PopupBlockedForeground", SendDlgItemMessage(optDlg,IDC_OPT_POPUPS_BLOCKED_FOREGROUND,CPM_GETCOLOUR,0,0));
+ _setOptD("PopupBlockedBackground", SendDlgItemMessage(optDlg,IDC_OPT_POPUPS_BLOCKED_BACKGROUND,CPM_GETCOLOUR,0,0));
+ _setOptD("PopupApprovedForeground", SendDlgItemMessage(optDlg,IDC_OPT_POPUPS_APPROVED_FOREGROUND,CPM_GETCOLOUR,0,0));
+ _setOptD("PopupApprovedBackground", SendDlgItemMessage(optDlg,IDC_OPT_POPUPS_APPROVED_BACKGROUND,CPM_GETCOLOUR,0,0));
+ _setOptD("PopupChallengeForeground", SendDlgItemMessage(optDlg,IDC_OPT_POPUPS_CHALLENGE_FOREGROUND,CPM_GETCOLOUR,0,0));
+ _setOptD("PopupChallengeBackground", SendDlgItemMessage(optDlg,IDC_OPT_POPUPS_CHALLENGE_BACKGROUND,CPM_GETCOLOUR,0,0));
+ break;
+ }
+ break;
+ case WM_DESTROY:
+ break;
+ }
+ return FALSE;
+}
+
+int ShowPopupPreview(HWND optDlg, BYTE popupType, TCHAR *line1, TCHAR *line2)
+{
+ POPUPDATAW ppdp = {0};
+ switch (popupType)
+ {
+ case POPUP_DEFAULT:
+ ppdp.colorText = SendDlgItemMessage(optDlg,IDC_OPT_POPUPS_APPROVED_FOREGROUND,CPM_GETCOLOUR,0,0);
+ ppdp.colorBack = SendDlgItemMessage(optDlg,IDC_OPT_POPUPS_APPROVED_BACKGROUND,CPM_GETCOLOUR,0,0);
+ break;
+ case POPUP_BLOCKED:
+ ppdp.colorText = SendDlgItemMessage(optDlg,IDC_OPT_POPUPS_BLOCKED_FOREGROUND,CPM_GETCOLOUR,0,0);
+ ppdp.colorBack = SendDlgItemMessage(optDlg,IDC_OPT_POPUPS_BLOCKED_BACKGROUND,CPM_GETCOLOUR,0,0);
+ ppdp.iSeconds = GetDlgItemInt(optDlg, IDC_OPT_POPUPS_BLOCKED_TIMEOUT, NULL, TRUE);
+ ppdp.lchIcon = LoadSkinnedIcon(SKINICON_OTHER_DELETE);
+ break;
+ case POPUP_APPROVED:
+ ppdp.colorText = SendDlgItemMessage(optDlg,IDC_OPT_POPUPS_APPROVED_FOREGROUND,CPM_GETCOLOUR,0,0);
+ ppdp.colorBack = SendDlgItemMessage(optDlg,IDC_OPT_POPUPS_APPROVED_BACKGROUND,CPM_GETCOLOUR,0,0);
+ ppdp.iSeconds = GetDlgItemInt(optDlg, IDC_OPT_POPUPS_APPROVED_TIMEOUT, NULL, TRUE);
+ ppdp.lchIcon = LoadSkinnedIcon(SKINICON_OTHER_ADDCONTACT);
+ break;
+ case POPUP_CHALLENGE:
+ ppdp.colorText = SendDlgItemMessage(optDlg,IDC_OPT_POPUPS_CHALLENGE_FOREGROUND,CPM_GETCOLOUR,0,0);
+ ppdp.colorBack = SendDlgItemMessage(optDlg,IDC_OPT_POPUPS_CHALLENGE_BACKGROUND,CPM_GETCOLOUR,0,0);
+ ppdp.iSeconds = GetDlgItemInt(optDlg, IDC_OPT_POPUPS_CHALLENGE_TIMEOUT, NULL, TRUE);
+ ppdp.lchIcon = LoadSkinnedIcon(SKINICON_EVENT_MESSAGE);
+ break;
+ }
+ if (SendDlgItemMessage(optDlg, IDC_OPT_POPUPS_WINDOWS_COLORS, BM_GETCHECK, 0, 0)) {
+ ppdp.colorText = GetSysColor(COLOR_WINDOWTEXT);
+ ppdp.colorBack = GetSysColor(COLOR_WINDOW);
+ }
+ if (SendDlgItemMessage(optDlg, IDC_OPT_POPUPS_DEFAULT_COLORS, BM_GETCHECK, 0, 0)) {
+ ppdp.colorText = (COLORREF)NULL;
+ ppdp.colorBack = (COLORREF)NULL;
+ }
+ if (ppdp.iSeconds < 1)
+ ppdp.iSeconds = -1;
+ if (SendDlgItemMessage(optDlg, IDC_OPT_POPUPS_DEFAULT_TIMEOUT, BM_GETCHECK, 0, 0) || popupType == POPUP_DEFAULT)
+ ppdp.iSeconds = 0;
+
+ ppdp.lchContact = NULL;
+ mir_sntprintf((WCHAR *)ppdp.lptzContactName, MAX_CONTACTNAME, _T("%s"), (line1)?line1:_T(PLUGIN_NAME));
+ if (line2)
+ mir_sntprintf((WCHAR *)ppdp.lptzText, MAX_SECONDLINE, _T("%s"), line2);
+ return PUAddPopUpW(&ppdp);
+
+}
+
+int ShowPopup(HANDLE hContact, BYTE popupType, TCHAR *line1, TCHAR *line2)
+{
+ POPUPDATAW ppdp = {0};
+ switch (popupType)
+ {
+ case POPUP_DEFAULT:
+ ppdp.colorText = _getOptD("PopupApprovedForeground", defaultPopupApprovedForeground);
+ ppdp.colorBack = _getOptD("PopupApprovedBackground", defaultPopupApprovedBackground);
+ break;
+ case POPUP_BLOCKED:
+ ppdp.colorText = _getOptD("PopupBlockedForeground", defaultPopupBlockedForeground);
+ ppdp.colorBack = _getOptD("PopupBlockedBackground", defaultPopupBlockedBackground);
+ ppdp.iSeconds = _getOptD("PopupBlockedTimeout", defaultPopupBlockedTimeout);
+ ppdp.lchIcon = LoadSkinnedIcon(SKINICON_OTHER_DELETE);
+ break;
+ case POPUP_APPROVED:
+ ppdp.colorText = _getOptD("PopupApprovedForeground", defaultPopupApprovedForeground);
+ ppdp.colorBack = _getOptD("PopupApprovedBackground", defaultPopupApprovedBackground);
+ ppdp.iSeconds = _getOptD("PopupApprovedTimeout", defaultPopupApprovedTimeout);
+ ppdp.lchIcon = LoadSkinnedIcon(SKINICON_OTHER_ADDCONTACT);
+ break;
+ case POPUP_CHALLENGE:
+ ppdp.colorText = _getOptD("PopupChallengeForeground", defaultPopupChallengeForeground);
+ ppdp.colorBack = _getOptD("PopupChallengeBackground", defaultPopupChallengeBackground);
+ ppdp.iSeconds = _getOptD("PopupChallengeTimeout", defaultPopupChallengeTimeout);
+ ppdp.lchIcon = LoadSkinnedIcon(SKINICON_EVENT_MESSAGE);
+ break;
+ }
+ if (_getOptB("PopupWindowsColors", defaultPopupWindowsColors)) {
+ ppdp.colorText = GetSysColor(COLOR_WINDOWTEXT);
+ ppdp.colorBack = GetSysColor(COLOR_WINDOW);
+ }
+ if (_getOptB("PopupDefaultColors", defaultPopupDefaultColors)) {
+ ppdp.colorText = (COLORREF)NULL;
+ ppdp.colorBack = (COLORREF)NULL;
+ }
+ if (ppdp.iSeconds < 1)
+ ppdp.iSeconds = -1;
+ if (_getOptB("PopupDefaultTimeout", defaultPopupDefaultTimeout) || popupType == POPUP_DEFAULT)
+ ppdp.iSeconds = 0;
+
+ ppdp.lchContact = hContact;
+ mir_sntprintf((WCHAR *)ppdp.lptzContactName, MAX_CONTACTNAME, _T("%s"), (line1)?line1:_T(PLUGIN_NAME));
+ if (line2)
+ mir_sntprintf((WCHAR *)ppdp.lptzText, MAX_SECONDLINE, _T("%s"), line2);
+ return PUAddPopUpW(&ppdp);
+}
\ No newline at end of file diff --git a/plugins/Spamotron/src/resource.h b/plugins/Spamotron/src/resource.h new file mode 100644 index 0000000000..31f5166fe9 --- /dev/null +++ b/plugins/Spamotron/src/resource.h @@ -0,0 +1,90 @@ +//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by spamotron.rc
+//
+#define IDD_SPAMOTRON_MAIN 101
+#define IDD_SPAMOTRON_Q 102
+#define IDD_SPAMOTRON_BAYES 103
+#define IDD_SPAMOTRON_POPUPS 104
+#define IDD_SPAMOTRON_MAIN1 105
+#define IDC_OPT_OUT_MSG_APPROVE 1002
+#define IDC_OPT_MODE 1003
+#define IDC_OPT_CHALLENGE 1004
+#define IDC_OPT_RESPONSE 1005
+#define IDC_OPT_SUCCESS_RESPONSE 1006
+#define IDC_OPT_AUTH_CHALLENGE 1007
+#define IDC_OPT_MATH_RESPONSE 1008
+#define IDC_STATIC_RESPONSE 1009
+#define IDC_STATIC_MODEMSG 1010
+#define IDC_DEFAULTS 1011
+#define IDC_OPT_PROTOCOLS 1012
+#define IDC_OPT_REPLY_ON_SUCCESS 1013
+#define IDC_OPT_DONT_REPLY_SAME_MSG 1014
+#define IDC_OPT_REPLY_ON_AUTH 1015
+#define IDC_OPT_BAYES_AUTOLEARN_APPROVED 1016
+#define IDC_OPT_POPUPS_NOTIFY_APPROVED 1017
+#define IDC_OPT_LOG_ACTIONS 1019
+#define IDC_OPT_MAX_MSG_CONTACT 1023
+#define IDC_OPT_DONT_REPLY_MSG_WORDLIST 1024
+#define IDC_OPT_MAX_SAME_MSG 1025
+#define IDC_OPT_IN_MSG_APPROVE 1027
+#define IDC_OPT_IN_MSG_APPROVE_WORDLIST 1028
+#define IDC_OPT_DONT_REPLY_MSG 1029
+#define IDC_OPT_HIDE_UNTIL_VERIFIED 1033
+#define IDC_OPT_ADD_PERMANENTLY 1034
+#define IDC_OPT_BAYES_SPAM 1036
+#define IDC_OPT_POPUPS_PREVIEW 1036
+#define IDC_OPT_KEEP_BLOCKED_MSG 1037
+#define IDC_OPT_BAYES_BLOCK_MSG 1039
+#define IDC_OPT_BAYES_AUTOLEARN_OUTGOING 1041
+#define IDC_OPT_BAYES_LEARNBOX 1042
+#define IDC_OPT_BAYES_HAM 1043
+#define IDC_OPT_BAYES_SPAM_SCORE 1044
+#define IDC_OPT_BAYES_AUTO_APPROVE 1045
+#define IDC_EDIT3 1046
+#define IDC_OPT_BAYES_HAM_SCORE 1046
+#define IDC_STATIC_HAM_COUNT 1047
+#define IDC_STATIC_SPAM_COUNT 1048
+#define IDC_CHECK_MSG 1049
+#define IDC_OPT_BAYES_AUTOLEARN_NOT_APPROVED 1050
+#define IDC_OPT_BAYES_WAIT_APPROVE 1051
+#define IDC_OPT_BAYES_ENABLED 1052
+#define IDC_OPT_FILTERING_GROUP 1053
+#define IDC_OPT_LEARNING_GROUP 1054
+#define IDC_OPT_BAYES_AUTOLEARN_NOT_APPROVED2 1055
+#define IDC_OPT_CCRESPONSE 1056
+#define IDC_OPT_BAYES_AUTOLEARN_AUTOAPPROVED 1058
+#define IDC_STATIC_DAYSASSPAM 1059
+#define IDC_STATIC_SPAMCOUNT_LABEL 1060
+#define IDC_STATIC_HAMCOUNT_LABEL 1061
+#define IDC_OPT_REPLY_ON_MSG 1062
+#define IDC_OPT_POPUPS_ENABLE 1063
+#define IDC_OPT_POPUPS_ENABLED 1063
+#define IDC_OPT_POPUPS_NOTIFY_BLOCKED 1064
+#define IDC_OPT_POPUPS_BLOCKED_FOREGROUND 1065
+#define IDC_OPT_POPUPS_BLOCKED_BACKGROUND 1066
+#define IDC_OPT_POPUPS_APPROVED_FOREGROUND 1067
+#define IDC_OPT_POPUPS_APPROVED_BACKGROUND 1068
+#define IDC_OPT_POPUPS_CHALLENGE_FOREGROUND 1069
+#define IDC_OPT_POPUPS_CHALLENGE_BACKGROUND 1070
+#define IDC_OPT_POPUPS_BLOCKED_TIMEOUT 1073
+#define IDC_OPT_POPUPS_APPROVED_TIMEOUT 1074
+#define IDC_OPT_POPUPS_CHALLENGE_TIMEOUT 1075
+#define IDC_OPT_POPUPS_DEFAULT_COLORS 1076
+#define IDC_OPT_POPUPS_DEFAULT_TIMEOUT 1077
+#define IDC_OPT_POPUPS_WINDOWS_COLORS 1078
+#define IDC_OPT_POPUPS_NOTIFY_CHALLENGE 1079
+#define IDC_OPT_MARK_MSG_AS_NEW_ON_APPROVAL 1080
+#define IDC_OPT_MARK_MSG_UNREAD_ON_APPROVAL 1080
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NO_MFC 1
+#define _APS_NEXT_RESOURCE_VALUE 105
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1081
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/plugins/Spamotron/src/spamotron.cpp b/plugins/Spamotron/src/spamotron.cpp new file mode 100644 index 0000000000..1d9e721712 --- /dev/null +++ b/plugins/Spamotron/src/spamotron.cpp @@ -0,0 +1,588 @@ +#include "common.h"
+
+HINSTANCE hInst;
+HANDLE hOptInitialize, hModulesLoaded, hDBContactAdded, hDBEventAdded, hDBEventFilterAdd;
+time_t last_queue_check = 0;
+int hLangpack;
+
+#define MIID_SPAMOTRON {0x14331048,0x5a73,0x4fdb,{0xb9,0x09,0x2d,0x7e,0x18,0x25,0xa0,0x12}} /* 14331048-5a73-4fdb-b909-2d7e1825a012 */
+
+PLUGININFOEX pluginInfo = {
+ sizeof(PLUGININFOEX),
+ PLUGIN_NAME,
+ PLUGIN_MAKE_VERSION(0,0,4,6),
+ "Anti-spam plugin with captcha and Bayes filtering",
+ "vu1tur",
+ "to@vu1tur.eu.org",
+ "© 2010 vu1tur",
+ "http://vu1tur.eu.org/spamotron",
+ UNICODE_AWARE,
+ MIID_SPAMOTRON
+};
+
+
+
+extern int OnOptInitialize(WPARAM wParam, LPARAM lParam);
+
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ hInst = hinstDLL;
+ return TRUE;
+}
+
+int OnModulesLoaded(WPARAM wParam, LPARAM lParam)
+{
+ hOptInitialize = HookEvent(ME_OPT_INITIALISE, OnOptInitialize);
+
+ return 0;
+}
+
+int OnDBContactAdded(WPARAM wParam, LPARAM lParam)
+{
+ //MessageBox(NULL, _T("OnDBContactAdded"), _T("Event"), MB_OK);
+ return 0;
+}
+
+int OnDBEventAdded(WPARAM wParam, LPARAM lParam)
+{
+
+ return 0;
+}
+
+int OnDBEventFilterAdd(WPARAM wParam, LPARAM lParam)
+{
+ HANDLE hContact = (HANDLE)wParam;
+ DBEVENTINFO *dbei = (DBEVENTINFO *)lParam;
+ char *msgblob;
+ POPUPDATA ppdp = {0};
+ DBTIMETOSTRING tts = {0};
+ char protoOption[256] = {0};
+ char *response, *tmp, *challenge;
+ int buflen = MAX_BUFFER_LENGTH;
+ TCHAR buf[MAX_BUFFER_LENGTH];
+ TCHAR *message = NULL, *challengeW = NULL, *tmpW = NULL;
+ TCHAR *whitelist = NULL, *ptok;
+ TCHAR mexpr[64];
+ int maxmsglen = 0, a, b, i;
+ BOOL bayesEnabled = _getOptB("BayesEnabled", defaultBayesEnabled);
+ BOOL bCorrectResponse = FALSE;
+
+ // get hContact from DBEVENTINFO as icq_proto.c doesn't pass hContact the usual way for some reason.
+ if (dbei->eventType == EVENTTYPE_AUTHREQUEST)
+ hContact = *((PHANDLE)(dbei->pBlob+sizeof(DWORD)));
+
+ // get maximum length of the message a protocol supports
+ maxmsglen = CallProtoService(dbei->szModule, PS_GETCAPS, PFLAG_MAXLENOFMESSAGE, (LPARAM)hContact);
+
+
+ /*** Dequeue and learn messages ***/
+
+ if (bayesEnabled && _getOptB("BayesAutolearnNotApproved", defaultBayesAutolearnNotApproved))
+ if (time(NULL) - last_queue_check > 4*3600) { // dequeue every 4 hours
+ dequeue_messages();
+ last_queue_check = time(NULL);
+ }
+
+
+ /*** Check for conditional and unconditional approval ***/
+
+ // Pass-through if protocol is not enabled
+ strcat(protoOption, "proto_");
+ strcat(protoOption, dbei->szModule);
+ if (_getOptB(protoOption, 0) == 0) // Protocol is not handled by Spam-o-tron
+ return 0;
+
+ // Pass-through if the event is not of type EVENTTYPE_MESSAGE or EVENTTYPE_AUTHREQUEST
+ if (dbei->eventType != EVENTTYPE_MESSAGE && dbei->eventType != EVENTTYPE_AUTHREQUEST)
+ return 0;
+
+ // Pass-through if contact is already verified.
+ if (_getCOptB(hContact, "Verified", 0) == 1)
+ return 0;
+
+ // Pass-through if the event is already read.
+ if (dbei->flags & DBEF_READ)
+ return 0;
+
+ // Pass-through if event is from a contact that is already in the list.
+ if (db_get_b(hContact, "CList", "NotOnList", 1) == 0) // Already in the list
+ return 0;
+
+ // Pass-through if event is from a contact that is already in the server-side contact list
+ if (db_get_w(hContact, dbei->szModule, "ServerId", 0))
+ return 0;
+
+ // Pass-through if contact is a MetaContact
+ if (db_get_dw(hContact, "MetaContacts", "NumContacts", 0))
+ return 0;
+
+ // Pass-through and approve if outgoing event.
+ if (dbei->flags & DBEF_SENT) {
+ if (_getOptB("ApproveOnMsgOut", 0)) {
+ _setCOptB(hContact, "Verified", 1);
+ if (_getOptB("AddPermanently", defaultAddPermanently))
+ db_unset(hContact, "CList", "NotOnList");
+ db_unset(hContact, "CList", "Delete");
+ }
+ return 0;
+ }
+
+ // Hide the contact until verified if option set.
+ if (_getOptB("HideUnverified", defaultHideUnverified))
+ db_set_b(hContact, "CList", "Hidden", 1);
+
+ // Fetch the incoming message body
+ if (dbei->eventType == EVENTTYPE_MESSAGE) {
+ msgblob = (char *)dbei->pBlob;
+ } else if (dbei->eventType == EVENTTYPE_AUTHREQUEST) {
+ msgblob = (char *)(dbei->pBlob + sizeof(DWORD) + sizeof(HANDLE));
+ for(a=4;a>0;a--)
+ msgblob += strlen(msgblob)+1;
+ }
+
+ if (dbei->flags & DBEF_UTF)
+ message = mir_utf8decodeW(msgblob);
+ else
+ message = mir_a2u(msgblob);
+
+
+ /*** Check for words in white-list ***/
+
+ if (_getOptB("ApproveOnMsgIn", defaultApproveOnMsgIn)) {
+ whitelist = (TCHAR*)malloc(2048 * sizeof(TCHAR));
+ if (whitelist != NULL) {
+ _getOptS(whitelist, 2048, "ApproveOnMsgInWordlist", defaultApproveOnMsgInWordlist);
+ if (_isregex(whitelist)) {
+ if (_regmatch(message, whitelist))
+ bCorrectResponse = TRUE;
+ } else {
+ ptok = _tcstok(whitelist, L" ");
+ while (ptok != NULL) {
+ if (_tcsstr(message, ptok)) {
+ bCorrectResponse = TRUE;
+ break;
+ }
+ ptok = _tcstok(NULL, L" ");
+ }
+ }
+ free(whitelist);
+
+ if (bCorrectResponse) {
+ _setCOptB(hContact, "Verified", 1);
+ if (_getOptB("HideUnverified", defaultHideUnverified))
+ db_unset(hContact, "CList", "Hidden");
+ if (_getOptB("AddPermanently", defaultAddPermanently))
+ db_unset(hContact, "CList", "NotOnList");
+ db_unset(hContact, "CList", "Delete");
+ if (_getOptB("ReplyOnSuccess", defaultReplyOnSuccess) && (_getCOptB(hContact, "MsgSent", 0))) {
+ tmp = mir_u2a(_getOptS(buf, buflen, "SuccessResponse", defaultSuccessResponse));
+ response = mir_utf8encode(tmp);
+ mir_free(tmp);
+ CallContactService(hContact, PSS_MESSAGE, PREF_UTF, (LPARAM)response);
+ mir_free(response);
+ }
+ return 0;
+ }
+ }
+ }
+
+
+ /*** Check for correct answer ***/
+
+ switch (_getOptB("Mode", defaultMode))
+ {
+ case SPAMOTRON_MODE_ROTATE:
+ case SPAMOTRON_MODE_RANDOM:
+ get_response(buf, buflen, _getCOptD(hContact, "ResponseNum", 0));
+ if (_isregex(buf)) {
+ if (_regmatch(message, buf))
+ bCorrectResponse = TRUE;
+ } else {
+ if (_tcsstr_cc(message, buf, _getOptB("ResponseCC", defaultResponseCC)) &&
+ (_tcslen(message) == _tcslen(buf)))
+ bCorrectResponse = TRUE;
+ }
+ break;
+
+ case SPAMOTRON_MODE_PLAIN:
+ _getOptS(buf, buflen, "Response", defaultResponse);
+ i = get_response_num(buf);
+ while (i-- > 0) {
+ get_response(buf, buflen, i-1);
+ if (_isregex(buf)) {
+ if (_regmatch(message, buf)) {
+ bCorrectResponse = TRUE;
+ break;
+ }
+ } else {
+ if (_tcsstr_cc(message, buf, _getOptB("ResponseCC", defaultResponseCC)) &&
+ (_tcslen(message) == _tcslen(buf))) {
+ bCorrectResponse = TRUE;
+ break;
+ }
+ }
+ }
+ break;
+
+ case SPAMOTRON_MODE_MATH:
+ if (message == NULL)
+ break;
+ _itot(_getCOptD(hContact, "ResponseMath", -1), buf, 10);
+ if (_tcsstr(message, buf) && (_tcslen(buf) == _tcslen(message))) {
+ bCorrectResponse = TRUE;
+ }
+ break;
+ }
+
+ if (bCorrectResponse)
+ {
+ _setCOptB(hContact, "Verified", 1);
+ if (_getOptB("HideUnverified", defaultHideUnverified))
+ db_unset(hContact, "CList", "Hidden");
+ if (_getOptB("AddPermanently", defaultAddPermanently))
+ db_unset(hContact, "CList", "NotOnList");
+ db_unset(hContact, "CList", "Delete");
+ db_unset(hContact, "CList", "ResponseNum");
+ if (_getOptB("ReplyOnSuccess", defaultReplyOnSuccess)) {
+ tmp = mir_u2a(_getOptS(buf, buflen, "SuccessResponse", defaultSuccessResponse));
+ response = mir_utf8encode(tmp);
+ mir_free(tmp);
+ CallContactService(hContact, PSS_MESSAGE, PREF_UTF, (LPARAM)response);
+ mir_free(response);
+ }
+ _notify(hContact, POPUP_APPROVED, TranslateT("Contact %s approved."), NULL);
+
+ // Resubmit pending authorization request
+ if (_getCOptB(hContact, "AuthEventPending", FALSE)) {
+ DBVARIANT _dbv;
+ TCHAR AuthEventModule[100];
+ char* szAuthEventModule;
+ if (db_get(hContact, PLUGIN_NAME, "AuthEvent", &_dbv) == 0) {
+ DBEVENTINFO *_dbei = NULL;
+ _dbei = (DBEVENTINFO *)malloc(sizeof(DBEVENTINFO));
+ if (_dbei != NULL) {
+ memcpy(&_dbei->cbBlob, _dbv.pbVal, sizeof(DWORD));
+ _dbei->eventType = EVENTTYPE_AUTHREQUEST;
+ _getCOptS(AuthEventModule, 100, hContact, "AuthEventModule", _T("ICQ"));
+ szAuthEventModule = mir_u2a(AuthEventModule);
+ _dbei->szModule = szAuthEventModule;
+ _dbei->timestamp = dbei->timestamp;
+ _dbei->flags = 0;
+ _dbei->cbSize = sizeof(DBEVENTINFO);
+ _dbei->pBlob = _dbv.pbVal + sizeof(DWORD);
+ CallService(MS_DB_EVENT_ADD, (WPARAM)hContact, (LPARAM)_dbei);
+ db_unset(hContact, PLUGIN_NAME, "AuthEvent");
+ db_unset(hContact, PLUGIN_NAME, "AuthEventPending");
+ db_unset(hContact, PLUGIN_NAME, "AuthEventModule");
+ mir_free(szAuthEventModule);
+ free(_dbei);
+ }
+ db_free(&_dbv);
+ }
+ }
+
+ // User approved, learn from previous messages
+ if (bayesEnabled && _getOptB("BayesAutolearnApproved", defaultBayesAutolearnApproved))
+ bayes_approve_contact(hContact);
+
+ // Mark previous messages unread if option set
+ if (_getOptB("KeepBlockedMsg", defaultKeepBlockedMsg) &&
+ _getOptB("MarkMsgUnreadOnApproval", defaultMarkMsgUnreadOnApproval) &&
+ hContact != NULL) {
+ // We will mark unread all blocked messages for the most recent day
+ MarkUnread(hContact);
+ }
+
+ return 1;
+ }
+
+
+
+ /*** Check for rejection ***/
+
+ // Completely reject if challenge was already sent today for MaxMsgContactCountPerDay times
+ // and the option is turned on.
+ if (isOneDay(dbei->timestamp, _getCOptD(hContact, "MsgSentTime", 0)) &&
+ _getOptD("MaxMsgContactCountPerDay", defaultMaxMsgContactCountPerDay) > 0 &&
+ _getCOptD(hContact, "MsgSent", 0) >= _getOptD("MaxMsgContactCountPerDay", defaultMaxMsgContactCountPerDay)) {
+ _notify(hContact, POPUP_BLOCKED, TranslateT("Message from %s rejected because it reached a maximum for challenge requests per day."), message);
+ if (bayesEnabled)
+ queue_message(hContact, dbei->timestamp, message);
+ return 1;
+ }
+
+ // Completely reject if duplicate incoming message found
+ if (_getOptD("MaxSameMsgCountPerDay", defaultMaxSameMsgCountPerDay) > 0 &&
+ _getCOptD(hContact, "SameMsgCount", 0) >= _getOptD("MaxSameMsgCountPerDay", defaultMaxSameMsgCountPerDay) &&
+ _tcscmp(message, _getCOptS(buf, buflen, hContact, "LastInMsg", _T(""))) == 0) {
+ _notify(hContact, POPUP_BLOCKED, TranslateT("Message from %s rejected because it reached a maximum for same responses per day."), message);
+ if (bayesEnabled)
+ queue_message(hContact, dbei->timestamp, message);
+ return 1;
+ }
+
+ // Completely reject if incoming message contains any word from DontReplyMsgWordlist option
+ if (_getOptB("DontReplyMsg", defaultDontReplyMsg) &&
+ Contains(message, _getOptS(buf, buflen, "DontReplyMsgWordlist", defaultDontReplyMsgWordlist))) {
+ _notify(hContact, POPUP_BLOCKED, TranslateT("Message from %s dropped because it has a word from black list."), message);
+ return 1;
+ }
+
+
+ /*** Bayes checks ***/
+
+ // Drop if score > spam score
+ if (bayesEnabled && _getOptB("BayesBlockMsg", defaultBayesBlockMsg))
+ if (get_msg_score(message) >= (double)_getOptD("BayesSpamScore", defaultBayesSpamScore) * SCORE_C) {
+ _notify(hContact, POPUP_BLOCKED, TranslateT("Message from %s dropped because of high spam score."), message);
+ if (bayesEnabled && _getOptB("BayesAutolearnNotApproved", defaultBayesAutolearnNotApproved))
+ queue_message(hContact, dbei->timestamp, message);
+ return 1;
+ }
+
+ // Accept if score < ham score
+ if (bayesEnabled && _getOptB("BayesAutoApprove", defaultBayesAutoApprove))
+ if (get_msg_score(message) <= (double)_getOptD("BayesHamScore", defaultBayesHamScore) * SCORE_C) {
+ _notify(hContact, POPUP_APPROVED, TranslateT("Contact %s approved."), message);
+ _setCOptB(hContact, "Verified", 1);
+ if (_getOptB("HideUnverified", defaultHideUnverified))
+ db_unset(hContact, "CList", "Hidden");
+ if (_getOptB("AddPermanently", defaultAddPermanently))
+ db_unset(hContact, "CList", "NotOnList");
+ db_unset(hContact, "CList", "Delete");
+ if (bayesEnabled &&
+ _getOptB("BayesAutolearnApproved", defaultBayesAutolearnApproved) &&
+ _getOptB("BayesAutolearnAutoApproved", defaultBayesAutolearnAutoApproved)) {
+ queue_message(hContact, dbei->timestamp, message);
+ bayes_approve_contact(hContact);
+ }
+ return 0;
+ }
+
+ // Accept if event is EVENTTYPE_AUTHREQUEST and ReplyOnAuth is NOT set
+ if (dbei->eventType == EVENTTYPE_AUTHREQUEST && !_getOptB("ReplyOnAuth", defaultReplyOnAuth))
+ return 0;
+ // Accept if event is EVENTTYPE_MESSAGE and ReplyOnMsg is NOT set
+ if (dbei->eventType == EVENTTYPE_MESSAGE && !_getOptB("ReplyOnMsg", defaultReplyOnMsg))
+ return 0;
+
+ /*** Send Challenge ***/
+
+ challengeW = (TCHAR *)malloc(maxmsglen*sizeof(TCHAR));
+ tmpW = (TCHAR *)malloc(maxmsglen*sizeof(TCHAR));
+ switch (_getOptB("Mode", defaultMode))
+ {
+ case SPAMOTRON_MODE_PLAIN:
+ if (dbei->eventType == EVENTTYPE_AUTHREQUEST)
+ _getOptS(challengeW, maxmsglen, "AuthChallenge", defaultAuthChallenge);
+ else
+ _getOptS(challengeW, maxmsglen, "Challenge", defaultChallenge);
+ ReplaceVars(challengeW, maxmsglen);
+ tmp = mir_u2a(challengeW);
+ challenge = mir_utf8encode(tmp);
+ mir_free(tmp);
+ CallContactService(hContact, PSS_MESSAGE, PREF_UTF, (LPARAM)challenge);
+ mir_free(challenge);
+ _notify(hContact, POPUP_CHALLENGE, TranslateT("Sending plain challenge to %s."), message);
+ break;
+
+ case SPAMOTRON_MODE_ROTATE:
+ if (dbei->eventType == EVENTTYPE_AUTHREQUEST)
+ _getOptS(challengeW, maxmsglen, "AuthChallenge", defaultAuthChallenge);
+ else
+ _getOptS(challengeW, maxmsglen, "Challenge", defaultChallenge);
+ _getOptS(buf, buflen, "Response", defaultResponse);
+ if (_getCOptD(hContact, "ResponseNum", 0) >= (unsigned int)(get_response_num(buf)-1)) {
+ _setCOptD(hContact, "ResponseNum", -1);
+ }
+ _setCOptD(hContact, "ResponseNum", _getCOptD(hContact, "ResponseNum", -1) + 1);
+ ReplaceVarsNum(challengeW, maxmsglen, _getCOptD(hContact, "ResponseNum", 0));
+
+ tmp = mir_u2a(challengeW);
+ challenge = mir_utf8encode(tmp);
+ mir_free(tmp);
+ CallContactService(hContact, PSS_MESSAGE, PREF_UTF, (LPARAM)challenge);
+ mir_free(challenge);
+ _notify(hContact, POPUP_CHALLENGE, TranslateT("Sending round-robin challenge to %s."), message);
+ break;
+
+ case SPAMOTRON_MODE_RANDOM:
+ if (dbei->eventType == EVENTTYPE_AUTHREQUEST)
+ _getOptS(challengeW, maxmsglen, "AuthChallenge", defaultAuthChallenge);
+ else
+ _getOptS(challengeW, maxmsglen, "Challenge", defaultChallenge);
+ _getOptS(buf, buflen, "Response", defaultResponse);
+ srand(time(NULL));
+ _setCOptD(hContact, "ResponseNum", rand() % get_response_num(buf));
+ ReplaceVarsNum(challengeW, maxmsglen, _getCOptD(hContact, "ResponseNum", 0));
+ tmp = mir_u2a(challengeW);
+ challenge = mir_utf8encode(tmp);
+ mir_free(tmp);
+ CallContactService(hContact, PSS_MESSAGE, PREF_UTF, (LPARAM)challenge);
+ mir_free(challenge);
+ _notify(hContact, POPUP_CHALLENGE, TranslateT("Sending random challenge to %s."), message);
+ break;
+
+ case SPAMOTRON_MODE_MATH:
+ a = (rand() % 10) + 1;
+ b = (rand() % 10) + 1;
+ mir_sntprintf(mexpr, sizeof(mexpr), _T("%d + %d"), a, b);
+ if (dbei->eventType == EVENTTYPE_AUTHREQUEST)
+ _getOptS(challengeW, maxmsglen, "AuthChallengeMath", defaultAuthChallengeMath);
+ else
+ _getOptS(challengeW, maxmsglen, "ChallengeMath", defaultChallengeMath);
+ ReplaceVar(challengeW, maxmsglen, _T("%mathexpr%"), mexpr);
+ _setCOptD(hContact, "ResponseMath", a + b);
+ tmp = mir_u2a(challengeW);
+ challenge = mir_utf8encode(tmp);
+ mir_free(tmp);
+ CallContactService(hContact, PSS_MESSAGE, PREF_UTF, (LPARAM)challenge);
+ mir_free(challenge);
+ _notify(hContact, POPUP_CHALLENGE, TranslateT("Sending math expression challenge to %s."), message);
+ break;
+ }
+ free(challengeW);
+ free(tmpW);
+
+ // As a workaround for temporary NotOnList contact not being deleted from server-side list
+ // (which was added by the ICQ server itself upon first outgoing challenge request message)
+ // we need to set Delete setting, so that contacts gets deleted on next restart/connect.
+ db_set_b(hContact, "CList", "Delete", 1);
+
+ // Queue user message in Bayes db
+ if (bayesEnabled && message != NULL)
+ queue_message(hContact, dbei->timestamp, message);
+
+
+ /*** Do any post-send procedures we need to do ***/
+
+ // Increment MsgSent if it was sent the same day. Otherwise set it to 1.
+ if (isOneDay(dbei->timestamp, _getCOptD(hContact, "MsgSentTime",0)))
+ _setCOptD(hContact, "MsgSent", _getCOptD(hContact, "MsgSent", 0)+1);
+ else
+ _setCOptD(hContact, "MsgSent", 1);
+ _setCOptD(hContact, "MsgSentTime", dbei->timestamp);
+
+ // Save Last Msg and update SameMsgCount
+ if (message != NULL) {
+ if (_tcscmp(_getCOptS(buf, buflen, hContact, "LastInMsg", _T("")), message) == 0)
+ _setCOptD(hContact, "SameMsgCount", 1+_getCOptD(hContact, "SameMsgCount", 0));
+ else
+ _setCOptD(hContact, "SameMsgCount", 1);
+ _setCOptTS(hContact, "LastInMsg", message);
+ }
+
+ if (message != NULL)
+ mir_free(message);
+
+ // Finally silently save the message to contact history if corresponding option is set
+ if (_getOptB("KeepBlockedMsg", defaultKeepBlockedMsg)) {
+ if (dbei->eventType == EVENTTYPE_AUTHREQUEST) {
+ // Save the request to database so that it can be automatically submitted on user approval
+ PBYTE eventdata = (PBYTE)malloc(sizeof(DWORD) + dbei->cbBlob);
+ if (eventdata != NULL && dbei->cbBlob > 0) {
+ memcpy(eventdata, &dbei->cbBlob, sizeof(DWORD));
+ memcpy(eventdata + sizeof(DWORD), dbei->pBlob, dbei->cbBlob);
+ db_set_blob(hContact, PLUGIN_NAME, "AuthEvent", eventdata, sizeof(DWORD) + dbei->cbBlob);
+ _setCOptS(hContact, "AuthEventModule", dbei->szModule);
+ _setCOptB(hContact, "AuthEventPending", TRUE);
+ free(eventdata);
+ }
+ } else {
+ if (_getOptB("MarkMsgUnreadOnApproval", defaultMarkMsgUnreadOnApproval)) {
+ DBVARIANT _dbv;
+ DWORD dbei_size = 3*sizeof(DWORD) + sizeof(WORD) + dbei->cbBlob + (DWORD)strlen(dbei->szModule)+1;
+ PBYTE eventdata = (PBYTE)malloc(dbei_size);
+ PBYTE pos = eventdata;
+ if (eventdata != NULL && dbei->cbBlob > 0) {
+ if (db_get(hContact, PLUGIN_NAME, "LastMsgEvents", &_dbv) == 0) {
+ eventdata = (PBYTE)realloc(eventdata, dbei_size + _dbv.cpbVal);
+ pos = eventdata;
+ memcpy(eventdata, _dbv.pbVal, _dbv.cpbVal);
+ pos += _dbv.cpbVal;
+ db_free(&_dbv);
+ }
+ memcpy(pos, &dbei->eventType, sizeof(WORD));
+ memcpy(pos+sizeof(WORD), &dbei->flags, sizeof(DWORD));
+ memcpy(pos+sizeof(WORD)+sizeof(DWORD), &dbei->timestamp, sizeof(DWORD));
+ memcpy(pos+sizeof(WORD)+sizeof(DWORD)*2, dbei->szModule, strlen(dbei->szModule)+1);
+ memcpy(pos+sizeof(WORD)+sizeof(DWORD)*2+strlen(dbei->szModule)+1, &dbei->cbBlob, sizeof(DWORD));
+ memcpy(pos+sizeof(WORD)+sizeof(DWORD)*3+strlen(dbei->szModule)+1, dbei->pBlob, dbei->cbBlob);
+ db_set_blob(hContact, PLUGIN_NAME, "LastMsgEvents", eventdata, (pos - eventdata) + dbei_size);
+ free(eventdata);
+ }
+
+ } else {
+ dbei->flags |= DBEF_READ;
+ CallService(MS_DB_EVENT_ADD, (WPARAM)hContact, (LPARAM)dbei);
+ }
+ }
+ }
+ return 1;
+}
+
+/* Removes NotOnList settings from contacts with Delete setting present */
+void RemoveNotOnListSettings()
+{
+ DBVARIANT dbv;
+ char protoName[256] = {0};
+ HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ strcpy(protoName, "proto_");
+ while (hContact != NULL) {
+ if (db_get_s(hContact, "Protocol", "p", &dbv) == 0) {
+ strcat(protoName, dbv.pszVal);
+ if (_getOptB(protoName, 0) != 0) {
+ if (db_get_b(hContact, "CList", "Delete", 0) == 1) {
+ db_unset(hContact, "CList", "NotOnList");
+ }
+ }
+ db_free(&dbv);
+ }
+ protoName[6] = 0;
+ hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0);
+ }
+}
+
+extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion)
+{
+ return &pluginInfo;
+}
+
+static const MUUID interfaces[] = {MIID_SPAMOTRON, MIID_LAST};
+extern "C" __declspec(dllexport) const MUUID* MirandaPluginInterfaces(void)
+{
+ return interfaces;
+}
+
+extern "C" __declspec(dllexport) int Load()
+{
+ mir_getLP(&pluginInfo);
+ srand((unsigned)time(0));
+ bayesdb = NULL;
+ if (_getOptB("BayesEnabled", defaultBayesEnabled)) {
+ if (CheckBayes()) {
+ OpenBayes();
+ if (_getOptB("BayesAutolearnNotApproved", defaultBayesAutolearnNotApproved)) {
+ dequeue_messages();
+ last_queue_check = time(NULL);
+ }
+ }
+ }
+
+ hModulesLoaded = HookEvent(ME_SYSTEM_MODULESLOADED, OnModulesLoaded);
+ hDBContactAdded = HookEvent(ME_DB_CONTACT_ADDED, OnDBContactAdded);
+ hDBEventAdded = HookEvent(ME_DB_EVENT_ADDED, OnDBEventAdded);
+ hDBEventFilterAdd = HookEvent(ME_DB_EVENT_FILTER_ADD, OnDBEventFilterAdd);
+ return 0;
+}
+
+extern "C" _declspec(dllexport) int Unload(void)
+{
+ RemoveNotOnListSettings();
+ UnhookEvent(hOptInitialize);
+ UnhookEvent(hModulesLoaded);
+ UnhookEvent(hDBContactAdded);
+ UnhookEvent(hDBEventAdded);
+ UnhookEvent(hDBEventFilterAdd);
+ return 0;
+}
\ No newline at end of file diff --git a/plugins/Spamotron/src/utils.cpp b/plugins/Spamotron/src/utils.cpp new file mode 100644 index 0000000000..ca31eda236 --- /dev/null +++ b/plugins/Spamotron/src/utils.cpp @@ -0,0 +1,521 @@ +#include "common.h"
+#include <locale.h>
+
+TCHAR *_tcstolower(TCHAR *dst)
+{
+ unsigned int i = 0;
+ setlocale(LC_ALL, "");
+ if (!dst)
+ return NULL;
+ for (i = 0; i < _tcslen(dst); i++)
+ dst[i] = _totlower(dst[i]);
+ return dst;
+}
+
+TCHAR *_tcstoupper(TCHAR *dst)
+{
+ unsigned int i = 0;
+ setlocale(LC_ALL, "");
+ if (!dst)
+ return NULL;
+ for (i = 0; i < _tcslen(dst); i++)
+ dst[i] = _totupper(dst[i]);
+ return dst;
+}
+
+BOOL _isregex(TCHAR* strSearch)
+{
+ BOOL ret = FALSE;
+ pcre *re;
+ const char *error;
+ int erroroffs, rc;
+ char *regex;
+ char regex_parse[] = "/(.*)/([igsm]*)";
+ int ovector[9];
+
+ re = pcre_compile(regex_parse, 0, &error, &erroroffs, NULL);
+ if (!re)
+ return FALSE;
+
+ regex = mir_u2a(strSearch);
+ rc = pcre_exec(re, NULL, regex, (int)strlen(regex), 0, 0, ovector, 9);
+ if (rc == 3)
+ ret = TRUE;
+
+ if (re)
+ pcre_free(re);
+ if (regex)
+ mir_free(regex);
+
+ return ret;
+}
+
+BOOL _isvalidregex(TCHAR* strSearch)
+{
+ BOOL ret;
+ pcre *re;
+ const char *error;
+ int erroroffs, rc;
+ char *regex, *regexp, *mod;
+ int opts = 0;
+ char regex_parse[] = "/(.*)/([igsm]*)";
+ int ovector[9];
+
+ re = pcre_compile(regex_parse, 0, &error, &erroroffs, NULL);
+ if (!re)
+ return FALSE;
+
+ regex = mir_u2a(strSearch);
+ rc = pcre_exec(re, NULL, regex, (int)strlen(regex), 0, 0, ovector, 9);
+ pcre_free(re);
+
+ if (rc == 3) {
+ regexp = regex + ovector[2];
+ regexp[ovector[3]-ovector[2]] = 0;
+ mod = regex + ovector[4];
+ mod[ovector[5]-ovector[4]] = 0;
+
+ if (strstr(mod, "i"))
+ opts |= PCRE_CASELESS;
+ if (strstr(mod, "m"))
+ opts |= PCRE_MULTILINE;
+ if (strstr(mod, "s"))
+ opts |= PCRE_DOTALL;
+
+ re = pcre_compile(regexp, opts, &error, &erroroffs, NULL);
+ ret = (re) ? TRUE : FALSE;
+ }
+
+ if (re)
+ pcre_free(re);
+ if (regex)
+ mir_free(regex);
+
+ return ret;
+}
+
+BOOL _regmatch(TCHAR* str, TCHAR* strSearch)
+{
+ BOOL ret;
+ pcre *re;
+ const char *error;
+ int erroroffs, rc;
+ char *regex, *regexp, *data, *mod;
+ int opts = 0;
+ char regex_parse[] = "^/(.*)/([igsm]*)";
+ int ovector[9];
+
+ re = pcre_compile(regex_parse, 0, &error, &erroroffs, NULL);
+ if (!re)
+ return FALSE; // [TODO] and log some error
+
+ regex = mir_u2a(strSearch);
+ rc = pcre_exec(re, NULL, regex, (int)strlen(regex), 0, 0, ovector, 9);
+ if (rc != 3) {
+ mir_free(regex);
+ return FALSE; // [TODO] and log some error (better check for valid regex on options save)
+ }
+
+ regexp = regex + ovector[2];
+ regexp[ovector[3]-ovector[2]] = 0;
+ mod = regex + ovector[4];
+ mod[ovector[5]-ovector[4]] = 0;
+ pcre_free(re);
+
+ data = mir_u2a(str);
+
+ if (strstr(mod, "i"))
+ opts |= PCRE_CASELESS;
+ if (strstr(mod, "m"))
+ opts |= PCRE_MULTILINE;
+ if (strstr(mod, "s"))
+ opts |= PCRE_DOTALL;
+
+ re = pcre_compile(regexp, opts, &error, &erroroffs, NULL);
+ if (!re) {
+ mir_free(regex);
+ mir_free(data);
+ return FALSE;
+ }
+
+ rc = pcre_exec(re, NULL, data, (int)strlen(data), 0, 0, NULL, 0);
+ if (rc < 0) {
+ ret = FALSE;
+ } else {
+ ret = TRUE;
+ }
+
+ if (re)
+ pcre_free(re);
+ if (regex)
+ mir_free(regex);
+ if (data)
+ mir_free(data);
+
+ return ret;
+}
+
+int get_response_id(const TCHAR* strvar)
+{
+ int ret;
+ pcre *re;
+ const char *error;
+ int erroroffs, rc;
+ char *_str, *_strvar;
+ int opts = 0;
+ char regex[] = "^%response([#-_]([0-9]+))?%$";
+ int ovector[9];
+
+ re = pcre_compile(regex, 0, &error, &erroroffs, NULL);
+ if (!re)
+ return FALSE; // [TODO] and log some error
+
+ _strvar = mir_u2a(strvar);
+ rc = pcre_exec(re, NULL, _strvar, (int)strlen(_strvar), 0, 0, ovector, 9);
+ if (rc < 0) {
+ ret = -1;
+ } else if (rc == 3) {
+ _str = _strvar + ovector[4];
+ _str[ovector[5]-ovector[4]] = 0;
+ ret = atoi(_str);
+ } else
+ ret = 0;
+
+ if (re)
+ pcre_free(re);
+ if (_strvar)
+ mir_free(_strvar);
+
+ return ret;
+}
+
+int get_response_num(const TCHAR *str)
+{
+ int i = 0;
+ TCHAR *tmp, *strc = NULL;
+ strc = (TCHAR*)malloc((_tcslen(str)+1)*sizeof(TCHAR));
+ if (strc != NULL) {
+ _tcscpy(strc, str);
+ tmp = _tcstok(strc, L"\r\n");
+ while(tmp) {
+ i++;
+ tmp = _tcstok(NULL, L"\r\n");
+ }
+ free(strc);
+ }
+ return i;
+}
+
+TCHAR* get_response(TCHAR* dst, unsigned int dstlen, int num)
+{
+ int i = 0;
+ TCHAR *tmp, *src = NULL;
+ if (num < 0)
+ return dst;
+ src = (TCHAR*)malloc(MAX_BUFFER_LENGTH * sizeof(TCHAR));
+ if (src != NULL) {
+ _getOptS(src, MAX_BUFFER_LENGTH, "Response", defaultResponse);
+ _tcscpy(src, src);
+ tmp = _tcstok(src, L"\r\n");
+ while (tmp) {
+ if (i == num) {
+ _tcscpy(dst, tmp);
+ free(src);
+ return dst;
+ }
+ i++;
+ tmp = _tcstok(NULL, L"\r\n");
+ }
+ free(src);
+ }
+ return dst;
+}
+
+TCHAR* _tcsstr_cc(TCHAR* str, TCHAR* strSearch, BOOL cc)
+{
+ if (cc)
+ return _tcsstr(str, strSearch);
+ else {
+ TCHAR *ret;
+ TCHAR *_str = (TCHAR*)malloc((_tcslen(str)+1)*sizeof(TCHAR));
+ TCHAR *_strSearch = (TCHAR*)malloc((_tcslen(strSearch)+1)*sizeof(TCHAR));
+ _tcscpy(_str, str);
+ _tcscpy(_strSearch, strSearch);
+ ret = _tcsstr(_tcstolower(_str), _tcstolower(_strSearch));
+ if (ret != NULL)
+ ret = (ret-_str) + str;
+ free(_str);
+ free(_strSearch);
+ return ret;
+ }
+}
+
+BOOL Contains(TCHAR* dst, TCHAR* src) // Checks for occurence of substring from src in dst
+{
+ int i = 0, n = 0, value = 0;
+ TCHAR *tsrc = (TCHAR *)malloc((_tcslen(src)+1)*sizeof(TCHAR));
+ TCHAR *tdst = (TCHAR *)malloc((_tcslen(dst)+1)*sizeof(TCHAR));
+ TCHAR **tokens = NULL;
+ TCHAR *token = NULL;
+ _tcscpy(tdst, dst);
+ _tcscpy(tsrc, src);
+ token = _tcstok(tsrc, _T(","));
+ while (token) {
+ tokens = (TCHAR **) realloc(tokens, (n+1)*sizeof(TCHAR *));
+ tokens[n] = (TCHAR *)malloc((_tcslen(token)+1)*sizeof(TCHAR));
+ while(!_tcsncmp(token, _T(" "), 1)) {++token;}
+ while(_tcschr(token+_tcslen(token)-1, _T(' '))) {
+ token[_tcslen(token)-1] = _T('\0');
+ }
+ _tcscpy(tokens[n], token);
+ token = _tcstok(NULL, _T(","));
+ ++n;
+ }
+ for (i = 0; i < n; i++) {
+
+ if (_tcsstr(_tcstoupper(tdst), _tcstoupper(tokens[i]))) {
+ value = 1;
+ break;
+ }
+ }
+ free(tsrc);
+ if (tokens) {
+ for(i = 0; i < n; i++)
+ free(tokens[i]);
+ free(tokens);
+ }
+ return value;
+}
+
+BOOL isOneDay(DWORD timestamp1, DWORD timestamp2)
+{
+ time_t t1, t2;
+ int at1[3], at2[3];
+ struct tm *tm;
+ if (!timestamp1 || !timestamp2)
+ return FALSE;
+ t1 = (time_t)timestamp1;
+ t2 = (time_t)timestamp2;
+ tm = gmtime(&t1);
+ at1[0] = tm->tm_mday;
+ at1[1] = tm->tm_mon;
+ at1[2] = tm->tm_year;
+ tm = gmtime(&t2);
+ at2[0] = tm->tm_mday;
+ at2[1] = tm->tm_mon;
+ at2[2] = tm->tm_year;
+ if (memcmp(&at1, &at2, 3*sizeof(int)) == 0)
+ return TRUE;
+ return FALSE;
+}
+
+TCHAR* ReplaceVar(TCHAR *dst, unsigned int len, const TCHAR *var, const TCHAR *rvar)
+{
+ TCHAR *_rvar = (TCHAR*)malloc((_tcslen(rvar)+1)*sizeof(TCHAR));
+ TCHAR *__rvar = NULL;
+ TCHAR *var_start, *tmp = NULL;
+ TCHAR *src = NULL;
+ int response_id = get_response_id(var);
+
+ src = (TCHAR*)malloc((_tcslen(dst)+1)*sizeof(TCHAR));
+ _tcscpy(_rvar, rvar);
+ __rvar = _rvar;
+/*
+ if (response_id >= 0) {
+ __rvar = _tcstok(_rvar, L"\r\n");
+ while(response_id--) {
+ __rvar = _tcstok(NULL, L"\r\n");
+ }
+ } else {
+ __rvar = _rvar;
+ }
+*/
+ if (!dst)
+ return NULL;
+ _tcscpy(src, dst);
+ var_start = _tcsstr(dst, var);
+ while (var_start) {
+ tmp = (TCHAR*)realloc(tmp, sizeof(TCHAR)*(_tcslen(dst) + _tcslen(__rvar) - _tcslen(var) + 1));
+ _tcsncpy(tmp, dst, var_start - dst);
+ tmp[var_start - dst] = 0;
+ _tcscat(tmp, __rvar);
+ _tcscat(tmp, var_start + _tcslen(var));
+ if (len < (_tcslen(src)+1)*sizeof(TCHAR)) {
+ free(tmp);
+ return NULL;
+ }
+ _tcscpy(dst, tmp);
+ var_start = _tcsstr(dst, var);
+ }
+ if (tmp)
+ free(tmp);
+ if (_rvar)
+ free(_rvar);
+ if (src)
+ free(src);
+ return dst;
+}
+
+TCHAR* ReplaceVars(TCHAR *dst, unsigned int len)
+{
+ return ReplaceVarsNum(dst, len, -1);
+}
+
+TCHAR* ReplaceVarsNum(TCHAR *dst, unsigned int len, int num)
+{
+ TCHAR response[2048];
+ int ret, i = 1;
+ pcre *re;
+ const char *error;
+ int erroroffs, rc;
+ char *_str, *tmp;
+ TCHAR **r;
+ TCHAR *ttmp, *dstcopy;
+ int opts = 0;
+ char regex[] = "%response([#-_]([0-9]+))?%";
+ int ovector[9];
+
+ re = pcre_compile(regex, 0, &error, &erroroffs, NULL);
+ if (!re)
+ return FALSE; // [TODO] and log some error
+
+ _getOptS(response, 2048, "Response", defaultResponse);
+
+ r = (TCHAR**)malloc(sizeof(char*));
+ ttmp = _tcstok(response, L"\r\n");
+ r[0] = ttmp;
+ while(ttmp) {
+ ttmp = _tcstok(NULL, L"\r\n");
+ if (ttmp != NULL) {
+ r = (TCHAR**)realloc(r, (i+1)*sizeof(TCHAR*));
+ r[i++] = ttmp;
+ }
+ }
+
+ do {
+ _str = mir_u2a(dst);
+ dstcopy = (TCHAR*)malloc((_tcslen(dst)+1)*sizeof(TCHAR));
+ _tcscpy(dstcopy, dst);
+
+ rc = pcre_exec(re, NULL, _str, (int)strlen(_str), 0, 0, ovector, 9);
+ if (rc < 0) {
+ ret = -1;
+ } else if (rc == 3) {
+ ttmp = dstcopy + ovector[0];
+ ttmp[ovector[1]-ovector[0]] = 0;
+ tmp = _str + ovector[4];
+ tmp[ovector[5]-ovector[4]] = 0;
+ ret = atoi(tmp);
+ } else {
+ ttmp = dstcopy + ovector[0];
+ ttmp[ovector[1]-ovector[0]] = 0;
+ ret = 0;
+ }
+
+ if (ret >= 0) {
+ if (ret > i)
+ ReplaceVar(dst, len, ttmp, r[0]);
+ else if (ret == 0 && num > 0 && num < i)
+ ReplaceVar(dst, len, ttmp, r[num]);
+ else
+ ReplaceVar(dst, len, ttmp, r[ret == 0 ? 0 : ret-1]);
+ }
+
+ if (_str)
+ mir_free(_str);
+ if (dstcopy)
+ free(dstcopy);
+ } while (rc >= 0);
+
+ if (re)
+ pcre_free(re);
+
+ return dst;
+}
+
+int _notify(HANDLE hContact, BYTE type, TCHAR *message, TCHAR *origmessage)
+{
+ char *tmp, *tmporig;
+ TCHAR msg[MAX_BUFFER_LENGTH];
+ mir_sntprintf(msg, MAX_BUFFER_LENGTH, message, CONTACT_NAME(hContact));
+
+ if (_getOptB("LogActions", defaultLogActions)) {
+ tmp = mir_u2a(msg);
+ tmporig = mir_u2a(origmessage);
+ LogToSystemHistory(tmp, origmessage ? tmporig : NULL);
+ mir_free(tmp);
+ mir_free(tmporig);
+ }
+
+ if (_NOTIFYP) {
+ if (type == POPUP_BLOCKED) {
+ if (_getOptB("NotifyPopupBlocked", defaultNotifyPopupBlocked))
+ ShowPopup(hContact, type, NULL, msg);
+ } else if (type == POPUP_APPROVED) {
+ if (_getOptB("NotifyPopupApproved", defaultNotifyPopupApproved))
+ ShowPopup(hContact, type, NULL, msg);
+ } else if (type == POPUP_CHALLENGE) {
+ if (_getOptB("NotifyPopupChallenge", defaultNotifyPopupChallenge))
+ ShowPopup(hContact, type, NULL, msg);
+ } else {
+ ShowPopup(hContact, type, NULL, msg);
+ }
+ }
+ return 0;
+}
+#define DOT(a) (a[strlen(a)-1] == 46) ? "" : "."
+int LogToSystemHistory(char *message, char *origmessage)
+{
+ char *msg = (char*)malloc(MAX_BUFFER_LENGTH);
+ time_t tm;
+ DBEVENTINFO dbei;
+ dbei.cbSize = sizeof(DBEVENTINFO);
+ dbei.timestamp = time(&tm);
+ dbei.szModule = PLUGIN_NAME;
+ if (origmessage)
+ mir_snprintf(msg, MAX_BUFFER_LENGTH, "%s: %s%s %s: %s", PLUGIN_NAME, message, DOT(message), Translate("Their message was"), origmessage);
+ else
+ mir_snprintf(msg, MAX_BUFFER_LENGTH, "%s: %s%s", PLUGIN_NAME, message, DOT(message));
+ dbei.pBlob = (PBYTE)msg;
+ dbei.cbBlob = (DWORD)strlen(msg)+1;
+ dbei.eventType = EVENTTYPE_MESSAGE;
+ dbei.flags = DBEF_READ;
+ CallService(MS_DB_EVENT_ADD, (WPARAM)NULL, (LPARAM)&dbei);
+ return 0;
+}
+
+void MarkUnread(HANDLE hContact)
+{
+ // We're not actually marking anything. We just pushing saved events to the database from a temporary location
+ DBVARIANT _dbv = {0};
+ DBEVENTINFO _dbei;
+ PBYTE pos;
+
+ if (hContact == NULL)
+ return;
+
+ if (db_get(hContact, PLUGIN_NAME, "LastMsgEvents", &_dbv) == 0) {
+ pos = _dbv.pbVal;
+ while (pos - _dbv.pbVal < _dbv.cpbVal) {
+ ZeroMemory(&_dbei, sizeof(_dbei));
+ _dbei.cbSize = sizeof(_dbei);
+
+ memcpy(&_dbei.eventType, pos, sizeof(WORD)); pos += sizeof(WORD);
+ memcpy(&_dbei.flags, pos, sizeof(DWORD)); pos += sizeof(DWORD);
+ memcpy(&_dbei.timestamp, pos, sizeof(DWORD)); pos += sizeof(DWORD);
+
+ _dbei.szModule = (char*)malloc(strlen((const char*)pos)+1);
+ strcpy(_dbei.szModule, (const char*)pos);
+ pos += strlen((const char*)pos)+1;
+
+ memcpy(&_dbei.cbBlob, pos, sizeof(DWORD)); pos += sizeof(DWORD);
+ _dbei.pBlob = (PBYTE)malloc(_dbei.cbBlob);
+ memcpy(_dbei.pBlob, pos, _dbei.cbBlob);
+ pos += _dbei.cbBlob;
+
+ CallService(MS_DB_EVENT_ADD, (WPARAM)hContact, (LPARAM)&_dbei);
+ }
+ db_free(&_dbv);
+ db_unset(hContact, PLUGIN_NAME, "LastMsgEvents");
+ }
+}
|