From cb4a46e7fbe62d788e66ed6121c717a2d22a4d7c Mon Sep 17 00:00:00 2001 From: watcherhd Date: Thu, 21 Apr 2011 14:14:52 +0000 Subject: svn.miranda.im is moving to a new home! git-svn-id: http://miranda-plugins.googlecode.com/svn/trunk@7 e753b5eb-9565-29b2-b5c5-2cc6f99dfbcb --- stopspam/src/eventhooker.cpp | 68 +++++ stopspam/src/eventhooker.h | 60 ++++ stopspam/src/events.cpp | 254 ++++++++++++++++ stopspam/src/m_variables.h | 668 +++++++++++++++++++++++++++++++++++++++++++ stopspam/src/opt_proto.cpp | 137 +++++++++ stopspam/src/options.cpp | 133 +++++++++ stopspam/src/services.cpp | 80 ++++++ stopspam/src/settings.cpp | 59 ++++ stopspam/src/settings.h | 100 +++++++ stopspam/src/stopspam.cpp | 103 +++++++ stopspam/src/utils.cpp | 77 +++++ 11 files changed, 1739 insertions(+) create mode 100644 stopspam/src/eventhooker.cpp create mode 100644 stopspam/src/eventhooker.h create mode 100644 stopspam/src/events.cpp create mode 100644 stopspam/src/m_variables.h create mode 100644 stopspam/src/opt_proto.cpp create mode 100644 stopspam/src/options.cpp create mode 100644 stopspam/src/services.cpp create mode 100644 stopspam/src/settings.cpp create mode 100644 stopspam/src/settings.h create mode 100644 stopspam/src/stopspam.cpp create mode 100644 stopspam/src/utils.cpp (limited to 'stopspam/src') diff --git a/stopspam/src/eventhooker.cpp b/stopspam/src/eventhooker.cpp new file mode 100644 index 0000000..f29e5b7 --- /dev/null +++ b/stopspam/src/eventhooker.cpp @@ -0,0 +1,68 @@ +/* eventhooker.cpp +* Copyright (C) Miklashevsky Roman +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include +#include "eventhooker.h" + +namespace miranda +{ + namespace + { + std::list eventHookerList; + } + + EventHooker::EventHooker(std::string name, MIRANDAHOOK fun) : name_(name), fun_(fun), handle_(0) + { + eventHookerList.push_back(this); + } + + EventHooker::~EventHooker() + { + eventHookerList.remove(this); + } + + void EventHooker::Hook() + { + handle_ = HookEvent(name_.c_str(), fun_); + } + + void EventHooker::Unhook() + { + if(handle_) + { + UnhookEvent(handle_); + handle_ = 0; + } + } + + void EventHooker::HookAll() + { + for(std::list::iterator it = eventHookerList.begin(); it != eventHookerList.end(); ++it) + { + (*it)->Hook(); + } + } + + void EventHooker::UnhookAll() + { + for(std::list::iterator it = eventHookerList.begin(); it != eventHookerList.end(); ++it) + { + (*it)->Unhook(); + } + } +} diff --git a/stopspam/src/eventhooker.h b/stopspam/src/eventhooker.h new file mode 100644 index 0000000..b1ca2ab --- /dev/null +++ b/stopspam/src/eventhooker.h @@ -0,0 +1,60 @@ +/* eventhooker.h - Helper for hooking events in Miranda. +* Copyright (C) Miklashevsky Roman +* +* To hook event just write +* MIRANDA_HOOK_EVENT('name of the event', wParam, lParam) { 'your code' } +* Include following in your Load function +* miranda::EventHooker::HookAll(); +* And following in your Unload function +* miranda::EventHooker::UnhookAll(); +* That's all +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef EVENTHOOKER_H_C8EAA58A_7C4D_45f7_A88E_0E41FE93754D +#define EVENTHOOKER_H_C8EAA58A_7C4D_45f7_A88E_0E41FE93754D + +#pragma warning( once : 4430 ) + +#include +#include +#include + +namespace miranda +{ + +#define MIRANDA_HOOK_EVENT(NAME, WPARAMNAME, LPARAMNAME) \ + int NAME##_Handler(WPARAM,LPARAM);\ + miranda::EventHooker NAME##_Hooker(NAME, NAME##_Handler);\ + int NAME##_Handler(WPARAM WPARAMNAME, LPARAM LPARAMNAME) + + struct EventHooker + { + EventHooker(std::string name, MIRANDAHOOK fun); + ~EventHooker(); + void Hook(); + void Unhook(); + static void HookAll(); + static void UnhookAll(); + private: + std::string name_; + MIRANDAHOOK fun_; + HANDLE handle_; + }; + +} + +#endif diff --git a/stopspam/src/events.cpp b/stopspam/src/events.cpp new file mode 100644 index 0000000..74d4195 --- /dev/null +++ b/stopspam/src/events.cpp @@ -0,0 +1,254 @@ +#include "../headers.h" + + +MIRANDA_HOOK_EVENT(ME_DB_EVENT_ADDED, wParam, lParam) +{ + HANDLE hDbEvent = (HANDLE)lParam; + + DBEVENTINFO dbei = {0}; + dbei.cbSize = sizeof(dbei); + dbei.cbBlob = CallService(MS_DB_EVENT_GETBLOBSIZE, (WPARAM)hDbEvent, 0); + if(-1 == dbei.cbBlob) + return 0; + + dbei.pBlob = new BYTE[dbei.cbBlob]; + CallService(MS_DB_EVENT_GET, lParam, (LPARAM)&dbei); + + // if event is in protocol that is not despammed + if(plSets->ProtoDisabled(dbei.szModule)) { + delete [] dbei.pBlob; + return 0; + } + + // event is an auth request + if(!(dbei.flags & DBEF_SENT) && !(dbei.flags & DBEF_READ) && dbei.eventType == EVENTTYPE_AUTHREQUEST) + { + HANDLE hcntct=*(HANDLE*)(dbei.pBlob + sizeof(DWORD)); + + // if request is from unknown or not marked Answered contact + //and if I don't sent message to this contact + + if(DBGetContactSettingByte(hcntct, "CList", "NotOnList", 0) && + !DBGetContactSettingByte(hcntct, pluginName, answeredSetting, 0) && + !IsExistMyMessage(hcntct)) + { + if(!plSets->HandleAuthReq.Get()) + { + #ifdef _UNICODE + char * buf=mir_utf8encodeW(variables_parse(plSets->AuthRepl.Get(), hcntct).c_str()); + CallContactService(hcntct, PSS_MESSAGE, PREF_UTF, (LPARAM)buf); + mir_free(buf); + #else + CallContactService(hcntct, PSS_MESSAGE, 0, (LPARAM)(variables_parse(plSets->AuthRepl.Get(), hcntct).c_str())); + #endif + } + char *AuthRepl; + #ifdef _UNICODE + AuthRepl=mir_u2a(variables_parse(plSets->AuthRepl.Get(), hcntct).c_str()); + #else + AuthRepl=variables_parse(plSets->AuthRepl.Get(), hcntct).c_str(); + #endif + // ...send message + std::string allowService = dbei.szModule; + allowService += PS_AUTHDENY; + CallService(allowService.c_str(), (WPARAM)hDbEvent, (LPARAM)AuthRepl); + #ifdef _UNICODE + mir_free(AuthRepl); + #endif + DBWriteContactSettingByte(hcntct, "CList", "NotOnList", 1); + DBWriteContactSettingByte(hcntct, "CList", "Hidden", 1); + if (!plSets->HistLog.Get()) + CallService(MS_DB_EVENT_DELETE, 0, (LPARAM)hDbEvent); + delete [] dbei.pBlob; + return 1; + } + } + delete [] dbei.pBlob; + return 0; +} + +MIRANDA_HOOK_EVENT(ME_DB_EVENT_FILTER_ADD, w, l) +{ + HANDLE hContact = (HANDLE)w; + + if(!l) //fix potential DEP crash + return 0; + DBEVENTINFO * dbei = (DBEVENTINFO*)l; + + // if event is in protocol that is not despammed + if(plSets->ProtoDisabled(dbei->szModule)) + // ...let the event go its way + return 0; + + // if event is not a message, or if the message has been read or sent... + if(dbei->flags & DBEF_SENT || dbei->flags & DBEF_READ || dbei->eventType != EVENTTYPE_MESSAGE ) + // ...let the event go its way + return 0; + + // if message is from known or marked Answered contact + if(DBGetContactSettingByte(hContact, pluginName, answeredSetting, 0)) + // ...let the event go its way + return 0; + + // checking if message from self-added contact + //Contact in Not in list icq group + if(!DBGetContactSettingByte(hContact, "CList", "NotOnList", 0) && DBGetContactSettingWord(hContact, dbei->szModule, "SrvGroupId", -1) != 1) + return 0; + + //if I sent message to this contact + if(IsExistMyMessage(hContact)) + return 0; + + // if message is corrupted or empty it cannot be an answer. + if(!dbei->cbBlob || !dbei->pBlob) + // reject processing of the event + return 1; + + tstring message; + + if(dbei->flags & DBEF_UTF){ + WCHAR* msg_u=mir_utf8decodeW((char*)dbei->pBlob); +#ifdef _UNICODE + message = msg_u; +#else + char* msg_a = mir_u2a(msg_u); + message = msg_a; + mir_free(msg_a); +#endif + mir_free(msg_u); + } + else{ +#ifdef _UNICODE + WCHAR* msg_u = mir_a2u((char*)(dbei->pBlob)); + message = msg_u; + mir_free(msg_u); +#else + message = (char*)(dbei->pBlob); +#endif + } + + // if message equal right answer... + tstring answers = variables_parse(plSets->Answer.Get(), hContact); + answers.append(plSets->AnswSplitString.Get()); + tstring::size_type pos = 0; + tstring::size_type prev_pos = 0; + while((pos = answers.find(plSets->AnswSplitString.Get(), pos)) != tstring::npos) + { + // get one of answers and trim witespace chars + tstring answer = trim(answers.substr(prev_pos, pos - prev_pos)); + // if answer not empty + if (answer.length() > 0) + { + // if message equal right answer... + if (plSets->AnswNotCaseSens.Get() ? + !lstrcmpi(message.c_str(), answer.c_str()) : + !lstrcmp(message.c_str(), answer.c_str()) + ) + { + // unhide contact + DBDeleteContactSetting(hContact, "CList", "Hidden"); + + // mark contact as Answered + DBWriteContactSettingByte(hContact, pluginName, answeredSetting, 1); + + //add contact permanently + if(plSets->AddPermanent.Get()) + DBDeleteContactSetting(hContact, "CList", "NotOnList"); + + // send congratulation + #ifdef _UNICODE + char * buf=mir_utf8encodeW(variables_parse(plSets->Congratulation.Get(), hContact).c_str()); + CallContactService(hContact, PSS_MESSAGE, PREF_UTF, (LPARAM)buf); + mir_free(buf); + #else + CallContactService(hContact, PSS_MESSAGE, 0, (LPARAM)(variables_parse(plSets->Congratulation.Get(), hContact).c_str())); + #endif + + // process the event + return 1; + } + } + prev_pos = ++pos; + } + + // if message message does not contain infintite talk protection prefix + // and question count for this contact is less then maximum + if( (!plSets->InfTalkProtection.Get() || tstring::npos==message.find(infTalkProtPrefix)) + && (!plSets->MaxQuestCount.Get() || DBGetContactSettingDword(hContact, pluginName, questCountSetting, 0) < plSets->MaxQuestCount.Get()) ) + { + // send question + tstring q = infTalkProtPrefix + variables_parse((tstring)(plSets->Question), hContact); + +#ifdef _UNICODE + char * buf=mir_utf8encodeW(q.c_str()); + CallContactService(hContact, PSS_MESSAGE, PREF_UTF, (LPARAM)buf); + mir_free(buf); +#else + CallContactService(hContact, PSS_MESSAGE, 0, (LPARAM)q.c_str()); +#endif + + // increment question count + DWORD questCount = DBGetContactSettingDword(hContact, pluginName, questCountSetting, 0); + DBWriteContactSettingDword(hContact, pluginName, questCountSetting, questCount + 1); + + // hide contact from contact list + } + DBWriteContactSettingByte(hContact, "CList", "NotOnList", 1); + DBWriteContactSettingByte(hContact, "CList", "Hidden", 1); + + // save message from contact + dbei->flags |= DBEF_READ; + CallService(MS_DB_EVENT_ADD, (WPARAM)hContact, (LPARAM)dbei); + + // reject processing of the event + return 1; +} + +MIRANDA_HOOK_EVENT(ME_OPT_INITIALISE, w, l) +{ + OPTIONSDIALOGPAGE odp = {0}; + odp.cbSize = sizeof(odp); + odp.ptszGroup = _T("Message Sessions"); + odp.ptszTitle = _T(pluginName); + odp.position = -1; + odp.hInstance = hInst; + odp.flags = ODPF_TCHAR; + + odp.ptszTab = _T("Main"); + odp.pszTemplate = MAKEINTRESOURCEA(IDD_MAIN); + odp.pfnDlgProc = MainDlgProc; + CallService(MS_OPT_ADDPAGE, w, (LPARAM)&odp); + + + odp.ptszTab = _T("Messages"); + odp.pszTemplate = MAKEINTRESOURCEA(IDD_MESSAGES); + odp.pfnDlgProc = MessagesDlgProc; + CallService(MS_OPT_ADDPAGE, w, (LPARAM)&odp); + + odp.ptszTab = _T("Protocols"); + odp.pszTemplate = MAKEINTRESOURCEA(IDD_PROTO); + odp.pfnDlgProc = ProtoDlgProc; + CallService(MS_OPT_ADDPAGE, w, (LPARAM)&odp); + + return 0; +} + +MIRANDA_HOOK_EVENT(ME_DB_CONTACT_SETTINGCHANGED, w, l) +{ + HANDLE hContact = (HANDLE)w; + DBCONTACTWRITESETTING * cws = (DBCONTACTWRITESETTING*)l; + + // if CList/NotOnList is being deleted then remove answeredSetting + if(strcmp(cws->szModule, "CList")) + return 0; + if(strcmp(cws->szSetting, "NotOnList")) + return 0; + if(!cws->value.type) + { + DBDeleteContactSetting(hContact, pluginName, answeredSetting); + DBDeleteContactSetting(hContact, pluginName, questCountSetting); + } + + return 0; +} + diff --git a/stopspam/src/m_variables.h b/stopspam/src/m_variables.h new file mode 100644 index 0000000..152994d --- /dev/null +++ b/stopspam/src/m_variables.h @@ -0,0 +1,668 @@ +/* + Variables Plugin for Miranda-IM (www.miranda-im.org) + Copyright 2003-2006 P. Boon + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef __M_VARS +#define __M_VARS + +#if !defined(_TCHAR_DEFINED) +#include +#endif + +#ifndef VARIABLES_NOHELPER +#include +#endif + +// -------------------------------------------------------------------------- +// Memory management +// -------------------------------------------------------------------------- + +// Release memory that was allocated by the Variables plugin, e.g. returned +// strings. + +#define MS_VARS_FREEMEMORY "Vars/FreeMemory" + +// Parameters: +// ------------------------ +// wParam = (WPARAM)(void *)pntr +// Pointer to memory that was allocated by the Variables plugin (e.g. a +// returned string) (can be NULL). +// lParam = 0 + +// Return Value: +// ------------------------ +// Does return 0 on success, nozero otherwise. + +// Note: Do only use this service to free memory that was *explicitliy* +// stated that it should be free with this service. + + + +#define MS_VARS_GET_MMI "Vars/GetMMI" + +// Get Variable's RTL/CRT function poiners to malloc(), free() and +// realloc(). + +// Parameters: +// ------------------------ +// wParam = 0 +// lParam = (LPARAM) &MM_INTERFACE +// Pointer to a memory manager interface struct (see m_system.h). + +// Return Value: +// ------------------------ +// Returns 0 on success, nozero otherwise + +// Note: Works exactly the same as the MS_SYSTEM_GET_MMI service +// service of m_system.h. + +// Helper function for easy using: +#ifndef VARIABLES_NOHELPER +__inline static void variables_free(void *pntr) { + + CallService(MS_VARS_FREEMEMORY, (WPARAM)pntr, 0); +} +#endif + + + +// -------------------------------------------------------------------------- +// String formatting +// -------------------------------------------------------------------------- + +#define MS_VARS_FORMATSTRING "Vars/FormatString" + +// This service can be used to parse tokens in a text. The tokens will be +// replaced by their resolved values. A token can either be a field or a +// function. A field takes no arguments and is represented between +// %-characters, e.g. "%winampsong%". A function can take any number of +// arguments and is represented by a ? or !-character followed by the name +// of the function and a list of arguments, e.g. "?add(1,2)". + +// Parameters: +// ------------------------ +// wParam = (WPARAM)(FORMATINFO *)&fi +// See below. +// lParam = 0 + +// Return Value: +// ------------------------ +// Returns a pointer to the resolved string or NULL in case of an error. + +// Note: The returned pointer needs to be freed using MS_VARS_FREEMEMORY. + +typedef struct { + int cbSize; // Set this to sizeof(FORMATINFO). + int flags; // Flags to use (see FIF_* below). + union { + char *szFormat; // Text in which the tokens will be replaced (can't be + // NULL). + WCHAR *wszFormat; + TCHAR *tszFormat; + }; + union { + char *szExtraText; // Extra, context-specific string (can be NULL) -> + // The field "extratext" will be replaced by this + // string. (Previously szSource). + WCHAR *wszExtraText; + TCHAR *tszExtraText; + }; + HANDLE hContact; // Handle to contact (can be NULL) -> The field "subject" + // represents this contact. + int pCount; // (output) Number of succesful parsed tokens, needs to be set + // to 0 before the call + int eCount; // (output) Number of failed tokens, needs to be set to 0 + // before the call +} FORMATINFO; + +// Possible flags: +#define FIF_UNICODE 0x01 // Expects and returns unicode text (WCHAR*). + +#if defined(UNICODE) || defined(_UNICODE) +#define FIF_TCHAR FIF_UNICODE // Strings in structure are TCHAR*. +#else +#define FIF_TCHAR 0 +#endif + +// Helper functions for easy using: + +// Helper #1: variables_parse +// ------------------------ +// The returned string needs to be freed using MS_VARS_FREEMEMORY. + +#ifndef VARIABLES_NOHELPER +__inline static TCHAR *variables_parse(TCHAR *tszFormat, TCHAR *tszExtraText, HANDLE hContact) { + + FORMATINFO fi; + + ZeroMemory(&fi, sizeof(fi)); + fi.cbSize = sizeof(fi); + fi.tszFormat = tszFormat; + fi.tszExtraText = tszExtraText; + fi.hContact = hContact; + fi.flags = FIF_TCHAR; + + return (TCHAR *)CallService(MS_VARS_FORMATSTRING, (WPARAM)&fi, 0); +} +#endif + +// Helper #2: variables_parsedup +// ------------------------ +// Returns a _strdup()'ed copy of the unparsed string when Variables is not +// installed, returns a strdup()'ed copy of the parsed result otherwise. + +// Note: The returned pointer needs to be released using your own free(). + +#ifndef VARIABLES_NOHELPER +__inline static TCHAR *variables_parsedup(TCHAR *tszFormat, TCHAR *tszExtraText, HANDLE hContact) { + + if (ServiceExists(MS_VARS_FORMATSTRING)) { + FORMATINFO fi; + TCHAR *tszParsed, *tszResult; + + ZeroMemory(&fi, sizeof(fi)); + fi.cbSize = sizeof(fi); + fi.tszFormat = tszFormat; + fi.tszExtraText = tszExtraText; + fi.hContact = hContact; + fi.flags |= FIF_TCHAR; + tszParsed = (TCHAR *)CallService(MS_VARS_FORMATSTRING, (WPARAM)&fi, 0); + if (tszParsed) { + tszResult = _tcsdup(tszParsed); + CallService(MS_VARS_FREEMEMORY, (WPARAM)tszParsed, 0); + return tszResult; + } + } + return tszFormat?_tcsdup(tszFormat):tszFormat; +} +#endif + + + +// -------------------------------------------------------------------------- +// Register tokens +// -------------------------------------------------------------------------- + +// Plugins can define tokens which will be parsed by the Variables plugin. + +#define MS_VARS_REGISTERTOKEN "Vars/RegisterToken" + +// With this service you can define your own token. The newly added tokens +// using this service are taken into account on every call to +// MS_VARS_FORMATSTRING. + +// Parameters: +// ------------------------ +// wParam = 0 +// lParam = (LPARAM)(TOKENREGISTER*)&tr +// See below. + +// Return Value: +// ------------------------ +// Returns 0 on success, nonzero otherwise. Existing tokens will be +// 'overwritten' if registered twice. + +// Needed for szService and parseFunction: +typedef struct { + int cbSize; // You need to check if this is >=sizeof(ARGUMENTSINFO) + // (already filled in). + FORMATINFO *fi; // Arguments passed to MS_VARS_FORMATSTRING. + unsigned int argc; // Number of elements in the argv array. + union { + char **argv; // Argv[0] will be the token name, the following elements + // are the additional arguments. + WCHAR **wargv; // If the registered token was registered as a unicode + // token, wargv should be accessed. + TCHAR **targv; + }; + int flags; // (output) You can set flags here (initially 0), use the + // AIF_* flags (see below). +} ARGUMENTSINFO; + +// Available flags for ARGUMENTSINFO: +// Set the flags of the ARGUMENTSINFO struct to any of these to influence +// further parsing. +#define AIF_DONTPARSE 0x01 // Don't parse the result of this function, + // usually the result of a token is parsed + // again, if the `?` is used as a function + // character. +#define AIF_FALSE 0x02 // The function returned logical false. + +// Definition of parse/cleanup functions: +typedef char* (*VARPARSEFUNCA)(ARGUMENTSINFO *ai); +typedef WCHAR* (*VARPARSEFUNCW)(ARGUMENTSINFO *ai); +typedef void (*VARCLEANUPFUNCA)(char *szReturn); +typedef void (*VARCLEANUPFUNCW)(WCHAR *wszReturn); + +#if defined(UNICODE) || defined(_UNICODE) +#define VARPARSEFUNC VARPARSEFUNCW +#define VARCLEANUPFUNC VARCLEANUPFUNCW +#else +#define VARPARSEFUNC VARPARSEFUNCA +#define VARCLEANUPFUNC VARCLEANUPFUNCA +#endif + +typedef struct { + int cbSize; // Set this to sizeof(TOKENREGISTER). + union { + char *szTokenString; // Name of the new token to be created, without %, + // ?, ! etc. signs (can't be NULL). + WCHAR *wszTokenString; + TCHAR *tszTokenString; + }; + union { + char *szService; // Name of a service that is used to request the + // token's value, if no service is used, a function + // and TRF_PARSEFUNC must be used. + VARPARSEFUNCA parseFunction; // See above, use with TRF_PARSEFUNC. + VARPARSEFUNCW parseFunctionW; + VARPARSEFUNC parseFunctionT; + }; + union { + char *szCleanupService; // Name of a service to be called when the + // memory allocated in szService can be freed + // (only used when flag VRF_CLEANUP is set, + // else set this to NULL). + VARCLEANUPFUNCA cleanupFunction; // See above, use with TRF_CLEANUPFUNC. + VARCLEANUPFUNCW cleanupFunctionW; + VARCLEANUPFUNC cleanupFunctionT; + }; + char *szHelpText; // Help info shown in help dialog (can be NULL). Has to + // be in the following format: + // "subject\targuments\tdescription" + // (Example: "math\t(x, y ,...)\tx + y + ..."), or: + // "subject\tdescription" + // (Example: "miranda\tPath to the Miranda-IM + // executable"). + // Note: subject and description are translated by + // Variables. + int memType; // Describes which method Varibale's plugin needs to use to + // free the returned buffer, use one of the VR_MEM_* values + // (see below). Only valid if the flag VRF_FREEMEM is set, + // use TR_MEM_OWNER otherwise). + int flags; // Flags to use (see below), one of TRF_* (see below). +} TOKENREGISTER; + +// Available Memory Storage Types: +// These values describe which method Variables Plugin will use to free the +// buffer returned by the parse function or service +#define TR_MEM_VARIABLES 1 // Memory is allocated using the functions + // retrieved by MS_VARS_GET_MMI. +#define TR_MEM_MIRANDA 2 // Memory is allocated using Miranda's Memory + // Manager Interface (using the functions + // returned by MS_SYSTEM_GET_MMI), if + // VRF_FREEMEM is set, the memory will be + // freed by Variables. +#define TR_MEM_OWNER 3 // Memory is owned by the calling plugin + // (can't be freed by Variables Plugin + // automatically). This should be used if + // VRF_FREEMEM is not specified in the flags. + +// Available Flags for TOKENREGISTER: +#define TRF_FREEMEM 0x01 // Variables Plugin will automatically free the + // pointer returned by the parse function or + // service (which method it will us is + // specified in memType -> see above). +#define TRF_CLEANUP 0x02 // Call cleanup service or function, notifying + // that the returned buffer can be freed. + // Normally you should use either TRF_FREEMEM + // or TRF_CLEANUP. +#define TRF_PARSEFUNC 0x40 // parseFunction will be used instead of a + // service. +#define TRF_CLEANUPFUNC 0x80 // cleanupFunction will be used instead of a + // service. +#define TRF_USEFUNCS TRF_PARSEFUNC|TRF_CLEANUPFUNC +#define TRF_UNPARSEDARGS 0x04 // Provide the arguments for the parse + // function in their raw (unparsed) form. + // By default, arguments are parsed before + // presenting them to the parse function. +#define TRF_FIELD 0x08 // The token can be used as a %field%. +#define TRF_FUNCTION 0x10 // The token can be used as a ?function(). + // Normally you should use either TRF_FIELD or + // TRF_FUNCTION. +#define TRF_UNICODE 0x20 // Strings in structure are unicode (WCHAR*). + // In this case, the strings pointing to the + // arguments in the ARGUMENTS struct are + // unicode also. The returned buffer is + // expected to be unicode also, and the + // unicode parse and cleanup functions are + // called. + +#if defined(UNICODE) || defined(_UNICODE) +#define TRF_TCHAR TRF_UNICODE // Strings in structure are TCHAR*. +#else +#define TRF_TCHAR 0 +#endif + +// Deprecated: +#define TRF_CALLSVC TRF_CLEANUP + +// Callback Service (szService) / parseFunction: +// ------------------------ +// Service that is called automatically by the Variable's Plugin to resolve a +// registered variable. + +// Parameters: +// wParam = 0 +// lParam = (LPARAM)(ARGUMENTSINFO *)&ai +// see above + +// Return Value: +// Needs to return the pointer to a dynamically allocacated string or NULL. +// A return value of NULL is regarded as an error (eCount will be increaded). +// Flags in the ARGUMENTSINFO struct can be set (see above). + +// Callback Service (szCallbackService) / cleanupFunction: +// ------------------------ +// This service is called when the memory that was allocated by the parse +// function or service can be freed. Note: It will only be called when the +// flag VRF_CLEANUP of TOKENREGISTER is set. + +// Parameters: +// wParam = 0 +// lParam = (LPARAM)(char *)&res +// Result from parse function or service (pointer to a string). + +// Return Value: +// Should return 0 on success. + + + +// -------------------------------------------------------------------------- +// Show the help dialog +// -------------------------------------------------------------------------- + +// Plugins can invoke Variables' help dialog which can be used for easy input +// by users. + +#define MS_VARS_SHOWHELPEX "Vars/ShowHelpEx" + +// This service can be used to open the help dialog of Variables. This dialog +// provides easy input for the user and/or information about the available +// tokens. + +// Parameters: +// ------------------------ +// wParam = (WPARAM)(HWND)hwndParent +// lParam = (LPARAM)(VARHELPINFO)&vhi +// See below. + +// Return Value: +// ------------------------ +// Returns 0 on succes, any other value on error. + +typedef struct { + int cbSize; // Set to sizeof(VARHELPINFO). + FORMATINFO *fi; // Used for both input and output. If this pointer is not + // NULL, the information is used as the initial values for + // the dialog. + HWND hwndCtrl; // Used for both input and output. The window text of this + // window will be read and used as the initial input of the + // input dialog. If the user presses the OK button the window + // text of this window will be set to the text of the input + // field and a EN_CHANGE message via WM_COMMAND is send to + // this window. (Can be NULL). + char *szSubjectDesc; // The description of the %subject% token will be set + // to this text, if not NULL. This is translated + // automatically. + char *szExtraTextDesc; // The description of the %extratext% token will be + // set to this text, if not NULL. This is translated + // automatically. + int flags; // Flags, see below. +} VARHELPINFO; + + +// Flags for VARHELPINFO +#define VHF_TOKENS 0x00000001 // Create a dialog with the list of + // tokens +#define VHF_INPUT 0x00000002 // Create a dialog with an input + // field (this contains the list of + // tokens as well). +#define VHF_SUBJECT 0x00000004 // Create a dialog to select a + // contact for the %subject% token. +#define VHF_EXTRATEXT 0x00000008 // Create a dialog to enter a text + // for the %extratext% token. +#define VHF_HELP 0x00000010 // Create a dialog with help info. +#define VHF_HIDESUBJECTTOKEN 0x00000020 // Hide the %subject% token in the + // list of tokens. +#define VHF_HIDEEXTRATEXTTOKEN 0x00000040 // Hide the %extratext% token in + // the list of tokens. +#define VHF_DONTFILLSTRUCT 0x00000080 // Don't fill the struct with the + // new information if OK is pressed +#define VHF_FULLFILLSTRUCT 0x00000100 // Fill all members of the struct + // when OK is pressed. By default + // only szFormat is set. With this + // flag on, hContact and + // szExtraText are also set. +#define VHF_SETLASTSUBJECT 0x00000200 // Set the last contact that was + // used in the %subject% dialog in + // case fi.hContact is NULL. + +// Predefined flags +#define VHF_FULLDLG VHF_INPUT|VHF_SUBJECT|VHF_EXTRATEXT|VHF_HELP +#define VHF_SIMPLEDLG VHF_INPUT|VHF_HELP +#define VHF_NOINPUTDLG VHF_TOKENS|VHF_HELP + +// If the service fills information in the struct for szFormat or szExtraText, +// these members must be free'd using the free function of Variables. +// If wParam==NULL, the dialog is created modeless. Only one dialog can be +// shown at the time. +// If both hwndCtrl and fi are NULL, the user input will not be retrievable. +// In this case, the dialog is created with only a "Close" button, instead of +// the "OK" and "Cancel" buttons. +// In case of modeless dialog and fi != NULL, please make sure this pointer +// stays valid while the dialog is open. + +// Helper function for easy use in standard case: +#ifndef VARIABLES_NOHELPER +__inline static int variables_showhelp(HWND hwndDlg, UINT uIDEdit, int flags, char *szSubjectDesc, char *szExtraDesc) { + + VARHELPINFO vhi; + + ZeroMemory(&vhi, sizeof(VARHELPINFO)); + vhi.cbSize = sizeof(VARHELPINFO); + if (flags == 0) { + flags = VHF_SIMPLEDLG; + } + vhi.flags = flags; + vhi.hwndCtrl = GetDlgItem(hwndDlg, uIDEdit); + vhi.szSubjectDesc = szSubjectDesc; + vhi.szExtraTextDesc = szExtraDesc; + + return CallService(MS_VARS_SHOWHELPEX, (WPARAM)hwndDlg, (LPARAM)&vhi); +} +#endif + + +#define MS_VARS_GETSKINITEM "Vars/GetSkinItem" + +// This service can be used to get the icon you can use for example on the +// Variables help button in your options screen. You can also get the tooltip +// text to use with such a button. If icon library is available the icon will +// be retrieved from icon library manager, otherwise the default is returned. + +// Parameters: +// ------------------------ +// wParam = (WPARAM)0 +// lParam = (LPARAM)VSI_* (see below) + +// Return Value: +// ------------------------ +// Depends on the information to retrieve (see below). + +// VSI_ constants +#define VSI_HELPICON 1 // Can be used on the button accessing the + // Variables help dialog. Returns (HICON)hIcon on + // success or NULL on failure; +#define VSI_HELPTIPTEXT 2 // Returns the tooltip text you can use for the + // help button. Returns (char *)szTipText, a + // static, translated buffer containing the help + // text or NULL on error. + +// Helper to set the icon on a button accessing the help dialog. +// Preferably a 16x14 MButtonClass control, but it works on a standard +// button control as well. If no icon is availble (because of old version of +// Variables) the string "V" is shown on the button. If Variables is not +// available, the button will be hidden. +#ifndef VARIABLES_NOHELPER +__inline static int variables_skin_helpbutton(HWND hwndDlg, UINT uIDButton) { + + int res; + HICON hIcon; + TCHAR tszClass[32]; + + hIcon = NULL; + res = 0; + if (ServiceExists(MS_VARS_GETSKINITEM)) { + hIcon = (HICON)CallService(MS_VARS_GETSKINITEM, 0, (LPARAM)VSI_HELPICON); + } + GetClassName(GetDlgItem(hwndDlg, uIDButton), tszClass, sizeof(tszClass)); + if (!_tcscmp(tszClass, _T("Button"))) { + if (hIcon != NULL) { + SetWindowLong(GetDlgItem(hwndDlg, uIDButton), GWL_STYLE, GetWindowLong(GetDlgItem(hwndDlg, uIDButton), GWL_STYLE)|BS_ICON); + SendMessage(GetDlgItem(hwndDlg, uIDButton), BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hIcon); + } + else { + SetWindowLong(GetDlgItem(hwndDlg, uIDButton), GWL_STYLE, GetWindowLong(GetDlgItem(hwndDlg, uIDButton), GWL_STYLE)&~BS_ICON); + SetDlgItemText(hwndDlg, uIDButton, _T("V")); + } + } + else if (!_tcscmp(tszClass, MIRANDABUTTONCLASS)) { + if (hIcon != NULL) { + char *szTipInfo; + + SendMessage(GetDlgItem(hwndDlg, uIDButton), BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hIcon); + if (ServiceExists(MS_VARS_GETSKINITEM)) { + szTipInfo = (char *)CallService(MS_VARS_GETSKINITEM, 0, (LPARAM)VSI_HELPTIPTEXT); + } + if (szTipInfo == NULL) { + szTipInfo = Translate("Open String Formatting Help"); + } + SendMessage(GetDlgItem(hwndDlg, uIDButton), BUTTONADDTOOLTIP, (WPARAM)szTipInfo, 0); + SendDlgItemMessage(hwndDlg, uIDButton, BUTTONSETASFLATBTN, 0, 0); + } + else { + SetDlgItemText(hwndDlg, uIDButton, _T("V")); + } + } + else { + res = -1; + } + ShowWindow(GetDlgItem(hwndDlg, uIDButton), ServiceExists(MS_VARS_FORMATSTRING)); + + return res; +} +#endif + + +#define MS_VARS_SHOWHELP "Vars/ShowHelp" + +// WARNING: This service is obsolete, please use MS_VARS_SHOWHELPEX + +// Shows a help dialog where all possible tokens are displayed. The tokens +// are explained on the dialog, too. The user can edit the initial string and +// insert as many tokens as he likes. + +// Parameters: +// ------------------------ +// wParam = (HWND)hwndEdit +// Handle to an edit control in which the modified string +// should be inserted (When the user clicks OK in the dialog the edited +// string will be set to hwndEdit) (can be NULL). +// lParam = (char *)pszInitialString +// String that the user is provided with initially when +// the dialog gets opened (If this is NULL then the current text in the +// hwndEdit edit control will be used) (can be NULL). + +// Return Value: +// ------------------------ +// Returns the handle to the help dialog (HWND). + +// Note: Only one help dialog can be opened at a time. When the dialog gets +// closed an EN_CHANGE of the edit controll will be triggered because the +// contents were updated. (Only when user selected OK). + +// Example: +// CallService(MS_VARS_SHOWHELP, (WPARAM)hwndEdit, (LPARAM)"some initial text"); + +// -------------------------------------------------------------------------- +// Retrieve a contact's HANDLE given a string +// -------------------------------------------------------------------------- + +#define MS_VARS_GETCONTACTFROMSTRING "Vars/GetContactFromString" + +// Searching for contacts in the database. You can find contacts in db by +// searching for their name, e.g first name. + +// Parameters: +// ------------------------ +// wParam = (WPARAM)(CONTACTSINFO *)&ci +// See below. +// lParam = 0 + +// Return Value: +// ------------------------ +// Returns number of contacts found matching the given string representation. +// The hContacts array of CONTACTSINFO struct contains these hContacts after +// the call. + +// Note: The hContacts array needs to be freed after use using +// MS_VARS_FREEMEMORY. + +typedef struct { + int cbSize; // Set this to sizeof(CONTACTSINFO). + union { + char *szContact; // String to search for, e.g. last name (can't be NULL). + WCHAR * wszContact; + TCHAR *tszContact; + }; + HANDLE *hContacts; // (output) Array of contacts found. + DWORD flags; // Contact details that will be matched with the search + // string (flags can be combined). +} CONTACTSINFO; + +// Possible flags: +#define CI_PROTOID 0x00000001 // The contact in the string is encoded + // in the format , e.g. + // . +#define CI_NICK 0x00000002 // Search nick names. +#define CI_LISTNAME 0x00000004 // Search custom names shown in contact + // list. +#define CI_FIRSTNAME 0x00000008 // Search contact's first names (contact + // details). +#define CI_LASTNAME 0x00000010 // Search contact's last names (contact + // details). +#define CI_EMAIL 0x00000020 // Search contact's email adresses + // (contact details). +#define CI_UNIQUEID 0x00000040 // Search unique ids of the contac, e.g. + // UIN. +#define CI_CNFINFO 0x40000000 // Searches one of the CNF_* flags (set + // flags to CI_CNFINFO|CNF_X), only one + // CNF_ type possible +#define CI_UNICODE 0x80000000 // tszContact is a unicode string + // (WCHAR*). + +#if defined(UNICODE) || defined(_UNICODE) +#define CI_TCHAR CI_UNICODE // Strings in structure are TCHAR*. +#else +#define CI_TCHAR 0 +#endif + + + +#endif //__M_VARS diff --git a/stopspam/src/opt_proto.cpp b/stopspam/src/opt_proto.cpp new file mode 100644 index 0000000..201fba6 --- /dev/null +++ b/stopspam/src/opt_proto.cpp @@ -0,0 +1,137 @@ +#include "../headers.h" + +struct ProtocolData +{ + char *RealName; + int show,enabled; +}; + +int IsProtoIM(const PROTOACCOUNT* pa) +{ + return (CallProtoService(pa->szModuleName, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_IM); +} + +int FillTree(HWND hwnd) +{ + ProtocolData *PD; + int i,n; + PROTOACCOUNT** pa; + + TVINSERTSTRUCT tvis; + tvis.hParent = NULL; + tvis.hInsertAfter = TVI_LAST; + tvis.item.mask = TVIF_PARAM|TVIF_TEXT|TVIF_IMAGE|TVIF_SELECTEDIMAGE; + + TreeView_DeleteAllItems(hwnd); + + if(CallService(MS_PROTO_ENUMACCOUNTS, (LPARAM)&n, (WPARAM)&pa)) + return FALSE; + + for ( i = 0; i < n; i++ ) { + if(IsAccountEnabled( pa[i] )){ + PD = ( ProtocolData* )mir_alloc( sizeof( ProtocolData )); + PD->RealName = pa[i]->szModuleName; + PD->enabled = IsProtoIM( pa[i]); + PD->show = PD->enabled ? (plSets->ProtoDisabled(PD->RealName)?1:0) : 100; + + tvis.item.lParam = ( LPARAM )PD; + tvis.item.pszText = pa[i]->tszAccountName; + tvis.item.iImage = tvis.item.iSelectedImage = PD->show; + TreeView_InsertItem( hwnd, &tvis ); + } + } + + return 0; +} + +INT_PTR CALLBACK ProtoDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + HWND hwndProto = GetDlgItem(hwnd, IDC_PROTO); + + switch (msg) + { + + case WM_INITDIALOG: + TranslateDialogDefault(hwnd); + + SetWindowLong(hwndProto, GWL_STYLE, GetWindowLong(hwndProto, GWL_STYLE) | TVS_NOHSCROLL); + { + HIMAGELIST himlCheckBoxes = ImageList_Create( GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), ILC_COLOR32|ILC_MASK, 2, 2 ); + HICON Icon; + Icon=(HICON)LoadSkinnedIcon(SKINICON_OTHER_NOTICK); + ImageList_AddIcon(himlCheckBoxes, Icon); + CallService(MS_SKIN2_RELEASEICON, (WPARAM)Icon, 0); + Icon=(HICON)LoadSkinnedIcon(SKINICON_OTHER_TICK); + ImageList_AddIcon(himlCheckBoxes, Icon); + CallService(MS_SKIN2_RELEASEICON, (WPARAM)Icon, 0); + + TreeView_SetImageList(hwndProto, himlCheckBoxes, TVSIL_NORMAL); + } + + FillTree(hwndProto); + return TRUE; + + case WM_NOTIFY: + switch(((LPNMHDR)lParam)->idFrom) { + case 0: + if (((LPNMHDR)lParam)->code == PSN_APPLY ) { + + std::ostringstream out; + + TVITEM tvi; + tvi.hItem = TreeView_GetRoot(hwndProto); + tvi.cchTextMax = 32; + tvi.mask = TVIF_PARAM | TVIF_HANDLE; + + while ( tvi.hItem != NULL ) { + TreeView_GetItem(hwndProto, &tvi); + + if (tvi.lParam!=0) { + ProtocolData* ppd = ( ProtocolData* )tvi.lParam; + if(ppd->enabled && ppd->show) + out << ppd->RealName << " "; + } + + tvi.hItem = TreeView_GetNextSibling(hwndProto, tvi.hItem ); + } + + plSets->DisabledProtoList=out.str(); + } + break; + + case IDC_PROTO: + switch (((LPNMHDR)lParam)->code) { + case TVN_DELETEITEMA: + { + NMTREEVIEWA * pnmtv = (NMTREEVIEWA *) lParam; + if (pnmtv && pnmtv->itemOld.lParam) + mir_free((ProtocolData*)pnmtv->itemOld.lParam); + } + break; + + case NM_CLICK: + { + TVHITTESTINFO hti; + hti.pt.x=(short)LOWORD(GetMessagePos()); + hti.pt.y=(short)HIWORD(GetMessagePos()); + ScreenToClient(((LPNMHDR)lParam)->hwndFrom,&hti.pt); + if ( TreeView_HitTest(((LPNMHDR)lParam)->hwndFrom, &hti )) { + if ( hti.flags & TVHT_ONITEMICON ) { + TVITEMA tvi; + tvi.mask = TVIF_HANDLE|TVIF_IMAGE|TVIF_SELECTEDIMAGE; + tvi.hItem = hti.hItem; + TreeView_GetItem(((LPNMHDR)lParam)->hwndFrom,&tvi); + + ProtocolData *pData = ( ProtocolData* )tvi.lParam; + if ( pData->enabled ) { + tvi.iImage = tvi.iSelectedImage = !tvi.iImage; + pData->show = tvi.iImage; + TreeView_SetItem(((LPNMHDR)lParam)->hwndFrom,&tvi); + SendMessage(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0); + } } } } } + break; + } + break; + } + return FALSE; +} diff --git a/stopspam/src/options.cpp b/stopspam/src/options.cpp new file mode 100644 index 0000000..52fab03 --- /dev/null +++ b/stopspam/src/options.cpp @@ -0,0 +1,133 @@ +#include "../headers.h" + +char * pluginDescription = "No more spam! Robots can't go! Only human beings invited!\r\n\r\n" +"This plugin works pretty simple:\r\n" +"While messages from users on your contact list go as there is no any anti-spam software, " +"messages from unknown users are not delivered to you. " +"But also they are not ignored, this plugin replies with a simple question, " +"and if user gives the right answer plugin adds him to your contact list " +"so that he can contact you."; +TCHAR const * infTalkProtPrefix = _T("StopSpam automatic message:\r\n"); +char const * answeredSetting = "Answered"; +char const * questCountSetting = "QuestionCount"; + +INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + + switch(msg) + { + case WM_INITDIALOG: + { + SetDlgItemTextA(hwnd, ID_DESCRIPTION, pluginDescription); + TranslateDialogDefault(hwnd); + SetDlgItemInt(hwnd, ID_MAXQUESTCOUNT, plSets->MaxQuestCount.Get(), FALSE); + SendDlgItemMessage(hwnd, ID_INFTALKPROT, BM_SETCHECK, plSets->InfTalkProtection.Get() ? BST_CHECKED : BST_UNCHECKED, 0); + SendDlgItemMessage(hwnd, ID_ADDPERMANENT, BM_SETCHECK, plSets->AddPermanent.Get() ? BST_CHECKED : BST_UNCHECKED, 0); + SendDlgItemMessage(hwnd, ID_HANDLEAUTHREQ, BM_SETCHECK, plSets->HandleAuthReq.Get() ? BST_CHECKED : BST_UNCHECKED, 0); + SendDlgItemMessage(hwnd, ID_NOTCASESENS, BM_SETCHECK, plSets->AnswNotCaseSens.Get() ? BST_CHECKED : BST_UNCHECKED, 0); + SendDlgItemMessage(hwnd, ID_REMOVE_TMP_ALL, BM_SETCHECK, plSets->RemTmpAll.Get() ? BST_CHECKED : BST_UNCHECKED, 0); + SendDlgItemMessage(hwnd, ID_HISTORY_LOG, BM_SETCHECK, plSets->HistLog.Get() ? BST_CHECKED : BST_UNCHECKED, 0); + } + return TRUE; + case WM_COMMAND:{ + switch (LOWORD(wParam)) + { + case ID_MAXQUESTCOUNT: + { + if (EN_CHANGE != HIWORD(wParam) || (HWND)lParam != GetFocus()) + return FALSE; + break; + } + } + SendMessage(GetParent(hwnd), PSM_CHANGED, 0, 0); + } + break; + case WM_NOTIFY: + { + NMHDR* nmhdr = (NMHDR*)lParam; + switch (nmhdr->code) + { + case PSN_APPLY: + { + plSets->MaxQuestCount=GetDlgItemInt(hwnd, ID_MAXQUESTCOUNT, NULL, FALSE); + plSets->InfTalkProtection=(BST_CHECKED == SendDlgItemMessage(hwnd, ID_INFTALKPROT, BM_GETCHECK, 0, 0)); + plSets->AddPermanent=(BST_CHECKED == SendDlgItemMessage(hwnd, ID_ADDPERMANENT, BM_GETCHECK, 0, 0)); + plSets->HandleAuthReq=(BST_CHECKED == SendDlgItemMessage(hwnd, ID_HANDLEAUTHREQ, BM_GETCHECK, 0, 0)); + plSets->AnswNotCaseSens=(BST_CHECKED == SendDlgItemMessage(hwnd, ID_NOTCASESENS, BM_GETCHECK, 0, 0)); + plSets->RemTmpAll=(BST_CHECKED == SendDlgItemMessage(hwnd, ID_REMOVE_TMP_ALL, BM_GETCHECK, 0, 0)); + plSets->HistLog=(BST_CHECKED == SendDlgItemMessage(hwnd, ID_HISTORY_LOG, BM_GETCHECK, 0, 0)); + } + return TRUE; + } + } + break; + } + return FALSE; +} + +INT_PTR CALLBACK MessagesDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + + switch(msg) + { + case WM_INITDIALOG: + { + TranslateDialogDefault(hwnd); + SetDlgItemString(hwnd, ID_QUESTION, plSets->Question.Get()); + SetDlgItemString(hwnd, ID_ANSWER, plSets->Answer.Get()); + SetDlgItemString(hwnd, ID_CONGRATULATION, plSets->Congratulation.Get()); + SetDlgItemString(hwnd, ID_AUTHREPL, plSets->AuthRepl.Get()); + SetDlgItemString(hwnd, ID_DIVIDER, plSets->AnswSplitString.Get()); + variables_skin_helpbutton(hwnd, IDC_VARS); + ServiceExists(MS_VARS_FORMATSTRING)?EnableWindow(GetDlgItem(hwnd, IDC_VARS),1):EnableWindow(GetDlgItem(hwnd, IDC_VARS),0); + } + return TRUE; + case WM_COMMAND: + { + switch(LOWORD(wParam)) + { + case ID_QUESTION: + case ID_ANSWER: + case ID_AUTHREPL: + case ID_CONGRATULATION: + case ID_DIVIDER: + { + if (EN_CHANGE != HIWORD(wParam) || (HWND)lParam != GetFocus()) + return FALSE; + break; + } + case ID_RESTOREDEFAULTS: + SetDlgItemString(hwnd, ID_QUESTION, plSets->Question.GetDefault()); + SetDlgItemString(hwnd, ID_ANSWER, plSets->Answer.GetDefault()); + SetDlgItemString(hwnd, ID_CONGRATULATION, plSets->Congratulation.GetDefault()); + SetDlgItemString(hwnd, ID_AUTHREPL, plSets->AuthRepl.GetDefault()); + SetDlgItemString(hwnd, ID_DIVIDER, plSets->AnswSplitString.GetDefault()); + SendMessage(GetParent(hwnd), PSM_CHANGED, 0, 0); + return TRUE; + case IDC_VARS: + variables_showhelp(hwnd, msg, VHF_FULLDLG|VHF_SETLASTSUBJECT, NULL, NULL); + return TRUE; + } + SendMessage(GetParent(hwnd), PSM_CHANGED, 0, 0); + } + break; + case WM_NOTIFY: + { + NMHDR* nmhdr = (NMHDR*)lParam; + switch (nmhdr->code) + { + case PSN_APPLY: + { + plSets->Question=GetDlgItemString(hwnd, ID_QUESTION); + plSets->Answer=GetDlgItemString(hwnd, ID_ANSWER); + plSets->AuthRepl=GetDlgItemString(hwnd, ID_AUTHREPL); + plSets->Congratulation=GetDlgItemString(hwnd, ID_CONGRATULATION); + plSets->AnswSplitString=GetDlgItemString(hwnd, ID_DIVIDER); + } + return TRUE; + } + } + break; + } + return FALSE; +} diff --git a/stopspam/src/services.cpp b/stopspam/src/services.cpp new file mode 100644 index 0000000..12ff332 --- /dev/null +++ b/stopspam/src/services.cpp @@ -0,0 +1,80 @@ +#include "../headers.h" + +INT_PTR IsContactPassed(WPARAM wParam, LPARAM /*lParam*/) +{ + HANDLE hContact = ( HANDLE )wParam; + std::string proto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0 ); + + if ( !plSets->ProtoDisabled( proto.c_str())) + return CS_PASSED; + + if ( DBGetContactSettingByte( hContact, pluginName, answeredSetting, 0 )) + return CS_PASSED; + + if ( !DBGetContactSettingByte( hContact, "CList", "NotOnList", 0) && DBGetContactSettingWord( hContact, proto.c_str(), "SrvGroupId", -1 ) != 1 ) + return CS_PASSED; + + if ( IsExistMyMessage( hContact )) + return CS_PASSED; + + return CS_NOTPASSED; +} + +INT_PTR RemoveTempContacts(WPARAM wParam,LPARAM lParam) +{ + HANDLE hContact = (HANDLE)CallService( MS_DB_CONTACT_FINDFIRST, 0, 0 ); + while ( hContact ) { + HANDLE hNext = (HANDLE)CallService( MS_DB_CONTACT_FINDNEXT, ( WPARAM )hContact, 0 ); + + DBVARIANT dbv = { 0 }; + if ( DBGetContactSettingTString( hContact, "CList", "Group", &dbv )) + dbv.ptszVal = NULL; + + if ( DBGetContactSettingByte( hContact, "CList", "NotOnList", 0 ) || lstrcmp(dbv.ptszVal, _T("Not In List")) == 0 || DBGetContactSettingByte(hContact, "CList", "Hidden", 0 )) { + char *szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + if ( szProto != NULL ) { + // Check if protocol uses server side lists + DWORD caps = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0); + if ( caps & PF1_SERVERCLIST ) { + int status; + status = CallProtoService(szProto, PS_GETSTATUS, 0, 0); + if (status == ID_STATUS_OFFLINE || (status >= ID_STATUS_CONNECTING && status < ID_STATUS_CONNECTING + MAX_CONNECT_RETRIES)) + // Set a flag so we remember to delete the contact when the protocol goes online the next time + DBWriteContactSettingByte( hContact, "CList", "Delete", 1 ); + else + CallService( MS_DB_CONTACT_DELETE, (WPARAM)hContact, 0 ); + } + } + } + + DBFreeVariant( &dbv ); + hContact = hNext; + } + + int hGroup = 1; + char *group_name; + do { + group_name = (char *)CallService(MS_CLIST_GROUPGETNAME, (WPARAM)hGroup, 0); + if ( group_name && lstrcmpA(group_name, "Not In List") == 0 ) { + BYTE ConfirmDelete = DBGetContactSettingByte(NULL, "CList", "ConfirmDelete", SETTING_CONFIRMDELETE_DEFAULT); + if ( ConfirmDelete ) + DBWriteContactSettingByte( NULL, "CList", "ConfirmDelete", 0 ); + + CallService( MS_CLIST_GROUPDELETE, (WPARAM)hGroup, 0 ); + if ( ConfirmDelete ) + DBWriteContactSettingByte( NULL, "CList", "ConfirmDelete", ConfirmDelete ); + break; + } + hGroup++; + } + while( group_name ); + + return 0; +} + +INT_PTR OnSystemModulesLoaded(WPARAM wParam,LPARAM lParam) +{ + if (plSets->RemTmpAll.Get()) + RemoveTempContacts(0,0); + return 0; +} diff --git a/stopspam/src/settings.cpp b/stopspam/src/settings.cpp new file mode 100644 index 0000000..39ce0c9 --- /dev/null +++ b/stopspam/src/settings.cpp @@ -0,0 +1,59 @@ +#include "../headers.h" + +//reading from database------------- +tstring db_usage::DBGetPluginSetting(std::string const &name, tstring const &defValue) +{ + DBVARIANT dbv; + if(DBGetContactSettingTString(NULL, pluginName, name.c_str(), &dbv)) + return defValue; + tstring value = dbv.ptszVal; + DBFreeVariant(&dbv); + return value; +} + +#ifdef _UNICODE +std::string db_usage::DBGetPluginSetting(std::string const &name, std::string const &defValue) +{ + DBVARIANT dbv; + if(DBGetContactSettingString(NULL, pluginName, name.c_str(), &dbv)) + return defValue; + std::string value = dbv.pszVal; + DBFreeVariant(&dbv); + return value; +} +#endif + +bool db_usage::DBGetPluginSetting(std::string const &name, bool const &defValue) +{ + return(0 != DBGetContactSettingByte(NULL, pluginName, name.c_str(), defValue?1:0)); +} + +DWORD db_usage::DBGetPluginSetting(std::string const &name, DWORD const &defValue) +{ + return DBGetContactSettingDword(NULL, pluginName, name.c_str(), defValue); +} + +//writting to database-------------- +void db_usage::DBSetPluginSetting(std::string const &name, tstring const &value) +{ + DBWriteContactSettingTString(NULL, pluginName, name.c_str(), value.c_str()); +} + +#ifdef _UNICODE +void db_usage::DBSetPluginSetting(std::string const &name, std::string const &value) +{ + DBWriteContactSettingString(NULL, pluginName, name.c_str(), value.c_str()); +} +#endif + +void db_usage::DBSetPluginSetting(std::string const &name, bool const &value) +{ + DBWriteContactSettingByte(NULL, pluginName, name.c_str(), value?1:0); +} + +void db_usage::DBSetPluginSetting(std::string const &name, DWORD const &value) +{ + DBWriteContactSettingDword(NULL, pluginName, name.c_str(),value); +} + +Settings *plSets; diff --git a/stopspam/src/settings.h b/stopspam/src/settings.h new file mode 100644 index 0000000..5fe2b43 --- /dev/null +++ b/stopspam/src/settings.h @@ -0,0 +1,100 @@ +#pragma once + +#include "../headers.h" + +class db_usage +{ +public: + //reading from database + static tstring DBGetPluginSetting(std::string const &name, tstring const &defValue); +#ifdef _UNICODE + static std::string DBGetPluginSetting(std::string const &name, std::string const &defValue); +#endif + static bool DBGetPluginSetting(std::string const &name, bool const &defValue); + static DWORD DBGetPluginSetting(std::string const &name, DWORD const &defValue); + //writting to database + static void DBSetPluginSetting(std::string const &name, tstring const &value); +#ifdef _UNICODE + static void DBSetPluginSetting(std::string const &name, std::string const &value); +#endif + static void DBSetPluginSetting(std::string const &name, bool const &value); + static void DBSetPluginSetting(std::string const &name, DWORD const &value); + +}; + +template +class db_setting +{ + std::string m_name; + T m_defValue; + T m_value; +public: + db_setting(std::string const &name, T const &defValue):m_name(name),m_defValue(defValue) + { + m_value=db_usage::DBGetPluginSetting(m_name, m_defValue); + } + const T & GetDefault()const{return m_defValue;} + void Set(T const &value) + { + m_value=value; + db_usage::DBSetPluginSetting(m_name, m_value); + } + const T & Get()const{return m_value;} + db_setting& operator=(T const &value) + { + m_value=value; + db_usage::DBSetPluginSetting(m_name, m_value); + return *this; + } + operator T(){return m_value;} + void SetResident(BOOL bResident){ + CallService(MS_DB_SETSETTINGRESIDENT, bResident, (LPARAM)(pluginName m_name.c_str())); + } +}; + +class Settings +{ +public: + db_setting Question; + db_setting AuthRepl; + db_setting Answer; + db_setting Congratulation; + db_setting DisabledProtoList; + db_setting InfTalkProtection; + db_setting AddPermanent; + db_setting MaxQuestCount; + db_setting HandleAuthReq; + db_setting AnswNotCaseSens; + db_setting AnswSplitString; + db_setting RemTmpAll; + db_setting HistLog; + + Settings():Question("Question",TranslateTS(_T("Spammers made me to install small anti-spam system you are now speaking with. ") + _T("Please reply \"nospam\" without quotes and spaces if you want to contact me.\r\n") + _T("Внимание! Антиспам защита. Ответьте \"nospam\" без кавычек и пробелов, если хотите связаться со мной."))) + ,AuthRepl("AuthReply",TranslateTS(_T("StopSpam: send a message and reply to a anti-spam bot question.\r\n") + _T("Антиспам: отправьте сообщение и ответьте на вопрос антиспам системы."))) + ,Answer("Answer",TranslateT("nospam")) + ,Congratulation("Congratulation",TranslateTS(_T("Congratulations! You just passed human/robot test. Now you can write me a message.\r\n") + _T("Поздравляю! Вы прошли антиспам проверку. Теперь вы можете писать мне."))) + ,DisabledProtoList("DisabledProtoList","MetaContacts RSSNews") + ,InfTalkProtection("InfTalkProtection", 1) + ,AddPermanent("AddPermanent", 0) + ,HandleAuthReq("HandleAuthReq", 0) + ,MaxQuestCount("MaxQuestCount", 2) + ,AnswNotCaseSens("AnswNotCaseSens", 1) + ,AnswSplitString("AnswSplitString",_T("|")) + ,RemTmpAll("RemTmpAll", 1) + ,HistLog("HistLog", 0) + { + const std::string& str = DisabledProtoList.Get(); + if ( !str.empty() && *(str.rbegin()) != ' ' ) + DisabledProtoList=DisabledProtoList.Get()+' '; + } + bool ProtoDisabled(std::string proto) + { + return std::string::npos != DisabledProtoList.Get().find(proto + " "); + } +}; + +extern Settings *plSets; diff --git a/stopspam/src/stopspam.cpp b/stopspam/src/stopspam.cpp new file mode 100644 index 0000000..4b84d10 --- /dev/null +++ b/stopspam/src/stopspam.cpp @@ -0,0 +1,103 @@ +#include "../headers.h" + +struct MM_INTERFACE mmi; + +UTF8_INTERFACE utfi; + +HANDLE hFunc; + + +///////////////////////////////////////////////////////////////////////////////////////// +// returns plugin's extended information + +// {553811EE-DEB6-48b8-8902-A8A00C1FD679} +#define MIID_STOPSPAM { 0x553811ee, 0xdeb6, 0x48b8, { 0x89, 0x2, 0xa8, 0xa0, 0xc, 0x1f, 0xd6, 0x79 } } + +PLUGININFOEX pluginInfoEx = { + sizeof(PLUGININFOEX), + __PLUGIN_NAME, + PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM), + __DESC, + __AUTHOR, + __AUTHOREMAIL, + __COPYRIGHT, + __AUTHORWEB, + UNICODE_AWARE, + 0, + MIID_STOPSPAM +}; + +PLUGINLINK *pluginLink; +HINSTANCE hInst; + +_inline unsigned int MakeVer(int a,int b,int c,int d) +{ + return PLUGIN_MAKE_VERSION(a,b,c,d); +} + +extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion) +{ + if ( mirandaVersion < MakeVer(__PRODVERSION_STRING)) + return NULL; + + return &pluginInfoEx; +} + +BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved) +{ + hInst = hinstDLL; + return TRUE; +} + + +///////////////////////////////////////////////////////////////////////////////////////// +// returns plugin's interfaces information + +static const MUUID interfaces[] = { MIID_STOPSPAM, MIID_LAST }; + +extern "C" __declspec(dllexport) const MUUID* MirandaPluginInterfaces(void) +{ + return interfaces; +} + +extern "C" int __declspec(dllexport) Load(PLUGINLINK *link) +{ + CLISTMENUITEM mi; + pluginLink = link; + mir_getMMI(&mmi); + mir_getUTFI(&utfi); + + plSets=new Settings; + + hFunc = CreateServiceFunction(MS_STOPSPAM_CONTACTPASSED, IsContactPassed); + + HookEvent(ME_SYSTEM_MODULESLOADED, OnSystemModulesLoaded); + + // Add deliting temporary contacts + CreateServiceFunction(pluginName"/RemoveTempContacts", RemoveTempContacts); + ZeroMemory(&mi, sizeof(mi)); + mi.cbSize = sizeof(mi); + mi.position = -0x7FFFFFFF; + mi.flags = CMIF_TCHAR; + mi.hIcon=LoadSkinnedIcon(SKINICON_OTHER_MIRANDA); + mi.ptszName = _T("Remove Temporary Contacts"); + mi.pszService = pluginName"/RemoveTempContacts"; + CallService(MS_CLIST_ADDMAINMENUITEM, 0, (LPARAM)&mi); + + miranda::EventHooker::HookAll(); + return 0; +} + +extern "C" int __declspec(dllexport) Unload(void) +{ + miranda::EventHooker::UnhookAll(); + + if(hFunc) + { + DestroyServiceFunction(hFunc); + hFunc = 0; + } + delete plSets; + + return 0; +} \ No newline at end of file diff --git a/stopspam/src/utils.cpp b/stopspam/src/utils.cpp new file mode 100644 index 0000000..673a858 --- /dev/null +++ b/stopspam/src/utils.cpp @@ -0,0 +1,77 @@ +#include "../headers.h" + + +tstring &GetDlgItemString(HWND hwnd, int id) +{ + HWND h = GetDlgItem(hwnd, id); + int len = GetWindowTextLength(h); + TCHAR * buf = new TCHAR[len + 1]; + GetWindowText(h, buf, len + 1); + static tstring s; + s = buf; + delete []buf; + return s; +} + +bool IsExistMyMessage(HANDLE hContact) +{ + DBEVENTINFO dbei = { 0 }; + HANDLE hDbEvent = (HANDLE)CallService(MS_DB_EVENT_FINDFIRST, (WPARAM)hContact, 0); + while(hDbEvent){ + ZeroMemory(&dbei, sizeof(dbei)); + dbei.cbSize = sizeof(dbei); + + if (CallService(MS_DB_EVENT_GET, (WPARAM)hDbEvent, (LPARAM)&dbei)) break; + if(dbei.flags & DBEF_SENT){ + // mark contact as Answered + DBWriteContactSettingByte(hContact, pluginName, answeredSetting, 1); + // ...let the event go its way + return true; + } + hDbEvent = (HANDLE)CallService(MS_DB_EVENT_FINDNEXT, (WPARAM)hDbEvent, 0); + } + return false; +} + +void SetDlgItemString(HWND hwndDlg, UINT idItem, std::string const &str) +{ + SetDlgItemTextA(hwndDlg, idItem, str.c_str()); +} + +void SetDlgItemString(HWND hwndDlg, UINT idItem, std::wstring const &str) +{ + SetDlgItemTextW(hwndDlg, idItem, str.c_str()); +} + +tstring variables_parse(tstring const &tstrFormat, HANDLE hContact){ + if (ServiceExists(MS_VARS_FORMATSTRING)) { + FORMATINFO fi; + TCHAR *tszParsed; + tstring tstrResult; + + ZeroMemory(&fi, sizeof(fi)); + fi.cbSize = sizeof(fi); + fi.tszFormat = _tcsdup(tstrFormat.c_str()); + fi.hContact = hContact; + fi.flags |= FIF_TCHAR; + tszParsed = (TCHAR *)CallService(MS_VARS_FORMATSTRING, (WPARAM)&fi, 0); + free(fi.tszFormat); + if (tszParsed) { + tstrResult = tszParsed; + CallService(MS_VARS_FREEMEMORY, (WPARAM)tszParsed, 0); + return tstrResult; + } + } + return tstrFormat; +} + +tstring trim(const tstring &tstr, const tstring& trimChars) +{ + size_t s = tstr.find_first_not_of(trimChars); + size_t e = tstr.find_last_not_of (trimChars); + + if ((tstring::npos == s) || ( tstring::npos == e)) + return _T(""); + else + return tstr.substr(s, e - s + 1); +} \ No newline at end of file -- cgit v1.2.3