#include "common.h"
#include "proto.h"
#include "server_con.h"
#include "resource.h"
#include "formatting.h"
#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;
break;
case PFLAGNUM_2:
ret = PF2_ONLINE | PF2_SHORTAWAY | PF2_INVISIBLE;
break;
case PFLAGNUM_3:
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_ICON_PROTO;
break;
case PLI_ONLINE:
id = IDI_ICON_PROTO;
break;
case PLI_OFFLINE:
id = IDI_ICON_PROTO;
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_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;
}
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 13
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);
// 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]);
}