#include "Mra.h" static int MraExtraIconsApplyAll(WPARAM, LPARAM) { for (int i=0; i < g_Instances.getCount(); i++) g_Instances[i]->MraExtraIconsApply(0, 0); return 0; } CMraProto::CMraProto(const char* _module, const TCHAR* _displayName) : PROTO(_module, _displayName), m_bLoggedIn(false), m_groups(5, NumericKeySortT) { InitializeCriticalSectionAndSpinCount(&csCriticalSectionSend, 0); MraSendQueueInitialize(0, &hSendQueueHandle); MraFilesQueueInitialize(0, &hFilesQueueHandle); MraMPopSessionQueueInitialize(&hMPopSessionQueue); MraAvatarsQueueInitialize(&hAvatarsQueueHandle); CreateProtoService(PS_SETCUSTOMSTATUSEX, &CMraProto::MraSetXStatusEx); CreateProtoService(PS_GETCUSTOMSTATUSEX, &CMraProto::MraGetXStatusEx); CreateProtoService(PS_GETCUSTOMSTATUSICON, &CMraProto::MraGetXStatusIcon); CreateProtoService(PS_SET_LISTENINGTO, &CMraProto::MraSetListeningTo); CreateProtoService(PS_CREATEACCMGRUI, &CMraProto::MraCreateAccMgrUI); CreateProtoService(PS_GETAVATARCAPS, &CMraProto::MraGetAvatarCaps); CreateProtoService(PS_GETAVATARINFOT, &CMraProto::MraGetAvatarInfo); CreateProtoService(PS_GETMYAVATART, &CMraProto::MraGetMyAvatar); CreateProtoService(MS_ICQ_SENDSMS, &CMraProto::MraSendSMS); CreateProtoService(PS_SEND_NUDGE, &CMraProto::MraSendNudge); if ( ServiceExists(MS_NUDGE_SEND)) m_heNudgeReceived = CreateProtoEvent(PE_NUDGE); TCHAR name[128]; mir_sntprintf( name, SIZEOF(name), TranslateT("%s connection"), m_tszUserName); NETLIBUSER nlu = { sizeof(nlu) }; nlu.flags = NUF_INCOMING | NUF_OUTGOING | NUF_HTTPCONNS | NUF_UNICODE; nlu.szSettingsModule = m_szModuleName; nlu.ptszDescriptiveName = name; m_hNetlibUser = (HANDLE)CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu); HookProtoEvent(ME_SYSTEM_PRESHUTDOWN, &CMraProto::OnPreShutdown); InitMenus(); mir_snprintf(szNewMailSound, SIZEOF(szNewMailSound), "%s: %s", m_szModuleName, MRA_SOUND_NEW_EMAIL); SkinAddNewSoundEx(szNewMailSound, m_szModuleName, MRA_SOUND_NEW_EMAIL); HookProtoEvent(ME_CLIST_PREBUILDSTATUSMENU, &CMraProto::MraRebuildStatusMenu); hExtraXstatusIcon = ExtraIcon_Register("MRAXstatus", LPGEN("Mail.ru Xstatus"), "mra_xstatus25"); hExtraInfo = ExtraIcon_Register("MRAStatus", LPGEN("Mail.ru extra info"), "mra_xstatus49"); bHideXStatusUI = FALSE; m_iXStatus = getByte(DBSETTING_XSTATUSID, MRA_MIR_XSTATUS_NONE); if ( !IsXStatusValid(m_iXStatus)) m_iXStatus = MRA_MIR_XSTATUS_NONE; bChatExists = MraChatRegister(); } CMraProto::~CMraProto() { Netlib_CloseHandle(m_hNetlibUser); if (m_heNudgeReceived) DestroyHookableEvent(m_heNudgeReceived); MraAvatarsQueueDestroy(hAvatarsQueueHandle); MraMPopSessionQueueDestroy(hMPopSessionQueue); MraFilesQueueDestroy(hFilesQueueHandle); MraSendQueueDestroy(hSendQueueHandle); DeleteCriticalSection(&csCriticalSectionSend); } INT_PTR CMraProto::MraCreateAccMgrUI(WPARAM wParam,LPARAM lParam) { return (int)CreateDialogParam(g_hInstance, MAKEINTRESOURCE(IDD_MRAACCOUNT), (HWND)lParam, DlgProcAccount, LPARAM(this)); } int CMraProto::OnModulesLoaded(WPARAM, LPARAM) { HookProtoEvent(ME_CLIST_EXTRA_IMAGE_APPLY, &CMraProto::MraExtraIconsApply); HookProtoEvent(ME_OPT_INITIALISE, &CMraProto::OnOptionsInit); HookProtoEvent(ME_DB_CONTACT_DELETED, &CMraProto::MraContactDeleted); HookProtoEvent(ME_DB_CONTACT_SETTINGCHANGED, &CMraProto::MraDbSettingChanged); HookProtoEvent(ME_CLIST_PREBUILDCONTACTMENU, &CMraProto::MraRebuildContactMenu); HookProtoEvent(ME_WAT_NEWSTATUS, &CMraProto::MraMusicChanged); HookProtoEvent(ME_CLIST_GROUPCHANGE, &CMraProto::OnGroupChanged); // всех в offline // тк unsaved values сохраняются их нужно инициализировать for (HANDLE hContact = db_find_first(m_szModuleName); hContact != NULL; hContact = db_find_next(hContact, m_szModuleName)) SetContactBasicInfoW(hContact, SCBIFSI_LOCK_CHANGES_EVENTS, (SCBIF_ID|SCBIF_GROUP_ID|SCBIF_SERVER_FLAG|SCBIF_STATUS), -1, -1, 0, 0, ID_STATUS_OFFLINE, 0, 0, 0); // unsaved values db_set_resident(m_szModuleName, "Status");// NOTE: XStatus cannot be temporary db_set_resident(m_szModuleName, "LogonTS"); db_set_resident(m_szModuleName, "ContactID"); db_set_resident(m_szModuleName, "GroupID"); db_set_resident(m_szModuleName, "ContactFlags"); db_set_resident(m_szModuleName, "ContactServerFlags"); db_set_resident(m_szModuleName, "HooksLocked"); db_set_resident(m_szModuleName, DBSETTING_CAPABILITIES); db_set_resident(m_szModuleName, DBSETTING_XSTATUSNAME); db_set_resident(m_szModuleName, DBSETTING_XSTATUSMSG); db_set_resident(m_szModuleName, DBSETTING_BLOGSTATUSTIME); db_set_resident(m_szModuleName, DBSETTING_BLOGSTATUSID); db_set_resident(m_szModuleName, DBSETTING_BLOGSTATUS); db_set_resident(m_szModuleName, DBSETTING_BLOGSTATUSMUSIC); // destroy all chat sessions if (bChatExists) MraChatSessionDestroy(NULL); return 0; } int CMraProto::OnPreShutdown(WPARAM, LPARAM) { SetStatus(ID_STATUS_OFFLINE); MraAvatarsQueueSuspend(hAvatarsQueueHandle); return 0; } ///////////////////////////////////////////////////////////////////////////////////////// HANDLE CMraProto::AddToListByEmail(LPCTSTR plpsEMail, LPCTSTR plpsNick, LPCTSTR plpsFirstName, LPCTSTR plpsLastName, DWORD dwFlags) { if (!plpsEMail) return NULL; BOOL bAdded; HANDLE hContact = MraHContactFromEmail(plpsEMail, TRUE, TRUE, &bAdded); if (hContact == NULL) return NULL; if (plpsNick) mraSetStringW(hContact, "Nick", plpsNick); if (plpsFirstName) mraSetStringW(hContact, "FirstName", plpsFirstName); if (plpsLastName) mraSetStringW(hContact, "LastName", plpsLastName); if (dwFlags & PALF_TEMPORARY) db_set_b(hContact, "CList", "Hidden", 1); else db_unset(hContact, "CList", "NotOnList"); if (bAdded) MraUpdateContactInfo(hContact); return hContact; } HANDLE CMraProto::AddToList(int flags, PROTOSEARCHRESULT *psr) { if (psr->cbSize != sizeof(PROTOSEARCHRESULT)) return 0; return AddToListByEmail(psr->email, psr->nick, psr->firstName, psr->lastName, flags); } HANDLE CMraProto::AddToListByEvent(int flags, int iContact, HANDLE hDbEvent) { DBEVENTINFO dbei = {0}; dbei.cbSize = sizeof(dbei); if ((dbei.cbBlob = db_event_getBlobSize(hDbEvent)) != -1) { dbei.pBlob = (PBYTE)alloca(dbei.cbBlob); if ( db_event_get(hDbEvent, &dbei) == 0 && !strcmp(dbei.szModule, m_szModuleName) && (dbei.eventType == EVENTTYPE_AUTHREQUEST || dbei.eventType == EVENTTYPE_CONTACTS)) { char *nick = (char*)(dbei.pBlob + sizeof(DWORD)*2); char *firstName = nick + strlen(nick) + 1; char *lastName = firstName + strlen(firstName) + 1; char *email = lastName + strlen(lastName) + 1; return AddToListByEmail( _A2T(email), _A2T(nick), _A2T(firstName), _A2T(lastName), 0); } } return 0; } ///////////////////////////////////////////////////////////////////////////////////////// // Stubs HANDLE CMraProto::ChangeInfo(int, void*) { return NULL; } int CMraProto::FileResume(HANDLE, int*, const TCHAR**) { return 1; } int CMraProto::RecvAwayMsg(HANDLE, int, PROTORECVEVENT*) { return 1; } int CMraProto::RecvUrl(HANDLE, PROTORECVEVENT*) { return 1; } int CMraProto::SendUrl(HANDLE, int, const char*) { return 1; } ///////////////////////////////////////////////////////////////////////////////////////// int CMraProto::Authorize(HANDLE hDBEvent) { if (!m_bLoggedIn) return 1; DBEVENTINFO dbei = { sizeof(dbei) }; if ((dbei.cbBlob = db_event_getBlobSize(hDBEvent)) == -1) return 1; dbei.pBlob = (PBYTE)alloca(dbei.cbBlob); if ( db_event_get(hDBEvent, &dbei)) return 1; if (dbei.eventType != EVENTTYPE_AUTHREQUEST) return 1; if ( strcmp(dbei.szModule, m_szModuleName)) return 1; LPSTR lpszNick = (LPSTR)(dbei.pBlob + sizeof(DWORD)*2); LPSTR lpszFirstName = lpszNick + lstrlenA(lpszNick) + 1; LPSTR lpszLastName = lpszFirstName + lstrlenA(lpszFirstName) + 1; MraAuthorize( CMStringA(lpszLastName + lstrlenA(lpszLastName) + 1)); return 0; } int CMraProto::AuthDeny(HANDLE hDBEvent, const TCHAR* szReason) { if (!m_bLoggedIn) return 1; DBEVENTINFO dbei = { sizeof(dbei) }; if ((dbei.cbBlob = db_event_getBlobSize(hDBEvent)) == -1) return 1; dbei.pBlob = (PBYTE)alloca(dbei.cbBlob); if ( db_event_get(hDBEvent, &dbei)) return 1; if (dbei.eventType != EVENTTYPE_AUTHREQUEST) return 1; if ( strcmp(dbei.szModule, m_szModuleName)) return 1; LPSTR lpszNick = (LPSTR)(dbei.pBlob + sizeof(DWORD)*2); LPSTR lpszFirstName = lpszNick + lstrlenA(lpszNick) + 1; LPSTR lpszLastName = lpszFirstName + lstrlenA(lpszFirstName) + 1; LPSTR szEmail = lpszLastName + lstrlenA(lpszLastName) + 1; MraMessage(FALSE, NULL, 0, 0, szEmail, szReason, NULL, 0); return 0; } int CMraProto::AuthRecv(HANDLE hContact, PROTORECVEVENT* pre) { Proto_AuthRecv(m_szModuleName, pre); return 0; } int CMraProto::AuthRequest(HANDLE hContact, const TCHAR *lptszMessage) { return 1; } ///////////////////////////////////////////////////////////////////////////////////////// HANDLE CMraProto::FileAllow(HANDLE hContact, HANDLE hTransfer, const TCHAR *szPath) { if (szPath != NULL) if ( MraFilesQueueAccept(hFilesQueueHandle, (DWORD)hTransfer, szPath, lstrlen(szPath)) == NO_ERROR) return hTransfer; // Success return NULL; } int CMraProto::FileCancel(HANDLE hContact, HANDLE hTransfer) { if (hContact && hTransfer) { MraFilesQueueCancel(hFilesQueueHandle, (DWORD)hTransfer, TRUE); return 0; // Success } return 1; } int CMraProto::FileDeny(HANDLE hContact, HANDLE hTransfer, const TCHAR*) { return FileCancel(hContact, hTransfer); } ///////////////////////////////////////////////////////////////////////////////////////// DWORD_PTR CMraProto::GetCaps(int type, HANDLE hContact) { switch ( type ) { case PFLAGNUM_1: return PF1_IM | PF1_FILE | PF1_MODEMSG | PF1_SERVERCLIST | PF1_AUTHREQ | PF1_ADDED | PF1_VISLIST | PF1_INVISLIST | PF1_INDIVSTATUS | PF1_PEER2PEER | PF1_CHAT | PF1_BASICSEARCH | PF1_EXTSEARCH | PF1_CANRENAMEFILE | PF1_FILERESUME | PF1_ADDSEARCHRES | PF1_CONTACT | PF1_SEARCHBYEMAIL | PF1_USERIDISEMAIL | PF1_SEARCHBYNAME | PF1_EXTSEARCHUI; case PFLAGNUM_2: return PF2_ONLINE | PF2_INVISIBLE | PF2_SHORTAWAY | PF2_HEAVYDND | PF2_FREECHAT; case PFLAGNUM_3: return PF2_ONLINE | PF2_INVISIBLE | PF2_SHORTAWAY | PF2_HEAVYDND | PF2_FREECHAT; case PFLAGNUM_4: return PF4_FORCEAUTH | PF4_FORCEADDED | PF4_SUPPORTTYPING | PF4_AVATARS | PF4_IMSENDUTF; case PFLAG_UNIQUEIDTEXT: return (INT_PTR)Translate("E-mail address"); case PFLAG_MAXCONTACTSPERPACKET: return MRA_MAXCONTACTSPERPACKET; case PFLAG_UNIQUEIDSETTING: return (INT_PTR)"e-mail"; case PFLAG_MAXLENOFMESSAGE: return MRA_MAXLENOFMESSAGE; default: return 0; } } int CMraProto::GetInfo(HANDLE hContact, int infoType) { return MraUpdateContactInfo(hContact) != 0; } ///////////////////////////////////////////////////////////////////////////////////////// HANDLE CMraProto::SearchBasic(const TCHAR *id) { return SearchByEmail(id); } HANDLE CMraProto::SearchByEmail(const TCHAR *email) { if (m_bLoggedIn && email) return MraWPRequestByEMail(NULL, ACKTYPE_SEARCH, CMStringA(email)); return NULL; } HANDLE CMraProto::SearchByName(const TCHAR *pszNick, const TCHAR *pszFirstName, const TCHAR *pszLastName) { INT_PTR iRet = 0; if (m_bLoggedIn && (*pszNick || *pszFirstName || *pszLastName)) { DWORD dwRequestFlags = 0; if (*pszNick) SetBit(dwRequestFlags, MRIM_CS_WP_REQUEST_PARAM_NICKNAME); if (*pszFirstName) SetBit(dwRequestFlags, MRIM_CS_WP_REQUEST_PARAM_FIRSTNAME); if (*pszLastName) SetBit(dwRequestFlags, MRIM_CS_WP_REQUEST_PARAM_LASTNAME); return MraWPRequestW(NULL, ACKTYPE_SEARCH, dwRequestFlags, "", "", pszNick, pszFirstName, pszLastName, 0, 0, 0, 0, 0, 0, 0, 0, 0); } return NULL; } ///////////////////////////////////////////////////////////////////////////////////////// int CMraProto::RecvContacts(HANDLE hContact, PROTORECVEVENT* pre) { DBEVENTINFO dbei = { sizeof(dbei) }; dbei.szModule = m_szModuleName; dbei.timestamp = pre->timestamp; dbei.flags = (pre->flags & PREF_CREATEREAD) ? DBEF_READ : 0; dbei.eventType = EVENTTYPE_CONTACTS; dbei.cbBlob = pre->lParam; dbei.pBlob = (PBYTE)pre->szMessage; db_event_add(hContact, &dbei); return 0; } int CMraProto::RecvFile(HANDLE hContact, PROTORECVFILET *pre) { return Proto_RecvFile(hContact, pre); } int CMraProto::RecvMsg(HANDLE hContact, PROTORECVEVENT *pre) { return Proto_RecvMessage(hContact, pre); } ///////////////////////////////////////////////////////////////////////////////////////// int CMraProto::SendContacts(HANDLE hContact, int flags, int nContacts, HANDLE* hContactsList) { INT_PTR iRet = 0; if (m_bLoggedIn && hContact) { BOOL bSlowSend; CMStringW wszData, wszEmail; CMStringA szEmail; if ( mraGetStringA(hContact, "e-mail", szEmail)) { for (int i = 0; i < nContacts; i++) { if ( IsContactMra( hContactsList[i] )) if ( mraGetStringW(hContactsList[i], "e-mail", wszEmail)) wszData += wszEmail + ';' + GetContactNameW(hContactsList[i]) + ';'; } bSlowSend = getByte("SlowSend", MRA_DEFAULT_SLOW_SEND); iRet = MraMessage(bSlowSend, hContact, ACKTYPE_CONTACTS, MESSAGE_FLAG_CONTACT, szEmail, wszData, NULL, 0); if (bSlowSend == FALSE) ProtoBroadcastAck(hContact, ACKTYPE_CONTACTS, ACKRESULT_SUCCESS, (HANDLE)iRet, 0); } } else ProtoBroadcastAck(hContact, ACKTYPE_CONTACTS, ACKRESULT_FAILED, NULL, (LPARAM)"You cannot send when you are offline."); return iRet; } HANDLE CMraProto::SendFile(HANDLE hContact, const TCHAR* szDescription, TCHAR** ppszFiles) { INT_PTR iRet = 0; if (m_bLoggedIn && hContact && ppszFiles) { size_t dwFilesCount; for (dwFilesCount = 0; ppszFiles[dwFilesCount]; dwFilesCount++); MraFilesQueueAddSend(hFilesQueueHandle, 0, hContact, ppszFiles, dwFilesCount, (DWORD*)&iRet); } return (HANDLE)iRet; } int CMraProto::SendMsg(HANDLE hContact, int flags, const char *lpszMessage) { if (!m_bLoggedIn) { ProtoBroadcastAck(hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, NULL, (LPARAM)"You cannot send when you are offline."); return 0; } DWORD dwFlags = 0; LPWSTR lpwszMessage = NULL; int iRet = 0; if (flags & PREF_UNICODE) lpwszMessage = (LPWSTR)(lpszMessage + lstrlenA(lpszMessage)+1 ); else if (flags & PREF_UTF) lpwszMessage = mir_utf8decodeT(lpszMessage); else lpwszMessage = mir_a2t(lpszMessage); if ( !lpwszMessage) { ProtoBroadcastAck(hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, NULL, (LPARAM)"Cant allocate buffer for convert to unicode."); return 0; } CMStringA szEmail; if ( mraGetStringA(hContact, "e-mail", szEmail)) { BOOL bSlowSend = getByte("SlowSend", MRA_DEFAULT_SLOW_SEND); if ( getByte("RTFSendEnable", MRA_DEFAULT_RTF_SEND_ENABLE) && (MraContactCapabilitiesGet(hContact) & FEATURE_FLAG_RTF_MESSAGE)) dwFlags |= MESSAGE_FLAG_RTF; iRet = MraMessage(bSlowSend, hContact, ACKTYPE_MESSAGE, dwFlags, szEmail, lpwszMessage, NULL, 0); if (bSlowSend == FALSE) ProtoBroadcastAckAsync(hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE)iRet, 0); } mir_free(lpwszMessage); return iRet; } ///////////////////////////////////////////////////////////////////////////////////////// int CMraProto::SetApparentMode(HANDLE hContact, int mode) { if (!m_bLoggedIn || !hContact) return 1; // Only 3 modes are supported if (hContact && (mode == 0 || mode == ID_STATUS_ONLINE || mode == ID_STATUS_OFFLINE)) { DWORD dwOldMode = getWord(hContact, "ApparentMode", 0); // Dont send redundant updates if (mode != dwOldMode) { DWORD dwContactFlag = 0; switch (mode) { case ID_STATUS_OFFLINE: dwContactFlag |= CONTACT_FLAG_INVISIBLE; break; case ID_STATUS_ONLINE: dwContactFlag |= CONTACT_FLAG_VISIBLE; break; } if ( MraModifyContact(hContact, 0, &dwContactFlag)) { SetContactBasicInfoW(hContact, 0, SCBIF_FLAG, 0, 0, dwContactFlag, 0, 0, 0, 0, 0); return 0; // Success } } } return 1; } int CMraProto::SetStatus(int iNewStatus) { // remap global statuses to local supported switch (iNewStatus) { case ID_STATUS_OCCUPIED: iNewStatus = ID_STATUS_DND; break; case ID_STATUS_NA: case ID_STATUS_ONTHEPHONE: case ID_STATUS_OUTTOLUNCH: iNewStatus = ID_STATUS_AWAY; break; } // nothing to change if (m_iStatus == iNewStatus) return 0; DWORD dwOldStatusMode; //set all contacts to offline if ((m_iDesiredStatus = iNewStatus) == ID_STATUS_OFFLINE) { m_bLoggedIn = FALSE; dwOldStatusMode = InterlockedExchange((volatile LONG*)&m_iStatus, m_iDesiredStatus); // всех в offline, только если мы бывали подключены if (dwOldStatusMode > ID_STATUS_OFFLINE) for (HANDLE hContact = db_find_first(m_szModuleName); hContact; hContact = db_find_next(hContact, m_szModuleName)) SetContactBasicInfoW(hContact, SCBIFSI_LOCK_CHANGES_EVENTS, (SCBIF_ID|SCBIF_GROUP_ID|SCBIF_SERVER_FLAG|SCBIF_STATUS), -1, -1, 0, 0, ID_STATUS_OFFLINE, 0, 0, 0); Netlib_CloseHandle(m_hConnection); } else { // если offline то сразу ставим connecting, но обработка как offline dwOldStatusMode = InterlockedCompareExchange((volatile LONG*)&m_iStatus, ID_STATUS_CONNECTING, ID_STATUS_OFFLINE); switch (dwOldStatusMode) { case ID_STATUS_OFFLINE: // offline, connecting if (StartConnect() != NO_ERROR) { m_bLoggedIn = FALSE; m_iDesiredStatus = ID_STATUS_OFFLINE; dwOldStatusMode = InterlockedExchange((volatile LONG*)&m_iStatus, m_iDesiredStatus); } break; case ID_STATUS_ONLINE:// connected, change status case ID_STATUS_AWAY: case ID_STATUS_DND: case ID_STATUS_FREECHAT: case ID_STATUS_INVISIBLE: MraSendNewStatus(m_iDesiredStatus, m_iXStatus, _T(""), _T("")); case ID_STATUS_CONNECTING: // предотвращаем переход в любой статус (кроме offline) из статуса connecting, если он не вызван самим плагином if (dwOldStatusMode == ID_STATUS_CONNECTING && iNewStatus != m_iDesiredStatus) break; default: dwOldStatusMode = InterlockedExchange((volatile LONG*)&m_iStatus, m_iDesiredStatus); break; } } MraSetContactStatus(NULL, m_iStatus); ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)dwOldStatusMode, m_iStatus); return 0; } HANDLE CMraProto::GetAwayMsg(HANDLE hContact) { if (!m_bLoggedIn || ! hContact) return 0; TCHAR szStatusDesc[MICBLOG_STATUS_MAX+MICBLOG_STATUS_MAX+MAX_PATH], szTime[64]; DWORD dwTime; int iRet = 0; CMStringW szBlogStatus; if ( mraGetStringW(hContact, DBSETTING_BLOGSTATUS, szBlogStatus)) { SYSTEMTIME tt = {0}; dwTime = getDword(hContact, DBSETTING_BLOGSTATUSTIME, 0); if (dwTime && MakeLocalSystemTimeFromTime32(dwTime, &tt)) mir_sntprintf(szTime, SIZEOF(szTime), _T("%04ld.%02ld.%02ld %02ld:%02ld: "), tt.wYear, tt.wMonth, tt.wDay, tt.wHour, tt.wMinute); else szTime[0] = 0; mir_sntprintf(szStatusDesc, SIZEOF(szStatusDesc), _T("%s%s"), szTime, szBlogStatus.c_str()); iRet = GetTickCount(); ProtoBroadcastAck(hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)iRet, (LPARAM)szStatusDesc); } return (HANDLE)iRet; } int CMraProto::SetAwayMsg(int m_iStatus, const TCHAR* msg) { if (!m_bLoggedIn) return 1; size_t dwStatusDescSize = lstrlen(msg); DWORD dwStatus = m_iStatus; DWORD dwXStatus = m_iXStatus; // не отправляем новый статусный текст для хстатусов, для хстатусов только эвей сообщения if (dwStatus != ID_STATUS_ONLINE || IsXStatusValid(dwXStatus) == FALSE) { dwStatusDescSize = min(dwStatusDescSize, STATUS_DESC_MAX); MraSendNewStatus(dwStatus, dwXStatus, _T(""), msg); } return 0; } int CMraProto::UserIsTyping(HANDLE hContact, int type) { if (!m_bLoggedIn || !hContact || type == PROTOTYPE_SELFTYPING_OFF) return 1; CMStringA szEmail; if ( MraGetContactStatus(hContact) != ID_STATUS_OFFLINE && m_iStatus != ID_STATUS_INVISIBLE) if ( mraGetStringA(hContact, "e-mail", szEmail)) if ( MraMessage(FALSE, hContact, 0, MESSAGE_FLAG_NOTIFY, szEmail, L" ", NULL, 0)) return 0; return 1; } int CMraProto::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_ONOPTIONS: return OnOptionsInit( wParam, lParam ); case EV_PROTO_ONMENU: CListCreateMenu(2000060000, 500085000, TRUE, gdiMenuItems, MAIN_MENU_ITEMS_COUNT, hMainMenuItems); break; } return 1; }