/* Copyright (C) Miklashevsky Roman, sss, elzor * * 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 "headers.h" MIRANDA_HOOK_EVENT(ME_DB_CONTACT_ADDED, w, l) { return 0; } MIRANDA_HOOK_EVENT(ME_DB_EVENT_ADDED, wParam, lParam) { HANDLE hContact = (HANDLE)wParam; 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(!ProtoInList(dbei.szModule)) { delete dbei.pBlob; return 0; } // event is an auth request if(gbHandleAuthReq) { if(!(dbei.flags & DBEF_SENT) && !(dbei.flags & DBEF_READ) && dbei.eventType == EVENTTYPE_AUTHREQUEST) { HANDLE hcntct; hcntct=*((PHANDLE)(dbei.pBlob+sizeof(DWORD))); // if request is from unknown or not marked Answered contact int a = DBGetContactSettingByte(hcntct, "CList", "NotOnList", 0); int b = !DBGetContactSettingByte(hcntct, pluginName, "Answered", 0); if(a && b)// { // ...send message if(gbHideContacts) DBWriteContactSettingByte(hcntct, "CList", "Hidden", 1); if(gbSpecialGroup) DBWriteContactSettingTString(hcntct, "CList", "Group", gbSpammersGroup.c_str()); BYTE msg = 1; if(gbIgnoreURL){ TCHAR* EventText = ReqGetText(&dbei); //else return NULL msg=!IsUrlContains(EventText); mir_free(EventText); }; if(gbInvisDisable) { if(CallProtoService(dbei.szModule, PS_GETSTATUS, 0, 0) == ID_STATUS_INVISIBLE) msg = 0; else if(DBGetContactSettingWord(hContact,dbei.szModule,"ApparentMode",0) == ID_STATUS_OFFLINE) msg = 0; //is it useful ? } if(msg) { char * buff=mir_utf8encodeW(variables_parse(gbAuthRepl, hcntct).c_str()); CallContactService(hcntct, PSS_MESSAGE, PREF_UTF, (LPARAM) buff); mir_free(buff); }; 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(!ProtoInList(dbei->szModule)) { // ...let the event go its way return 0; } //do not check excluded contact if(DBGetContactSettingByte(hContact, pluginName, "Answered", 0)) return 0; if(DBGetContactSettingByte(hContact, pluginName, "Excluded", 0)) { if(!DBGetContactSettingByte(hContact, "CList", "NotOnList", 0)) DBDeleteContactSetting(hContact, pluginName, "Excluded"); return 0; } //we want block not only messages, i seen many types other eventtype flood if(dbei->flags & DBEF_READ) // ...let the event go its way return 0; //mark contact which we trying to contact for exclude from check if((dbei->flags & DBEF_SENT) && DBGetContactSettingByte(hContact, "CList", "NotOnList", 0) && (!gbMaxQuestCount || DBGetContactSettingDword(hContact, pluginName, "QuestionCount", 0) < gbMaxQuestCount) && gbExclude) { DBWriteContactSettingByte(hContact, pluginName, "Excluded", 1); return 0; } // if message is from known or marked Answered contact if(!DBGetContactSettingByte(hContact, "CList", "NotOnList", 0)) // ...let the event go its way 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_t* msg_u; char* msg_a = mir_strdup(( char* )dbei->pBlob ); mir_utf8decode( msg_a, &msg_u ); message = msg_u; } else message = mir_a2u((char*)(dbei->pBlob)); // if message contains right answer... BYTE msg = 1; if(gbInvisDisable) { if(CallProtoService(dbei->szModule, PS_GETSTATUS, 0, 0) == ID_STATUS_INVISIBLE) msg = 0; else if(DBGetContactSettingWord(hContact,dbei->szModule,"ApparentMode",0) == ID_STATUS_OFFLINE) msg = 0; //is it useful ? } bool answered = false; if(gbMathExpression) { if(boost::algorithm::all(message, boost::is_digit())) { int msg = _ttoi(message.c_str()); int math_answer = DBGetContactSettingDword(hContact, pluginName, "MathAnswer", 0); if(msg && math_answer) answered = (msg == math_answer); } } else if(!gbRegexMatch) answered = gbCaseInsensitive?(!Stricmp(message.c_str(), (variables_parse(gbAnswer, hContact).c_str()))):( !_tcscmp(message.c_str(), (variables_parse(gbAnswer, hContact).c_str()))); else { if(gbCaseInsensitive) { std::string check(toUTF8(variables_parse(gbAnswer, hContact))), msg(toUTF8(message)); boost::algorithm::to_upper(check); boost::algorithm::to_upper(msg); boost::regex expr(check); answered = boost::regex_search(msg.begin(), msg.end(), expr); } else { std::string check(toUTF8(variables_parse(gbAnswer, hContact))), msg(toUTF8(message)); boost::regex expr(check); answered = boost::regex_search(msg.begin(), msg.end(), expr); } } if(answered) { // unhide contact DBDeleteContactSetting(hContact, "CList", "Hidden"); DBDeleteContactSetting(hContact, pluginName, "MathAnswer"); // mark contact as Answered DBWriteContactSettingByte(hContact, pluginName, "Answered", 1); //add contact permanently if(gbAddPermanent) //do not use this ) DBDeleteContactSetting(hContact, "CList", "NotOnList"); // send congratulation if(msg) { tstring prot=DBGetContactSettingStringPAN(NULL,dbei->szModule,"AM_BaseProto", _T("")); // for notICQ protocols or disable auto auth. reqwest if((Stricmp(_T("ICQ"),prot.c_str()))||(!gbAutoReqAuth)) { #ifdef _UNICODE char * buf=mir_utf8encodeW(variables_parse(gbCongratulation, hContact).c_str()); CallContactService(hContact, PSS_MESSAGE, PREF_UTF, (LPARAM)buf); mir_free(buf); #else CallContactService(hContact, PSS_MESSAGE, 0, (LPARAM)GetCongratulation().c_str()); #endif }; // Note: For ANSI can be not work if(!Stricmp(_T("ICQ"),prot.c_str())){ // grand auth. if(gbAutoAuth) CallProtoService(dbei->szModule, "/GrantAuth", w, 0); // add contact to server list and local group if(gbAutoAddToServerList) { DBWriteContactSettingTString(hContact, "CList", "Group", gbAutoAuthGroup.c_str()); CallProtoService(dbei->szModule, "/AddServerContact", w, 0); DBDeleteContactSetting(hContact, "CList", "NotOnList"); }; // auto auth. reqwest with send congratulation if(gbAutoReqAuth) CallContactService(hContact,PSS_AUTHREQUESTW,0, (LPARAM)variables_parse(gbCongratulation, hContact).c_str()); } } return 0; } // URL contains check msg=(msg&&gbIgnoreURL)?(!IsUrlContains((TCHAR *) message.c_str())):msg; // if message message does not contain infintite talk protection prefix // and question count for this contact is less then maximum if(msg) { if((!gbInfTalkProtection || tstring::npos==message.find(_T("StopSpam automatic message:\r\n"))) && (!gbMaxQuestCount || DBGetContactSettingDword(hContact, pluginName, "QuestionCount", 0) < gbMaxQuestCount)) { // send question tstring q; if(gbInfTalkProtection) q += _T("StopSpam automatic message:\r\n"); if(gbMathExpression) { //parse math expression in question tstring tmp_question = gbQuestion; std::list args; std::list actions; tstring::size_type p1 = gbQuestion.find(_T("X")), p2 = 0; const tstring expr_chars = _T("X+-/*"), expr_acts = _T("+-/*"); while(p1 < gbQuestion.length() && p1 != tstring::npos && expr_chars.find(gbQuestion[p1]) != tstring::npos) { std::string arg; p2 = p1; #ifdef UNICODE for(p1 = gbQuestion.find(_T("X"), p1); (p1 < gbQuestion.length()) && (gbQuestion[p1] == L'X'); ++p1) #else for(p1 = gbQuestion.find(_T("X"), p1); gbQuestion[p1] == 'X'; ++p1) #endif arg += get_random_num(1); #ifdef UNICODE tmp_question.replace(p2, arg.size(), toUTF16(arg)); #else tmp_question.replace(p2, arg.size(), arg); #endif args.push_back(atoi(arg.c_str())); if((p1 < gbQuestion.length()) && (p1 != tstring::npos) && (expr_acts.find(gbQuestion[p1]) != tstring::npos)) actions.push_back(gbQuestion[p1]); ++p1; } int math_answer = 0; math_answer = args.front(); args.pop_front(); while(!args.empty()) { if(!actions.empty()) { switch(actions.front()) { case _T('+'): { math_answer += args.front(); args.pop_front(); } break; case _T('-'): { math_answer -= args.front(); args.pop_front(); } break; case _T('/'): { math_answer /= args.front(); args.pop_front(); } break; case _T('*'): { math_answer *= args.front(); args.pop_front(); } break; } actions.pop_front(); } else break; } DBWriteContactSettingDword(hContact, pluginName, "MathAnswer", math_answer); q += variables_parse(tmp_question, hContact); } else q += variables_parse(gbQuestion, 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, "QuestionCount", 0); DBWriteContactSettingDword(hContact, pluginName, "QuestionCount", questCount + 1); } else { /* if (gbDosServiceExist) { if(gbDosServiceIntegration) { int i; i = rand()%255*13; CallService(MS_DOS_SERVICE, (WPARAM)hContact, (LPARAM)i); } } */ if(gbIgnoreContacts) { DBWriteContactSettingDword(hContact, "Ignore", "Mask1", 0x0000007F); } } } if(gbHideContacts) DBWriteContactSettingByte(hContact, "CList", "Hidden", 1); if(gbSpecialGroup) DBWriteContactSettingTString(hContact, "CList", "Group", gbSpammersGroup.c_str()); DBWriteContactSettingByte(hContact, "CList", "NotOnList", 1); // save first message from contact if (DBGetContactSettingDword(hContact, pluginName, "QuestionCount", 0)<2){ dbei->flags |= DBEF_READ; CallService(MS_DB_EVENT_ADD, (WPARAM)hContact, (LPARAM)dbei); }; // reject processing of the event LogSpamToFile(hContact, message); return 1; } 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, "Answered"); DBDeleteContactSetting(hContact, pluginName, "QuestionCount"); } return 0; }