/* Miranda IM: the free IM client for Microsoft* Windows* Copyright 2000-2009 Miranda ICQ/IM project, all portions of this codebase are copyrighted to the people listed in contributors.txt. 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 "..\..\core\commonheaders.h" #include //Protocol chain is list of integers "0".."n", with network protocol named "p" INT_PTR Proto_CallContactService(WPARAM wParam, LPARAM lParam) //note that this is ChainSend() too, due to a quirk of function definitions { CCSDATA *ccs = (CCSDATA*)lParam; int i; char str[10]; DBVARIANT dbv; INT_PTR ret; PROTOACCOUNT* pa; if (wParam == (WPARAM)(-1)) return 1; for (i = wParam;; i++) { _itoa(i, str, 10); if (DBGetContactSettingString(ccs->hContact, "_Filter", str, &dbv)) break; if ((ret = CallProtoServiceInt(NULL,dbv.pszVal, ccs->szProtoService, i+1, lParam)) != CALLSERVICE_NOTFOUND) { //chain was started, exit mir_free(dbv.pszVal); return ret; } mir_free(dbv.pszVal); } if (DBGetContactSettingString(ccs->hContact, "Protocol", "p", &dbv)) return 1; pa = Proto_GetAccount(dbv.pszVal); if (pa == NULL || pa->ppro == NULL) ret = 1; else { if (pa->bOldProto) ret = CallProtoServiceInt(ccs->hContact, dbv.pszVal, ccs->szProtoService, (WPARAM)(-1), (LPARAM)ccs); else ret = CallProtoServiceInt(ccs->hContact, dbv.pszVal, ccs->szProtoService, ccs->wParam, ccs->lParam); if (ret == CALLSERVICE_NOTFOUND) ret = 1; } mir_free(dbv.pszVal); return ret; } static INT_PTR CallRecvChain(WPARAM wParam, LPARAM lParam) { CCSDATA *ccs = (CCSDATA*)lParam; int i; INT_PTR ret; char str[10]; DBVARIANT dbv; PROTOACCOUNT* pa; if (wParam == (WPARAM)(-1)) return 1; //shouldn't happen - sanity check if (wParam == 0) { //begin processing by finding end of chain for (;;wParam++) { _itoa(wParam, str, 10); if (DBGetContactSettingString(ccs->hContact, "_Filter", str, &dbv)) break; mir_free(dbv.pszVal); } } else wParam--; for (i = wParam-1; i >= 0; i--) { _itoa(i, str, 10); if (DBGetContactSettingString(ccs->hContact, "_Filter", str, &dbv)) //never happens return 1; if ((ret = CallProtoServiceInt(NULL,dbv.pszVal, ccs->szProtoService, i+1, lParam)) != CALLSERVICE_NOTFOUND) { //chain was started, exit mir_free(dbv.pszVal); return ret; } mir_free(dbv.pszVal); } //end of chain, call network protocol again if (DBGetContactSettingString(ccs->hContact, "Protocol", "p", &dbv)) return 1; pa = Proto_GetAccount(dbv.pszVal); if (pa == NULL || pa->ppro == NULL) ret = 1; else { if (pa->bOldProto) ret = CallProtoServiceInt(ccs->hContact, dbv.pszVal, ccs->szProtoService, (WPARAM)(-1), (LPARAM)ccs); else ret = CallProtoServiceInt(ccs->hContact, dbv.pszVal, ccs->szProtoService, ccs->wParam, ccs->lParam); if (ret == CALLSERVICE_NOTFOUND) ret = 1; } mir_free(dbv.pszVal); return ret; } static INT_PTR Proto_ChainRecv(WPARAM wParam, LPARAM lParam) { /* this will switch threads just like before */ return CallServiceSync(MS_PROTO_CHAINRECV "ThreadSafe", wParam, lParam); } PROTOACCOUNT* __fastcall Proto_GetAccount(HANDLE hContact) { DBVARIANT dbv; DBCONTACTGETSETTING dbcgs; char name[32]; dbv.type = DBVT_ASCIIZ; dbv.pszVal = name; dbv.cchVal = SIZEOF(name); dbcgs.pValue = &dbv; dbcgs.szModule = "Protocol"; dbcgs.szSetting = "p"; if (CallService(MS_DB_CONTACT_GETSETTINGSTATIC, (WPARAM)hContact, (LPARAM)&dbcgs)) return 0; return Proto_GetAccount((char*)dbv.pszVal); } static INT_PTR Proto_GetContactBaseProto(WPARAM wParam, LPARAM) { PROTOACCOUNT* pa = Proto_GetAccount((HANDLE)wParam); return (INT_PTR)(Proto_IsAccountEnabled(pa) ? pa->szModuleName : NULL); } static INT_PTR Proto_GetContactBaseAccount(WPARAM wParam, LPARAM) { PROTOACCOUNT* pa = Proto_GetAccount((HANDLE)wParam); return (INT_PTR)(pa ? pa->szModuleName : NULL); } static INT_PTR Proto_IsProtoOnContact(WPARAM wParam, LPARAM lParam) { int i; char str[10]; DBVARIANT dbv; if ( !lParam) return 0; if ( !DBGetContactSettingString((HANDLE)wParam, "Protocol", "p", &dbv)) { if ( !_stricmp((char*)lParam, dbv.pszVal)) { mir_free(dbv.pszVal); return -1; } mir_free(dbv.pszVal); } for (i=0;;i++) { _itoa(i, str, 10); if (DBGetContactSettingString((HANDLE)wParam, "_Filter", str, &dbv)) break; if ( !strcmp((char*)lParam, dbv.pszVal)) { mir_free(dbv.pszVal); return i+1; } mir_free(dbv.pszVal); } return 0; } static INT_PTR Proto_AddToContact(WPARAM wParam, LPARAM lParam) { PROTOCOLDESCRIPTOR *pd, *pdCompare; pd = Proto_IsProtocolLoaded((char*)lParam); if (pd == NULL) { PROTOACCOUNT* pa = Proto_GetAccount((char*)lParam); if (pa) { DBWriteContactSettingString((HANDLE)wParam, "Protocol", "p", (char*)lParam); return 0; } return 1; } if (pd->type == PROTOTYPE_PROTOCOL) { DBWriteContactSettingString((HANDLE)wParam, "Protocol", "p", (char*)lParam); return 0; } if (Proto_IsProtoOnContact(wParam, lParam)) return 1; { /* v:0.3.3 + PROTO FILTERS ARE NOW KEPT IN THEIR OWN DB MODULE! */ int i; char str[10], *lastProto; DBVARIANT dbv; for (i=0;;i++) { _itoa(i, str, 10); if (DBGetContactSettingString((HANDLE)wParam, "_Filter", str, &dbv)) break; pdCompare = Proto_IsProtocolLoaded((char*)dbv.pszVal); mir_free(dbv.pszVal); if (pdCompare == NULL) continue; if (pd->type > pdCompare->type) break; } //put the new module at position i lastProto = mir_strdup((char*)lParam); for (;;i++) { _itoa(i, str, 10); if (DBGetContactSettingString((HANDLE)wParam, "_Filter", str, &dbv)) { DBWriteContactSettingString((HANDLE)wParam, "_Filter", str, lastProto); mir_free(lastProto); break; } DBWriteContactSettingString((HANDLE)wParam, "_Filter", str, lastProto); mir_free(lastProto); lastProto = dbv.pszVal; } } return 0; } static INT_PTR Proto_RemoveFromContact(WPARAM wParam, LPARAM lParam) { int i; DBVARIANT dbv; char str[10]; i = Proto_IsProtoOnContact(wParam, lParam); if ( !i) return 1; if (i == -1) DBDeleteContactSetting((HANDLE)wParam, "Protocol", "p"); else { for (i--;;i++) { //we have to decrease i, as Proto_IsOnContact returns +1 more number than read from database _itoa(i+1, str, 10); if (0 != DBGetContactSettingString((HANDLE)wParam, "_Filter", str, &dbv)) { _itoa(i, str, 10); DBDeleteContactSetting((HANDLE)wParam, "_Filter", str); break; } _itoa(i, str, 10); DBWriteContactSettingString((HANDLE)wParam, "_Filter", str, dbv.pszVal); mir_free(dbv.pszVal); } } return 0; } int LoadProtoChains(void) { CreateServiceFunction(MS_PROTO_CALLCONTACTSERVICE, Proto_CallContactService); CreateServiceFunction(MS_PROTO_CHAINSEND, Proto_CallContactService); CreateServiceFunction(MS_PROTO_CHAINRECV, Proto_ChainRecv); CreateServiceFunction(MS_PROTO_CHAINRECV "ThreadSafe", CallRecvChain); CreateServiceFunction(MS_PROTO_GETCONTACTBASEPROTO, Proto_GetContactBaseProto); CreateServiceFunction(MS_PROTO_GETCONTACTBASEACCOUNT, Proto_GetContactBaseAccount); CreateServiceFunction(MS_PROTO_ISPROTOONCONTACT, Proto_IsProtoOnContact); CreateServiceFunction(MS_PROTO_ADDTOCONTACT, Proto_AddToContact); CreateServiceFunction(MS_PROTO_REMOVEFROMCONTACT, Proto_RemoveFromContact); return 0; }