From 08fd5437555d0b5cab972fb3316b4cdb8f11cdae Mon Sep 17 00:00:00 2001 From: Vadim Dashevskiy Date: Fri, 12 Oct 2012 11:45:28 +0000 Subject: AimOscar: folders restructurization git-svn-id: http://svn.miranda-ng.org/main/trunk@1886 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- protocols/AimOscar/src/proto.cpp | 913 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 913 insertions(+) create mode 100644 protocols/AimOscar/src/proto.cpp (limited to 'protocols/AimOscar/src/proto.cpp') diff --git a/protocols/AimOscar/src/proto.cpp b/protocols/AimOscar/src/proto.cpp new file mode 100644 index 0000000000..09f7ba4ab1 --- /dev/null +++ b/protocols/AimOscar/src/proto.cpp @@ -0,0 +1,913 @@ +/* +Plugin of Miranda IM for communicating with users of the AIM protocol. +Copyright (c) 2008-2012 Boris Krasnovskiy + +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, see . +*/ +#include "aim.h" + +#include "m_genmenu.h" + +CAimProto::CAimProto(const char* aProtoName, const TCHAR* aUserName) + : chat_rooms(5) +{ + m_iVersion = 2; + m_tszUserName = mir_tstrdup(aUserName); + m_szModuleName = mir_strdup(aProtoName); + m_szProtoName = mir_strdup(aProtoName); + _strlwr(m_szProtoName); + m_szProtoName[0] = (char)toupper(m_szProtoName[0]); + LOG("Setting protocol/module name to '%s/%s'", m_szProtoName, m_szModuleName); + + //create some events + hAvatarEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + hChatNavEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + hAdminEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + InitializeCriticalSection(&SendingMutex); + InitializeCriticalSection(&connMutex); + + CreateProtoService(PS_CREATEACCMGRUI, &CAimProto::SvcCreateAccMgrUI); + + CreateProtoService(PS_GETMYAWAYMSG, &CAimProto::GetMyAwayMsg); + + CreateProtoService(PS_GETAVATARINFOT, &CAimProto::GetAvatarInfo); + CreateProtoService(PS_GETMYAVATART, &CAimProto::GetAvatar); + CreateProtoService(PS_SETMYAVATART, &CAimProto::SetAvatar); + CreateProtoService(PS_GETAVATARCAPS, &CAimProto::GetAvatarCaps); + + CreateProtoService(PS_JOINCHAT, &CAimProto::OnJoinChat); + CreateProtoService(PS_LEAVECHAT, &CAimProto::OnLeaveChat); + + HookProtoEvent(ME_CLIST_PREBUILDCONTACTMENU, &CAimProto::OnPreBuildContactMenu); + HookProtoEvent(ME_CLIST_GROUPCHANGE, &CAimProto::OnGroupChange); + HookProtoEvent(ME_OPT_INITIALISE, &CAimProto::OnOptionsInit); + + init_custom_folders(); + offline_contacts(); + + TCHAR descr[MAX_PATH]; + + NETLIBUSER nlu = {0}; + nlu.cbSize = sizeof(nlu); + nlu.flags = NUF_OUTGOING | NUF_HTTPCONNS | NUF_TCHAR; + nlu.szSettingsModule = m_szModuleName; + mir_sntprintf(descr, SIZEOF(descr), TranslateT("%s server connection"), m_tszUserName); + nlu.ptszDescriptiveName = descr; + hNetlib = (HANDLE) CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu); + + char szP2P[128]; + mir_snprintf(szP2P, sizeof(szP2P), "%sP2P", m_szModuleName); + nlu.flags = NUF_OUTGOING | NUF_INCOMING | NUF_TCHAR; + mir_sntprintf(descr, SIZEOF(descr), TranslateT("%s Client-to-client connection"), m_tszUserName); + nlu.szSettingsModule = szP2P; + nlu.minIncomingPorts = 1; + hNetlibPeer = (HANDLE) CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu); +} + +CAimProto::~CAimProto() +{ + RemoveMainMenus(); + RemoveContactMenus(); + + if(hServerConn) + Netlib_CloseHandle(hServerConn); + if(hAvatarConn && hAvatarConn != (HANDLE)1) + Netlib_CloseHandle(hAvatarConn); + if(hChatNavConn && hChatNavConn != (HANDLE)1) + Netlib_CloseHandle(hChatNavConn); + if(hAdminConn && hAdminConn != (HANDLE)1) + Netlib_CloseHandle(hAdminConn); + + close_chat_conn(); + + Netlib_CloseHandle(hNetlib); + Netlib_CloseHandle(hNetlibPeer); + + DeleteCriticalSection(&SendingMutex); + DeleteCriticalSection(&connMutex); + + CloseHandle(hAvatarEvent); + CloseHandle(hChatNavEvent); + CloseHandle(hAdminEvent); + + ft_list.destroy(); + + for (int i=0; i<9; ++i) + mir_free(modeMsgs[i]); + + mir_free(pref2_flags); + mir_free(pref2_set_flags); + + mir_free(COOKIE); + mir_free(MAIL_COOKIE); + mir_free(AVATAR_COOKIE); + mir_free(CHATNAV_COOKIE); + mir_free(ADMIN_COOKIE); + mir_free(username); + + mir_free(m_szModuleName); + mir_free(m_tszUserName); + mir_free(m_szProtoName); +} + +//////////////////////////////////////////////////////////////////////////////////////// +// OnModulesLoadedEx - performs hook registration + +int CAimProto::OnModulesLoaded(WPARAM wParam, LPARAM lParam) +{ + HookProtoEvent(ME_USERINFO_INITIALISE, &CAimProto::OnUserInfoInit); + HookProtoEvent(ME_IDLE_CHANGED, &CAimProto::OnIdleChanged); + HookProtoEvent(ME_MSG_WINDOWEVENT, &CAimProto::OnWindowEvent); + + chat_register(); + InitContactMenus(); + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// AddToList - adds a contact to the contact list + +HANDLE CAimProto::AddToList(int flags, PROTOSEARCHRESULT* psr) +{ + if (state != 1) return 0; + TCHAR *id = psr->id ? psr->id : psr->nick; + char *sn = psr->flags & PSR_UNICODE ? mir_u2a((wchar_t*)id) : mir_strdup((char*)id); + HANDLE hContact = contact_from_sn(sn, true, (flags & PALF_TEMPORARY) != 0); + mir_free(sn); + return hContact; //See authrequest for serverside addition +} + +HANDLE __cdecl CAimProto::AddToListByEvent(int flags, int iContact, HANDLE hDbEvent) +{ + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// AuthAllow - processes the successful authorization + +int CAimProto::Authorize(HANDLE hDbEvent) +{ + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// AuthDeny - handles the unsuccessful authorization + +int CAimProto::AuthDeny(HANDLE hDbEvent, const TCHAR* szReason) +{ + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// PSR_AUTH + +int __cdecl CAimProto::AuthRecv(HANDLE hContact, PROTORECVEVENT* evt) +{ + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// PSS_AUTHREQUEST + +int __cdecl CAimProto::AuthRequest(HANDLE hContact, const TCHAR* szMessage) +{ + //Not a real authrequest- only used b/c we don't know the group until now. + if (state != 1) + return 1; + + DBVARIANT dbv; + if (!DBGetContactSettingStringUtf(hContact, MOD_KEY_CL, OTH_KEY_GP, &dbv) && dbv.pszVal[0]) + { + add_contact_to_group(hContact, dbv.pszVal); + DBFreeVariant(&dbv); + } + else add_contact_to_group(hContact, AIM_DEFAULT_GROUP); + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// ChangeInfo + +HANDLE __cdecl CAimProto::ChangeInfo(int iInfoType, void* pInfoData) +{ + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// FileAllow - starts a file transfer + +HANDLE __cdecl CAimProto::FileAllow(HANDLE hContact, HANDLE hTransfer, const PROTOCHAR* szPath) +{ + file_transfer *ft = (file_transfer*)hTransfer; + if (ft && ft_list.find_by_ft(ft)) + { + char *path = mir_utf8encodeT(szPath); + + if (ft->pfts.totalFiles > 1 && ft->file[0]) + { + size_t path_len = strlen(path); + size_t len = strlen(ft->file) + 2; + + path = (char*)mir_realloc(path, path_len + len); + mir_snprintf(&path[path_len], len, "%s\\", ft->file); + } + + mir_free(ft->file); + ft->file = path; + + ForkThread(&CAimProto::accept_file_thread, ft); + return ft; + } + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// FileCancel - cancels a file transfer + +int __cdecl CAimProto::FileCancel(HANDLE hContact, HANDLE hTransfer) +{ + file_transfer *ft = (file_transfer*)hTransfer; + if (!ft_list.find_by_ft(ft)) return 0; + + LOG("We are cancelling a file transfer."); + + aim_chat_deny(hServerConn, seqno, ft->sn, ft->icbm_cookie); + + if (ft->hConn) + { + Netlib_Shutdown(ft->hConn); + SetEvent(ft->hResumeEvent); + } + else + ft_list.remove_by_ft(ft); + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// FileDeny - denies a file transfer + +int __cdecl CAimProto::FileDeny(HANDLE hContact, HANDLE hTransfer, const PROTOCHAR* /*szReason*/) +{ + file_transfer *ft = (file_transfer*)hTransfer; + if (!ft_list.find_by_ft(ft)) return 0; + + LOG("We are denying a file transfer."); + + aim_chat_deny(hServerConn, seqno, ft->sn, ft->icbm_cookie); + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// FileResume - processes file renaming etc + +int __cdecl CAimProto::FileResume(HANDLE hTransfer, int* action, const PROTOCHAR** szFilename) +{ + file_transfer *ft = (file_transfer*)hTransfer; + if (!ft_list.find_by_ft(ft)) return 0; + + switch (*action) + { + case FILERESUME_RESUME: + { + struct _stati64 statbuf; + _tstati64(ft->pfts.tszCurrentFile, &statbuf); + ft->pfts.currentFileProgress = statbuf.st_size; + } + break; + + case FILERESUME_RENAME: + mir_free(ft->pfts.tszCurrentFile); + ft->pfts.tszCurrentFile = mir_tstrdup(*szFilename); + break; + + case FILERESUME_OVERWRITE: + ft->pfts.currentFileProgress = 0; + break; + + case FILERESUME_SKIP: + mir_free(ft->pfts.tszCurrentFile); + ft->pfts.tszCurrentFile = NULL; + break; + + default: + aim_file_ad(hServerConn, seqno, ft->sn, ft->icbm_cookie, true, ft->max_ver); + break; + } + SetEvent(ft->hResumeEvent); + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// GetCaps - return protocol capabilities bits + +DWORD_PTR __cdecl CAimProto::GetCaps(int type, HANDLE hContact) +{ + switch (type) + { + case PFLAGNUM_1: + return PF1_IM | PF1_MODEMSG | PF1_BASICSEARCH | PF1_SEARCHBYEMAIL | PF1_FILE; + + case PFLAGNUM_2: +#ifdef ALLOW_BUSY + return PF2_ONLINE | PF2_INVISIBLE | PF2_SHORTAWAY | PF2_ONTHEPHONE | PF2_LIGHTDND; +#else + return PF2_ONLINE | PF2_INVISIBLE | PF2_SHORTAWAY | PF2_ONTHEPHONE; +#endif + + case PFLAGNUM_3: +#ifdef ALLOW_BUSY + return PF2_ONLINE | PF2_SHORTAWAY | PF2_INVISIBLE | PF2_LIGHTDND; +#else + return PF2_ONLINE | PF2_SHORTAWAY | PF2_INVISIBLE; +#endif + + case PFLAGNUM_4: + return PF4_SUPPORTTYPING | PF4_FORCEAUTH | PF4_NOCUSTOMAUTH | PF4_FORCEADDED | + PF4_SUPPORTIDLE | PF4_AVATARS | PF4_IMSENDUTF | PF4_IMSENDOFFLINE; + + case PFLAGNUM_5: + return PF2_ONTHEPHONE; + + case PFLAG_MAXLENOFMESSAGE: + return MAX_MESSAGE_LENGTH; + + case PFLAG_UNIQUEIDTEXT: + return (DWORD_PTR) "Screen Name"; + + case PFLAG_UNIQUEIDSETTING: + return (DWORD_PTR) AIM_KEY_SN; + } + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// GetIcon - loads an icon for the contact list + +HICON __cdecl CAimProto::GetIcon(int iconIndex) +{ + if (LOWORD(iconIndex) == PLI_PROTOCOL) + { + if (iconIndex & PLIF_ICOLIBHANDLE) + return (HICON)GetIconHandle("aim"); + + bool big = (iconIndex & PLIF_SMALL) == 0; + HICON hIcon = LoadIconEx("aim", big); + + if (iconIndex & PLIF_ICOLIB) + return hIcon; + + hIcon = CopyIcon(hIcon); + ReleaseIconEx("aim", big); + return hIcon; + } + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// GetInfo - retrieves a contact info + +int __cdecl CAimProto::GetInfo(HANDLE hContact, int infoType) +{ + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SearchBasic - searches the contact by JID + +void __cdecl CAimProto::basic_search_ack_success(void* p) +{ + char *sn = normalize_name((char*)p); + if (sn) // normalize it + { + if (strlen(sn) > 32) + { + sendBroadcast(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE) 1, 0); + } + else + { + PROTOSEARCHRESULT psr = {0}; + psr.cbSize = sizeof(psr); + psr.id = (TCHAR*)sn; + sendBroadcast(NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE) 1, (LPARAM) & psr); + sendBroadcast(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE) 1, 0); + } + } + mir_free(sn); + mir_free(p); +} + +HANDLE __cdecl CAimProto::SearchBasic(const PROTOCHAR* szId) +{ + if (state != 1) + return 0; + + //duplicating the parameter so that it isn't deleted before it's needed- e.g. this function ends before it's used + ForkThread(&CAimProto::basic_search_ack_success, mir_t2a(szId)); + return (HANDLE)1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SearchByEmail - searches the contact by its e-mail + +HANDLE __cdecl CAimProto::SearchByEmail(const PROTOCHAR* email) +{ + // Maximum email size should really be 320, but the char string is limited to 255. + if (state != 1 || email == NULL || _tcslen(email) >= 254) + return NULL; + + char* szEmail = mir_t2a(email); + aim_search_by_email(hServerConn, seqno, szEmail); + mir_free(szEmail); + return (HANDLE)1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SearchByName - searches the contact by its first or last name, or by a nickname + +HANDLE __cdecl CAimProto::SearchByName(const PROTOCHAR* nick, const PROTOCHAR* firstName, const PROTOCHAR* lastName) +{ + return NULL; +} + +HWND __cdecl CAimProto::SearchAdvanced(HWND owner) +{ + return NULL; +} + +HWND __cdecl CAimProto::CreateExtendedSearchUI(HWND owner) +{ + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// RecvContacts + +int __cdecl CAimProto::RecvContacts(HANDLE hContact, PROTORECVEVENT*) +{ + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// RecvFile + +int __cdecl CAimProto::RecvFile(HANDLE hContact, PROTOFILEEVENT* evt) +{ + return Proto_RecvFile(hContact, evt); +} + +//////////////////////////////////////////////////////////////////////////////////////// +// RecvMsg + +int __cdecl CAimProto::RecvMsg(HANDLE hContact, PROTORECVEVENT* pre) +{ + char *omsg = pre->szMessage; + char *bbuf = NULL; + if (getByte(AIM_KEY_FI, 1)) + { + LOG("Converting from html to bbcodes then stripping leftover html."); + pre->szMessage = bbuf = html_to_bbcodes(pre->szMessage); + } + LOG("Stripping html."); + html_decode(pre->szMessage); + + INT_PTR res = Proto_RecvMessage(hContact, pre); + mir_free(bbuf); + pre->szMessage = omsg; + return ( int )res; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// RecvUrl + +int __cdecl CAimProto::RecvUrl(HANDLE hContact, PROTORECVEVENT*) +{ + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SendContacts + +int __cdecl CAimProto::SendContacts(HANDLE hContact, int flags, int nContacts, HANDLE* hContactsList) +{ + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SendFile - sends a file + +HANDLE __cdecl CAimProto::SendFile(HANDLE hContact, const PROTOCHAR* szDescription, PROTOCHAR** ppszFiles) +{ + if (state != 1) return 0; + + if (hContact && szDescription && ppszFiles) + { + DBVARIANT dbv; + if (!getString(hContact, AIM_KEY_SN, &dbv)) + { + file_transfer *ft = new file_transfer(hContact, dbv.pszVal, NULL); + + bool isDir = false; + int count = 0; + while (ppszFiles[count] != NULL) + { + struct _stati64 statbuf; + if (_tstati64(ppszFiles[count++], &statbuf) == 0) + { + if (statbuf.st_mode & _S_IFDIR) + { + if (ft->pfts.totalFiles == 0) isDir = true; + } + else + { + ft->pfts.totalBytes += statbuf.st_size; + ++ft->pfts.totalFiles; + } + } + } + + if (ft->pfts.totalFiles == 0) + { + delete ft; + return NULL; + } + + ft->pfts.flags |= PFTS_SENDING; + ft->pfts.ptszFiles = ppszFiles; + + ft->file = ft->pfts.totalFiles == 1 || isDir ? mir_utf8encodeT(ppszFiles[0]) : (char*)mir_calloc(1); + ft->sending = true; + ft->message = szDescription[0] ? mir_utf8encodeT(szDescription) : NULL; + ft->me_force_proxy = getByte(AIM_KEY_FP, 0) != 0; + ft->requester = true; + + ft_list.insert(ft); + + if (ft->me_force_proxy) + { + LOG("We are forcing a proxy file transfer."); + ForkThread(&CAimProto::accept_file_thread, ft); + } + else + { + ft->listen(this); + aim_send_file(hServerConn, seqno, detected_ip, ft->local_port, false, ft); + } + + DBFreeVariant(&dbv); + + return ft; + } + } + + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SendMessage - sends a message + +void __cdecl CAimProto::msg_ack_success(void* param) +{ + msg_ack_param *msg_ack = (msg_ack_param*)param; + + Sleep(150); + sendBroadcast(msg_ack->hContact, ACKTYPE_MESSAGE, + msg_ack->success ? ACKRESULT_SUCCESS : ACKRESULT_FAILED, + (HANDLE)msg_ack->id, (LPARAM)msg_ack->msg); + + mir_free(msg_ack); +} + + +int __cdecl CAimProto::SendMsg(HANDLE hContact, int flags, const char* pszSrc) +{ + if (pszSrc == NULL) return 0; + + if (state != 1) + { + msg_ack_param *msg_ack = (msg_ack_param*)mir_calloc(sizeof(msg_ack_param)); + msg_ack->hContact = hContact; + msg_ack->msg = "Message cannot be sent, when protocol offline"; + ForkThread(&CAimProto::msg_ack_success, msg_ack); + } + + char *sn = getSetting(hContact, AIM_KEY_SN); + if (sn == NULL) + { + msg_ack_param *msg_ack = (msg_ack_param*)mir_calloc(sizeof(msg_ack_param)); + msg_ack->hContact = hContact; + msg_ack->msg = "Screen Name for the contact not available"; + ForkThread(&CAimProto::msg_ack_success, msg_ack); + } + + char* msg; + if (flags & PREF_UNICODE) + { + const char* p = strchr(pszSrc, '\0'); + if (p != pszSrc) + { + while (*(++p) == '\0'); + } + msg = mir_utf8encodeW((wchar_t*)p); + } + else if (flags & PREF_UTF) + msg = mir_strdup(pszSrc); + else + msg = mir_utf8encode(pszSrc); + + char* smsg = html_encode(msg); + mir_free(msg); + + if (getByte(AIM_KEY_FO, 1)) + { + msg = bbcodes_to_html(smsg); + mir_free(smsg); + } + else + msg = smsg; + + bool blast = getBool(hContact, AIM_KEY_BLS, false); + int res = aim_send_message(hServerConn, seqno, sn, msg, false, blast); + + mir_free(msg); + mir_free(sn); + + if (!res || blast || 0 == getByte(AIM_KEY_DC, 1)) + { + msg_ack_param *msg_ack = (msg_ack_param*)mir_alloc(sizeof(msg_ack_param)); + msg_ack->hContact = hContact; + msg_ack->msg = NULL; + msg_ack->id = res; + msg_ack->success = res != 0; + ForkThread(&CAimProto::msg_ack_success, msg_ack); + } + + return res; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SendUrl + +int __cdecl CAimProto::SendUrl(HANDLE hContact, int flags, const char* url) +{ + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SetApparentMode - sets the visibility m_iStatus + +int __cdecl CAimProto::SetApparentMode(HANDLE hContact, int mode) +{ + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SetStatus - sets the protocol m_iStatus + +int __cdecl CAimProto::SetStatus(int iNewStatus) +{ + switch (iNewStatus) + { + case ID_STATUS_FREECHAT: + iNewStatus = ID_STATUS_ONLINE; + break; + + case ID_STATUS_DND: + case ID_STATUS_OCCUPIED: + case ID_STATUS_ONTHEPHONE: +#ifdef ALLOW_BUSY + iNewStatus = ID_STATUS_OCCUPIED; + break; +#endif + + case ID_STATUS_OUTTOLUNCH: + case ID_STATUS_NA: + iNewStatus = ID_STATUS_AWAY; + break; + } + + if (iNewStatus == m_iStatus) + return 0; + + if (iNewStatus == ID_STATUS_OFFLINE) + { + broadcast_status(ID_STATUS_OFFLINE); + return 0; + } + + m_iDesiredStatus = iNewStatus; + if (m_iStatus == ID_STATUS_OFFLINE) + { + broadcast_status(ID_STATUS_CONNECTING); + ForkThread(&CAimProto::start_connection, (void*)iNewStatus); + } + else if (m_iStatus > ID_STATUS_OFFLINE) + { + switch(iNewStatus) + { + case ID_STATUS_ONLINE: + aim_set_status(hServerConn, seqno, AIM_STATUS_ONLINE); + broadcast_status(ID_STATUS_ONLINE); + break; + + case ID_STATUS_INVISIBLE: + aim_set_status(hServerConn, seqno, AIM_STATUS_INVISIBLE); + broadcast_status(ID_STATUS_INVISIBLE); + break; + + case ID_STATUS_OCCUPIED: + aim_set_status(hServerConn, seqno, AIM_STATUS_BUSY | AIM_STATUS_AWAY); + broadcast_status(ID_STATUS_OCCUPIED); + break; + + case ID_STATUS_AWAY: + aim_set_status(hServerConn, seqno, AIM_STATUS_AWAY); + broadcast_status(ID_STATUS_AWAY); + break; + } + } + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// GetAwayMsg - returns a contact's away message + +void __cdecl CAimProto::get_online_msg_thread(void* arg) +{ + Sleep(150); + + const HANDLE hContact = arg; + DBVARIANT dbv; + if (!DBGetContactSettingTString(hContact, MOD_KEY_CL, OTH_KEY_SM, &dbv)) { + sendBroadcast(hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)1, (LPARAM)dbv.ptszVal); + DBFreeVariant(&dbv); + } + else sendBroadcast(hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)1, (LPARAM)0); +} + +HANDLE __cdecl CAimProto::GetAwayMsg(HANDLE hContact) +{ + if (state != 1) + return 0; + + int status = getWord(hContact, AIM_KEY_ST, ID_STATUS_OFFLINE); + switch (status) { + case ID_STATUS_AWAY: + case ID_STATUS_ONLINE: + ForkThread(&CAimProto::get_online_msg_thread, hContact); + break; + + default: + return 0; + } + + return (HANDLE)1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// PSR_AWAYMSG + +int __cdecl CAimProto::RecvAwayMsg(HANDLE hContact, int statusMode, PROTORECVEVENT* pre) +{ + sendBroadcast(hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)1, (LPARAM)pre->szMessage); + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// PSS_AWAYMSG + +int __cdecl CAimProto::SendAwayMsg(HANDLE hContact, HANDLE hProcess, const char* msg) +{ + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SetAwayMsg - sets the away m_iStatus message + +int __cdecl CAimProto::SetAwayMsg(int status, const TCHAR* msg) +{ + char** msgptr = get_status_msg_loc(status); + if (msgptr == NULL) return 1; + + char* nmsg = mir_utf8encodeT(msg); + mir_free(*msgptr); *msgptr = nmsg; + + switch (status) + { + case ID_STATUS_FREECHAT: + status = ID_STATUS_ONLINE; + break; + + case ID_STATUS_DND: + case ID_STATUS_OCCUPIED: + case ID_STATUS_ONTHEPHONE: +#ifdef ALLOW_BUSY + status = ID_STATUS_OCCUPIED; + break; +#endif + + case ID_STATUS_OUTTOLUNCH: + case ID_STATUS_NA: + status = ID_STATUS_AWAY; + break; + } + + if (state == 1 && status == m_iStatus) + { + if (!_strcmps(last_status_msg, nmsg)) + return 0; + + mir_free(last_status_msg); + last_status_msg = mir_strdup(nmsg); + aim_set_statusmsg(hServerConn, seqno, nmsg); + aim_set_away(hServerConn, seqno, nmsg, + status == ID_STATUS_AWAY || status == ID_STATUS_OCCUPIED); + } + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// UserIsTyping - sends a UTN notification + +int __cdecl CAimProto::UserIsTyping(HANDLE hContact, int type) +{ + if (state != 1) return 0; + + if (getWord(hContact, AIM_KEY_ST, ID_STATUS_OFFLINE) == ID_STATUS_ONTHEPHONE) + return 0; + + DBVARIANT dbv; + if (!getBool(hContact, AIM_KEY_BLS, false) && !getString(hContact, AIM_KEY_SN, &dbv)) + { + if (type == PROTOTYPE_SELFTYPING_ON) + aim_typing_notification(hServerConn, seqno, dbv.pszVal, 0x0002); + else if (type == PROTOTYPE_SELFTYPING_OFF) + aim_typing_notification(hServerConn, seqno, dbv.pszVal, 0x0000); + DBFreeVariant(&dbv); + } + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// OnEvent - maintain protocol events + +int __cdecl CAimProto::OnEvent(PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM lParam) +{ + switch (eventType) + { + case EV_PROTO_ONLOAD: + return OnModulesLoaded(0, 0); + +// case EV_PROTO_ONEXIT: +// return OnPreShutdown(0, 0); + + case EV_PROTO_ONMENU: + InitMainMenus(); + break; + + case EV_PROTO_ONOPTIONS: + return OnOptionsInit(wParam, lParam); + + case EV_PROTO_ONERASE: + { + char szDbsettings[64]; + mir_snprintf(szDbsettings, sizeof(szDbsettings), "%sP2P", m_szModuleName); + CallService(MS_DB_MODULE_DELETE, 0, (LPARAM)szDbsettings); + break; + } + + case EV_PROTO_ONRENAME: + if (hMenuRoot) + { + CLISTMENUITEM clmi = { 0 }; + clmi.cbSize = sizeof(CLISTMENUITEM); + clmi.flags = CMIM_NAME | CMIF_TCHAR | CMIF_KEEPUNTRANSLATED; + clmi.ptszName = m_tszUserName; + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuRoot, (LPARAM)&clmi); + } + break; + + case EV_PROTO_ONCONTACTDELETED: + return OnContactDeleted(wParam, lParam); + + case EV_PROTO_DBSETTINGSCHANGED: + return OnDbSettingChanged(wParam, lParam); + } + return 1; +} -- cgit v1.2.3