summaryrefslogtreecommitdiff
path: root/meta2/proto.cpp
diff options
context:
space:
mode:
authorsje <sje@4f64403b-2f21-0410-a795-97e2b3489a10>2007-10-03 05:26:48 +0000
committersje <sje@4f64403b-2f21-0410-a795-97e2b3489a10>2007-10-03 05:26:48 +0000
commit9814933f4bc5a7a4320819de54e313d8fc0ceffe (patch)
treead1b95ce79312a3e88bc0e5c47d2f11c43f2e58f /meta2/proto.cpp
parent812d72d8d92f24e1989a56d1180d1435ee27b5f6 (diff)
initial revision of new metacontacts
git-svn-id: https://server.scottellis.com.au/svn/mim_plugs@338 4f64403b-2f21-0410-a795-97e2b3489a10
Diffstat (limited to 'meta2/proto.cpp')
-rw-r--r--meta2/proto.cpp547
1 files changed, 547 insertions, 0 deletions
diff --git a/meta2/proto.cpp b/meta2/proto.cpp
new file mode 100644
index 0000000..61ff69d
--- /dev/null
+++ b/meta2/proto.cpp
@@ -0,0 +1,547 @@
+#include "common.h"
+#include "proto.h"
+#include "resource.h"
+#include "core_functions.h"
+#include "api.h"
+#include "priorities.h"
+
+bool firstSetOnline = true;
+DWORD status = ID_STATUS_OFFLINE;
+DWORD setStatusTimerId = 0;
+
+DWORD next_meta_id = 1;
+int meta_count = 0;
+
+// a 'fake' module name for copied subcontact events - used to prevent infinite recursion when creating event copies
+#define META_COPY_MODULE "MetaCopy"
+
+HANDLE NewMetaContact() {
+ HANDLE hMeta = (HANDLE) CallService(MS_DB_CONTACT_ADD, 0, 0);
+ DBWriteContactSettingDword(hMeta, MODULE, META_ID, next_meta_id++);
+ CallService( MS_PROTO_ADDTOCONTACT, ( WPARAM )hMeta, ( LPARAM )MODULE);
+ meta_count++;
+ return hMeta;
+}
+
+
+int GetCaps(WPARAM wParam,LPARAM lParam) {
+ int ret = 0;
+ switch (wParam) {
+ case PFLAGNUM_1:
+ ret = PF1_NUMERICUSERID | PF1_IM | PF1_MODEMSGRECV | PF1_FILESEND;
+ break;
+ case PFLAGNUM_2:
+ ret = PF2_ONLINE | PF2_INVISIBLE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND
+ | PF2_HEAVYDND | PF2_FREECHAT | PF2_OUTTOLUNCH | PF2_ONTHEPHONE;
+ break;
+ case PFLAGNUM_3:
+ ret = PF2_ONLINE | PF2_INVISIBLE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND
+ | PF2_HEAVYDND | PF2_FREECHAT | PF2_OUTTOLUNCH | PF2_ONTHEPHONE;
+ break;
+ case PFLAGNUM_4:
+ ret = PF4_SUPPORTTYPING | PF4_AVATARS | PF4_SUPPORTIDLE | PF4_IMSENDUTF | PF4_IMSENDOFFLINE;
+ break;
+ case PFLAGNUM_5:
+ ret = PF2_ONLINE | PF2_INVISIBLE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND
+ | PF2_HEAVYDND | PF2_FREECHAT | PF2_OUTTOLUNCH | PF2_ONTHEPHONE;
+ break;
+ case PFLAG_UNIQUEIDTEXT:
+ ret = (int) Translate("Meta ID");
+ break;
+ case PFLAG_MAXLENOFMESSAGE:
+ ret = 2048;
+ break;
+ case PFLAG_UNIQUEIDSETTING:
+ ret = (int) META_ID;
+ break;
+ }
+ return ret;
+}
+
+int GetName(WPARAM wParam,LPARAM lParam) {
+ char *name = (char *)Translate(MODULE);
+ size_t size = min(strlen(name),wParam-1); // copy only the first size bytes.
+ if(strncpy((char *)lParam,name,size)==NULL)
+ return 1;
+ ((char *)lParam)[size]='\0';
+ return 0;
+}
+
+int LoadIcon(WPARAM wParam,LPARAM lParam) {
+
+ UINT id;
+ switch (wParam & 0xFFFF)
+ {
+ case PLI_PROTOCOL:
+ id = IDI_MCMENU;
+ break;
+ case PLI_ONLINE:
+ id = IDI_MCMENU;
+ break;
+ case PLI_OFFLINE:
+ id = IDI_MCMENUOFF;
+ break;
+ default:
+ return (int) (HICON) NULL;
+ }
+
+ return (int) LoadImage(hInst, MAKEINTRESOURCE(id), IMAGE_ICON,
+ GetSystemMetrics(wParam & PLIF_SMALL ? SM_CXSMICON : SM_CXICON),
+ GetSystemMetrics(wParam & PLIF_SMALL ? SM_CYSMICON : SM_CYICON), 0);
+ return 0;
+}
+
+int ProtoGetInfo(WPARAM wParam,LPARAM lParam) {
+ CCSDATA *ccs = ( CCSDATA* )lParam;
+
+ ccs->hContact = Meta_GetMostOnline(ccs->hContact);
+ char *proto = ContactProto(ccs->hContact);
+ if(!proto)
+ return 1;
+
+ char szServiceName[256];
+ mir_snprintf(szServiceName, 256, "%s%s", proto, PSS_GETINFO);
+ if (ServiceExists(szServiceName)) {
+ return CallContactService(ccs->hContact, PSS_GETINFO, ccs->wParam, ccs->lParam);
+ }
+ return 1;
+}
+
+int ProtoGetAwayMsg(WPARAM wParam, LPARAM lParam) {
+ CCSDATA *ccs = ( CCSDATA* )lParam;
+
+ ccs->hContact = Meta_GetMostOnline(ccs->hContact);
+ char *proto = ContactProto(ccs->hContact);
+ if(!proto)
+ return 0;
+
+ char szServiceName[256];
+ mir_snprintf(szServiceName, 256, "%s%s", proto, PSS_GETAWAYMSG);
+ if (ServiceExists(szServiceName)) {
+ return CallContactService(ccs->hContact, PSS_GETAWAYMSG, ccs->wParam, ccs->lParam);
+ }
+ return 0;
+}
+
+void CALLBACK SetStatusProc(HWND hWnd, UINT msg, UINT_PTR id, DWORD dw)
+{
+ int previousMode = status;
+ status = (int)ID_STATUS_ONLINE;
+ ProtoBroadcastAck(MODULE, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)previousMode, status);
+
+ KillTimer(0, setStatusTimerId);
+}
+
+int SetStatus(WPARAM wParam,LPARAM lParam)
+{
+ // firstSetOnline starts out true - used to delay metacontact's 'onlineness' to prevent double status notifications on startup
+ if(status == ID_STATUS_OFFLINE && firstSetOnline) {
+ // causes crash on exit if miranda is closed in under options.set_status_from_offline milliseconds!
+ //CloseHandle( CreateThread( NULL, 0, SetStatusThread, (void *)wParam, 0, 0 ));
+ setStatusTimerId = SetTimer(0, 0, 10000, SetStatusProc);
+ firstSetOnline = FALSE;
+ } else {
+ int previousMode = status;
+ status = (int)wParam;
+ ProtoBroadcastAck(MODULE, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)previousMode, status);
+ }
+ return 0;
+}
+
+int GetStatus(WPARAM wParam,LPARAM lParam) {
+ return status;
+}
+
+int ProtoSendMessage(WPARAM wParam, LPARAM lParam) {
+ CCSDATA *ccs = (CCSDATA *) lParam;
+ char *message = (char *)ccs->lParam;
+ int flags = ccs->wParam;
+ char *buff = 0;
+
+ HANDLE most_online = Meta_GetMostOnline(ccs->hContact);
+ char *proto = ContactProto(most_online);
+ if(ContactStatus(most_online, proto) == ID_STATUS_OFFLINE) {
+ most_online = Meta_GetMostOnlineSupporting(ccs->hContact, PFLAGNUM_4, PF4_IMSENDOFFLINE);
+ proto = ContactProto(most_online);
+ }
+
+ char szServiceName[256];
+ mir_snprintf(szServiceName, 256, "%s", PSS_MESSAGE);
+ if((flags & PREF_UNICODE) && proto != 0) {
+ char szTemp[256];
+ mir_snprintf(szTemp, 256, "%s%sW", proto, PSS_MESSAGE);
+ if (ServiceExists(szTemp))
+ strncpy(szServiceName, PSS_MESSAGE "W", sizeof(szServiceName));
+ }
+ if((flags & PREF_UTF) && !(CallContactService(most_online, PS_GETCAPS, PFLAGNUM_4, 0) & PF4_IMSENDUTF)) {
+ ccs->wParam &= ~PREF_UTF;
+ ccs->wParam |= PREF_UNICODE;
+ wchar_t *unicode = mir_utf8decodeW(message);
+ char *ascii = mir_u2a(unicode);
+
+ char *buff = new char[strlen(ascii) + 1 + (wcslen(unicode) + 1) * sizeof(wchar_t)];
+ strcpy(buff, ascii);
+ wcscpy((wchar_t *)(buff + strlen(ascii) + 1), unicode);
+ mir_free(unicode);
+ mir_free(ascii);
+ ccs->lParam = (LPARAM)buff;
+ }
+
+ int ret = (int)CallContactService(most_online, szServiceName, ccs->wParam, ccs->lParam);
+ if(buff) {
+ ccs->lParam = (LPARAM)message;
+ delete[] buff;
+ }
+ return ret;
+}
+
+int ProtoSendMessageW(WPARAM wParam, LPARAM lParam) {
+ CCSDATA *ccs = (CCSDATA *) lParam;
+ if(!(ccs->wParam & PREF_UTF))
+ ccs->wParam |= PREF_UNICODE;
+
+ return ProtoSendMessage(wParam, lParam);
+}
+
+int ProtoRecvMessage(WPARAM wParam, LPARAM lParam) {
+ CCSDATA *ccs = (CCSDATA *) lParam;
+ PROTORECVEVENT *pre = (PROTORECVEVENT *) ccs->lParam;
+
+ // use the subcontact's protocol to add to the db (AIMOSCAR removes HTML here!)
+ HANDLE most_online = Meta_GetMostOnline(ccs->hContact);
+ char *proto = ContactProto(most_online);
+ if(proto) {
+ char service[256];
+ mir_snprintf(service, 256, "%s%s", proto, PSR_MESSAGE);
+ if(ServiceExists(service))
+ return CallService(service, wParam, lParam);
+ }
+
+ return 0;
+}
+
+int RedirectACKs(WPARAM wParam, LPARAM lParam)
+{
+ ACKDATA *ack = (ACKDATA*) lParam;
+ HANDLE hMeta;
+
+ if(ack->hContact == 0 || (hMeta = (HANDLE)DBGetContactSettingDword(ack->hContact, MODULE, "Handle", 0)) == 0)
+ return 0; // Can't find the MetaID, let through the protocol chain
+
+ if(!strcmp(ack->szModule, MODULE)) {
+ return 0; // don't rebroadcast our own acks
+ }
+
+ // if it's for something we don't support, ignore
+ if(ack->type != ACKTYPE_MESSAGE && ack->type != ACKTYPE_CHAT && ack->type != ACKTYPE_FILE && ack->type != ACKTYPE_AWAYMSG
+ && ack->type != ACKTYPE_AVATAR && ack->type != ACKTYPE_GETINFO)
+ {
+ return 0;
+ }
+
+ // change the hContact in the avatar info struct, if it's the avatar we're using - else drop it
+ if(ack->type == ACKTYPE_AVATAR) {
+ if(ack->result == ACKRESULT_SUCCESS || ack->result == ACKRESULT_FAILED || ack->result == ACKRESULT_STATUS) {
+ if(ack->hContact == 0) {
+ return 0;
+ }
+
+ if(ack->hProcess) {
+ PROTO_AVATAR_INFORMATION AI;
+ memcpy(&AI, (PROTO_AVATAR_INFORMATION *)ack->hProcess, sizeof(PROTO_AVATAR_INFORMATION));
+ if(AI.hContact)
+ AI.hContact = hMeta;
+
+ return ProtoBroadcastAck(MODULE,hMeta,ack->type,ack->result, (HANDLE)&AI, ack->lParam);
+ } else
+ return ProtoBroadcastAck(MODULE,hMeta,ack->type,ack->result, 0, ack->lParam);
+ }
+ }
+
+ return ProtoBroadcastAck(MODULE, hMeta, ack->type, ack->result, ack->hProcess, ack->lParam);
+}
+
+int ProtoGetAvatarInfo(WPARAM wParam, LPARAM lParam) {
+ PROTO_AVATAR_INFORMATION *AI = (PROTO_AVATAR_INFORMATION *) lParam;
+
+ HANDLE hMeta = AI->hContact;
+
+ // find the most online contact supporting avatars, according to priorities
+ HANDLE most_online = (HANDLE)Meta_GetMostOnlineSupporting(hMeta, PFLAGNUM_4, PF4_AVATARS);
+ char *most_online_proto = ContactProto(most_online);
+
+ AI->hContact = most_online;
+ char szServiceName[100];
+ mir_snprintf(szServiceName, sizeof(szServiceName), "%s%s", most_online_proto, PS_GETAVATARINFO);
+ int result = CallService(szServiceName, wParam, lParam);
+ AI->hContact = hMeta;
+ if (result != CALLSERVICE_NOTFOUND) return result;
+
+ return GAIR_NOAVATAR; // fail
+}
+
+int ProtoFileSend(WPARAM wParam, LPARAM lParam) {
+ CCSDATA *ccs = (CCSDATA *) lParam;
+ HANDLE hMeta = ccs->hContact;
+
+ // find the most online contact supporting file send, according to priorities
+ HANDLE most_online = (HANDLE)Meta_GetMostOnlineSupporting(hMeta, PFLAGNUM_1, PF1_FILESEND);
+ char *most_online_proto = ContactProto(most_online);
+
+ ccs->hContact = most_online;
+ char szServiceName[100];
+ mir_snprintf(szServiceName, sizeof(szServiceName), "%s%s", most_online_proto, PSS_FILE);
+ int result = CallService(szServiceName, wParam, lParam);
+ ccs->hContact = hMeta;
+ if(result != CALLSERVICE_NOTFOUND) return result;
+
+ return 0; // fail
+}
+
+int ProtoUserIsTyping(WPARAM wParam, LPARAM lParam) {
+ HANDLE hMeta = (HANDLE)wParam;
+ // find the most online contact supporting file send, according to priorities
+ HANDLE most_online = (HANDLE)Meta_GetMostOnlineSupporting(hMeta, PFLAGNUM_4, PF4_SUPPORTTYPING);
+ char *most_online_proto = ContactProto(most_online);
+
+ CallContactService(most_online, PSS_USERISTYPING, (WPARAM)most_online, lParam);
+ return 0;
+}
+
+int EventContactIsTyping(WPARAM wParam, LPARAM lParam) {
+ HANDLE hMeta;
+
+ if((hMeta = (HANDLE)DBGetContactSettingDword((HANDLE)wParam, MODULE, "Handle", 0)) != 0 && MetaEnabled()) {
+ // try to remove any clist events added for subcontact
+ CallServiceSync(MS_CLIST_REMOVEEVENT, wParam, (LPARAM) 1);
+
+ CallService(MS_PROTO_CONTACTISTYPING, (WPARAM)hMeta, lParam);
+
+ // stop processing of event
+ return 1;
+ }
+
+ return 0;
+}
+
+int SendNudge(WPARAM wParam,LPARAM lParam)
+{
+ HANDLE hMeta = (HANDLE)wParam,
+ hSubContact = Meta_GetMostOnline(hMeta);
+
+ char servicefunction[256];
+ char *protoName = ContactProto(hSubContact);
+ mir_snprintf(servicefunction, 256, "%s/SendNudge", protoName);
+
+ return CallService(servicefunction, (WPARAM)hSubContact, lParam);
+}
+
+int ContactDeleted(WPARAM wParam, LPARAM lParam) {
+ HANDLE hContact = (HANDLE)wParam;
+ if(IsSubcontact(hContact))
+ Meta_Remove(hContact);
+ else if(IsMetacontact(hContact)) {
+ SubcontactList::Iterator i = metaMap[hContact].start();
+ HANDLE hSub;
+ while(i.has_val()) {
+ // same functionality as Meta_Remove - except the meta is not deleted when all subcontacts are removed here since it's already happening,
+ // and the 'subcontacts changed' event isn't fired
+ hSub = i.val().handle();
+ DBDeleteContactSetting(hSub, MODULE, "ParentMetaID");
+ // deleting these (resident) settings doesn't work :( [25/9/07]
+ DBWriteContactSettingDword(hSub, MODULE, "Handle", 0);
+ DBWriteContactSettingByte(hSub, MODULE, "IsSubcontact", 0);
+ if(!meta_group_hack_disabled) DBWriteContactSettingByte(hSub, "CList", "Hidden", 0);
+
+ i.next();
+ }
+ metaMap.remove(hContact);
+ meta_count--;
+ }
+ return 0;
+}
+
+int SettingChanged(WPARAM wParam, LPARAM lParam) {
+ if(wParam == 0 || !IsSubcontact((HANDLE)wParam)) return 0;
+
+ DBCONTACTWRITESETTING *dcws = (DBCONTACTWRITESETTING *)lParam;
+ if(strcmp(dcws->szSetting, "Status") == 0) {
+ // subcontact status has changed
+ Meta_CalcStatus((HANDLE)DBGetContactSettingDword((HANDLE)wParam, MODULE, "Handle", 0));
+ }
+
+ // keep subcontacts hidden if the clist doesn't do it for us
+ if(strcmp(dcws->szSetting, "Hidden") == 0 && strcmp(dcws->szModule, "CList") == 0 && MetaEnabled() && !meta_group_hack_disabled) {
+ if(dcws->value.type == DBVT_DELETED || dcws->value.bVal == 0) {
+ DBWriteContactSettingByte((HANDLE)wParam, "CList", "Hidden", 1);
+ }
+ }
+
+ return 0;
+}
+
+int MetaChanged(WPARAM wParam, LPARAM lParam) {
+ Meta_CalcStatus((HANDLE)wParam);
+ return 0;
+}
+
+int WindowEvent(WPARAM wParam, LPARAM lParam) {
+ MessageWindowEventData *mwed = (MessageWindowEventData *)lParam;
+ if(IsMetacontact(mwed->hContact) || IsSubcontact(mwed->hContact)) {
+ if(mwed->uType == MSG_WINDOW_EVT_OPEN || mwed->uType == MSG_WINDOW_EVT_OPENING) {
+ DBWriteContactSettingByte(mwed->hContact, MODULE, "WindowOpen", 1);
+ if(IsMetacontact(mwed->hContact))
+ CallService(MS_CLIST_REMOVEEVENT, (WPARAM)mwed->hContact, (LPARAM)EVENTTYPE_MESSAGE);
+ } else if(mwed->uType == MSG_WINDOW_EVT_CLOSE || mwed->uType == MSG_WINDOW_EVT_CLOSING)
+ DBWriteContactSettingByte(mwed->hContact, MODULE, "WindowOpen", 0);
+
+ }
+ return 0;
+}
+
+void RegisterProto() {
+ PROTOCOLDESCRIPTOR pd = {0};
+ pd.cbSize = sizeof(pd);
+ pd.szName = MODULE;
+ pd.type = PROTOTYPE_PROTOCOL;
+ CallService(MS_PROTO_REGISTERMODULE,0,(LPARAM)&pd);
+}
+
+// redirect events to subcontact (except the ones we add in the EventAdded handler below - i.e. dbei->szModule == META_COPY_MODULE)
+int EventFilterAdd(WPARAM wParam, LPARAM lParam) {
+ HANDLE hContact = (HANDLE)wParam;
+ DBEVENTINFO *dbei = (DBEVENTINFO *)lParam;
+
+ if(IsMetacontact(hContact) && strcmp(dbei->szModule, MODULE) == 0) {
+ // add the event to the subcontact instead
+ HANDLE most_online = Meta_GetMostOnline(hContact);
+ dbei->szModule = ContactProto(most_online);
+ CallService(MS_DB_EVENT_ADD, (WPARAM)most_online, (LPARAM)dbei);
+ return 1; // don't add original event
+ }
+ if(IsSubcontact(hContact)) {
+ if(dbei->eventType == EVENTTYPE_MESSAGE && !(dbei->flags & DBEF_SENT) && DBGetContactSettingByte(hContact, MODULE, "WindowOpen", 0) == 0) {
+ dbei->flags |= DBEF_READ;
+ }
+ }
+
+ return 0;
+}
+
+// add subcontact events to metacontacts
+int EventAdded(WPARAM wParam, LPARAM lParam) {
+ HANDLE hContact = (HANDLE)wParam,
+ hDbEvent = (HANDLE)lParam,
+ hMeta;
+
+ if(MetaEnabled() && (hMeta = (HANDLE)DBGetContactSettingDword(hContact, MODULE, "Handle", 0)) != 0) {
+ DBEVENTINFO dbei = {0};
+ dbei.cbSize = sizeof(dbei);
+ dbei.cbBlob = (int)CallService(MS_DB_EVENT_GETBLOBSIZE, (WPARAM)hDbEvent, 0);
+ dbei.pBlob = (PBYTE)mir_alloc(dbei.cbBlob);
+ if(CallService(MS_DB_EVENT_GET, (WPARAM)hDbEvent, (LPARAM)&dbei) == 0) {
+ if(dbei.eventType < EVENTTYPE_ADDED) {
+ DBEVENTINFO dbeiMeta = {0};
+ dbeiMeta.cbSize = sizeof(dbeiMeta);
+ dbeiMeta.eventType = dbei.eventType;
+ dbeiMeta.flags = dbei.flags & ~DBEF_READ;
+ dbeiMeta.cbBlob = dbei.cbBlob;
+ dbeiMeta.pBlob = dbei.pBlob;
+ dbeiMeta.szModule = dbei.szModule;
+ dbeiMeta.timestamp = dbei.timestamp;
+
+ if(dbei.eventType == EVENTTYPE_MESSAGE) {
+ if(!(dbeiMeta.flags & DBEF_SENT)
+ && DBGetContactSettingByte(hContact, MODULE, "WindowOpen", 0) == 1
+ && DBGetContactSettingByte(hMeta, MODULE, "WindowOpen", 0) == 0)
+ {
+ dbeiMeta.flags |= DBEF_READ;
+ }
+
+ // set default
+ int num = metaMap[hMeta].index_of(hContact);
+ if(num != -1 && num != DBGetContactSettingByte(hMeta, MODULE, "Default", -1))
+ MetaAPI_SetDefaultContactNum((WPARAM)hMeta, (LPARAM)num);
+
+ // set meta nick
+ char *proto = ContactProto(hContact);
+ DBVARIANT dbv;
+ if(proto && !DBGetContactSettingUTF8String(0, proto, "Nick", &dbv)) {
+ DBWriteContactSettingUTF8String(0, MODULE, "Nick", dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ }
+ CallService(MS_DB_EVENT_ADD, (WPARAM)hMeta, (LPARAM)&dbeiMeta);
+ }
+ }
+ mir_free(dbei.pBlob);
+ }
+
+ return 0;
+}
+
+HANDLE hEventMessageWindow = 0;
+int ModulesLoadedProto(WPARAM wParam, LPARAM lParam) {
+ hEventMessageWindow = (HANDLE)HookEvent(ME_MSG_WINDOWEVENT, WindowEvent);
+
+ Meta_Hide(DBGetContactSettingByte(0, MODULE, "Enabled", 1) == 0);
+ return 0;
+}
+
+#define NUM_SERVICES 14
+HANDLE hServices[NUM_SERVICES] = {0}, hEventContactDeleted = 0, hEventSettingChanged = 0;
+#define NUM_HOOKS_INTERNAL 8
+HANDLE hHooksInternal[NUM_HOOKS_INTERNAL] = {0};
+
+void InitProto() {
+ RegisterProto();
+
+ // create our services
+ int i = 0;
+
+ hServices[i++] = CreateProtoServiceFunction(MODULE, PS_GETCAPS, GetCaps);
+ hServices[i++] = CreateProtoServiceFunction(MODULE, PS_GETNAME, GetName);
+ hServices[i++] = CreateProtoServiceFunction(MODULE, PS_LOADICON, LoadIcon);
+ hServices[i++] = CreateProtoServiceFunction(MODULE, PS_SETSTATUS, SetStatus);
+ hServices[i++] = CreateProtoServiceFunction(MODULE, PS_GETSTATUS, GetStatus);
+
+ hServices[i++] = CreateProtoServiceFunction(MODULE, PSS_GETINFO, ProtoGetInfo);
+
+ hServices[i++] = CreateProtoServiceFunction(MODULE, PSS_MESSAGE, ProtoSendMessage);
+ hServices[i++] = CreateProtoServiceFunction(MODULE, PSS_MESSAGE"W", ProtoSendMessageW);
+ hServices[i++] = CreateProtoServiceFunction(MODULE, PSR_MESSAGE, ProtoRecvMessage);
+
+ hServices[i++] = CreateProtoServiceFunction(MODULE, PSS_GETAWAYMSG, ProtoGetAwayMsg);
+
+ hServices[i++] = CreateProtoServiceFunction(MODULE, PS_GETAVATARINFO, ProtoGetAvatarInfo);
+ hServices[i++] = CreateProtoServiceFunction(MODULE, PSS_FILE, ProtoFileSend);
+ hServices[i++] = CreateProtoServiceFunction(MODULE, PSS_USERISTYPING, ProtoUserIsTyping);
+
+ // REMEMBER to modify the NUM_SERVICES #define above if you add more services!
+
+ hServices[i++] = CreateProtoServiceFunction(MODULE, "/SendNudge", SendNudge);
+
+ hEventContactDeleted = HookEvent(ME_DB_CONTACT_DELETED, ContactDeleted);
+ hEventSettingChanged = HookEvent(ME_DB_CONTACT_SETTINGCHANGED, SettingChanged);
+
+ i = 0;
+ hHooksInternal[i++] = (HANDLE)HookEvent(ME_MC_DEFAULTTCHANGED, MetaChanged );
+ hHooksInternal[i++] = (HANDLE)HookEvent(ME_MC_FORCESEND, MetaChanged );
+ hHooksInternal[i++] = (HANDLE)HookEvent(ME_MC_UNFORCESEND, MetaChanged );
+ hHooksInternal[i++] = (HANDLE)HookEvent(ME_PROTO_ACK, RedirectACKs);
+ hHooksInternal[i++] = (HANDLE)HookEvent(ME_SYSTEM_MODULESLOADED, ModulesLoadedProto);
+ hHooksInternal[i++] = (HANDLE)HookEvent(ME_DB_EVENT_ADDED, EventAdded);
+ hHooksInternal[i++] = (HANDLE)HookEvent(ME_DB_EVENT_FILTER_ADD, EventFilterAdd);
+ hHooksInternal[i++] = (HANDLE)HookEvent(ME_PROTO_CONTACTISTYPING, EventContactIsTyping);
+}
+
+void DeinitProto() {
+ UnhookEvent(hEventMessageWindow);
+ UnhookEvent(hEventSettingChanged);
+ UnhookEvent(hEventContactDeleted);
+ for(int i = 0; i < NUM_SERVICES; i++)
+ DestroyServiceFunction(hServices[i]);
+ for(int i = 0; i < NUM_HOOKS_INTERNAL; i++)
+ UnhookEvent(hHooksInternal[i]);
+
+} \ No newline at end of file