#include "common.h" #include "proto.h" #include "server_con.h" #include "resource.h" #include "formatting.h" #include #include #define FAILED_MESSAGE_HANDLE 99998 int msg_id = 1; int GetCaps(WPARAM wParam,LPARAM lParam) { int ret = 0; switch (wParam) { case PFLAGNUM_1: ret = PF1_NUMERICUSERID | PF1_IM | PF1_BASICSEARCH | PF1_SEARCHBYEMAIL | PF1_SEARCHBYNAME | PF1_ADDSEARCHRES | PF1_SERVERCLIST | PF1_MODEMSG; break; case PFLAGNUM_2: ret = PF2_ONLINE | PF2_SHORTAWAY | PF2_INVISIBLE; break; case PFLAGNUM_3: ret = PF2_ONLINE | PF2_SHORTAWAY | PF2_INVISIBLE; break; case PFLAGNUM_4: ret = PF4_SUPPORTTYPING; break; case PFLAGNUM_5: //ret = PF2_INVISIBLE; break; case PFLAG_UNIQUEIDTEXT: ret = (int) Translate("UserID"); break; case PFLAG_MAXLENOFMESSAGE: ret = MAX_MESSAGE_SIZE; break; case PFLAG_UNIQUEIDSETTING: ret = (int) "UID"; break; } return ret; } int GetName(WPARAM wParam,LPARAM lParam) { mir_snprintf((char *)lParam, wParam, "%s", MODULE); return 0; } int LoadIcon(WPARAM wParam,LPARAM lParam) { UINT id; switch (wParam & 0xFFFF) { case PLI_PROTOCOL: id = IDI_MYSPACE; break; case PLI_ONLINE: id = IDI_MYSPACE; break; case PLI_OFFLINE: id = IDI_MYSPACE; 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 GetInfo(WPARAM wParam,LPARAM lParam) { CCSDATA *ccs = ( CCSDATA* )lParam; int uid; if((uid = DBGetContactSettingDword(ccs->hContact, MODULE, "UID", 0)) == 0) return 1; // fail LookupUID(uid); return 0; } int SetStatus(WPARAM wParam,LPARAM lParam) { if(wParam == status) return 0; SetServerStatus(wParam); return 0; } int GetStatus(WPARAM wParam,LPARAM lParam) { return status; } typedef struct tag_TFakeAckParams { HANDLE hEvent; HANDLE hContact; LPARAM lParam; } TFakeAckParams; static DWORD CALLBACK sttFakeAckMessageSuccess( LPVOID param ) { TFakeAckParams *tParam = ( TFakeAckParams* )param; WaitForSingleObject( tParam->hEvent, INFINITE ); Sleep( 100 ); ProtoBroadcastAck(MODULE, tParam->hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, ( HANDLE )tParam->lParam, 0 ); CloseHandle( tParam->hEvent ); delete tParam; return 0; } static DWORD CALLBACK sttFakeAckMessageFailed( LPVOID param ) { TFakeAckParams *tParam = ( TFakeAckParams* )param; WaitForSingleObject( tParam->hEvent, INFINITE ); Sleep( 100 ); ProtoBroadcastAck(MODULE, tParam->hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, (HANDLE)FAILED_MESSAGE_HANDLE, tParam->lParam); CloseHandle( tParam->hEvent ); delete tParam; return 0; } int ProtoSendMessage(WPARAM wParam, LPARAM lParam) { CCSDATA *ccs = (CCSDATA *) lParam; char *message = (char *)ccs->lParam; char msg_utf[MAX_MESSAGE_SIZE], msg_fmt[MAX_MESSAGE_SIZE]; int uid; if((uid = DBGetContactSettingDword(ccs->hContact, MODULE, "UID", 0)) == 0 || status == ID_STATUS_OFFLINE) { HANDLE hEvent; TFakeAckParams *tfap; hEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); tfap = new TFakeAckParams; tfap->hContact = ccs->hContact; tfap->hEvent = hEvent; tfap->lParam = 0; CloseHandle( CreateThread( NULL, 0, sttFakeAckMessageFailed, tfap, 0, 0 )); SetEvent( hEvent ); return FAILED_MESSAGE_HANDLE; } // TODO: process 'message' and/or 'messagew' below if(ccs->wParam & PREF_UNICODE) { wchar_t *messagew = (wchar_t *)&message[strlen(message)+1]; WideCharToMultiByte(CP_UTF8, 0, messagew, -1, msg_utf, MAX_MESSAGE_SIZE, 0, 0); } else { //} else if(ccs->wParam & PREF_UTF) { // message is utf8 encoded - you can use mir_utf8decode (m_system.h) to make it wide strncpy(msg_utf, message, MAX_MESSAGE_SIZE); } msg_utf[MAX_MESSAGE_SIZE-1] = 0; entitize_msg(msg_utf, MAX_MESSAGE_SIZE); encode_smileys(msg_utf, MAX_MESSAGE_SIZE); mir_snprintf(msg_fmt, MAX_MESSAGE_SIZE, "

%s

", msg_utf); ClientNetMessage msg; msg.add_int("bm", 1); msg.add_int("sesskey", sesskey); msg.add_int("t", uid); msg.add_int("f", my_uid); msg.add_int("cv", CLIENT_VER); msg.add_string("msg", msg_fmt); SendMessage(msg); HANDLE hEvent; TFakeAckParams *tfap; hEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); int ret = msg_id++; tfap = new TFakeAckParams; tfap->hContact = ccs->hContact; tfap->hEvent = hEvent; tfap->lParam = (LPARAM)ret; CloseHandle( CreateThread( NULL, 0, sttFakeAckMessageSuccess, tfap, 0, 0 )); SetEvent( hEvent ); return ret; } int ProtoSendMessageW(WPARAM wParam, LPARAM lParam) { CCSDATA *ccs = (CCSDATA *) lParam; ccs->wParam |= PREF_UNICODE; return ProtoSendMessage(wParam, lParam); } int ProtoRecvMessage(WPARAM wParam, LPARAM lParam) { DBEVENTINFO dbei; CCSDATA* ccs = (CCSDATA*)lParam; PROTORECVEVENT* pre = (PROTORECVEVENT*)ccs->lParam; DBDeleteContactSetting(ccs->hContact, "CList", "Hidden"); ZeroMemory(&dbei, sizeof(dbei)); dbei.cbSize = sizeof(dbei); dbei.szModule = MODULE; dbei.timestamp = pre->timestamp; dbei.flags = (pre->flags & PREF_CREATEREAD) ? DBEF_READ : 0; dbei.flags |= (pre->flags & PREF_RTL) ? DBEF_RTL : 0; dbei.flags |= (pre->flags & PREF_UTF) ? DBEF_UTF : 0; dbei.eventType = EVENTTYPE_MESSAGE; dbei.cbBlob = strlen(pre->szMessage) + 1; if ( pre->flags & PREF_UNICODE ) dbei.cbBlob *= ( sizeof( wchar_t )+1 ); dbei.pBlob = (PBYTE)pre->szMessage; CallService(MS_DB_EVENT_ADD, (WPARAM)ccs->hContact, (LPARAM)&dbei); return 0; } int BasicSearch(WPARAM wParam, LPARAM lParam) { if(status <= ID_STATUS_OFFLINE) return 0; char *szId = (char *)lParam; ClientNetMessage msg; msg.add_int("persist", 1); msg.add_int("sesskey", sesskey); msg.add_int("uid", DBGetContactSettingDword(0, MODULE, "UID", 0)); msg.add_int("cmd", 1); msg.add_int("dsn", 4); msg.add_int("lid", 3); int req = req_id++; msg.add_int("rid", req); char body[512]; mir_snprintf(body, 512, "UserID=%s", szId); msg.add_string("body", body); SendMessage(msg); return req; } int SearchByEmail(WPARAM wParam, LPARAM lParam) { if(status <= ID_STATUS_OFFLINE) return 0; char *email = (char*)lParam; ClientNetMessage msg; msg.add_int("persist", 1); msg.add_int("sesskey", sesskey); msg.add_int("uid", DBGetContactSettingDword(0, MODULE, "UID", 0)); msg.add_int("cmd", 1); msg.add_int("dsn", 5); msg.add_int("lid", 7); int req = req_id++; msg.add_int("rid", req); char body[512]; mir_snprintf(body, 512, "Email=%s", email); msg.add_string("body", body); SendMessage(msg); return req; } int SearchByName(WPARAM wParam, LPARAM lParam) { if(status <= ID_STATUS_OFFLINE) return 0; PROTOSEARCHBYNAME *sbn = (PROTOSEARCHBYNAME *)lParam; if(!sbn->pszNick) return 0; ClientNetMessage msg; msg.add_int("persist", 1); msg.add_int("sesskey", sesskey); msg.add_int("uid", DBGetContactSettingDword(0, MODULE, "UID", 0)); msg.add_int("cmd", 1); msg.add_int("dsn", 5); msg.add_int("lid", 7); int req = req_id++; msg.add_int("rid", req); char body[512]; mir_snprintf(body, 512, "UserName=%s", sbn->pszNick); msg.add_string("body", body); SendMessage(msg); return req; } int AddToList(WPARAM wParam, LPARAM lParam) { MYPROTOSEARCHRESULT *mpsr = (MYPROTOSEARCHRESULT *)lParam; bool temp = (wParam & PALF_TEMPORARY) != 0; HANDLE hContact = FindContact(mpsr->uid); if(!hContact) { hContact = CreateContact(mpsr->uid, mpsr->psr.nick, mpsr->psr.email, true); } if(temp) { DBWriteContactSettingByte(hContact, "CList", "NotOnList", 1); DBWriteContactSettingByte(hContact, "CList", "Hidden", 1); } else { DBDeleteContactSetting(hContact, "CList", "NotOnList"); DBDeleteContactSetting(hContact, "CList", "Hidden"); } return (int)hContact; } static DWORD CALLBACK sttRecvAway( LPVOID param ) { TFakeAckParams *tParam = ( TFakeAckParams* )param; WaitForSingleObject( tParam->hEvent, INFINITE ); Sleep( 100 ); DBVARIANT dbv; char buff[512]; buff[0] = 0; if(!DBGetContactSettingStringUtf(tParam->hContact, MODULE, "StatusMsg", &dbv) && strlen(dbv.pszVal)) { strncpy(buff, dbv.pszVal, 512); buff[511] = 0; DBFreeVariant(&dbv); } CCSDATA ccs = {0}; PROTORECVEVENT pre = {0}; ccs.hContact = tParam->hContact; ccs.szProtoService = PSR_AWAYMSG; ccs.wParam = 0; ccs.lParam = (LPARAM)⪯ pre.timestamp = (DWORD)time(0); if(strlen(buff)) pre.szMessage = buff; else pre.szMessage = 0; CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs); CloseHandle( tParam->hEvent ); delete tParam; return 0; } int GetAwayMsg(WPARAM wParam, LPARAM lParam) { CCSDATA* ccs = (CCSDATA*)lParam; HANDLE hEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); TFakeAckParams *tfap = new TFakeAckParams; tfap->hContact = ccs->hContact; tfap->hEvent = hEvent; tfap->lParam = 0; CloseHandle( CreateThread( NULL, 0, sttRecvAway, tfap, 0, 0 )); SetEvent( hEvent ); return 1; } int RecvAwayMsg(WPARAM wParam, LPARAM lParam) { CCSDATA* ccs = (CCSDATA*)lParam; PROTORECVEVENT* pre = (PROTORECVEVENT*)ccs->lParam; ProtoBroadcastAck(MODULE, ccs->hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)1, (LPARAM)pre->szMessage); return 0; } int SetAwayMsg(WPARAM wParam, LPARAM lParam) { int status = (int)wParam; char *msg = (char *)lParam; // called *just after* SetStatus :( SetServerStatusMessage(msg); return 0; } int SendTyping(WPARAM wParam, LPARAM lParam) { HANDLE hContact = (HANDLE)wParam; int flags = (int)lParam, uid; if(status != ID_STATUS_OFFLINE) { if((uid = DBGetContactSettingDword(hContact, MODULE, "UID", 0)) != 0) { ClientNetMessage msg; msg.add_int("bm", 121); msg.add_int("sesskey", sesskey); msg.add_int("t", uid); msg.add_int("f", my_uid); msg.add_int("cv", CLIENT_VER); msg.add_string("msg", (flags == PROTOTYPE_SELFTYPING_ON ? "%typing%" : "%stoptyping%")); SendMessage(msg); } } return 0; } int ContactDeleted(WPARAM wParam, LPARAM lParam) { HANDLE hContact = (HANDLE)wParam; int uid = DBGetContactSettingDword(hContact, MODULE, "UID", 0); if(uid) { ClientNetMessage msg_del; msg_del.add_string("delbuddy", ""); msg_del.add_int("sesskey", sesskey); msg_del.add_int("delprofileid", uid); SendMessage(msg_del); ClientNetMessage msg_persist; msg_persist.add_int("persist", 1); msg_persist.add_int("sesskey", sesskey); msg_persist.add_int("cmd", 515); msg_persist.add_int("dsn", 0); msg_persist.add_int("uid", DBGetContactSettingDword(0, MODULE, "UID", 0)); msg_persist.add_int("lid", 8); msg_persist.add_int("rid", req_id++); char body[1024]; mir_snprintf(body, 1024, "ContactID=%d", uid); msg_persist.add_string("body", body); SendMessage(msg_persist); ClientNetMessage msg_block; msg_block.add_string("blocklist", ""); msg_block.add_int("sesskey", sesskey); char idlist[1024]; mir_snprintf(idlist, 1024, "a-|%d|b-|%d", uid, uid); msg_block.add_string("idlist", idlist); SendMessage(msg_block); } 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); } #define NUM_FILTER_SERVICES 17 HANDLE hServices[NUM_FILTER_SERVICES]; HANDLE hEventContactDeleted; void CreateProtoServices() { // create our services int i = 0; 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, PS_GETCAPS, GetCaps); hServices[i++] = CreateProtoServiceFunction(MODULE, PS_GETNAME, GetName); hServices[i++] = CreateProtoServiceFunction(MODULE, PS_LOADICON,LoadIcon); hServices[i++] = CreateProtoServiceFunction(MODULE, PSS_GETINFO,GetInfo); hServices[i++] = CreateProtoServiceFunction(MODULE, PS_SETSTATUS, SetStatus); hServices[i++] = CreateProtoServiceFunction(MODULE, PS_GETSTATUS, GetStatus); hServices[i++] = CreateProtoServiceFunction(MODULE, PS_BASICSEARCH, BasicSearch); hServices[i++] = CreateProtoServiceFunction(MODULE, PS_SEARCHBYEMAIL, SearchByEmail); hServices[i++] = CreateProtoServiceFunction(MODULE, PS_SEARCHBYNAME, SearchByName); hServices[i++] = CreateProtoServiceFunction(MODULE, PS_ADDTOLIST, AddToList); hServices[i++] = CreateProtoServiceFunction(MODULE, PSS_GETAWAYMSG, GetAwayMsg); hServices[i++] = CreateProtoServiceFunction(MODULE, PSR_AWAYMSG, RecvAwayMsg); hServices[i++] = CreateProtoServiceFunction(MODULE, PS_SETAWAYMSG, SetAwayMsg); hServices[i++] = CreateProtoServiceFunction(MODULE, PSS_USERISTYPING, SendTyping); // remember to modify the NUM_FILTER_SERVICES #define above if you add more services! hEventContactDeleted = HookEvent(ME_DB_CONTACT_DELETED, ContactDeleted); //my_space_server_running = false; } void DeinitProto() { UnhookEvent(hEventContactDeleted); for(int i = 0; i < NUM_FILTER_SERVICES; i++) DestroyServiceFunction(hServices[i]); }