#include "stdafx.h" #include "MraOfflineMsg.h" #include "MraRTFMsg.h" #include "MraPlaces.h" DWORD CMraProto::StartConnect() { if (m_bShutdown) return ERROR_OPERATION_ABORTED; // поток ещё/уже не работал, поставили статус что работает и запускаем if (InterlockedCompareExchange((volatile LONG*)&m_dwThreadWorkerRunning, TRUE, FALSE)) return 0; CMStringA szEmail; if (!mraGetStringA(NULL, "e-mail", szEmail)) return 0; CMStringA szPass; if (szEmail.GetLength() <= 5) MraPopupShowFromAgentW(MRA_POPUP_TYPE_WARNING, TranslateT("Please, setup e-mail in options")); else if (!GetPassDB(szPass)) MraPopupShowFromAgentW(MRA_POPUP_TYPE_WARNING, TranslateT("Please, setup password in options")); else { InterlockedExchange((volatile LONG*)&m_dwThreadWorkerLastPingTime, GetTickCount()); if (INVALID_HANDLE_VALUE != ForkThreadEx(&CMraProto::MraThreadProc, nullptr, nullptr)) return 0; /* OK. */ MraPopupShowFromAgentW(MRA_POPUP_TYPE_ERROR, TranslateT("Thread creation failure")); } InterlockedExchange((volatile LONG*)&m_dwThreadWorkerRunning, FALSE); return ERROR_OPERATION_ABORTED; } void CMraProto::MraThreadProc(LPVOID) { BOOL bConnected = FALSE; CMStringA szHost; DWORD dwConnectReTryCount, dwCurConnectReTryCount; Thread_SetName("MRA: ProtoThreadProc"); SleepEx(100, FALSE);// to prevent high CPU load by some status plugins like allwaysonline dwConnectReTryCount = getDword("ConnectReTryCountMRIM", MRA_DEFAULT_CONN_RETRY_COUNT_MRIM); NETLIBOPENCONNECTION nloc = { 0 }; nloc.cbSize = sizeof(nloc); nloc.flags = NLOCF_V2; nloc.timeout = getDword("TimeOutConnectMRIM", MRA_DEFAULT_TIMEOUT_CONN_MRIM); if (nloc.timeout < MRA_TIMEOUT_CONN_MIN) nloc.timeout = MRA_TIMEOUT_CONN_MIN; if (nloc.timeout > MRA_TIMEOUT_CONN_MAX) nloc.timeout = MRA_TIMEOUT_CONN_MAX; InterlockedExchange((volatile LONG*)&m_dwThreadWorkerLastPingTime, GetTickCount()); if (MraGetNLBData(szHost, &nloc.wPort) == NO_ERROR) { nloc.szHost = szHost; //nloc.szHost = "217.69.141.245"; //nloc.wPort = 443; //nloc.flags |= NLOCF_SSL; dwCurConnectReTryCount = dwConnectReTryCount; do { InterlockedExchange((volatile LONG*)&m_dwThreadWorkerLastPingTime, GetTickCount()); m_hConnection = Netlib_OpenConnection(m_hNetlibUser, &nloc); } while (--dwCurConnectReTryCount && m_hConnection == nullptr); if (m_hConnection) bConnected = TRUE; } if (bConnected == FALSE) if (getByte("NLBFailDirectConnect", MRA_DEFAULT_NLB_FAIL_DIRECT_CONNECT)) { if (IsHTTPSProxyUsed(m_hNetlibUser)) nloc.wPort = MRA_SERVER_PORT_HTTPS; else { nloc.wPort = getWord("ServerPort", MRA_DEFAULT_SERVER_PORT); if (nloc.wPort == MRA_SERVER_PORT_STANDART_NLB) nloc.wPort = MRA_SERVER_PORT_STANDART; } for (DWORD i = 1; (i < MRA_MAX_MRIM_SERVER && m_iStatus != ID_STATUS_OFFLINE); i++) { szHost.Format("mrim%lu.mail.ru", i); dwCurConnectReTryCount = dwConnectReTryCount; do { InterlockedExchange((volatile LONG*)&m_dwThreadWorkerLastPingTime, GetTickCount()); m_hConnection = Netlib_OpenConnection(m_hNetlibUser, &nloc); } while (--dwCurConnectReTryCount && m_hConnection == nullptr); if (m_hConnection) { bConnected = TRUE; break; } } } if (bConnected && m_iStatus != ID_STATUS_OFFLINE) MraNetworkDispatcher(); else { if (bConnected == FALSE) { ShowFormattedErrorMessage(L"Can't connect to MRIM server, error", GetLastError()); ProtoBroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, nullptr, LOGINERR_NONETWORK); } } MraMPopSessionQueueFlush(hMPopSessionQueue); NETLIB_CLOSEHANDLE(m_hConnection); dwCMDNum = 0; InterlockedExchange((volatile LONG*)&m_dwThreadWorkerRunning, FALSE); SetStatus(ID_STATUS_OFFLINE); } DWORD CMraProto::MraGetNLBData(CMStringA &szHost, WORD *pwPort) { DWORD dwRetErrorCode; BOOL bContinue = TRUE; BYTE btBuff[MAX_PATH]; DWORD dwConnectReTryCount, dwCurConnectReTryCount; LPSTR lpszPort; size_t dwBytesReceived, dwRcvBuffSizeUsed = 0; NETLIBSELECT nls = { 0 }; NETLIBOPENCONNECTION nloc = { 0 }; dwConnectReTryCount = getDword("ConnectReTryCountNLB", MRA_DEFAULT_CONN_RETRY_COUNT_NLB); nloc.cbSize = sizeof(nloc); nloc.flags = NLOCF_V2; if (mraGetStringA(NULL, "Server", szHost)) nloc.szHost = szHost; else nloc.szHost = MRA_DEFAULT_SERVER; if (IsHTTPSProxyUsed(m_hNetlibUser)) nloc.wPort = MRA_SERVER_PORT_HTTPS; else nloc.wPort = getWord("ServerPort", MRA_DEFAULT_SERVER_PORT); nloc.timeout = getDword("TimeOutConnectNLB", MRA_DEFAULT_TIMEOUT_CONN_NLB); if (nloc.timeout < MRA_TIMEOUT_CONN_MIN) nloc.timeout = MRA_TIMEOUT_CONN_MIN; if (nloc.timeout > MRA_TIMEOUT_CONN_MAX) nloc.timeout = MRA_TIMEOUT_CONN_MAX; dwCurConnectReTryCount = dwConnectReTryCount; do { InterlockedExchange((volatile LONG*)&m_dwThreadWorkerLastPingTime, GetTickCount()); nls.hReadConns[0] = Netlib_OpenConnection(m_hNetlibUser, &nloc); } while (--dwCurConnectReTryCount && nls.hReadConns[0] == nullptr); if (nls.hReadConns[0]) { nls.dwTimeout = 1000 * getDword("TimeOutReceiveNLB", MRA_DEFAULT_TIMEOUT_RECV_NLB); InterlockedExchange((volatile LONG*)&m_dwThreadWorkerLastPingTime, GetTickCount()); while (m_iStatus != ID_STATUS_OFFLINE && bContinue) { switch (Netlib_Select(&nls)) { case SOCKET_ERROR: case 0:// Time out bContinue = FALSE; break; case 1: dwBytesReceived = Netlib_Recv(nls.hReadConns[0], (LPSTR)(btBuff + dwRcvBuffSizeUsed), (int)(_countof(btBuff) - dwRcvBuffSizeUsed), 0); if (dwBytesReceived && dwBytesReceived != SOCKET_ERROR) dwRcvBuffSizeUsed += dwBytesReceived; else bContinue = FALSE; break; } InterlockedExchange((volatile LONG*)&m_dwThreadWorkerLastPingTime, GetTickCount()); } Netlib_CloseHandle(nls.hReadConns[0]); if (dwRcvBuffSizeUsed) { lpszPort = (LPSTR)MemoryFindByte(0, btBuff, dwRcvBuffSizeUsed, ':'); if (lpszPort) { (*lpszPort) = 0; lpszPort++; szHost = (LPSTR)btBuff; if (pwPort) (*pwPort) = (WORD)StrToUNum32(lpszPort, (dwRcvBuffSizeUsed - (lpszPort - (LPSTR)btBuff))); dwRetErrorCode = NO_ERROR; } else { dwRetErrorCode = ERROR_INVALID_USER_BUFFER; ShowFormattedErrorMessage(L"NLB data corrupted", NO_ERROR); } } else { dwRetErrorCode = GetLastError(); ShowFormattedErrorMessage(L"Can't get data for NLB, error", dwRetErrorCode); } } else { dwRetErrorCode = GetLastError(); ShowFormattedErrorMessage(L"Can't connect to NLB server, error", dwRetErrorCode); } return dwRetErrorCode; } DWORD CMraProto::MraNetworkDispatcher() { DWORD dwRetErrorCode = NO_ERROR; bool bContinue = true; DWORD dwDataCurrentBuffSize, dwDataCurrentBuffSizeUsed; size_t dwRcvBuffSize = BUFF_SIZE_RCV, dwRcvBuffSizeUsed = 0, dwDataCurrentBuffOffset = 0; LPBYTE lpbBufferRcv; mrim_packet_header_t *pmaHeader; NETLIBSELECT nls = { sizeof(nls) }; nls.dwTimeout = 30000; nls.hReadConns[0] = m_hConnection; lpbBufferRcv = (LPBYTE)mir_calloc(dwRcvBuffSize); m_dwNextPingSendTickTime = m_dwPingPeriod = MAXDWORD; dwCMDNum = 0; MraSendCMD(MRIM_CS_HELLO, nullptr, 0); while (m_iStatus != ID_STATUS_OFFLINE && bContinue) { int iSelectRet = Netlib_Select(&nls); if (SOCKET_ERROR == iSelectRet) { if (m_iStatus != ID_STATUS_OFFLINE) { dwRetErrorCode = GetLastError(); ShowFormattedErrorMessage(L"Disconnected, socket error", dwRetErrorCode); } break; } // Time out or normal m_dwThreadWorkerLastPingTime = GetTickCount(); /* Server ping. */ if (m_dwNextPingSendTickTime <= m_dwThreadWorkerLastPingTime) { nls.dwTimeout = (m_dwPingPeriod * 1000); m_dwNextPingSendTickTime = (m_dwThreadWorkerLastPingTime + nls.dwTimeout); MraSendCMD(MRIM_CS_PING, nullptr, 0); } else { if (MAXDWORD != m_dwNextPingSendTickTime) nls.dwTimeout = (m_dwNextPingSendTickTime - m_dwThreadWorkerLastPingTime); } { /* Remove old items from send queue. */ DWORD dwCmdNum, dwFlags, dwAckType; MCONTACT hContact; LPBYTE lpbData; size_t dwDataSize; while (!MraSendQueueFindOlderThan(hSendQueueHandle, SEND_QUEUE_TIMEOUT, &dwCmdNum, &dwFlags, &hContact, &dwAckType, &lpbData, &dwDataSize)) { switch (dwAckType) { case ACKTYPE_ADDED: case ACKTYPE_AUTHREQ: case ACKTYPE_CONTACTS: //nothing to do break; case ACKTYPE_MESSAGE: ProtoBroadcastAck(hContact, dwAckType, ACKRESULT_FAILED, (HANDLE)dwCmdNum, (LPARAM)"Undefined message deliver error, time out"); break; case ACKTYPE_GETINFO: ProtoBroadcastAck(hContact, dwAckType, ACKRESULT_FAILED, (HANDLE)1, 0); break; case ACKTYPE_SEARCH: ProtoBroadcastAck(hContact, dwAckType, ACKRESULT_SUCCESS, (HANDLE)dwCmdNum, 0); break; case ICQACKTYPE_SMS: ProtoBroadcastAck(NULL, dwAckType, ACKRESULT_FAILED, (HANDLE)dwCmdNum, 0); mir_free(lpbData); break; } MraSendQueueFree(hSendQueueHandle, dwCmdNum); } } if (iSelectRet == 0) // Time out continue; // expand receive buffer dynamically if ((dwRcvBuffSize - dwRcvBuffSizeUsed) < BUFF_SIZE_RCV_MIN_FREE) { dwRcvBuffSize += BUFF_SIZE_RCV; lpbBufferRcv = (LPBYTE)mir_realloc(lpbBufferRcv, dwRcvBuffSize); } DWORD dwBytesReceived = Netlib_Recv(nls.hReadConns[0], (LPSTR)(lpbBufferRcv + dwRcvBuffSizeUsed), (int)(dwRcvBuffSize - dwRcvBuffSizeUsed), 0); if ( !dwBytesReceived || dwBytesReceived == SOCKET_ERROR) { // disconnected if (m_iStatus != ID_STATUS_OFFLINE) { dwRetErrorCode = GetLastError(); debugLogA("Disconnected, socket read error %d", dwRetErrorCode); } break; } dwRcvBuffSizeUsed += dwBytesReceived; while (TRUE) { dwDataCurrentBuffSize = (int)(dwRcvBuffSize - dwDataCurrentBuffOffset); dwDataCurrentBuffSizeUsed = (int)(dwRcvBuffSizeUsed - dwDataCurrentBuffOffset); pmaHeader = (mrim_packet_header_t*)(lpbBufferRcv + dwDataCurrentBuffOffset); // packet header received if (dwDataCurrentBuffSizeUsed < sizeof(mrim_packet_header_t)) { // packet to small, continue receiving debugLogW(L"Packet to small, continue receiving\n"); memmove(lpbBufferRcv, (lpbBufferRcv + dwDataCurrentBuffOffset), dwDataCurrentBuffSizeUsed); dwRcvBuffSizeUsed = dwDataCurrentBuffSizeUsed; dwDataCurrentBuffOffset = 0; break; } if (pmaHeader->magic != CS_MAGIC) { // bad packet debugLogW(L"Bad packet\n"); dwDataCurrentBuffOffset = 0; dwRcvBuffSizeUsed = 0; break; } // packet OK if ((dwDataCurrentBuffSizeUsed - sizeof(mrim_packet_header_t)) < pmaHeader->dlen) { // not all packet received, continue receiving if (dwDataCurrentBuffOffset) { memmove(lpbBufferRcv, (lpbBufferRcv + dwDataCurrentBuffOffset), dwDataCurrentBuffSizeUsed); dwRcvBuffSizeUsed = dwDataCurrentBuffSizeUsed; dwDataCurrentBuffOffset = 0; } debugLogW(L"Not all packet received, continue receiving\n"); break; } // full packet received, may be more than one bContinue = MraCommandDispatcher(pmaHeader); // move pointer to next packet in buffer if (dwDataCurrentBuffSizeUsed - sizeof(mrim_packet_header_t) > pmaHeader->dlen) dwDataCurrentBuffOffset += sizeof(mrim_packet_header_t)+pmaHeader->dlen; // move pointer to begin of buffer else { // динамическое уменьшение буффера приёма if (dwRcvBuffSize > BUFF_SIZE_RCV) { dwRcvBuffSize = BUFF_SIZE_RCV; lpbBufferRcv = (LPBYTE)mir_realloc(lpbBufferRcv, dwRcvBuffSize); } dwDataCurrentBuffOffset = 0; dwRcvBuffSizeUsed = 0; break; } } } mir_free(lpbBufferRcv); return dwRetErrorCode; } //Подтверждение установки соединения// UL ## ping_period ## Ожидаемая частота подтверждения соединения (в секундах) bool CMraProto::CmdHelloAck(BinBuffer &buf) { buf >> m_dwPingPeriod; CMStringA szPass; if (!GetPassDB(szPass)) return false; char szValueName[MAX_PATH]; CMStringA szUserAgentFormatted, szEmail; CMStringW wszStatusTitle, wszStatusDesc; DWORD dwXStatusMir = m_iXStatus, dwXStatus; DWORD dwStatus = GetMraStatusFromMiradaStatus(m_iDesiredStatus, dwXStatusMir, &dwXStatus); if (IsXStatusValid(dwXStatusMir)) {// xstatuses mir_snprintf(szValueName, "XStatus%ldName", dwXStatusMir); if (!mraGetStringW(NULL, szValueName, wszStatusTitle)) wszStatusTitle = TranslateW(lpcszXStatusNameDef[dwXStatusMir]); mir_snprintf(szValueName, "XStatus%ldMsg", dwXStatusMir); mraGetStringW(NULL, szValueName, wszStatusDesc); } else wszStatusTitle = Clist_GetStatusModeDescription(m_iDesiredStatus, 0); CMStringA szSelfVersionString = MraGetSelfVersionString(); if (!mraGetStringA(NULL, "MirVerCustom", szUserAgentFormatted)) szUserAgentFormatted.Format( "client=\"magent\" name=\"Miranda NG\" title=\"%s\" version=\"777.%lu.%lu.%lu\" build=\"%lu\" protocol=\"%lu.%lu\"", szSelfVersionString.c_str(), __FILEVERSION_STRING, PROTO_VERSION_MAJOR, PROTO_VERSION_MINOR); DWORD dwFutureFlags = (getByte("RTFReceiveEnable", MRA_DEFAULT_RTF_RECEIVE_ENABLE) ? FEATURE_FLAG_RTF_MESSAGE : 0) | MRA_FEATURE_FLAGS; if (!mraGetStringA(NULL, "e-mail", szEmail)) return false; MraLogin2W(szEmail, szPass, dwStatus, lpcszStatusUri[dwXStatus], wszStatusTitle, wszStatusDesc, dwFutureFlags, szUserAgentFormatted, szSelfVersionString); return true; } // Successful authorization bool CMraProto::CmdLoginAck() { m_bLoggedIn = TRUE; m_dwNextPingSendTickTime = 0; // force send ping MraSendCMD(MRIM_CS_PING, nullptr, 0); SetStatus(m_iDesiredStatus); MraAvatarsQueueGetAvatarSimple(hAvatarsQueueHandle, GAIF_FORCE, NULL); return true; } // Unsuccessful authorization //LPS ## reason ## причина отказа bool CMraProto::CmdLoginRejected(BinBuffer &buf) { ProtoBroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, nullptr, LOGINERR_WRONGPASSWORD); CMStringA reason; buf >> reason; MraPopupShowW(NULL, MRA_POPUP_TYPE_ERROR, TranslateT("Logon error: invalid login/password"), _A2T(reason.c_str())); return false; } // Message delivery //LPS ## from ## Адрес отправителя //LPS ## message ## текстовая версия сообщения //LPS ## rtf-message ## форматированная версия сообщения bool CMraProto::CmdMessageAck(BinBuffer &buf) { DWORD dwMsgID, dwFlags; CMStringA szEmail, szText, szRTFText, szMultiChatData; buf >> dwMsgID >> dwFlags >> szEmail >> szText >> szRTFText; if (dwFlags & MESSAGE_FLAG_MULTICHAT) buf >> szMultiChatData; // LPS multichat_data // подтверждаем получение, только если удалось его обработать if (MraRecvCommand_Message((DWORD)_time32(nullptr), dwFlags, szEmail, szText, szRTFText, szMultiChatData) == NO_ERROR) if ((dwFlags & MESSAGE_FLAG_NORECV) == 0) MraMessageRecv(szEmail, dwMsgID); return true; } bool CMraProto::CmdMessageStatus(ULONG seq, BinBuffer &buf) { DWORD dwAckType, dwTemp = buf.getDword(); MCONTACT hContact; if (!MraSendQueueFind(hSendQueueHandle, seq, nullptr, &hContact, &dwAckType, nullptr, nullptr)) { switch (dwTemp) { case MESSAGE_DELIVERED:// Message delivered directly to user ProtoBroadcastAckAsync(hContact, dwAckType, ACKRESULT_SUCCESS, (HANDLE)seq, 0); break;//***deb возможны сбои из-за асинхронности тк там передаётся указатель case MESSAGE_REJECTED_NOUSER:// Message rejected - no such user ProtoBroadcastAck(hContact, dwAckType, ACKRESULT_FAILED, (HANDLE)seq, (LPARAM)"Message rejected - no such user"); break; case MESSAGE_REJECTED_INTERR:// Internal server error ProtoBroadcastAck(hContact, dwAckType, ACKRESULT_FAILED, (HANDLE)seq, (LPARAM)"Internal server error"); break; case MESSAGE_REJECTED_LIMIT_EXCEEDED:// Offline messages limit exceeded ProtoBroadcastAck(hContact, dwAckType, ACKRESULT_FAILED, (HANDLE)seq, (LPARAM)"Offline messages limit exceeded"); break; case MESSAGE_REJECTED_TOO_LARGE:// Message is too large ProtoBroadcastAck(hContact, dwAckType, ACKRESULT_FAILED, (HANDLE)seq, (LPARAM)"Message is too large"); break; case MESSAGE_REJECTED_DENY_OFFMSG:// User does not accept offline messages ProtoBroadcastAck(hContact, dwAckType, ACKRESULT_FAILED, (HANDLE)seq, (LPARAM)"User does not accept offline messages"); break; case MESSAGE_REJECTED_DENY_OFFFLSH:// User does not accept offline flash animation ProtoBroadcastAck(hContact, dwAckType, ACKRESULT_FAILED, (HANDLE)seq, (LPARAM)"User does not accept offline flash animation"); break; default: ProtoBroadcastAck(hContact, dwAckType, ACKRESULT_FAILED, (HANDLE)seq, (LPARAM)CMStringA().Format("Undefined message delivery error, code: %lu", dwTemp)); break; } MraSendQueueFree(hSendQueueHandle, seq); } // not found in queue else if (dwTemp != MESSAGE_DELIVERED) MraPopupShowFromAgentW(MRA_POPUP_TYPE_DEBUG, TranslateT("MRIM_CS_MESSAGE_STATUS: not found in queue")); return true; } bool CMraProto::CmdUserInfo(BinBuffer &buf) { CMStringA szString; CMStringW szStringW; while (!buf.eof()) { buf >> szString; if (szString == "MESSAGES.TOTAL") { buf >> szString; dwEmailMessagesTotal = atoi(szString); } else if (szString == "MESSAGES.UNREAD") { buf >> szString; m_dwEmailMessagesUnread = atoi(szString); } else if (szString == "MRIM.NICKNAME") { buf >> szStringW; mraSetStringW(NULL, "Nick", szStringW); } else if (szString == "client.endpoint") { buf >> szStringW; szString = szStringW; int lpszDelimiter = szString.Find(':'); if (lpszDelimiter != -1) { CMStringA szAddr(szString, lpszDelimiter); setDword("IP", ntohl(inet_addr(szAddr.c_str()))); } } else if (szString == "connect.xml") { debugLogA(szString); buf >> szStringW; debugLogW(szStringW); } else if (szString == "micblog.show_title") { debugLogA(szString); buf >> szString; debugLogW(szStringW); } else if (szString == "micblog.status.xml") { debugLogA(szString); buf >> szString; debugLogA(szString); } else if (szString == "micblog.status.id") { buf >> szStringW; DWORDLONG dwBlogStatusID = _wtoi64(szStringW); mraWriteContactSettingBlob(NULL, DBSETTING_BLOGSTATUSID, &dwBlogStatusID, sizeof(DWORDLONG)); } else if (szString == "micblog.status.time") { buf >> szStringW; setDword(DBSETTING_BLOGSTATUSTIME, _wtoi(szStringW)); } else if (szString == "micblog.status.text") { buf >> szStringW; mraSetStringW(NULL, DBSETTING_BLOGSTATUS, szStringW); } else if (szString == "HAS_MYMAIL" || szString == "mrim.status.open_search" || szString == "rb.target.cookie" || szString == "show_web_history_link" || szString == "friends_suggest" || szString == "timestamp" || szString == "trusted_update" || szString == "mrim.wp.dating") { debugLogA(szString); buf >> szStringW; debugLogW(szStringW); } else _CrtDbgBreak(); } MraUpdateEmailStatus("", "", false); return true; } //Сообщение доставленное, пока пользователь не был подключен к сети bool CMraProto::CmdOfflineMessageAck(BinBuffer &buf) { CMStringA szEmail, szText, lpsRTFText, lpsMultiChatData, szString; DWORDLONG dwMsgUIDL; buf >> dwMsgUIDL >> szString; DWORD dwTime, dwFlags; if (MraOfflineMessageGet(szString, dwTime, dwFlags, szEmail, szText, lpsRTFText, lpsMultiChatData) == NO_ERROR) { DWORD dwTemp = MraRecvCommand_Message(dwTime, dwFlags, szEmail, szText, lpsRTFText, lpsMultiChatData); if (dwTemp == NO_ERROR || dwTemp == ERROR_ACCESS_DENIED) MraOfflineMessageDel(dwMsgUIDL); else ShowFormattedErrorMessage(L"Offline message processing error, message will not deleted from server", NO_ERROR); } else ShowFormattedErrorMessage(L"Offline message processing error, message will not deleted from server", NO_ERROR); return true; } // Auth confirmation bool CMraProto::CmdAuthAck(BinBuffer &buf) { CMStringA szEmail; buf >> szEmail; BOOL bAdded; MCONTACT hContact = MraHContactFromEmail(szEmail, TRUE, TRUE, &bAdded); if (bAdded) MraUpdateContactInfo(hContact); if (IsEMailChatAgent(szEmail) == FALSE) { CMStringA szBuff = CreateBlobFromContact(hContact, L""); DBEVENTINFO dbei = {}; dbei.flags = DBEF_UTF; dbei.szModule = m_szModuleName; dbei.timestamp = (DWORD)_time32(nullptr); dbei.eventType = EVENTTYPE_ADDED; dbei.cbBlob = szBuff.GetLength(); dbei.pBlob = (PBYTE)szBuff.GetString(); db_event_add(0, &dbei); } DWORD dwTemp; GetContactBasicInfoW(hContact, nullptr, nullptr, nullptr, &dwTemp, nullptr, nullptr, nullptr, nullptr); dwTemp &= ~CONTACT_INTFLAG_NOT_AUTHORIZED; SetContactBasicInfoW(hContact, SCBIFSI_LOCK_CHANGES_EVENTS, SCBIF_SERVER_FLAG, 0, 0, 0, dwTemp, 0, nullptr, nullptr, nullptr); setDword(hContact, "HooksLocked", TRUE); db_unset(hContact, "CList", "NotOnList"); setDword(hContact, "HooksLocked", FALSE); return true; } // Web auth key bool CMraProto::CmdPopSession(BinBuffer &buf) { DWORD dwTemp = buf.getDword(); if (dwTemp) { CMStringA szString; buf >> szString; if (NO_ERROR == MraMPopSessionQueueSetNewMPopKey(hMPopSessionQueue, szString)) { MraMPopSessionQueueStart(hMPopSessionQueue); return true; } } //error MraPopupShowFromAgentW(MRA_POPUP_TYPE_WARNING, TranslateT("Server error: can't get MPOP key for web authorize")); MraMPopSessionQueueFlush(hMPopSessionQueue); return true; } bool CMraProto::CmdFileTransfer(BinBuffer &buf) { DWORD dwIDRequest, dwFilesTotalSize, dwTemp; CMStringA szFiles, szEmail, szAddresses; CMStringW wszFilesW; buf >> szEmail >> dwIDRequest >> dwFilesTotalSize >> dwTemp; if (dwTemp) { buf >> szFiles >> dwTemp; if (dwTemp) { // LPS DESCRIPTION buf >> dwTemp >> wszFilesW; _ASSERTE(dwTemp != 1); } buf >> szAddresses; } BOOL bAdded = FALSE; MCONTACT hContact = MraHContactFromEmail(szEmail, TRUE, TRUE, &bAdded); if (bAdded) MraUpdateContactInfo(hContact); if (wszFilesW.IsEmpty()) wszFilesW = szFiles; if (!wszFilesW.IsEmpty()) MraFilesQueueAddReceive(hFilesQueueHandle, 0, hContact, dwIDRequest, wszFilesW, szAddresses); return true; } bool CMraProto::CmdFileTransferAck(BinBuffer &buf) { CMStringA szEmail, szString; DWORD dwAckType, dwTemp; buf >> dwAckType >> szEmail >> dwTemp >> szString; switch (dwAckType) { case FILE_TRANSFER_STATUS_OK:// игнорируем, мы и так уже слушаем порт(ждём), то что кто то согласился ничего не меняет //hContact = MraHContactFromEmail(szEmail.lpszData, szEmail.dwSize, TRUE, TRUE, NULL); break; case FILE_TRANSFER_STATUS_DECLINE: MraFilesQueueCancel(hFilesQueueHandle, dwTemp, FALSE); break; case FILE_TRANSFER_STATUS_ERROR: ShowFormattedErrorMessage(L"File transfer: error", NO_ERROR); MraFilesQueueCancel(hFilesQueueHandle, dwTemp, FALSE); break; case FILE_TRANSFER_STATUS_INCOMPATIBLE_VERS: ShowFormattedErrorMessage(L"File transfer: incompatible versions", NO_ERROR); MraFilesQueueCancel(hFilesQueueHandle, dwTemp, FALSE); break; case FILE_TRANSFER_MIRROR: MraFilesQueueSendMirror(hFilesQueueHandle, dwTemp, szString); break; default:// ## unknown error wchar_t szBuff[1024]; mir_snwprintf(szBuff, TranslateT("MRIM_CS_FILE_TRANSFER_ACK: unknown error, code: %lu"), dwAckType); ShowFormattedErrorMessage(szBuff, NO_ERROR); break; } return true; } // Смена статуса другого пользователя bool CMraProto::CmdUserStatus(BinBuffer &buf) { DWORD dwStatus, dwXStatus, dwFutureFlags; CMStringA szSpecStatusUri, szUserAgentFormatted, szEmail; CMStringW szStatusTitle, szStatusDesc; buf >> dwStatus >> szSpecStatusUri >> szStatusTitle >> szStatusDesc >> szEmail >> dwFutureFlags >> szUserAgentFormatted; BOOL bAdded; if (MCONTACT hContact = MraHContactFromEmail(szEmail, TRUE, TRUE, &bAdded)) { if (bAdded) MraUpdateContactInfo(hContact); DWORD dwTemp = GetMirandaStatusFromMraStatus(dwStatus, GetMraXStatusIDFromMraUriStatus(szSpecStatusUri), &dwXStatus); MraContactCapabilitiesSet(hContact, dwFutureFlags); setByte(hContact, DBSETTING_XSTATUSID, (BYTE)dwXStatus); if (dwXStatus) { mraSetStringW(hContact, DBSETTING_XSTATUSNAME, szStatusTitle); mraSetStringW(hContact, DBSETTING_XSTATUSMSG, szStatusDesc); } else { delSetting(hContact, DBSETTING_XSTATUSNAME); delSetting(hContact, DBSETTING_XSTATUSMSG); } if (dwTemp != ID_STATUS_OFFLINE) { // пишем клиента только если юзер не отключён, иначе не затираем старое if (!szUserAgentFormatted.IsEmpty()) { if (getByte("MirVerRaw", MRA_DEFAULT_MIRVER_RAW) == FALSE) szUserAgentFormatted = MraGetVersionStringFromFormatted(szUserAgentFormatted); } else szUserAgentFormatted = (szEmail.Find("@uin.icq") == -1) ? MIRVER_UNKNOWN : "ICQ client"; mraSetStringA(hContact, "MirVer", szUserAgentFormatted); } if (dwTemp == MraGetContactStatus(hContact)) {// меняем шило на шило, подозрительно? ;) if (dwTemp == ID_STATUS_OFFLINE) { // was/now invisible CMStringW wszEmail, wszBuff; mraGetStringW(hContact, "e-mail", wszEmail); wszBuff.Format(L"%s <%s> - %s", Clist_GetContactDisplayName(hContact), wszEmail.c_str(), TranslateT("invisible status changed")); MraPopupShowFromContactW(hContact, MRA_POPUP_TYPE_INFORMATION, wszBuff); MraSetContactStatus(hContact, ID_STATUS_INVISIBLE); } } MraSetContactStatus(hContact, dwTemp); SetExtraIcons(hContact); } return true; } bool CMraProto::CmdContactAck(int cmd, int seq, BinBuffer &buf) { DWORD dwAckType; MCONTACT hContact; if (!MraSendQueueFind(hSendQueueHandle, seq, nullptr, &hContact, &dwAckType, nullptr, nullptr)) { DWORD dwTemp = buf.getDword(); switch (dwTemp) { case CONTACT_OPER_SUCCESS:// ## добавление произведено успешно if (cmd == MRIM_CS_ADD_CONTACT_ACK) { DWORD dwFlags = SCBIF_ID | SCBIF_SERVER_FLAG, dwGroupID = 0; ptrW grpName(db_get_wsa(hContact, "CList", "Group")); if (grpName) { dwFlags |= SCBIF_GROUP_ID; dwGroupID = MraMoveContactToGroup(hContact, -1, grpName); } SetContactBasicInfoW(hContact, 0, dwFlags, buf.getDword(), dwGroupID, 0, CONTACT_INTFLAG_NOT_AUTHORIZED, 0, nullptr, nullptr, nullptr); } break; case CONTACT_OPER_ERROR:// ## переданные данные были некорректны ShowFormattedErrorMessage(L"Data been sent are invalid", NO_ERROR); break; case CONTACT_OPER_INTERR:// ## при обработке запроса произошла внутренняя ошибка ShowFormattedErrorMessage(L"Internal server error", NO_ERROR); break; case CONTACT_OPER_NO_SUCH_USER:// ## добавляемого пользователя не существует в системе SetContactBasicInfoW(hContact, 0, SCBIF_SERVER_FLAG, 0, 0, 0, -1, 0, nullptr, nullptr, nullptr); ShowFormattedErrorMessage(L"No such user to add", NO_ERROR); break; case CONTACT_OPER_INVALID_INFO:// ## некорректное имя пользователя ShowFormattedErrorMessage(L"Invalid user name", NO_ERROR); break; case CONTACT_OPER_USER_EXISTS:// ## пользователь уже есть в контакт-листе ShowFormattedErrorMessage(L"User already added", NO_ERROR); break; case CONTACT_OPER_GROUP_LIMIT:// ## превышено максимально допустимое количество групп (20) ShowFormattedErrorMessage(L"Group limit is 20", NO_ERROR); break; default:// ## unknown error wchar_t szBuff[1024]; mir_snwprintf(szBuff, TranslateT("MRIM_CS_*_CONTACT_ACK: unknown server error, code: %lu"), dwTemp); MraPopupShowFromAgentW(MRA_POPUP_TYPE_DEBUG, szBuff); break; } MraSendQueueFree(hSendQueueHandle, seq); } else MraPopupShowFromAgentW(MRA_POPUP_TYPE_DEBUG, TranslateT("MRIM_CS_*_CONTACT_ACK: not found in queue")); return true; } bool CMraProto::CmdAnketaInfo(int seq, BinBuffer &buf) { DWORD dwAckType, dwFlags; MCONTACT hContact; if (MraSendQueueFind(hSendQueueHandle, seq, &dwFlags, &hContact, &dwAckType, nullptr, nullptr)) { MraPopupShowFromAgentW(MRA_POPUP_TYPE_DEBUG, TranslateT("MRIM_ANKETA_INFO: not found in queue")); return true; } switch (buf.getDword()) { case MRIM_ANKETA_INFO_STATUS_NOUSER:// не найдено ни одной подходящей записи SetContactBasicInfoW(hContact, 0, SCBIF_SERVER_FLAG, 0, 0, 0, -1, 0, nullptr, nullptr, nullptr); case MRIM_ANKETA_INFO_STATUS_DBERR:// ошибка базы данных case MRIM_ANKETA_INFO_STATUS_RATELIMERR:// слишком много запросов, поиск временно запрещен switch (dwAckType) { case ACKTYPE_GETINFO: ProtoBroadcastAck(hContact, dwAckType, ACKRESULT_FAILED, (HANDLE)1, 0); break; case ACKTYPE_SEARCH: ProtoBroadcastAck(hContact, dwAckType, ACKRESULT_SUCCESS, (HANDLE)seq, 0); break; } break; case MRIM_ANKETA_INFO_STATUS_OK: // поиск успешно завершен DWORD dwFieldsNum, dwMaxRows, dwServerTime; DWORD dwID, dwContactSeverFlags, dwStatus, dwXStatus; buf >> dwFieldsNum >> dwMaxRows >> dwServerTime; CMStringA *pmralpsFields = new CMStringA[dwFieldsNum]; CMStringA val; CMStringW valW, StatusNameW, StatusMsgW; /* Default contact statuses in mail.ru format. */ dwStatus = STATUS_OFFLINE; dwXStatus = MRA_XSTATUS_OFFLINE; // read headers name for (DWORD i = 0; i < dwFieldsNum; i++) { buf >> pmralpsFields[i]; debugLogA(pmralpsFields[i] + " "); } while (!buf.eof()) { // write to DB and exit loop if (dwAckType == ACKTYPE_GETINFO && hContact) { setDword(hContact, "InfoTS", (DWORD)_time32(nullptr)); //MRA_LPS mralpsUsernameValue; for (DWORD i = 0; i < dwFieldsNum; i++) { CMStringA &fld = pmralpsFields[i]; if (fld == "Nickname") { buf >> valW; mraSetStringW(hContact, "Nick", valW); } else if (fld == "FirstName") { buf >> valW; mraSetStringW(hContact, "FirstName", valW); } else if (fld == "LastName") { buf >> valW; mraSetStringW(hContact, "LastName", valW); } else if (fld == "Sex") { buf >> val; switch (atoi(val)) { case 1:// мужской setByte(hContact, "Gender", 'M'); break; case 2:// женский setByte(hContact, "Gender", 'F'); break; default:// а фиг его знает delSetting(hContact, "Gender"); break; } } else if (fld == "Birthday") { buf >> val; if (val.GetLength() > 9) {// calc "Age" SYSTEMTIME stTime = { 0 }; stTime.wYear = (WORD)StrToUNum32(val.c_str(), 4); stTime.wMonth = (WORD)StrToUNum32(val.c_str() + 5, 2); stTime.wDay = (WORD)StrToUNum32(val.c_str() + 8, 2); setWord(hContact, "BirthYear", stTime.wYear); setByte(hContact, "BirthMonth", (BYTE)stTime.wMonth); setByte(hContact, "BirthDay", (BYTE)stTime.wDay); setWord(hContact, "Age", (WORD)GetYears(&stTime)); } else { delSetting(hContact, "BirthYear"); delSetting(hContact, "BirthMonth"); delSetting(hContact, "BirthDay"); delSetting(hContact, "Age"); } } else if (fld == "City_id") { buf >> val; DWORD dwTemp = atoi(val); if (dwTemp) { for (size_t j = 0; mrapPlaces[j].lpszData; j++) { if (mrapPlaces[j].dwCityID == dwTemp) { mraSetStringW(hContact, "City", mrapPlaces[j].lpszData); break; } } } else delSetting(hContact, "City"); } else if (fld == "Location") { buf >> valW; mraSetStringW(hContact, "About", valW); } else if (fld == "Country_id") { buf >> val; DWORD dwTemp = atoi(val); if (dwTemp) { for (size_t j = 0; mrapPlaces[j].lpszData; j++) { if (mrapPlaces[j].dwCountryID == dwTemp) { mraSetStringW(hContact, "Country", mrapPlaces[j].lpszData); break; } } } else delSetting(hContact, "Country"); } else if (fld == "Phone") { delSetting(hContact, "Phone"); delSetting(hContact, "Cellular"); delSetting(hContact, "Fax"); buf >> val; if (val.GetLength()) { int iStart = 0; CMStringA szPhone = val.Tokenize(",", iStart); if (iStart != -1) { mraSetStringA(hContact, "Phone", szPhone); szPhone = val.Tokenize(",", iStart); } if (iStart != -1) { mraSetStringA(hContact, "Cellular", szPhone); szPhone = val.Tokenize(",", iStart); } if (iStart != -1) mraSetStringA(hContact, "Fax", szPhone); } } else if (fld == "mrim_status") { buf >> val; if (val.GetLength()) dwStatus = atoi(val); } else if (fld == "status_uri") { buf >> val; if (val.GetLength()) dwXStatus = GetMraXStatusIDFromMraUriStatus(val); } else if (fld == "status_title") { buf >> StatusNameW; } else if (fld == "status_desc") { buf >> StatusMsgW; } else {// for DEBUG ONLY buf >> val; debugLogA("%s = %s\n", fld.c_str(), val.c_str()); } } /* for */ // для авторизованного нам и так присылают правильный статус GetContactBasicInfoW(hContact, &dwID, nullptr, nullptr, &dwContactSeverFlags, nullptr, nullptr, nullptr, nullptr); if (dwID == -1 || (dwContactSeverFlags & CONTACT_INTFLAG_NOT_AUTHORIZED)) { /* Convert mail.ru statuses to miranda. */ dwStatus = GetMirandaStatusFromMraStatus(dwStatus, dwXStatus, &dwXStatus); MraSetContactStatus(hContact, dwStatus); setByte(hContact, DBSETTING_XSTATUSID, (BYTE)dwXStatus); if (StatusNameW.GetLength()) mraSetStringW(hContact, DBSETTING_XSTATUSNAME, StatusNameW); if (StatusMsgW.GetLength()) mraSetStringW(hContact, DBSETTING_XSTATUSMSG, StatusMsgW); } } else if (dwAckType == ACKTYPE_SEARCH) { wchar_t szNick[MAX_EMAIL_LEN] = { 0 }, szFirstName[MAX_EMAIL_LEN] = { 0 }, szLastName[MAX_EMAIL_LEN] = { 0 }, szEmail[MAX_EMAIL_LEN] = { 0 }; CMStringA mralpsUsernameValue; PROTOSEARCHRESULT psr = { 0 }; psr.cbSize = sizeof(psr); psr.flags = PSR_UNICODE; psr.nick.w = szNick; psr.firstName.w = szFirstName; psr.lastName.w = szLastName; psr.email.w = szEmail; psr.id.w = szEmail; for (DWORD i = 0; i < dwFieldsNum; i++) { CMStringA &fld = pmralpsFields[i]; if (fld == "Username") { buf >> val; mralpsUsernameValue = val; } else if (fld == "Domain") { // имя было уже задано ранее buf >> val; wcsncpy_s(szEmail, _A2T(mralpsUsernameValue + "@" + val), _TRUNCATE); } else if (fld == "Nickname") { buf >> valW; wcsncpy_s(szNick, valW, _TRUNCATE); } else if (fld == "FirstName") { buf >> valW; wcsncpy_s(szFirstName, valW, _TRUNCATE); } else if (fld == "LastName") { buf >> valW; wcsncpy_s(szLastName, valW, _TRUNCATE); } else buf >> val; } ProtoBroadcastAck(hContact, dwAckType, ACKRESULT_DATA, (HANDLE)seq, (LPARAM)&psr); } } delete[] pmralpsFields; switch (dwAckType) { case ACKTYPE_GETINFO: ProtoBroadcastAck(hContact, dwAckType, ACKRESULT_SUCCESS, (HANDLE)1, 0); break; case ACKTYPE_SEARCH: default: ProtoBroadcastAck(hContact, dwAckType, ACKRESULT_SUCCESS, (HANDLE)seq, 0); break; } break; } MraSendQueueFree(hSendQueueHandle, seq); return true; } bool CMraProto::CmdGame(BinBuffer &buf) { MCONTACT hContact; CMStringA szEmail, szData; DWORD dwGameSessionID, dwGameMsg, dwGameMsgID, dwTemp; buf >> szEmail >> dwGameSessionID >> dwGameMsg >> dwGameMsgID >> dwTemp >> szData; switch (dwGameMsg) { case GAME_CONNECTION_INVITE: if (m_iStatus != ID_STATUS_INVISIBLE) MraGame(szEmail, dwGameSessionID, GAME_DECLINE, dwGameMsgID, szData); break; case GAME_CONNECTION_ACCEPT: break; case GAME_DECLINE: break; case GAME_INC_VERSION: break; case GAME_NO_SUCH_GAME:// user invisible if ((hContact = MraHContactFromEmail(szEmail, FALSE, TRUE, nullptr))) if (MraGetContactStatus(hContact) == ID_STATUS_OFFLINE) MraSetContactStatus(hContact, ID_STATUS_INVISIBLE); break; case GAME_JOIN: break; case GAME_CLOSE: break; case GAME_SPEED: break; case GAME_SYNCHRONIZATION: break; case GAME_USER_NOT_FOUND: break; case GAME_ACCEPT_ACK: break; case GAME_PING: break; case GAME_RESULT: break; case GAME_MESSAGES_NUMBER: break; default: wchar_t szBuff[1024]; mir_snwprintf(szBuff, TranslateT("MRIM_CS_GAME: unknown internal game message code: %lu"), dwGameMsg); MraPopupShowFromAgentW(MRA_POPUP_TYPE_DEBUG, szBuff); break; } return true; } bool CMraProto::CmdClist2(BinBuffer &buf) { DWORD dwTemp = buf.getDword(); if (dwTemp == GET_CONTACTS_OK) { // received contact list m_groups.destroy(); DWORD dwGroupsCount, dwContactFlag = 0, dwGroupID = 0, dwContactSeverFlags = 0, dwStatus = 0, dwXStatus, dwFutureFlags = 0, dwBlogStatusTime = 0; ULARGE_INTEGER dwBlogStatusID; CMStringA szGroupMask, szContactMask, szEmail, szString; CMStringA szCustomPhones, szSpecStatusUri, szUserAgentFormatted; CMStringW wszNick, wszString, wszGroupName, wszStatusTitle, wszStatusDesc, wszBlogStatus, wszBlogStatusMusic; buf >> dwGroupsCount >> szGroupMask >> szContactMask; int iGroupMode = getByte("GroupMode", 100); debugLogA("Groups: %s\n", szGroupMask.c_str()); DWORD dwID = 0; for (DWORD i = 0; i < dwGroupsCount; i++) { //groups handle DWORD dwControlParam = 0, dwGroupFlags = 0; for (int j = 0; j < szGroupMask.GetLength(); j++) { //enumerating parameters switch (szGroupMask[j]) { case 's'://LPS buf >> wszString; break; case 'u'://UL buf >> dwTemp; break; } if (j == 0 && szGroupMask[j] == 'u') { // GroupFlags dwGroupFlags = dwTemp; dwControlParam++; } else if (j == 1 && szGroupMask[j] == 's') { // GroupName wszGroupName = wszString; dwControlParam++; } } // add/modify group if (dwControlParam > 1) { // все параметры правильно инициализированны! if (!(dwGroupFlags & CONTACT_FLAG_REMOVED)) { m_groups.insert(new MraGroupItem(dwID, dwGroupFlags, wszGroupName)); Clist_GroupCreate(0, wszGroupName); } debugLogW(L"'%s', flags: %lu (", wszGroupName.c_str(), dwGroupFlags); if (dwGroupFlags & CONTACT_FLAG_REMOVED) debugLogA("CONTACT_FLAG_REMOVED, "); if (dwGroupFlags & CONTACT_FLAG_GROUP) debugLogA("CONTACT_FLAG_GROUP, "); if (dwGroupFlags & CONTACT_FLAG_INVISIBLE) debugLogA("CONTACT_FLAG_INVISIBLE, "); if (dwGroupFlags & CONTACT_FLAG_VISIBLE) debugLogA("CONTACT_FLAG_VISIBLE, "); if (dwGroupFlags & CONTACT_FLAG_IGNORE) debugLogA("CONTACT_FLAG_IGNORE, "); if (dwGroupFlags & CONTACT_FLAG_SHADOW) debugLogA("CONTACT_FLAG_SHADOW, "); if (dwGroupFlags & CONTACT_FLAG_AUTHORIZED) debugLogA("CONTACT_FLAG_AUTHORIZED, "); if (dwGroupFlags & CONTACT_FLAG_MULTICHAT) debugLogA("CONTACT_FLAG_MULTICHAT, "); if (dwGroupFlags & CONTACT_FLAG_UNICODE_NAME) debugLogA("CONTACT_FLAG_UNICODE_NAME, "); if (dwGroupFlags & CONTACT_FLAG_PHONE) debugLogA("CONTACT_FLAG_PHONE, "); debugLogA(")"); } dwID++; } debugLogA("Contacts: %s\n", szContactMask.c_str()); dwID = 20; while (!buf.eof()) { DWORD dwControlParam = 0; for (int j = 0; j < szContactMask.GetLength(); j++) { //enumerating parameters BYTE fieldType = szContactMask[j]; if (fieldType == 'u') buf >> dwTemp; if (j == 0 && fieldType == 'u') { // Flags dwContactFlag = dwTemp; dwControlParam++; } else if (j == 1 && fieldType == 'u') { // Group id dwGroupID = dwTemp; dwControlParam++; } else if (j == 2 && fieldType == 's') { // Email buf >> szEmail; dwControlParam++; } else if (j == 3 && fieldType == 's') { // Nick buf >> wszNick; dwControlParam++; } else if (j == 4 && fieldType == 'u') { // Server flags dwContactSeverFlags = dwTemp; dwControlParam++; } else if (j == 5 && fieldType == 'u') { // Status dwStatus = dwTemp; dwControlParam++; } else if (j == 6 && fieldType == 's') { // Custom Phone number, buf >> szCustomPhones; dwControlParam++; } else if (j == 7 && fieldType == 's') { // spec_status_uri buf >> szSpecStatusUri; dwControlParam++; } else if (j == 8 && fieldType == 's') { // status_title buf >> wszStatusTitle; dwControlParam++; } else if (j == 9 && fieldType == 's') { // status_desc buf >> wszStatusDesc; dwControlParam++; } else if (j == 10 && fieldType == 'u') { // com_support (future flags) dwFutureFlags = dwTemp; dwControlParam++; } else if (j == 11 && fieldType == 's') { // user_agent (formated string) buf >> szUserAgentFormatted; dwControlParam++; } else if (j == 12 && fieldType == 'u') { // BlogStatusID dwBlogStatusID.LowPart = dwTemp; dwControlParam++; } else if (j == 13 && fieldType == 'u') { // BlogStatusID dwBlogStatusID.HighPart = dwTemp; dwControlParam++; } else if (j == 14 && fieldType == 'u') { // BlogStatusTime dwBlogStatusTime = dwTemp; dwControlParam++; } else if (j == 15 && fieldType == 's') { // BlogStatus buf >> wszBlogStatus; dwControlParam++; } else if (j == 16 && fieldType == 's') { // BlogStatusMusic buf >> wszBlogStatusMusic; dwControlParam++; } else if (j == 17 && fieldType == 's') { // BlogStatusSender // ignory buf >> szString; dwControlParam++; } else if (j == 18 && fieldType == 's') { // geo data ? buf >> szString; dwControlParam++; } else if (j == 19 && fieldType == 's') { // ?????? ? buf >> szString; dwControlParam++; _ASSERTE(szString.GetLength()); } else { if (fieldType == 's') { buf >> szString; if (szString.GetLength()) { debugLogA(szString + " "); } } else if (fieldType == 'u') { char szBuff[50]; mir_snprintf(szBuff, "%lu, ", dwTemp);//; debugLogA("%s ", szBuff); } else _CrtDbgBreak(); } } debugLogA("ID: %lu, Group id: %lu, %s: flags: %lu (", dwID, dwGroupID, szEmail.c_str(), dwContactFlag); if (dwContactFlag & CONTACT_FLAG_REMOVED) debugLogA("CONTACT_FLAG_REMOVED, "); if (dwContactFlag & CONTACT_FLAG_GROUP) debugLogA("CONTACT_FLAG_GROUP, "); if (dwContactFlag & CONTACT_FLAG_INVISIBLE) debugLogA("CONTACT_FLAG_INVISIBLE, "); if (dwContactFlag & CONTACT_FLAG_VISIBLE) debugLogA("CONTACT_FLAG_VISIBLE, "); if (dwContactFlag & CONTACT_FLAG_IGNORE) debugLogA("CONTACT_FLAG_IGNORE, "); if (dwContactFlag & CONTACT_FLAG_SHADOW) debugLogA("CONTACT_FLAG_SHADOW, "); if (dwContactFlag & CONTACT_FLAG_AUTHORIZED) debugLogA("CONTACT_FLAG_AUTHORIZED, "); if (dwContactFlag & CONTACT_FLAG_MULTICHAT) debugLogA("CONTACT_FLAG_MULTICHAT, "); if (dwContactFlag & CONTACT_FLAG_UNICODE_NAME) debugLogA("CONTACT_FLAG_UNICODE_NAME, "); if (dwContactFlag & CONTACT_FLAG_PHONE) debugLogA("CONTACT_FLAG_PHONE, "); debugLogA(")"); debugLogA(": server flags: %lu (", dwContactSeverFlags); if (dwContactSeverFlags & CONTACT_INTFLAG_NOT_AUTHORIZED) debugLogA("CONTACT_INTFLAG_NOT_AUTHORIZED, "); debugLogA(")"); // add/modify contact if (dwGroupID != 103)//***deb filtering phone/sms contats if (_strnicmp(szEmail, "phone", 5)) if (dwControlParam > 5)// все параметры правильно инициализированны! if ((dwContactFlag & (CONTACT_FLAG_GROUP | CONTACT_FLAG_REMOVED)) == 0) { BOOL bAdded; MCONTACT hContact = MraHContactFromEmail(szEmail, TRUE, FALSE, &bAdded); if (hContact) { // already in list, remove the duplicate if (GetContactBasicInfoW(hContact, &dwTemp, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr) == NO_ERROR && dwTemp != -1) { _CrtDbgBreak(); } else { dwTemp = GetMirandaStatusFromMraStatus(dwStatus, GetMraXStatusIDFromMraUriStatus(szSpecStatusUri), &dwXStatus); if (bAdded) { // update user info SetContactBasicInfoW(hContact, SCBIFSI_LOCK_CHANGES_EVENTS, (SCBIF_ID | SCBIF_GROUP_ID | SCBIF_FLAG | SCBIF_SERVER_FLAG | SCBIF_STATUS | SCBIF_NICK | SCBIF_PHONES), dwID, dwGroupID, dwContactFlag, dwContactSeverFlags, dwTemp, nullptr, &wszNick, &szCustomPhones); // request user info from server MraUpdateContactInfo(hContact); } else { if (iGroupMode == 100) { // first start ptrW tszGroup(db_get_wsa(hContact, "CList", "Group")); if (tszGroup) dwGroupID = MraMoveContactToGroup(hContact, dwGroupID, tszGroup); } SetContactBasicInfoW(hContact, SCBIFSI_LOCK_CHANGES_EVENTS, (SCBIF_ID | SCBIF_GROUP_ID | SCBIF_SERVER_FLAG | SCBIF_STATUS), dwID, dwGroupID, dwContactFlag, dwContactSeverFlags, dwTemp, nullptr, &wszNick, &szCustomPhones); if (wszNick.IsEmpty()) { // set the server-side nick wszNick = Clist_GetContactDisplayName(hContact); MraModifyContact(hContact, &dwID, &dwContactFlag, &dwGroupID, &szEmail, &wszNick, &szCustomPhones); } } MraContactCapabilitiesSet(hContact, dwFutureFlags); setByte(hContact, DBSETTING_XSTATUSID, (BYTE)dwXStatus); mraSetStringW(hContact, DBSETTING_XSTATUSNAME, wszStatusTitle); mraSetStringW(hContact, DBSETTING_XSTATUSMSG, wszStatusDesc); setDword(hContact, DBSETTING_BLOGSTATUSTIME, dwBlogStatusTime); mraWriteContactSettingBlob(hContact, DBSETTING_BLOGSTATUSID, &dwBlogStatusID.QuadPart, sizeof(DWORDLONG)); mraSetStringW(hContact, DBSETTING_BLOGSTATUS, wszBlogStatus); mraSetStringW(hContact, DBSETTING_BLOGSTATUSMUSIC, wszBlogStatusMusic); if (IsXStatusValid(dwXStatus) || wszBlogStatus.GetLength()) SetExtraIcons(hContact); if (dwTemp != ID_STATUS_OFFLINE) { // пишем клиента только если юзер не отключён, иначе не затираем старое if (!szUserAgentFormatted.IsEmpty()) { if (getByte("MirVerRaw", MRA_DEFAULT_MIRVER_RAW) == FALSE) szUserAgentFormatted = MraGetVersionStringFromFormatted(szUserAgentFormatted); } else szUserAgentFormatted = MIRVER_UNKNOWN; mraSetStringA(hContact, "MirVer", szUserAgentFormatted); } if (dwContactSeverFlags & CONTACT_INTFLAG_NOT_AUTHORIZED) if (getByte("AutoAuthRequestOnLogon", MRA_DEFAULT_AUTO_AUTH_REQ_ON_LOGON)) CallProtoService(m_szModuleName, MRA_REQ_AUTH, hContact, 0); } } } dwID++; }// end while (processing contacts) // post processing contact list { CMStringA email, phones; CMStringW wszAuthMessage, nick; if (mraGetStringW(NULL, "AuthMessage", wszAuthMessage) == FALSE) // def auth message wszAuthMessage = TranslateW(MRA_DEFAULT_AUTH_MESSAGE); for (auto &hContact : AccContacts()) { if (GetContactBasicInfoW(hContact, &dwID, nullptr, nullptr, nullptr, nullptr, &email, nullptr, nullptr) == NO_ERROR) if (dwID == -1) { if (IsEMailChatAgent(email)) {// чат: ещё раз запросим авторизацию, пометим как видимый в списке, постоянный db_unset(hContact, "CList", "Hidden"); db_unset(hContact, "CList", "NotOnList"); SetExtraIcons(hContact); MraSetContactStatus(hContact, ID_STATUS_ONLINE); CMStringW wszCustomName = Clist_GetContactDisplayName(hContact); MraAddContact(hContact, (CONTACT_FLAG_VISIBLE | CONTACT_FLAG_MULTICHAT), -1, email, wszCustomName); } else { if (db_get_b(hContact, "CList", "NotOnList", 0) == 0) { // set extra icons and upload contact SetExtraIcons(hContact); if (getByte("AutoAddContactsToServer", MRA_DEFAULT_AUTO_ADD_CONTACTS_TO_SERVER)) { //add all contacts to server GetContactBasicInfoW(hContact, nullptr, &dwGroupID, nullptr, nullptr, nullptr, nullptr, &nick, &phones); MraAddContact(hContact, (CONTACT_FLAG_VISIBLE | CONTACT_FLAG_UNICODE_NAME), dwGroupID, email, nick, &phones, &wszAuthMessage); } } } MraUpdateContactInfo(hContact); } } } setByte("GroupMode", 1); } else { // контакт лист почемуто не получили // всех в offline и id в нестандарт for (auto &hContact : AccContacts()) { SetContactBasicInfoW(hContact, SCBIFSI_LOCK_CHANGES_EVENTS, (SCBIF_ID | SCBIF_GROUP_ID | SCBIF_SERVER_FLAG | SCBIF_STATUS), -1, -2, 0, 0, ID_STATUS_OFFLINE, nullptr, nullptr, nullptr); // request user info from server MraUpdateContactInfo(hContact); } if (dwTemp == GET_CONTACTS_ERROR) // найденный контакт-лист некорректен ShowFormattedErrorMessage(L"MRIM_CS_CONTACT_LIST2: bad contact list", NO_ERROR); else if (dwTemp == GET_CONTACTS_INTERR) // произошла внутренняя ошибка ShowFormattedErrorMessage(L"MRIM_CS_CONTACT_LIST2: internal server error", NO_ERROR); else { wchar_t szBuff[1024]; mir_snwprintf(szBuff, TranslateT("MRIM_CS_CONTACT_LIST2: unknown server error, code: %lu"), dwTemp); MraPopupShowFromAgentW(MRA_POPUP_TYPE_DEBUG, szBuff); } } return true; } bool CMraProto::CmdProxy(BinBuffer &buf) { DWORD dwIDRequest, dwAckType; CMStringA szAddresses, szEmail, szString; MRA_GUID mguidSessionID; buf >> szEmail >> dwIDRequest >> dwAckType >> szString >> szAddresses >> mguidSessionID; if (dwAckType == MRIM_PROXY_TYPE_FILES) { // файлы, on file recv // set proxy info to file transfer context if (!MraMrimProxySetData(MraFilesQueueItemProxyByID(hFilesQueueHandle, dwIDRequest), szEmail, dwIDRequest, dwAckType, szString, szAddresses, &mguidSessionID)) MraFilesQueueStartMrimProxy(hFilesQueueHandle, dwIDRequest); else { // empty/invalid session MraProxyAck(PROXY_STATUS_ERROR, szEmail, dwIDRequest, dwAckType, szString, szAddresses, mguidSessionID); _CrtDbgBreak(); } } return true; } bool CMraProto::CmdProxyAck(BinBuffer &buf) { DWORD dwIDRequest, dwTemp, dwAckType; HANDLE hMraMrimProxyData; CMStringA szAddresses, szEmail, szString; MRA_GUID mguidSessionID; buf >> dwTemp >> szEmail >> dwIDRequest >> dwAckType >> szString >> szAddresses >> mguidSessionID; if (dwAckType == MRIM_PROXY_TYPE_FILES) { // on file send if ((hMraMrimProxyData = MraFilesQueueItemProxyByID(hFilesQueueHandle, dwIDRequest))) { switch (dwTemp) { case PROXY_STATUS_DECLINE: MraFilesQueueCancel(hFilesQueueHandle, dwIDRequest, FALSE); break; case PROXY_STATUS_OK: // set proxy info to file transfer context if (!MraMrimProxySetData(hMraMrimProxyData, szEmail, dwIDRequest, dwAckType, szString, szAddresses, &mguidSessionID)) MraFilesQueueStartMrimProxy(hFilesQueueHandle, dwIDRequest); break; case PROXY_STATUS_ERROR: ShowFormattedErrorMessage(L"Proxy File transfer: error", NO_ERROR); MraFilesQueueCancel(hFilesQueueHandle, dwIDRequest, FALSE); break; case PROXY_STATUS_INCOMPATIBLE_VERS: ShowFormattedErrorMessage(L"Proxy File transfer: incompatible versions", NO_ERROR); MraFilesQueueCancel(hFilesQueueHandle, dwIDRequest, FALSE); break; case PROXY_STATUS_NOHARDWARE: case PROXY_STATUS_MIRROR: case PROXY_STATUS_CLOSED: default: _CrtDbgBreak(); break; } } else _CrtDbgBreak(); } return true; } bool CMraProto::CmdNewMail(BinBuffer &buf) { DWORD dwDate, dwUIDL, dwUnreadCount; CMStringA szEmail, szString; buf >> dwUnreadCount >> szEmail >> szString >> dwDate >> dwUIDL; if (dwUnreadCount > dwEmailMessagesTotal) dwEmailMessagesTotal += (dwUnreadCount - m_dwEmailMessagesUnread); DWORD dwSave = m_dwEmailMessagesUnread; m_dwEmailMessagesUnread = dwUnreadCount;// store new value if (getByte("IncrementalNewMailNotify", MRA_DEFAULT_INC_NEW_MAIL_NOTIFY) == 0 || dwSave < dwUnreadCount || dwUnreadCount == 0) MraUpdateEmailStatus(szEmail, szString, false); return true; } bool CMraProto::CmdBlogStatus(BinBuffer &buf) { DWORD dwTime, dwFlags; CMStringA szEmail, szString; CMStringW wszText; DWORDLONG dwBlogStatusID; buf >> dwFlags >> szEmail >> dwBlogStatusID >> dwTime >> wszText >> szString; if (MCONTACT hContact = MraHContactFromEmail(szEmail, FALSE, TRUE, nullptr)) { if (dwFlags & MRIM_BLOG_STATUS_MUSIC) mraSetStringW(hContact, DBSETTING_BLOGSTATUSMUSIC, wszText); else { setDword(hContact, DBSETTING_BLOGSTATUSTIME, dwTime); mraWriteContactSettingBlob(hContact, DBSETTING_BLOGSTATUSID, &dwBlogStatusID, sizeof(DWORDLONG)); mraSetStringW(hContact, DBSETTING_BLOGSTATUS, wszText); } SetExtraIcons(hContact); } return true; } bool CMraProto::MraCommandDispatcher(mrim_packet_header_t *pmaHeader) { WCHAR szBuff[4096] = { 0 }; DWORD dwTemp, dwAckType; size_t dwSize; MCONTACT hContact = NULL; LPBYTE pByte; debugLogA("Received packet %x\n", pmaHeader->msg); BinBuffer buf((LPBYTE)pmaHeader + sizeof(mrim_packet_header_t), pmaHeader->dlen); switch (pmaHeader->msg) { case MRIM_CS_HELLO_ACK: return CmdHelloAck(buf); case MRIM_CS_LOGIN_ACK: return CmdLoginAck(); case MRIM_CS_LOGIN_REJ: return CmdLoginRejected(buf); case MRIM_CS_MESSAGE_ACK: return CmdMessageAck(buf); case MRIM_CS_MESSAGE_STATUS: return CmdMessageStatus(pmaHeader->seq, buf); case MRIM_CS_USER_INFO: return CmdUserInfo(buf); case MRIM_CS_OFFLINE_MESSAGE_ACK: return CmdOfflineMessageAck(buf); case MRIM_CS_AUTHORIZE_ACK: return CmdAuthAck(buf); case MRIM_CS_MPOP_SESSION: return CmdPopSession(buf); case MRIM_CS_FILE_TRANSFER: return CmdFileTransfer(buf); case MRIM_CS_FILE_TRANSFER_ACK: return CmdFileTransferAck(buf); case MRIM_CS_USER_STATUS: return CmdUserStatus(buf); case MRIM_CS_ADD_CONTACT_ACK: case MRIM_CS_MODIFY_CONTACT_ACK: return CmdContactAck(pmaHeader->msg, pmaHeader->seq, buf); case MRIM_CS_ANKETA_INFO: return CmdAnketaInfo(pmaHeader->seq, buf); case MRIM_CS_GAME: return CmdGame(buf); case MRIM_CS_CONTACT_LIST2: return CmdClist2(buf); case MRIM_CS_PROXY: return CmdProxy(buf); case MRIM_CS_PROXY_ACK: return CmdProxyAck(buf); case MRIM_CS_NEW_MAIL: return CmdNewMail(buf); case MRIM_CS_USER_BLOG_STATUS: return CmdBlogStatus(buf); case MRIM_CS_CONNECTION_PARAMS:// Изменение параметров соединения buf >> m_dwPingPeriod; m_dwNextPingSendTickTime = 0; // force send ping MraSendCMD(MRIM_CS_PING, nullptr, 0); break; case MRIM_CS_LOGOUT:// Пользователь отключен из-за параллельного входа с его логином. buf >> dwTemp; if (dwTemp == LOGOUT_NO_RELOGIN_FLAG) ShowFormattedErrorMessage(L"Another user connected with your login", NO_ERROR); return false; case MRIM_CS_MAILBOX_STATUS: buf >> dwTemp; if (dwTemp > dwEmailMessagesTotal) dwEmailMessagesTotal += (dwTemp - m_dwEmailMessagesUnread); dwAckType = m_dwEmailMessagesUnread;// save old value m_dwEmailMessagesUnread = dwTemp;// store new value if (getByte("IncrementalNewMailNotify", MRA_DEFAULT_INC_NEW_MAIL_NOTIFY) == 0 || dwAckType < dwTemp || dwTemp == 0) MraUpdateEmailStatus("", "", false); break; case MRIM_CS_SMS_ACK: buf >> dwTemp; if (MraSendQueueFind(hSendQueueHandle, pmaHeader->seq, nullptr, &hContact, &dwAckType, &pByte, &dwSize) == NO_ERROR) { /* pByte point to phone number ansi string. */ /* dwAckType = ICQACKTYPE_SMS */ CMStringA szEmail; if (mraGetStringA(NULL, "e-mail", szEmail)) { mir_snprintf((LPSTR)szBuff, sizeof(szBuff), "Mail.ruYesMail.ru, Russia%s-1-1955988055-%s%s0\r\n", szEmail.c_str(), (LPSTR)pByte, (LPSTR)pByte); ProtoBroadcastAck(NULL, ICQACKTYPE_SMS, ACKRESULT_SENTREQUEST, (HANDLE)pmaHeader->seq, (LPARAM)szBuff); } mir_free(pByte); MraSendQueueFree(hSendQueueHandle, pmaHeader->seq); } else MraPopupShowFromAgentW(MRA_POPUP_TYPE_DEBUG, TranslateT("MRIM_CS_SMS_ACK: not found in queue")); break; case MRIM_CS_PROXY_HELLO: _CrtDbgBreak(); break; case MRIM_CS_PROXY_HELLO_ACK: _CrtDbgBreak(); break; case MRIM_CS_UNKNOWN: case MRIM_CS_UNKNOWN2: case MRIM_CS_USER_GEO: case MRIM_CS_SERVER_SETTINGS: break; default: _CrtDbgBreak(); break; } return true; } // Сообщение DWORD CMraProto::MraRecvCommand_Message(DWORD dwTime, DWORD dwFlags, CMStringA &plpsFrom, CMStringA &plpsText, CMStringA &plpsRFTText, CMStringA &plpsMultiChatData) { DWORD dwBackColour; CMStringA lpszMessageExt; CMStringW wszMessage; PROTORECVEVENT pre = { 0 }; pre.timestamp = dwTime; // check flags and datas if ((dwFlags & MESSAGE_FLAG_RTF) && plpsRFTText.IsEmpty()) dwFlags &= ~MESSAGE_FLAG_RTF; if ((dwFlags & MESSAGE_FLAG_MULTICHAT) && plpsMultiChatData.IsEmpty()) dwFlags &= ~MESSAGE_FLAG_MULTICHAT; // pre processing - extracting/decoding if (dwFlags & MESSAGE_FLAG_AUTHORIZE) { // extract auth message из обычного текста size_t dwAuthDataSize; LPBYTE lpbAuthData = (LPBYTE)mir_base64_decode(plpsText, &dwAuthDataSize); if (lpbAuthData) { BinBuffer buf(lpbAuthData, dwAuthDataSize); DWORD dwAuthPartsCount; CMStringA lpsAuthFrom; buf >> dwAuthPartsCount >> lpsAuthFrom; if (dwFlags & MESSAGE_FLAG_v1p16 && (dwFlags & MESSAGE_FLAG_CP1251) == 0) { // unicode text CMStringW lpsAuthMessageW; buf >> lpsAuthMessageW; wszMessage = lpsAuthMessageW; } else { // преобразуем в юникод текст только если он в АНСИ и если это не Флэш мультик и будильник тоже не нуждается в этом CMStringA lpsAuthMessage; buf >> lpsAuthMessage; wszMessage = ptrW(mir_a2u_cp(lpsAuthMessage, MRA_CODE_PAGE)); } mir_free(lpbAuthData); } } else { // unicode text if ((dwFlags & (MESSAGE_FLAG_ALARM | MESSAGE_FLAG_FLASH | MESSAGE_FLAG_v1p16)) && (dwFlags & MESSAGE_FLAG_CP1251) == 0) { plpsText.AppendChar(0); // compensate difference between ASCIIZ & WCHARZ wszMessage = (WCHAR*)plpsText.GetString(); } else wszMessage = plpsText; if (dwFlags & (MESSAGE_FLAG_CONTACT | MESSAGE_FLAG_NOTIFY | MESSAGE_FLAG_SMS | MESSAGE_SMS_DELIVERY_REPORT | MESSAGE_FLAG_ALARM)) ; // do nothing; there's no extra part in a message else { if ((dwFlags & MESSAGE_FLAG_RTF) && !plpsRFTText.IsEmpty()) { //MESSAGE_FLAG_FLASH there size_t dwRFTBuffSize = ((plpsRFTText.GetLength() * 16) + 8192); mir_ptr lpbRTFData((LPBYTE)mir_calloc(dwRFTBuffSize)); if (lpbRTFData) { size_t dwCompressedSize; mir_ptr lpbCompressed((LPBYTE)mir_base64_decode(plpsRFTText, &dwCompressedSize)); DWORD dwRTFDataSize = (DWORD)dwRFTBuffSize; if (uncompress(lpbRTFData, &dwRTFDataSize, lpbCompressed, dwCompressedSize) == Z_OK) { BinBuffer buf(lpbRTFData, dwRTFDataSize); CMStringA lpsRTFString, lpsBackColour, szString; DWORD dwRTFPartsCount; // количество частей в некоторых случаях больше 2, тогда нужно игнорировать первый текст, тк там сообщения об ущербности buf >> dwRTFPartsCount >> lpsRTFString >> dwBackColour; if (dwFlags & MESSAGE_FLAG_FLASH) { if (dwRTFPartsCount == 4) { buf >> szString; dwRTFPartsCount--; } if (dwRTFPartsCount == 3) { // ansi text only buf >> szString; wszMessage = ptrW(mir_a2u_cp(szString, MRA_CODE_PAGE)); } else _CrtDbgBreak(); } else { // RTF text if (dwRTFPartsCount > 2) { buf >> szString; _CrtDbgBreak(); } lpszMessageExt = lpsRTFString; } } else _CrtDbgBreak(); } } } } debugLogA("Processing message: %08X, from '%s', text '%S'\n", dwFlags, plpsFrom.c_str(), wszMessage.c_str()); // processing if (dwFlags & (MESSAGE_FLAG_SMS | MESSAGE_SMS_DELIVERY_REPORT)) { // SMS INTERNET_TIME itTime; InternetTimeGetCurrentTime(&itTime); CMStringA szTime = InternetTimeGetString(&itTime); CMStringA szPhone = CopyNumber(plpsFrom), szEmail; if (!mraGetStringA(NULL, "e-mail", szEmail)) return 0; CMStringW wszMessageXMLEncoded = EncodeXML(wszMessage); ptrA lpszMessageUTF(mir_utf8encodeW(wszMessageXMLEncoded)); CMStringA szText; if (dwFlags & MESSAGE_SMS_DELIVERY_REPORT) { szText.Format("%s-1-1955988055-%s%sNo%s015%s", szEmail.c_str(), szPhone.c_str(), szPhone.c_str(), szTime.c_str(), lpszMessageUTF); ProtoBroadcastAck(NULL, ICQACKTYPE_SMS, ACKRESULT_FAILED, nullptr, (LPARAM)szText.GetString()); } else { // new sms szText.Format("Mail.ru%s%sMail.ru%s", szEmail.c_str(), szPhone.c_str(), lpszMessageUTF, szTime.c_str()); ProtoBroadcastAck(NULL, ICQACKTYPE_SMS, ACKRESULT_SUCCESS, nullptr, (LPARAM)szText.GetString()); } } else { BOOL bAdded; MCONTACT hContact = MraHContactFromEmail(plpsFrom, TRUE, TRUE, &bAdded); if (bAdded) MraUpdateContactInfo(hContact); // user typing if (dwFlags & MESSAGE_FLAG_NOTIFY) CallService(MS_PROTO_CONTACTISTYPING, hContact, MAILRU_CONTACTISTYPING_TIMEOUT); else { // text/contact/auth // typing OFF CallService(MS_PROTO_CONTACTISTYPING, hContact, PROTOTYPE_CONTACTTYPING_OFF); if (dwFlags & MESSAGE_FLAG_MULTICHAT) { DWORD dwMultiChatEventType; CMStringA lpsEMailInMultiChat, szString; CMStringW lpsMultichatName; BinBuffer buf((PBYTE)plpsMultiChatData.GetString(), plpsMultiChatData.GetLength()); buf >> dwMultiChatEventType >> lpsMultichatName >> lpsEMailInMultiChat; switch (dwMultiChatEventType) { case MULTICHAT_MESSAGE: MraChatSessionMessageAdd(hContact, lpsEMailInMultiChat, wszMessage, dwTime);// LPS sender break; case MULTICHAT_ADD_MEMBERS: MraChatSessionMembersAdd(hContact, lpsEMailInMultiChat, dwTime);// LPS sender buf >> szString;// CLPS members MraChatSessionSetIviter(hContact, lpsEMailInMultiChat); case MULTICHAT_MEMBERS: { DWORD dwMultiChatMembersCount; BinBuffer binBuf((PBYTE)lpsEMailInMultiChat.GetString(), lpsEMailInMultiChat.GetLength()); binBuf >> dwMultiChatMembersCount;// count for (unsigned i = 0; i < dwMultiChatMembersCount && !binBuf.eof(); i++) { binBuf >> szString; MraChatSessionJoinUser(hContact, szString, ((dwMultiChatEventType == MULTICHAT_MEMBERS) ? 0 : dwTime)); } if (dwMultiChatEventType == MULTICHAT_MEMBERS) { binBuf >> szString; // [ LPS owner ] MraChatSessionSetOwner(hContact, szString); } } break; case MULTICHAT_ATTACHED: MraChatSessionJoinUser(hContact, lpsEMailInMultiChat, dwTime);// LPS member break; case MULTICHAT_DETACHED: MraChatSessionLeftUser(hContact, lpsEMailInMultiChat, dwTime);// LPS member break; case MULTICHAT_INVITE: MraChatSessionInvite(hContact, lpsEMailInMultiChat, dwTime);// LPS sender MraAddContact(hContact, (CONTACT_FLAG_VISIBLE | CONTACT_FLAG_MULTICHAT | CONTACT_FLAG_UNICODE_NAME), -1, plpsFrom, lpsMultichatName); break; default: _CrtDbgBreak(); break; } } else if (dwFlags & MESSAGE_FLAG_AUTHORIZE) { // auth request BOOL bAutoGrantAuth = FALSE; if (IsEMailChatAgent(plpsFrom)) bAutoGrantAuth = FALSE; else { // temporary contact if (db_get_b(hContact, "CList", "NotOnList", 0)) { if (getByte("AutoAuthGrandNewUsers", MRA_DEFAULT_AUTO_AUTH_GRAND_NEW_USERS)) bAutoGrantAuth = TRUE; } else if (getByte("AutoAuthGrandUsersInCList", MRA_DEFAULT_AUTO_AUTH_GRAND_IN_CLIST)) bAutoGrantAuth = TRUE; } CMStringA szBlob = CreateBlobFromContact(hContact, wszMessage); if (bAutoGrantAuth) { // auto grant auth DBEVENTINFO dbei = {}; dbei.szModule = m_szModuleName; dbei.timestamp = _time32(nullptr); dbei.flags = DBEF_READ | DBEF_UTF; dbei.eventType = EVENTTYPE_AUTHREQUEST; dbei.pBlob = (PBYTE)szBlob.c_str(); dbei.cbBlob = szBlob.GetLength(); db_event_add(0, &dbei); MraAuthorize(plpsFrom); } else { pre.szMessage = (LPSTR)szBlob.GetString(); pre.lParam = szBlob.GetLength(); ProtoChainRecv(hContact, PSR_AUTH, 0, (LPARAM)&pre); } } else { db_unset(hContact, "CList", "Hidden"); if (dwFlags & MESSAGE_FLAG_CONTACT) { // contacts received ptrA lpbBuffer(mir_u2a_cp(wszMessage, MRA_CODE_PAGE)); pre.flags = 0; pre.szMessage = (LPSTR)lpbBuffer; pre.lParam = mir_strlen(lpbBuffer); LPSTR lpbBufferCurPos = lpbBuffer; while (TRUE) { // цикл замены ; на 0 lpbBufferCurPos = (LPSTR)MemoryFindByte((lpbBufferCurPos - (LPSTR)lpbBuffer), lpbBuffer, pre.lParam, ';'); if (!lpbBufferCurPos) break; // found (*lpbBufferCurPos) = 0; lpbBufferCurPos ++; } ProtoChainRecv(hContact, PSR_CONTACTS, 0, (LPARAM)&pre); } else if (dwFlags & MESSAGE_FLAG_ALARM) { // alarm if (m_heNudgeReceived) NotifyEventHooks(m_heNudgeReceived, hContact, NULL); else { T2Utf szMsg(TranslateW(MRA_ALARM_MESSAGE)); pre.szMessage = szMsg; ProtoChainRecvMsg(hContact, &pre); } } else { // standart message// flash animation // пишем в ANSI, всё равно RTF if ((dwFlags & MESSAGE_FLAG_RTF) && (dwFlags & MESSAGE_FLAG_FLASH) == 0 && !lpszMessageExt.IsEmpty() && getByte("RTFReceiveEnable", MRA_DEFAULT_RTF_RECEIVE_ENABLE)) { pre.flags = 0; pre.szMessage = (LPSTR)lpszMessageExt.GetString(); ProtoChainRecvMsg(hContact, &pre); } else { // some plugins can change pre.szMessage pointer and we failed to free it ptrA lpszMessageUTF(mir_utf8encodeW(wszMessage)); pre.szMessage = lpszMessageUTF; ProtoChainRecvMsg(hContact, &pre); } if (dwFlags & MESSAGE_FLAG_SYSTEM) MraPopupShowW(hContact, MRA_POPUP_TYPE_INFORMATION, TranslateT("Mail.ru System notify"), (LPWSTR)pre.szMessage); } } } } return NO_ERROR; } DWORD GetMraXStatusIDFromMraUriStatus(const char *szStatusUri) { if (szStatusUri) for (DWORD i = 0; lpcszStatusUri[i]; i++) if (!_stricmp(lpcszStatusUri[i], szStatusUri)) return i; return MRA_XSTATUS_UNKNOWN; } DWORD GetMraStatusFromMiradaStatus(DWORD dwMirandaStatus, DWORD dwXStatusMir, DWORD *pdwXStatusMra) { if (IsXStatusValid(dwXStatusMir)) { if (pdwXStatusMra) *pdwXStatusMra = (dwXStatusMir + MRA_XSTATUS_INDEX_OFFSET - 1); return STATUS_USER_DEFINED; } switch (dwMirandaStatus) { case ID_STATUS_OFFLINE: if (pdwXStatusMra) *pdwXStatusMra = MRA_XSTATUS_OFFLINE; return STATUS_OFFLINE; case ID_STATUS_ONLINE: if (pdwXStatusMra) *pdwXStatusMra = MRA_XSTATUS_ONLINE; return STATUS_ONLINE; case ID_STATUS_AWAY: case ID_STATUS_NA: case ID_STATUS_ONTHEPHONE: case ID_STATUS_OUTTOLUNCH: if (pdwXStatusMra) *pdwXStatusMra = MRA_XSTATUS_AWAY; return STATUS_AWAY; case ID_STATUS_DND: case ID_STATUS_OCCUPIED: if (pdwXStatusMra) *pdwXStatusMra = MRA_XSTATUS_DND; return STATUS_USER_DEFINED; case ID_STATUS_FREECHAT: if (pdwXStatusMra) *pdwXStatusMra = MRA_XSTATUS_CHAT; return STATUS_USER_DEFINED; case ID_STATUS_INVISIBLE: if (pdwXStatusMra) *pdwXStatusMra = MRA_XSTATUS_INVISIBLE; return (STATUS_ONLINE | STATUS_FLAG_INVISIBLE); } if (pdwXStatusMra) *pdwXStatusMra = MRA_XSTATUS_OFFLINE; return STATUS_OFFLINE; } DWORD GetMirandaStatusFromMraStatus(DWORD dwMraStatus, DWORD dwXStatusMra, DWORD *pdwXStatusMir) { if (pdwXStatusMir) *pdwXStatusMir = 0; switch (dwMraStatus) { case STATUS_OFFLINE: return ID_STATUS_OFFLINE; case STATUS_ONLINE: return ID_STATUS_ONLINE; case STATUS_AWAY: return ID_STATUS_AWAY; case STATUS_UNDETERMINATED: return ID_STATUS_OFFLINE; case STATUS_USER_DEFINED: switch (dwXStatusMra) { case MRA_XSTATUS_DND: return ID_STATUS_DND; case MRA_XSTATUS_CHAT: return ID_STATUS_FREECHAT; case MRA_XSTATUS_MOBILE: return ID_STATUS_ONTHEPHONE; case MRA_XSTATUS_UNKNOWN: if (pdwXStatusMir) *pdwXStatusMir = MRA_MIR_XSTATUS_UNKNOWN; return ID_STATUS_ONLINE; } if (pdwXStatusMir) *pdwXStatusMir = dwXStatusMra - MRA_XSTATUS_INDEX_OFFSET + 1; return ID_STATUS_ONLINE; default: if (dwMraStatus & STATUS_FLAG_INVISIBLE) return ID_STATUS_INVISIBLE; } return ID_STATUS_OFFLINE; } ///////////////////////////////////////////////////////////////////////////////////////////////// DWORD BinBuffer::getDword() { if (m_len >= sizeof(DWORD)) { DWORD ret = *(DWORD*)m_data; m_data += sizeof(DWORD); m_len -= sizeof(DWORD); return ret; } return 0; } DWORDLONG BinBuffer::getInt64() { if (m_len >= sizeof(DWORDLONG)) { DWORDLONG ret = *(DWORDLONG*)m_data; m_data += sizeof(DWORDLONG); m_len -= sizeof(DWORDLONG); return ret; } return 0; } MRA_GUID BinBuffer::getGuid() { MRA_GUID ret; if (m_len >= sizeof(MRA_GUID)) { ret = *(MRA_GUID*)m_data; m_data += sizeof(MRA_GUID); m_len -= sizeof(MRA_GUID); return ret; } else memset(&ret, 0, sizeof(ret)); return ret; } void BinBuffer::getStringA(CMStringA& ret) { if (m_len >= sizeof(DWORD)) { DWORD dwLen = *(DWORD*)m_data; m_data += sizeof(DWORD); m_len -= sizeof(DWORD); if (m_len >= dwLen) { ret = CMStringA((LPSTR)m_data, dwLen); m_data += dwLen; m_len -= dwLen; return; } } ret.Empty(); } void BinBuffer::getStringW(CMStringW& ret) { if (m_len >= sizeof(DWORD)) { DWORD dwLen = *(DWORD*)m_data; m_data += sizeof(DWORD); m_len -= sizeof(DWORD); if (m_len >= dwLen) { ret = CMStringW((LPWSTR)m_data, dwLen / 2); m_data += dwLen; m_len -= dwLen; return; } } ret.Empty(); }