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 --- miranda-wine/src/modules/protocols/protochains.c | 225 ++++++++++++++++++++ miranda-wine/src/modules/protocols/protocols.c | 134 ++++++++++++ miranda-wine/src/modules/protocols/protodir.c | 248 +++++++++++++++++++++++ 3 files changed, 607 insertions(+) create mode 100644 miranda-wine/src/modules/protocols/protochains.c create mode 100644 miranda-wine/src/modules/protocols/protocols.c create mode 100644 miranda-wine/src/modules/protocols/protodir.c (limited to 'miranda-wine/src/modules/protocols') diff --git a/miranda-wine/src/modules/protocols/protochains.c b/miranda-wine/src/modules/protocols/protochains.c new file mode 100644 index 0000000..e36d95d --- /dev/null +++ b/miranda-wine/src/modules/protocols/protochains.c @@ -0,0 +1,225 @@ +/* + +Miranda IM: the free IM client for Microsoft* Windows* + +Copyright 2000-2006 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 "commonheaders.h" +#include + +int Proto_IsProtocolLoaded(WPARAM wParam,LPARAM lParam); + +//Protocol chain is list of integers "0".."n", with network protocol named "p" +static int 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 ret; + + if(wParam==(WPARAM)(-1)) return 1; + for(i=wParam;;i++) { + _itoa(i,str,10); + if(DBGetContactSetting(ccs->hContact,"_Filter",str,&dbv)) break; + if((ret=CallProtoService(dbv.pszVal,ccs->szProtoService,i+1,lParam))!=CALLSERVICE_NOTFOUND) { + //chain was started, exit + mir_free(dbv.pszVal); + return ret; + } + mir_free(dbv.pszVal); + } + if(DBGetContactSetting(ccs->hContact,"Protocol","p",&dbv)) return 1; + if((ret=CallProtoService(dbv.pszVal,ccs->szProtoService,(WPARAM)(-1),lParam))!=CALLSERVICE_NOTFOUND) { + //chain was started, exit + mir_free(dbv.pszVal); + return ret; + } + mir_free(dbv.pszVal); + return 1; +} + +static int CallRecvChain(WPARAM wParam,LPARAM lParam) +{ + CCSDATA *ccs=(CCSDATA*)lParam; + int i,ret; + char str[10]; + DBVARIANT dbv; + + 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(DBGetContactSetting(ccs->hContact,"_Filter",str,&dbv)) break; + mir_free(dbv.pszVal); + } + } + else wParam--; + for(i=wParam-1;i>=0;i--) { + _itoa(i,str,10); + if(DBGetContactSetting(ccs->hContact,"_Filter",str,&dbv)) return 1; //never happens + if((ret=CallProtoService(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(DBGetContactSetting(ccs->hContact,"Protocol","p",&dbv)) return 1; + if((ret=CallProtoService(dbv.pszVal,ccs->szProtoService,(WPARAM)(-1),lParam))!=CALLSERVICE_NOTFOUND) { + mir_free(dbv.pszVal); + return ret; + } + mir_free(dbv.pszVal); + return 1; +} + +static int Proto_ChainRecv(WPARAM wParam,LPARAM lParam) +{ + /* this will switch threads just like before */ + return CallServiceSync(MS_PROTO_CHAINRECV "ThreadSafe",wParam,lParam); +} + +#if 1 +static int Proto_GetContactBaseProto(WPARAM wParam,LPARAM lParam) +{ + DBVARIANT dbv; + PROTOCOLDESCRIPTOR *pd; + 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,(LPARAM)&dbcgs)) return (int)(char*)NULL; + pd=(PROTOCOLDESCRIPTOR*)Proto_IsProtocolLoaded(0,(LPARAM)dbv.pszVal); + if(pd==NULL) return (int)(char*)NULL; + return (int)pd->szName; +} +#endif + +static int Proto_IsProtoOnContact(WPARAM wParam,LPARAM lParam) +{ + int i; + char str[10]; + DBVARIANT dbv; + + if(!DBGetContactSetting((HANDLE)wParam,"Protocol","p",&dbv)) { + if(!strcmp((char*)lParam,dbv.pszVal)) { + mir_free(dbv.pszVal); + return -1; + } + mir_free(dbv.pszVal); + } + for(i=0;;i++) { + _itoa(i,str,10); + if(DBGetContactSetting((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 Proto_AddToContact(WPARAM wParam,LPARAM lParam) +{ + PROTOCOLDESCRIPTOR *pd,*pdCompare; + + pd=(PROTOCOLDESCRIPTOR*)Proto_IsProtocolLoaded(0,lParam); + if(pd==NULL) 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(DBGetContactSetting((HANDLE)wParam,"_Filter",str,&dbv)) break; + pdCompare=(PROTOCOLDESCRIPTOR*)Proto_IsProtocolLoaded(0,(LPARAM)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(DBGetContactSetting((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 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!=DBGetContactSetting((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_ISPROTOONCONTACT,Proto_IsProtoOnContact); + CreateServiceFunction(MS_PROTO_ADDTOCONTACT,Proto_AddToContact); + CreateServiceFunction(MS_PROTO_REMOVEFROMCONTACT,Proto_RemoveFromContact); + return 0; +} diff --git a/miranda-wine/src/modules/protocols/protocols.c b/miranda-wine/src/modules/protocols/protocols.c new file mode 100644 index 0000000..88b5513 --- /dev/null +++ b/miranda-wine/src/modules/protocols/protocols.c @@ -0,0 +1,134 @@ +/* + +Miranda IM: the free IM client for Microsoft* Windows* + +Copyright 2000-2006 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 "commonheaders.h" + +int LoadProtoChains(void); + +static HANDLE hAckEvent,hTypeEvent; +static int protocolModuleCount; +static PROTOCOLDESCRIPTOR *protocolModule; +static PROTOCOLDESCRIPTOR **pProtocolModules; + +void InitContactDir(void); +void UninitContactDir(void); + +static int Proto_BroadcastAck(WPARAM wParam,LPARAM lParam) +{ + return NotifyEventHooks(hAckEvent,wParam,lParam); +} + +int Proto_IsProtocolLoaded(WPARAM wParam,LPARAM lParam) +{ + int i; + for(i=0;icbSize!=sizeof(PROTOCOLDESCRIPTOR)) return 1; + protocolModule=(PROTOCOLDESCRIPTOR*)mir_realloc(protocolModule,sizeof(PROTOCOLDESCRIPTOR)*(protocolModuleCount+1)); + protocolModule[protocolModuleCount]=*pd; + protocolModule[protocolModuleCount++].szName=mir_strdup(pd->szName); + pProtocolModules=(PROTOCOLDESCRIPTOR**)mir_realloc(pProtocolModules,sizeof(PROTOCOLDESCRIPTOR*)*(protocolModuleCount+1)); + for(i=0;iproto fast, these two caches + share the same data, they're indexes, each entry might not have an "id" set. + + There is a small cache which maintains a protocol list + +*/ + +/* + + The information we need to cache is not readily available, data has to be gathered at startup + when a new contact is created/deleted, when a new proto registers and so on. + + The information we get at startup includes walking the contact chain and reading Protocol/p which + will give us the protocol the contact is on, all this info is stored in contactEntry's within + protoCache ONLY - contactCache is EMPTY at this point. + + We can not fetch the id of the contact because this information is only in SOME protocol plugins, + this is a problem but we'll hook all proto registrations and ask each proto if it supports the + returning this ID name, if not - it won't even use our id <-> contact look so no biggie! + +*/ + +typedef struct { + char * proto; // within proto cache + char * id; // optional + HANDLE hContact; +} contactEntry; + +typedef struct { + CRITICAL_SECTION csLock; + SortedList contactCache; // index for id/proto -> hContact + SortedList protoCache; // index for hContact -> proto/id + SortedList protoNameCache; // index of protocol names +} contactDir; + +static contactDir condir; + +// compare's id/proto and return's hContact's +int contactCacheCompare(void * a, void * b) +{ + contactEntry * x = (contactEntry *) a; + contactEntry * y = (contactEntry *) b; + int rc=0; + // same protocol? + rc = strcmp(x->proto, y->proto); + if ( rc == 0 ) { + // same id? id's might be missing + if ( x->id && y->id ) rc = strcmp(x->id, y->id); + } + return rc; +} + +// compares hContact's and returns associated data +int protoCacheCompare(void * a, void * b) +{ + contactEntry * x = (contactEntry *) a; + contactEntry * y = (contactEntry *) b; + if ( x->hContact < y->hContact ) return -1; + if ( x->hContact > y->hContact ) return 1; + return 0; +} + +// keeps a list of protocol names +int protoNameCacheCompare(void * a, void * b) +{ + return strcmp( (char *)a, (char*)b ); +} + +// cache the protocol string so that its not allocated per contact but shared +char * contactDir_Proto_Add(contactDir * cd, char * proto) +{ + int index = 0 ; + char * szCache = 0; + EnterCriticalSection(&cd->csLock); + if ( List_GetIndex(&cd->protoNameCache, proto, &index) ) szCache = cd->protoNameCache.items[index]; + else { + szCache = HeapAlloc(hCacheHeap, HEAP_NO_SERIALIZE, strlen(proto)+1); + strcpy(szCache, proto); + List_Insert(&cd->protoNameCache, szCache, index); + } + LeaveCriticalSection(&cd->csLock); + return szCache; +} + +// thread safe +char * contactDir_Proto_Get(contactDir * cd, HANDLE hContact) +{ + char * szCache = 0; + int index = 0; + contactEntry e; + e.hContact=hContact; + e.proto=""; + e.id=""; + EnterCriticalSection(&cd->csLock); + if ( List_GetIndex(&cd->protoCache, &e, &index) ) { + contactEntry * p = cd->protoCache.items[index]; + szCache = p->proto; + } + LeaveCriticalSection(&cd->csLock); + return szCache; +} + +// thread tolerant, if updating id dont pass proto, if updating proto dont pass id +void contactDir_Contact_Add(contactDir * cd, HANDLE hContact, char * proto, char * id) +{ + // if a contact is gonna exist anywhere it's going to be in the ->protoCache which has a key of hContact + // if id is not null then the contact should be indexed via the ->contactCache instead + if ( id == NULL ) { + int index = 0; + contactEntry e; + e.hContact=hContact; + e.proto = proto; + e.id = ""; + EnterCriticalSection(&cd->csLock); + if ( List_GetIndex(&cd->protoCache, &e, &index) ) { + contactEntry * p = cd->protoCache.items[index]; + // this hContact is in the cache, protcol changing? + p->proto = contactDir_Proto_Add(cd, proto); // just replace the old pointer + } else { + contactEntry * p = 0; + // this hContact isn't in the cache, add it + p = HeapAlloc(hCacheHeap, HEAP_NO_SERIALIZE, sizeof(contactEntry)); + p->proto = contactDir_Proto_Add(cd, proto); + p->id = 0; + p->hContact = hContact; + // add it + List_Insert(&cd->protoCache, p, index); + } + LeaveCriticalSection(&cd->csLock); + } else { + // this contact HAS to be in ->protoCache since it was added during startup + // need to find the contactEntry* that should already exist for it + } //if +} + +// only expected to be called at startup. +void contactDir_Proto_Walk(contactDir * cd) +{ + HANDLE hContact; + char buf[128]; + DBCONTACTGETSETTING gsProto; + DBVARIANT dbvProto; + // setup the read structure + gsProto.szModule="Protocol"; + gsProto.szSetting="p"; + gsProto.pValue = &dbvProto; + // this might not work + hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + while ( hContact ) { + // and how we'll get the reset + dbvProto.type=DBVT_ASCIIZ; + dbvProto.pszVal = (char *) &buf; + dbvProto.cchVal = SIZEOF(buf); + // figure out what hContact/Protocol/p is + if ( CallService(MS_DB_CONTACT_GETSETTINGSTATIC,(WPARAM)hContact, (LPARAM)&gsProto) == 0 ) { + contactDir_Contact_Add(cd, hContact, buf, NULL); + } + // find next + hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0); + } +} + +// ctor/dtor + +void contactDir_Init(contactDir * cd) +{ + InitializeCriticalSection(&cd->csLock); + cd->contactCache.increment=50; + cd->contactCache.sortFunc=contactCacheCompare; + cd->protoCache.increment=50; + cd->protoCache.sortFunc=protoCacheCompare; + cd->protoNameCache.increment=5; + cd->protoNameCache.sortFunc=protoNameCacheCompare; + // build a list of all hContact's and what proto's they are on + contactDir_Proto_Walk(cd); +} + +void contactDir_Deinit(contactDir * cd) +{ + List_Destroy(&cd->contactCache); + List_Destroy(&cd->protoCache); + List_Destroy(&cd->protoNameCache); + DeleteCriticalSection(&cd->csLock); +} + +static int contactDirGetProto(WPARAM wParam, LPARAM lParam) +{ + return (int) contactDir_Proto_Get(&condir,(HANDLE)wParam); +} + +#endif + +void InitContactDir(void) +{ + return; + //contactDir_Init(&condir); + //CreateServiceFunction(MS_PROTODIR_PROTOFROMCONTACT, contactDirGetProto); +} + + +void UninitContactDir(void) +{ + return; +#if 0 + { + int j; + for ( j = 0; j< condir.protoCache.realCount; j++) { + char buf[128]; + contactEntry * p = condir.protoCache.items[j]; + mir_snprintf(buf,SIZEOF(buf)," [%s] %s @ %x \n", p->proto, p->id ? p->id : "", p->hContact); + OutputDebugString(buf); + } + } + contactDir_Deinit(&condir); +#endif +} -- cgit v1.2.3