From de6eb3e4bc30eff928dc932c03812ede3077926a Mon Sep 17 00:00:00 2001 From: Kirill Volinsky Date: Sat, 13 Oct 2012 08:54:34 +0000 Subject: MRA: folders restructurization git-svn-id: http://svn.miranda-ng.org/main/trunk@1900 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- protocols/MRA/src/Mra.cpp | 157 + protocols/MRA/src/Mra.h | 265 ++ protocols/MRA/src/MraAdvancedSearch.cpp | 361 ++ protocols/MRA/src/MraAntiSpam.cpp | 444 ++ protocols/MRA/src/MraAntiSpam.h | 16 + protocols/MRA/src/MraAvatars.cpp | 755 ++++ protocols/MRA/src/MraAvatars.h | 16 + protocols/MRA/src/MraChat.cpp | 285 ++ protocols/MRA/src/MraChat.h | 9 + protocols/MRA/src/MraConstans.h | 281 ++ protocols/MRA/src/MraFilesQueue.cpp | 1203 ++++++ protocols/MRA/src/MraFilesQueue.h | 23 + protocols/MRA/src/MraFilesQueue_mod.cpp | 1298 ++++++ protocols/MRA/src/MraIcons.cpp | 208 + protocols/MRA/src/MraIcons.h | 13 + protocols/MRA/src/MraMPop.cpp | 181 + protocols/MRA/src/MraMPop.h | 13 + protocols/MRA/src/MraMRIMProxy.cpp | 211 + protocols/MRA/src/MraMRIMProxy.h | 15 + protocols/MRA/src/MraOfflineMsg.cpp | 432 ++ protocols/MRA/src/MraOfflineMsg.h | 19 + protocols/MRA/src/MraPlaces.h | 5959 ++++++++++++++++++++++++++ protocols/MRA/src/MraPopUp.cpp | 309 ++ protocols/MRA/src/MraPopUp.h | 22 + protocols/MRA/src/MraProto.cpp | 739 ++++ protocols/MRA/src/MraProto.h | 377 ++ protocols/MRA/src/MraRTFMsg.cpp | 259 ++ protocols/MRA/src/MraRTFMsg.h | 11 + protocols/MRA/src/MraSelectEMail.cpp | 158 + protocols/MRA/src/MraSelectEMail.h | 19 + protocols/MRA/src/MraSendCommand.cpp | 688 +++ protocols/MRA/src/MraSendCommand.h | 10 + protocols/MRA/src/MraSendQueue.cpp | 168 + protocols/MRA/src/MraSendQueue.h | 23 + protocols/MRA/src/Mra_functions.cpp | 1834 ++++++++ protocols/MRA/src/Mra_options.cpp | 259 ++ protocols/MRA/src/Mra_proto.cpp | 2224 ++++++++++ protocols/MRA/src/Mra_svcs.cpp | 1117 +++++ protocols/MRA/src/Sdk/Base64.h | 380 ++ protocols/MRA/src/Sdk/BuffToLowerCase.h | 98 + protocols/MRA/src/Sdk/DebugFunctions.h | 148 + protocols/MRA/src/Sdk/FIFOMT.h | 117 + protocols/MRA/src/Sdk/InterlockedFunctions.h | 156 + protocols/MRA/src/Sdk/InternetTime.h | 473 ++ protocols/MRA/src/Sdk/ListMT.h | 360 ++ protocols/MRA/src/Sdk/MemoryCompare.h | 101 + protocols/MRA/src/Sdk/MemoryFind.h | 80 + protocols/MRA/src/Sdk/MemoryFindByte.h | 97 + protocols/MRA/src/Sdk/MemoryReplace.h | 150 + protocols/MRA/src/Sdk/RC4.h | 103 + protocols/MRA/src/Sdk/SHA1.h | 596 +++ protocols/MRA/src/Sdk/SocketFunctions.h | 485 +++ protocols/MRA/src/Sdk/StrHexToNum.h | 634 +++ protocols/MRA/src/Sdk/StrToNum.h | 447 ++ protocols/MRA/src/Sdk/SystemHeaders.h | 65 + protocols/MRA/src/Sdk/timefuncs.h | 131 + protocols/MRA/src/Sdk/zconf.h | 428 ++ protocols/MRA/src/Sdk/zlib.h | 1357 ++++++ protocols/MRA/src/proto.h | 611 +++ protocols/MRA/src/resource.h | 142 + protocols/MRA/src/version.h | 6 + 61 files changed, 27546 insertions(+) create mode 100644 protocols/MRA/src/Mra.cpp create mode 100644 protocols/MRA/src/Mra.h create mode 100644 protocols/MRA/src/MraAdvancedSearch.cpp create mode 100644 protocols/MRA/src/MraAntiSpam.cpp create mode 100644 protocols/MRA/src/MraAntiSpam.h create mode 100644 protocols/MRA/src/MraAvatars.cpp create mode 100644 protocols/MRA/src/MraAvatars.h create mode 100644 protocols/MRA/src/MraChat.cpp create mode 100644 protocols/MRA/src/MraChat.h create mode 100644 protocols/MRA/src/MraConstans.h create mode 100644 protocols/MRA/src/MraFilesQueue.cpp create mode 100644 protocols/MRA/src/MraFilesQueue.h create mode 100644 protocols/MRA/src/MraFilesQueue_mod.cpp create mode 100644 protocols/MRA/src/MraIcons.cpp create mode 100644 protocols/MRA/src/MraIcons.h create mode 100644 protocols/MRA/src/MraMPop.cpp create mode 100644 protocols/MRA/src/MraMPop.h create mode 100644 protocols/MRA/src/MraMRIMProxy.cpp create mode 100644 protocols/MRA/src/MraMRIMProxy.h create mode 100644 protocols/MRA/src/MraOfflineMsg.cpp create mode 100644 protocols/MRA/src/MraOfflineMsg.h create mode 100644 protocols/MRA/src/MraPlaces.h create mode 100644 protocols/MRA/src/MraPopUp.cpp create mode 100644 protocols/MRA/src/MraPopUp.h create mode 100644 protocols/MRA/src/MraProto.cpp create mode 100644 protocols/MRA/src/MraProto.h create mode 100644 protocols/MRA/src/MraRTFMsg.cpp create mode 100644 protocols/MRA/src/MraRTFMsg.h create mode 100644 protocols/MRA/src/MraSelectEMail.cpp create mode 100644 protocols/MRA/src/MraSelectEMail.h create mode 100644 protocols/MRA/src/MraSendCommand.cpp create mode 100644 protocols/MRA/src/MraSendCommand.h create mode 100644 protocols/MRA/src/MraSendQueue.cpp create mode 100644 protocols/MRA/src/MraSendQueue.h create mode 100644 protocols/MRA/src/Mra_functions.cpp create mode 100644 protocols/MRA/src/Mra_options.cpp create mode 100644 protocols/MRA/src/Mra_proto.cpp create mode 100644 protocols/MRA/src/Mra_svcs.cpp create mode 100644 protocols/MRA/src/Sdk/Base64.h create mode 100644 protocols/MRA/src/Sdk/BuffToLowerCase.h create mode 100644 protocols/MRA/src/Sdk/DebugFunctions.h create mode 100644 protocols/MRA/src/Sdk/FIFOMT.h create mode 100644 protocols/MRA/src/Sdk/InterlockedFunctions.h create mode 100644 protocols/MRA/src/Sdk/InternetTime.h create mode 100644 protocols/MRA/src/Sdk/ListMT.h create mode 100644 protocols/MRA/src/Sdk/MemoryCompare.h create mode 100644 protocols/MRA/src/Sdk/MemoryFind.h create mode 100644 protocols/MRA/src/Sdk/MemoryFindByte.h create mode 100644 protocols/MRA/src/Sdk/MemoryReplace.h create mode 100644 protocols/MRA/src/Sdk/RC4.h create mode 100644 protocols/MRA/src/Sdk/SHA1.h create mode 100644 protocols/MRA/src/Sdk/SocketFunctions.h create mode 100644 protocols/MRA/src/Sdk/StrHexToNum.h create mode 100644 protocols/MRA/src/Sdk/StrToNum.h create mode 100644 protocols/MRA/src/Sdk/SystemHeaders.h create mode 100644 protocols/MRA/src/Sdk/timefuncs.h create mode 100644 protocols/MRA/src/Sdk/zconf.h create mode 100644 protocols/MRA/src/Sdk/zlib.h create mode 100644 protocols/MRA/src/proto.h create mode 100644 protocols/MRA/src/resource.h create mode 100644 protocols/MRA/src/version.h (limited to 'protocols/MRA/src') diff --git a/protocols/MRA/src/Mra.cpp b/protocols/MRA/src/Mra.cpp new file mode 100644 index 0000000000..d96a29a242 --- /dev/null +++ b/protocols/MRA/src/Mra.cpp @@ -0,0 +1,157 @@ +#include "Mra.h" + +MRA_SETTINGS masMraSettings; +int hLangpack; + +PLUGININFOEX pluginInfoEx = { + sizeof(PLUGININFOEX), + PROTOCOL_DISPLAY_NAME_ORIGA, + __VERSION_DWORD, + "Provides support for Mail.ru agent Instant Messenger protocol.", + "Rozhuk Ivan", + "Rozhuk_I@mail.ru", + "© 2006-2011 Rozhuk Ivan", + "http://miranda-ng.org/", + UNICODE_AWARE, + // {E7C48BAB-8ACE-4CB3-8446-D4B73481F497} + { 0xe7c48bab, 0x8ace, 0x4cb3, { 0x84, 0x46, 0xd4, 0xb7, 0x34, 0x81, 0xf4, 0x97 } } +}; + +void IconsLoad(); + +int OnModulesLoaded(WPARAM wParam, LPARAM lParam); +int OnPreShutdown(WPARAM wParam, LPARAM lParam); + +BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID Reserved) +{ + switch (dwReason) { + case DLL_PROCESS_ATTACH: + bzero(&masMraSettings, sizeof(masMraSettings)); + masMraSettings.hInstance = hInstance; + masMraSettings.hHeap = HeapCreate(0, 0, 0); + DisableThreadLibraryCalls(hInstance); + break; + + case DLL_PROCESS_DETACH: + HeapDestroy(masMraSettings.hHeap); + masMraSettings.hHeap = NULL; + } + + return TRUE; +} + +extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = {MIID_PROTOCOL, MIID_LAST}; + +extern "C" MRA_API PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion) +{ + return &pluginInfoEx; +} + +/////////////////////////////////////////////////////////////////////////////// +// Protocol instances + +static int sttCompareProtocols(const CMraProto *p1, const CMraProto *p2) +{ + return lstrcmp(p1->m_tszUserName, p2->m_tszUserName); +} + +LIST g_Instances(1, sttCompareProtocols); + +/////////////////////////////////////////////////////////////////////////////// + +static CMraProto* mraProtoInit(const char* pszProtoName, const TCHAR* tszUserName) +{ + CMraProto *ppro = new CMraProto( pszProtoName, tszUserName ); + g_Instances.insert(ppro); + return ppro; +} + +static int mraProtoUninit(CMraProto *ppro) +{ + g_Instances.remove(ppro); + delete ppro; + return 0; +} + +extern "C" MRA_API int Load(void) +{ + mir_getLP(&pluginInfoEx); + + IconsLoad(); + + size_t dwBuffLen; + WCHAR szBuff[MAX_FILEPATH]; + LPSTR lpszFullFileName = (LPSTR)szBuff; + LPWSTR lpwszFileName; + + // load libs + if (GetModuleFileName(NULL, szBuff, MAX_FILEPATH)) { + masMraSettings.dwMirWorkDirPathLen = GetFullPathName(szBuff, MAX_FILEPATH, masMraSettings.szMirWorkDirPath, &lpwszFileName); + if (masMraSettings.dwMirWorkDirPathLen) { + masMraSettings.dwMirWorkDirPathLen -= lstrlenW(lpwszFileName); + masMraSettings.szMirWorkDirPath[masMraSettings.dwMirWorkDirPathLen] = 0; + + // load xstatus icons lib + DWORD dwErrorCode = FindFile(masMraSettings.szMirWorkDirPath, (DWORD)masMraSettings.dwMirWorkDirPathLen, L"xstatus_MRA.dll", -1, szBuff, SIZEOF(szBuff), (DWORD*)&dwBuffLen); + if (dwErrorCode == NO_ERROR) { + masMraSettings.hDLLXStatusIcons = LoadLibraryEx(szBuff, NULL, 0); + if (masMraSettings.hDLLXStatusIcons) { + if ((dwBuffLen = LoadStringW(masMraSettings.hDLLXStatusIcons, IDS_IDENTIFY, szBuff, MAX_FILEPATH)) == 0 || _wcsnicmp(L"# Custom Status Icons #", szBuff, 23)) { + FreeLibrary(masMraSettings.hDLLXStatusIcons); + masMraSettings.hDLLXStatusIcons = NULL; + } + } + } + } + } + + HookEvent(ME_SYSTEM_MODULESLOADED, OnModulesLoaded); + HookEvent(ME_SYSTEM_PRESHUTDOWN, OnPreShutdown); + + PROTOCOLDESCRIPTOR pd = {0}; + pd.cbSize = sizeof(pd); + pd.szName = "MRA"; + pd.type = PROTOTYPE_PROTOCOL; + pd.fnInit = (pfnInitProto)mraProtoInit; + pd.fnUninit = (pfnUninitProto)mraProtoUninit; + CallService(MS_PROTO_REGISTERMODULE, 0, (LPARAM)&pd); + + DebugPrintCRLFW(L"Load - DONE"); + return 0; +} + +extern "C" MRA_API int Unload(void) +{ + if (masMraSettings.hDLLXStatusIcons) { + FreeLibrary(masMraSettings.hDLLXStatusIcons); + masMraSettings.hDLLXStatusIcons = NULL; + } + + DebugPrintCRLFW(L"Unload - DONE"); + return 0; +} + + +static int OnModulesLoaded(WPARAM wParam, LPARAM lParam) +{ + MraAntiSpamLoadBadWordsW(); + + LoadModules(); + + InterlockedExchange((volatile LONG*)&masMraSettings.dwGlobalPluginRunning, TRUE); + + DebugPrintCRLFW(L"OnModulesLoaded - DONE"); + return 0; +} + +int OnPreShutdown(WPARAM wParam, LPARAM lParam) +{ + InterlockedExchange((volatile LONG*)&masMraSettings.dwGlobalPluginRunning, FALSE); + + UnloadModules(); + + MraAntiSpamFreeBadWords(); + + DebugPrintCRLFW(L"OnPreShutdown - DONE"); + return 0; +} diff --git a/protocols/MRA/src/Mra.h b/protocols/MRA/src/Mra.h new file mode 100644 index 0000000000..7c6faac372 --- /dev/null +++ b/protocols/MRA/src/Mra.h @@ -0,0 +1,265 @@ +#if !defined(AFX_MRA_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_) +#define AFX_MRA_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_ + + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define _CRT_SECURE_NO_WARNINGS + +#pragma warning(disable:4267) + +//#define CRTDLL + +#include "resource.h" +#include "..\xstatus_MRA\src\resource.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define bzero(pvDst, count) memset(pvDst, 0, count) +#include + +#include "../../plugins/zlib/zlib.h" + +#define MIRANDA_VER 0x0A00 + +// http://miranda.svn.sourceforge.net/viewvc/miranda/trunk/miranda/include/?sortby = file +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +// LPS +typedef struct +{ + size_t dwSize; + + union { + LPSTR lpszData; + LPWSTR lpwszData; + }; +} MRA_LPS; + + +// GUID +typedef struct +{ + DWORD id[4]; +} MRA_GUID; + + + +struct MRA_ADDR_LIST_ITEM +{ + DWORD dwPort; + DWORD dwAddr; +}; + +struct MRA_ADDR_LIST +{ + DWORD dwAddrCount; + MRA_ADDR_LIST_ITEM *pmaliAddress; +}; + +#include "MraConstans.h" +#include "MraProto.h" + +// структура содержащая информацию по построению меню или расширеных иконок +struct GUI_DISPLAY_ITEM +{ + LPSTR lpszName; // имя сервиса, оно же имя в иколибе + LPWSTR lpwszDescr; // текстовое описание отображаемое юзеру + LONG defIcon; // иконка из ресурсов + ServiceFunc lpFunc; // функция вызываемая меню + HANDLE hIconHandle; +}; + +// структура содержащая информацию о сервисах/функциях +struct SERVICE_ITEM +{ + LPSTR lpszName; // имя сервиса, оно же имя в иколибе + ServiceFunc lpFunc; // функция вызываемая +}; + +extern GUI_DISPLAY_ITEM gdiMenuItems[]; +extern GUI_DISPLAY_ITEM gdiContactMenuItems[]; +extern GUI_DISPLAY_ITEM gdiExtraStatusIconsItems[]; + +#include "proto.h" +#include "MraSendCommand.h" +#include "MraMRIMProxy.h" +#include "MraSendQueue.h" +#include "MraFilesQueue.h" +#include "MraPopUp.h" +#include "MraAvatars.h" +#include "MraIcons.h" +#include "MraSelectEMail.h" +#include "MraAntiSpam.h" +#include "MraMPop.h" +#include "MraChat.h" + + +#ifdef MRA_EXPORTS + #define MRA_API __declspec(dllexport) +#else + #define MRA_API + // __declspec(dllimport) + #pragma comment(lib, "MRALib.lib") +#endif + +///////////////////////////////////////////////////////////////////////////////////////// +// plugin options + +typedef struct +{ + HANDLE hHeap; + HINSTANCE hInstance; + HMODULE hDLLXStatusIcons; + + DWORD dwGlobalPluginRunning; + BOOL bChatExist; + + size_t dwMirWorkDirPathLen; + WCHAR szMirWorkDirPath[MAX_FILEPATH]; +} MRA_SETTINGS; + + +///////////////////////////////////////////////////////////////////////////////////////// +// External variables +extern MRA_SETTINGS masMraSettings; +extern LIST g_Instances; + +INT_PTR LoadModules(); +void UnloadModules(); +void InitExtraIcons(); + +DWORD MraGetSelfVersionString(LPSTR lpszSelfVersion, size_t dwSelfVersionSize, size_t *pdwSelfVersionSizeRet); + +#define GetContactNameA(Contact) (LPSTR)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)Contact, 0) +#define GetContactNameW(Contact) (LPWSTR)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)Contact, GCDNF_UNICODE) + +#define GetStatusModeDescriptionA(Status) (LPSTR)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, (WPARAM)Status, 0) +#define GetStatusModeDescriptionW(Status) (LPWSTR)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, (WPARAM)Status, GSMDF_UNICODE) + +#define SetBit(bytes, bitpos) bytes |= (1<mraGetByte(NULL, "AdvancedSearchRemember", MRA_DEFAULT_SEARCH_REMEMBER)) { + SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_GENDER, CB_SETCURSEL, ppro->mraGetWord(NULL, "AdvancedSearchGender", 0), 0); + SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_AGERANGE_FROM, CB_SETCURSEL, ppro->mraGetWord(NULL, "AdvancedSearchAgeFrom", 0), 0); + SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_AGERANGE_TO, CB_SETCURSEL, ppro->mraGetWord(NULL, "AdvancedSearchAgeTo", 0), 0); + SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_BIRTHDAY_MONTH, CB_SETCURSEL, ppro->mraGetWord(NULL, "AdvancedSearchBirthDayMonth", 0), 0); + SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_BIRTHDAY_DAY, CB_SETCURSEL, ppro->mraGetWord(NULL, "AdvancedSearchBirthDayDay", 0), 0); + + SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_ZODIAK, CB_SETCURSEL, ppro->mraGetWord(NULL, "AdvancedSearchZodiakID", 0), 0); + + + SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_COUNTRY, CB_SETCURSEL, ppro->mraGetWord(NULL, "AdvancedSearchCountryID", 0), 0); + SendMessageW(hWndDlg, WM_COMMAND, (WPARAM)MAKELONG(IDC_COUNTRY, CBN_SELCHANGE), (LPARAM)GetDlgItem(hWndDlg, IDC_COUNTRY)); + + SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_STATE, CB_SETCURSEL, ppro->mraGetWord(NULL, "AdvancedSearchStateID", 0), 0); + SendMessageW(hWndDlg, WM_COMMAND, (WPARAM)MAKELONG(IDC_STATE, CBN_SELCHANGE), (LPARAM)GetDlgItem(hWndDlg, IDC_STATE)); + + SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_CITY, CB_SETCURSEL, ppro->mraGetWord(NULL, "AdvancedSearchCityID", 0), 0); + + + CHECK_DLG_BUTTON(hWndDlg, IDC_ONLINEONLY, ppro->mraGetByte(NULL, "AdvancedSearchOnlineOnly", FALSE)); + CHECK_DLG_BUTTON(hWndDlg, IDC_CHK_REMEMBER, TRUE); + } + TranslateDialogDefault(hWndDlg); + } + return TRUE; + + case WM_DESTROY: + ppro->mraSetWord(NULL, "AdvancedSearchGender", SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_GENDER, CB_GETCURSEL, 0, 0)); + ppro->mraSetWord(NULL, "AdvancedSearchAgeFrom", SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_AGERANGE_FROM, CB_GETCURSEL, 0, 0)); + ppro->mraSetWord(NULL, "AdvancedSearchAgeTo", SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_AGERANGE_TO, CB_GETCURSEL, 0, 0)); + ppro->mraSetWord(NULL, "AdvancedSearchBirthDayMonth", SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_BIRTHDAY_MONTH, CB_GETCURSEL, 0, 0)); + ppro->mraSetWord(NULL, "AdvancedSearchBirthDayDay", SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_BIRTHDAY_DAY, CB_GETCURSEL, 0, 0)); + + ppro->mraSetWord(NULL, "AdvancedSearchZodiakID", SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_ZODIAK, CB_GETCURSEL, 0, 0)); + + ppro->mraSetWord(NULL, "AdvancedSearchCityID", SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_CITY, CB_GETCURSEL, 0, 0)); + ppro->mraSetWord(NULL, "AdvancedSearchStateID", SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_STATE, CB_GETCURSEL, 0, 0)); + ppro->mraSetWord(NULL, "AdvancedSearchCountryID", SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_COUNTRY, CB_GETCURSEL, 0, 0)); + + ppro->mraSetByte(NULL, "AdvancedSearchOnlineOnly", IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_ONLINEONLY)); + ppro->mraSetByte(NULL, "AdvancedSearchRemember", IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_CHK_REMEMBER)); + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDOK: + SendMessage(GetParent(hWndDlg), WM_COMMAND, MAKEWPARAM(IDOK, BN_CLICKED), (LPARAM)GetDlgItem(GetParent(hWndDlg), IDOK)); + break; + case IDC_AGERANGE_FROM: + case IDC_AGERANGE_TO: + if (HIWORD(wParam) == CBN_SELCHANGE) + { + if (LOWORD(wParam) == IDC_AGERANGE_FROM) + { + DWORD dwAgeFrom, dwAgeTo; + + dwAgeFrom = GET_CURRENT_COMBO_DATA(hWndDlg, IDC_AGERANGE_FROM); + dwAgeTo = GET_CURRENT_COMBO_DATA(hWndDlg, IDC_AGERANGE_TO); + if (dwAgeFrom == 0) dwAgeFrom++; + InitComboBoxNumders(GetDlgItem(hWndDlg, IDC_AGERANGE_TO), dwAgeFrom, 100); + SendMessage(GetDlgItem(hWndDlg, IDC_AGERANGE_TO), CB_SETCURSEL, ((dwAgeTo-dwAgeFrom)+1), 0); + } + SendMessage(GetDlgItem(hWndDlg, IDC_BIRTHDAY_YEAR), CB_SETCURSEL, 0, 0); + } + break; + case IDC_BIRTHDAY_DAY: + case IDC_BIRTHDAY_MONTH: + case IDC_BIRTHDAY_YEAR: + if (HIWORD(wParam) == CBN_SELCHANGE) + { + DWORD dwAge; + SYSTEMTIME stTime = {0}; + + stTime.wYear = (WORD)GET_CURRENT_COMBO_DATA(hWndDlg, IDC_BIRTHDAY_YEAR); + stTime.wMonth = (WORD)GET_CURRENT_COMBO_DATA(hWndDlg, IDC_BIRTHDAY_MONTH); + stTime.wDay = (WORD)GET_CURRENT_COMBO_DATA(hWndDlg, IDC_BIRTHDAY_DAY); + + dwAge = GetYears(&stTime); + SendMessage(GetDlgItem(hWndDlg, IDC_AGERANGE_FROM), CB_SETCURSEL, dwAge, 0); + SendMessage(GetDlgItem(hWndDlg, IDC_AGERANGE_TO), CB_SETCURSEL, dwAge, 0); + SendMessage(GetDlgItem(hWndDlg, IDC_ZODIAK), CB_SETCURSEL, 0, 0); + } + break; + case IDC_ZODIAK: + if (HIWORD(wParam) == CBN_SELCHANGE) + { + SendMessage(GetDlgItem(hWndDlg, IDC_BIRTHDAY_DAY), CB_SETCURSEL, 0, 0); + SendMessage(GetDlgItem(hWndDlg, IDC_BIRTHDAY_MONTH), CB_SETCURSEL, 0, 0); + //SendMessage(GetDlgItem(hWndDlg, IDC_BIRTHDAY_YEAR), CB_SETCURSEL, 0, 0); + } + break; + case IDC_COUNTRY: + if (HIWORD(wParam) == CBN_SELCHANGE) + { + HWND hWndCombo; + DWORD dwItem, dwCountryID; + + dwCountryID = GET_CURRENT_COMBO_DATA(hWndDlg, IDC_COUNTRY); + hWndCombo = GetDlgItem(hWndDlg, IDC_STATE); + SendMessage(hWndCombo, CB_RESETCONTENT, 0, 0); + ResetComboBox(GetDlgItem(hWndDlg, IDC_CITY)); + dwItem = SendMessage(hWndCombo, CB_ADDSTRING, 0, (LPARAM)L""); + SendMessage(hWndCombo, CB_SETITEMDATA, dwItem, 0); + SendMessage(hWndCombo, CB_SETCURSEL, dwItem, 0); + + for (size_t i = 0;mrapPlaces[i].lpszData;i++) + { + if (mrapPlaces[i].dwCountryID == dwCountryID && mrapPlaces[i].dwCityID && mrapPlaces[i].dwPlaceID == 0) + { + dwItem = SendMessage(hWndCombo, CB_ADDSTRING, 0, (LPARAM)mrapPlaces[i].lpszData); + SendMessage(hWndCombo, CB_SETITEMDATA, dwItem, mrapPlaces[i].dwCityID); + } + } + } + break; + case IDC_STATE: + if (HIWORD(wParam) == CBN_SELCHANGE) + { + HWND hWndCombo; + DWORD dwItem, dwCountryID, dwStateID; + + dwCountryID = GET_CURRENT_COMBO_DATA(hWndDlg, IDC_COUNTRY); + dwStateID = GET_CURRENT_COMBO_DATA(hWndDlg, IDC_STATE); + hWndCombo = GetDlgItem(hWndDlg, IDC_CITY); + SendMessage(hWndCombo, CB_RESETCONTENT, 0, 0); + dwItem = SendMessage(hWndCombo, CB_ADDSTRING, 0, (LPARAM)L""); + SendMessage(hWndCombo, CB_SETITEMDATA, dwItem, 0); + SendMessage(hWndCombo, CB_SETCURSEL, dwItem, 0); + + for (size_t i = 0;mrapPlaces[i].lpszData;i++) + { + if (mrapPlaces[i].dwCountryID == dwCountryID && mrapPlaces[i].dwCityID == dwStateID && mrapPlaces[i].dwPlaceID) + { + dwItem = SendMessage(hWndCombo, CB_ADDSTRING, 0, (LPARAM)mrapPlaces[i].lpszData); + SendMessage(hWndCombo, CB_SETITEMDATA, dwItem, mrapPlaces[i].dwPlaceID); + } + } + } + break; + default: + break; + } + break; + default: + break; + } +return FALSE; +} + +HWND CMraProto::SearchAdvanced(HWND hWndDlg) +{ + DWORD dwRequestFlags = 0; + CHAR szUser[MAX_PATH], szDomain[MAX_PATH]; + WCHAR wszNickName[MAX_PATH], wszFirstName[MAX_PATH], wszLastName[MAX_PATH]; + size_t dwUserSize, dwDomainSize, dwNickNameSize, dwFirstNameSize, dwLastNameSize; + DWORD dwSex, dwDate1, dwDate2, dwCityID, dwZodiak, dwBirthdayMonth, dwBirthdayDay, dwCountryID, dwOnline; + + dwUserSize = GET_DLG_ITEM_TEXTA(hWndDlg, IDC_EMAIL_USER, szUser, SIZEOF(szUser)); + dwDomainSize = GET_DLG_ITEM_TEXTA(hWndDlg, IDC_EMAIL_DOMAIN, szDomain, SIZEOF(szDomain)); + if (dwUserSize && dwDomainSize) + { + SetBit(dwRequestFlags, MRIM_CS_WP_REQUEST_PARAM_USER); + SetBit(dwRequestFlags, MRIM_CS_WP_REQUEST_PARAM_DOMAIN); + } + + dwNickNameSize = GET_DLG_ITEM_TEXT(hWndDlg, IDC_NICK, wszNickName, SIZEOF(wszNickName)); + if (dwNickNameSize) SetBit(dwRequestFlags, MRIM_CS_WP_REQUEST_PARAM_NICKNAME); + + dwFirstNameSize = GET_DLG_ITEM_TEXT(hWndDlg, IDC_FIRSTNAME, wszFirstName, SIZEOF(wszFirstName)); + if (dwFirstNameSize) SetBit(dwRequestFlags, MRIM_CS_WP_REQUEST_PARAM_FIRSTNAME); + + dwLastNameSize = GET_DLG_ITEM_TEXT(hWndDlg, IDC_LASTNAME, wszLastName, SIZEOF(wszLastName)); + if (dwLastNameSize) SetBit(dwRequestFlags, MRIM_CS_WP_REQUEST_PARAM_LASTNAME); + + dwSex = GET_CURRENT_COMBO_DATA(hWndDlg, IDC_GENDER); + if (dwSex) SetBit(dwRequestFlags, MRIM_CS_WP_REQUEST_PARAM_SEX); + + dwDate1 = GET_CURRENT_COMBO_DATA(hWndDlg, IDC_AGERANGE_FROM); + if (dwDate1) SetBit(dwRequestFlags, MRIM_CS_WP_REQUEST_PARAM_DATE1); + + dwDate2 = GET_CURRENT_COMBO_DATA(hWndDlg, IDC_AGERANGE_TO); + if (dwDate2) SetBit(dwRequestFlags, MRIM_CS_WP_REQUEST_PARAM_DATE2); + + dwCityID = GET_CURRENT_COMBO_DATA(hWndDlg, IDC_CITY); + if (dwCityID == 0) dwCityID = GET_CURRENT_COMBO_DATA(hWndDlg, IDC_STATE); + if (dwCityID) SetBit(dwRequestFlags, MRIM_CS_WP_REQUEST_PARAM_CITY_ID); + + dwZodiak = GET_CURRENT_COMBO_DATA(hWndDlg, IDC_ZODIAK); + if (dwZodiak) SetBit(dwRequestFlags, MRIM_CS_WP_REQUEST_PARAM_ZODIAC); + + dwBirthdayMonth = GET_CURRENT_COMBO_DATA(hWndDlg, IDC_BIRTHDAY_MONTH); + if (dwBirthdayMonth) SetBit(dwRequestFlags, MRIM_CS_WP_REQUEST_PARAM_BIRTHDAY_MONTH); + + dwBirthdayDay = GET_CURRENT_COMBO_DATA(hWndDlg, IDC_BIRTHDAY_DAY); + if (dwBirthdayMonth) SetBit(dwRequestFlags, MRIM_CS_WP_REQUEST_PARAM_BIRTHDAY_DAY); + + dwCountryID = GET_CURRENT_COMBO_DATA(hWndDlg, IDC_COUNTRY); + if (dwCountryID) SetBit(dwRequestFlags, MRIM_CS_WP_REQUEST_PARAM_COUNTRY_ID); + + + dwOnline = IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_ONLINEONLY); + if (dwOnline) SetBit(dwRequestFlags, MRIM_CS_WP_REQUEST_PARAM_ONLINE); + + return (HWND)MraWPRequestW(NULL, ACKTYPE_SEARCH, dwRequestFlags, szUser, dwUserSize, szDomain, dwDomainSize, wszNickName, dwNickNameSize, wszFirstName, dwFirstNameSize, wszLastName, dwLastNameSize, dwSex, dwDate1, dwDate2, dwCityID, dwZodiak, dwBirthdayMonth, dwBirthdayDay, dwCountryID, dwOnline); +} + +HWND CMraProto::CreateExtendedSearchUI(HWND owner) +{ + if (masMraSettings.hInstance && owner) + return CreateDialogParam(masMraSettings.hInstance, MAKEINTRESOURCE(IDD_MRAADVANCEDSEARCH), owner, AdvancedSearchDlgProc, (LPARAM)this); + + return NULL; +} diff --git a/protocols/MRA/src/MraAntiSpam.cpp b/protocols/MRA/src/MraAntiSpam.cpp new file mode 100644 index 0000000000..4d8456d5c1 --- /dev/null +++ b/protocols/MRA/src/MraAntiSpam.cpp @@ -0,0 +1,444 @@ +// started: 19.12.2006 + +#include "Mra.h" +#include "MraAntiSpam.h" +#include "MraRTFMsg.h" + +struct MRA_ANTISPAM_BAD_WORD +{ + LPWSTR lpwszBadWord; + DWORD dwBadWordLen; +}; + +static MRA_ANTISPAM_BAD_WORD *pmabwBadWords = NULL; +static size_t dwBadWordsCount = 0; + +#define MRA_ANTISPAM_PREALLOC_COUNT 256 + +size_t MraAntiSpamLoadBadWordsW() +{ + char szSettingName[MAX_PATH]; + size_t i = 0, dwValueSize, dwAllocatedItemsCount = MRA_ANTISPAM_PREALLOC_COUNT; + DBVARIANT dbv = {0}; + DBCONTACTGETSETTING sVal = {0}; + + dbv.type = DBVT_WCHAR; + sVal.pValue = &dbv; + sVal.szModule = "MRA"; + sVal.szSetting = szSettingName; + + if (pmabwBadWords || dwBadWordsCount) + MraAntiSpamFreeBadWords(); + + pmabwBadWords = (MRA_ANTISPAM_BAD_WORD*)mir_calloc((sizeof(MRA_ANTISPAM_BAD_WORD)*dwAllocatedItemsCount)); + + for (i = 0;TRUE;i++) { + mir_snprintf(szSettingName, SIZEOF(szSettingName), "AntiSpamBadWord %lu", i); + dbv.type = DBVT_WCHAR; + if (CallService(MS_DB_CONTACT_GETSETTING_STR, NULL, (LPARAM)&sVal)) + break; + + if (dwAllocatedItemsCount == i) { + dwAllocatedItemsCount += MRA_ANTISPAM_PREALLOC_COUNT; + pmabwBadWords = (MRA_ANTISPAM_BAD_WORD*)mir_realloc(pmabwBadWords, (sizeof(MRA_ANTISPAM_BAD_WORD)*dwAllocatedItemsCount)); + if (pmabwBadWords == NULL) + break; + } + + dwValueSize = lstrlenW(dbv.pwszVal); + pmabwBadWords[i].lpwszBadWord = (LPWSTR)mir_calloc((dwValueSize*sizeof(WCHAR))); + if (pmabwBadWords[i].lpwszBadWord) { + memmove(pmabwBadWords[i].lpwszBadWord, dbv.pwszVal, (dwValueSize*sizeof(WCHAR))); + CharLowerBuffW(pmabwBadWords[i].lpwszBadWord, DWORD(dwValueSize)); + pmabwBadWords[i].dwBadWordLen = DWORD(dwValueSize); + } + DBFreeVariant(&dbv); + + if (pmabwBadWords[i].lpwszBadWord == NULL) + break; + } + dwBadWordsCount = i; + + return 0; +} + + +void MraAntiSpamFreeBadWords() +{ + for (size_t i = 0; i < dwBadWordsCount; i++) + mir_free(pmabwBadWords[i].lpwszBadWord); + + mir_free(pmabwBadWords); + dwBadWordsCount = 0; +} + +static WORD wMraAntiSpamControlsList[] = { + IDC_CHK_TEMP_CONTACTS, IDC_CLN_NON_ALPHNUM, IDC_MAX_LANG_CHANGES, IDC_SHOWPOPUP, IDC_WRITETOSYSTEMHISTORY, IDC_SEND_SPAM_REPORT_TO_SERVER, + IDC_BAD_WORDS_LIST, IDC_EDIT_BAD_WORD, IDC_BUTTON_ADD, IDC_BUTTONREMOVE, IDC_BUTTON_DEFAULT }; + +void MraAntiSpamEnableControls(HWND hWndDlg, BOOL bEnabled) +{ + EnableControlsArray(hWndDlg, (WORD*)&wMraAntiSpamControlsList, SIZEOF(wMraAntiSpamControlsList), bEnabled); + EnableWindow(GetDlgItem(hWndDlg, IDC_DELETE_SPAMBOT_CONTACT), (bEnabled && IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_CHK_TEMP_CONTACTS))); +} + +INT_PTR CALLBACK MraAntiSpamDlgProcOpts(HWND hWndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + CMraProto *ppro = (CMraProto*)GetWindowLongPtr(hWndDlg, GWLP_USERDATA); + + switch (msg) { + case WM_INITDIALOG: + TranslateDialogDefault(hWndDlg); + SetWindowLongPtr(hWndDlg, GWLP_USERDATA, lParam); + ppro = (CMraProto*)lParam; + + CHECK_DLG_BUTTON(hWndDlg, IDC_ENABLE, ppro->mraGetByte(NULL, "AntiSpamEnable", MRA_ANTISPAM_DEFAULT_ENABLE)); + CHECK_DLG_BUTTON(hWndDlg, IDC_CHK_TEMP_CONTACTS, ppro->mraGetByte(NULL, "AntiSpamCheckTempContacts", MRA_ANTISPAM_DEFAULT_CHK_TEMP_CONTACTS)); + CHECK_DLG_BUTTON(hWndDlg, IDC_DELETE_SPAMBOT_CONTACT, ppro->mraGetByte(NULL, "AntiSpamDeteleSpamBotContacts", MRA_ANTISPAM_DEFAULT_DELETE_SPAMBOT_CONTACT)); + CHECK_DLG_BUTTON(hWndDlg, IDC_CLN_NON_ALPHNUM, ppro->mraGetByte(NULL, "AntiSpamCleanNonAlphaNumeric", MRA_ANTISPAM_DEFAULT_CLN_NON_ALPHNUM)); + SetDlgItemInt(hWndDlg, IDC_MAX_LANG_CHANGES, ppro->mraGetDword(NULL, "AntiSpamMaxLangChanges", MRA_ANTISPAM_DEFAULT_MAX_LNG_CHANGES), FALSE); + CHECK_DLG_BUTTON(hWndDlg, IDC_SHOWPOPUP, ppro->mraGetByte(NULL, "AntiSpamShowPopUp", MRA_ANTISPAM_DEFAULT_SHOWPOP)); + CHECK_DLG_BUTTON(hWndDlg, IDC_WRITETOSYSTEMHISTORY, ppro->mraGetByte(NULL, "AntiSpamWriteToSystemHistory", MRA_ANTISPAM_DEFAULT_WRITETOSYSTEMHISTORY)); + CHECK_DLG_BUTTON(hWndDlg, IDC_SEND_SPAM_REPORT_TO_SERVER, ppro->mraGetByte(NULL, "AntiSpamSendSpamReportToSrv", MRA_ANTISPAM_DEFAULT_SEND_SPAM_REPORT_TO_SERVER)); + { + // fill list + char szSettingName[MAX_PATH]; + WCHAR wszBuff[MAX_PATH]; + + SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_BAD_WORDS_LIST, LB_RESETCONTENT, 0, 0); + SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_BAD_WORDS_LIST, LB_INITSTORAGE, (WPARAM)1024, (LPARAM)32768); + for (size_t i = 0; TRUE; i++) { + mir_snprintf(szSettingName, SIZEOF(szSettingName), "AntiSpamBadWord %lu", i); + if (ppro->mraGetStaticStringW(NULL, szSettingName, wszBuff, SIZEOF(wszBuff), NULL)) { + if (SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_BAD_WORDS_LIST, LB_FINDSTRING, -1, (LPARAM)wszBuff) == LB_ERR) + SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_BAD_WORDS_LIST, LB_ADDSTRING, 0, (LPARAM)wszBuff); + } + else break; + } + } + + MraAntiSpamEnableControls(hWndDlg, IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_ENABLE)); + return TRUE; + + case WM_COMMAND: + if (LOWORD(wParam) == IDC_ENABLE) + MraAntiSpamEnableControls(hWndDlg, IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_ENABLE)); + + if (LOWORD(wParam) == IDC_CHK_TEMP_CONTACTS) + EnableWindow(GetDlgItem(hWndDlg, IDC_DELETE_SPAMBOT_CONTACT), IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_CHK_TEMP_CONTACTS)); + + if (LOWORD(wParam) == IDC_BUTTON_ADD) { + WCHAR szBadWord[MAX_PATH]; + + if (GET_DLG_ITEM_TEXT(hWndDlg, IDC_EDIT_BAD_WORD, szBadWord, SIZEOF(szBadWord))) { + SET_DLG_ITEM_TEXTW(hWndDlg, IDC_EDIT_BAD_WORD, L""); + if (SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_BAD_WORDS_LIST, LB_FINDSTRING, -1, (LPARAM)szBadWord) == LB_ERR) SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_BAD_WORDS_LIST, LB_ADDSTRING, 0, (LPARAM)szBadWord); + } + } + + if (LOWORD(wParam) == IDC_BUTTONREMOVE) + SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_BAD_WORDS_LIST, LB_DELETESTRING, SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_BAD_WORDS_LIST, LB_GETCURSEL, 0, 0), 0); + + if (LOWORD(wParam) == IDC_BUTTON_DEFAULT) { + MraAntiSpamResetBadWordsList(); + + char szSettingName[MAX_PATH]; + WCHAR wszBuff[MAX_PATH]; + + SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_BAD_WORDS_LIST, LB_RESETCONTENT, 0, 0); + SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_BAD_WORDS_LIST, LB_INITSTORAGE, (WPARAM)1024, (LPARAM)32768); + for (size_t i = 0;TRUE;i++) { + mir_snprintf(szSettingName, SIZEOF(szSettingName), "AntiSpamBadWord %lu", i); + if (ppro->mraGetStaticStringW(NULL, szSettingName, wszBuff, SIZEOF(wszBuff), NULL)) { + if (SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_BAD_WORDS_LIST, LB_FINDSTRING, -1, (LPARAM)wszBuff) == LB_ERR) + SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_BAD_WORDS_LIST, LB_ADDSTRING, 0, (LPARAM)wszBuff); + } + else break; + } + MraAntiSpamLoadBadWordsW(); + } + + if ((LOWORD(wParam) == IDC_EDIT_BAD_WORD) && (HIWORD(wParam) != EN_CHANGE || (HWND)lParam != GetFocus())) return 0; + SendMessage(GetParent(hWndDlg), PSM_CHANGED, 0, 0); + break; + + case WM_NOTIFY: + switch (((LPNMHDR)lParam)->code) { + case PSN_APPLY: + { + char szSettingName[MAX_PATH]; + WCHAR szBadWord[MAX_PATH]; + size_t i, dwCount; + + ppro->mraSetByte(NULL, "AntiSpamEnable", IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_ENABLE)); + ppro->mraSetByte(NULL, "AntiSpamCheckTempContacts", IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_CHK_TEMP_CONTACTS)); + ppro->mraSetByte(NULL, "AntiSpamDeteleSpamBotContacts", IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_DELETE_SPAMBOT_CONTACT)); + ppro->mraSetByte(NULL, "AntiSpamCleanNonAlphaNumeric", IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_CLN_NON_ALPHNUM)); + ppro->mraSetDword(NULL, "AntiSpamMaxLangChanges", (DWORD)GetDlgItemInt(hWndDlg, IDC_MAX_LANG_CHANGES, NULL, FALSE)); + ppro->mraSetByte(NULL, "AntiSpamShowPopUp", IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_SHOWPOPUP)); + ppro->mraSetByte(NULL, "AntiSpamWriteToSystemHistory", IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_WRITETOSYSTEMHISTORY)); + ppro->mraSetByte(NULL, "AntiSpamSendSpamReportToSrv", IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_SEND_SPAM_REPORT_TO_SERVER)); + + dwCount = SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_BAD_WORDS_LIST, LB_GETCOUNT, 0, 0); + for (i = 0; i < dwCount; i++) { + mir_snprintf(szSettingName, SIZEOF(szSettingName), "AntiSpamBadWord %lu", i); + SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_BAD_WORDS_LIST, LB_GETTEXT, i, (LPARAM)szBadWord); + ppro->mraSetStringW(NULL, szSettingName, szBadWord); + } + + dwCount = ((i*2)+1024); + for (; i < dwCount; i++) { + mir_snprintf(szSettingName, SIZEOF(szSettingName), "AntiSpamBadWord %lu", i); + ppro->mraDelValue(NULL, szSettingName); + } + + MraAntiSpamLoadBadWordsW(); + } + return TRUE; + } + break; + } + return FALSE; +} + +/////////////////////////////////////////////////////////////////////////////// + +static LPWSTR lpwszBadWords[] = +{ + // web words + L"@", L"http://", L"ftp://", L"www", L"wap.", L".com", L".org", L".info", L".net", L".ua", L".uz", L".to", L".biz", L".vu", L".ru", L"mailto:", L"ICQ", L"SKYPE", + + // spam words + L"sex", L"seks", L"sekc", L"xxx", L"phorno", L"video", L"photo", L"SMS", L"WMZ", L"WMR", L"narod", L"ucoz", L"ref", L"Agent", L"+7", L"495", L"$", L"spam", L"URL", L"%2E", + + // spam words rus + L"прода", L"цена", L"деньги", L"денег", L"секс", L"лесби", L"лезби", L"анал", L"порн", L"эротич", L"видео", L"фильм", L"кино", L"муз", L"фотки", L"фото", L"СМС", L"аськ", L"база", L"сайт", L"проект", L"рассылк", L"обьявлен", L"реклам", L"услуг", L"оплат", L"заказ", L"пиши", L"звони", L"работ", L"зараб", L"зайди", L"загляни", L"посети", L"посмотр", L"погляд", L"точка", L"тчк", L"спам", L"ссылк", L"майл", L"агент", L"супер", L"лох", L"регистрац", L"троян", L"вирус", L"взлом", + + // executable + L".ade", L".adp", L".bas", L".bat", L".chm", L".cmd", L".com", L".cpl", L".crt", L".exe", L".hlp", L".hta", L".inf", L".ins", L".isp", L".js", L".jse", L".lnk", L".mdb", L".mde", L".msc", L".msi", L".msp", L".mst", L".pcd", L".pif", L".reg", L".scr", L".sct", L".shs", L".shb", L".url", L".vb", L".vbe", L".vbs", L".wsc", L".wsf", L".wsh", + + // archives + L".zip", L".rar", L".cab", L".arj", L".tar", L".gz", L".zoo", L".lzh", L".jar", L".ace", L".z", L".iso", L".bz2", L".uue", L".gzip", + + NULL +}; + +void MraAntiSpamResetBadWordsList() +{ + char szSettingName[MAX_PATH]; + size_t i, dwMax; + + for (i = 0; lpwszBadWords[i]; i++) { + mir_snprintf(szSettingName, SIZEOF(szSettingName), "AntiSpamBadWord %lu", i); + db_set_ws(NULL, "MRA", szSettingName, lpwszBadWords[i]); + } + + dwMax = (i+1024); + for (; i < dwMax; i++) { + mir_snprintf(szSettingName, SIZEOF(szSettingName), "AntiSpamBadWord %lu", i); + db_unset(NULL, "MRA", szSettingName); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +static WCHAR lpwszExceptedChars[] = L"\r\n .,<>//?;:'\"\\][}{`-=~!@#$%^&*()_+№1234567890"; + +BOOL MraAntiSpamIsCharExcepted(WCHAR wcTestChar) +{ + for (size_t i = 0; i < SIZEOF(lpwszExceptedChars); i++) + if (lpwszExceptedChars[i] == wcTestChar) + return TRUE; + + return FALSE; +} + +size_t MraAntiSpamCalcLangChanges(LPWSTR lpwszMessage, size_t dwMessageSize) +{ + size_t dwRet = 0; + + if (lpwszMessage && dwMessageSize) { + WCHAR wcPrevChar = 0; + for (size_t i = 1; i < dwMessageSize; i++) { + if (MraAntiSpamIsCharExcepted(lpwszMessage[i]) == FALSE) { + if (wcPrevChar) + if ( (max(wcPrevChar, lpwszMessage[i])-min(wcPrevChar, lpwszMessage[i])) > 255) + dwRet++; + + wcPrevChar = lpwszMessage[i]; + } + } + } + + return dwRet; +} + +size_t MraAntiSpamCleanNonAlphaNumeric(LPWSTR lpwszMessage, size_t dwMessageSize) +{ + size_t dwRet = 0; + + if (lpwszMessage && dwMessageSize) { + LPWSTR lpwszCurWritePos = lpwszMessage; + for (size_t i = 0;i(SIZEOF(wszBuff)-(dwDBMessageSize+sizeof(DWORD)))) dwMessageSize = (SIZEOF(wszBuff)-(dwDBMessageSize+sizeof(DWORD))); + memmove((wszBuff+dwDBMessageSize), lpwszMessage, (dwMessageSize*sizeof(WCHAR))); + dwDBMessageSize += dwMessageSize; + (*((DWORD*)(wszBuff+dwDBMessageSize))) = 0; + dwDBMessageSize += sizeof(DWORD); + + if (bAntiSpamShowPopUp) + MraPopupShowFromAgentW(MRA_POPUP_TYPE_INFORMATION, 0, wszBuff); + + if (bAntiSpamWriteToSystemHistory) { + CHAR szBuff[MRA_MAXLENOFMESSAGE*2]; + WideCharToMultiByte(CP_UTF8, 0, wszBuff, DWORD(dwDBMessageSize), szBuff, SIZEOF(szBuff), NULL, NULL); + + DBEVENTINFO dbei = {0}; + dbei.cbSize = sizeof(dbei); + dbei.szModule = m_szModuleName; + dbei.timestamp = _time32(NULL); + dbei.flags = (DBEF_READ|DBEF_UTF); + dbei.eventType = EVENTTYPE_MESSAGE; + dbei.cbBlob = DWORD(dwDBMessageSize*sizeof(WCHAR)); + dbei.pBlob = (PBYTE)szBuff; + + CallService(MS_DB_EVENT_ADD, 0, (LPARAM)&dbei); + } + + if (hContact && bAntiSpamDeteleSpamBotContacts) { + dwDBMessageSize = mir_sntprintf(wszBuff, SIZEOF(wszBuff), L"%s: %S", TranslateW(L"Spam bot contact deleted"), szEMail); + + if (bAntiSpamShowPopUp) + MraPopupShowFromAgentW(MRA_POPUP_TYPE_INFORMATION, 0, wszBuff); + + if (bAntiSpamWriteToSystemHistory) { + (*((DWORD*)(wszBuff+dwDBMessageSize))) = 0; + dwDBMessageSize += sizeof(DWORD); + + CHAR szBuff[MRA_MAXLENOFMESSAGE*2]; + WideCharToMultiByte(CP_UTF8, 0, wszBuff, DWORD(dwDBMessageSize), szBuff, SIZEOF(szBuff), NULL, NULL); + + DBEVENTINFO dbei = {0}; + dbei.cbSize = sizeof(dbei); + dbei.szModule = m_szModuleName; + dbei.timestamp = _time32(NULL); + dbei.flags = (DBEF_READ|DBEF_UTF); + dbei.eventType = EVENTTYPE_MESSAGE; + dbei.cbBlob = DWORD(dwDBMessageSize*sizeof(WCHAR)); + dbei.pBlob = (PBYTE)szBuff; + CallService(MS_DB_EVENT_ADD, 0, (LPARAM)&dbei); + } + } + } + + if (hContact && bAntiSpamDeteleSpamBotContacts) + CallService(MS_DB_CONTACT_DELETE, (WPARAM)hContact, 0); + } + } + return dwRet; +} diff --git a/protocols/MRA/src/MraAntiSpam.h b/protocols/MRA/src/MraAntiSpam.h new file mode 100644 index 0000000000..7549e308c3 --- /dev/null +++ b/protocols/MRA/src/MraAntiSpam.h @@ -0,0 +1,16 @@ +#if !defined(AFX_MRA_ANTISPAM_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_) +#define AFX_MRA_ANTISPAM_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_ + + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +size_t MraAntiSpamLoadBadWordsW(); +void MraAntiSpamFreeBadWords(); + +INT_PTR CALLBACK MraAntiSpamDlgProcOpts(HWND hWndDlg, UINT msg, WPARAM wParam, LPARAM lParam); + +void MraAntiSpamResetBadWordsList(); + +#endif // !defined(AFX_MRA_ANTISPAM_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_) diff --git a/protocols/MRA/src/MraAvatars.cpp b/protocols/MRA/src/MraAvatars.cpp new file mode 100644 index 0000000000..78989906ee --- /dev/null +++ b/protocols/MRA/src/MraAvatars.cpp @@ -0,0 +1,755 @@ +#include "Mra.h" +#include "MraAvatars.h" + +#define PA_FORMAT_MAX 7 +const LPTSTR lpcszExtensions[9] = +{ + _T(".dat"), // PA_FORMAT_UNKNOWN + _T(".png"), // PA_FORMAT_PNG + _T(".jpg"), // PA_FORMAT_JPEG + _T(".ico"), // PA_FORMAT_ICON + _T(".bmp"), // PA_FORMAT_BMP + _T(".gif"), // PA_FORMAT_GIF + _T(".swf"), // PA_FORMAT_SWF + _T(".xml"), // PA_FORMAT_XML + NULL +}; + +const LPSTR lpcszContentType[9] = +{ + "", // PA_FORMAT_UNKNOWN + "image/png", // PA_FORMAT_PNG + "image/jpeg", // PA_FORMAT_JPEG + "image/icon", // PA_FORMAT_ICON + "image/x-xbitmap", // PA_FORMAT_BMP + "image/gif", // PA_FORMAT_GIF + "", // PA_FORMAT_SWF + "", // PA_FORMAT_XML + NULL +}; + +struct MRA_AVATARS_QUEUE : public FIFO_MT +{ + BOOL bIsRunning; + HANDLE hNetlibUser; + HANDLE hThreadEvent; + DWORD dwThreadsCount; + HANDLE hThread[MAXIMUM_WAIT_OBJECTS]; + LONG lThreadsRunningCount; + HANDLE hAvatarsPath; +}; + +struct MRA_AVATARS_QUEUE_ITEM : public FIFO_MT_ITEM +{ + DWORD dwAvatarsQueueID; + DWORD dwFlags; + HANDLE hContact; +}; + +#define FILETIME_SECOND ((DWORDLONG)10000000) +#define FILETIME_MINUTE ((DWORDLONG)FILETIME_SECOND*60) + + +char szAvtSectName[MAX_PATH]; +#define MRA_AVT_SECT_NAME szAvtSectName + + +static bool bFoldersPresent = false; + + +//#define mir_calloc(Size) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (Size+sizeof(size_t))) +//#define mir_realloc(Mem, Size) HeapReAlloc(GetProcessHeap(), (HEAP_ZERO_MEMORY), (LPVOID)Mem, (Size+sizeof(size_t))) +//#define mir_free(Mem) if (Mem) {HeapFree(GetProcessHeap(), 0, (LPVOID)Mem);Mem = NULL;} + +#define NETLIB_CLOSEHANDLE(hConnection) {Netlib_CloseHandle(hConnection);hConnection = NULL;} + +HANDLE MraAvatarsHttpConnect(HANDLE hNetlibUser, LPSTR lpszHost, DWORD dwPort); + +#define MAHTRO_AVT 0 +#define MAHTRO_AVTMRIM 1 +#define MAHTRO_AVTSMALL 2 +#define MAHTRO_AVTSMALLMRIM 3 + +DWORD MraAvatarsHttpTransaction (HANDLE hConnection, DWORD dwRequestType, LPSTR lpszUser, LPSTR lpszDomain, LPSTR lpszHost, DWORD dwReqObj, BOOL bUseKeepAliveConn, DWORD *pdwResultCode, BOOL *pbKeepAlive, DWORD *pdwFormat, size_t *pdwAvatarSize, INTERNET_TIME *pitLastModifiedTime); +DWORD MraAvatarsGetFileFormat (LPTSTR lpszPath, size_t dwPathSize); + +DWORD CMraProto::MraAvatarsQueueInitialize(HANDLE *phAvatarsQueueHandle) +{ + bFoldersPresent = ServiceExists( MS_FOLDERS_REGISTER_PATH ) != 0; + mir_snprintf(szAvtSectName, SIZEOF(szAvtSectName), "%s Avatars", m_szModuleName); + + if (phAvatarsQueueHandle == NULL) + return ERROR_INVALID_HANDLE; + + MRA_AVATARS_QUEUE *pmraaqAvatarsQueue = (MRA_AVATARS_QUEUE*)mir_calloc(sizeof(MRA_AVATARS_QUEUE)); + if (pmraaqAvatarsQueue == NULL) + return GetLastError(); + + DWORD dwRetErrorCode = FifoMTInitialize(pmraaqAvatarsQueue, 0); + if (dwRetErrorCode == NO_ERROR) { + CHAR szBuffer[MAX_PATH]; + mir_snprintf(szBuffer, SIZEOF(szBuffer), "%s %s %s", m_szModuleName, Translate("Avatars"), Translate("plugin connections")); + + NETLIBUSER nlu = {0}; + nlu.cbSize = sizeof(nlu); + nlu.flags = NUF_OUTGOING | NUF_HTTPCONNS; + nlu.szSettingsModule = MRA_AVT_SECT_NAME; + nlu.szDescriptiveName = szBuffer; + pmraaqAvatarsQueue->hNetlibUser = (HANDLE)CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu); + if (pmraaqAvatarsQueue->hNetlibUser) { + if (bFoldersPresent) { + TCHAR tszPath[ MAX_PATH ]; + mir_sntprintf( tszPath, SIZEOF(tszPath), _T("%%miranda_avatarcache%%\\%s"), m_tszUserName); + pmraaqAvatarsQueue->hAvatarsPath = FoldersRegisterCustomPathT(MRA_AVT_SECT_NAME, "AvatarsPath", tszPath); + } + else pmraaqAvatarsQueue->hAvatarsPath = NULL; + + InterlockedExchange((volatile LONG*)&pmraaqAvatarsQueue->bIsRunning, TRUE); + pmraaqAvatarsQueue->hThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + pmraaqAvatarsQueue->dwThreadsCount = DBGetContactSettingDword(NULL, MRA_AVT_SECT_NAME, "WorkThreadsCount", MRA_AVT_DEFAULT_WRK_THREAD_COUNTS); + if (pmraaqAvatarsQueue->dwThreadsCount == 0) + pmraaqAvatarsQueue->dwThreadsCount = 1; + if (pmraaqAvatarsQueue->dwThreadsCount > MAXIMUM_WAIT_OBJECTS) + pmraaqAvatarsQueue->dwThreadsCount = MAXIMUM_WAIT_OBJECTS; + for (DWORD i = 0; i < pmraaqAvatarsQueue->dwThreadsCount; i++) + pmraaqAvatarsQueue->hThread[i] = ForkThreadEx(&CMraProto::MraAvatarsThreadProc, pmraaqAvatarsQueue); + + *phAvatarsQueueHandle = (HANDLE)pmraaqAvatarsQueue; + } + } + + return dwRetErrorCode; +} + +void CMraProto::MraAvatarsQueueClear(HANDLE hAvatarsQueueHandle) +{ + if ( !hAvatarsQueueHandle) + return; + + MRA_AVATARS_QUEUE *pmraaqAvatarsQueue = (MRA_AVATARS_QUEUE*)hAvatarsQueueHandle; + MRA_AVATARS_QUEUE_ITEM *pmraaqiAvatarsQueueItem; + + PROTO_AVATAR_INFORMATIONT pai = {0}; + pai.cbSize = sizeof(pai); + pai.format = PA_FORMAT_UNKNOWN; + + while (FifoMTItemPop(pmraaqAvatarsQueue, NULL, (LPVOID*)&pmraaqiAvatarsQueueItem) == NO_ERROR) { + pai.hContact = pmraaqiAvatarsQueueItem->hContact; + ProtoBroadcastAck(m_szModuleName, pmraaqiAvatarsQueueItem->hContact, ACKTYPE_AVATAR, ACKRESULT_FAILED, (HANDLE)&pai, 0); + mir_free(pmraaqiAvatarsQueueItem); + } +} + +void CMraProto::MraAvatarsQueueDestroy(HANDLE hAvatarsQueueHandle) +{ + if ( !hAvatarsQueueHandle) + return; + + MRA_AVATARS_QUEUE *pmraaqAvatarsQueue = (MRA_AVATARS_QUEUE*)hAvatarsQueueHandle; + + InterlockedExchange((volatile LONG*)&pmraaqAvatarsQueue->bIsRunning, FALSE); + SetEvent(pmraaqAvatarsQueue->hThreadEvent); + + WaitForMultipleObjects(pmraaqAvatarsQueue->dwThreadsCount, (HANDLE*)&pmraaqAvatarsQueue->hThread[0], TRUE, (WAIT_FOR_THREAD_TIMEOUT*1000)); + + if (InterlockedExchangeAdd((volatile LONG*)&pmraaqAvatarsQueue->lThreadsRunningCount, 0)) + while (InterlockedExchangeAdd((volatile LONG*)&pmraaqAvatarsQueue->lThreadsRunningCount, 0)) + SleepEx(100, TRUE); + + CloseHandle(pmraaqAvatarsQueue->hThreadEvent); + + MraAvatarsQueueClear(hAvatarsQueueHandle); + + FifoMTDestroy(pmraaqAvatarsQueue); + Netlib_CloseHandle(pmraaqAvatarsQueue->hNetlibUser); + mir_free(pmraaqAvatarsQueue); +} + +DWORD CMraProto::MraAvatarsQueueAdd(HANDLE hAvatarsQueueHandle, DWORD dwFlags, HANDLE hContact, DWORD *pdwAvatarsQueueID) +{ + if ( !hAvatarsQueueHandle) + return ERROR_INVALID_HANDLE; + + MRA_AVATARS_QUEUE *pmraaqAvatarsQueue = (MRA_AVATARS_QUEUE*)hAvatarsQueueHandle; + MRA_AVATARS_QUEUE_ITEM *pmraaqiAvatarsQueueItem = (MRA_AVATARS_QUEUE_ITEM*)mir_calloc(sizeof(MRA_AVATARS_QUEUE_ITEM)); + if ( !pmraaqiAvatarsQueueItem) + return GetLastError(); + + pmraaqiAvatarsQueueItem->dwAvatarsQueueID = GetTickCount(); + pmraaqiAvatarsQueueItem->dwFlags = dwFlags; + pmraaqiAvatarsQueueItem->hContact = hContact; + + FifoMTItemPush(pmraaqAvatarsQueue, pmraaqiAvatarsQueueItem, (LPVOID)pmraaqiAvatarsQueueItem); + if (pdwAvatarsQueueID) + *pdwAvatarsQueueID = pmraaqiAvatarsQueueItem->dwAvatarsQueueID; + SetEvent(pmraaqAvatarsQueue->hThreadEvent); + return NO_ERROR; +} + +void CMraProto::MraAvatarsThreadProc(LPVOID lpParameter) +{ + MRA_AVATARS_QUEUE *pmraaqAvatarsQueue = (MRA_AVATARS_QUEUE*)lpParameter; + MRA_AVATARS_QUEUE_ITEM *pmraaqiAvatarsQueueItem; + + char szEMail[MAX_EMAIL_LEN], szServer[MAX_PATH]; + WCHAR wszFileName[MAX_FILEPATH], szErrorText[2048]; + BOOL bContinue, bKeepAlive, bUseKeepAliveConn, bFailed, bDownloadNew, bDefaultAvt; + BYTE btBuff[BUFF_SIZE_RCV]; + DWORD dwResultCode, dwAvatarFormat, dwReceived, dwServerPort, dwErrorCode; + LPSTR lpszUser, lpszDomain; + size_t dwEMailSize, dwAvatarSizeServer, dwFileNameSize; + FILETIME ftLastModifiedTimeServer, ftLastModifiedTimeLocal; + SYSTEMTIME stAvatarLastModifiedTimeLocal; + HANDLE hConnection = NULL; + NETLIBSELECT nls = {0}; + INTERNET_TIME itAvatarLastModifiedTimeServer; + PROTO_AVATAR_INFORMATIONT pai; + + nls.cbSize = sizeof(nls); + pai.cbSize = sizeof(pai); + + InterlockedIncrement((volatile LONG*)&pmraaqAvatarsQueue->lThreadsRunningCount); + + while ( InterlockedExchangeAdd((volatile LONG*)&pmraaqAvatarsQueue->bIsRunning, 0)) { + if ( FifoMTItemPop(pmraaqAvatarsQueue, NULL, (LPVOID*)&pmraaqiAvatarsQueueItem) == NO_ERROR) { + bFailed = TRUE; + bDownloadNew = FALSE; + bDefaultAvt = FALSE; + + if (DB_GetStaticStringA(NULL, MRA_AVT_SECT_NAME, "Server", szServer, SIZEOF(szServer), NULL) == FALSE) memmove(szServer, MRA_AVT_DEFAULT_SERVER, sizeof(MRA_AVT_DEFAULT_SERVER)); + dwServerPort = DBGetContactSettingDword(NULL, MRA_AVT_SECT_NAME, "ServerPort", MRA_AVT_DEFAULT_SERVER_PORT); + bUseKeepAliveConn = db_get_b(NULL, MRA_AVT_SECT_NAME, "UseKeepAliveConn", MRA_AVT_DEFAULT_USE_KEEPALIVE_CONN); + + if ( mraGetStaticStringA(pmraaqiAvatarsQueueItem->hContact, "e-mail", szEMail, SIZEOF(szEMail), &dwEMailSize)) { + BuffToLowerCase(szEMail, szEMail, dwEMailSize); + lpszDomain = (LPSTR)MemoryFindByte(0, szEMail, dwEMailSize, '@'); + lpszUser = (LPSTR)MemoryFindByte((lpszDomain-szEMail), szEMail, dwEMailSize, '.'); + if (lpszDomain && lpszUser) { + *lpszUser = 0; + lpszUser = szEMail; + *lpszDomain = 0; + lpszDomain++; + + ProtoBroadcastAck(m_szModuleName, pmraaqiAvatarsQueueItem->hContact, ACKTYPE_AVATAR, ACKRESULT_CONNECTING, NULL, 0); + if (hConnection == NULL) + hConnection = MraAvatarsHttpConnect(pmraaqAvatarsQueue->hNetlibUser, szServer, dwServerPort); + if (hConnection) { + ProtoBroadcastAck(m_szModuleName, pmraaqiAvatarsQueueItem->hContact, ACKTYPE_AVATAR, ACKRESULT_CONNECTED, NULL, 0); + ProtoBroadcastAck(m_szModuleName, pmraaqiAvatarsQueueItem->hContact, ACKTYPE_AVATAR, ACKRESULT_SENTREQUEST, NULL, 0); + if ( !MraAvatarsHttpTransaction(hConnection, REQUEST_HEAD, lpszUser, lpszDomain, szServer, MAHTRO_AVTMRIM, bUseKeepAliveConn, &dwResultCode, &bKeepAlive, &dwAvatarFormat, &dwAvatarSizeServer, &itAvatarLastModifiedTimeServer)) { + switch (dwResultCode) { + case 200: + if (MraAvatarsGetContactTime(pmraaqiAvatarsQueueItem->hContact, "AvatarLastModifiedTime", &stAvatarLastModifiedTimeLocal)) { + SystemTimeToFileTime(&itAvatarLastModifiedTimeServer.stTime, &ftLastModifiedTimeServer); + SystemTimeToFileTime(&stAvatarLastModifiedTimeLocal, &ftLastModifiedTimeLocal); + + if ((*((DWORDLONG*)&ftLastModifiedTimeServer)) != (*((DWORDLONG*)&ftLastModifiedTimeLocal))) + {// need check for update + bDownloadNew = TRUE; + //ProtoBroadcastAck(m_szModuleName, pmraaqiAvatarsQueueItem->hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, 0, 0); + } + else {// avatar is valid + if (MraAvatarsGetFileName(pmraaqAvatarsQueue, pmraaqiAvatarsQueueItem->hContact, dwAvatarFormat, wszFileName, SIZEOF(wszFileName), NULL) == NO_ERROR) { + if ( IsFileExist( wszFileName )) + bFailed = FALSE; + else + bDownloadNew = TRUE; + } + } + } + else // need update + bDownloadNew = TRUE; + + break; + case 404:// return def avatar + if (MraAvatarsGetFileName((HANDLE)pmraaqAvatarsQueue, NULL, PA_FORMAT_DEFAULT, wszFileName, SIZEOF(wszFileName), &dwFileNameSize) == NO_ERROR) { + if ( IsFileExist( wszFileName )) { + dwAvatarFormat = MraAvatarsGetFileFormat(wszFileName, dwFileNameSize); + bFailed = FALSE; + } + else//loading default avatar + bDownloadNew = TRUE; + + bDefaultAvt = TRUE; + } + break; + + default: + mir_sntprintf(szErrorText, SIZEOF(szErrorText), TranslateW(L"Avatars: server return HTTP code: %lu"), dwResultCode); + ShowFormattedErrorMessage(szErrorText, NO_ERROR); + break; + } + } + if (bUseKeepAliveConn == FALSE || bKeepAlive == FALSE) NETLIB_CLOSEHANDLE(hConnection); + } + + if (bDownloadNew) { + if (hConnection == NULL) + hConnection = MraAvatarsHttpConnect(pmraaqAvatarsQueue->hNetlibUser, szServer, dwServerPort); + + if (hConnection) { + ProtoBroadcastAck(m_szModuleName, pmraaqiAvatarsQueueItem->hContact, ACKTYPE_AVATAR, ACKRESULT_DATA, NULL, 0); + if (MraAvatarsHttpTransaction(hConnection, REQUEST_GET, lpszUser, lpszDomain, szServer, MAHTRO_AVT, bUseKeepAliveConn, &dwResultCode, &bKeepAlive, &dwAvatarFormat, &dwAvatarSizeServer, &itAvatarLastModifiedTimeServer) == NO_ERROR && dwResultCode == 200) { + if (bDefaultAvt) + dwAvatarFormat = PA_FORMAT_DEFAULT; + + if ( !MraAvatarsGetFileName(pmraaqAvatarsQueue, pmraaqiAvatarsQueueItem->hContact, dwAvatarFormat, wszFileName, SIZEOF(wszFileName), NULL)) { + HANDLE hFile = CreateFile(wszFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile != INVALID_HANDLE_VALUE) { + DWORD dwWritten = 0; + bContinue = TRUE; + nls.dwTimeout = (1000*DBGetContactSettingDword(NULL, MRA_AVT_SECT_NAME, "TimeOutReceive", MRA_AVT_DEFAULT_TIMEOUT_RECV)); + nls.hReadConns[0] = hConnection; + + while ( bContinue ) { + switch (CallService(MS_NETLIB_SELECT, 0, (LPARAM)&nls)) { + case SOCKET_ERROR: + case 0:// Time out + dwErrorCode = GetLastError(); + ShowFormattedErrorMessage(L"Avatars: error on receive file data", dwErrorCode); + bContinue = FALSE; + break; + case 1: + dwReceived = Netlib_Recv(hConnection, (LPSTR)&btBuff, SIZEOF(btBuff), 0); + if (dwReceived == 0 || dwReceived == SOCKET_ERROR) { + dwErrorCode = GetLastError(); + ShowFormattedErrorMessage(L"Avatars: error on receive file data", dwErrorCode); + bContinue = FALSE; + } + else { + if ( WriteFile( hFile, (LPVOID)&btBuff, dwReceived, &dwReceived, NULL)) { + dwWritten += dwReceived; + if (dwWritten >= dwAvatarSizeServer) + bContinue = FALSE; + } + else { + dwErrorCode = GetLastError(); + ShowFormattedErrorMessage(L"Avatars: cant write file data, error", dwErrorCode); + bContinue = FALSE; + } + } + break; + } + } + CloseHandle(hFile); + bFailed = FALSE; + } + else { + dwErrorCode = GetLastError(); + mir_sntprintf(szErrorText, SIZEOF(szErrorText), TranslateW(L"Avatars: cant open file %s, error"), wszFileName); + ShowFormattedErrorMessage(szErrorText, dwErrorCode); + } + } + } + else DebugBreak(); + + if (bUseKeepAliveConn == FALSE || bKeepAlive == FALSE) NETLIB_CLOSEHANDLE(hConnection); + } + } + } + } + + if (bFailed) { + DeleteFile(wszFileName); + pai.hContact = pmraaqiAvatarsQueueItem->hContact; + pai.format = PA_FORMAT_UNKNOWN; + pai.filename[0] = 0; + ProtoBroadcastAck(m_szModuleName, pmraaqiAvatarsQueueItem->hContact, ACKTYPE_AVATAR, ACKRESULT_FAILED, (HANDLE)&pai, 0); + } + else { + pai.hContact = pmraaqiAvatarsQueueItem->hContact; + pai.format = dwAvatarFormat; + if ( db_get_b(NULL, MRA_AVT_SECT_NAME, "ReturnAbsolutePath", MRA_AVT_DEFAULT_RET_ABC_PATH)) + lstrcpyn(pai.filename, wszFileName, SIZEOF(pai.filename)); + else + CallService(MS_UTILS_PATHTORELATIVET, (WPARAM)wszFileName, (LPARAM)pai.filename ); + + if (bDefaultAvt) dwAvatarFormat = PA_FORMAT_DEFAULT; + SetContactAvatarFormat(pmraaqiAvatarsQueueItem->hContact, dwAvatarFormat); + MraAvatarsSetContactTime(pmraaqiAvatarsQueueItem->hContact, "AvatarLastModifiedTime", &itAvatarLastModifiedTimeServer.stTime); + // write owner avatar file name to DB + if ( pmraaqiAvatarsQueueItem->hContact == NULL) // proto avatar + CallService(MS_AV_REPORTMYAVATARCHANGED, (WPARAM)m_szModuleName, 0); + + ProtoBroadcastAck(m_szModuleName, pmraaqiAvatarsQueueItem->hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, (HANDLE)&pai, 0); + } + mir_free(pmraaqiAvatarsQueueItem); + } + else { // waiting until service stop or new task + NETLIB_CLOSEHANDLE(hConnection); + WaitForSingleObjectEx(pmraaqAvatarsQueue->hThreadEvent, MRA_AVT_DEFAULT_QE_CHK_INTERVAL, FALSE); + } + } + + InterlockedDecrement((volatile LONG*)&pmraaqAvatarsQueue->lThreadsRunningCount); +} + +HANDLE MraAvatarsHttpConnect(HANDLE hNetlibUser, LPSTR lpszHost, DWORD dwPort) +{ + NETLIBOPENCONNECTION nloc = {0}; + nloc.cbSize = sizeof(nloc); + nloc.flags = (NLOCF_HTTP|NLOCF_V2); + nloc.szHost = lpszHost; + nloc.wPort = ( IsHTTPSProxyUsed(hNetlibUser)) ? MRA_SERVER_PORT_HTTPS : dwPort; + nloc.timeout = DBGetContactSettingDword(NULL, MRA_AVT_SECT_NAME, "TimeOutConnect", MRA_AVT_DEFAULT_TIMEOUT_CONN); + if (nloc.timeoutMRA_TIMEOUT_CONN_МАХ) nloc.timeout = MRA_TIMEOUT_CONN_МАХ; + + DWORD dwConnectReTryCount = DBGetContactSettingDword(NULL, MRA_AVT_SECT_NAME, "ConnectReTryCount", MRA_AVT_DEFAULT_CONN_RETRY_COUNT); + DWORD dwCurConnectReTryCount = dwConnectReTryCount; + HANDLE hConnection; + do { + hConnection = (HANDLE)CallService(MS_NETLIB_OPENCONNECTION, (WPARAM)hNetlibUser, (LPARAM)&nloc); + } + while (--dwCurConnectReTryCount && hConnection == NULL); + + return hConnection; +} + +DWORD MraAvatarsHttpTransaction(HANDLE hConnection, DWORD dwRequestType, LPSTR lpszUser, LPSTR lpszDomain, LPSTR lpszHost, DWORD dwReqObj, BOOL bUseKeepAliveConn, DWORD *pdwResultCode, BOOL *pbKeepAlive, DWORD *pdwFormat, size_t *pdwAvatarSize, INTERNET_TIME *pitLastModifiedTime) +{ + if (pdwResultCode) *pdwResultCode = 0; + if (pbKeepAlive) *pbKeepAlive = FALSE; + if (pdwFormat) *pdwFormat = PA_FORMAT_UNKNOWN; + if (pdwAvatarSize) *pdwAvatarSize = 0; + if (pitLastModifiedTime) bzero(pitLastModifiedTime, sizeof(INTERNET_TIME)); + + if (!hConnection) + return ERROR_INVALID_HANDLE; + + LPSTR lpszReqObj; + + switch (dwReqObj) { + case MAHTRO_AVT: lpszReqObj = "_avatar"; break; + case MAHTRO_AVTMRIM: lpszReqObj = "_mrimavatar"; break; + case MAHTRO_AVTSMALL: lpszReqObj = "_avatarsmall"; break; + case MAHTRO_AVTSMALLMRIM: lpszReqObj = "_mrimavatarsmall"; break; + default: lpszReqObj = ""; break; + } + + char szBuff[4096], szSelfVersionString[MAX_PATH]; + DWORD dwBuffSize = mir_snprintf(szBuff, SIZEOF(szBuff), "http://%s/%s/%s/%s", lpszHost, lpszDomain, lpszUser, lpszReqObj); + MraGetSelfVersionString(szSelfVersionString, SIZEOF(szSelfVersionString), NULL); + + NETLIBHTTPHEADER nlbhHeaders[8] = {0}; + nlbhHeaders[0].szName = "User-Agent"; nlbhHeaders[0].szValue = szSelfVersionString; + nlbhHeaders[1].szName = "Accept-Encoding"; nlbhHeaders[1].szValue = "deflate"; + nlbhHeaders[2].szName = "Pragma"; nlbhHeaders[2].szValue = "no-cache"; + nlbhHeaders[3].szName = "Connection"; nlbhHeaders[3].szValue = (bUseKeepAliveConn)? "keep-alive":"close"; + + NETLIBHTTPREQUEST *pnlhr, nlhr = {0}; + nlhr.cbSize = sizeof(nlhr); + nlhr.requestType = dwRequestType; + nlhr.flags = (NLHRF_GENERATEHOST|NLHRF_SMARTREMOVEHOST|NLHRF_SMARTAUTHHEADER); + nlhr.szUrl = szBuff; + nlhr.headers = (NETLIBHTTPHEADER*)&nlbhHeaders; + nlhr.headersCount = 4; + + DWORD dwSent = CallService(MS_NETLIB_SENDHTTPREQUEST, (WPARAM)hConnection, (LPARAM)&nlhr); + if (dwSent == SOCKET_ERROR || !dwSent) + return GetLastError(); + + pnlhr = (NETLIBHTTPREQUEST*)CallService(MS_NETLIB_RECVHTTPHEADERS, (WPARAM)hConnection, (LPARAM)0); + if (!pnlhr) + return GetLastError(); + + for (int i = 0; i < pnlhr->headersCount; i++) { + if ( !_strnicmp(pnlhr->headers[i].szName, "Connection", 10)) { + if (pbKeepAlive) + *pbKeepAlive = !_strnicmp(pnlhr->headers[i].szValue, "keep-alive", 10); + } + else if ( !_strnicmp(pnlhr->headers[i].szName, "Content-Type", 12)) { + if (pdwFormat) { + for (DWORD j = 0; j < PA_FORMAT_MAX; j++) { + if ( !_stricmp(pnlhr->headers[i].szValue, lpcszContentType[j])) { + *pdwFormat = j; + break; + } + } + } + } + else if ( !_strnicmp(pnlhr->headers[i].szName, "Content-Length", 14)) { + if (pdwAvatarSize) + *pdwAvatarSize = StrToUNum(pnlhr->headers[i].szValue, lstrlenA(pnlhr->headers[i].szValue)); + } + else if ( !_strnicmp(pnlhr->headers[i].szName, "Last-Modified", 13)) { + if (pitLastModifiedTime) + InternetTimeGetTime(pnlhr->headers[i].szValue, lstrlenA(pnlhr->headers[i].szValue), pitLastModifiedTime); + } + } + + if (pdwResultCode) (*pdwResultCode) = pnlhr->resultCode; + CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, (WPARAM)0, (LPARAM)pnlhr); + return 0; +} + +BOOL CMraProto::MraAvatarsGetContactTime(HANDLE hContact, LPSTR lpszValueName, SYSTEMTIME *pstTime) +{ + if (lpszValueName && pstTime) { + char szBuff[MAX_PATH]; + size_t dwBuffSize; + INTERNET_TIME itAvatarLastModifiedTimeLocal; + + if (mraGetStaticStringA(hContact, lpszValueName, (LPSTR)szBuff, SIZEOF(szBuff), &dwBuffSize)) + if (InternetTimeGetTime(szBuff, dwBuffSize, &itAvatarLastModifiedTimeLocal) == NO_ERROR) { + memmove(pstTime, &itAvatarLastModifiedTimeLocal.stTime, sizeof(SYSTEMTIME)); + return TRUE; + } + } + return FALSE; +} + + +void CMraProto::MraAvatarsSetContactTime(HANDLE hContact, LPSTR lpszValueName, SYSTEMTIME *pstTime) +{ + if (!lpszValueName) + return; + + char szBuff[MAX_PATH]; + size_t dwBuffUsedSize; + INTERNET_TIME itTime; + + if (pstTime) { + itTime.lTimeZone = 0; + memmove(&itTime.stTime, pstTime, sizeof(SYSTEMTIME)); + } + else InternetTimeGetCurrentTime(&itTime); + + if (itTime.stTime.wYear) { + InternetTimeGetString(&itTime, (LPSTR)szBuff, SIZEOF(szBuff), &dwBuffUsedSize); + mraSetStringExA(hContact, lpszValueName, (LPSTR)szBuff, dwBuffUsedSize); + } + else mraDelValue(hContact, lpszValueName); +} + +DWORD MraAvatarsGetFileFormat(LPTSTR lpszPath, size_t dwPathSize) +{ + TCHAR dwExt[ 5 ]; + BuffToLowerCase(&dwExt, lpszPath+(dwPathSize-4), 4); + + for ( DWORD i = 0; i < PA_FORMAT_MAX; i++ ) + if ( !_tcscmp( dwExt, lpcszExtensions[i])) + return i; + + return -1; +} + + +DWORD CMraProto::MraAvatarsGetFileName(HANDLE hAvatarsQueueHandle, HANDLE hContact, DWORD dwFormat, LPTSTR lpszPath, size_t dwPathSize, size_t *pdwPathSizeRet) +{ + if (hAvatarsQueueHandle == NULL) + return ERROR_INVALID_HANDLE; + + if (IsContactChatAgent(hContact)) + return ERROR_NOT_SUPPORTED; + + LPTSTR lpszCurPath = lpszPath; + size_t dwEMailSize; + MRA_AVATARS_QUEUE *pmraaqAvatarsQueue = (MRA_AVATARS_QUEUE*)hAvatarsQueueHandle; + + if ( !bFoldersPresent ) { + // default path + mir_ptr lpszPathToAvatarsCache( Utils_ReplaceVarsT( _T("%miranda_avatarcache%"))); + dwEMailSize = mir_sntprintf(lpszPath, dwPathSize, _T("%s\\%s\\"), (TCHAR*)lpszPathToAvatarsCache, m_tszUserName); + } + else { + FoldersGetCustomPathT( pmraaqAvatarsQueue->hAvatarsPath, lpszCurPath, int(dwPathSize), _T("")); + dwEMailSize = lstrlen( lpszCurPath ); + _tcscpy( lpszCurPath + dwEMailSize, _T("\\")); + dwEMailSize++; + } + + dwPathSize -= dwEMailSize; + lpszCurPath += dwEMailSize; + + if (dwPathSize) { + // some path in buff and free space for file name is avaible + CallService(MS_UTILS_CREATEDIRTREET, 0, (LPARAM)lpszPath); + + if (dwFormat != PA_FORMAT_DEFAULT) { + if ( mraGetStaticStringW(hContact, "e-mail", lpszCurPath, dwPathSize-5, &dwEMailSize)) { + BuffToLowerCase(lpszCurPath, lpszCurPath, dwEMailSize); + lpszCurPath += dwEMailSize; + _tcscpy( lpszCurPath, lpcszExtensions[dwFormat] ); + lpszCurPath += 4; + *lpszCurPath = 0; + + if ( pdwPathSizeRet ) + *pdwPathSizeRet = lpszCurPath - lpszPath; + return NO_ERROR; + } + } + else { + if ( DB_GetStaticStringW(NULL, MRA_AVT_SECT_NAME, "DefaultAvatarFileName", lpszCurPath, dwPathSize-5, &dwEMailSize ) == FALSE) { + _tcscpy(lpszCurPath, MRA_AVT_DEFAULT_AVT_FILENAME); + lpszCurPath += SIZEOF( MRA_AVT_DEFAULT_AVT_FILENAME )-1; + + if (pdwPathSizeRet) + *pdwPathSizeRet = lpszCurPath - lpszPath; + return NO_ERROR; + } + } + } + + return ERROR_INSUFFICIENT_BUFFER; +} + +DWORD CMraProto::MraAvatarsQueueGetAvatar(HANDLE hAvatarsQueueHandle, DWORD dwFlags, HANDLE hContact, DWORD *pdwAvatarsQueueID, DWORD *pdwFormat, LPTSTR lpszPath) +{ + DWORD dwRetCode = GAIR_NOAVATAR; + + if (hAvatarsQueueHandle) + if (db_get_b(NULL, MRA_AVT_SECT_NAME, "Enable", MRA_AVT_DEFAULT_ENABLE)) + if (IsContactChatAgent(hContact) == FALSE) { + // not @chat.agent conference + BOOL bQueueAdd = TRUE;// check for updates + MRA_AVATARS_QUEUE *pmraaqAvatarsQueue = (MRA_AVATARS_QUEUE*)hAvatarsQueueHandle; + SYSTEMTIME stAvatarLastCheckTime; + + if ((dwFlags & GAIF_FORCE) == 0)// если флаг принудит. обновления, то даже не проверяем времени последнего обновления + if (MraAvatarsGetContactTime(hContact, "AvatarLastCheckTime", &stAvatarLastCheckTime)) { + TCHAR wszFileName[MAX_FILEPATH]; + size_t dwPathSize; + FILETIME ftCurrentTime, ftExpireTime; + + GetSystemTimeAsFileTime(&ftCurrentTime); + SystemTimeToFileTime(&stAvatarLastCheckTime, &ftExpireTime); + (*((DWORDLONG*)&ftExpireTime)) += (FILETIME_MINUTE*(DWORDLONG)DBGetContactSettingDword(NULL, MRA_AVT_SECT_NAME, "CheckInterval", MRA_AVT_DEFAULT_CHK_INTERVAL)); + + if ((*((DWORDLONG*)&ftExpireTime))>(*((DWORDLONG*)&ftCurrentTime))) + if ( MraAvatarsGetFileName(hAvatarsQueueHandle, hContact, GetContactAvatarFormat(hContact, PA_FORMAT_DEFAULT), wszFileName, SIZEOF(wszFileName), &dwPathSize) == NO_ERROR) + if ( IsFileExist( wszFileName )) { + // файл с аватаром существует и не устарел/не было комманды обновлять(просто запрос имени) + if (lpszPath) { + if (db_get_b(NULL, MRA_AVT_SECT_NAME, "ReturnAbsolutePath", MRA_AVT_DEFAULT_RET_ABC_PATH)) + lstrcpyn(lpszPath, wszFileName, MAX_PATH); + else + CallService( MS_UTILS_PATHTORELATIVET, (WPARAM)wszFileName, (LPARAM)lpszPath ); + } + if (pdwFormat) + *pdwFormat = GetContactAvatarFormat(hContact, PA_FORMAT_DEFAULT); + dwRetCode = GAIR_SUCCESS; + bQueueAdd = FALSE; + } + } + + if (bQueueAdd || (dwFlags & GAIF_FORCE)) + if ( !MraAvatarsQueueAdd(hAvatarsQueueHandle, dwFlags, hContact, pdwAvatarsQueueID)) { + MraAvatarsSetContactTime(hContact, "AvatarLastCheckTime", NULL); + dwRetCode = GAIR_WAITFOR; + } + } + return dwRetCode; +} + +DWORD CMraProto::MraAvatarsQueueGetAvatarSimple(HANDLE hAvatarsQueueHandle, DWORD dwFlags, HANDLE hContact, DWORD dwSourceID) +{ + DWORD dwRetCode = GAIR_NOAVATAR; + + PROTO_AVATAR_INFORMATIONT pai = {0}; + pai.cbSize = sizeof(pai); + pai.hContact = hContact; + if ((dwRetCode = MraAvatarsQueueGetAvatar(hAvatarsQueueHandle, dwFlags, hContact, NULL, (DWORD*)&pai.format, pai.filename )) == GAIR_SUCCESS ) { + // write owner avatar file name to DB + if (hContact == NULL) + CallService(MS_AV_REPORTMYAVATARCHANGED, (WPARAM)m_szModuleName, 0); + + ProtoBroadcastAck(m_szModuleName, hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, (HANDLE)&pai, 0); + } + return dwRetCode; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Avatars options + +WORD wMraAvatarsControlsList[] = { + IDC_SERVER, + IDC_SERVERPORT, + IDC_BUTTON_DEFAULT, + IDC_USE_KEEPALIVE_CONN, + IDC_UPD_CHECK_INTERVAL, + IDC_RETURN_ABC_PATH, + IDC_DELETE_AVT_ON_CONTACT_DELETE +}; + +INT_PTR CALLBACK MraAvatarsQueueDlgProcOpts(HWND hWndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + CMraProto *ppro = (CMraProto*)GetWindowLongPtr(hWndDlg, GWLP_USERDATA); + + switch (msg) { + case WM_INITDIALOG: + TranslateDialogDefault(hWndDlg); + SetWindowLongPtr(hWndDlg, GWLP_USERDATA, lParam); + ppro = (CMraProto*)lParam; + { + WCHAR szServer[MAX_PATH]; + + CHECK_DLG_BUTTON(hWndDlg, IDC_ENABLE, db_get_b(NULL, MRA_AVT_SECT_NAME, "Enable", MRA_AVT_DEFAULT_ENABLE)); + + if (DB_GetStaticStringW(NULL, MRA_AVT_SECT_NAME, "Server", szServer, MAX_PATH, NULL)) + SET_DLG_ITEM_TEXT(hWndDlg, IDC_SERVER, szServer); + else + SET_DLG_ITEM_TEXTA(hWndDlg, IDC_SERVER, MRA_AVT_DEFAULT_SERVER); + + SetDlgItemInt(hWndDlg, IDC_SERVERPORT, DBGetContactSettingDword(NULL, MRA_AVT_SECT_NAME, "ServerPort", MRA_AVT_DEFAULT_SERVER_PORT), FALSE); + CHECK_DLG_BUTTON(hWndDlg, IDC_USE_KEEPALIVE_CONN, db_get_b(NULL, MRA_AVT_SECT_NAME, "UseKeepAliveConn", MRA_AVT_DEFAULT_USE_KEEPALIVE_CONN)); + SetDlgItemInt(hWndDlg, IDC_UPD_CHECK_INTERVAL, DBGetContactSettingDword(NULL, MRA_AVT_SECT_NAME, "CheckInterval", MRA_AVT_DEFAULT_CHK_INTERVAL), FALSE); + CHECK_DLG_BUTTON(hWndDlg, IDC_RETURN_ABC_PATH, db_get_b(NULL, MRA_AVT_SECT_NAME, "ReturnAbsolutePath", MRA_AVT_DEFAULT_RET_ABC_PATH)); + CHECK_DLG_BUTTON(hWndDlg, IDC_DELETE_AVT_ON_CONTACT_DELETE, db_get_b(NULL, MRA_AVT_SECT_NAME, "DeleteAvtOnContactDelete", MRA_DELETE_AVT_ON_CONTACT_DELETE)); + + EnableControlsArray(hWndDlg, (WORD*)&wMraAvatarsControlsList, SIZEOF(wMraAvatarsControlsList), IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_ENABLE)); + } + return TRUE; + + case WM_COMMAND: + if (LOWORD(wParam) == IDC_ENABLE) + EnableControlsArray(hWndDlg, (WORD*)&wMraAvatarsControlsList, SIZEOF(wMraAvatarsControlsList), IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_ENABLE)); + + if (LOWORD(wParam) == IDC_BUTTON_DEFAULT) { + SET_DLG_ITEM_TEXTA(hWndDlg, IDC_SERVER, MRA_AVT_DEFAULT_SERVER); + SetDlgItemInt(hWndDlg, IDC_SERVERPORT, MRA_AVT_DEFAULT_SERVER_PORT, FALSE); + } + + if ((LOWORD(wParam) == IDC_SERVER || LOWORD(wParam) == IDC_SERVERPORT || LOWORD(wParam) == IDC_UPD_CHECK_INTERVAL) && (HIWORD(wParam) != EN_CHANGE || (HWND)lParam != GetFocus())) return FALSE; + SendMessage(GetParent(hWndDlg), PSM_CHANGED, 0, 0); + break; + + case WM_NOTIFY: + switch (((LPNMHDR)lParam)->code) { + case PSN_APPLY: + { + WCHAR szServer[MAX_PATH]; + + DBWriteContactSettingByte(NULL, MRA_AVT_SECT_NAME, "Enable", IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_ENABLE)); + DBWriteContactSettingByte(NULL, MRA_AVT_SECT_NAME, "DeleteAvtOnContactDelete", IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_DELETE_AVT_ON_CONTACT_DELETE)); + DBWriteContactSettingByte(NULL, MRA_AVT_SECT_NAME, "ReturnAbsolutePath", IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_RETURN_ABC_PATH)); + DBWriteContactSettingDword(NULL, MRA_AVT_SECT_NAME, "CheckInterval", GetDlgItemInt(hWndDlg, IDC_UPD_CHECK_INTERVAL, NULL, FALSE)); + DBWriteContactSettingByte(NULL, MRA_AVT_SECT_NAME, "UseKeepAliveConn", IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_USE_KEEPALIVE_CONN)); + DBWriteContactSettingDword(NULL, MRA_AVT_SECT_NAME, "ServerPort", GetDlgItemInt(hWndDlg, IDC_SERVERPORT, NULL, FALSE)); + + GET_DLG_ITEM_TEXT(hWndDlg, IDC_SERVER, szServer, SIZEOF(szServer)); + db_set_ws(NULL, MRA_AVT_SECT_NAME, "Server", szServer); + } + return TRUE; + } + break; + } + return FALSE; +} + + +DWORD CMraProto::MraAvatarsDeleteContactAvatarFile(HANDLE hAvatarsQueueHandle, HANDLE hContact) +{ + if (hAvatarsQueueHandle == NULL) + return ERROR_INVALID_HANDLE; + + MRA_AVATARS_QUEUE *pmraaqAvatarsQueue = (MRA_AVATARS_QUEUE*)hAvatarsQueueHandle; + + DWORD dwAvatarFormat = GetContactAvatarFormat(hContact, PA_FORMAT_UNKNOWN); + if ( db_get_b(NULL, MRA_AVT_SECT_NAME, "DeleteAvtOnContactDelete", MRA_DELETE_AVT_ON_CONTACT_DELETE) && dwAvatarFormat != PA_FORMAT_DEFAULT) { + TCHAR szFileName[MAX_FILEPATH]; + if ( !MraAvatarsGetFileName(hAvatarsQueueHandle, hContact, dwAvatarFormat, szFileName, SIZEOF(szFileName), NULL)) + return DeleteFile(szFileName); + } + return NO_ERROR; +} diff --git a/protocols/MRA/src/MraAvatars.h b/protocols/MRA/src/MraAvatars.h new file mode 100644 index 0000000000..67c0eff121 --- /dev/null +++ b/protocols/MRA/src/MraAvatars.h @@ -0,0 +1,16 @@ +#if !defined(AFX_MRA_AVATARS_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_) +#define AFX_MRA_AVATARS_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_ + + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define PA_FORMAT_DEFAULT 255 // return file name of def avatar +#define GetContactAvatarFormat(hContact, dwDefaultFormat) mraGetByte(hContact, "AvatarType", dwDefaultFormat) +#define SetContactAvatarFormat(hContact, dwFormat) mraSetByte(hContact, "AvatarType", (BYTE)dwFormat) + +INT_PTR CALLBACK MraAvatarsQueueDlgProcOpts(HWND hWndDlg, UINT msg, WPARAM wParam, LPARAM lParam); + + +#endif // !defined(AFX_MRA_AVATARS_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_) diff --git a/protocols/MRA/src/MraChat.cpp b/protocols/MRA/src/MraChat.cpp new file mode 100644 index 0000000000..30cac7690d --- /dev/null +++ b/protocols/MRA/src/MraChat.cpp @@ -0,0 +1,285 @@ +#include "Mra.h" +#include "MraChat.h" +#include "proto.h" + +static LPWSTR lpwszStatuses[] = { L"Owners", L"Inviter", L"Visitors" }; +#define MRA_CHAT_STATUS_OWNER 0 +#define MRA_CHAT_STATUS_INVITER 1 +#define MRA_CHAT_STATUS_VISITOR 2 + +void MraChatSendPrivateMessage(LPWSTR lpwszEMail); + +void CMraProto::MraChatDllError() +{ + MessageBoxW(NULL, TranslateW(L"CHAT plugin is required for conferences. Install it before chatting"), m_tszUserName, (MB_OK|MB_ICONWARNING)); +} + +BOOL CMraProto::MraChatRegister() +{ + if ( !ServiceExists(MS_GC_REGISTER)) + return FALSE; + + GCREGISTER gcr = {0}; + gcr.cbSize = sizeof(GCREGISTER); + gcr.dwFlags = GC_UNICODE; + gcr.iMaxText = MRA_MAXLENOFMESSAGE; + gcr.nColors = 0; + gcr.ptszModuleDispName = m_tszUserName; + gcr.pszModule = m_szModuleName; + CallServiceSync(MS_GC_REGISTER, NULL, (LPARAM)&gcr); + + HookEvent(ME_GC_EVENT, &CMraProto::MraChatGcEventHook); + return TRUE; +} + +INT_PTR CMraProto::MraChatSessionNew(HANDLE hContact) +{ + if (bChatExists) + if (hContact) { + GCSESSION gcw = {0}; + WCHAR wszEMail[MAX_EMAIL_LEN] = {0}; + + gcw.cbSize = sizeof(GCSESSION); + gcw.iType = GCW_CHATROOM; + gcw.pszModule = m_szModuleName; + gcw.ptszName = GetContactNameW(hContact); + gcw.ptszID = (LPWSTR)wszEMail; + gcw.ptszStatusbarText = L"status bar"; + gcw.dwFlags = GC_UNICODE; + gcw.dwItemData = (DWORD)hContact; + mraGetStaticStringW(hContact, "e-mail", wszEMail, SIZEOF(wszEMail), NULL); + if ( !CallServiceSync(MS_GC_NEWSESSION, NULL, (LPARAM)&gcw)) { + CHAR szEMail[MAX_EMAIL_LEN] = {0}; + size_t dwEMailSize; + GCDEST gcd = {0}; + GCEVENT gce = {0}; + + gcd.pszModule = m_szModuleName; + gcd.ptszID = (LPWSTR)wszEMail; + gcd.iType = GC_EVENT_ADDGROUP; + + gce.cbSize = sizeof(GCEVENT); + gce.pDest = &gcd; + gce.dwFlags = GC_UNICODE; + for (int i = 0; i < SIZEOF(lpwszStatuses); i++) { + gce.ptszStatus = TranslateW(lpwszStatuses[i]); + CallServiceSync(MS_GC_EVENT, NULL, (LPARAM)&gce); + } + + gce.cbSize = sizeof(GCEVENT); + gce.pDest = &gcd; + gcd.iType = GC_EVENT_CONTROL; + + CallServiceSync(MS_GC_EVENT, SESSION_INITDONE, (LPARAM)&gce); + CallServiceSync(MS_GC_EVENT, SESSION_ONLINE, (LPARAM)&gce); + + //MraChatSessionJoinUser(hContact, NULL, 0, 0); + (*(DWORD*)wszEMail) = MULTICHAT_GET_MEMBERS; + mraGetStaticStringA(hContact, "e-mail", szEMail, SIZEOF(szEMail), &dwEMailSize); + MraMessageW(FALSE, NULL, 0, MESSAGE_FLAG_MULTICHAT, szEMail, dwEMailSize, NULL, 0, (LPBYTE)wszEMail, 4); + return 0; + } + } + return 1; +} + +void CMraProto::MraChatSessionDestroy(HANDLE hContact) +{ + if ( !bChatExists) + return; + + GCDEST gcd = {0}; + GCEVENT gce = {0}; + WCHAR wszEMail[MAX_EMAIL_LEN] = {0}; + + gcd.pszModule = m_szModuleName; + gcd.iType = GC_EVENT_CONTROL; + if (hContact) { + gcd.ptszID = (LPWSTR)wszEMail; + mraGetStaticStringW(hContact, "e-mail", wszEMail, SIZEOF(wszEMail), NULL); + } + gce.cbSize = sizeof(GCEVENT); + gce.pDest = &gcd; + gce.dwFlags = GC_UNICODE; + + CallServiceSync(MS_GC_EVENT, SESSION_TERMINATE, (LPARAM)&gce); + CallServiceSync(MS_GC_EVENT, WINDOW_CLEARLOG, (LPARAM)&gce); +} + +INT_PTR CMraProto::MraChatSessionEventSendByHandle(HANDLE hContactChatSession, DWORD dwType, DWORD dwFlags, LPSTR lpszUID, size_t dwUIDSize, LPWSTR lpwszStatus, LPWSTR lpwszMessage, DWORD_PTR dwItemData, DWORD dwTime) +{ + if (!bChatExists) + return 1; + + WCHAR wszID[MAX_EMAIL_LEN] = {0}, wszUID[MAX_EMAIL_LEN] = {0}, wszNick[MAX_EMAIL_LEN] = {0}; + + GCDEST gcd = {0}; + gcd.pszModule = m_szModuleName; + if (hContactChatSession) { + gcd.ptszID = (LPWSTR)wszID; + mraGetStaticStringW(hContactChatSession, "e-mail", wszID, SIZEOF(wszID), NULL); + } + gcd.iType = dwType; + + GCEVENT gce = {0}; + gce.cbSize = sizeof(GCEVENT); + gce.pDest = &gcd; + gce.dwFlags = GC_UNICODE|dwFlags; + gce.ptszUID = wszUID; + gce.ptszStatus = lpwszStatus; + gce.ptszText = lpwszMessage; + gce.dwItemData = dwItemData; + gce.time = dwTime; + + if (lpszUID && dwUIDSize) + gce.bIsMe = IsEMailMy(lpszUID, dwUIDSize); + else + gce.bIsMe = TRUE; + + if (gce.bIsMe) { + mraGetStaticStringW(NULL, "e-mail", wszUID, SIZEOF(wszUID), NULL); + mraGetStaticStringW(NULL, "Nick", wszNick, SIZEOF(wszNick), NULL); + gce.ptszNick = wszNick; + } + else { + HANDLE hContactSender = MraHContactFromEmail(lpszUID, dwUIDSize, FALSE, TRUE, NULL); + MultiByteToWideChar(MRA_CODE_PAGE, 0, lpszUID, (DWORD)dwUIDSize, wszUID, SIZEOF(wszUID)); + if (hContactSender) + gce.ptszNick = GetContactNameW(hContactSender); + else + gce.ptszNick = wszUID; + } + + return CallServiceSync(MS_GC_EVENT, NULL, (LPARAM)&gce); +} + +INT_PTR CMraProto::MraChatSessionInvite(HANDLE hContactChatSession, LPSTR lpszEMailInMultiChat, size_t dwEMailInMultiChatSize, DWORD dwTime) +{ + if (!hContactChatSession) + return 1; + + WCHAR wszBuff[((MAX_EMAIL_LEN*2)+MAX_PATH)]; + mir_sntprintf(wszBuff, SIZEOF(wszBuff), L"[%s]: %s", _A2T(lpszEMailInMultiChat), TranslateW(L"invite sender")); + return MraChatSessionEventSendByHandle(hContactChatSession, GC_EVENT_ACTION, GCEF_ADDTOLOG, lpszEMailInMultiChat, dwEMailInMultiChatSize, NULL, wszBuff, 0, dwTime); +} + +INT_PTR CMraProto::MraChatSessionMembersAdd(HANDLE hContactChatSession, LPSTR lpszEMailInMultiChat, size_t dwEMailInMultiChatSize, DWORD dwTime) +{ + if (!hContactChatSession) + return 1; + + WCHAR wszBuff[((MAX_EMAIL_LEN*2)+MAX_PATH)]; + mir_sntprintf(wszBuff, SIZEOF(wszBuff), L"[%s]: %s", _A2T(lpszEMailInMultiChat), TranslateW(L"invite new members")); + return MraChatSessionEventSendByHandle(hContactChatSession, GC_EVENT_ACTION, GCEF_ADDTOLOG, lpszEMailInMultiChat, dwEMailInMultiChatSize, NULL, wszBuff, 0, dwTime); +} + +INT_PTR CMraProto::MraChatSessionJoinUser(HANDLE hContactChatSession, LPSTR lpszEMailInMultiChat, size_t dwEMailInMultiChatSize, DWORD dwTime) +{ + if (hContactChatSession) + return MraChatSessionEventSendByHandle(hContactChatSession, GC_EVENT_JOIN, GCEF_ADDTOLOG, lpszEMailInMultiChat, dwEMailInMultiChatSize, lpwszStatuses[MRA_CHAT_STATUS_VISITOR], L"", 0, dwTime); + + return 1; +} + +INT_PTR CMraProto::MraChatSessionLeftUser(HANDLE hContactChatSession, LPSTR lpszEMailInMultiChat, size_t dwEMailInMultiChatSize, DWORD dwTime) +{ + if (hContactChatSession) + return MraChatSessionEventSendByHandle(hContactChatSession, GC_EVENT_PART, GCEF_ADDTOLOG, lpszEMailInMultiChat, dwEMailInMultiChatSize, NULL, NULL, 0, dwTime); + + return 1; +} + +INT_PTR CMraProto::MraChatSessionSetIviter(HANDLE hContactChatSession, LPSTR lpszEMailInMultiChat, size_t dwEMailInMultiChatSize) +{ + if (hContactChatSession && lpszEMailInMultiChat && dwEMailInMultiChatSize) + return MraChatSessionEventSendByHandle(hContactChatSession, GC_EVENT_ADDSTATUS, 0, lpszEMailInMultiChat, dwEMailInMultiChatSize, lpwszStatuses[MRA_CHAT_STATUS_INVITER], NULL, 0, 0); + + return 1; +} + +INT_PTR CMraProto::MraChatSessionSetOwner(HANDLE hContactChatSession, LPSTR lpszEMailInMultiChat, size_t dwEMailInMultiChatSize) +{ + if (hContactChatSession && lpszEMailInMultiChat && dwEMailInMultiChatSize) + return MraChatSessionEventSendByHandle(hContactChatSession, GC_EVENT_ADDSTATUS, 0, lpszEMailInMultiChat, dwEMailInMultiChatSize, lpwszStatuses[MRA_CHAT_STATUS_OWNER], NULL, 0, 0); + + return 1; +} + + +INT_PTR CMraProto::MraChatSessionMessageAdd(HANDLE hContactChatSession, LPSTR lpszEMailInMultiChat, size_t dwEMailInMultiChatSize, LPWSTR lpwszMessage, size_t dwMessageSize, DWORD dwTime) +{ + if (hContactChatSession) { + LPWSTR lpwszMessageLocal = (LPWSTR)_alloca((dwMessageSize*sizeof(WCHAR))); + if (lpwszMessageLocal) { // we need zeros after text allways + memmove((LPVOID)lpwszMessageLocal, lpwszMessage, (dwMessageSize*sizeof(WCHAR)));//gce.ptszText = lpwszMessage; + return MraChatSessionEventSendByHandle(hContactChatSession, GC_EVENT_MESSAGE, GCEF_ADDTOLOG, lpszEMailInMultiChat, dwEMailInMultiChatSize, NULL, lpwszMessageLocal, 0, dwTime); + } + } + return 1; +} + +int CMraProto::MraChatGcEventHook(WPARAM, LPARAM lParam) +{ + if (lParam) + if (bChatExists) { + GCHOOK* gch = (GCHOOK*)lParam; + + if ( !_stricmp(gch->pDest->pszModule, m_szModuleName)) { + switch (gch->pDest->iType) { + case GC_USER_MESSAGE: + if (gch->ptszText && lstrlen(gch->ptszText)) { + CHAR szEMail[MAX_EMAIL_LEN] = {0}; + + size_t dwMessageSize = lstrlenW(gch->ptszText); + size_t dwEMailSize = (WideCharToMultiByte(MRA_CODE_PAGE, 0, gch->pDest->ptszID, -1, szEMail, SIZEOF(szEMail), NULL, NULL)-1); + HANDLE hContact = MraHContactFromEmail(szEMail, dwEMailSize, FALSE, TRUE, NULL); + BOOL bSlowSend = mraGetByte(NULL, "SlowSend", MRA_DEFAULT_SLOW_SEND); + + DWORD dwFlags = 0; + if (mraGetByte(NULL, "RTFSendEnable", MRA_DEFAULT_RTF_SEND_ENABLE) && (MraContactCapabilitiesGet(hContact)&FEATURE_FLAG_RTF_MESSAGE)) + dwFlags |= MESSAGE_FLAG_RTF; + + INT_PTR iSendRet = MraMessageW(bSlowSend, hContact, ACKTYPE_MESSAGE, dwFlags, szEMail, dwEMailSize, gch->ptszText, dwMessageSize, NULL, 0); + if (bSlowSend == FALSE) + ProtoBroadcastAckAsync(hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE)iSendRet, 0); + + MraChatSessionEventSendByHandle(hContact, GC_EVENT_MESSAGE, GCEF_ADDTOLOG, NULL, 0, NULL, gch->ptszText, 0, (DWORD)_time32(NULL)); + } + break; + + case GC_USER_PRIVMESS: + MraChatSendPrivateMessage(gch->ptszUID); + break; + + case GC_USER_LOGMENU: + //sttLogListHook( this, item, gch ); + break; + + case GC_USER_NICKLISTMENU: + //sttNickListHook( this, item, gch ); + break; + + case GC_USER_CHANMGR: + //int iqId = SerialNext(); + //IqAdd( iqId, IQ_PROC_NONE, &CJabberProto::OnIqResultGetMuc ); + //m_ThreadInfo->send( XmlNodeIq( _T("get"), iqId, item->jid ) << XQUERY( xmlnsOwner )); + break; + } + } + } + return 0; +} + +void CMraProto::MraChatSendPrivateMessage(LPWSTR lpwszEMail) +{ + CHAR szEMail[MAX_EMAIL_LEN] = {0}; + size_t dwEMailSize = WideCharToMultiByte(MRA_CODE_PAGE, 0, lpwszEMail, -1, szEMail, SIZEOF(szEMail), NULL, NULL)-1; + + BOOL bAdded; + HANDLE hContact = MraHContactFromEmail(szEMail, dwEMailSize, TRUE, TRUE, &bAdded); + if (bAdded) + DBWriteContactSettingByte(hContact, "CList", "Hidden", 1); + + CallService(MS_IGNORE_UNIGNORE, (WPARAM)hContact, IGNOREEVENT_ALL); + CallService(MS_MSG_SENDMESSAGE, (WPARAM)hContact, 0); +} diff --git a/protocols/MRA/src/MraChat.h b/protocols/MRA/src/MraChat.h new file mode 100644 index 0000000000..790c16584a --- /dev/null +++ b/protocols/MRA/src/MraChat.h @@ -0,0 +1,9 @@ +#if !defined(AFX_MRA_CHAT_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_) +#define AFX_MRA_CHAT_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_ + + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#endif // !defined(AFX_MRA_CHAT_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_) diff --git a/protocols/MRA/src/MraConstans.h b/protocols/MRA/src/MraConstans.h new file mode 100644 index 0000000000..17b73e5642 --- /dev/null +++ b/protocols/MRA/src/MraConstans.h @@ -0,0 +1,281 @@ +#if !defined(AFX_MRA_CONSTANS_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_) +#define AFX_MRA_CONSTANS_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_ + +#include "proto.h" + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define PROTOCOL_DISPLAY_NAME_ORIGA "Mail.ru Agent" + +#define MIRVER_UNKNOWN ("Mail.ru Agent unknown client") + +#define MRA_PLUGIN_UPDATER_ID 2544 //появляется после первого выкладывания на сайт +#define MRA_SERVER_PORT_STANDART_NLB 2042 +#define MRA_SERVER_PORT_STANDART 2041 +#define MRA_SERVER_PORT_HTTPS 443 +static const LPSTR lpcszMailRuDomains[] = +{ + ("mail.ru"), + ("list.ru"), + ("bk.ru"), + ("inbox.ru"), + ("corp.mail.ru"), + NULL +}; +#define MAILRU_CHAT_CONF_DOMAIN "chat.agent" + + +#define MAX_EMAIL_LEN 1024 +#define MAX_FILEPATH 32768 //internal +#define BUFF_SIZE_RCV 65535 //internal +#define BUFF_SIZE_RCV_MIN_FREE 16384 //internal +#define BUFF_SIZE_BLOB 16384 //internal +#define BUFF_SIZE_URL 4096 //internal +#define NETLIB_SELECT_TIMEOUT 250 //internal // время ожидания событий на сокете +#define WAIT_FOR_THREAD_TIMEOUT 15 //internal // время ожидания завершения потока +#define THREAD_SLEEP_TIME 100 //internal +#define THREAD_MAX_PING_TIME 20 // sec, internal +#define THREAD_MAX_PING_FAIL_COUNT 3 // internal +#define SEND_QUEUE_TIMEOUT 600 //internal // время удаления недоставленных сообщений из очереди отправки +#define ALLOCATED_COUNT 32 //internal // колличество элементов +#define EMAILS_MIN_COUNT 16 //internal // колличество элементов обязательно проверяемых при извлечении email адреса из инфы юзера +#define PHONES_MIN_COUNT 4 //internal // колличество элементов обязательно проверяемых при извлечении email адреса из инфы юзера + +#define MRA_ALARM_MESSAGE L"Your contact wakes you" + +#define MRA_GOTO_INBOX "/GotoInbox" +#define MRA_GOTO_INBOX_STR L"Display &Inbox" +#define MRA_SHOW_INBOX_STATUS "/ShowInboxStatus" +#define MRA_SHOW_INBOX_STATUS_STR L"Display &Inbox status" +#define MRA_EDIT_PROFILE "/EditProfile" +#define MRA_EDIT_PROFILE_STR L"Edit &Profile" +#define MRA_MY_ALBUM "/MyAlbum" +#define MRA_MY_ALBUM_STR L"My Album" +#define MRA_MY_BLOG "/MyBlog" +#define MRA_MY_BLOG_STR L"My Blog" +#define MRA_MY_BLOGSTATUS "/MyBlogStatus" +#define MRA_MY_BLOGSTATUS_STR L"My Blog Status" +#define MRA_MY_VIDEO "/MyVideo" +#define MRA_MY_VIDEO_STR L"My Video" +#define MRA_MY_ANSWERS "/MyAnswers" +#define MRA_MY_ANSWERS_STR L"My Answers" +#define MRA_MY_WORLD "/MyWorld" +#define MRA_MY_WORLD_STR L"My World" +#define MRA_ZHUKI "/Zhuki" +#define MRA_ZHUKI_STR L"Zhuki" +#define MRA_CHAT "/Chat" +#define MRA_CHAT_STR L"Chat" +#define MRA_WEB_SEARCH "/WebSearch" +#define MRA_WEB_SEARCH_STR L"Web search" +#define MRA_UPD_ALL_USERS_INFO "/UpdateAllUsersInfo" +#define MRA_UPD_ALL_USERS_INFO_STR L"Update all users info" +#define MRA_CHK_USERS_AVATARS "/CheckUpdatesUsersAvatars" +#define MRA_CHK_USERS_AVATARS_STR L"Check updates users avatars" +#define MRA_REQ_AUTH_FOR_ALL "/ReqAuthForAll" +#define MRA_REQ_AUTH_FOR_ALL_STR L"Request authorization for all" + +#define MRA_MPOP_AUTH_URL "http://swa.mail.ru/cgi-bin/auth?Login = %s&agent = %s&page = %s" + +#define MRA_WIN_INBOX_URL "http://win.mail.ru/cgi-bin/start" +#define MRA_PDA_INBOX_URL "http://pda.mail.ru/cgi-bin/start" +#define MRA_EDIT_PROFILE_URL "http://win.mail.ru/cgi-bin/userinfo?mra = 1" +#define MRA_CHAT_URL "http://chat.mail.ru" +#define MRA_ZHUKI_URL "http://zhuki.mail.ru" +#define MRA_SEARCH_URL "http://go.mail.ru" + +// used spesialy! added: /domain/user +#define MRA_BLOGS_URL "http://blogs.mail.ru" +#define MRA_FOTO_URL "http://foto.mail.ru" +#define MRA_VIDEO_URL "http://video.mail.ru" +#define MRA_ANSWERS_URL "http://otvet.mail.ru" +#define MRA_WORLD_URL "http://my.mail.ru" + +// without auth +#define MRA_REGISTER_URL "http://win.mail.ru/cgi-bin/signup" +#define MRA_FORGOT_PASSWORD_URL "http://win.mail.ru/cgi-bin/passremind" + + +// wParam = (WPARAM)hContact +#define MRA_REQ_AUTH "/ReqAuth" +#define MRA_REQ_AUTH_STR L"Request authorization" +#define MRA_GRANT_AUTH "/GrantAuth" +#define MRA_GRANT_AUTH_STR L"Grant authorization" +#define MRA_SEND_POSTCARD "/SendPostcard" +#define MRA_SEND_POSTCARD_STR L"&Send postcard" +#define MRA_VIEW_ALBUM "/ViewAlbum" +#define MRA_VIEW_ALBUM_STR L"&View Album" +#define MRA_READ_BLOG "/ReadBlog" +#define MRA_READ_BLOG_STR L"&Read Blog" +#define MRA_REPLY_BLOG_STATUS "/ReplyBlogStatus" +#define MRA_REPLY_BLOG_STATUS_STR L"Reply Blog Status" +#define MRA_VIEW_VIDEO "/ViewVideo" +#define MRA_VIEW_VIDEO_STR L"View Video" +#define MRA_ANSWERS "/Answers" +#define MRA_ANSWERS_STR L"Answers" +#define MRA_WORLD "/World" +#define MRA_WORLD_STR L"World" +#define MRA_SEND_NUDGE "/SendNudge" +#define MS_NUDGE "/Nudge" +#define MRA_SENDNUDGE_STR L"Send &Nudge" + + +#define ADV_ICON_DELETED 0 +#define ADV_ICON_DELETED_ID "ADV_ICON_DELETED" +#define ADV_ICON_DELETED_STR L"Mail box deleted" +#define ADV_ICON_NOT_ON_SERVER 1 +#define ADV_ICON_NOT_ON_SERVER_ID "ADV_ICON_NOT_ON_SERVER" +#define ADV_ICON_NOT_ON_SERVER_STR L"Contact not on server" +#define ADV_ICON_NOT_AUTHORIZED 2 +#define ADV_ICON_NOT_AUTHORIZED_ID "ADV_ICON_NOT_AUTHORIZED" +#define ADV_ICON_NOT_AUTHORIZED_STR L"Not authorized" +#define ADV_ICON_PHONE 3 +#define ADV_ICON_PHONE_ID "ADV_ICON_PHONE" +#define ADV_ICON_PHONE_STR L"Phone/SMS only contact" +#define ADV_ICON_BLOGSTATUS 4 +#define ADV_ICON_BLOGSTATUS_ID "ADV_ICON_BLOGSTATUS" +#define ADV_ICON_BLOGSTATUS_STR L"Blog status message" + +#define MRA_SOUND_NEW_EMAIL "New E-mail available in Inbox" + +#define MAILRU_SERVER_TIME_ZONE -180 //internal // +0300 +#define MAILRU_CONTACTISTYPING_TIMEOUT 10 //internal +#define MRA_DEFAULT_SERVER "mrim.mail.ru" +#define MRA_DEFAULT_SERVER_PORT MRA_SERVER_PORT_STANDART_NLB +#define MRA_MAX_MRIM_SERVER 46 +#define MRA_DEFAULT_TIMEOUT_CONN_MRIM 20 +#define MRA_DEFAULT_CONN_RETRY_COUNT_MRIM 2 +#define MRA_DEFAULT_TIMEOUT_CONN_NLB 20 +#define MRA_DEFAULT_CONN_RETRY_COUNT_NLB 3 +#define MRA_DEFAULT_TIMEOUT_RECV_NLB 20 +#define MRA_DEFAULT_CONN_RETRY_COUNT_FILES 2 +#define MRA_DEFAULT_CONN_RETRY_COUNT_MRIMPROXY 3 +#define MRA_TIMEOUT_DIRECT_CONN 30 //internal; время после которого клиент считает что к нему подключится не удалось +#define MRA_TIMEOUT_CONN_MIN 2 //internal; минимальное время ожидания пока устанавливается исходящее подключение +#define MRA_TIMEOUT_CONN_МАХ 16 //internal; максимальное время ожидания пока устанавливается исходящее подключение +#define MRA_MAXLENOFMESSAGE 32768 //internal +#define MRA_MAXCONTACTSPERPACKET 256 //internal +#define MRA_CODE_PAGE 1251 //internal +#define MRA_FEATURE_FLAGS (FEATURE_FLAG_BASE_SMILES|FEATURE_FLAG_ADVANCED_SMILES|FEATURE_FLAG_CONTACTS_EXCH|FEATURE_FLAG_WAKEUP|FEATURE_FLAG_MULTS|FEATURE_FLAG_FILE_TRANSFER|FEATURE_FLAG_GAMES) + +#define MRA_DEFAULT_POPUPS_ENABLED TRUE +#define MRA_DEFAULT_POPUPS_EVENT_FILTER -1 +#define MRA_DEFAULT_POPUP_TIMEOUT 8 +#define MRA_DEFAULT_POPUP_USE_WIN_COLORS TRUE +#define MRA_DEFAULT_POPUP_COLOR_BACK RGB(191, 0, 0) //Red +#define MRA_DEFAULT_POPUP_COLOR_TEXT RGB(255, 245, 225) //Yellow + +#define MRA_DEFAULT_NLB_FAIL_DIRECT_CONNECT FALSE // hidden option +#define MRA_DEFAULT_AUTO_ADD_CONTACTS_TO_SERVER TRUE +#define MRA_DEFAULT_AUTO_AUTH_REQ_ON_LOGON FALSE +#define MRA_DEFAULT_AUTO_AUTH_GRAND_IN_CLIST FALSE +#define MRA_DEFAULT_AUTO_AUTH_GRAND_NEW_USERS FALSE +#define MRA_DEFAULT_AUTO_AUTH_GRAND_NEW_USERS_DISABLE_SPAM_CHECK FALSE +#define MRA_DEFAULT_SLOW_SEND TRUE +#define MRA_DEFAULT_CVT_SMILES_TO_TAGS TRUE +#define MRA_DEFAULT_MIRVER_RAW FALSE // hidden option +#define MRA_DEFAULT_AUTH_MESSAGE L"Please authorize me" + +#define MRA_DEFAULT_RTF_RECEIVE_ENABLE FALSE +#define MRA_DEFAULT_RTF_SEND_ENABLE TRUE +#define MRA_DEFAULT_RTF_SEND_SMART TRUE +#define MRA_DEFAULT_RTF_BACKGROUND_COLOUR RGB(255, 255, 255) +#define MRA_DEFAULT_RTF_FONT_COLOUR RGB(255, 0, 0) +#define MRA_DEFAULT_RTF_FONT_SIZE 12 +#define MRA_DEFAULT_RTF_FONT_CHARSET RUSSIAN_CHARSET +#define MRA_DEFAULT_RTF_FONT_NAME L"Tahoma" + +#define MRA_DEFAULT_SEARCH_REMEMBER TRUE +#define MRA_DEFAULT_LAST_SEARCH_COUTRY 0 + + +#define MRA_DEFAULT_FILE_SEND_BLOCK_SIZE 8192 //hidden, размер блока при отправке файла + +#define MRA_DEFAULT_HIDE_MENU_ITEMS_FOR_NON_MRA FALSE + +#define MRA_DEFAULT_INC_NEW_MAIL_NOTIFY FALSE +#define MRA_DEFAULT_TRAYICON_NEW_MAIL_NOTIFY FALSE +#define MRA_DEFAULT_TRAYICON_NEW_MAIL_CLK_TO_INBOX FALSE + +#define MRA_ANTISPAM_DEFAULT_ENABLE TRUE +#define MRA_ANTISPAM_DEFAULT_CHK_TEMP_CONTACTS TRUE +#define MRA_ANTISPAM_DEFAULT_DELETE_SPAMBOT_CONTACT FALSE +#define MRA_ANTISPAM_DEFAULT_CLN_NON_ALPHNUM TRUE +#define MRA_ANTISPAM_DEFAULT_MAX_LNG_CHANGES 5 +#define MRA_ANTISPAM_DEFAULT_SHOWPOP TRUE +#define MRA_ANTISPAM_DEFAULT_WRITETOSYSTEMHISTORY TRUE +#define MRA_ANTISPAM_DEFAULT_SEND_SPAM_REPORT_TO_SERVER TRUE + +#define MRA_AVT_DEFAULT_ENABLE TRUE +#define MRA_AVT_DEFAULT_WRK_THREAD_COUNTS 4 // hidden +#define MRA_AVT_DEFAULT_SERVER "obraz.foto.mail.ru" +#define MRA_AVT_DEFAULT_SERVER_PORT 80 +#define MRA_AVT_DEFAULT_TIMEOUT_CONN 10 +#define MRA_AVT_DEFAULT_CONN_RETRY_COUNT 3 +#define MRA_AVT_DEFAULT_TIMEOUT_RECV 30 +#define MRA_AVT_DEFAULT_USE_KEEPALIVE_CONN TRUE +#define MRA_AVT_DEFAULT_CHK_INTERVAL 60 +#define MRA_AVT_DEFAULT_AVT_FILENAME _T("_default.jpg") +#define MRA_AVT_DEFAULT_RET_ABC_PATH TRUE +#define MRA_DELETE_AVT_ON_CONTACT_DELETE TRUE +#define MRA_AVT_DEFAULT_QE_CHK_INTERVAL 1000 //internal + +#define MRA_FILES_QUEUE_PROGRESS_INTERVAL 250 //internal +#define MRA_FILES_NULL_ADDRR "192.168.0.1:26666;" +#define MRA_DEF_FS_TIMEOUT_RECV 600 +#define MRA_DEF_FS_ENABLE_DIRECT_CONN TRUE +#define MRA_DEF_FS_NO_OUT_CONN_ON_RCV FALSE +#define MRA_DEF_FS_NO_OUT_CONN_ON_SEND FALSE +#define MRA_DEF_FS_IGNORY_ADDITIONAL_PORTS FALSE +#define MRA_DEF_FS_HIDE_MY_ADDRESSES FALSE +#define MRA_DEF_FS_ADD_EXTRA_ADDRESSES FALSE +#define MRA_DEF_FS_ENABLE_MRIM_PROXY_CONS TRUE + +#define PS_GETMYAVATAR "/GetMyAvatar" +//wParam = (char *)Buffer to file name +//lParam = (int)Buffer size +//return = 0 for sucess + +#define ICQACKTYPE_SMS 1001 +#define ICQEVENTTYPE_SMS 2001 //database event type +#define MS_ICQ_SENDSMS "/SendSMS" + +// Database setting names +#define DBSETTING_CAPABILITIES "caps" +#define DBSETTING_XSTATUSID "XStatusId" +#define DBSETTING_XSTATUSNAME "XStatusName" +#define DBSETTING_XSTATUSMSG "XStatusMsg" +#define DBSETTING_BLOGSTATUSTIME "BlogStatusTime" +#define DBSETTING_BLOGSTATUSID "BlogStatusID" +#define DBSETTING_BLOGSTATUS "BlogStatus" +#define DBSETTING_BLOGSTATUSMUSIC "ListeningTo" + +#define CSSF_MASK_STATUS 0x0001 // status member valid for set/get +#define CSSF_MASK_NAME 0x0002 // pszName member valid for set/get +#define CSSF_MASK_MESSAGE 0x0004 // pszMessage member valid for set/get +#define CSSF_DISABLE_UI 0x0040 // disable default custom status UI, wParam = bEnable +#define CSSF_DEFAULT_NAME 0x0080 // only with CSSF_MASK_NAME and get API to get default custom status name (wParam = status) +#define CSSF_STATUSES_COUNT 0x0100 // returns number of custom statuses in wParam, only get API +#define CSSF_STR_SIZES 0x0200 // returns sizes of custom status name & message (wParam & lParam members) in chars +#define CSSF_UNICODE 0x1000 // strings are in UCS-2 + +extern const LPSTR lpcszStatusUri[]; +extern const LPWSTR lpcszXStatusNameDef[]; + +#define MRA_XSTATUS_MENU "/menuXStatus" +#define MRA_XSTATUS_COUNT 50 +#define MRA_MIR_XSTATUS_NONE 0 +#define MRA_MIR_XSTATUS_UNKNOWN MRA_XSTATUS_COUNT + +#define MRA_XSTATUS_OFFLINE 0 +#define MRA_XSTATUS_ONLINE 1 +#define MRA_XSTATUS_AWAY 2 +#define MRA_XSTATUS_INVISIBLE 3 +#define MRA_XSTATUS_DND 4 +#define MRA_XSTATUS_CHAT 5 +#define MRA_XSTATUS_UNKNOWN 55 + +#define MRA_XSTATUS_INDEX_OFFSET 6 + +#endif // !defined(AFX_MRA_CONSTANS_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_) diff --git a/protocols/MRA/src/MraFilesQueue.cpp b/protocols/MRA/src/MraFilesQueue.cpp new file mode 100644 index 0000000000..539bf9562d --- /dev/null +++ b/protocols/MRA/src/MraFilesQueue.cpp @@ -0,0 +1,1203 @@ +#include "Mra.h" +#include "MraFilesQueue.h" +#include "proto.h" + +#define MRA_FT_HELLO "MRA_FT_HELLO" +#define MRA_FT_GET_FILE "MRA_FT_GET_FILE" + +struct MRA_FILES_QUEUE : public LIST_MT +{ + DWORD dwSendTimeOutInterval; +}; + +struct MRA_FILES_QUEUE_FILE +{ + LPWSTR lpwszName; + size_t dwNameLen; + DWORDLONG dwSize; +}; + +struct MRA_FILES_QUEUE_ITEM : public LIST_MT_ITEM +{ + // internal + BOOL bIsWorking; + DWORD dwSendTime; + + // external + CMraProto *ppro; + DWORD dwIDRequest; + DWORD dwFlags; + HANDLE hContact; + DWORDLONG dwFilesCount; + DWORDLONG dwFilesTotalSize; + MRA_FILES_QUEUE_FILE *pmfqfFiles; + LPWSTR pwszFilesList; + LPWSTR pwszDescription; + MRA_ADDR_LIST malAddrList; + LPWSTR lpwszPath; + size_t dwPathSize; + BOOL bSending; + HANDLE hConnection; + HANDLE hListen; + HANDLE hThread; + HANDLE hWaitHandle; + HANDLE hMraMrimProxyData; +}; + +struct MRA_FILES_THREADPROC_PARAMS +{ + HANDLE hFilesQueueHandle; + MRA_FILES_QUEUE_ITEM *dat; +}; + +DWORD MraFilesQueueItemFindByID(HANDLE hFilesQueueHandle, DWORD dwIDRequest, MRA_FILES_QUEUE_ITEM **ppmrafqFilesQueueItem); +void MraFilesQueueItemFree(MRA_FILES_QUEUE_ITEM *dat); + +///////////////////////////////////////////////////////////////////////////////////////// +// File transfer options + +static WORD wMraFilesControlsList[] = { + IDC_FILE_SEND_NOOUTCONNECTIONONRECEIVE, + IDC_FILE_SEND_NOOUTCONNECTIONONSEND, + IDC_FILE_SEND_IGNORYADDITIONALPORTS, + IDC_FILE_SEND_HIDE_MY_ADDRESSES, + IDC_FILE_SEND_ADD_EXTRA_ADDRESS, + IDC_FILE_SEND_EXTRA_ADDRESS +}; + +void MraFilesQueueDlgEnableDirectConsControls(HWND hWndDlg, BOOL bEnabled) +{ + EnableControlsArray(hWndDlg, (WORD*)&wMraFilesControlsList, SIZEOF(wMraFilesControlsList), bEnabled); + EnableWindow(GetDlgItem(hWndDlg, IDC_FILE_SEND_EXTRA_ADDRESS), (bEnabled && IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_FILE_SEND_ADD_EXTRA_ADDRESS))); +} + +INT_PTR CALLBACK MraFilesQueueDlgProcOpts(HWND hWndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + CMraProto *ppro = (CMraProto*)GetWindowLongPtr(hWndDlg, GWLP_USERDATA); + + switch (msg) { + case WM_INITDIALOG: + TranslateDialogDefault(hWndDlg); + SetWindowLongPtr(hWndDlg, GWLP_USERDATA, lParam); + ppro = (CMraProto*)lParam; + { + WCHAR szBuff[MAX_PATH]; + CHECK_DLG_BUTTON(hWndDlg, IDC_FILE_SEND_ENABLE_DIRECT_CONN, ppro->mraGetByte(NULL, "FileSendEnableDirectConn", MRA_DEF_FS_ENABLE_DIRECT_CONN)); + CHECK_DLG_BUTTON(hWndDlg, IDC_FILE_SEND_NOOUTCONNECTIONONRECEIVE, ppro->mraGetByte(NULL, "FileSendNoOutConnOnRcv", MRA_DEF_FS_NO_OUT_CONN_ON_RCV)); + CHECK_DLG_BUTTON(hWndDlg, IDC_FILE_SEND_NOOUTCONNECTIONONSEND, ppro->mraGetByte(NULL, "FileSendNoOutConnOnSend", MRA_DEF_FS_NO_OUT_CONN_ON_SEND)); + CHECK_DLG_BUTTON(hWndDlg, IDC_FILE_SEND_IGNORYADDITIONALPORTS, ppro->mraGetByte(NULL, "FileSendIgnoryAdditionalPorts", MRA_DEF_FS_IGNORY_ADDITIONAL_PORTS)); + CHECK_DLG_BUTTON(hWndDlg, IDC_FILE_SEND_HIDE_MY_ADDRESSES, ppro->mraGetByte(NULL, "FileSendHideMyAddresses", MRA_DEF_FS_HIDE_MY_ADDRESSES)); + CHECK_DLG_BUTTON(hWndDlg, IDC_FILE_SEND_ADD_EXTRA_ADDRESS, ppro->mraGetByte(NULL, "FileSendAddExtraAddresses", MRA_DEF_FS_ADD_EXTRA_ADDRESSES)); + + if (ppro->mraGetStaticStringW(NULL, "FileSendExtraAddresses", szBuff, SIZEOF(szBuff), NULL)) + SET_DLG_ITEM_TEXT(hWndDlg, IDC_FILE_SEND_EXTRA_ADDRESS, szBuff); + + CHECK_DLG_BUTTON(hWndDlg, IDC_FILE_SEND_ENABLE_MRIMPROXY_CONS, ppro->mraGetByte(NULL, "FileSendEnableMRIMProxyCons", MRA_DEF_FS_ENABLE_MRIM_PROXY_CONS)); + + SetDlgItemInt(hWndDlg, IDC_FILE_SEND_BLOCK_SIZE, ppro->mraGetDword(NULL, "FileSendBlockSize", MRA_DEFAULT_FILE_SEND_BLOCK_SIZE), FALSE); + + MraFilesQueueDlgEnableDirectConsControls(hWndDlg, IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_FILE_SEND_ENABLE_DIRECT_CONN)); + } + return TRUE; + + case WM_COMMAND: + if (LOWORD(wParam) == IDC_FILE_SEND_ENABLE_DIRECT_CONN) + MraFilesQueueDlgEnableDirectConsControls(hWndDlg, IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_FILE_SEND_ENABLE_DIRECT_CONN)); + + if (LOWORD(wParam) == IDC_FILE_SEND_ADD_EXTRA_ADDRESS) + EnableWindow(GetDlgItem(hWndDlg, IDC_FILE_SEND_EXTRA_ADDRESS), IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_FILE_SEND_ADD_EXTRA_ADDRESS)); + + if ((LOWORD(wParam) == IDC_FILE_SEND_EXTRA_ADDRESS || LOWORD(wParam) == IDC_FILE_SEND_BLOCK_SIZE) && (HIWORD(wParam) != EN_CHANGE || (HWND)lParam != GetFocus())) return FALSE; + SendMessage(GetParent(hWndDlg), PSM_CHANGED, 0, 0); + break; + + case WM_NOTIFY: + switch (((LPNMHDR)lParam)->code) { + case PSN_APPLY: + { + WCHAR szBuff[MAX_PATH]; + + ppro->mraSetByte(NULL, "FileSendEnableDirectConn", IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_FILE_SEND_ENABLE_DIRECT_CONN)); + ppro->mraSetByte(NULL, "FileSendNoOutConnOnRcv", IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_FILE_SEND_NOOUTCONNECTIONONRECEIVE)); + ppro->mraSetByte(NULL, "FileSendNoOutConnOnSend", IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_FILE_SEND_NOOUTCONNECTIONONSEND)); + ppro->mraSetByte(NULL, "FileSendIgnoryAdditionalPorts", IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_FILE_SEND_IGNORYADDITIONALPORTS)); + ppro->mraSetByte(NULL, "FileSendHideMyAddresses", IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_FILE_SEND_HIDE_MY_ADDRESSES)); + ppro->mraSetByte(NULL, "FileSendAddExtraAddresses", IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_FILE_SEND_ADD_EXTRA_ADDRESS)); + GET_DLG_ITEM_TEXT(hWndDlg, IDC_FILE_SEND_EXTRA_ADDRESS, szBuff, SIZEOF(szBuff)); + ppro->mraSetStringW(NULL, "FileSendExtraAddresses", szBuff); + ppro->mraSetDword(NULL, "FileSendBlockSize", (DWORD)GetDlgItemInt(hWndDlg, IDC_FILE_SEND_BLOCK_SIZE, NULL, FALSE)); + ppro->mraSetByte(NULL, "FileSendEnableMRIMProxyCons", IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_FILE_SEND_ENABLE_MRIMPROXY_CONS)); + } + return TRUE; + } + break; + } + return FALSE; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// MRA files' queue + +DWORD MraFilesQueueInitialize(DWORD dwSendTimeOutInterval, HANDLE *phFilesQueueHandle) +{ + if (!phFilesQueueHandle) + return ERROR_INVALID_HANDLE; + + MRA_FILES_QUEUE *pmrafqFilesQueue = (MRA_FILES_QUEUE*)mir_calloc(sizeof(MRA_FILES_QUEUE)); + if (!pmrafqFilesQueue) + return GetLastError(); + + DWORD dwRetErrorCode = ListMTInitialize(pmrafqFilesQueue, 0); + if (dwRetErrorCode == NO_ERROR) { + pmrafqFilesQueue->dwSendTimeOutInterval = dwSendTimeOutInterval; + *phFilesQueueHandle = (HANDLE)pmrafqFilesQueue; + } + else mir_free(pmrafqFilesQueue); + + return dwRetErrorCode; +} + +void MraFilesQueueDestroy(HANDLE hFilesQueueHandle) +{ + if ( !hFilesQueueHandle) + return; + + MRA_FILES_QUEUE *pmrafqFilesQueue = (MRA_FILES_QUEUE*)hFilesQueueHandle; + MRA_FILES_QUEUE_ITEM *dat; + { + mt_lock l(pmrafqFilesQueue); + while ( ListMTItemGetFirst(pmrafqFilesQueue, NULL, (LPVOID*)&dat) == NO_ERROR) + MraFilesQueueItemFree(dat); + } + ListMTDestroy(pmrafqFilesQueue); + mir_free(pmrafqFilesQueue); +} + +DWORD MraFilesQueueItemFindByID(HANDLE hFilesQueueHandle, DWORD dwIDRequest, MRA_FILES_QUEUE_ITEM **ppmrafqFilesQueueItem) +{ + if (!hFilesQueueHandle) + return ERROR_INVALID_HANDLE; + + MRA_FILES_QUEUE *pmrafqFilesQueue = (MRA_FILES_QUEUE*)hFilesQueueHandle; + MRA_FILES_QUEUE_ITEM *dat; + LIST_MT_ITERATOR lmtiIterator; + + mt_lock l(pmrafqFilesQueue); + ListMTIteratorMoveFirst(pmrafqFilesQueue, &lmtiIterator); + do { + if (ListMTIteratorGet(&lmtiIterator, NULL, (LPVOID*)&dat) == NO_ERROR) + if (dat->dwIDRequest == dwIDRequest) { + if (ppmrafqFilesQueueItem) + *ppmrafqFilesQueueItem = dat; + return 0; + } + } + while (ListMTIteratorMoveNext(&lmtiIterator)); + + return ERROR_NOT_FOUND; +} + +HANDLE MraFilesQueueItemProxyByID(HANDLE hFilesQueueHandle, DWORD dwIDRequest) +{ + MRA_FILES_QUEUE_ITEM *dat; + if ( !MraFilesQueueItemFindByID(hFilesQueueHandle, dwIDRequest, &dat)) + return dat->hMraMrimProxyData; + + return NULL; +} + +void MraFilesQueueItemFree(MRA_FILES_QUEUE_ITEM *dat) +{ + LIST_MT *plmtListMT = (LIST_MT*)dat->lpListMT; + + for (size_t i = 0;idwFilesCount;i++) + mir_free(dat->pmfqfFiles[i].lpwszName); + + mir_free(dat->pmfqfFiles); + mir_free(dat->pwszFilesList); + mir_free(dat->pwszDescription); + MraAddrListFree(&dat->malAddrList); + MraMrimProxyFree(dat->hMraMrimProxyData); + mir_free(dat->lpwszPath); + { + mt_lock l(plmtListMT); + ListMTItemDelete(plmtListMT, dat); + } + mir_free(dat); +} + +size_t CMraProto::MraFilesQueueGetLocalAddressesList(LPSTR lpszBuff, size_t dwBuffSize, DWORD dwPort) +{ + CHAR szHostName[MAX_PATH] = {0}; + LPSTR lpszCurPos = lpszBuff; + + if (mraGetByte(NULL, "FileSendHideMyAddresses", MRA_DEF_FS_HIDE_MY_ADDRESSES)) + {// не выдаём врагу наш IP адрес!!! :) + if (mraGetByte(NULL, "FileSendAddExtraAddresses", MRA_DEF_FS_ADD_EXTRA_ADDRESSES) == FALSE) + {// только если не добавляем адрес роутера + lpszCurPos += mir_snprintf(lpszCurPos, (dwBuffSize-((size_t)lpszCurPos-(size_t)lpszBuff)), MRA_FILES_NULL_ADDRR); + } + } + else {// создаём список наших IP адресов + BYTE btAddress[32]; + DWORD dwSelfExternalIP; + size_t dwAdapter = 0; + hostent *sh; + + dwSelfExternalIP = NTOHL(mraGetDword(NULL, "IP", 0)); + if (dwSelfExternalIP) { + memmove(&btAddress, &dwSelfExternalIP, sizeof(DWORD)); + lpszCurPos += mir_snprintf(lpszCurPos, (dwBuffSize-((size_t)lpszCurPos-(size_t)lpszBuff)), "%lu.%lu.%lu.%lu:%lu;", btAddress[0], btAddress[1], btAddress[2], btAddress[3], dwPort); + } + + if (gethostname(szHostName, SIZEOF(szHostName)) == 0) + if ((sh = gethostbyname((LPSTR)&szHostName))) { + while (sh->h_addr_list[dwAdapter]) { + lpszCurPos += mir_snprintf(lpszCurPos, (dwBuffSize-((size_t)lpszCurPos-(size_t)lpszBuff)), "%s:%lu;", inet_ntoa(*((struct in_addr*)sh->h_addr_list[dwAdapter])), dwPort); + dwAdapter++; + } + } + } + + if (mraGetByte(NULL, "FileSendAddExtraAddresses", MRA_DEF_FS_ADD_EXTRA_ADDRESSES))// добавляем произвольный адрес + if (mraGetStaticStringA(NULL, "FileSendExtraAddresses", szHostName, SIZEOF(szHostName), NULL)) + lpszCurPos += mir_snprintf(lpszCurPos, (dwBuffSize-((size_t)lpszCurPos-(size_t)lpszBuff)), "%s:%lu;", szHostName, dwPort); + + return lpszCurPos - lpszBuff; +} + +DWORD CMraProto::MraFilesQueueAccept(HANDLE hFilesQueueHandle, DWORD dwIDRequest, LPCWSTR lpwszPath, size_t dwPathSize) +{ + if ( !hFilesQueueHandle || !lpwszPath || !dwPathSize) + return ERROR_INVALID_HANDLE; + + MRA_FILES_QUEUE *pmrafqFilesQueue = (MRA_FILES_QUEUE*)hFilesQueueHandle; + MRA_FILES_QUEUE_ITEM *dat; + + mt_lock l(pmrafqFilesQueue); + DWORD dwRetErrorCode = MraFilesQueueItemFindByID(hFilesQueueHandle, dwIDRequest, &dat); + if (dwRetErrorCode == NO_ERROR) { + MRA_FILES_THREADPROC_PARAMS *pmftpp = (MRA_FILES_THREADPROC_PARAMS*)mir_calloc(sizeof(MRA_FILES_THREADPROC_PARAMS)); + dat->lpwszPath = (LPWSTR)mir_calloc((dwPathSize*sizeof(WCHAR))); + dat->dwPathSize = dwPathSize; + memmove(dat->lpwszPath, lpwszPath, (dwPathSize*sizeof(WCHAR))); + + if ( (*(WCHAR*)(dat->lpwszPath+(dat->dwPathSize-1))) != '\\') + {// add slash at the end if needed + (*(WCHAR*)(dat->lpwszPath+dat->dwPathSize)) = '\\'; + dat->dwPathSize++; + (*(WCHAR*)(dat->lpwszPath+dat->dwPathSize)) = 0; + } + + pmftpp->hFilesQueueHandle = hFilesQueueHandle; + pmftpp->dat = dat; + + dat->hThread = ForkThreadEx(&CMraProto::MraFilesQueueRecvThreadProc, pmftpp); + } + return dwRetErrorCode; +} + +DWORD CMraProto::MraFilesQueueCancel(HANDLE hFilesQueueHandle, DWORD dwIDRequest, BOOL bSendDecline) +{ + if (!hFilesQueueHandle) + return ERROR_INVALID_HANDLE; + + MRA_FILES_QUEUE *pmrafqFilesQueue = (MRA_FILES_QUEUE*)hFilesQueueHandle; + MRA_FILES_QUEUE_ITEM *dat; + + mt_lock l(pmrafqFilesQueue); + DWORD dwRetErrorCode = MraFilesQueueItemFindByID(hFilesQueueHandle, dwIDRequest, &dat); + if (dwRetErrorCode == NO_ERROR) { //***deb closesocket, send message to thread + InterlockedExchange((volatile LONG*)&dat->bIsWorking, FALSE); + + if (bSendDecline) { + CHAR szEMail[MAX_EMAIL_LEN]; + size_t dwEMailSize; + + if (mraGetStaticStringA(dat->hContact, "e-mail", szEMail, SIZEOF(szEMail), &dwEMailSize)) + MraFileTransferAck(FILE_TRANSFER_STATUS_DECLINE, szEMail, dwEMailSize, dwIDRequest, NULL, 0); + } + + MraMrimProxyCloseConnection(dat->hMraMrimProxyData); + + Netlib_CloseHandle(dat->hListen); + dat->hListen = NULL; + + Netlib_CloseHandle(dat->hConnection); + dat->hConnection = NULL; + + SetEvent(dat->hWaitHandle); + + if (dat->hThread == NULL) + MraFilesQueueItemFree(dat); + } + return dwRetErrorCode; +} + +DWORD CMraProto::MraFilesQueueStartMrimProxy(HANDLE hFilesQueueHandle, DWORD dwIDRequest) +{ + if (!hFilesQueueHandle || !mraGetByte(NULL, "FileSendEnableMRIMProxyCons", MRA_DEF_FS_ENABLE_MRIM_PROXY_CONS)) + return ERROR_INVALID_HANDLE; + + MRA_FILES_QUEUE *pmrafqFilesQueue = (MRA_FILES_QUEUE*)hFilesQueueHandle; + MRA_FILES_QUEUE_ITEM *dat; + + mt_lock l(pmrafqFilesQueue); + if ( !MraFilesQueueItemFindByID(hFilesQueueHandle, dwIDRequest, &dat)) + if (dat->bSending == FALSE) + SetEvent(dat->hWaitHandle);// cancel wait incomming connection + + return 0; +} + +DWORD MraFilesQueueFree(HANDLE hFilesQueueHandle, DWORD dwIDRequest) +{ + if (!hFilesQueueHandle) + return ERROR_INVALID_HANDLE; + + MRA_FILES_QUEUE *pmrafqFilesQueue = (MRA_FILES_QUEUE*)hFilesQueueHandle; + MRA_FILES_QUEUE_ITEM *dat; + LIST_MT_ITERATOR lmtiIterator; + + mt_lock l(pmrafqFilesQueue); + ListMTIteratorMoveFirst(pmrafqFilesQueue, &lmtiIterator); + do { + if (ListMTIteratorGet(&lmtiIterator, NULL, (LPVOID*)&dat) == NO_ERROR) + if (dat->dwIDRequest == dwIDRequest) { + MraFilesQueueItemFree(dat); + return 0; + } + } + while (ListMTIteratorMoveNext(&lmtiIterator)); + + return ERROR_NOT_FOUND; +} + +DWORD CMraProto::MraFilesQueueSendMirror(HANDLE hFilesQueueHandle, DWORD dwIDRequest, LPSTR lpszAddreses, size_t dwAddresesSize) +{ + if (!hFilesQueueHandle) + return ERROR_INVALID_HANDLE; + + MRA_FILES_QUEUE *pmrafqFilesQueue = (MRA_FILES_QUEUE*)hFilesQueueHandle; + MRA_FILES_QUEUE_ITEM *dat; + + mt_lock l(pmrafqFilesQueue); + DWORD dwRetErrorCode = MraFilesQueueItemFindByID(hFilesQueueHandle, dwIDRequest, &dat); + if (dwRetErrorCode == NO_ERROR) { + MraAddrListGetFromBuff(lpszAddreses, dwAddresesSize, &dat->malAddrList); + MraAddrListStoreToContact(dat->hContact, &dat->malAddrList); + + dat->hConnection = NULL; + SetEvent(dat->hWaitHandle); + } + return dwRetErrorCode; +} + +BOOL CMraProto::MraFilesQueueHandCheck(HANDLE hConnection, MRA_FILES_QUEUE_ITEM *dat) +{ + BOOL bRet = FALSE; + + if (hConnection && dat) + { + CHAR szEMail[MAX_EMAIL_LEN] = {0}, szEMailMy[MAX_EMAIL_LEN] = {0}; + BYTE btBuff[((MAX_EMAIL_LEN*2)+(sizeof(MRA_FT_HELLO)*2)+8)] = {0}; + size_t dwEMailSize, dwEMailMySize, dwBuffSize; + + mraGetStaticStringA(NULL, "e-mail", szEMailMy, SIZEOF(szEMailMy), &dwEMailMySize);BuffToLowerCase(szEMailMy, szEMailMy, dwEMailMySize); + mraGetStaticStringA(dat->hContact, "e-mail", szEMail, SIZEOF(szEMail), &dwEMailSize);BuffToLowerCase(szEMail, szEMail, dwEMailSize); + + if (dat->bSending == FALSE) + {// receiving + dwBuffSize = mir_snprintf((LPSTR)btBuff, SIZEOF(btBuff), "%s %s", MRA_FT_HELLO, szEMailMy)+1; + if (dwBuffSize == Netlib_Send(hConnection, (LPSTR)btBuff, (int)dwBuffSize, 0)) + {// my email sended + ProtoBroadcastAck(m_szModuleName, dat->hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, (HANDLE)dat->dwIDRequest, 0); + dwBuffSize = Netlib_Recv(hConnection, (LPSTR)btBuff, sizeof(btBuff), 0); + if ((dwEMailSize+sizeof(MRA_FT_HELLO)+1) == dwBuffSize) + {// email received + mir_snprintf(((LPSTR)btBuff+dwBuffSize), (SIZEOF(btBuff)-dwBuffSize), "%s %s", MRA_FT_HELLO, szEMail); + if (CompareStringA( MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), NORM_IGNORECASE, (LPSTR)btBuff, dwBuffSize, ((LPSTR)btBuff+dwBuffSize), dwBuffSize) == CSTR_EQUAL) + bRet = TRUE; + } + } + }else {// sending + dwBuffSize = Netlib_Recv(hConnection, (LPSTR)btBuff, sizeof(btBuff), 0); + if ((dwEMailSize+sizeof(MRA_FT_HELLO)+1) == dwBuffSize) + {// email received + ProtoBroadcastAck(m_szModuleName, dat->hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, (HANDLE)dat->dwIDRequest, 0); + mir_snprintf(((LPSTR)btBuff+dwBuffSize), (SIZEOF(btBuff)-dwBuffSize), "%s %s", MRA_FT_HELLO, szEMail); + if (CompareStringA( MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), NORM_IGNORECASE, (LPSTR)btBuff, dwBuffSize, ((LPSTR)btBuff+dwBuffSize), dwBuffSize) == CSTR_EQUAL) + {// email verified + dwBuffSize = (mir_snprintf((LPSTR)btBuff, SIZEOF(btBuff), "%s %s", MRA_FT_HELLO, szEMailMy)+1); + if (dwBuffSize == Netlib_Send(hConnection, (LPSTR)btBuff, dwBuffSize, 0)) + {// my email sended + bRet = TRUE; + } + } + } + } + } + return bRet; +} + +HANDLE CMraProto::MraFilesQueueConnectOut(MRA_FILES_QUEUE_ITEM *dat) +{ + if (!dat) + return NULL; + + if (mraGetByte(NULL, "FileSendEnableDirectConn", MRA_DEF_FS_ENABLE_DIRECT_CONN) && InterlockedExchangeAdd((volatile LONG*)&dat->bIsWorking, 0) && ((dat->bSending == FALSE && mraGetByte(NULL, "FileSendNoOutConnOnRcv", MRA_DEF_FS_NO_OUT_CONN_ON_RCV) == FALSE) || (dat->bSending == TRUE && mraGetByte(NULL, "FileSendNoOutConnOnSend", MRA_DEF_FS_NO_OUT_CONN_ON_SEND) == FALSE))) { + BOOL bFiltering = FALSE, bIsHTTPSProxyUsed = IsHTTPSProxyUsed(hNetlibUser); + DWORD dwLocalPort = 0, dwConnectReTryCount, dwCurConnectReTryCount; + size_t dwAddrCount; + NETLIBOPENCONNECTION nloc = {0}; + + if (mraGetByte(NULL, "FileSendIgnoryAdditionalPorts", MRA_DEF_FS_IGNORY_ADDITIONAL_PORTS) || bIsHTTPSProxyUsed) + {// фильтруем порты для одного IP, вместо 3 будем коннектится только к одному + if (bIsHTTPSProxyUsed) + dwLocalPort = MRA_SERVER_PORT_HTTPS; + else if ((dwLocalPort = mraGetWord(NULL, "ServerPort", MRA_DEFAULT_SERVER_PORT)) == MRA_SERVER_PORT_STANDART_NLB) + dwLocalPort = MRA_SERVER_PORT_STANDART; + + dwAddrCount = 0; + for (size_t i = 0; i < dat->malAddrList.dwAddrCount; i++) { + if (dwLocalPort == dat->malAddrList.pmaliAddress[i].dwPort) { + bFiltering = TRUE; + dwAddrCount++; + } + } + } + + if (bFiltering == FALSE) + dwAddrCount = dat->malAddrList.dwAddrCount; + + if (dwAddrCount) { + dat->hConnection = NULL; + dwConnectReTryCount = mraGetDword(NULL, "ConnectReTryCountFileSend", MRA_DEFAULT_CONN_RETRY_COUNT_FILES); + nloc.cbSize = sizeof(nloc); + nloc.flags = NLOCF_V2; + nloc.timeout = mraGetDword(NULL, "TimeOutConnectFileSend", ((MRA_TIMEOUT_DIRECT_CONN-1)/(dwAddrCount*dwConnectReTryCount)));// -1 сек чтобы был запас + if (nloc.timeoutMRA_TIMEOUT_CONN_МАХ) nloc.timeout = MRA_TIMEOUT_CONN_МАХ; + + // Set up the sockaddr structure + for (size_t i = 0;imalAddrList.dwAddrCount;i++) { + if (dwLocalPort == dat->malAddrList.pmaliAddress[i].dwPort || bFiltering == FALSE) { + ProtoBroadcastAck(m_szModuleName, dat->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTING, (HANDLE)dat->dwIDRequest, 0); + + nloc.szHost = inet_ntoa((*((in_addr*)&dat->malAddrList.pmaliAddress[i].dwAddr))); + nloc.wPort = (WORD)dat->malAddrList.pmaliAddress[i].dwPort; + + dwCurConnectReTryCount = dwConnectReTryCount; + do { + dat->hConnection = (HANDLE)CallService(MS_NETLIB_OPENCONNECTION, (WPARAM)hNetlibUser, (LPARAM)&nloc); + } + while (--dwCurConnectReTryCount && dat->hConnection == NULL); + + if (dat->hConnection) { + ProtoBroadcastAck(m_szModuleName, dat->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTED, (HANDLE)dat->dwIDRequest, 0); + if (MraFilesQueueHandCheck(dat->hConnection, dat)) { + // связь установленная с тем кем нужно + mraSetDword(dat->hContact, "OldIP", mraGetDword(dat->hContact, "IP", 0)); + mraSetDword(dat->hContact, "IP", HTONL(dat->malAddrList.pmaliAddress[i].dwAddr)); + break; + } + else { + // кажется не туда подключились :) + Netlib_CloseHandle(dat->hConnection); + dat->hConnection = NULL; + } + } + } + } + } + } + return dat->hConnection; +} + +LPWSTR GetFileNameFromFullPathW(LPWSTR lpwszFullPath, size_t dwFullPathSize) +{ + LPWSTR lpwszFileName = lpwszFullPath, lpwszCurPos; + + lpwszCurPos = (lpwszFullPath+dwFullPathSize); + for (; lpwszCurPos>lpwszFullPath; lpwszCurPos--) { + if ((*lpwszCurPos) == '\\') { + lpwszFileName = (lpwszCurPos+1); + break; + } + } + return lpwszFileName; +} + +HANDLE CMraProto::MraFilesQueueConnectIn(MRA_FILES_QUEUE_ITEM *dat) +{ + if (!dat) + return NULL; + if ( !InterlockedExchangeAdd((volatile LONG*)&dat->bIsWorking, 0)) + return NULL; + + CHAR szEMail[MAX_EMAIL_LEN]; + size_t dwEMailSize; + + if (mraGetStaticStringA(dat->hContact, "e-mail", szEMail, SIZEOF(szEMail), &dwEMailSize)) { + CHAR szAddrList[2048] = {0}; + size_t dwAddrListSize; + + // копируем адреса в соответствии с правилами и начинаем слушать порт + if (mraGetByte(NULL, "FileSendEnableDirectConn", MRA_DEF_FS_ENABLE_DIRECT_CONN)) { + NETLIBBIND nlbBind = {0}; + + nlbBind.cbSize = sizeof(nlbBind); + nlbBind.pfnNewConnectionV2 = MraFilesQueueConnectionReceived; + nlbBind.wPort = 0; + nlbBind.pExtra = (LPVOID)dat; + + dat->hListen = (HANDLE)CallService(MS_NETLIB_BINDPORT, (WPARAM)hNetlibUser, (LPARAM)&nlbBind); + if (dat->hListen) { + ProtoBroadcastAck(m_szModuleName, dat->hContact, ACKTYPE_FILE, ACKRESULT_LISTENING, (HANDLE)dat->dwIDRequest, 0); + dwAddrListSize = MraFilesQueueGetLocalAddressesList(szAddrList, sizeof(szAddrList), nlbBind.wPort); + } + // не смогли слушать порт, хз почему. + else { + ShowFormattedErrorMessage(L"Files exchange: cant create listen soscket, will try connect to remonte host. Error", GetLastError()); + + //dwAddrListSize = 0; + memmove(szAddrList, MRA_FILES_NULL_ADDRR, sizeof(MRA_FILES_NULL_ADDRR)); + dwAddrListSize = (sizeof(MRA_FILES_NULL_ADDRR)-1); + } + } + // подставляем ложный адрес, чтобы точно не подключились и не слушаем порт + else { + memmove(szAddrList, MRA_FILES_NULL_ADDRR, sizeof(MRA_FILES_NULL_ADDRR)); + dwAddrListSize = (sizeof(MRA_FILES_NULL_ADDRR)-1); + } + + if (dwAddrListSize) { + dat->hWaitHandle = CreateEvent(NULL, TRUE, FALSE, NULL); + if (dat->bSending == FALSE) // запрашиваем зеркальное соединение, тк сами подключится не смогли + MraFileTransferAck(FILE_TRANSFER_MIRROR, szEMail, dwEMailSize, dat->dwIDRequest, (LPBYTE)szAddrList, dwAddrListSize); + else { // здесь отправляем запрос на передачу(установление соединения) + // создаём текстовый список файлов для отправки другой стороне + LPWSTR lpwszFiles, lpwszCurPos; + size_t dwFilesSize; + + dwFilesSize = ((MAX_PATH*2)*dat->dwFilesCount); + lpwszFiles = (LPWSTR)mir_calloc((dwFilesSize*sizeof(WCHAR))); + if (lpwszFiles) { + lpwszCurPos = lpwszFiles; + for (size_t i = 0;i < dat->dwFilesCount;i++) { + MRA_FILES_QUEUE_FILE &p = dat->pmfqfFiles[i]; + lpwszCurPos += mir_sntprintf(lpwszCurPos, (dwFilesSize-((size_t)lpwszCurPos-(size_t)lpwszFiles)), L"%s;%I64u;", + GetFileNameFromFullPathW(p.lpwszName, p.dwNameLen), p.dwSize); + } + dwFilesSize = (lpwszCurPos-lpwszFiles);// size in WCHARs + + if (dat->hMraMrimProxyData) { + // устанавливаем данные для майловской прокси, если она разрешена + LPSTR lpszFiles; + size_t dwFilesSizeA; + + dwFilesSizeA = WideCharToMultiByte(MRA_CODE_PAGE, 0, lpwszFiles, dwFilesSize, NULL, 0, NULL, NULL); + lpszFiles = (LPSTR)mir_calloc((dwFilesSizeA+MAX_PATH)); + if (lpszFiles) { + dwFilesSizeA = WideCharToMultiByte(MRA_CODE_PAGE, 0, lpwszFiles, dwFilesSize, lpszFiles, (dwFilesSizeA+MAX_PATH), NULL, NULL); + MraMrimProxySetData(dat->hMraMrimProxyData, szEMail, dwEMailSize, dat->dwIDRequest, MRIM_PROXY_TYPE_FILES, lpszFiles, dwFilesSizeA, NULL, 0, NULL); + mir_free(lpszFiles); + } + } + MraFileTransfer(szEMail, dwEMailSize, dat->dwIDRequest, dat->dwFilesTotalSize, lpwszFiles, dwFilesSize, szAddrList, dwAddrListSize); + + mir_free(lpwszFiles); + } + } + WaitForSingleObjectEx(dat->hWaitHandle, INFINITE, FALSE); + CloseHandle(dat->hWaitHandle); + dat->hWaitHandle = NULL; + } + } + return dat->hConnection; +} + +// This function is called from the Netlib when someone is connecting to +// one of our incomming DC ports +void MraFilesQueueConnectionReceived(HANDLE hNewConnection, DWORD dwRemoteIP, void *pExtra) +{ + if (pExtra) { + MRA_FILES_QUEUE_ITEM *dat = (MRA_FILES_QUEUE_ITEM*)pExtra; + + ProtoBroadcastAck(dat->ppro->m_szModuleName, dat->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTED, (HANDLE)dat->dwIDRequest, 0); + if ( dat->ppro->MraFilesQueueHandCheck(hNewConnection, dat)) { // связь установленная с тем кем нужно + dat->hConnection = hNewConnection; + ProtoBroadcastAck(dat->ppro->m_szModuleName, dat->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTED, (HANDLE)dat->dwIDRequest, 0); + dat->ppro->mraSetDword(dat->hContact, "OldIP", dat->ppro->mraGetDword(dat->hContact, "IP", 0)); + dat->ppro->mraSetDword(dat->hContact, "IP", dwRemoteIP); + SetEvent(dat->hWaitHandle); + }else {// кажется кто то не туда подключилися :) + ProtoBroadcastAck(dat->ppro->m_szModuleName, dat->hContact, ACKTYPE_FILE, ACKRESULT_LISTENING, (HANDLE)dat->dwIDRequest, 0); + Netlib_CloseHandle(hNewConnection); + } + } + else Netlib_CloseHandle(hNewConnection); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Receive files + +DWORD CMraProto::MraFilesQueueAddReceive(HANDLE hFilesQueueHandle, DWORD dwFlags, HANDLE hContact, DWORD dwIDRequest, LPWSTR lpwszFiles, size_t dwFilesSize, LPSTR lpszAddreses, size_t dwAddresesSize) +{ + if (!hFilesQueueHandle || !dwIDRequest) + return ERROR_INVALID_HANDLE; + + MRA_FILES_QUEUE *pmrafqFilesQueue = (MRA_FILES_QUEUE*)hFilesQueueHandle; + MRA_FILES_QUEUE_ITEM *dat = (MRA_FILES_QUEUE_ITEM*)mir_calloc(sizeof(MRA_FILES_QUEUE_ITEM)+sizeof(LPSTR)+64); + if ( !dat) + return GetLastError(); + + WCHAR szBuff[MAX_PATH]; + LPWSTR lpwszCurrentItem, lpwszDelimiter, lpwszEndItem; + size_t dwMemSize, dwAllocatedCount, dwFileNameTotalSize; + + //dat->lmtListMTItem; + dat->ppro = this; + dat->bIsWorking = TRUE; + dat->dwSendTime = GetTickCount(); + dat->dwIDRequest = dwIDRequest; + dat->dwFlags = dwFlags; + dat->hContact = hContact; + if (mraGetByte(NULL, "FileSendEnableMRIMProxyCons", MRA_DEF_FS_ENABLE_MRIM_PROXY_CONS)) + dat->hMraMrimProxyData = MraMrimProxyCreate(); + + dwFileNameTotalSize = 0; + dwAllocatedCount = ALLOCATED_COUNT; + dat->dwFilesCount = 0; + dat->dwFilesTotalSize = 0; + dat->pmfqfFiles = (MRA_FILES_QUEUE_FILE*)mir_calloc((sizeof(MRA_FILES_QUEUE_FILE)*dwAllocatedCount)); + lpwszCurrentItem = lpwszFiles; + while (TRUE) { + lpwszDelimiter = (LPWSTR)MemoryFind(((size_t)lpwszCurrentItem-(size_t)lpwszFiles), lpwszFiles, (dwFilesSize*sizeof(WCHAR)), ";", 2); + if (!lpwszDelimiter) + break; + + lpwszEndItem = (LPWSTR)MemoryFind((((size_t)lpwszDelimiter+2)-(size_t)lpwszFiles), lpwszFiles, (dwFilesSize*sizeof(WCHAR)), ";", 2); + if (!lpwszEndItem) + break; + + if (dat->dwFilesCount == dwAllocatedCount) { + dwAllocatedCount *= 2; + dat->pmfqfFiles = (MRA_FILES_QUEUE_FILE*)mir_realloc(dat->pmfqfFiles, (sizeof(MRA_FILES_QUEUE_FILE)*dwAllocatedCount)); + } + + MRA_FILES_QUEUE_FILE &p = dat->pmfqfFiles[dat->dwFilesCount]; + *lpwszDelimiter++ = 0; + p.lpwszName = mir_wstrdup(lpwszCurrentItem); + p.dwNameLen = lstrlen(p.lpwszName); + p.dwSize = StrToUNum64((LPSTR)lpwszDelimiter, (size_t)lpwszEndItem-(size_t)lpwszDelimiter+1); + dat->dwFilesTotalSize += p.dwSize; + dwFileNameTotalSize += p.dwNameLen * sizeof(TCHAR); + + dat->dwFilesCount++; + lpwszCurrentItem = lpwszEndItem+1; + } + dat->pmfqfFiles = (MRA_FILES_QUEUE_FILE*)mir_realloc(dat->pmfqfFiles, (sizeof(MRA_FILES_QUEUE_FILE)*(dat->dwFilesCount+4))); + + dwMemSize = (((dat->dwFilesCount+4)*64)+(dwFileNameTotalSize*sizeof(WCHAR))+(dwAddresesSize*sizeof(WCHAR))+128); + dat->pwszFilesList = (LPWSTR)mir_calloc(dwMemSize); + dat->pwszDescription = (LPWSTR)mir_calloc(dwMemSize); + + lpwszDelimiter = dat->pwszFilesList; + lpwszCurrentItem = dat->pwszDescription; + StrFormatByteSizeW(dat->dwFilesTotalSize, szBuff, SIZEOF(szBuff)); + lpwszCurrentItem += mir_sntprintf(lpwszCurrentItem, ((dwMemSize-((size_t)lpwszCurrentItem-(size_t)dat->pwszDescription))/sizeof(WCHAR)), L"%I64u Files (%s)\r\n", dat->dwFilesCount, szBuff); + + // description + filesnames + for (size_t i = 0; i < dat->dwFilesCount; i++) { + lpwszDelimiter += mir_sntprintf(lpwszDelimiter, ((dwMemSize-((size_t)lpwszDelimiter-(size_t)dat->pwszFilesList))/sizeof(WCHAR)), L"%s", dat->pmfqfFiles[i].lpwszName); + StrFormatByteSizeW(dat->pmfqfFiles[i].dwSize, szBuff, SIZEOF(szBuff)); + lpwszCurrentItem += mir_sntprintf(lpwszCurrentItem, ((dwMemSize-((size_t)lpwszCurrentItem-(size_t)dat->pwszDescription))/sizeof(WCHAR)), L"%s - %s\r\n", dat->pmfqfFiles[i].lpwszName, szBuff); + } + + lpwszCurrentItem += MultiByteToWideChar(MRA_CODE_PAGE, 0, lpszAddreses, dwAddresesSize, lpwszCurrentItem, ((dwMemSize-((size_t)lpwszCurrentItem-(size_t)dat->pwszDescription))/sizeof(WCHAR))); + *lpwszCurrentItem = 0; + + MraAddrListGetFromBuff(lpszAddreses, dwAddresesSize, &dat->malAddrList); + MraAddrListStoreToContact(dat->hContact, &dat->malAddrList); + { + mt_lock l(pmrafqFilesQueue); + ListMTItemAdd(pmrafqFilesQueue, dat, dat); + } + + // Send chain event + PROTORECVFILET prf; + prf.flags = PREF_UNICODE; + prf.timestamp = _time32(NULL); + prf.tszDescription = dat->pwszDescription; + prf.fileCount = 1;//dat->dwFilesCount; + prf.ptszFiles = &dat->pwszFilesList; + prf.lParam = dwIDRequest; + + CCSDATA ccs; + ccs.szProtoService = PSR_FILE; + ccs.hContact = hContact; + ccs.wParam = 0; + ccs.lParam = (LPARAM)&prf; + + CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs); + return NO_ERROR; +} + +void CMraProto::MraFilesQueueRecvThreadProc(LPVOID lpParameter) +{ + DWORD dwRetErrorCode = NO_ERROR; + + if (lpParameter) + { + MRA_FILES_QUEUE *pmrafqFilesQueue = (MRA_FILES_QUEUE*)((MRA_FILES_THREADPROC_PARAMS*)lpParameter)->hFilesQueueHandle; + MRA_FILES_QUEUE_ITEM *dat = ((MRA_FILES_THREADPROC_PARAMS*)lpParameter)->dat; + + WCHAR wszFileName[MAX_FILEPATH] = {0}; + WCHAR szErrorText[2048]; + BYTE btBuff[BUFF_SIZE_RCV]; + BOOL bContinue, bFailed, bOK, bConnected; + DWORD dwReceived, dwUpdateTimeNext, dwUpdateTimeCur; + HANDLE hFile; + size_t i, dwBuffSizeUsed; + LARGE_INTEGER liFileSize; + NETLIBSELECT nls = {0}; + PROTOFILETRANSFERSTATUS pfts = {0}; + + mir_free(lpParameter); + + bFailed = TRUE; + bConnected = FALSE; + nls.cbSize = sizeof(nls); + pfts.cbSize = sizeof(pfts); + pfts.hContact = dat->hContact; + pfts.flags = (PFTS_RECEIVING|PFTS_UNICODE);// pfts.sending = dat->bSending; //true if sending, false if receiving + //pfts.files; + pfts.totalFiles = dat->dwFilesCount; + //pfts.currentFileNumber = 0; + pfts.totalBytes = dat->dwFilesTotalSize; + //pfts.totalProgress = 0; + pfts.wszWorkingDir = dat->lpwszPath; + //pfts.currentFile; + //pfts.currentFileSize; + //pfts.currentFileProgress; + //pfts.currentFileTime; //as seconds since 1970 + + if (MraFilesQueueConnectOut(dat)) + { + bConnected = TRUE; + }else { + if (MraFilesQueueConnectIn(dat)) + { + bConnected = TRUE; + }else { + if (InterlockedExchangeAdd((volatile LONG*)&dat->bIsWorking, 0)) + { + ProtoBroadcastAck(m_szModuleName, dat->hContact, ACKRESULT_CONNECTPROXY, ACKRESULT_CONNECTED, (HANDLE)dat->dwIDRequest, 0); + if (MraMrimProxyConnect(dat->hMraMrimProxyData, &dat->hConnection) == NO_ERROR) + {// подключились к прокси, проверяем та ли сессия (ещё раз, на этот раз сами) + if (MraFilesQueueHandCheck(dat->hConnection, dat)) + {// связь установленная с тем кем нужно// dat->bSending + ProtoBroadcastAck(m_szModuleName, dat->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTED, (HANDLE)dat->dwIDRequest, 0); + bConnected = TRUE; + } + } + } + } + } + + if (bConnected) + {// email verified + bFailed = FALSE; + for (i = 0;idwFilesCount;i++) + {// receiving files + pfts.currentFileNumber = i; + pfts.wszCurrentFile = wszFileName; + pfts.currentFileSize = dat->pmfqfFiles[i].dwSize; + pfts.currentFileProgress = 0; + //pfts.currentFileTime; //as seconds since 1970 + + if ((dat->dwPathSize+dat->pmfqfFiles[i].dwNameLen)lpwszPath, (dat->dwPathSize*sizeof(WCHAR))); + memmove((wszFileName+dat->dwPathSize), dat->pmfqfFiles[i].lpwszName, ((dat->pmfqfFiles[i].dwNameLen+1)*sizeof(WCHAR))); + wszFileName[dat->dwPathSize+dat->pmfqfFiles[i].dwNameLen] = 0; + }else { + dwRetErrorCode = ERROR_BAD_PATHNAME; + ShowFormattedErrorMessage(L"Receive files: error", dwRetErrorCode); + bFailed = TRUE; + break; + } + + //***deb add + //dwBuffSizeUsed = ProtoBroadcastAck(m_szModuleName, dat->hContact, ACKTYPE_FILE, ACKRESULT_FILERESUME, (HANDLE)dat->dwIDRequest, (LPARAM)&pfts); + + ProtoBroadcastAck(m_szModuleName, dat->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, (HANDLE)dat->dwIDRequest, 0); + + //dwBuffSizeUsed = (mir_snprintf((LPSTR)btBuff, SIZEOF(btBuff), "%s %S", MRA_FT_GET_FILE, dat->pmfqfFiles[i].lpwszName)+1); + memmove(btBuff, MRA_FT_GET_FILE, sizeof(MRA_FT_GET_FILE)); + btBuff[(sizeof(MRA_FT_GET_FILE)-1)] = ' '; + dwBuffSizeUsed = sizeof(MRA_FT_GET_FILE)+WideCharToMultiByte(MRA_CODE_PAGE, 0, dat->pmfqfFiles[i].lpwszName, dat->pmfqfFiles[i].dwNameLen, (LPSTR)(btBuff+sizeof(MRA_FT_GET_FILE)), (SIZEOF(btBuff)-sizeof(MRA_FT_GET_FILE)), NULL, NULL); + btBuff[dwBuffSizeUsed] = 0; + dwBuffSizeUsed++; + + if (dwBuffSizeUsed == Netlib_Send(dat->hConnection, (LPSTR)btBuff, dwBuffSizeUsed, 0)) + {// file request sended + hFile = CreateFileW(wszFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile != INVALID_HANDLE_VALUE) + {// file opened/created, pre allocating disk space, for best perfomance + bOK = FALSE; + + liFileSize.QuadPart = (LONGLONG)dat->pmfqfFiles[i].dwSize; + if (SetFilePointerEx(hFile, liFileSize, NULL, FILE_BEGIN)) + if (SetEndOfFile(hFile)) + { + liFileSize.QuadPart = 0; + bOK = SetFilePointerEx(hFile, liFileSize, NULL, FILE_BEGIN); + } + + if (bOK) + {// disk space pre allocated + bOK = FALSE; + bContinue = TRUE; + dwUpdateTimeNext = GetTickCount(); + nls.dwTimeout = (1000*mraGetDword(NULL, "TimeOutReceiveFileData", MRA_DEF_FS_TIMEOUT_RECV)); + nls.hReadConns[0] = dat->hConnection; + ProtoBroadcastAck(m_szModuleName, dat->hContact, ACKTYPE_FILE, ACKRESULT_DATA, (HANDLE)dat->dwIDRequest, (LPARAM)&pfts); + + while (bContinue) + { + switch (CallService(MS_NETLIB_SELECT, 0, (LPARAM)&nls)) { + case SOCKET_ERROR: + case 0:// Time out + dwRetErrorCode = GetLastError(); + ShowFormattedErrorMessage(L"Receive files: error on receive file data", dwRetErrorCode); + bContinue = FALSE; + break; + case 1: + dwReceived = Netlib_Recv(dat->hConnection, (LPSTR)&btBuff, SIZEOF(btBuff), 0); + if (dwReceived == 0 || dwReceived == SOCKET_ERROR) + { + dwRetErrorCode = GetLastError(); + ShowFormattedErrorMessage(L"Receive files: error on receive file data", dwRetErrorCode); + bContinue = FALSE; + }else { + if (WriteFile(hFile, (LPVOID)&btBuff, dwReceived, &dwReceived, NULL)) + { + pfts.currentFileProgress += dwReceived; + pfts.totalProgress += dwReceived; + + // progress updates + dwUpdateTimeCur = GetTickCount(); + if (dwUpdateTimeNext <= dwUpdateTimeCur || pfts.currentFileProgress >= dat->pmfqfFiles[i].dwSize) + {// we update it + dwUpdateTimeNext = dwUpdateTimeCur+MRA_FILES_QUEUE_PROGRESS_INTERVAL; + ProtoBroadcastAck(m_szModuleName, dat->hContact, ACKTYPE_FILE, ACKRESULT_DATA, (HANDLE)dat->dwIDRequest, (LPARAM)&pfts); + + if (pfts.currentFileProgress >= dat->pmfqfFiles[i].dwSize) + {// file received + bOK = TRUE; + bContinue = FALSE; + } + } + }else {// err on write file + dwRetErrorCode = GetLastError(); + ShowFormattedErrorMessage(L"Receive files: cant write file data, error", dwRetErrorCode); + bContinue = FALSE; + } + } + break; + } + }// end while + }else {// err allocating file disk space + dwRetErrorCode = GetLastError(); + mir_sntprintf(szErrorText, SIZEOF(szErrorText), TranslateW(L"Receive files: cant allocate disk space for file, size %lu bytes, error"), dat->pmfqfFiles[i].dwSize); + ShowFormattedErrorMessage(szErrorText, dwRetErrorCode); + } + CloseHandle(hFile); + + if (bOK == FALSE) + {// file recv failed + DeleteFileW(wszFileName); + bFailed = TRUE; + break; + } + }else {// err on open file + dwRetErrorCode = GetLastError(); + mir_sntprintf(szErrorText, SIZEOF(szErrorText), TranslateW(L"Receive files: cant open file %s, error"), wszFileName); + ShowFormattedErrorMessage(szErrorText, dwRetErrorCode); + bFailed = TRUE; + break; + } + }else {// err on send request for file + dwRetErrorCode = GetLastError(); + mir_sntprintf(szErrorText, SIZEOF(szErrorText), TranslateW(L"Receive files: request for file %s not sended, error"), dat->pmfqfFiles[i].lpwszName); + ShowFormattedErrorMessage(szErrorText, NO_ERROR); + bFailed = TRUE; + break; + } + }// end for + + Netlib_CloseHandle(dat->hConnection); + dat->hConnection = NULL; + } + + if (bFailed) { + CHAR szEMail[MAX_EMAIL_LEN]; + size_t dwEMailSize; + + if (mraGetStaticStringA(dat->hContact, "e-mail", szEMail, SIZEOF(szEMail), &dwEMailSize)) + MraFileTransferAck(FILE_TRANSFER_STATUS_ERROR, szEMail, dwEMailSize, dat->dwIDRequest, NULL, 0); + + ProtoBroadcastAck(m_szModuleName, dat->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)dat->dwIDRequest, 0); + } + else ProtoBroadcastAck(m_szModuleName, dat->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, (HANDLE)dat->dwIDRequest, 0); + + mt_lock l(pmrafqFilesQueue); + MraFilesQueueItemFree(dat); + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Send files + +DWORD CMraProto::MraFilesQueueAddSend(HANDLE hFilesQueueHandle, DWORD dwFlags, HANDLE hContact, LPWSTR *plpwszFiles, size_t dwFilesCount, DWORD *pdwIDRequest) +{ + if ( !hFilesQueueHandle) + return ERROR_INVALID_HANDLE; + + MRA_FILES_QUEUE *pmrafqFilesQueue = (MRA_FILES_QUEUE*)hFilesQueueHandle; + MRA_FILES_QUEUE_ITEM *dat = (MRA_FILES_QUEUE_ITEM*)mir_calloc(sizeof(MRA_FILES_QUEUE_ITEM)+sizeof(LPSTR)+64); + if ( !dat) + return GetLastError(); + + ULARGE_INTEGER uliFileSize; + WIN32_FILE_ATTRIBUTE_DATA wfad; + + dat->ppro = this; + dat->bIsWorking = TRUE; + dat->dwSendTime = GetTickCount(); + dat->dwIDRequest = InterlockedIncrement((LONG volatile*)&dwCMDNum);// уникальный, рандомный идентификатор + dat->dwFlags = dwFlags; + dat->hContact = hContact; + if (mraGetByte(NULL, "FileSendEnableMRIMProxyCons", MRA_DEF_FS_ENABLE_MRIM_PROXY_CONS)) dat->hMraMrimProxyData = MraMrimProxyCreate(); + dat->dwFilesCount = dwFilesCount; + dat->pmfqfFiles = (MRA_FILES_QUEUE_FILE*)mir_calloc((sizeof(MRA_FILES_QUEUE_FILE)*(dat->dwFilesCount+1))); + dat->dwFilesTotalSize = 0; + + for (size_t i = 0; i < dat->dwFilesCount; i++) { + MRA_FILES_QUEUE_FILE &p = dat->pmfqfFiles[i]; + if (GetFileAttributesExW(plpwszFiles[i], GetFileExInfoStandard, &wfad)) { + uliFileSize.LowPart = wfad.nFileSizeLow; + uliFileSize.HighPart = wfad.nFileSizeHigh; + p.dwSize = uliFileSize.QuadPart; + dat->dwFilesTotalSize += uliFileSize.QuadPart; + } + else p.dwSize = 0; + + p.dwNameLen = lstrlenW(plpwszFiles[i]); + p.lpwszName = mir_wstrdup(plpwszFiles[i]); + } + + dat->bSending = TRUE; + if (pdwIDRequest) *pdwIDRequest = dat->dwIDRequest; + + { + mt_lock l(pmrafqFilesQueue); + ListMTItemAdd(pmrafqFilesQueue, dat, dat); + } + MRA_FILES_THREADPROC_PARAMS *pmftpp = (MRA_FILES_THREADPROC_PARAMS*)mir_calloc(sizeof(MRA_FILES_THREADPROC_PARAMS)); + pmftpp->hFilesQueueHandle = hFilesQueueHandle; + pmftpp->dat = dat; + dat->hThread = ForkThreadEx(&CMraProto::MraFilesQueueSendThreadProc, pmftpp); + + return NO_ERROR; +} + +void CMraProto::MraFilesQueueSendThreadProc(LPVOID lpParameter) +{ + DWORD dwRetErrorCode = NO_ERROR; + + if ( !lpParameter) + return; + + MRA_FILES_QUEUE *pmrafqFilesQueue = (MRA_FILES_QUEUE*)((MRA_FILES_THREADPROC_PARAMS*)lpParameter)->hFilesQueueHandle; + MRA_FILES_QUEUE_ITEM *dat = ((MRA_FILES_THREADPROC_PARAMS*)lpParameter)->dat; + mir_free(lpParameter); + + CHAR szFileName[MAX_FILEPATH] = {0}; + WCHAR szErrorText[2048]; + BYTE btBuff[BUFF_SIZE_RCV]; + BOOL bFailed = TRUE, bOK, bConnected = FALSE; + DWORD dwReceived, dwSendBlockSize, dwUpdateTimeNext, dwUpdateTimeCur; + size_t i, j, dwBuffSizeUsed = 0; + LPWSTR lpwszFileName; + + PROTOFILETRANSFERSTATUS pfts = {0}; + pfts.cbSize = sizeof(pfts); + pfts.hContact = dat->hContact; + pfts.flags = (PFTS_SENDING|PFTS_UNICODE);// pfts.sending = dat->bSending; //true if sending, false if receiving + pfts.totalFiles = dat->dwFilesCount; + pfts.totalBytes = dat->dwFilesTotalSize; + pfts.wszWorkingDir = dat->lpwszPath; + + dwSendBlockSize = mraGetDword(NULL, "FileSendBlockSize", MRA_DEFAULT_FILE_SEND_BLOCK_SIZE); + if (dwSendBlockSize>SIZEOF(btBuff)) dwSendBlockSize = SIZEOF(btBuff); + if (dwSendBlockSize<512) dwSendBlockSize = MRA_DEFAULT_FILE_SEND_BLOCK_SIZE; + + if (MraFilesQueueConnectIn(dat)) + bConnected = TRUE; + else if (MraFilesQueueConnectOut(dat)) + bConnected = TRUE; + else { + if (InterlockedExchangeAdd((volatile LONG*)&dat->bIsWorking, 0)) { + ProtoBroadcastAck(m_szModuleName, dat->hContact, ACKRESULT_CONNECTPROXY, ACKRESULT_CONNECTED, (HANDLE)dat->dwIDRequest, 0); + if (MraMrimProxyConnect(dat->hMraMrimProxyData, &dat->hConnection) == NO_ERROR) { + // подключились к прокси, проверяем та ли сессия (ещё раз, на этот раз сами) + if (MraFilesQueueHandCheck(dat->hConnection, dat)) { + // связь установленная с тем кем нужно// dat->bSending + ProtoBroadcastAck(m_szModuleName, dat->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTED, (HANDLE)dat->dwIDRequest, 0); + bConnected = TRUE; + } + } + } + } + + if (bConnected) { // email verified + bFailed = FALSE; + for (i = 0; i < dat->dwFilesCount; i++) { // sending files + ProtoBroadcastAck(m_szModuleName, dat->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, (HANDLE)dat->dwIDRequest, 0); + + dwBuffSizeUsed = 0; + while (TRUE) { + dwReceived = Netlib_Recv(dat->hConnection, ((LPSTR)btBuff+dwBuffSizeUsed), (SIZEOF(btBuff)-dwBuffSizeUsed), 0); + if (dwReceived == 0 || dwReceived == SOCKET_ERROR) { // err on receive file name to send + dwRetErrorCode = GetLastError(); + ShowFormattedErrorMessage(L"Send files: file send request not received, error", dwRetErrorCode); + bFailed = TRUE; + break; + } + else { + dwBuffSizeUsed += dwReceived; + if (MemoryFindByte((dwBuffSizeUsed-dwReceived), btBuff, dwBuffSizeUsed, 0)) + break; + } + }// end while (file name passible received)*/ + + if (bFailed) + break; + + // ...received + if (dwBuffSizeUsed > (sizeof(MRA_FT_GET_FILE)+1)) {// file name received + if (CompareStringA( MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), NORM_IGNORECASE, (LPSTR)btBuff, (sizeof(MRA_FT_GET_FILE)-1), MRA_FT_GET_FILE, (sizeof(MRA_FT_GET_FILE)-1)) == CSTR_EQUAL) { + // MRA_FT_GET_FILE verified + bFailed = TRUE; + for (j = 0;jdwFilesCount;j++) { + lpwszFileName = GetFileNameFromFullPathW(dat->pmfqfFiles[j].lpwszName, dat->pmfqfFiles[j].dwNameLen); + szFileName[WideCharToMultiByte(MRA_CODE_PAGE, 0, lpwszFileName, (dat->pmfqfFiles[j].dwNameLen-(lpwszFileName-dat->pmfqfFiles[j].lpwszName)), szFileName, SIZEOF(szFileName), NULL, NULL)] = 0; + + if (CompareStringA( MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), NORM_IGNORECASE, (((LPSTR)btBuff)+sizeof(MRA_FT_GET_FILE)), (dwBuffSizeUsed-(sizeof(MRA_FT_GET_FILE)+1)), szFileName, -1) == CSTR_EQUAL) { + bFailed = FALSE; + break; + } + } + + if (bFailed == FALSE) { + HANDLE hFile = CreateFileW(dat->pmfqfFiles[j].lpwszName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, (FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN), NULL); + if (hFile != INVALID_HANDLE_VALUE) { + bOK = FALSE; + dwUpdateTimeNext = GetTickCount(); + pfts.currentFileNumber = i; + pfts.wszCurrentFile = dat->pmfqfFiles[j].lpwszName; + pfts.currentFileSize = dat->pmfqfFiles[j].dwSize; + pfts.currentFileProgress = 0; + //pfts.currentFileTime; //as seconds since 1970 + + WideCharToMultiByte(MRA_CODE_PAGE, 0, dat->pmfqfFiles[j].lpwszName, dat->pmfqfFiles[j].dwNameLen, szFileName, SIZEOF(szFileName), NULL, NULL); + ProtoBroadcastAck(m_szModuleName, dat->hContact, ACKTYPE_FILE, ACKRESULT_DATA, (HANDLE)dat->dwIDRequest, (LPARAM)&pfts); + + while (TRUE) { // read and sending + if (ReadFile(hFile, btBuff, dwSendBlockSize, (DWORD*)&dwBuffSizeUsed, NULL)) { + dwReceived = Netlib_Send(dat->hConnection, (LPSTR)btBuff, dwBuffSizeUsed, 0); + if (dwBuffSizeUsed == dwReceived) { + pfts.currentFileProgress += dwBuffSizeUsed; + pfts.totalProgress += dwBuffSizeUsed; + + // progress updates + dwUpdateTimeCur = GetTickCount(); + if (dwUpdateTimeNext <= dwUpdateTimeCur || pfts.currentFileProgress >= dat->pmfqfFiles[j].dwSize) { // we update it + dwUpdateTimeNext = dwUpdateTimeCur+MRA_FILES_QUEUE_PROGRESS_INTERVAL; + + ProtoBroadcastAck(m_szModuleName, dat->hContact, ACKTYPE_FILE, ACKRESULT_DATA, (HANDLE)dat->dwIDRequest, (LPARAM)&pfts); + + if (pfts.currentFileProgress >= dat->pmfqfFiles[j].dwSize) { // file received + bOK = TRUE; + break; + } + } + } + else { // err on send file data + dwRetErrorCode = GetLastError(); + ShowFormattedErrorMessage(L"Send files: error on send file data", dwRetErrorCode); + break; + } + } + else {// read failure + dwRetErrorCode = GetLastError(); + ShowFormattedErrorMessage(L"Send files: cant read file data, error", dwRetErrorCode); + break; + } + }// end while + CloseHandle(hFile); + + if (bOK == FALSE) { // file recv failed + bFailed = TRUE; + break; + } + } + else {// err on open file + dwRetErrorCode = GetLastError(); + mir_sntprintf(szErrorText, SIZEOF(szErrorText), TranslateW(L"Send files: cant open file %s, error"), dat->pmfqfFiles[j].lpwszName); + ShowFormattedErrorMessage(szErrorText, dwRetErrorCode); + bFailed = TRUE; + break; + } + } + else { + mir_sntprintf(szErrorText, SIZEOF(szErrorText), TranslateW(L"Send files: requested file: %S - not found in send files list."), (((LPSTR)btBuff)+sizeof(MRA_FT_GET_FILE))); + ShowFormattedErrorMessage(szErrorText, NO_ERROR); + bFailed = TRUE; + break; + } + } + else {// err on receive, trash + ShowFormattedErrorMessage(L"Send files: bad file send request - invalid header", NO_ERROR); + bFailed = TRUE; + break; + } + } + else {// bad file name or trash + ShowFormattedErrorMessage(L"Send files: bad file send request - to small packet", NO_ERROR); + bFailed = TRUE; + break; + } + }// end for + + Netlib_CloseHandle(dat->hConnection); + dat->hConnection = NULL; + } + + if (bFailed) { + CHAR szEMail[MAX_EMAIL_LEN]; + size_t dwEMailSize; + + if (mraGetStaticStringA(dat->hContact, "e-mail", szEMail, SIZEOF(szEMail), &dwEMailSize)) + MraFileTransferAck(FILE_TRANSFER_STATUS_ERROR, szEMail, dwEMailSize, dat->dwIDRequest, NULL, 0); + + ProtoBroadcastAck(m_szModuleName, dat->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)dat->dwIDRequest, 0); + } + else ProtoBroadcastAck(m_szModuleName, dat->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, (HANDLE)dat->dwIDRequest, 0); + + mt_lock l(pmrafqFilesQueue); + MraFilesQueueItemFree(dat); +} diff --git a/protocols/MRA/src/MraFilesQueue.h b/protocols/MRA/src/MraFilesQueue.h new file mode 100644 index 0000000000..5c55c5b8ad --- /dev/null +++ b/protocols/MRA/src/MraFilesQueue.h @@ -0,0 +1,23 @@ +#if !defined(AFX_MRA_FILESQUEUE_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_) +#define AFX_MRA_FILESQUEUE_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_ + + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + +INT_PTR CALLBACK MraFilesQueueDlgProcOpts(HWND hWndDlg, UINT msg, WPARAM wParam, LPARAM lParam); +DWORD MraFilesQueueInitialize (DWORD dwFilesTimeOutInterval, HANDLE *phFilesQueueHandle); +void MraFilesQueueDestroy (HANDLE hFilesQueueHandle); + +void MraFilesQueueConnectionReceived(HANDLE hNewConnection, DWORD dwRemoteIP, void *pExtra); + +HANDLE MraFilesQueueItemProxyByID (HANDLE hFilesQueueHandle, DWORD dwIDRequest); +DWORD MraFilesQueueStartMrimProxy (HANDLE hFilesQueueHandle, DWORD dwIDRequest); +DWORD MraFilesQueueFree (HANDLE hFilesQueueHandle, DWORD dwCMDNum); + + + + +#endif // !defined(AFX_MRA_FILESQUEUE_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_) diff --git a/protocols/MRA/src/MraFilesQueue_mod.cpp b/protocols/MRA/src/MraFilesQueue_mod.cpp new file mode 100644 index 0000000000..b315636a69 --- /dev/null +++ b/protocols/MRA/src/MraFilesQueue_mod.cpp @@ -0,0 +1,1298 @@ +#include +#include +#include +#include +#include +#include +#include "MraFilesQueue.h" +#include "proto.h" +#include "Mra.h" + + + +#define MRA_FT_HELLO "MRA_FT_HELLO" +#define MRA_FT_GET_FILE "MRA_FT_GET_FILE" + + + +typedef struct +{ + LIST_MT lmtListMT; + DWORD dwSendTimeOutInterval; +} MRA_FILES_QUEUE; + + + +struct MRA_FILES_QUEUE_FILE +{ + LPSTR lpszName; + SIZE_T dwNameLen; + SIZE_T dwSize; +}; + +struct MRA_FILES_QUEUE_ADDR +{ + DWORD dwIP; + DWORD dwPort; +}; + + +typedef struct +{ + // internal + LIST_MT_ITEM lmtListMTItem; + DWORD dwSendTime; + // external + DWORD dwIDRequest; + DWORD dwFlags; + HANDLE hContact; + DWORD dwFilesCount; + DWORD dwFilesTotalSize; + DWORD dwAddrCount; + LPSTR lpszDescription; + SIZE_T dwDescriptionSize; + MRA_FILES_QUEUE_FILE *pmfqfFiles; + MRA_FILES_QUEUE_ADDR *pmfqaAddreses; + LPSTR lpszPath; + SIZE_T dwPathSize; + BOOL bSending; + HANDLE hConnection; + HANDLE hListen; + HANDLE hThread; + HANDLE hWaitHandle; + +} MRA_FILES_QUEUE_ITEM; + + + +struct MRA_FILES_THREADPROC_PARAMS +{ + HANDLE hFilesQueueHandle; + MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem; +}; + + + +//#define MEMALLOC(Size) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(Size+sizeof(SIZE_T))) +//#define MEMREALLOC(Mem,Size) HeapReAlloc(GetProcessHeap(),(HEAP_ZERO_MEMORY),(LPVOID)Mem,(Size+sizeof(SIZE_T))) +//#define MEMFREE(Mem) if (Mem) {HeapFree(GetProcessHeap(),0,(LPVOID)Mem);Mem=NULL;} + + +DWORD MraFilesQueueItemFindByID (HANDLE hFilesQueueHandle,DWORD dwIDRequest,MRA_FILES_QUEUE_ITEM **ppmrafqFilesQueueItem); +DWORD MraFilesQueueItemFindByEMail (HANDLE hFilesQueueHandle,LPSTR lpszEMail,SIZE_T dwEMailSize,MRA_FILES_QUEUE_ITEM **ppmrafqFilesQueueItem); +void MraFilesQueueItemFree (MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem); +SIZE_T MraFilesQueueGetLocalAddressesList (LPSTR lpszBuff,SIZE_T dwBuffSize,DWORD dwPort); + +BOOL MraFilesQueueHandCheck (HANDLE hConnection,MRA_FILES_QUEUE_ITEM **ppmrafqFilesQueueItem); +void MraFilesQueueConnectionReceived (HANDLE hNewConnection,DWORD dwRemoteIP,void *pExtra); + +DWORD WINAPI MraFilesQueueRecvThreadProc (LPVOID lpParameter); +DWORD WINAPI MraFilesQueueSendThreadProc (LPVOID lpParameter); + + + +BOOL CALLBACK MraFilesQueueDlgProcOpts(HWND hWndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch(msg){ + case WM_INITDIALOG: + { + DBVARIANT dbv; + TranslateDialogDefault(hWndDlg); + + CheckDlgButton(hWndDlg,IDC_FILE_SEND_HIDE_MY_NOOUTCONNECTIONONRECEIVE,DB_Mra_GetByte(NULL,"FileSendNoOutConnOnRcv",MRA_DEF_FS_NO_OUT_CONN_ON_RCV)); + CheckDlgButton(hWndDlg,IDC_FILE_SEND_HIDE_MY_NOOUTCONNECTIONONSEND,DB_Mra_GetByte(NULL,"FileSendNoOutConnOnSend",MRA_DEF_FS_NO_OUT_CONN_ON_SEND)); + CheckDlgButton(hWndDlg,IDC_FILE_SEND_IGNORYADDITIONALPORTS,DB_Mra_GetByte(NULL,"FileSendIgnoryAdditionalPorts",MRA_DEF_FS_IGNORY_ADDITIONAL_PORTS)); + CheckDlgButton(hWndDlg,IDC_FILE_SEND_HIDE_MY_ADDRESSES,DB_Mra_GetByte(NULL,"FileSendHideMyAddresses",MRA_DEF_FS_HIDE_MY_ADDRESSES)); + CheckDlgButton(hWndDlg,IDC_FILE_SEND_ADD_EXTRA_ADDRESS,DB_Mra_GetByte(NULL,"FileSendAddExtraAddresses",MRA_DEF_FS_ADD_EXTRA_ADDRESSES)); + if (!DBGetContactSetting(NULL,PROTOCOL_NAME,"FileSendExtraAddresses",&dbv)) { + //bit of a security hole here, since it's easy to extract a password from an edit box + SetDlgItemText(hWndDlg,IDC_FILE_SEND_EXTRA_ADDRESS,dbv.pszVal); + DBFreeVariant(&dbv); + } + EnableWindow(GetDlgItem(hWndDlg,IDC_FILE_SEND_EXTRA_ADDRESS),IsDlgButtonChecked(hWndDlg,IDC_FILE_SEND_ADD_EXTRA_ADDRESS)); + + SetDlgItemInt(hWndDlg,IDC_FILE_SEND_BLOCK_SIZE,DB_Mra_GetDword(NULL,"FileSendBlockSize",MRA_DEFAULT_FILE_SEND_BLOCK_SIZE),FALSE); + } + return(TRUE); + case WM_COMMAND: + if (LOWORD(wParam)==IDC_FILE_SEND_ADD_EXTRA_ADDRESS) + { + EnableWindow(GetDlgItem(hWndDlg,IDC_FILE_SEND_EXTRA_ADDRESS),IsDlgButtonChecked(hWndDlg,IDC_FILE_SEND_ADD_EXTRA_ADDRESS)); + } + + if ((LOWORD(wParam)==IDC_FILE_SEND_EXTRA_ADDRESS || LOWORD(wParam)==IDC_FILE_SEND_BLOCK_SIZE) && (HIWORD(wParam)!=EN_CHANGE || (HWND)lParam!=GetFocus()) ) return(0); + SendMessage(GetParent(hWndDlg),PSM_CHANGED,0,0); + break; + case WM_NOTIFY: + switch (((LPNMHDR)lParam)->code){ + case PSN_APPLY: + { + char szBuff[MAX_PATH]; + + DB_Mra_SetByte(NULL,"FileSendNoOutConnOnRcv",IsDlgButtonChecked(hWndDlg,IDC_FILE_SEND_HIDE_MY_NOOUTCONNECTIONONRECEIVE)); + DB_Mra_SetByte(NULL,"FileSendNoOutConnOnSend",IsDlgButtonChecked(hWndDlg,IDC_FILE_SEND_HIDE_MY_NOOUTCONNECTIONONSEND)); + DB_Mra_SetByte(NULL,"FileSendIgnoryAdditionalPorts",IsDlgButtonChecked(hWndDlg,IDC_FILE_SEND_IGNORYADDITIONALPORTS)); + DB_Mra_SetByte(NULL,"FileSendHideMyAddresses",IsDlgButtonChecked(hWndDlg,IDC_FILE_SEND_HIDE_MY_ADDRESSES)); + DB_Mra_SetByte(NULL,"FileSendAddExtraAddresses",IsDlgButtonChecked(hWndDlg,IDC_FILE_SEND_ADD_EXTRA_ADDRESS)); + GetDlgItemText(hWndDlg,IDC_FILE_SEND_EXTRA_ADDRESS,szBuff,sizeof(szBuff)); + DBWriteContactSettingString(NULL,PROTOCOL_NAME,"FileSendExtraAddresses",szBuff); + DB_Mra_SetDword(NULL,"FileSendBlockSize",(DWORD)GetDlgItemInt(hWndDlg,IDC_FILE_SEND_BLOCK_SIZE,NULL,FALSE)); + } + return(TRUE); + } + break; + } +return(FALSE); +} + + + +DWORD MraFilesQueueInitialize(DWORD dwSendTimeOutInterval,HANDLE *phFilesQueueHandle) +{ + DWORD dwRetErrorCode; + + if (phFilesQueueHandle) + { + MRA_FILES_QUEUE *pmrafqFilesQueue; + + pmrafqFilesQueue=(MRA_FILES_QUEUE*)MEMALLOC(sizeof(MRA_FILES_QUEUE)); + if (pmrafqFilesQueue) + { + dwRetErrorCode=ListMTInitialize(&pmrafqFilesQueue->lmtListMT,0); + if (dwRetErrorCode==NO_ERROR) + { + pmrafqFilesQueue->dwSendTimeOutInterval=dwSendTimeOutInterval; + (*phFilesQueueHandle)=(HANDLE)pmrafqFilesQueue; + }else{ + MEMFREE(pmrafqFilesQueue); + } + }else{ + dwRetErrorCode=GetLastError(); + } + }else{ + dwRetErrorCode=ERROR_INVALID_HANDLE; + } +return(dwRetErrorCode); +} + + +void MraFilesQueueDestroy(HANDLE hFilesQueueHandle) +{ + if (hFilesQueueHandle) + { + MRA_FILES_QUEUE *pmrafqFilesQueue=(MRA_FILES_QUEUE*)hFilesQueueHandle; + MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem; + + ListMTLock(&pmrafqFilesQueue->lmtListMT); + while(ListMTItemGetFirst(&pmrafqFilesQueue->lmtListMT,NULL,(LPVOID*)&pmrafqFilesQueueItem)==NO_ERROR) + { + ListMTItemDelete(&pmrafqFilesQueue->lmtListMT,&pmrafqFilesQueueItem->lmtListMTItem); + MraFilesQueueItemFree(pmrafqFilesQueueItem); + } + ListMTUnLock(&pmrafqFilesQueue->lmtListMT); + + ListMTDestroy(&pmrafqFilesQueue->lmtListMT); + MEMFREE(pmrafqFilesQueue); + } +} + + +DWORD MraFilesQueueItemFindByID(HANDLE hFilesQueueHandle,DWORD dwIDRequest,MRA_FILES_QUEUE_ITEM **ppmrafqFilesQueueItem) +{ + DWORD dwRetErrorCode; + + if (hFilesQueueHandle) + { + MRA_FILES_QUEUE *pmrafqFilesQueue=(MRA_FILES_QUEUE*)hFilesQueueHandle; + MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem; + LIST_MT_ITERATOR lmtiIterator; + + dwRetErrorCode=ERROR_NOT_FOUND; + ListMTLock(&pmrafqFilesQueue->lmtListMT); + ListMTIteratorMoveFirst(&pmrafqFilesQueue->lmtListMT,&lmtiIterator); + do + {// цикл + if (ListMTIteratorGet(&lmtiIterator,NULL,(LPVOID*)&pmrafqFilesQueueItem)==NO_ERROR) + if (pmrafqFilesQueueItem->dwIDRequest==dwIDRequest) + { + if (ppmrafqFilesQueueItem) (*ppmrafqFilesQueueItem)=pmrafqFilesQueueItem; + dwRetErrorCode=NO_ERROR; + break; + } + }while(ListMTIteratorMoveNext(&lmtiIterator)); + ListMTUnLock(&pmrafqFilesQueue->lmtListMT); + }else{ + dwRetErrorCode=ERROR_INVALID_HANDLE; + } +return(dwRetErrorCode); +} + + +DWORD MraFilesQueueItemFindByEMail(HANDLE hFilesQueueHandle,LPSTR lpszEMail,SIZE_T dwEMailSize,MRA_FILES_QUEUE_ITEM **ppmrafqFilesQueueItem) +{ + DWORD dwRetErrorCode; + + if (hFilesQueueHandle) + { + char szEMailLocal[MAX_EMAIL_LEN]; + SIZE_T dwEMailLocalSize; + MRA_FILES_QUEUE *pmrafqFilesQueue=(MRA_FILES_QUEUE*)hFilesQueueHandle; + MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem; + LIST_MT_ITERATOR lmtiIterator; + + dwRetErrorCode=ERROR_NOT_FOUND; + ListMTLock(&pmrafqFilesQueue->lmtListMT); + ListMTIteratorMoveFirst(&pmrafqFilesQueue->lmtListMT,&lmtiIterator); + do + {// цикл + if (ListMTIteratorGet(&lmtiIterator,NULL,(LPVOID*)&pmrafqFilesQueueItem)==NO_ERROR) + if (DB_Mra_GetStaticString(pmrafqFilesQueueItem->hContact,"e-mail",szEMailLocal,sizeof(szEMailLocal),&dwEMailLocalSize)) + if (dwEMailSize==dwEMailLocalSize) + if (CompareStringA(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),NORM_IGNORECASE,lpszEMail,dwEMailSize,szEMailLocal,dwEMailLocalSize)==CSTR_EQUAL) + { + if (ppmrafqFilesQueueItem) (*ppmrafqFilesQueueItem)=pmrafqFilesQueueItem; + dwRetErrorCode=NO_ERROR; + break; + } + }while(ListMTIteratorMoveNext(&lmtiIterator)); + ListMTUnLock(&pmrafqFilesQueue->lmtListMT); + }else{ + dwRetErrorCode=ERROR_INVALID_HANDLE; + } +return(dwRetErrorCode); +} + + +void MraFilesQueueItemFree(MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem) +{ + + for(SIZE_T i=0;idwFilesCount;i++) + { + MEMFREE(pmrafqFilesQueueItem->pmfqfFiles[i].lpszName); + } + MEMFREE(pmrafqFilesQueueItem->pmfqfFiles); + MEMFREE(pmrafqFilesQueueItem->pmfqaAddreses); + MEMFREE(pmrafqFilesQueueItem->lpszPath); + //MEMFREE(pmrafqFilesQueueItem->lpszDescription); //placed after pmrafqFilesQueueItem + MEMFREE(pmrafqFilesQueueItem); +} + + + + + +SIZE_T MraFilesQueueGetLocalAddressesList(LPSTR lpszBuff,SIZE_T dwBuffSize,DWORD dwPort) +{ + char szHostName[MAX_PATH]={0}; + LPSTR lpszCurPos=lpszBuff; + SIZE_T dwAdapter=0; + hostent *sh; + + if (DB_Mra_GetByte(NULL,"FileSendHideMyAddresses",MRA_DEF_FS_HIDE_MY_ADDRESSES)) + {// не выдаём врагу наш IP адрес!!! :) + lpszCurPos+=mir_snprintf(lpszCurPos,(dwBuffSize-(lpszCurPos-lpszBuff)),"192.168.0.1:26775;"); + }else{// создаём список наших IP адресов + if (gethostname(szHostName,sizeof(szHostName))==0) + if ((sh=gethostbyname((LPSTR)&szHostName))) + { + while(sh->h_addr_list[dwAdapter]) + { + lpszCurPos+=mir_snprintf(lpszCurPos,(dwBuffSize-(lpszCurPos-lpszBuff)),"%s:%ld;",inet_ntoa(*((struct in_addr*)sh->h_addr_list[dwAdapter])),dwPort); + dwAdapter++; + } + } + } + + if (DB_Mra_GetByte(NULL,"FileSendAddExtraAddresses",MRA_DEF_FS_ADD_EXTRA_ADDRESSES))// добавляем произвольный адрес + if (DB_Mra_GetStaticString(NULL,"FileSendExtraAddresses",szHostName,sizeof(szHostName),NULL)) + { + lpszCurPos+=mir_snprintf(lpszCurPos,(dwBuffSize-(lpszCurPos-lpszBuff)),"%s:%ld;",szHostName,dwPort); + } +return((lpszCurPos-lpszBuff)); +} + + + + +DWORD MraFilesQueueAddReceive(HANDLE hFilesQueueHandle,DWORD dwFlags,HANDLE hContact,DWORD dwIDRequest,DWORD dwFilesTotalSize,LPSTR lpszFiles,SIZE_T dwFilesSize,LPSTR lpszDescription,SIZE_T dwDescriptionSize,LPSTR lpszAddreses,SIZE_T dwAddresesSize) +{ + DWORD dwRetErrorCode; + + if (hFilesQueueHandle && dwIDRequest) + { + MRA_FILES_QUEUE *pmrafqFilesQueue=(MRA_FILES_QUEUE*)hFilesQueueHandle; + MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem; + + if (!lpszDescription || dwDescriptionSize==0) + { + lpszDescription=Translate("No description given"); + dwDescriptionSize=lstrlenA(lpszDescription); + } + + pmrafqFilesQueueItem=(MRA_FILES_QUEUE_ITEM*)MEMALLOC(sizeof(MRA_FILES_QUEUE_ITEM)+sizeof(LPSTR)+dwDescriptionSize+64); + if (pmrafqFilesQueueItem) + { + char szBuff[MAX_PATH]; + LPSTR lpszCurrentItem,lpszDelimiter,lpszEndItem,lpszBlob; + SIZE_T dwMemSize,dwAllocatedCount; + CCSDATA ccs; + PROTORECVEVENT pre; + + //pmrafqFilesQueueItem->lmtListMTItem; + pmrafqFilesQueueItem->dwSendTime=GetTickCount(); + pmrafqFilesQueueItem->dwIDRequest=dwIDRequest; + pmrafqFilesQueueItem->dwFlags=dwFlags; + pmrafqFilesQueueItem->hContact=hContact; + pmrafqFilesQueueItem->lpszDescription=(LPSTR)(pmrafqFilesQueueItem+1); + pmrafqFilesQueueItem->dwDescriptionSize=dwDescriptionSize; + CopyMemory(pmrafqFilesQueueItem->lpszDescription,lpszDescription,dwDescriptionSize); + + + dwAllocatedCount=ALLOCATED_COUNT; + pmrafqFilesQueueItem->dwFilesCount=0; + pmrafqFilesQueueItem->dwFilesTotalSize=dwFilesTotalSize; + pmrafqFilesQueueItem->pmfqfFiles=(MRA_FILES_QUEUE_FILE*)MEMALLOC((sizeof(MRA_FILES_QUEUE_FILE)*dwAllocatedCount)); + lpszCurrentItem=lpszFiles; + while(TRUE) + { + lpszDelimiter=(LPSTR)MemoryFindByte((lpszCurrentItem-lpszFiles),lpszFiles,dwFilesSize,';'); + if (lpszDelimiter) + { + lpszEndItem=(LPSTR)MemoryFindByte(((lpszDelimiter+1)-lpszFiles),lpszFiles,dwFilesSize,';'); + if (lpszEndItem) + { + if (pmrafqFilesQueueItem->dwFilesCount==dwAllocatedCount) + { + dwAllocatedCount*=2; + pmrafqFilesQueueItem->pmfqfFiles=(MRA_FILES_QUEUE_FILE*)MEMREALLOC(pmrafqFilesQueueItem->pmfqfFiles,(sizeof(MRA_FILES_QUEUE_FILE)*dwAllocatedCount)); + } + + dwMemSize=(lpszDelimiter-lpszCurrentItem); + pmrafqFilesQueueItem->pmfqfFiles[pmrafqFilesQueueItem->dwFilesCount].lpszName=(LPSTR)MEMALLOC(dwMemSize); + CopyMemory(pmrafqFilesQueueItem->pmfqfFiles[pmrafqFilesQueueItem->dwFilesCount].lpszName,lpszCurrentItem,dwMemSize); + pmrafqFilesQueueItem->pmfqfFiles[pmrafqFilesQueueItem->dwFilesCount].dwNameLen=dwMemSize; + pmrafqFilesQueueItem->pmfqfFiles[pmrafqFilesQueueItem->dwFilesCount].dwSize=StrToUNum32((lpszDelimiter+1),(lpszEndItem-(lpszDelimiter+1))); + + pmrafqFilesQueueItem->dwFilesCount++; + lpszCurrentItem=(lpszEndItem+1); + }else{ + break; + } + }else{ + break; + } + } + pmrafqFilesQueueItem->pmfqfFiles=(MRA_FILES_QUEUE_FILE*)MEMREALLOC(pmrafqFilesQueueItem->pmfqfFiles,(sizeof(MRA_FILES_QUEUE_FILE)*pmrafqFilesQueueItem->dwFilesCount)); + + + dwAllocatedCount=ALLOCATED_COUNT; + pmrafqFilesQueueItem->dwAddrCount=0; + pmrafqFilesQueueItem->pmfqaAddreses=(MRA_FILES_QUEUE_ADDR*)MEMALLOC(sizeof(MRA_FILES_QUEUE_ADDR)*dwAllocatedCount); + lpszCurrentItem=lpszAddreses; + while(TRUE) + { + lpszEndItem=(LPSTR)MemoryFindByte((lpszCurrentItem-lpszAddreses),lpszAddreses,dwAddresesSize,';'); + if (lpszEndItem) + { + lpszDelimiter=(LPSTR)MemoryFindByte((lpszCurrentItem-lpszAddreses),lpszAddreses,dwAddresesSize,':'); + if (lpszDelimiter) + { + if (pmrafqFilesQueueItem->dwAddrCount==dwAllocatedCount) + { + dwAllocatedCount*=2; + pmrafqFilesQueueItem->pmfqaAddreses=(MRA_FILES_QUEUE_ADDR*)MEMREALLOC(pmrafqFilesQueueItem->pmfqaAddreses,(sizeof(MRA_FILES_QUEUE_ADDR)*dwAllocatedCount)); + } + + (*lpszDelimiter)=0; + pmrafqFilesQueueItem->pmfqaAddreses[pmrafqFilesQueueItem->dwAddrCount].dwIP=inet_addr(lpszCurrentItem); + pmrafqFilesQueueItem->pmfqaAddreses[pmrafqFilesQueueItem->dwAddrCount].dwPort=StrToUNum32((lpszDelimiter+1),(lpszEndItem-(lpszDelimiter+1))); + (*lpszDelimiter)=':'; + + switch(pmrafqFilesQueueItem->dwAddrCount){ + case 0: + DB_Mra_SetDword(pmrafqFilesQueueItem->hContact,"OldIP",DB_Mra_GetDword(pmrafqFilesQueueItem->hContact,"IP",0));DB_Mra_SetDword(pmrafqFilesQueueItem->hContact,"IP",htonl(pmrafqFilesQueueItem->pmfqaAddreses[pmrafqFilesQueueItem->dwAddrCount].dwIP)); + break; + case 1: + DB_Mra_SetDword(pmrafqFilesQueueItem->hContact,"OldRealIP",DB_Mra_GetDword(pmrafqFilesQueueItem->hContact,"RealIP",0));DB_Mra_SetDword(pmrafqFilesQueueItem->hContact,"RealIP",htonl(pmrafqFilesQueueItem->pmfqaAddreses[pmrafqFilesQueueItem->dwAddrCount].dwIP)); + break; + } + pmrafqFilesQueueItem->dwAddrCount++; + lpszCurrentItem=(lpszEndItem+1); + }else{ + break; + } + }else{ + break; + } + } + pmrafqFilesQueueItem->pmfqaAddreses=(MRA_FILES_QUEUE_ADDR*)MEMREALLOC(pmrafqFilesQueueItem->pmfqaAddreses,(sizeof(MRA_FILES_QUEUE_ADDR)*pmrafqFilesQueueItem->dwAddrCount)); + + ListMTLock(&pmrafqFilesQueue->lmtListMT); + ListMTItemAdd(&pmrafqFilesQueue->lmtListMT,&pmrafqFilesQueueItem->lmtListMTItem,pmrafqFilesQueueItem); + ListMTUnLock(&pmrafqFilesQueue->lmtListMT); + + + // Send chain event + dwMemSize=(sizeof(DWORD)+dwDescriptionSize+dwAddresesSize+sizeof(SIZE_T)); + for(SIZE_T i=0;idwFilesCount;i++) + { + dwMemSize+=(pmrafqFilesQueueItem->pmfqfFiles[i].dwNameLen+64); + } + lpszBlob=(LPSTR)MEMALLOC(dwMemSize); + lpszCurrentItem=lpszBlob; + // user data + (*((DWORD*)lpszCurrentItem))=dwIDRequest;lpszCurrentItem+=sizeof(DWORD); + // file name + StrFormatByteSizeA(pmrafqFilesQueueItem->dwFilesTotalSize,szBuff,sizeof(szBuff)); + lpszCurrentItem+=(mir_snprintf(lpszCurrentItem,(dwMemSize-(lpszCurrentItem-lpszBlob)),"%ld Files (%s)",pmrafqFilesQueueItem->dwFilesCount,szBuff)+1); + // description + for(SIZE_T i=0;idwFilesCount;i++) + { + StrFormatByteSizeA(pmrafqFilesQueueItem->pmfqfFiles[i].dwSize,szBuff,sizeof(szBuff)); + lpszCurrentItem+=mir_snprintf(lpszCurrentItem,(dwMemSize-(lpszCurrentItem-lpszBlob)),"%s - %s\r\n",pmrafqFilesQueueItem->pmfqfFiles[i].lpszName,szBuff); + } + CopyMemory(lpszCurrentItem,lpszAddreses,dwAddresesSize);lpszCurrentItem+=dwAddresesSize; + lpszCurrentItem+=(mir_snprintf(lpszCurrentItem,(dwMemSize-(lpszCurrentItem-lpszBlob)),"\r\n%s",lpszDescription)+1); + + ccs.szProtoService=PSR_FILE; + ccs.hContact=hContact; + ccs.wParam=0; + ccs.lParam=(LPARAM)⪯ + pre.flags=0; + pre.timestamp=time(NULL); + pre.szMessage=lpszBlob; + pre.lParam=(lpszCurrentItem-lpszBlob); + + CallService(MS_PROTO_CHAINRECV,0,(LPARAM)&ccs); + MEMFREE(lpszBlob); + + dwRetErrorCode=NO_ERROR; + }else{ + dwRetErrorCode=GetLastError(); + } + }else{ + dwRetErrorCode=ERROR_INVALID_HANDLE; + } +return(dwRetErrorCode); +} + + + +DWORD MraFilesQueueAddSend(HANDLE hFilesQueueHandle,DWORD dwFlags,HANDLE hContact,LPSTR *plpszFiles,LPSTR lpszDescription,SIZE_T dwDescriptionSize,DWORD *pdwIDRequest) +{ + DWORD dwRetErrorCode; + + if (hFilesQueueHandle) + { + MRA_FILES_QUEUE *pmrafqFilesQueue=(MRA_FILES_QUEUE*)hFilesQueueHandle; + MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem; + + + pmrafqFilesQueueItem=(MRA_FILES_QUEUE_ITEM*)MEMALLOC(sizeof(MRA_FILES_QUEUE_ITEM)+sizeof(LPSTR)+dwDescriptionSize+64); + if (pmrafqFilesQueueItem) + { + SIZE_T i; + WIN32_FILE_ATTRIBUTE_DATA wfad; + + //pmrafqFilesQueueItem->lmtListMTItem; + pmrafqFilesQueueItem->dwSendTime=GetTickCount(); + pmrafqFilesQueueItem->dwIDRequest=InterlockedIncrement((LONG volatile*)&masMraSettings.dwCMDNum);// уникальный, рандомный идентификатор + pmrafqFilesQueueItem->dwFlags=dwFlags; + pmrafqFilesQueueItem->hContact=hContact; + pmrafqFilesQueueItem->lpszDescription=(LPSTR)(pmrafqFilesQueueItem+1); + pmrafqFilesQueueItem->dwDescriptionSize=dwDescriptionSize; + CopyMemory(pmrafqFilesQueueItem->lpszDescription,lpszDescription,dwDescriptionSize); + + + for(pmrafqFilesQueueItem->dwFilesCount=0;plpszFiles[pmrafqFilesQueueItem->dwFilesCount];pmrafqFilesQueueItem->dwFilesCount++); + pmrafqFilesQueueItem->pmfqfFiles=(MRA_FILES_QUEUE_FILE*)MEMALLOC((sizeof(MRA_FILES_QUEUE_FILE)*(pmrafqFilesQueueItem->dwFilesCount+1))); + pmrafqFilesQueueItem->dwFilesTotalSize=0; + + for(i=0;idwFilesCount;i++) + { + if (GetFileAttributesExA(plpszFiles[i],GetFileExInfoStandard,&wfad)) + { + pmrafqFilesQueueItem->pmfqfFiles[i].dwSize=wfad.nFileSizeLow; + pmrafqFilesQueueItem->dwFilesTotalSize+=wfad.nFileSizeLow; + }else{ + pmrafqFilesQueueItem->pmfqfFiles[i].dwSize=0; + } + pmrafqFilesQueueItem->pmfqfFiles[i].dwNameLen=lstrlenA(plpszFiles[i]); + pmrafqFilesQueueItem->pmfqfFiles[i].lpszName=(LPSTR)MEMALLOC(pmrafqFilesQueueItem->pmfqfFiles[i].dwNameLen); + CopyMemory(pmrafqFilesQueueItem->pmfqfFiles[i].lpszName,plpszFiles[i],pmrafqFilesQueueItem->pmfqfFiles[i].dwNameLen); + } + //pmrafqFilesQueueItem->dwAddrCount=0; + //pmrafqFilesQueueItem->pmfqaAddreses=NULL; + pmrafqFilesQueueItem->bSending=TRUE; + if (pdwIDRequest) (*pdwIDRequest)=pmrafqFilesQueueItem->dwIDRequest; + + ListMTLock(&pmrafqFilesQueue->lmtListMT); + ListMTItemAdd(&pmrafqFilesQueue->lmtListMT,&pmrafqFilesQueueItem->lmtListMTItem,pmrafqFilesQueueItem); + ListMTUnLock(&pmrafqFilesQueue->lmtListMT); + + { + MRA_FILES_THREADPROC_PARAMS *pmftpp=(MRA_FILES_THREADPROC_PARAMS*)MEMALLOC(sizeof(MRA_FILES_THREADPROC_PARAMS)); + pmftpp->hFilesQueueHandle=hFilesQueueHandle; + pmftpp->pmrafqFilesQueueItem=pmrafqFilesQueueItem; + + pmrafqFilesQueueItem->hThread=CreateThread(0,0,MraFilesQueueSendThreadProc,pmftpp,0,NULL); + } + + dwRetErrorCode=NO_ERROR; + }else{ + dwRetErrorCode=GetLastError(); + } + }else{ + dwRetErrorCode=ERROR_INVALID_HANDLE; + } +return(dwRetErrorCode); +} + + + +DWORD MraFilesQueueAccept(HANDLE hFilesQueueHandle,DWORD dwIDRequest,LPSTR lpszPath,SIZE_T dwPathSize) +{ + DWORD dwRetErrorCode; + + if (hFilesQueueHandle) + { + MRA_FILES_QUEUE *pmrafqFilesQueue=(MRA_FILES_QUEUE*)hFilesQueueHandle; + MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem; + + ListMTLock(&pmrafqFilesQueue->lmtListMT); + if ((dwRetErrorCode=MraFilesQueueItemFindByID(hFilesQueueHandle,dwIDRequest,&pmrafqFilesQueueItem))==NO_ERROR) + { + MRA_FILES_THREADPROC_PARAMS *pmftpp=(MRA_FILES_THREADPROC_PARAMS*)MEMALLOC(sizeof(MRA_FILES_THREADPROC_PARAMS)); + pmrafqFilesQueueItem->lpszPath=(LPSTR)MEMALLOC(dwPathSize); + pmrafqFilesQueueItem->dwPathSize=dwPathSize; + CopyMemory(pmrafqFilesQueueItem->lpszPath,lpszPath,dwPathSize); + + pmftpp->hFilesQueueHandle=hFilesQueueHandle; + pmftpp->pmrafqFilesQueueItem=pmrafqFilesQueueItem; + + pmrafqFilesQueueItem->hThread=CreateThread(0,0,MraFilesQueueRecvThreadProc,pmftpp,0,NULL); + } + ListMTUnLock(&pmrafqFilesQueue->lmtListMT); + }else{ + dwRetErrorCode=ERROR_INVALID_HANDLE; + } +return(dwRetErrorCode); +} + + +DWORD MraFilesQueueDecline(HANDLE hFilesQueueHandle,DWORD dwIDRequest,LPSTR lpszDescription,SIZE_T dwDescriptionSize) +{ + DWORD dwRetErrorCode; + + if (hFilesQueueHandle) + { + MRA_FILES_QUEUE *pmrafqFilesQueue=(MRA_FILES_QUEUE*)hFilesQueueHandle; + MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem; + + ListMTLock(&pmrafqFilesQueue->lmtListMT); + if ((dwRetErrorCode=MraFilesQueueItemFindByID(hFilesQueueHandle,dwIDRequest,&pmrafqFilesQueueItem))==NO_ERROR) + { + char szEMail[MAX_EMAIL_LEN]; + SIZE_T dwEMailSize; + if (DB_Mra_GetStaticString(pmrafqFilesQueueItem->hContact,"e-mail",szEMail,sizeof(szEMail),&dwEMailSize)) + { + MraSendCommand_FileTransferAck(FILE_TRANSFER_STATUS_DECLINE,szEMail,dwEMailSize,dwIDRequest,lpszDescription,dwDescriptionSize); + } + ListMTItemDelete(&pmrafqFilesQueue->lmtListMT,&pmrafqFilesQueueItem->lmtListMTItem); + MraFilesQueueItemFree(pmrafqFilesQueueItem); + } + ListMTUnLock(&pmrafqFilesQueue->lmtListMT); + }else{ + dwRetErrorCode=ERROR_INVALID_HANDLE; + } +return(dwRetErrorCode); +} + + +DWORD MraFilesQueueCancel(HANDLE hFilesQueueHandle,DWORD dwIDRequest,BOOL bSendDecline) +{ + DWORD dwRetErrorCode; + + if (hFilesQueueHandle) + { + MRA_FILES_QUEUE *pmrafqFilesQueue=(MRA_FILES_QUEUE*)hFilesQueueHandle; + MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem; + + ListMTLock(&pmrafqFilesQueue->lmtListMT); + if ((dwRetErrorCode=MraFilesQueueItemFindByID(hFilesQueueHandle,dwIDRequest,&pmrafqFilesQueueItem))==NO_ERROR) + {//***deb closesocket, send message to thread + if (bSendDecline) + { + char szEMail[MAX_EMAIL_LEN]; + SIZE_T dwEMailSize; + if (DB_Mra_GetStaticString(pmrafqFilesQueueItem->hContact,"e-mail",szEMail,sizeof(szEMail),&dwEMailSize)) + { + MraSendCommand_FileTransferAck(FILE_TRANSFER_STATUS_DECLINE,szEMail,dwEMailSize,dwIDRequest,NULL,0); + } + } + Netlib_CloseHandle(pmrafqFilesQueueItem->hConnection); + pmrafqFilesQueueItem->hConnection=NULL; + + Netlib_CloseHandle(pmrafqFilesQueueItem->hListen); + pmrafqFilesQueueItem->hListen=NULL; + + SetEvent(pmrafqFilesQueueItem->hWaitHandle); + + if (pmrafqFilesQueueItem->hThread==NULL) + { + ListMTItemDelete(&pmrafqFilesQueue->lmtListMT,&pmrafqFilesQueueItem->lmtListMTItem); + MraFilesQueueItemFree(pmrafqFilesQueueItem); + } + } + ListMTUnLock(&pmrafqFilesQueue->lmtListMT); + }else{ + dwRetErrorCode=ERROR_INVALID_HANDLE; + } +return(dwRetErrorCode); +} + + +DWORD MraFilesQueueFree(HANDLE hFilesQueueHandle,DWORD dwIDRequest) +{ + DWORD dwRetErrorCode; + + if (hFilesQueueHandle) + { + MRA_FILES_QUEUE *pmrafqFilesQueue=(MRA_FILES_QUEUE*)hFilesQueueHandle; + MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem; + LIST_MT_ITERATOR lmtiIterator; + + dwRetErrorCode=ERROR_NOT_FOUND; + ListMTLock(&pmrafqFilesQueue->lmtListMT); + ListMTIteratorMoveFirst(&pmrafqFilesQueue->lmtListMT,&lmtiIterator); + do + {// цикл + if (ListMTIteratorGet(&lmtiIterator,NULL,(LPVOID*)&pmrafqFilesQueueItem)==NO_ERROR) + if (pmrafqFilesQueueItem->dwIDRequest==dwIDRequest) + { + ListMTItemDelete(&pmrafqFilesQueue->lmtListMT,&pmrafqFilesQueueItem->lmtListMTItem); + MraFilesQueueItemFree(pmrafqFilesQueueItem); + dwRetErrorCode=NO_ERROR; + break; + } + }while(ListMTIteratorMoveNext(&lmtiIterator)); + ListMTUnLock(&pmrafqFilesQueue->lmtListMT); + }else{ + dwRetErrorCode=ERROR_INVALID_HANDLE; + } +return(dwRetErrorCode); +} + + +DWORD MraFilesQueueSendMirror(HANDLE hFilesQueueHandle,DWORD dwIDRequest,LPSTR lpszAddreses,SIZE_T dwAddresesSize) +{ + DWORD dwRetErrorCode; + + if (hFilesQueueHandle) + { + MRA_FILES_QUEUE *pmrafqFilesQueue=(MRA_FILES_QUEUE*)hFilesQueueHandle; + MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem; + + ListMTLock(&pmrafqFilesQueue->lmtListMT); + if ((dwRetErrorCode=MraFilesQueueItemFindByID(hFilesQueueHandle,dwIDRequest,&pmrafqFilesQueueItem))==NO_ERROR) + {// + LPSTR lpszCurrentItem,lpszDelimiter,lpszEndItem; + SIZE_T dwAllocatedCount; + + dwAllocatedCount=ALLOCATED_COUNT; + pmrafqFilesQueueItem->dwAddrCount=0; + pmrafqFilesQueueItem->pmfqaAddreses=(MRA_FILES_QUEUE_ADDR*)MEMALLOC(sizeof(MRA_FILES_QUEUE_ADDR)*dwAllocatedCount); + lpszCurrentItem=lpszAddreses; + while(TRUE) + { + lpszEndItem=(LPSTR)MemoryFindByte((lpszCurrentItem-lpszAddreses),lpszAddreses,dwAddresesSize,';'); + if (lpszEndItem) + { + lpszDelimiter=(LPSTR)MemoryFindByte((lpszCurrentItem-lpszAddreses),lpszAddreses,dwAddresesSize,':'); + if (lpszDelimiter) + { + if (pmrafqFilesQueueItem->dwAddrCount==dwAllocatedCount) + { + dwAllocatedCount*=2; + pmrafqFilesQueueItem->pmfqaAddreses=(MRA_FILES_QUEUE_ADDR*)MEMREALLOC(pmrafqFilesQueueItem->pmfqaAddreses,(sizeof(MRA_FILES_QUEUE_ADDR)*dwAllocatedCount)); + } + + (*lpszDelimiter)=0; + pmrafqFilesQueueItem->pmfqaAddreses[pmrafqFilesQueueItem->dwAddrCount].dwIP=inet_addr(lpszCurrentItem); + pmrafqFilesQueueItem->pmfqaAddreses[pmrafqFilesQueueItem->dwAddrCount].dwPort=StrToUNum32((lpszDelimiter+1),(lpszEndItem-(lpszDelimiter+1))); + (*lpszDelimiter)=':'; + + switch(pmrafqFilesQueueItem->dwAddrCount){ + case 0: + DB_Mra_SetDword(pmrafqFilesQueueItem->hContact,"OldIP",DB_Mra_GetDword(pmrafqFilesQueueItem->hContact,"IP",0)); + DB_Mra_SetDword(pmrafqFilesQueueItem->hContact,"IP",htonl(pmrafqFilesQueueItem->pmfqaAddreses[pmrafqFilesQueueItem->dwAddrCount].dwIP)); + break; + case 1: + DB_Mra_SetDword(pmrafqFilesQueueItem->hContact,"OldRealIP",DB_Mra_GetDword(pmrafqFilesQueueItem->hContact,"RealIP",0)); + DB_Mra_SetDword(pmrafqFilesQueueItem->hContact,"RealIP",htonl(pmrafqFilesQueueItem->pmfqaAddreses[pmrafqFilesQueueItem->dwAddrCount].dwIP)); + break; + } + pmrafqFilesQueueItem->dwAddrCount++; + lpszCurrentItem=(lpszEndItem+1); + }else{ + break; + } + }else{ + break; + } + } + pmrafqFilesQueueItem->pmfqaAddreses=(MRA_FILES_QUEUE_ADDR*)MEMREALLOC(pmrafqFilesQueueItem->pmfqaAddreses,(sizeof(MRA_FILES_QUEUE_ADDR)*pmrafqFilesQueueItem->dwAddrCount)); + + pmrafqFilesQueueItem->hConnection=NULL; + SetEvent(pmrafqFilesQueueItem->hWaitHandle); + } + ListMTUnLock(&pmrafqFilesQueue->lmtListMT); + }else{ + dwRetErrorCode=ERROR_INVALID_HANDLE; + } +return(dwRetErrorCode); +} + + + +BOOL MraFilesQueueHandCheck(HANDLE hConnection,MRA_FILES_QUEUE_ITEM **ppmrafqFilesQueueItem) +{ + BOOL bRet=FALSE; + + if (hConnection) + { + char szEMail[MAX_EMAIL_LEN]={0},szEMailMy[MAX_EMAIL_LEN]={0}; + BYTE btBuff[((MAX_EMAIL_LEN*2)+(sizeof(MRA_FT_HELLO)*2)+8)]={0}; + SIZE_T dwEMailSize,dwEMailMySize,dwBuffSize; + + DB_Mra_GetStaticString(NULL,"e-mail",szEMailMy,sizeof(szEMailMy),&dwEMailMySize);BuffToLowerCase(szEMailMy,szEMailMy,dwEMailMySize); + + if (pmrafqFilesQueueItem->bSending==FALSE) + { + dwBuffSize=(mir_snprintf((LPSTR)btBuff,sizeof(btBuff),"%s %s",MRA_FT_HELLO,szEMailMy)+1); + if (dwBuffSize==Netlib_Send(hConnection,(LPSTR)btBuff,dwBuffSize,0)) + {// my email sended + //ProtoBroadcastAck(PROTOCOL_NAME,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_INITIALISING,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,0); + dwBuffSize=Netlib_Recv(hConnection,(LPSTR)btBuff,sizeof(btBuff),0); + if (ppmrafqFilesQueueItem && (*ppmrafqFilesQueueItem)) + {// have context, connecting or some times in receive + DB_Mra_GetStaticString((*ppmrafqFilesQueueItem)->hContact,"e-mail",szEMail,sizeof(szEMail),&dwEMailSize);BuffToLowerCase(szEMail,szEMail,dwEMailSize); + if ((dwEMailSize+sizeof(MRA_FT_HELLO)+1)==dwBuffSize) + {// email received + mir_snprintf(((LPSTR)btBuff+dwBuffSize),(sizeof(btBuff)-dwBuffSize),"%s %s",MRA_FT_HELLO,szEMail); + if (CompareStringA(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),NORM_IGNORECASE,(LPSTR)btBuff,dwBuffSize,((LPSTR)btBuff+dwBuffSize),dwBuffSize)==CSTR_EQUAL) + {// email verifyed + bRet=TRUE; + } + } + }else{// some times on receive pExtra=NULL, and we looking for context + if (dwBuffSize!=SOCKET_ERROR && dwBuffSize>sizeof(MRA_FT_HELLO)) + {// readed + if (MraFilesQueueItemFindByEMail(HANDLE hFilesQueueHandle,((LPSTR)btBuff+sizeof(MRA_FT_HELLO)),(dwBuffSize-(sizeof(MRA_FT_HELLO)+1)),ppmrafqFilesQueueItem)==NO_ERROR) + {// email verifyed + bRet=TRUE; + } + } + } + } + }else{ + dwBuffSize=Netlib_Recv(hConnection,(LPSTR)btBuff,sizeof(btBuff),0); + if (ppmrafqFilesQueueItem && (*ppmrafqFilesQueueItem)) + {// have context, connecting or some times in receive + DB_Mra_GetStaticString((*ppmrafqFilesQueueItem)->hContact,"e-mail",szEMail,sizeof(szEMail),&dwEMailSize);BuffToLowerCase(szEMail,szEMail,dwEMailSize); + if ((dwEMailSize+sizeof(MRA_FT_HELLO)+1)==dwBuffSize) + {// email received + ProtoBroadcastAck(PROTOCOL_NAME,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_INITIALISING,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,0); + mir_snprintf(((LPSTR)btBuff+dwBuffSize),(sizeof(btBuff)-dwBuffSize),"%s %s",MRA_FT_HELLO,szEMail); + if (CompareStringA(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),NORM_IGNORECASE,(LPSTR)btBuff,dwBuffSize,((LPSTR)btBuff+dwBuffSize),dwBuffSize)==CSTR_EQUAL) + {// email verifyed + dwBuffSize=(mir_snprintf((LPSTR)btBuff,sizeof(btBuff),"%s %s",MRA_FT_HELLO,szEMailMy)+1); + if (dwBuffSize==Netlib_Send(hConnection,(LPSTR)btBuff,dwBuffSize,0)) + {// my email sended + bRet=TRUE; + } + } + } + }else{// some times on receive pExtra=NULL, and we looking for context + if (dwBuffSize!=SOCKET_ERROR && dwBuffSize>sizeof(MRA_FT_HELLO)) + {// readed + if (MraFilesQueueItemFindByEMail(HANDLE hFilesQueueHandle,((LPSTR)btBuff+sizeof(MRA_FT_HELLO)),(dwBuffSize-(sizeof(MRA_FT_HELLO)+1)),ppmrafqFilesQueueItem)==NO_ERROR) + {// email verifyed + ProtoBroadcastAck(PROTOCOL_NAME,(*ppmrafqFilesQueueItem)->hContact,ACKTYPE_FILE,ACKRESULT_INITIALISING,(HANDLE)(*ppmrafqFilesQueueItem)->dwIDRequest,0); + dwBuffSize=(mir_snprintf((LPSTR)btBuff,sizeof(btBuff),"%s %s",MRA_FT_HELLO,szEMailMy)+1); + if (dwBuffSize==Netlib_Send(hConnection,(LPSTR)btBuff,dwBuffSize,0)) + {// my email sended + bRet=TRUE; + } + } + } + } + } + } +return(bRet); +} + + +HANDLE MraFilesQueueConnectOut(MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem) +{ + if ((pmrafqFilesQueueItem->bSending==FALSE && DB_Mra_GetByte(NULL,"FileSendNoOutConnOnRcv",MRA_DEF_FS_NO_OUT_CONN_ON_RCV)==FALSE) || (pmrafqFilesQueueItem->bSending==TRUE && DB_Mra_GetByte(NULL,"FileSendNoOutConnOnSend",MRA_DEF_FS_NO_OUT_CONN_ON_SEND)==FALSE)) + { + BOOL bFiltering=FALSE; + DWORD dwLocalPort=0; + SIZE_T i; + NETLIBOPENCONNECTION nloc={0}; + + nloc.cbSize=sizeof(nloc); + nloc.flags=NLOCF_V2; + if (DB_Mra_GetByte(NULL,"FileSendIgnoryAdditionalPorts",MRA_DEF_FS_IGNORY_ADDITIONAL_PORTS)) + {// фильтруем порты для одного IP, вместо 3 будем коннектится только к одному + switch(DB_Mra_GetWord(NULL,"ServerPort",MRA_DEFAULT_SERVER_PORT)) { + case MRA_SERVER_PORT_STANDART_NLB: + dwLocalPort=MRA_SERVER_PORT_STANDART; + break; + case MRA_SERVER_PORT_HTTPS: + dwLocalPort=MRA_SERVER_PORT_HTTPS; + break; + default: + dwLocalPort=DB_Mra_GetWord(NULL,"ServerPort",MRA_DEFAULT_SERVER_PORT); + break; + } + + for(i=0;idwAddrCount;i++) + {// Set up the sockaddr structure + if (dwLocalPort==pmrafqFilesQueueItem->pmfqaAddreses[i].dwPort) + { + bFiltering=TRUE; + break; + } + } + } + + for(i=0;idwAddrCount;i++) + {// Set up the sockaddr structure + if (dwLocalPort==pmrafqFilesQueueItem->pmfqaAddreses[i].dwPort || bFiltering==FALSE) + { + nloc.szHost=inet_ntoa((*((in_addr*)&pmrafqFilesQueueItem->pmfqaAddreses[i].dwIP))); + nloc.wPort=(WORD)pmrafqFilesQueueItem->pmfqaAddreses[i].dwPort; + + ProtoBroadcastAck(PROTOCOL_NAME,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_CONNECTING,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,0); + if ((pmrafqFilesQueueItem->hConnection=(HANDLE)CallService(MS_NETLIB_OPENCONNECTION,(WPARAM)masMraSettings.hNetlibUser,(LPARAM)&nloc))) + { + ProtoBroadcastAck(PROTOCOL_NAME,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_CONNECTED,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,0); + if (MraFilesQueueHandCheck(pmrafqFilesQueueItem->hConnection,&pmrafqFilesQueueItem)) + {// связь установленная с тем кем нужно + break; + }else{// кажется не туда подключились :) + ProtoBroadcastAck(PROTOCOL_NAME,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_CONNECTING,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,0); + Netlib_CloseHandle(pmrafqFilesQueueItem->hConnection); + pmrafqFilesQueueItem->hConnection=NULL; + } + } + } + } + } +return(pmrafqFilesQueueItem->hConnection); +} + + +HANDLE MraFilesQueueConnectIn(MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem) +{ + char szEMail[MAX_EMAIL_LEN],szAddrList[2048]={0}; + SIZE_T dwEMailSize,dwAddrListSize; + NETLIBBIND nlbBind={0}; + + nlbBind.cbSize=sizeof(nlbBind); + nlbBind.pfnNewConnectionV2=MraFilesQueueConnectionReceived; + nlbBind.wPort=0; + nlbBind.pExtra=(LPVOID)pmrafqFilesQueueItem; + + if (DB_Mra_GetStaticString(pmrafqFilesQueueItem->hContact,"e-mail",szEMail,sizeof(szEMail),&dwEMailSize)) + if ((pmrafqFilesQueueItem->hListen=(HANDLE)CallService(MS_NETLIB_BINDPORT,(WPARAM)masMraSettings.hNetlibUser,(LPARAM)&nlbBind))) + { + dwAddrListSize=MraFilesQueueGetLocalAddressesList(szAddrList,sizeof(szAddrList),nlbBind.wPort); + if (dwAddrListSize) + { + pmrafqFilesQueueItem->hWaitHandle=CreateEvent(NULL,TRUE,FALSE,NULL); + if (pmrafqFilesQueueItem->bSending==FALSE) + {// запрашиваем зеркальное соединение + MraSendCommand_FileTransferAck(FILE_TRANSFER_MIRROR,szEMail,dwEMailSize,pmrafqFilesQueueItem->dwIDRequest,szAddrList,dwAddrListSize); + }else{// здесь отправляем запрос на передачу(установление соединения) + LPSTR lpszFiles,lpszFileName,lpszCurPos; + SIZE_T i,dwFilesSize=((MAX_PATH*2)*pmrafqFilesQueueItem->dwFilesCount); + + lpszFiles=(LPSTR)MEMALLOC(dwFilesSize); + if (lpszFiles) + { + lpszCurPos=lpszFiles; + for(i=0;idwFilesCount;i++) + { + GetFullPathName(pmrafqFilesQueueItem->pmfqfFiles[i].lpszName,MAX_PATH,pmrafqFilesQueueItem->pmfqfFiles[i].lpszName,&lpszFileName); + lpszCurPos+=mir_snprintf(lpszCurPos,(dwFilesSize-(lpszCurPos-lpszFiles)),"%s;%ld;",lpszFileName,pmrafqFilesQueueItem->pmfqfFiles[i].dwSize); + } + MraSendCommand_FileTransfer(szEMail,dwEMailSize,pmrafqFilesQueueItem->dwIDRequest,pmrafqFilesQueueItem->dwFilesTotalSize,lpszFiles,(lpszCurPos-lpszFiles),pmrafqFilesQueueItem->lpszDescription,pmrafqFilesQueueItem->dwDescriptionSize,szAddrList,dwAddrListSize); + MEMFREE(lpszFiles); + } + } + + WaitForSingleObject(pmrafqFilesQueueItem->hWaitHandle,INFINITE); + CloseHandle(pmrafqFilesQueueItem->hWaitHandle); + pmrafqFilesQueueItem->hWaitHandle=NULL; + Netlib_CloseHandle(pmrafqFilesQueueItem->hListen); + pmrafqFilesQueueItem->hListen=NULL; + } + } +return(pmrafqFilesQueueItem->hConnection); +} + +// This function is called from the Netlib when someone is connecting to +// one of our incomming DC ports +void MraFilesQueueConnectionReceived(HANDLE hNewConnection,DWORD dwRemoteIP,void *pExtra) +{ + MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem=(MRA_FILES_QUEUE_ITEM*)pExtra; + + if (MraFilesQueueHandCheck(hNewConnection,&pmrafqFilesQueueItem)) + {// связь установленная с тем кем нужно + pmrafqFilesQueueItem->hConnection=hNewConnection; + ProtoBroadcastAck(PROTOCOL_NAME,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_CONNECTED,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,0); + DB_Mra_SetDword(pmrafqFilesQueueItem->hContact,"OldIP",DB_Mra_GetDword(pmrafqFilesQueueItem->hContact,"IP",0)); + DB_Mra_SetDword(pmrafqFilesQueueItem->hContact,"IP",dwRemoteIP); + SetEvent(pmrafqFilesQueueItem->hWaitHandle); + }else{// кажется кто то не туда подключилися :) + if (pmrafqFilesQueueItem) ProtoBroadcastAck(PROTOCOL_NAME,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_CONNECTING,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,0); + Netlib_CloseHandle(hNewConnection); + } + + if (pExtra==NULL) + { + MraPopupShowFromAgent(MRA_POPUP_TYPE_DEBUG,0,"MraFilesQueueConnectionReceived: connection accepted, but pExtra=NULL, this is miranda bug."); + DebugBreak(); + } +} + + + +DWORD WINAPI MraFilesQueueRecvThreadProc(LPVOID lpParameter) +{ + MRA_FILES_QUEUE *pmrafqFilesQueue=(MRA_FILES_QUEUE*)((MRA_FILES_THREADPROC_PARAMS*)lpParameter)->hFilesQueueHandle; + MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem=((MRA_FILES_THREADPROC_PARAMS*)lpParameter)->pmrafqFilesQueueItem; + + char szFileName[MAX_FILEPATH]={0}; + BYTE btBuff[65536]; + BOOL bFailed=TRUE,bOK,bConnected=FALSE; + DWORD dwWritten,dwReceived,dwUpdateTimeNext,dwUpdateTimeCur; + HANDLE hFile; + SIZE_T i,dwBuffSize; + PROTOFILETRANSFERSTATUS pfts={0}; + + + MEMFREE(lpParameter); + pfts.cbSize=sizeof(pfts); + pfts.hContact=pmrafqFilesQueueItem->hContact; + pfts.sending=pmrafqFilesQueueItem->bSending; //true if sending, false if receiving + //pfts.files; + pfts.totalFiles=pmrafqFilesQueueItem->dwFilesCount; + pfts.currentFileNumber=0; + pfts.totalBytes=pmrafqFilesQueueItem->dwFilesTotalSize; + pfts.totalProgress=0; + pfts.workingDir=pmrafqFilesQueueItem->lpszPath; + //pfts.currentFile; + //pfts.currentFileSize; + //pfts.currentFileProgress; + //pfts.currentFileTime; //as seconds since 1970 + + + CallService(MS_SYSTEM_THREAD_PUSH,0,0); + //ProtoBroadcastAck(PROTOCOL_NAME,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_CONNECTING,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,0); + + if (MraFilesQueueConnectOut(pmrafqFilesQueueItem)) + { + bConnected=TRUE; + }else{ + if (MraFilesQueueConnectIn(pmrafqFilesQueueItem)) bConnected=TRUE; + } + + if (bConnected) + {// email verifyed + bFailed=FALSE; + for(i=0;idwFilesCount;i++) + {// receiving files + ProtoBroadcastAck(PROTOCOL_NAME,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_NEXTFILE,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,0); + dwBuffSize=(mir_snprintf((LPSTR)btBuff,sizeof(btBuff),"%s %s",MRA_FT_GET_FILE,pmrafqFilesQueueItem->pmfqfFiles[i].lpszName)+1); + if (dwBuffSize==Netlib_Send(pmrafqFilesQueueItem->hConnection,(LPSTR)btBuff,dwBuffSize,0)) + {// file request sended + mir_snprintf(szFileName,sizeof(szFileName),"%s%s",pmrafqFilesQueueItem->lpszPath,pmrafqFilesQueueItem->pmfqfFiles[i].lpszName); + hFile=CreateFile(szFileName,GENERIC_WRITE,FILE_SHARE_READ,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); + if (hFile!=INVALID_HANDLE_VALUE) + { + bOK=FALSE; + dwWritten=0; + dwUpdateTimeNext=GetTickCount(); + pfts.currentFileNumber=i; + pfts.currentFile=pmrafqFilesQueueItem->pmfqfFiles[i].lpszName; + pfts.currentFileSize=pmrafqFilesQueueItem->pmfqfFiles[i].dwSize; + pfts.currentFileProgress=0; + //pfts.currentFileTime; //as seconds since 1970 + ProtoBroadcastAck(PROTOCOL_NAME,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_DATA,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,(LPARAM)&pfts); + + // pre allocating disk space, best perfomance + SetFilePointer(hFile,pmrafqFilesQueueItem->pmfqfFiles[i].dwSize,NULL,FILE_BEGIN); + SetEndOfFile(hFile); + SetFilePointer(hFile,0,NULL,FILE_BEGIN); + + while(TRUE) + { + dwReceived=Netlib_Recv(pmrafqFilesQueueItem->hConnection,(LPSTR)&btBuff,sizeof(btBuff),0); + if (dwReceived==0 || dwReceived==SOCKET_ERROR) + { + dwWritten=0; + break; + }else{ + WriteFile(hFile,(LPVOID)&btBuff,dwReceived,&dwReceived,NULL); + dwWritten+=dwReceived; + pfts.totalProgress+=dwReceived; + if (dwWritten>=pmrafqFilesQueueItem->pmfqfFiles[i].dwSize) + { + dwUpdateTimeNext=GetTickCount();// force stat update + bOK=TRUE; + break; + } + + // progress updates + dwUpdateTimeCur=GetTickCount(); + if (dwUpdateTimeNext<=dwUpdateTimeCur) + {// we update it + dwUpdateTimeNext=dwUpdateTimeCur+MRA_FILES_QUEUE_PROGRESS_INTERVAL; + pfts.currentFileProgress=dwWritten; + ProtoBroadcastAck(PROTOCOL_NAME,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_DATA,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,(LPARAM)&pfts); + } + } + }// end while + CloseHandle(hFile); + + if (bOK==FALSE) + {// file recv failed + DeleteFile(szFileName); + bFailed=TRUE; + break; + } + }else{// err on write file + bFailed=TRUE; + break; + } + }else{//err + break; + } + }// end for + + Netlib_CloseHandle(pmrafqFilesQueueItem->hConnection); + pmrafqFilesQueueItem->hConnection=NULL; + } + + if (bFailed) + { + char szEMail[MAX_EMAIL_LEN]; + SIZE_T dwEMailSize; + if (DB_Mra_GetStaticString(pmrafqFilesQueueItem->hContact,"e-mail",szEMail,sizeof(szEMail),&dwEMailSize)) + { + MraSendCommand_FileTransferAck(FILE_TRANSFER_STATUS_DECLINE,szEMail,dwEMailSize,pmrafqFilesQueueItem->dwIDRequest,NULL,0); + } + ProtoBroadcastAck(PROTOCOL_NAME,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_FAILED,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,0); + }else{ + ProtoBroadcastAck(PROTOCOL_NAME,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_SUCCESS,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,0); + } + + ListMTLock(&pmrafqFilesQueue->lmtListMT); + ListMTItemDelete(&pmrafqFilesQueue->lmtListMT,&pmrafqFilesQueueItem->lmtListMTItem); + CloseHandle(pmrafqFilesQueueItem->hThread); + MraFilesQueueItemFree(pmrafqFilesQueueItem); + ListMTUnLock(&pmrafqFilesQueue->lmtListMT); + + CallService(MS_SYSTEM_THREAD_POP,0,0); + ExitThread(NO_ERROR); +return(0); +} + + + +DWORD WINAPI MraFilesQueueSendThreadProc(LPVOID lpParameter) +{ + MRA_FILES_QUEUE *pmrafqFilesQueue=(MRA_FILES_QUEUE*)((MRA_FILES_THREADPROC_PARAMS*)lpParameter)->hFilesQueueHandle; + MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem=((MRA_FILES_THREADPROC_PARAMS*)lpParameter)->pmrafqFilesQueueItem; + + BYTE btBuff[65536]; + BOOL bFailed=TRUE,bOK,bConnected=FALSE; + DWORD dwReceived,dwSended,dwSendBlockSize,dwUpdateTimeNext,dwUpdateTimeCur; + HANDLE hFile; + SIZE_T i,j,dwBuffSize=0; + LPSTR lpszFileName; + PROTOFILETRANSFERSTATUS pfts={0}; + + + MEMFREE(lpParameter); + pfts.cbSize=sizeof(pfts); + pfts.hContact=pmrafqFilesQueueItem->hContact; + pfts.sending=pmrafqFilesQueueItem->bSending; //true if sending, false if receiving + //pfts.files; + pfts.totalFiles=pmrafqFilesQueueItem->dwFilesCount; + pfts.currentFileNumber=0; + pfts.totalBytes=pmrafqFilesQueueItem->dwFilesTotalSize; + pfts.totalProgress=0; + pfts.workingDir=pmrafqFilesQueueItem->lpszPath; + //pfts.currentFile; + //pfts.currentFileSize; + //pfts.currentFileProgress; + //pfts.currentFileTime; //as seconds since 1970 + dwSendBlockSize=DB_Mra_GetDword(NULL,"FileSendBlockSize",MRA_DEFAULT_FILE_SEND_BLOCK_SIZE); + if (dwSendBlockSize>sizeof(btBuff)) dwSendBlockSize=sizeof(btBuff); + if (dwSendBlockSize<512) dwSendBlockSize=MRA_DEFAULT_FILE_SEND_BLOCK_SIZE; + + + CallService(MS_SYSTEM_THREAD_PUSH,0,0); + //ProtoBroadcastAck(PROTOCOL_NAME,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_SENTREQUEST,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,0); + + if (MraFilesQueueConnectIn(pmrafqFilesQueueItem)) + { + bConnected=TRUE; + }else{ + if (MraFilesQueueConnectOut(pmrafqFilesQueueItem)) bConnected=TRUE; + } + + if (bConnected) + {// email verifyed + bFailed=FALSE; + for(i=0;idwFilesCount;i++) + {// seiding files + ProtoBroadcastAck(PROTOCOL_NAME,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_NEXTFILE,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,0); + + dwBuffSize=0; + while(TRUE) + { + dwReceived=Netlib_Recv(pmrafqFilesQueueItem->hConnection,((LPSTR)btBuff+dwBuffSize),(sizeof(btBuff)-dwBuffSize),0); + if (dwReceived==0 || dwReceived==SOCKET_ERROR) + { + bFailed=TRUE; + break; + }else{ + dwBuffSize+=dwReceived; + if (MemoryFindByte((dwBuffSize-dwReceived),btBuff,dwBuffSize,0)) break; + } + }// end while (file name passible received)*/ + + if (bFailed==FALSE) + {// ...received + if (dwBuffSize>(sizeof(MRA_FT_GET_FILE)+1)) + {// file name received + if (CompareStringA(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),NORM_IGNORECASE,(LPSTR)btBuff,(sizeof(MRA_FT_GET_FILE)-1),MRA_FT_GET_FILE,(sizeof(MRA_FT_GET_FILE)-1))==CSTR_EQUAL) + {// MRA_FT_GET_FILE verifyed + bFailed=TRUE; + for(j=0;jdwFilesCount;j++) + { + if (GetFullPathName(pmrafqFilesQueueItem->pmfqfFiles[j].lpszName,(pmrafqFilesQueueItem->pmfqfFiles[j].dwNameLen+1),pmrafqFilesQueueItem->pmfqfFiles[j].lpszName,&lpszFileName)) + if (CompareStringA(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),NORM_IGNORECASE,(((LPSTR)btBuff)+sizeof(MRA_FT_GET_FILE)),(dwBuffSize-(sizeof(MRA_FT_GET_FILE)+1)),lpszFileName,-1)==CSTR_EQUAL) + { + bFailed=FALSE; + break; + } + } + + if (bFailed==FALSE) + { + hFile=CreateFile(pmrafqFilesQueueItem->pmfqfFiles[j].lpszName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,(FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN),NULL); + if (hFile!=INVALID_HANDLE_VALUE) + { + bOK=FALSE; + dwUpdateTimeNext=GetTickCount(); + pfts.currentFileNumber=i; + pfts.currentFile=pmrafqFilesQueueItem->pmfqfFiles[j].lpszName; + pfts.currentFileSize=pmrafqFilesQueueItem->pmfqfFiles[j].dwSize; + pfts.currentFileProgress=0; + //pfts.currentFileTime; //as seconds since 1970 + ProtoBroadcastAck(PROTOCOL_NAME,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_DATA,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,(LPARAM)&pfts); + + while(TRUE) + {// read and sending + if (ReadFile(hFile,btBuff,dwSendBlockSize,&dwBuffSize,NULL)) + { + dwSended=Netlib_Send(pmrafqFilesQueueItem->hConnection,(LPSTR)btBuff,dwBuffSize,0); + if (dwSended==0 || dwSended==SOCKET_ERROR) + { + break; + }else{ + pfts.currentFileProgress+=dwSended; + pfts.totalProgress+=dwSended; + if (pfts.currentFileProgress>=pmrafqFilesQueueItem->pmfqfFiles[j].dwSize) + { + dwUpdateTimeNext=GetTickCount();// force stat update + bOK=TRUE; + break; + } + + // progress updates + dwUpdateTimeCur=GetTickCount(); + if (dwUpdateTimeNext<=dwUpdateTimeCur) + {// we update it + dwUpdateTimeNext=dwUpdateTimeCur+MRA_FILES_QUEUE_PROGRESS_INTERVAL; + //pfts.currentFileProgress=dwSended; + ProtoBroadcastAck(PROTOCOL_NAME,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_DATA,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,(LPARAM)&pfts); + } + } + }else{// read failure + break; + } + }// end while + CloseHandle(hFile); + + if (bOK==FALSE) + {// file recv failed + bFailed=TRUE; + break; + } + ProtoBroadcastAck(PROTOCOL_NAME,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_DATA,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,(LPARAM)&pfts); + }else{// err on read file + bFailed=TRUE; + break; + } + }else{ + break; + } + }else{// err on receive, trash + bFailed=TRUE; + break; + } + }else{// bad file name or trash + bFailed=TRUE; + break; + } + }else{// err on receive + bFailed=TRUE; + break; + } + }// end for + + Netlib_CloseHandle(pmrafqFilesQueueItem->hConnection); + pmrafqFilesQueueItem->hConnection=NULL; + } + + if (bFailed) + { + char szEMail[MAX_EMAIL_LEN]; + SIZE_T dwEMailSize; + if (DB_Mra_GetStaticString(pmrafqFilesQueueItem->hContact,"e-mail",szEMail,sizeof(szEMail),&dwEMailSize)) + { + MraSendCommand_FileTransferAck(FILE_TRANSFER_STATUS_DECLINE,szEMail,dwEMailSize,pmrafqFilesQueueItem->dwIDRequest,NULL,0); + } + ProtoBroadcastAck(PROTOCOL_NAME,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_FAILED,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,0); + }else{ + ProtoBroadcastAck(PROTOCOL_NAME,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_SUCCESS,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,0); + } + + ListMTLock(&pmrafqFilesQueue->lmtListMT); + ListMTItemDelete(&pmrafqFilesQueue->lmtListMT,&pmrafqFilesQueueItem->lmtListMTItem); + CloseHandle(pmrafqFilesQueueItem->hThread); + MraFilesQueueItemFree(pmrafqFilesQueueItem); + ListMTUnLock(&pmrafqFilesQueue->lmtListMT); + + CallService(MS_SYSTEM_THREAD_POP,0,0); + ExitThread(NO_ERROR); +return(0); +} diff --git a/protocols/MRA/src/MraIcons.cpp b/protocols/MRA/src/MraIcons.cpp new file mode 100644 index 0000000000..d3d6828238 --- /dev/null +++ b/protocols/MRA/src/MraIcons.cpp @@ -0,0 +1,208 @@ +#include "Mra.h" +#include "MraIcons.h" + +GUI_DISPLAY_ITEM gdiMenuItems[] = +{ + { MRA_GOTO_INBOX, MRA_GOTO_INBOX_STR, IDI_INBOX, &CMraProto::MraGotoInbox }, + { MRA_SHOW_INBOX_STATUS, MRA_SHOW_INBOX_STATUS_STR, IDI_MAIL_NOTIFY, &CMraProto::MraShowInboxStatus }, + { MRA_EDIT_PROFILE, MRA_EDIT_PROFILE_STR, IDI_PROFILE, &CMraProto::MraEditProfile }, + { MRA_MY_ALBUM, MRA_MY_ALBUM_STR, IDI_MRA_PHOTO, &CMraProto::MraViewAlbum }, + { MRA_MY_BLOG, MRA_MY_BLOG_STR, IDI_MRA_BLOGS, &CMraProto::MraReadBlog }, + { MRA_MY_BLOGSTATUS, MRA_MY_BLOGSTATUS_STR, IDI_BLOGSTATUS, &CMraProto::MraReplyBlogStatus }, + { MRA_MY_VIDEO, MRA_MY_VIDEO_STR, IDI_MRA_VIDEO, &CMraProto::MraViewVideo }, + { MRA_MY_ANSWERS, MRA_MY_ANSWERS_STR, IDI_MRA_ANSWERS, &CMraProto::MraAnswers }, + { MRA_MY_WORLD, MRA_MY_WORLD_STR, IDI_MRA_WORLD, &CMraProto::MraWorld }, + { MRA_ZHUKI, MRA_ZHUKI_STR, IDI_MRA_ZHUKI, &CMraProto::MraZhuki }, + { MRA_CHAT, MRA_CHAT_STR, IDI_MRA_CHAT, &CMraProto::MraChat }, + { MRA_WEB_SEARCH, MRA_WEB_SEARCH_STR, IDI_MRA_WEB_SEARCH, &CMraProto::MraWebSearch }, + { MRA_UPD_ALL_USERS_INFO, MRA_UPD_ALL_USERS_INFO_STR, IDI_PROFILE, &CMraProto::MraUpdateAllUsersInfo }, + { MRA_CHK_USERS_AVATARS, MRA_CHK_USERS_AVATARS_STR, IDI_PROFILE, &CMraProto::MraCheckUpdatesUsersAvt }, + { MRA_REQ_AUTH_FOR_ALL, MRA_REQ_AUTH_FOR_ALL_STR, IDI_AUTHRUGUEST, &CMraProto::MraRequestAuthForAll } +}; + +GUI_DISPLAY_ITEM gdiContactMenuItems[] = +{ + { MRA_REQ_AUTH, MRA_REQ_AUTH_STR, IDI_AUTHRUGUEST, &CMraProto::MraRequestAuthorization }, + { MRA_GRANT_AUTH, MRA_GRANT_AUTH_STR, IDI_AUTHGRANT, &CMraProto::MraGrantAuthorization }, + { MRA_SEND_POSTCARD, MRA_SEND_POSTCARD_STR, IDI_MRA_POSTCARD, &CMraProto::MraSendPostcard }, + { MRA_VIEW_ALBUM, MRA_VIEW_ALBUM_STR, IDI_MRA_PHOTO, &CMraProto::MraViewAlbum }, + { MRA_READ_BLOG, MRA_READ_BLOG_STR , IDI_MRA_BLOGS, &CMraProto::MraReadBlog }, + { MRA_REPLY_BLOG_STATUS, MRA_REPLY_BLOG_STATUS_STR, IDI_BLOGSTATUS, &CMraProto::MraReplyBlogStatus }, + { MRA_VIEW_VIDEO, MRA_VIEW_VIDEO_STR, IDI_MRA_VIDEO, &CMraProto::MraViewVideo }, + { MRA_ANSWERS, MRA_ANSWERS_STR, IDI_MRA_ANSWERS, &CMraProto::MraAnswers }, + { MRA_WORLD, MRA_WORLD_STR, IDI_MRA_WORLD, &CMraProto::MraWorld }, + { MRA_SEND_NUDGE, MRA_SENDNUDGE_STR, IDI_MRA_ALARM, NULL } +}; + +GUI_DISPLAY_ITEM gdiExtraStatusIconsItems[] = +{ + { ADV_ICON_DELETED_ID, ADV_ICON_DELETED_STR, (INT_PTR)IDI_ERROR, NULL }, + { ADV_ICON_NOT_ON_SERVER_ID, ADV_ICON_NOT_ON_SERVER_STR, IDI_AUTHGRANT, NULL }, + { ADV_ICON_NOT_AUTHORIZED_ID, ADV_ICON_NOT_AUTHORIZED_STR, IDI_AUTHRUGUEST, NULL }, + { ADV_ICON_PHONE_ID, ADV_ICON_PHONE_STR, IDI_MRA_PHONE, NULL }, + { ADV_ICON_BLOGSTATUS_ID, ADV_ICON_BLOGSTATUS_STR, IDI_BLOGSTATUS, NULL }, +}; + +////////////////////////////////////////////////////////////////////////////////////// + +static void AddIcoLibItems(LPWSTR lpwszSubSectionName, GUI_DISPLAY_ITEM *pgdiItems, size_t dwCount) +{ + char szBuff[MAX_PATH]; + WCHAR wszSection[MAX_PATH], wszPath[MAX_FILEPATH]; + + SKINICONDESC sid = {0}; + sid.cbSize = sizeof(sid); + sid.pwszSection = wszSection; + sid.pwszDefaultFile = wszPath; + sid.cx = sid.cy = 16; + sid.flags = SIDF_ALL_UNICODE; + + if (lpwszSubSectionName == NULL) lpwszSubSectionName = L""; + GetModuleFileName(masMraSettings.hInstance, wszPath, SIZEOF(wszPath)); + mir_sntprintf(wszSection, SIZEOF(wszSection), L"Protocols/MRA/%s", lpwszSubSectionName); + + for (size_t i = 0;i 1000 +#pragma once +#endif // _MSC_VER > 1000 + + +HICON IconLibGetIcon(HANDLE hIcon); +HICON IconLibGetIconEx(HANDLE hIcon, DWORD dwFlags); + +#endif // !defined(AFX_MRA_ICONS_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_) \ No newline at end of file diff --git a/protocols/MRA/src/MraMPop.cpp b/protocols/MRA/src/MraMPop.cpp new file mode 100644 index 0000000000..ec49686f5e --- /dev/null +++ b/protocols/MRA/src/MraMPop.cpp @@ -0,0 +1,181 @@ +#include "Mra.h" +#include "MraMPop.h" + +// MPOP_SESSION +struct MRA_MPOP_SESSION_QUEUE : public FIFO_MT +{ + BOOL bKeyValid; + LPSTR lpszMPOPKey; + size_t dwMPOPKeySize; +}; + +struct MRA_MPOP_SESSION_QUEUE_ITEM : public FIFO_MT_ITEM +{ + LPSTR lpszUrl; + size_t dwUrlSize; +}; + +void MraMPopSessionQueueClear(HANDLE hMPopSessionQueue); + +DWORD MraMPopSessionQueueInitialize(HANDLE *phMPopSessionQueue) +{ + if (!phMPopSessionQueue) + return ERROR_ALREADY_INITIALIZED; + + MRA_MPOP_SESSION_QUEUE *pmpsqMPopSessionQueue = (MRA_MPOP_SESSION_QUEUE*)mir_calloc(sizeof(MRA_MPOP_SESSION_QUEUE)); + if (!pmpsqMPopSessionQueue) + return GetLastError(); + + pmpsqMPopSessionQueue->bKeyValid = FALSE; + pmpsqMPopSessionQueue->lpszMPOPKey = NULL; + pmpsqMPopSessionQueue->dwMPOPKeySize = 0; + FifoMTInitialize(pmpsqMPopSessionQueue, 0); + *phMPopSessionQueue = (HANDLE)pmpsqMPopSessionQueue; + return NO_ERROR; +} + +void MraMPopSessionQueueClear(HANDLE hMPopSessionQueue) +{ + if (hMPopSessionQueue) { + MRA_MPOP_SESSION_QUEUE *pmpsqMPopSessionQueue = (MRA_MPOP_SESSION_QUEUE*)hMPopSessionQueue; + pmpsqMPopSessionQueue->bKeyValid = FALSE; + mir_free(pmpsqMPopSessionQueue->lpszMPOPKey); + pmpsqMPopSessionQueue->dwMPOPKeySize = 0; + + MRA_MPOP_SESSION_QUEUE_ITEM *pmpsqi; + while ( !FifoMTItemPop(pmpsqMPopSessionQueue, NULL, (LPVOID*)&pmpsqi)) + mir_free(pmpsqi); + } +} + +void CMraProto::MraMPopSessionQueueFlush(HANDLE hMPopSessionQueue) +{ + if (hMPopSessionQueue) { + MRA_MPOP_SESSION_QUEUE *pmpsqMPopSessionQueue = (MRA_MPOP_SESSION_QUEUE*)hMPopSessionQueue; + while ( FifoMTGetCount(pmpsqMPopSessionQueue)) { + MraMPopSessionQueueSetNewMPopKey(hMPopSessionQueue, NULL, 0); + MraMPopSessionQueueStart(hMPopSessionQueue); + } + } +} + +void MraMPopSessionQueueDestroy(HANDLE hMPopSessionQueue) +{ + if (hMPopSessionQueue) { + MRA_MPOP_SESSION_QUEUE *pmpsqMPopSessionQueue = (MRA_MPOP_SESSION_QUEUE*)hMPopSessionQueue; + MraMPopSessionQueueClear(hMPopSessionQueue); + FifoMTDestroy(pmpsqMPopSessionQueue); + mir_free(pmpsqMPopSessionQueue); + } +} + +DWORD CMraProto::MraMPopSessionQueueAddUrl(HANDLE hMPopSessionQueue, LPSTR lpszUrl, size_t dwUrlSize) +{ + if (!hMPopSessionQueue || !lpszUrl || !dwUrlSize) + return ERROR_INVALID_HANDLE; + + MRA_MPOP_SESSION_QUEUE *pmpsqMPopSessionQueue = (MRA_MPOP_SESSION_QUEUE*)hMPopSessionQueue; + MRA_MPOP_SESSION_QUEUE_ITEM *pmpsqi = (MRA_MPOP_SESSION_QUEUE_ITEM*)mir_calloc((sizeof(MRA_MPOP_SESSION_QUEUE_ITEM)+dwUrlSize+sizeof(size_t))); + if (!pmpsqi) + return GetLastError(); + + pmpsqi->dwUrlSize = dwUrlSize; + pmpsqi->lpszUrl = (LPSTR)(pmpsqi+1); + memmove(pmpsqi->lpszUrl, lpszUrl, dwUrlSize); + FifoMTItemPush(pmpsqMPopSessionQueue, pmpsqi, (LPVOID)pmpsqi); + if (pmpsqMPopSessionQueue->bKeyValid) + return MraMPopSessionQueueStart(hMPopSessionQueue); + + if (m_bLoggedIn) + MraSendCMD(MRIM_CS_GET_MPOP_SESSION, NULL, 0); + else + MraMPopSessionQueueFlush(hMPopSessionQueue); + + return NO_ERROR; +} + +DWORD CMraProto::MraMPopSessionQueueAddUrlAndEMail(HANDLE hMPopSessionQueue, LPSTR lpszUrl, size_t dwUrlSize, LPSTR lpszEMail, size_t dwEMailSize) +{ + if (!hMPopSessionQueue || !lpszUrl || !dwUrlSize || !lpszEMail || !dwEMailSize) + return ERROR_INVALID_HANDLE; + + char szUrl[BUFF_SIZE_URL], szEMail[MAX_EMAIL_LEN]; + LPSTR lpszUser, lpszDomain; + + BuffToLowerCase(szEMail, lpszEMail, dwEMailSize); + lpszDomain = (LPSTR)MemoryFindByte(0, szEMail, dwEMailSize, '@'); + if (lpszDomain) + if (lpszUser = (LPSTR)MemoryFindByte((lpszDomain-szEMail), szEMail, dwEMailSize, '.')) { + *lpszUser = 0; + lpszUser = szEMail; + *lpszDomain = 0; + lpszDomain++; + + dwUrlSize = mir_snprintf(szUrl, SIZEOF(szUrl), "%s/%s/%s", lpszUrl, lpszDomain, lpszUser); + return MraMPopSessionQueueAddUrl(hMPopSessionQueue, szUrl, dwUrlSize); + } + return ERROR_INVALID_DATA; +} + +DWORD CMraProto::MraMPopSessionQueueStart(HANDLE hMPopSessionQueue) +{ + DWORD dwRetErrorCode; + + if (!hMPopSessionQueue) + return ERROR_INVALID_HANDLE; + + MRA_MPOP_SESSION_QUEUE *pmpsqMPopSessionQueue = (MRA_MPOP_SESSION_QUEUE*)hMPopSessionQueue; + MRA_MPOP_SESSION_QUEUE_ITEM *pmpsqi; + + dwRetErrorCode = NO_ERROR; + if (pmpsqMPopSessionQueue->bKeyValid == TRUE) + if ( FifoMTItemPop(pmpsqMPopSessionQueue, NULL, (LPVOID*)&pmpsqi) == NO_ERROR) { + char szUrl[BUFF_SIZE_URL], szEMail[MAX_EMAIL_LEN]; + size_t dwUrlSize, dwEMailSize; + + if (mraGetStaticStringA(NULL, "e-mail", szEMail, SIZEOF(szEMail), &dwEMailSize)) { + pmpsqMPopSessionQueue->bKeyValid = FALSE; + BuffToLowerCase(szEMail, szEMail, dwEMailSize); + dwUrlSize = mir_snprintf(szUrl, SIZEOF(szUrl), MRA_MPOP_AUTH_URL, szEMail, pmpsqMPopSessionQueue->lpszMPOPKey, pmpsqi->lpszUrl); + + CallService(MS_UTILS_OPENURL, TRUE, (LPARAM)szUrl); + DebugPrint(L"Opening URL: ");DebugPrintCRLFA(szUrl); + } + mir_free(pmpsqi); + } + return NO_ERROR; +} + +DWORD MraMPopSessionQueueSetNewMPopKey(HANDLE hMPopSessionQueue, LPSTR lpszKey, size_t dwKeySize) +{ + if (!hMPopSessionQueue) + return ERROR_INVALID_HANDLE; + + if (lpszKey == NULL) dwKeySize = 0; + + MRA_MPOP_SESSION_QUEUE *pmpsqMPopSessionQueue = (MRA_MPOP_SESSION_QUEUE*)hMPopSessionQueue; + if (pmpsqMPopSessionQueue->dwMPOPKeySizelpszMPOPKey); + pmpsqMPopSessionQueue->lpszMPOPKey = (LPSTR)mir_calloc(dwKeySize+sizeof(size_t)); + } + + if (pmpsqMPopSessionQueue->lpszMPOPKey) { + pmpsqMPopSessionQueue->bKeyValid = TRUE; + pmpsqMPopSessionQueue->dwMPOPKeySize = dwKeySize; + memmove(pmpsqMPopSessionQueue->lpszMPOPKey, lpszKey, dwKeySize); + (*(pmpsqMPopSessionQueue->lpszMPOPKey+dwKeySize)) = 0; + + DebugPrint(L"New MPOP session key: ");DebugPrintCRLFA(pmpsqMPopSessionQueue->lpszMPOPKey); + return NO_ERROR; + } + + pmpsqMPopSessionQueue->bKeyValid = FALSE; + pmpsqMPopSessionQueue->lpszMPOPKey = NULL; + pmpsqMPopSessionQueue->dwMPOPKeySize = 0; + return GetLastError(); +} + + + + + diff --git a/protocols/MRA/src/MraMPop.h b/protocols/MRA/src/MraMPop.h new file mode 100644 index 0000000000..18aef30f27 --- /dev/null +++ b/protocols/MRA/src/MraMPop.h @@ -0,0 +1,13 @@ +#if !defined(AFX_MRA_MPOP_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_) +#define AFX_MRA_MPOP_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_ + + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +DWORD MraMPopSessionQueueInitialize (HANDLE *phMPopSessionQueue); +void MraMPopSessionQueueDestroy (HANDLE hMPopSessionQueue); +DWORD MraMPopSessionQueueSetNewMPopKey (HANDLE hMPopSessionQueue, LPSTR lpszKey, size_t dwKeySize); + +#endif // !defined(AFX_MRA_MPOP_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_) diff --git a/protocols/MRA/src/MraMRIMProxy.cpp b/protocols/MRA/src/MraMRIMProxy.cpp new file mode 100644 index 0000000000..01a46ecc49 --- /dev/null +++ b/protocols/MRA/src/MraMRIMProxy.cpp @@ -0,0 +1,211 @@ +#include "Mra.h" +#include "MraMRIMProxy.h" +#include "proto.h" + +struct MRA_MRIMPROXY_DATA +{ + LPSTR lpszEMail; // LPS to + size_t dwEMailSize; + DWORD dwIDRequest; // DWORD id_request + DWORD dwDataType; // DWORD data_type + LPSTR lpszUserData; // LPS user_data + size_t dwUserDataSize; + MRA_ADDR_LIST malAddrList; // LPS lps_ip_port + MRA_GUID mguidSessionID; // DWORD session_id[4] + HANDLE hConnection; + HANDLE hWaitHandle; // internal +}; + +HANDLE MraMrimProxyCreate() +{ + MRA_MRIMPROXY_DATA *pmmpd = (MRA_MRIMPROXY_DATA*)mir_calloc(sizeof(MRA_MRIMPROXY_DATA)); + return (HANDLE)pmmpd; +} + +DWORD MraMrimProxySetData(HANDLE hMraMrimProxyData, LPSTR lpszEMail, size_t dwEMailSize, DWORD dwIDRequest, DWORD dwDataType, LPSTR lpszUserData, size_t dwUserDataSize, LPSTR lpszAddreses, size_t dwAddresesSize, MRA_GUID *pmguidSessionID) +{ + if (!hMraMrimProxyData) + return ERROR_INVALID_HANDLE; + + MRA_MRIMPROXY_DATA *pmmpd = (MRA_MRIMPROXY_DATA*)hMraMrimProxyData; + + if (lpszEMail && dwEMailSize) { + mir_free(pmmpd->lpszEMail); + pmmpd->lpszEMail = (LPSTR)mir_calloc(dwEMailSize); + memmove(pmmpd->lpszEMail, lpszEMail, dwEMailSize); + pmmpd->dwEMailSize = dwEMailSize; + } + + if (dwIDRequest) pmmpd->dwIDRequest = dwIDRequest; + if (dwDataType) pmmpd->dwDataType = dwDataType; + + if (lpszUserData) { + mir_free(pmmpd->lpszUserData); + pmmpd->lpszUserData = (LPSTR)mir_calloc(dwUserDataSize); + memmove(pmmpd->lpszUserData, lpszUserData, dwUserDataSize); + pmmpd->dwUserDataSize = dwUserDataSize; + } + + if (lpszAddreses && dwAddresesSize) + MraAddrListGetFromBuff(lpszAddreses, dwAddresesSize, &pmmpd->malAddrList); + if (pmguidSessionID) + memmove(&pmmpd->mguidSessionID, pmguidSessionID, sizeof(MRA_GUID)); + + SetEvent(pmmpd->hWaitHandle); + return 0; +} + +void MraMrimProxyFree(HANDLE hMraMrimProxyData) +{ + if (hMraMrimProxyData) { + MRA_MRIMPROXY_DATA *pmmpd = (MRA_MRIMPROXY_DATA*)hMraMrimProxyData; + + CloseHandle(pmmpd->hWaitHandle); + Netlib_CloseHandle(pmmpd->hConnection); + mir_free(pmmpd->lpszEMail); + mir_free(pmmpd->lpszUserData); + MraAddrListFree(&pmmpd->malAddrList); + mir_free(hMraMrimProxyData); + } +} + +void MraMrimProxyCloseConnection(HANDLE hMraMrimProxyData) +{ + if (hMraMrimProxyData) { + MRA_MRIMPROXY_DATA *pmmpd = (MRA_MRIMPROXY_DATA*)hMraMrimProxyData; + SetEvent(pmmpd->hWaitHandle); + Netlib_CloseHandle(pmmpd->hConnection); + } +} + +DWORD CMraProto::MraMrimProxyConnect(HANDLE hMraMrimProxyData, HANDLE *phConnection) +{ + DWORD dwRetErrorCode; + + if (hMraMrimProxyData && phConnection) { + BOOL bIsHTTPSProxyUsed, bContinue; + BYTE lpbBufferRcv[BUFF_SIZE_RCV_MIN_FREE]; + DWORD dwBytesReceived, dwConnectReTryCount, dwCurConnectReTryCount; + size_t dwRcvBuffSize = BUFF_SIZE_RCV_MIN_FREE, dwRcvBuffSizeUsed; + NETLIBSELECT nls = {0}; + MRA_MRIMPROXY_DATA *pmmpd = (MRA_MRIMPROXY_DATA*)hMraMrimProxyData; + NETLIBOPENCONNECTION nloc = {0}; + + // адреса есть, значит инициаторы не мы + if (pmmpd->malAddrList.dwAddrCount) { + MraAddrListGetToBuff(&pmmpd->malAddrList, (LPSTR)lpbBufferRcv, SIZEOF(lpbBufferRcv), &dwRcvBuffSizeUsed); + MraProxyAck(PROXY_STATUS_OK, pmmpd->lpszEMail, pmmpd->dwEMailSize, pmmpd->dwIDRequest, pmmpd->dwDataType, pmmpd->lpszUserData, pmmpd->dwUserDataSize, (LPSTR)lpbBufferRcv, dwRcvBuffSizeUsed, pmmpd->mguidSessionID); + } + // мы инициаторы + else { + pmmpd->hWaitHandle = CreateEvent(NULL, TRUE, FALSE, NULL); + if (pmmpd->lpszEMail && pmmpd->dwEMailSize) + if (MraProxy(pmmpd->lpszEMail, pmmpd->dwEMailSize, pmmpd->dwIDRequest, pmmpd->dwDataType, pmmpd->lpszUserData, pmmpd->dwUserDataSize, NULL, 0, pmmpd->mguidSessionID)) + WaitForSingleObjectEx(pmmpd->hWaitHandle, INFINITE, FALSE); + + CloseHandle(pmmpd->hWaitHandle); + pmmpd->hWaitHandle = NULL; + } + + dwRetErrorCode = ERROR_NO_NETWORK; + if (pmmpd->malAddrList.dwAddrCount) { + pmmpd->hConnection = NULL; + bIsHTTPSProxyUsed = IsHTTPSProxyUsed(hNetlibUser); + dwConnectReTryCount = mraGetDword(NULL, "ConnectReTryCountMRIMProxy", MRA_DEFAULT_CONN_RETRY_COUNT_MRIMPROXY); + nloc.cbSize = sizeof(nloc); + nloc.flags = NLOCF_V2; + nloc.timeout = ((MRA_TIMEOUT_DIRECT_CONN-1)/(pmmpd->malAddrList.dwAddrCount*dwConnectReTryCount));// -1 сек чтобы был запас + if (nloc.timeoutMRA_TIMEOUT_CONN_МАХ) nloc.timeout = MRA_TIMEOUT_CONN_МАХ; + + // Set up the sockaddr structure + for (size_t i = 0; i < pmmpd->malAddrList.dwAddrCount && dwRetErrorCode != NO_ERROR; i++) { + // через https прокси только 443 порт + if ((pmmpd->malAddrList.pmaliAddress[i].dwPort == MRA_SERVER_PORT_HTTPS && bIsHTTPSProxyUsed) || bIsHTTPSProxyUsed == FALSE) { + if (pmmpd->dwDataType == MRIM_PROXY_TYPE_FILES) + ProtoBroadcastAck(m_szModuleName, MraHContactFromEmail(pmmpd->lpszEMail, pmmpd->dwEMailSize, FALSE, TRUE, NULL), ACKTYPE_FILE, ACKRESULT_CONNECTING, (HANDLE)pmmpd->dwIDRequest, 0); + + nloc.szHost = inet_ntoa((*((in_addr*)&pmmpd->malAddrList.pmaliAddress[i].dwAddr))); + nloc.wPort = (WORD)pmmpd->malAddrList.pmaliAddress[i].dwPort; + + dwCurConnectReTryCount = dwConnectReTryCount; + do { + pmmpd->hConnection = (HANDLE)CallService(MS_NETLIB_OPENCONNECTION, (WPARAM)hNetlibUser, (LPARAM)&nloc); + } + while (--dwCurConnectReTryCount && pmmpd->hConnection == NULL); + + if (pmmpd->hConnection) { + nls.cbSize = sizeof(nls); + nls.dwTimeout = (MRA_TIMEOUT_DIRECT_CONN*1000*2); + nls.hReadConns[0] = pmmpd->hConnection; + bContinue = TRUE; + dwRcvBuffSizeUsed = 0; + + if (pmmpd->dwDataType == MRIM_PROXY_TYPE_FILES) + ProtoBroadcastAck(m_szModuleName, MraHContactFromEmail(pmmpd->lpszEMail, pmmpd->dwEMailSize, FALSE, TRUE, NULL), ACKTYPE_FILE, ACKRESULT_CONNECTED, (HANDLE)pmmpd->dwIDRequest, 0); + MraSendPacket(nls.hReadConns[0], 0, MRIM_CS_PROXY_HELLO, &pmmpd->mguidSessionID, sizeof(MRA_GUID)); + + while (bContinue) { + switch (CallService(MS_NETLIB_SELECT, 0, (LPARAM)&nls)) { + case SOCKET_ERROR: + case 0:// Time out + dwRetErrorCode = GetLastError(); + ShowFormattedErrorMessage(L"Disconnected, socket error", dwRetErrorCode); + bContinue = FALSE; + break; + + case 1: + if (dwRcvBuffSizeUsed == BUFF_SIZE_RCV_MIN_FREE) { // bad packet + bContinue = FALSE; + DebugBreak(); + } + else { + dwBytesReceived = Netlib_Recv(nls.hReadConns[0], (LPSTR)(lpbBufferRcv+dwRcvBuffSizeUsed), (dwRcvBuffSize-dwRcvBuffSizeUsed), 0); + if (dwBytesReceived && dwBytesReceived != SOCKET_ERROR) { // connected + dwRcvBuffSizeUsed += dwBytesReceived; + if (dwRcvBuffSizeUsed >= sizeof(mrim_packet_header_t)) { // packet header received + if (((mrim_packet_header_t*)lpbBufferRcv)->magic == CS_MAGIC) { // packet OK + if ((dwRcvBuffSizeUsed-sizeof(mrim_packet_header_t)) >= ((mrim_packet_header_t*)lpbBufferRcv)->dlen) { // full packet received, may be more than one + if (((mrim_packet_header_t*)lpbBufferRcv)->msg == MRIM_CS_PROXY_HELLO_ACK) // connect OK! + dwRetErrorCode = NO_ERROR; + else // bad/wrong + DebugBreak(); + + bContinue = FALSE; + } + else // not all packet received, continue receiving + DebugPrintCRLF(L"Not all packet received, continue receiving"); + } + else { // bad packet + DebugPrintCRLF(L"Bad packet"); + DebugBreak(); + bContinue = FALSE; + } + } + else // packet too small, continue receiving + DebugPrintCRLF(L"Packet to small, continue receiving"); + } + else { // disconnected + dwRetErrorCode = GetLastError(); + ShowFormattedErrorMessage(L"Disconnected, socket read error", dwRetErrorCode); + bContinue = FALSE; + } + } + break; + }// end switch + }// end while + } + else dwRetErrorCode = GetLastError(); + }// filtered + }// end for + + if (dwRetErrorCode != NO_ERROR) { // кажется не туда подключились :) + Netlib_CloseHandle(pmmpd->hConnection); + pmmpd->hConnection = NULL; + } + } + *phConnection = pmmpd->hConnection; + } + else dwRetErrorCode = ERROR_INVALID_HANDLE; + return dwRetErrorCode; +} diff --git a/protocols/MRA/src/MraMRIMProxy.h b/protocols/MRA/src/MraMRIMProxy.h new file mode 100644 index 0000000000..c0051daec9 --- /dev/null +++ b/protocols/MRA/src/MraMRIMProxy.h @@ -0,0 +1,15 @@ +#if !defined(AFX_MRA_MRIMPROXY_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_) +#define AFX_MRA_MRIMPROXY_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_ + + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +DWORD MraMrimProxySetData(HANDLE hMraMrimProxyData, LPSTR lpszEMail, size_t dwEMailSize, DWORD dwIDRequest, DWORD dwDataType, LPSTR lpszUserData, size_t dwUserDataSize, LPSTR lpszAddreses, size_t dwAddresesSize, MRA_GUID *pmguidSessionID); + +HANDLE MraMrimProxyCreate(); +void MraMrimProxyFree(HANDLE hMraMrimProxyData); +void MraMrimProxyCloseConnection(HANDLE hMraMrimProxyData); + +#endif // !defined(AFX_MRA_MRIMPROXY_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_) diff --git a/protocols/MRA/src/MraOfflineMsg.cpp b/protocols/MRA/src/MraOfflineMsg.cpp new file mode 100644 index 0000000000..e3e8b76aff --- /dev/null +++ b/protocols/MRA/src/MraOfflineMsg.cpp @@ -0,0 +1,432 @@ +#include "Mra.h" +#include "MraOfflineMsg.h" +#include "MraConstans.h" + + +#define LF "\n" +#define LFLF "\n\n" +#define CRLF "\r\n" +#define CRLFCRLF "\r\n\r\n" + + +DWORD MraOfflineMessageGetMIMEHeadAndBody (LPSTR lpszMessage, size_t dwMessageSize, LPSTR *plpszHeader, size_t *pdwHeaderSize, LPSTR *plpszBody, size_t *pdwBodySize); +DWORD MraOfflineMessageGetNextMIMEPart (LPSTR lpszBody, size_t dwBodySize, LPSTR lpszBoundary, size_t dwBoundarySize, LPSTR *plpszCurMIMEPos, LPSTR *plpszMIMEPart, size_t *pdwMIMEPartSize); +DWORD MraOfflineMessageGetHeaderValue (LPSTR lpszHeader, LPSTR lpszHeaderLow, size_t dwHeaderSize, LPSTR lpszValueName, size_t dwValueNameSize, LPSTR *plpszValue, size_t *pdwValueSize); +DWORD MraOfflineMessageGetHeaderValueLow (LPSTR lpszHeaderLow, size_t dwHeaderSize, LPSTR lpszValueName, size_t dwValueNameSize, LPSTR *plpszValue, size_t *pdwValueSize); +DWORD MraOfflineMessageConvertTime (INTERNET_TIME *pitTime); + + + + +DWORD MraOfflineMessageGet(MRA_LPS *plpsMsg, DWORD *pdwTime, DWORD *pdwFlags, MRA_LPS *plpsEMail, MRA_LPS *plpsText, MRA_LPS *plpsRTFText, MRA_LPS *plpsMultiChatData, LPBYTE *plpbBuff) +{// Сообщение + DWORD dwRetErrorCode = ERROR_INVALID_HANDLE; + + + if (plpsMsg) + if (plpsMsg->lpszData && plpsMsg->dwSize) + { + LPSTR lpszHeader, lpszHeaderLow, lpszBody, lpszContentTypeLow, lpszTemp; + size_t dwHeaderSize, dwBodySize, dwContentTypeSize, dwTempSize; + DWORD dwMultichatType; + + #ifdef _DEBUG + DebugPrintCRLFA(plpsMsg->lpszData); + #endif + + if (MraOfflineMessageGetMIMEHeadAndBody(plpsMsg->lpszData, plpsMsg->dwSize, &lpszHeader, &dwHeaderSize, &lpszBody, &dwBodySize) == NO_ERROR) + { + lpszHeaderLow = (LPSTR)mir_calloc(dwHeaderSize); + if (lpszHeaderLow) BuffToLowerCase(lpszHeaderLow, lpszHeader, dwHeaderSize); + + if (pdwTime) + if (MraOfflineMessageGetHeaderValue(lpszHeader, lpszHeaderLow, dwHeaderSize, "date", 4, &lpszTemp, &dwTempSize) == NO_ERROR) + { + INTERNET_TIME itTime; + InternetTimeGetTime(lpszTemp, dwTempSize, &itTime); + (*pdwTime) = MraOfflineMessageConvertTime(&itTime); + }else { + (*pdwTime) = 0; + } + + if (pdwFlags) + if (MraOfflineMessageGetHeaderValue(lpszHeader, lpszHeaderLow, dwHeaderSize, "x-mrim-flags", 12, &lpszTemp, &dwTempSize) == NO_ERROR) + { + (*pdwFlags) = StrHexToUNum32(lpszTemp, dwTempSize); + }else { + (*pdwFlags) = 0; + } + + if (MraOfflineMessageGetHeaderValue(lpszHeader, lpszHeaderLow, dwHeaderSize, "x-mrim-multichat-type", 21, &lpszTemp, &dwTempSize) == NO_ERROR) + { + dwMultichatType = StrHexToUNum32(lpszTemp, dwTempSize); + }else { + dwMultichatType = 0; + } + + + if (plpsEMail) + if (MraOfflineMessageGetHeaderValue(lpszHeader, lpszHeaderLow, dwHeaderSize, "from", 4, &plpsEMail->lpszData, &plpsEMail->dwSize) != NO_ERROR) + { + plpsEMail->lpszData = NULL; + plpsEMail->dwSize = 0; + } + + + if (plpsText) + { + plpsText->lpszData = NULL; + plpsText->dwSize = 0; + } + if (plpsRTFText) + { + plpsRTFText->lpszData = NULL; + plpsRTFText->dwSize = 0; + } + if (plpsMultiChatData) + { + plpsMultiChatData->lpszData = NULL; + plpsMultiChatData->dwSize = 0; + } + if (plpbBuff) (*plpbBuff) = NULL; + + if (plpsText || plpsRTFText) + if (MraOfflineMessageGetHeaderValueLow(lpszHeaderLow, dwHeaderSize, "content-type", 12, &lpszContentTypeLow, &dwContentTypeSize) == NO_ERROR) + { + + if (MemoryFind(0, lpszContentTypeLow, dwContentTypeSize, "multipart/alternative", 21)) + {// Content-Type: multipart/alternative; boundary = 1217508709J3777283291217508709T31197726 + LPSTR lpszBoundary, lpszMIMEPart, lpszCurMIMEPos, lpszMIMEHeader, lpszMIMEHeaderLow, lpszMIMEBody, lpszMIMEContentType; + size_t i, dwBoundarySize, dwMIMEPartSize, dwMIMEHeaderSize, dwMIMEBodySize, dwMIMEContentTypeSize; + + lpszBoundary = (LPSTR)MemoryFind(0, lpszContentTypeLow, dwContentTypeSize, "boundary=", 9); + if (lpszBoundary) + { + dwBoundarySize = ((dwContentTypeSize-(lpszBoundary-lpszContentTypeLow))-9); + lpszBoundary = (lpszHeader+((lpszBoundary+9)-lpszHeaderLow)); + + i = 0; + lpszCurMIMEPos = lpszBody; + while (MraOfflineMessageGetNextMIMEPart(lpszBody, dwBodySize, lpszBoundary, dwBoundarySize, &lpszCurMIMEPos, &lpszMIMEPart, &dwMIMEPartSize) == NO_ERROR) + { + if (MraOfflineMessageGetMIMEHeadAndBody(lpszMIMEPart, dwMIMEPartSize, &lpszMIMEHeader, &dwMIMEHeaderSize, &lpszMIMEBody, &dwMIMEBodySize) == NO_ERROR) + { + lpszMIMEHeaderLow = (LPSTR)mir_calloc(dwMIMEHeaderSize); + if (lpszMIMEHeaderLow) + { + BuffToLowerCase(lpszMIMEHeaderLow, lpszMIMEHeader, dwMIMEHeaderSize); + if (MraOfflineMessageGetHeaderValueLow(lpszMIMEHeaderLow, dwMIMEHeaderSize, "content-type", 12, &lpszMIMEContentType, &dwMIMEContentTypeSize) == NO_ERROR) + { + if (MemoryFind(0, lpszMIMEContentType, dwMIMEContentTypeSize, "text/plain", 10)) + {// this is simple text part: text/plain + if (plpsText) + { + if (MemoryFind(0, lpszMIMEContentType, dwMIMEContentTypeSize, "utf-16le", 8)) + {// charset = UTF-16LE// предполагаем что оно в base64 + if (plpbBuff) + {// буффер для декодирования текста можно выделять + LPWSTR lpwszText; + size_t dwTextSize; + + lpwszText = (LPWSTR)mir_calloc(dwMIMEBodySize); + if (lpwszText) + { + BASE64DecodeFormated(lpszMIMEBody, dwMIMEBodySize, lpwszText, dwMIMEBodySize, &dwTextSize); + plpsText->lpwszData = lpwszText; + plpsText->dwSize = dwTextSize; + if (pdwFlags) + { + (*pdwFlags) |= MESSAGE_FLAG_v1p16; // set unocode flag if not exist + (*pdwFlags) &= ~MESSAGE_FLAG_CP1251; // reset ansi flag if exist + } + (*plpbBuff) = (LPBYTE)lpwszText; + dwRetErrorCode = NO_ERROR; + } + } + }else + if (MemoryFind(0, lpszMIMEContentType, dwMIMEContentTypeSize, "cp-1251", 7)) + {// charset = CP-1251 + plpsText->lpszData = lpszMIMEBody; + plpsText->dwSize = dwMIMEBodySize; + if (pdwFlags) + { + (*pdwFlags) &= ~MESSAGE_FLAG_v1p16; // reset unocode flag if exist + (*pdwFlags) |= MESSAGE_FLAG_CP1251; // set ansi flag + } + dwRetErrorCode = NO_ERROR; + }else { + DebugBreak(); + } + } + }else + if (MemoryFind(0, lpszMIMEContentType, dwMIMEContentTypeSize, "application/x-mrim-rtf", 22)) + { + if (plpsRTFText) + { + plpsRTFText->lpszData = lpszMIMEBody; + plpsRTFText->dwSize = dwMIMEBodySize; + if (pdwFlags) (*pdwFlags) |= MESSAGE_FLAG_RTF; // set RTF flag if not exist + dwRetErrorCode = NO_ERROR; + } + }else + if (MemoryFind(0, lpszMIMEContentType, dwMIMEContentTypeSize, "application/x-mrim+xml", 22)) + { + if (plpsMultiChatData) + { + plpsMultiChatData->lpszData = lpszMIMEBody; + plpsMultiChatData->dwSize = dwMIMEBodySize; + if (pdwFlags) (*pdwFlags) |= MESSAGE_FLAG_MULTICHAT; // set MESSAGE_FLAG_MULTICHAT flag if not exist + dwRetErrorCode = NO_ERROR; + } + }else { + DebugBreak(); + } + } + mir_free(lpszMIMEHeaderLow); + } + } + i++; + } + + DebugBreakIf((i>3 || i == 0)); + }else {// boundary not found + DebugBreak(); + } + }else + if (MemoryFind(0, lpszContentTypeLow, dwContentTypeSize, "text/plain", 10)) + {// Content-Type: text/plain; charset = CP-1251 + if (MemoryFind(0, lpszContentTypeLow, dwContentTypeSize, "utf-16le", 8)) + {// charset = UTF-16LE// предполагаем что оно в base64 + if (plpbBuff) + {// буффер для декодирования текста можно выделять + LPWSTR lpwszText; + size_t dwTextSize; + + lpwszText = (LPWSTR)mir_calloc(dwBodySize); + if (lpwszText) + { + BASE64DecodeFormated(lpszBody, dwBodySize, lpwszText, dwBodySize, &dwTextSize); + plpsText->lpwszData = lpwszText; + plpsText->dwSize = dwTextSize; + if (pdwFlags) + { + (*pdwFlags) |= MESSAGE_FLAG_v1p16; // set unocode flag if not exist + (*pdwFlags) &= ~MESSAGE_FLAG_CP1251; // reset ansi flag if exist + } + (*plpbBuff) = (LPBYTE)lpwszText; + dwRetErrorCode = NO_ERROR; + } + } + }else + if (MemoryFind(0, lpszContentTypeLow, dwContentTypeSize, "cp-1251", 7)) + {// charset = CP-1251 + plpsText->lpszData = lpszBody; + plpsText->dwSize = dwBodySize; + if (pdwFlags) + { + (*pdwFlags) &= ~MESSAGE_FLAG_v1p16; // reset unocode flag if exist + (*pdwFlags) |= MESSAGE_FLAG_CP1251; // set ansi flag + } + dwRetErrorCode = NO_ERROR; + }else { + DebugBreak(); + } + }else + if (MemoryFind(0, lpszContentTypeLow, dwContentTypeSize, "application/x-mrim-auth-req", 27)) + {// Content-Type: application/x-mrim-auth-req + if (plpsText) + { + plpsText->lpszData = lpszBody; + plpsText->dwSize = dwBodySize; + } + dwRetErrorCode = NO_ERROR; + }else { + DebugBreak(); + } + }else { + DebugBreak(); + } + + mir_free(lpszHeaderLow); + } + } + +return(dwRetErrorCode); +} + + +DWORD MraOfflineMessageGetMIMEHeadAndBody(LPSTR lpszMessage, size_t dwMessageSize, LPSTR *plpszHeader, size_t *pdwHeaderSize, LPSTR *plpszBody, size_t *pdwBodySize) +{ + DWORD dwRetErrorCode = ERROR_NOT_FOUND; + + if (lpszMessage && dwMessageSize) + { + LPSTR lpszBody; + size_t dwBodySize; + + // затычка: майл не придерживается RFC и вместо CRLFCRLF ставит LFLF в MIME частях, иногда ставит + lpszBody = (LPSTR)MemoryFind(0, lpszMessage, dwMessageSize, CRLFCRLF, (sizeof(CRLFCRLF)-1)); + if (lpszBody) + { + lpszBody += (sizeof(CRLFCRLF)-1); + }else { + lpszBody = (LPSTR)MemoryFind(0, lpszMessage, dwMessageSize, LFLF, (sizeof(LFLF)-1)); + if (lpszBody) lpszBody += (sizeof(LFLF)-1); + } + + if (lpszBody) + {// нашли начало контента миме части + dwBodySize = (dwMessageSize-(lpszBody-lpszMessage)); + + if (plpszHeader) (*plpszHeader) = lpszMessage; + if (pdwHeaderSize) (*pdwHeaderSize) = ((lpszBody-(sizeof(LFLF)-1))-lpszMessage); + if (plpszBody) (*plpszBody) = lpszBody; + if (pdwBodySize) (*pdwBodySize) = dwBodySize; + + dwRetErrorCode = NO_ERROR; + } + }else { + dwRetErrorCode = ERROR_INVALID_HANDLE; + } +return(dwRetErrorCode); +} + + +DWORD MraOfflineMessageGetNextMIMEPart(LPSTR lpszBody, size_t dwBodySize, LPSTR lpszBoundary, size_t dwBoundarySize, LPSTR *plpszCurMIMEPos, LPSTR *plpszMIMEPart, size_t *pdwMIMEPartSize) +{ + DWORD dwRetErrorCode = ERROR_NOT_FOUND; + + if (lpszBody && dwBodySize) + { + LPSTR lpszMIMEPart, lpszCurMIMEPos, lpszTemp; + size_t dwMIMEPartSize; + + if (plpszCurMIMEPos) lpszCurMIMEPos = (*plpszCurMIMEPos); + lpszMIMEPart = (LPSTR)MemoryFind((lpszCurMIMEPos-lpszBody), lpszBody, dwBodySize, lpszBoundary, dwBoundarySize); + if (lpszMIMEPart) + {// первая миме часть + lpszMIMEPart += dwBoundarySize; + + // затычка: майл не придерживается RFC и вместо CRLF ставит LF в MIME частях, иногда ставит + if ((*((WORD*)lpszMIMEPart)) == (*((WORD*)CRLF))) + { + lpszMIMEPart += (sizeof(CRLF)-1); + }else + if ((*((BYTE*)lpszMIMEPart)) == (*((BYTE*)LF))) + { + lpszMIMEPart += (sizeof(LF)-1); + }else + if ((*((WORD*)lpszMIMEPart)) == '--') + { + lpszMIMEPart = NULL; + }else { + DebugBreak(); + } + + if (lpszMIMEPart) + { + lpszTemp = (LPSTR)MemoryFind((lpszMIMEPart-lpszBody), lpszBody, dwBodySize, lpszBoundary, dwBoundarySize); + if (lpszTemp) + {// нашли конец миме части с текстом + dwMIMEPartSize = (lpszTemp-lpszMIMEPart);// 4 = CRLF"--"Boundary / 3 = LF"--"Boundary + // затычка: майл не придерживается RFC и вместо CRLF ставит LF в MIME частях, иногда ставит + if ((*((WORD*)(lpszTemp-4))) == (*((WORD*)CRLF))) + { + dwMIMEPartSize-=4; + }else + if ((*((BYTE*)(lpszTemp-3))) == (*((BYTE*)LF))) + { + dwMIMEPartSize-=3; + }else { + DebugBreak(); + } + + if (plpszMIMEPart) (*plpszMIMEPart) = lpszMIMEPart; + if (pdwMIMEPartSize) (*pdwMIMEPartSize) = dwMIMEPartSize; + if (plpszCurMIMEPos) (*plpszCurMIMEPos) = lpszTemp; + dwRetErrorCode = NO_ERROR; + } + }else { + dwRetErrorCode = ERROR_NO_MORE_ITEMS; + } + } + }else { + dwRetErrorCode = ERROR_INVALID_HANDLE; + } +return(dwRetErrorCode); +} + + +DWORD MraOfflineMessageGetHeaderValue(LPSTR lpszHeader, LPSTR lpszHeaderLow, size_t dwHeaderSize, LPSTR lpszValueName, size_t dwValueNameSize, LPSTR *plpszValue, size_t *pdwValueSize) +{ + DWORD dwRetErrorCode = ERROR_NOT_FOUND; + LPSTR lpszValue, lpszValueEnd; + size_t dwValueSize; + + lpszValue = (LPSTR)MemoryFind(0, lpszHeaderLow, dwHeaderSize, lpszValueName, dwValueNameSize); + if (lpszValue) + { + lpszValue += dwValueNameSize; + lpszValueEnd = (LPSTR)MemoryFind((lpszValue-lpszHeaderLow), lpszHeaderLow, dwHeaderSize, CRLF, (sizeof(CRLF)-1)); + if (lpszValueEnd == NULL) lpszValueEnd = (LPSTR)MemoryFind((lpszValue-lpszHeaderLow), lpszHeaderLow, dwHeaderSize, LF, (sizeof(LF)-1)); + if (lpszValueEnd == NULL) lpszValueEnd = (LPSTR)(lpszHeaderLow+dwHeaderSize); + + lpszValue = (LPSTR)MemoryFind((lpszValue-lpszHeaderLow), lpszHeaderLow, (lpszValueEnd-lpszHeaderLow), ":", 1); + if (lpszValue) + { + lpszValue++; + dwValueSize = (lpszValueEnd-lpszValue); + SkeepSPWSP((lpszHeader+(lpszValue-lpszHeaderLow)), dwValueSize, plpszValue, pdwValueSize); + dwRetErrorCode = NO_ERROR; + } + } +return(dwRetErrorCode); +} + + +DWORD MraOfflineMessageGetHeaderValueLow(LPSTR lpszHeaderLow, size_t dwHeaderSize, LPSTR lpszValueName, size_t dwValueNameSize, LPSTR *plpszValue, size_t *pdwValueSize) +{ + DWORD dwRetErrorCode = ERROR_NOT_FOUND; + LPSTR lpszValue, lpszValueEnd; + size_t dwValueSize; + + lpszValue = (LPSTR)MemoryFind(0, lpszHeaderLow, dwHeaderSize, lpszValueName, dwValueNameSize); + if (lpszValue) + { + lpszValue += dwValueNameSize; + lpszValueEnd = (LPSTR)MemoryFind((lpszValue-lpszHeaderLow), lpszHeaderLow, dwHeaderSize, CRLF, (sizeof(CRLF)-1)); + if (lpszValueEnd == NULL) lpszValueEnd = (LPSTR)MemoryFind((lpszValue-lpszHeaderLow), lpszHeaderLow, dwHeaderSize, LF, (sizeof(LF)-1)); + if (lpszValueEnd == NULL) lpszValueEnd = (LPSTR)(lpszHeaderLow+dwHeaderSize); + + lpszValue = (LPSTR)MemoryFind((lpszValue-lpszHeaderLow), lpszHeaderLow, (lpszValueEnd-lpszHeaderLow), ":", 1); + if (lpszValue) + { + lpszValue++; + dwValueSize = (lpszValueEnd-lpszValue); + SkeepSPWSP(lpszValue, dwValueSize, plpszValue, pdwValueSize); + dwRetErrorCode = NO_ERROR; + } + } +return(dwRetErrorCode); +} + + +DWORD MraOfflineMessageConvertTime(INTERNET_TIME *pitTime) +{ + SYSTEMTIME stTime, stUniversalTime; + TIME_ZONE_INFORMATION tziTimeZoneMailRu = {0}, tziTimeZoneLocal; + + GetTimeZoneInformation(&tziTimeZoneLocal); + if (GetTimeZoneInformation(&tziTimeZoneMailRu) == TIME_ZONE_ID_DAYLIGHT) tziTimeZoneMailRu.DaylightBias *= 2; + tziTimeZoneMailRu.Bias = MAILRU_SERVER_TIME_ZONE; + + //TzSpecificLocalTimeToSystemTime(&tziTimeZoneMailRu, &pitTime->stTime, &stUniversalTime); + {// for win 2000 compatible + tziTimeZoneMailRu.Bias = -tziTimeZoneMailRu.Bias; + tziTimeZoneMailRu.DaylightBias = -tziTimeZoneMailRu.DaylightBias; + SystemTimeToTzSpecificLocalTime(&tziTimeZoneMailRu, &pitTime->stTime, &stUniversalTime); + }//*/ + SystemTimeToTzSpecificLocalTime(&tziTimeZoneLocal, &stUniversalTime, &stTime); + +return((DWORD)MakeTime32FromLocalSystemTime(&stTime)); +} diff --git a/protocols/MRA/src/MraOfflineMsg.h b/protocols/MRA/src/MraOfflineMsg.h new file mode 100644 index 0000000000..2958fbe4a9 --- /dev/null +++ b/protocols/MRA/src/MraOfflineMsg.h @@ -0,0 +1,19 @@ +#if !defined(AFX_MRA_OFFLINEMSG_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_) +#define AFX_MRA_OFFLINEMSG_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_ + + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + + + + +DWORD MraOfflineMessageGet(MRA_LPS *plpsMsg, DWORD *pdwTime, DWORD *pdwFlags, MRA_LPS *plpsEMail, MRA_LPS *plpsText, MRA_LPS *plpsRTFText, MRA_LPS *plpsMultiChatData, LPBYTE *plpbBuff); + + + + + +#endif // !defined(AFX_MRA_OFFLINEMSG_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_) diff --git a/protocols/MRA/src/MraPlaces.h b/protocols/MRA/src/MraPlaces.h new file mode 100644 index 0000000000..56a0573a6d --- /dev/null +++ b/protocols/MRA/src/MraPlaces.h @@ -0,0 +1,5959 @@ +#if !defined(AFX_MRA_PLACES_H__INCLUDED_) +#define AFX_MRA_PLACES_H__INCLUDED_ + + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + +#define lpwszOther TEXT("Другое") +//static LPWSTR lpwszOther = TEXT("Другое"); + + +typedef struct +{ + WORD dwCountryID; + LPWSTR lpszData; +} MRA_COUNTRY; + + +typedef struct +{ + WORD dwCountryID; + WORD dwCityID; + LPWSTR lpszData; +} MRA_CITY; + + + + +typedef struct +{ + WORD dwCountryID; + WORD dwCityID; + WORD dwPlaceID; + LPWSTR lpszData; +} MRA_PLACE; + + +/* WCHAR szBuff[MAX_FILEPATH]; + + DebugPrintCRLFA("static const MRA_COUNTRY mracCountrys[] = \r\n{"); + for (size_t i = 0;mrapPlaces[i].lpszData;i++) + { + if (mrapPlaces[i].dwCityID == 0 && mrapPlaces[i].dwPlaceID == 0) + { + mir_sntprintf(szBuff, SIZEOF(szBuff), L" {%ld, TEXT(\"%s\")}, ", mrapPlaces[i].dwCountryID, mrapPlaces[i].lpszData); + DebugPrintCRLFW(szBuff); + } + } + DebugPrintCRLFA(" {0, NULL}\r\n};"); + + + DebugPrintCRLFA("static const MRA_CITY mracCitys[] = \r\n{"); + for (size_t i = 0;mrapPlaces[i].lpszData;i++) + { + if (mrapPlaces[i].dwCityID && mrapPlaces[i].dwPlaceID == 0) + { + mir_sntprintf(szBuff, SIZEOF(szBuff), L" {%ld, %ld, TEXT(\"%s\")}, ", mrapPlaces[i].dwCountryID, mrapPlaces[i].dwCityID, mrapPlaces[i].lpszData); + DebugPrintCRLFW(szBuff); + } + } + DebugPrintCRLFA(" {0, NULL}\r\n};"); + + + +static const MRA_PLACE mrapPlaces[] = +{ + {24, 0, 0, TEXT("Россия")}, + {81, 0, 0, TEXT("Азербайджан")}, + {82, 0, 0, TEXT("Армения")}, + {97, 0, 0, TEXT("Афганистан")}, + {96, 0, 0, TEXT("Бангладеш")}, + {99, 0, 0, TEXT("Бахрейн")}, + {100, 0, 0, TEXT("Бруней-Даруссалам")}, + {101, 0, 0, TEXT("Бутан")}, + {102, 0, 0, TEXT("Вьетнам")}, + {83, 0, 0, TEXT("Грузия")}, + {86, 0, 0, TEXT("Израиль")}, + {95, 0, 0, TEXT("Индия")}, + {103, 0, 0, TEXT("Индонезия")}, + {79, 0, 0, TEXT("Иордания")}, + {85, 0, 0, TEXT("Ирак")}, + {87, 0, 0, TEXT("Иран")}, + {104, 0, 0, TEXT("Йемен")}, + {84, 0, 0, TEXT("Казахстан")}, + {105, 0, 0, TEXT("Камбоджа")}, + {106, 0, 0, TEXT("Катар")}, + {107, 0, 0, TEXT("Кипр")}, + {92, 0, 0, TEXT("Киргизия (Кыргызстан)")}, + {76, 0, 0, TEXT("Китай")}, + {3215, 0, 0, TEXT("Кокосовые острова (Австр.)")}, + {29, 0, 0, TEXT("Корея (КНДР)")}, + {108, 0, 0, TEXT("Корея")}, + {88, 0, 0, TEXT("Кувейт")}, + {109, 0, 0, TEXT("Лаос")}, + {110, 0, 0, TEXT("Ливан")}, + {111, 0, 0, TEXT("Малайзия")}, + {112, 0, 0, TEXT("Мальдивы")}, + {113, 0, 0, TEXT("Монголия")}, + {114, 0, 0, TEXT("Мьянма")}, + {115, 0, 0, TEXT("Непал")}, + {116, 0, 0, TEXT("Объединенные Арабские Эмираты")}, + {117, 0, 0, TEXT("Оман")}, + {3216, 0, 0, TEXT("Остров Рождества (Австр.)")}, + {122, 0, 0, TEXT("Пакистан")}, + {89, 0, 0, TEXT("Палестина")}, + {94, 0, 0, TEXT("Саудовская Аравия")}, + {118, 0, 0, TEXT("Сингапур")}, + {78, 0, 0, TEXT("Сирия")}, + {91, 0, 0, TEXT("Таджикистан")}, + {119, 0, 0, TEXT("Таиланд")}, + {120, 0, 0, TEXT("Тайвань")}, + {132, 0, 0, TEXT("Тимор")}, + {90, 0, 0, TEXT("Туркмения")}, + {77, 0, 0, TEXT("Турция")}, + {93, 0, 0, TEXT("Узбекистан")}, + {121, 0, 0, TEXT("Филиппины")}, + {98, 0, 0, TEXT("Шри Ланка")}, + {75, 0, 0, TEXT("Япония")}, + {123, 0, 0, TEXT("Австралия")}, + {454, 0, 0, TEXT("Американское Самоа")}, + {124, 0, 0, TEXT("Вануату")}, + {453, 0, 0, TEXT("Гуам (США)")}, + {126, 0, 0, TEXT("Кирибати")}, + {127, 0, 0, TEXT("Маршалловы Острова")}, + {128, 0, 0, TEXT("Микронезия (Федеративные Штаты Микронезии)")}, + {129, 0, 0, TEXT("Науру")}, + {3220, 0, 0, TEXT("Ниуэ (Н.Зел.)")}, + {130, 0, 0, TEXT("Новая Зеландия")}, + {3218, 0, 0, TEXT("Новая Каледония (Фр.)")}, + {3221, 0, 0, TEXT("Острова Кука (Н.Зел.)")}, + {3230, 0, 0, TEXT("Острова Херд и Макдональд (Австр.)")}, + {131, 0, 0, TEXT("Палау")}, + {133, 0, 0, TEXT("Папуа - Новая Гвинея")}, + {3222, 0, 0, TEXT("Питкерн (Брит.)")}, + {125, 0, 0, TEXT("Самоа")}, + {3219, 0, 0, TEXT("Сев. Марианские острова (США)")}, + {134, 0, 0, TEXT("Соломоновы Острова")}, + {3223, 0, 0, TEXT("Токелау (Н.Зел.)")}, + {135, 0, 0, TEXT("Тонга")}, + {136, 0, 0, TEXT("Тувалу")}, + {3224, 0, 0, TEXT("Уоллис и Футуна острова (Фр.)")}, + {137, 0, 0, TEXT("Фиджи")}, + {3226, 0, 0, TEXT("Французская Полинезия")}, + {3225, 0, 0, TEXT("Французские Южные территории")}, + {138, 0, 0, TEXT("Канада")}, + {139, 0, 0, TEXT("США")}, + {3200, 0, 0, TEXT("Ангилья (Брит.)")}, + {140, 0, 0, TEXT("Антигуа и Барбуда")}, + {141, 0, 0, TEXT("Аргентина")}, + {3202, 0, 0, TEXT("Аруба (Нид.)")}, + {142, 0, 0, TEXT("Багамы")}, + {143, 0, 0, TEXT("Барбадос")}, + {146, 0, 0, TEXT("Белиз")}, + {3203, 0, 0, TEXT("Бермуды (Брит.)")}, + {144, 0, 0, TEXT("Боливия")}, + {145, 0, 0, TEXT("Бразилия")}, + {147, 0, 0, TEXT("Венесуэла")}, + {3204, 0, 0, TEXT("Виргинские острова (Брит.)")}, + {452, 0, 0, TEXT("Виргинские острова (США)")}, + {149, 0, 0, TEXT("Гаити")}, + {148, 0, 0, TEXT("Гайана")}, + {3205, 0, 0, TEXT("Гваделупа (Фр.)")}, + {173, 0, 0, TEXT("Гватемала")}, + {150, 0, 0, TEXT("Гондурас")}, + {151, 0, 0, TEXT("Гренада")}, + {152, 0, 0, TEXT("Гренландия (Дат.)")}, + {153, 0, 0, TEXT("Доминика")}, + {154, 0, 0, TEXT("Доминиканская Республика")}, + {155, 0, 0, TEXT("Колумбия")}, + {156, 0, 0, TEXT("Коста-Рика")}, + {157, 0, 0, TEXT("Куба")}, + {3208, 0, 0, TEXT("Мартиника (Фр.)")}, + {158, 0, 0, TEXT("Мексика")}, + {3209, 0, 0, TEXT("Монтсеррат (Брит)")}, + {3201, 0, 0, TEXT("Нидерландские Антилы")}, + {159, 0, 0, TEXT("Никарагуа")}, + {3207, 0, 0, TEXT("Остров Кайман (Брит.)")}, + {3211, 0, 0, TEXT("Острова Теркс и Кайкос (Брит.)")}, + {160, 0, 0, TEXT("Панама")}, + {161, 0, 0, TEXT("Парагвай")}, + {162, 0, 0, TEXT("Перу")}, + {163, 0, 0, TEXT("Сальвадор")}, + {164, 0, 0, TEXT("Сент-Винсент и Гренадины")}, + {165, 0, 0, TEXT("Сент-Китс и Невис")}, + {166, 0, 0, TEXT("Сент-Люсия")}, + {3210, 0, 0, TEXT("Сент-Пьер и Микелон (Фр.)")}, + {167, 0, 0, TEXT("Суринам")}, + {168, 0, 0, TEXT("Тринидат и Тобаго")}, + {169, 0, 0, TEXT("Уругвай")}, + {3212, 0, 0, TEXT("Фолклендские острова (Брит.)")}, + {3206, 0, 0, TEXT("Французская Гвиана")}, + {170, 0, 0, TEXT("Чили")}, + {171, 0, 0, TEXT("Эквадор")}, + {3213, 0, 0, TEXT("Юж. Джорджия и Юж. Сандвичевы о-ва (Брит.)")}, + {172, 0, 0, TEXT("Ямайка")}, + {174, 0, 0, TEXT("Алжир")}, + {175, 0, 0, TEXT("Ангола")}, + {176, 0, 0, TEXT("Бенин")}, + {177, 0, 0, TEXT("Ботсвана")}, + {3228, 0, 0, TEXT("Британская территория в Индийском океане")}, + {178, 0, 0, TEXT("Буркина-Фасо")}, + {179, 0, 0, TEXT("Бурунди")}, + {180, 0, 0, TEXT("Габон")}, + {181, 0, 0, TEXT("Гамбия")}, + {182, 0, 0, TEXT("Гана")}, + {183, 0, 0, TEXT("Гвинея")}, + {184, 0, 0, TEXT("Гвинея-Бисау")}, + {185, 0, 0, TEXT("Джибути")}, + {186, 0, 0, TEXT("Египет")}, + {187, 0, 0, TEXT("Замбия")}, + {3198, 0, 0, TEXT("Зап. Сахара")}, + {23, 0, 0, TEXT("Зимбабве")}, + {188, 0, 0, TEXT("Кабо-Верде")}, + {189, 0, 0, TEXT("Камерун")}, + {190, 0, 0, TEXT("Кения")}, + {191, 0, 0, TEXT("Коморы")}, + {193, 0, 0, TEXT("Конго (Заир)")}, + {192, 0, 0, TEXT("Конго")}, + {194, 0, 0, TEXT("Кот-д`Ивуар")}, + {195, 0, 0, TEXT("Лесото")}, + {196, 0, 0, TEXT("Либерия")}, + {197, 0, 0, TEXT("Ливия")}, + {198, 0, 0, TEXT("Маврикий")}, + {199, 0, 0, TEXT("Мавритания")}, + {200, 0, 0, TEXT("Мадагаскар")}, + {3229, 0, 0, TEXT("Майотт (Фр.)")}, + {201, 0, 0, TEXT("Малави")}, + {202, 0, 0, TEXT("Мали")}, + {203, 0, 0, TEXT("Марокко")}, + {204, 0, 0, TEXT("Мозамбик")}, + {205, 0, 0, TEXT("Намибия")}, + {206, 0, 0, TEXT("Нигер")}, + {207, 0, 0, TEXT("Нигерия")}, + {3227, 0, 0, TEXT("Остров Буве (Норв.)")}, + {3197, 0, 0, TEXT("Реюньон (Фр.)")}, + {208, 0, 0, TEXT("Руанда")}, + {209, 0, 0, TEXT("Сан-Томе и Принсипи")}, + {210, 0, 0, TEXT("Свазиленд")}, + {3199, 0, 0, TEXT("Святая Елена (Брит.)")}, + {211, 0, 0, TEXT("Сейшелы")}, + {212, 0, 0, TEXT("Сенегал")}, + {213, 0, 0, TEXT("Сомали")}, + {214, 0, 0, TEXT("Судан")}, + {215, 0, 0, TEXT("Сьерра-Леоне")}, + {216, 0, 0, TEXT("Танзания")}, + {217, 0, 0, TEXT("Того")}, + {218, 0, 0, TEXT("Тунис")}, + {219, 0, 0, TEXT("Уганда")}, + {220, 0, 0, TEXT("Центральноафриканская Республика")}, + {222, 0, 0, TEXT("Чад")}, + {223, 0, 0, TEXT("Экваториальная Гвинея")}, + {221, 0, 0, TEXT("Эритрея")}, + {224, 0, 0, TEXT("Эфиопия")}, + {225, 0, 0, TEXT("Южно-Африканская Республика (ЮАР)")}, + {39, 0, 0, TEXT("Украина")}, + {40, 0, 0, TEXT("Австрия")}, + {32, 0, 0, TEXT("Албания")}, + {33, 0, 0, TEXT("Андорра")}, + {340, 0, 0, TEXT("Белоруссия")}, + {38, 0, 0, TEXT("Бельгия")}, + {41, 0, 0, TEXT("Болгария")}, + {42, 0, 0, TEXT("Босния и Герцеговина")}, + {43, 0, 0, TEXT("Ватикан")}, + {45, 0, 0, TEXT("Великобритания")}, + {44, 0, 0, TEXT("Венгрия")}, + {46, 0, 0, TEXT("Германия")}, + {3193, 0, 0, TEXT("Гернси (Брит.)")}, + {47, 0, 0, TEXT("Гибралтар (Брит.)")}, + {48, 0, 0, TEXT("Греция")}, + {49, 0, 0, TEXT("Дания")}, + {3194, 0, 0, TEXT("Джерси (Брит.)")}, + {50, 0, 0, TEXT("Ирландия")}, + {51, 0, 0, TEXT("Исландия")}, + {34, 0, 0, TEXT("Испания")}, + {52, 0, 0, TEXT("Италия")}, + {53, 0, 0, TEXT("Латвия")}, + {54, 0, 0, TEXT("Литва")}, + {55, 0, 0, TEXT("Лихтенштейн")}, + {56, 0, 0, TEXT("Люксембург")}, + {57, 0, 0, TEXT("Македония")}, + {58, 0, 0, TEXT("Мальта")}, + {59, 0, 0, TEXT("Молдавия")}, + {36, 0, 0, TEXT("Монако")}, + {60, 0, 0, TEXT("Нидерланды")}, + {61, 0, 0, TEXT("Норвегия")}, + {3195, 0, 0, TEXT("Остров Мэн (Брит.)")}, + {62, 0, 0, TEXT("Польша")}, + {35, 0, 0, TEXT("Португалия")}, + {63, 0, 0, TEXT("Румыния")}, + {64, 0, 0, TEXT("Сан-Марино")}, + {74, 0, 0, TEXT("Сербия и Черногория")}, + {65, 0, 0, TEXT("Словакия")}, + {66, 0, 0, TEXT("Словения")}, + {67, 0, 0, TEXT("Фарерские о-ва (Дания)")}, + {68, 0, 0, TEXT("Финляндия")}, + {37, 0, 0, TEXT("Франция")}, + {69, 0, 0, TEXT("Хорватия")}, + {70, 0, 0, TEXT("Чехия")}, + {71, 0, 0, TEXT("Швейцария")}, + {72, 0, 0, TEXT("Швеция")}, + {3196, 0, 0, TEXT("Шпицберген (Норв.)")}, + {73, 0, 0, TEXT("Эстония")}, + {24, 25, 0, TEXT("Москва")}, + {24, 226, 0, TEXT("Санкт-Петербург")}, + {24, 233, 0, TEXT("Саха (Якутия)")}, + {24, 232, 0, TEXT("Приморский край")}, + {24, 235, 0, TEXT("Хабаровский край")}, + {24, 227, 0, TEXT("Амурская обл.")}, + {24, 229, 0, TEXT("Камчатская обл.")}, + {24, 231, 0, TEXT("Магаданская обл.")}, + {24, 234, 0, TEXT("Сахалинская обл.")}, + {24, 228, 0, TEXT("Еврейская АО")}, + {24, 230, 0, TEXT("Корякский АО")}, + {24, 236, 0, TEXT("Чукотский АО")}, + {24, 237, 0, TEXT("Башкортостан")}, + {24, 240, 0, TEXT("Марий-Эл")}, + {24, 241, 0, TEXT("Мордовия")}, + {24, 248, 0, TEXT("Татарстан")}, + {24, 249, 0, TEXT("Удмуртия")}, + {24, 251, 0, TEXT("Чувашия")}, + {24, 238, 0, TEXT("Кировская обл.")}, + {24, 242, 0, TEXT("Нижегородская обл.")}, + {24, 243, 0, TEXT("Оренбургская обл.")}, + {24, 244, 0, TEXT("Пензенская обл.")}, + {24, 245, 0, TEXT("Пермская обл.")}, + {24, 246, 0, TEXT("Самарская обл.")}, + {24, 247, 0, TEXT("Саратовская обл.")}, + {24, 250, 0, TEXT("Ульяновская обл.")}, + {24, 239, 0, TEXT("Коми-Пермяцкий АО")}, + {24, 255, 0, TEXT("Карелия")}, + {24, 256, 0, TEXT("Коми")}, + {24, 252, 0, TEXT("Архангельская обл.")}, + {24, 253, 0, TEXT("Вологодская обл.")}, + {24, 254, 0, TEXT("Калининградская обл.")}, + {24, 257, 0, TEXT("Ленинградская обл.")}, + {24, 258, 0, TEXT("Мурманская обл.")}, + {24, 260, 0, TEXT("Новгородская обл.")}, + {24, 261, 0, TEXT("Псковская обл.")}, + {24, 259, 0, TEXT("Ненецкий АО")}, + {24, 265, 0, TEXT("Бурятия")}, + {24, 263, 0, TEXT("Республика Алтай")}, + {24, 273, 0, TEXT("Тыва")}, + {24, 275, 0, TEXT("Хакасия")}, + {24, 264, 0, TEXT("Алтайский край")}, + {24, 268, 0, TEXT("Красноярский край")}, + {24, 266, 0, TEXT("Иркутская обл.")}, + {24, 267, 0, TEXT("Кемеровская обл.")}, + {24, 269, 0, TEXT("Новосибирская обл.")}, + {24, 270, 0, TEXT("Омская обл.")}, + {24, 272, 0, TEXT("Томская обл.")}, + {24, 276, 0, TEXT("Читинская обл.")}, + {24, 262, 0, TEXT("Агинский Бурятский АО")}, + {24, 271, 0, TEXT("Таймырский АО")}, + {24, 274, 0, TEXT("Усть-Ордынский Бурятский АО")}, + {24, 277, 0, TEXT("Эвенкийский АО")}, + {24, 278, 0, TEXT("Курганская обл.")}, + {24, 279, 0, TEXT("Свердловская обл.")}, + {24, 280, 0, TEXT("Тюменская обл.")}, + {24, 282, 0, TEXT("Челябинская обл.")}, + {24, 281, 0, TEXT("Ханты-Мансийский АО - Югра")}, + {24, 283, 0, TEXT("Ямало-Ненецкий АО")}, + {24, 284, 0, TEXT("Белгородская обл.")}, + {24, 285, 0, TEXT("Брянская обл.")}, + {24, 286, 0, TEXT("Владимирская обл.")}, + {24, 287, 0, TEXT("Воронежская обл.")}, + {24, 288, 0, TEXT("Ивановская обл.")}, + {24, 289, 0, TEXT("Калужская обл.")}, + {24, 290, 0, TEXT("Костромская обл.")}, + {24, 291, 0, TEXT("Курская обл.")}, + {24, 292, 0, TEXT("Липецкая обл.")}, + {24, 293, 0, TEXT("Московская обл.")}, + {24, 294, 0, TEXT("Орловская обл.")}, + {24, 295, 0, TEXT("Рязанская обл.")}, + {24, 296, 0, TEXT("Смоленская обл.")}, + {24, 297, 0, TEXT("Тамбовская обл.")}, + {24, 298, 0, TEXT("Тверская обл.")}, + {24, 299, 0, TEXT("Тульская обл.")}, + {24, 300, 0, TEXT("Ярославская обл.")}, + {24, 301, 0, TEXT("Адыгея")}, + {24, 304, 0, TEXT("Дагестан")}, + {24, 305, 0, TEXT("Ингушетия")}, + {24, 306, 0, TEXT("Кабардино-Балкария")}, + {24, 307, 0, TEXT("Калмыкия")}, + {24, 308, 0, TEXT("Карачаево-Черкессия")}, + {24, 311, 0, TEXT("Северная Осетия - Алания")}, + {24, 313, 0, TEXT("Чечня")}, + {24, 309, 0, TEXT("Краснодарский край")}, + {24, 312, 0, TEXT("Ставропольский край")}, + {24, 302, 0, TEXT("Астраханская обл.")}, + {24, 303, 0, TEXT("Волгоградская обл.")}, + {24, 310, 0, TEXT("Ростовская обл.")}, + {81, 1055, 0, TEXT("Баку")}, + {81, 1058, 0, TEXT("Гянджа")}, + {81, 1056, 0, TEXT("Нахичевань")}, + {81, 1057, 0, TEXT("Ханкенди")}, + {81, 3153, 0, TEXT("Шеки")}, + {81, 2291, 0, lpwszOther}, + {82, 2932, 0, TEXT("Абовян")}, + {82, 1060, 0, TEXT("Аштарак")}, + {82, 3084, 0, TEXT("Ванадзор")}, + {82, 3011, 0, TEXT("Гюмри")}, + {82, 3306, 0, TEXT("Дилижан")}, + {82, 1059, 0, TEXT("Ереван")}, + {82, 3145, 0, TEXT("Ханкенди")}, + {82, 2292, 0, lpwszOther}, + {97, 1061, 0, TEXT("Кабул")}, + {97, 2293, 0, lpwszOther}, + {96, 1062, 0, TEXT("Дакка")}, + {96, 2294, 0, lpwszOther}, + {99, 1063, 0, TEXT("Манама")}, + {99, 2295, 0, lpwszOther}, + {100, 1064, 0, TEXT("Бандар-Сери-Бегаван")}, + {100, 2296, 0, lpwszOther}, + {101, 1065, 0, TEXT("Тхимпху")}, + {101, 2297, 0, lpwszOther}, + {102, 1066, 0, TEXT("Ханой")}, + {102, 2298, 0, lpwszOther}, + {83, 1067, 0, TEXT("Батуми")}, + {83, 3158, 0, TEXT("Боржоми")}, + {83, 1068, 0, TEXT("Поти")}, + {83, 3129, 0, TEXT("Рустави")}, + {83, 1069, 0, TEXT("Сухуми")}, + {83, 1070, 0, TEXT("Тбилиси")}, + {83, 2299, 0, lpwszOther}, + {86, 3345, 0, TEXT("Ариэль")}, + {86, 1071, 0, TEXT("Афула")}, + {86, 2992, 0, TEXT("Ашдод")}, + {86, 3175, 0, TEXT("Ашкелон")}, + {86, 3363, 0, TEXT("Бат-Ям")}, + {86, 2884, 0, TEXT("Беер-Яков")}, + {86, 3243, 0, TEXT("Бейт-Шемеш")}, + {86, 1074, 0, TEXT("Беэр-Шева")}, + {86, 3348, 0, TEXT("Герцелия")}, + {86, 3241, 0, TEXT("Димона")}, + {86, 1075, 0, TEXT("Иерусалим")}, + {86, 3350, 0, TEXT("Йокнеам-Иллит")}, + {86, 2982, 0, TEXT("Кармиэль")}, + {86, 2971, 0, TEXT("Кфар-Саба")}, + {86, 3136, 0, TEXT("Назарет")}, + {86, 1080, 0, TEXT("Натания")}, + {86, 3303, 0, TEXT("Офаким")}, + {86, 3050, 0, TEXT("Раанана")}, + {86, 3151, 0, TEXT("Рамат Ган")}, + {86, 3141, 0, TEXT("Реховот")}, + {86, 3012, 0, TEXT("Ришон ле Цион")}, + {86, 1081, 0, TEXT("Тверия")}, + {86, 1077, 0, TEXT("Тель-Авив")}, + {86, 1079, 0, TEXT("Хадера")}, + {86, 1078, 0, TEXT("Хайфа")}, + {86, 1076, 0, TEXT("Хеврон")}, + {86, 2929, 0, TEXT("Цфат")}, + {86, 2928, 0, TEXT("Эйлат")}, + {86, 2300, 0, lpwszOther}, + {95, 3315, 0, TEXT("Бангалор")}, + {95, 1082, 0, TEXT("Дели")}, + {95, 1083, 0, TEXT("Джайпур")}, + {95, 3144, 0, TEXT("Калькутта")}, + {95, 3025, 0, TEXT("Мумбаи")}, + {95, 3277, 0, TEXT("Панаджи")}, + {95, 1084, 0, TEXT("Ченнаи")}, + {95, 2301, 0, lpwszOther}, + {103, 1085, 0, TEXT("Джакарта")}, + {103, 2302, 0, lpwszOther}, + {79, 1086, 0, TEXT("Амман")}, + {79, 2303, 0, lpwszOther}, + {85, 1087, 0, TEXT("Багдад")}, + {85, 2304, 0, lpwszOther}, + {87, 1088, 0, TEXT("Тегеран")}, + {87, 2305, 0, lpwszOther}, + {104, 1089, 0, TEXT("Сана")}, + {104, 2306, 0, lpwszOther}, + {84, 1090, 0, TEXT("Актау")}, + {84, 1091, 0, TEXT("Актюбинск")}, + {84, 1092, 0, TEXT("Алма-Ата")}, + {84, 3242, 0, TEXT("Аршалы")}, + {84, 1093, 0, TEXT("Астана")}, + {84, 1094, 0, TEXT("Атырау (Гурьев)")}, + {84, 1095, 0, TEXT("Байконур")}, + {84, 3245, 0, TEXT("Балхаш")}, + {84, 3083, 0, TEXT("Жезказган")}, + {84, 1096, 0, TEXT("Капчагай")}, + {84, 1097, 0, TEXT("Караганда")}, + {84, 1098, 0, TEXT("Кокшетау")}, + {84, 1099, 0, TEXT("Кустанай")}, + {84, 2868, 0, TEXT("Лисаковск")}, + {84, 1100, 0, TEXT("Павлодар")}, + {84, 1101, 0, TEXT("Петропавловск (Сев.-Каз. обл.)")}, + {84, 1102, 0, TEXT("Рудный")}, + {84, 1103, 0, TEXT("Семипалатинск")}, + {84, 1104, 0, TEXT("Степногорск")}, + {84, 3166, 0, TEXT("Талгар")}, + {84, 1105, 0, TEXT("Талды-Курган")}, + {84, 2927, 0, TEXT("Тараз")}, + {84, 1106, 0, TEXT("Темиртау")}, + {84, 1107, 0, TEXT("Уральск")}, + {84, 1108, 0, TEXT("Усть-Каменогорск")}, + {84, 1109, 0, TEXT("Чимкент")}, + {84, 1110, 0, TEXT("Экибастуз")}, + {84, 2307, 0, lpwszOther}, + {105, 1111, 0, TEXT("Пномпень")}, + {105, 2308, 0, lpwszOther}, + {106, 1112, 0, TEXT("Доха")}, + {106, 2309, 0, lpwszOther}, + {107, 1113, 0, TEXT("Ларнака")}, + {107, 1114, 0, TEXT("Лимассол")}, + {107, 1115, 0, TEXT("Никосия")}, + {107, 2954, 0, TEXT("Пафос")}, + {107, 2310, 0, lpwszOther}, + {92, 1116, 0, TEXT("Бишкек")}, + {92, 1117, 0, TEXT("Джалал-Абад")}, + {92, 3027, 0, TEXT("Кара-Балта")}, + {92, 1118, 0, TEXT("Каракол")}, + {92, 1119, 0, TEXT("Ош")}, + {92, 1120, 0, TEXT("Талас")}, + {92, 2933, 0, TEXT("Хайдаркен")}, + {92, 2311, 0, lpwszOther}, + {76, 3214, 0, TEXT("Аомынь (Макао)")}, + {76, 1121, 0, TEXT("Гонконг")}, + {76, 2869, 0, TEXT("Гуанчжоу")}, + {76, 3262, 0, TEXT("Далянь")}, + {76, 1122, 0, TEXT("Пекин")}, + {76, 1123, 0, TEXT("Харбин")}, + {76, 1124, 0, TEXT("Шанхай")}, + {76, 3043, 0, TEXT("Шеньян")}, + {76, 2312, 0, lpwszOther}, + {29, 1125, 0, TEXT("Пхеньян")}, + {29, 2313, 0, lpwszOther}, + {108, 1126, 0, TEXT("Сеул")}, + {108, 3240, 0, TEXT("Тейджон")}, + {108, 2314, 0, lpwszOther}, + {88, 1127, 0, TEXT("Эль-Кувейт")}, + {88, 2315, 0, lpwszOther}, + {109, 1128, 0, TEXT("Вьентьян")}, + {109, 2316, 0, lpwszOther}, + {110, 1129, 0, TEXT("Бейрут")}, + {110, 2317, 0, lpwszOther}, + {111, 1130, 0, TEXT("Джохор-Бару")}, + {111, 1131, 0, TEXT("Куала-Лумпур")}, + {111, 2318, 0, lpwszOther}, + {112, 1132, 0, TEXT("Мале")}, + {112, 2319, 0, lpwszOther}, + {113, 1133, 0, TEXT("Улан-Батор")}, + {113, 1134, 0, TEXT("Эрдэнэт")}, + {113, 2320, 0, lpwszOther}, + {114, 1135, 0, TEXT("Янгон")}, + {114, 2321, 0, lpwszOther}, + {115, 1136, 0, TEXT("Катманду")}, + {115, 2322, 0, lpwszOther}, + {116, 1137, 0, TEXT("Абу-Даби")}, + {116, 1138, 0, TEXT("Дубай")}, + {116, 1139, 0, TEXT("Шарджа")}, + {116, 2323, 0, lpwszOther}, + {117, 1140, 0, TEXT("Маскат")}, + {117, 2324, 0, lpwszOther}, + {122, 1141, 0, TEXT("Исламабад")}, + {122, 2325, 0, lpwszOther}, + {89, 1072, 0, TEXT("Ашдод")}, + {89, 1073, 0, TEXT("Ашкелон")}, + {89, 1142, 0, TEXT("Газа")}, + {89, 2326, 0, lpwszOther}, + {94, 3250, 0, TEXT("Медина")}, + {94, 1143, 0, TEXT("Эр-Рияд")}, + {94, 2327, 0, lpwszOther}, + {78, 1144, 0, TEXT("Дамаск")}, + {78, 2328, 0, lpwszOther}, + {91, 1145, 0, TEXT("Душанбе")}, + {91, 3307, 0, TEXT("Кайраккум")}, + {91, 3308, 0, TEXT("Худжанд")}, + {91, 2329, 0, lpwszOther}, + {119, 1146, 0, TEXT("Бангкок")}, + {119, 1147, 0, TEXT("Пхукет")}, + {119, 2330, 0, lpwszOther}, + {120, 1148, 0, TEXT("Тайбэй")}, + {120, 2331, 0, lpwszOther}, + {132, 1149, 0, TEXT("Дили")}, + {132, 2332, 0, lpwszOther}, + {90, 1150, 0, TEXT("Ашхабад")}, + {90, 3079, 0, TEXT("Безмеин")}, + {90, 2333, 0, lpwszOther}, + {77, 1152, 0, TEXT("Анкара")}, + {77, 1153, 0, TEXT("Анталия")}, + {77, 3080, 0, TEXT("Бурса")}, + {77, 1151, 0, TEXT("Мармарис")}, + {77, 1154, 0, TEXT("Стамбул")}, + {77, 1155, 0, TEXT("Трабзон")}, + {77, 2334, 0, lpwszOther}, + {93, 3362, 0, TEXT("Алмалык")}, + {93, 3137, 0, TEXT("Андижан")}, + {93, 3273, 0, TEXT("Асака")}, + {93, 1156, 0, TEXT("Ахангаран")}, + {93, 1157, 0, TEXT("Бухара")}, + {93, 3167, 0, TEXT("Джизак")}, + {93, 3347, 0, TEXT("Кунград")}, + {93, 1158, 0, TEXT("Навои")}, + {93, 1159, 0, TEXT("Наманган")}, + {93, 1160, 0, TEXT("Самарканд")}, + {93, 1161, 0, TEXT("Ташкент")}, + {93, 1162, 0, TEXT("Ургенч")}, + {93, 1163, 0, TEXT("Фергана")}, + {93, 1164, 0, TEXT("Чирчик")}, + {93, 2335, 0, lpwszOther}, + {121, 1165, 0, TEXT("Манила")}, + {121, 3319, 0, TEXT("Себу")}, + {121, 2336, 0, lpwszOther}, + {98, 1166, 0, TEXT("Коломбо")}, + {98, 2337, 0, lpwszOther}, + {75, 3176, 0, TEXT("Исесаки")}, + {75, 3339, 0, TEXT("Корияма")}, + {75, 1167, 0, TEXT("Саппоро")}, + {75, 1168, 0, TEXT("Токио")}, + {75, 2338, 0, lpwszOther}, + {123, 1914, 0, TEXT("Аделаида")}, + {123, 2957, 0, TEXT("Блэк Рок")}, + {123, 1915, 0, TEXT("Брисбен")}, + {123, 3331, 0, TEXT("Горокан")}, + {123, 1916, 0, TEXT("Канберра")}, + {123, 3001, 0, TEXT("Лидкомб")}, + {123, 1917, 0, TEXT("Мельбурн")}, + {123, 3217, 0, TEXT("Норфолк")}, + {123, 3064, 0, TEXT("Перт")}, + {123, 3020, 0, TEXT("Санта Люсиа")}, + {123, 1918, 0, TEXT("Сидней")}, + {123, 3238, 0, TEXT("Энеабба")}, + {123, 2339, 0, lpwszOther}, + {454, 1192, 0, TEXT("Паго-Паго")}, + {454, 2366, 0, lpwszOther}, + {124, 1919, 0, TEXT("Порт-Вила")}, + {124, 2340, 0, lpwszOther}, + {453, 1193, 0, TEXT("Аганья")}, + {453, 2368, 0, lpwszOther}, + {126, 1921, 0, TEXT("Баирики")}, + {126, 2342, 0, lpwszOther}, + {127, 1922, 0, TEXT("Маджуро")}, + {127, 2343, 0, lpwszOther}, + {128, 1923, 0, TEXT("Паликир")}, + {128, 2344, 0, lpwszOther}, + {129, 1924, 0, TEXT("Ярен")}, + {129, 2345, 0, lpwszOther}, + {130, 1925, 0, TEXT("Веллингтон")}, + {130, 1926, 0, TEXT("Гамильтон")}, + {130, 1928, 0, TEXT("Данидин")}, + {130, 1929, 0, TEXT("Крайстчерч")}, + {130, 3235, 0, TEXT("Кромвель")}, + {130, 1927, 0, TEXT("Окленд")}, + {130, 3323, 0, TEXT("Тауранга")}, + {130, 2346, 0, lpwszOther}, + {131, 1930, 0, TEXT("Корор")}, + {131, 2347, 0, lpwszOther}, + {133, 1931, 0, TEXT("Порт-Морсби")}, + {133, 2348, 0, lpwszOther}, + {125, 1920, 0, TEXT("Апиа")}, + {125, 2341, 0, lpwszOther}, + {134, 1932, 0, TEXT("Хониара")}, + {134, 2349, 0, lpwszOther}, + {135, 1933, 0, TEXT("Нукуалофа")}, + {135, 2350, 0, lpwszOther}, + {136, 1934, 0, TEXT("Фунафути")}, + {136, 2351, 0, lpwszOther}, + {137, 1935, 0, TEXT("Сува")}, + {137, 2352, 0, lpwszOther}, + {138, 3055, 0, TEXT("Барлингтон")}, + {138, 3049, 0, TEXT("Броссард")}, + {138, 3330, 0, TEXT("Бурнаби")}, + {138, 1169, 0, TEXT("Ванкувер")}, + {138, 3106, 0, TEXT("Ватерлоо")}, + {138, 1170, 0, TEXT("Виннипег")}, + {138, 1171, 0, TEXT("Галифакс")}, + {138, 1172, 0, TEXT("Гамильтон")}, + {138, 3365, 0, TEXT("Денвер")}, + {138, 1173, 0, TEXT("Калгари")}, + {138, 3104, 0, TEXT("Камлупс")}, + {138, 3366, 0, TEXT("Каннингтон")}, + {138, 1174, 0, TEXT("Квебек")}, + {138, 2964, 0, TEXT("Кингстон")}, + {138, 3113, 0, TEXT("Коквитлам")}, + {138, 1175, 0, TEXT("Монреаль")}, + {138, 2920, 0, TEXT("Ниагара-Фолс")}, + {138, 2889, 0, TEXT("Норд-Йорк")}, + {138, 1176, 0, TEXT("Оттава")}, + {138, 2903, 0, TEXT("Порт Алберни")}, + {138, 1177, 0, TEXT("Ричмонд")}, + {138, 1178, 0, TEXT("Тимминс")}, + {138, 2946, 0, TEXT("Торнхилл")}, + {138, 1179, 0, TEXT("Торонто")}, + {138, 1180, 0, TEXT("Эдмонтон")}, + {138, 2353, 0, lpwszOther}, + {139, 407, 0, TEXT("Вашингтон")}, + {139, 426, 0, TEXT("Айдахо")}, + {139, 378, 0, TEXT("Айова")}, + {139, 412, 0, TEXT("Алабама")}, + {139, 446, 0, TEXT("Аляска")}, + {139, 434, 0, TEXT("Аризона")}, + {139, 416, 0, TEXT("Арканзас")}, + {139, 428, 0, TEXT("Вайоминг")}, + {139, 440, 0, TEXT("Вашингтон")}, + {139, 352, 0, TEXT("Вермонт")}, + {139, 394, 0, TEXT("Виргиния")}, + {139, 374, 0, TEXT("Висконсин")}, + {139, 448, 0, TEXT("Гавайи")}, + {139, 390, 0, TEXT("Делавер")}, + {139, 402, 0, TEXT("Джорджия")}, + {139, 396, 0, TEXT("Западная Виргиния")}, + {139, 370, 0, TEXT("Иллинойс")}, + {139, 368, 0, TEXT("Индиана")}, + {139, 444, 0, TEXT("Калифорния")}, + {139, 388, 0, TEXT("Канзас")}, + {139, 408, 0, TEXT("Кентукки")}, + {139, 430, 0, TEXT("Колорадо")}, + {139, 358, 0, TEXT("Коннектикут")}, + {139, 418, 0, TEXT("Луизиана")}, + {139, 354, 0, TEXT("Массачусетс")}, + {139, 376, 0, TEXT("Миннесота")}, + {139, 414, 0, TEXT("Миссисипи")}, + {139, 380, 0, TEXT("Миссури")}, + {139, 372, 0, TEXT("Мичиган")}, + {139, 424, 0, TEXT("Монтана")}, + {139, 348, 0, TEXT("Мэн")}, + {139, 392, 0, TEXT("Мэриленд")}, + {139, 386, 0, TEXT("Небраска")}, + {139, 438, 0, TEXT("Невада")}, + {139, 362, 0, TEXT("Нью-Джерси")}, + {139, 360, 0, TEXT("Нью-Йорк")}, + {139, 432, 0, TEXT("Нью-Мексико")}, + {139, 350, 0, TEXT("Нью-Хэмпшир")}, + {139, 366, 0, TEXT("Огайо")}, + {139, 420, 0, TEXT("Оклахома")}, + {139, 442, 0, TEXT("Орегон")}, + {139, 364, 0, TEXT("Пенсильвания")}, + {139, 450, 0, TEXT("Пуэрто-Рико")}, + {139, 356, 0, TEXT("Род-Айленд")}, + {139, 382, 0, TEXT("Северная Дакота")}, + {139, 398, 0, TEXT("Северная Каролина")}, + {139, 410, 0, TEXT("Теннесси")}, + {139, 422, 0, TEXT("Техас")}, + {139, 406, 0, TEXT("Федеральный округ Колумбия")}, + {139, 404, 0, TEXT("Флорида")}, + {139, 384, 0, TEXT("Южная Дакота")}, + {139, 400, 0, TEXT("Южная Каролина")}, + {139, 436, 0, TEXT("Юта")}, + {140, 1238, 0, TEXT("Сент-Джонс")}, + {140, 2442, 0, lpwszOther}, + {141, 1239, 0, TEXT("Буэнос-Айрес")}, + {141, 2441, 0, lpwszOther}, + {142, 1240, 0, TEXT("Нассау")}, + {142, 2440, 0, lpwszOther}, + {143, 1241, 0, TEXT("Бриджтаун")}, + {143, 2439, 0, lpwszOther}, + {146, 1242, 0, TEXT("Бельмопан")}, + {146, 2438, 0, lpwszOther}, + {144, 1243, 0, TEXT("Ла-Пас")}, + {144, 2437, 0, lpwszOther}, + {145, 1244, 0, TEXT("Бразилиа")}, + {145, 3094, 0, TEXT("Пассо Фундо")}, + {145, 1245, 0, TEXT("Рио-де-Жанейро")}, + {145, 1246, 0, TEXT("Сан-Паулу")}, + {145, 2436, 0, lpwszOther}, + {147, 1247, 0, TEXT("Каракас")}, + {147, 2435, 0, lpwszOther}, + {452, 1190, 0, TEXT("Шарлотта-Амалия")}, + {452, 2364, 0, lpwszOther}, + {149, 1248, 0, TEXT("Порт-о-Пренс")}, + {149, 2434, 0, lpwszOther}, + {148, 1249, 0, TEXT("Джоржтаун")}, + {148, 2433, 0, lpwszOther}, + {173, 1250, 0, TEXT("Гватемала")}, + {173, 2432, 0, lpwszOther}, + {150, 1251, 0, TEXT("Тегусигальпа")}, + {150, 2431, 0, lpwszOther}, + {151, 1252, 0, TEXT("Сент-Джорджес")}, + {151, 2430, 0, lpwszOther}, + {152, 1253, 0, TEXT("Уманак")}, + {152, 2429, 0, lpwszOther}, + {153, 1254, 0, TEXT("Розо")}, + {153, 2428, 0, lpwszOther}, + {154, 1255, 0, TEXT("Санто-Доминго")}, + {154, 2427, 0, lpwszOther}, + {155, 1256, 0, TEXT("Богота")}, + {155, 2426, 0, lpwszOther}, + {156, 1257, 0, TEXT("Сан-Хосе")}, + {156, 2425, 0, lpwszOther}, + {157, 1258, 0, TEXT("Гавана")}, + {157, 2424, 0, lpwszOther}, + {158, 1259, 0, TEXT("Акапулько")}, + {158, 1260, 0, TEXT("Мехико")}, + {158, 2423, 0, lpwszOther}, + {159, 1261, 0, TEXT("Манагуа")}, + {159, 2422, 0, lpwszOther}, + {160, 1262, 0, TEXT("Панама")}, + {160, 2421, 0, lpwszOther}, + {161, 1263, 0, TEXT("Асунсьон")}, + {161, 2420, 0, lpwszOther}, + {162, 1264, 0, TEXT("Лима")}, + {162, 2419, 0, lpwszOther}, + {163, 1265, 0, TEXT("Сан-Сальвадор")}, + {163, 2418, 0, lpwszOther}, + {164, 1266, 0, TEXT("Кингстаун")}, + {164, 2417, 0, lpwszOther}, + {165, 1267, 0, TEXT("Бастер")}, + {165, 2416, 0, lpwszOther}, + {166, 1268, 0, TEXT("Кастри")}, + {166, 2415, 0, lpwszOther}, + {167, 1269, 0, TEXT("Парамарибо")}, + {167, 2414, 0, lpwszOther}, + {168, 1270, 0, TEXT("Порт-оф-Спейн")}, + {168, 2413, 0, lpwszOther}, + {169, 1271, 0, TEXT("Монтевидео")}, + {169, 2412, 0, lpwszOther}, + {170, 1272, 0, TEXT("Сантьяго")}, + {170, 2411, 0, lpwszOther}, + {171, 1273, 0, TEXT("Гуаякиль")}, + {171, 1274, 0, TEXT("Кито")}, + {171, 2410, 0, lpwszOther}, + {172, 1275, 0, TEXT("Кингстон")}, + {172, 2409, 0, lpwszOther}, + {174, 1854, 0, TEXT("Алжир")}, + {174, 2495, 0, lpwszOther}, + {175, 1855, 0, TEXT("Луанда")}, + {175, 2494, 0, lpwszOther}, + {176, 1856, 0, TEXT("Котону")}, + {176, 1857, 0, TEXT("Порто-Ново")}, + {176, 2493, 0, lpwszOther}, + {177, 1858, 0, TEXT("Габороне")}, + {177, 2492, 0, lpwszOther}, + {178, 1859, 0, TEXT("Уагадугу")}, + {178, 2491, 0, lpwszOther}, + {179, 1860, 0, TEXT("Бужумбуру")}, + {179, 2490, 0, lpwszOther}, + {180, 1861, 0, TEXT("Либревиль")}, + {180, 2489, 0, lpwszOther}, + {181, 1862, 0, TEXT("Банжул")}, + {181, 2488, 0, lpwszOther}, + {182, 1863, 0, TEXT("Аккра")}, + {182, 2487, 0, lpwszOther}, + {183, 1864, 0, TEXT("Конакри")}, + {183, 2486, 0, lpwszOther}, + {184, 1865, 0, TEXT("Бисау")}, + {184, 2485, 0, lpwszOther}, + {185, 1866, 0, TEXT("Джибути")}, + {185, 2484, 0, lpwszOther}, + {186, 3312, 0, TEXT("Дахаб")}, + {186, 1867, 0, TEXT("Каир")}, + {186, 1868, 0, TEXT("Хургада")}, + {186, 2483, 0, lpwszOther}, + {187, 1869, 0, TEXT("Лусака")}, + {187, 2482, 0, lpwszOther}, + {23, 1870, 0, TEXT("Хараре")}, + {23, 2481, 0, lpwszOther}, + {188, 1871, 0, TEXT("Прая")}, + {188, 2480, 0, lpwszOther}, + {189, 1872, 0, TEXT("Яунде")}, + {189, 2479, 0, lpwszOther}, + {190, 1873, 0, TEXT("Найроби")}, + {190, 2478, 0, lpwszOther}, + {191, 1874, 0, TEXT("Морони")}, + {191, 2477, 0, lpwszOther}, + {193, 1875, 0, TEXT("Киншаса")}, + {193, 2476, 0, lpwszOther}, + {192, 1876, 0, TEXT("Браззавиль")}, + {192, 2475, 0, lpwszOther}, + {194, 1877, 0, TEXT("Ямусукро")}, + {194, 2474, 0, lpwszOther}, + {195, 1878, 0, TEXT("Масеру")}, + {195, 2473, 0, lpwszOther}, + {196, 1879, 0, TEXT("Монровия")}, + {196, 2472, 0, lpwszOther}, + {197, 1880, 0, TEXT("Триполи")}, + {197, 2471, 0, lpwszOther}, + {198, 1881, 0, TEXT("Порт-Луи")}, + {198, 2470, 0, lpwszOther}, + {199, 1882, 0, TEXT("Нуакшот")}, + {199, 2469, 0, lpwszOther}, + {200, 1883, 0, TEXT("Антананариву")}, + {200, 2468, 0, lpwszOther}, + {201, 1884, 0, TEXT("Лилонгве")}, + {201, 2467, 0, lpwszOther}, + {202, 1885, 0, TEXT("Бамако")}, + {202, 2466, 0, lpwszOther}, + {203, 1886, 0, TEXT("Агадир")}, + {203, 1887, 0, TEXT("Рабат")}, + {203, 2465, 0, lpwszOther}, + {204, 1888, 0, TEXT("Мапуту")}, + {204, 2464, 0, lpwszOther}, + {205, 1889, 0, TEXT("Виндхук")}, + {205, 2463, 0, lpwszOther}, + {206, 1890, 0, TEXT("Ниамей")}, + {206, 2462, 0, lpwszOther}, + {207, 1891, 0, TEXT("Абуджа")}, + {207, 2461, 0, lpwszOther}, + {208, 1892, 0, TEXT("Кигали")}, + {208, 2460, 0, lpwszOther}, + {209, 1893, 0, TEXT("Сан-Томе")}, + {209, 2459, 0, lpwszOther}, + {210, 1894, 0, TEXT("Мбабане")}, + {210, 2458, 0, lpwszOther}, + {211, 1895, 0, TEXT("Виктория")}, + {211, 2457, 0, lpwszOther}, + {212, 1896, 0, TEXT("Дакар")}, + {212, 2456, 0, lpwszOther}, + {213, 1897, 0, TEXT("Могадишо")}, + {213, 2455, 0, lpwszOther}, + {214, 1898, 0, TEXT("Хартум")}, + {214, 2454, 0, lpwszOther}, + {215, 1899, 0, TEXT("Фритаун")}, + {215, 2453, 0, lpwszOther}, + {216, 1900, 0, TEXT("Дар-эс-Салам")}, + {216, 1901, 0, TEXT("Додома")}, + {216, 2452, 0, lpwszOther}, + {217, 1902, 0, TEXT("Ломе")}, + {217, 2451, 0, lpwszOther}, + {218, 1903, 0, TEXT("Тунис")}, + {218, 2450, 0, lpwszOther}, + {219, 1904, 0, TEXT("Кампала")}, + {219, 2449, 0, lpwszOther}, + {220, 1905, 0, TEXT("Банги")}, + {220, 2448, 0, lpwszOther}, + {222, 1906, 0, TEXT("Нджамена")}, + {222, 2447, 0, lpwszOther}, + {223, 1907, 0, TEXT("Малабо")}, + {223, 2446, 0, lpwszOther}, + {221, 1908, 0, TEXT("Асмэра")}, + {221, 2445, 0, lpwszOther}, + {224, 1909, 0, TEXT("Аддис-Абеба")}, + {224, 2444, 0, lpwszOther}, + {225, 1910, 0, TEXT("Дурбан")}, + {225, 1913, 0, TEXT("Йоханнесбург")}, + {225, 1912, 0, TEXT("Кейптаун")}, + {225, 3033, 0, TEXT("Пайнтаун")}, + {225, 1911, 0, TEXT("Претория")}, + {225, 2443, 0, lpwszOther}, + {39, 314, 0, TEXT("Киев")}, + {39, 315, 0, TEXT("Винницкая обл.")}, + {39, 316, 0, TEXT("Волынская обл.")}, + {39, 317, 0, TEXT("Днепропетровская обл.")}, + {39, 318, 0, TEXT("Донецкая обл.")}, + {39, 319, 0, TEXT("Житомирская обл.")}, + {39, 320, 0, TEXT("Закарпатская обл.")}, + {39, 321, 0, TEXT("Запорожская обл.")}, + {39, 322, 0, TEXT("Ивано-Франковская обл.")}, + {39, 323, 0, TEXT("Киевская обл.")}, + {39, 324, 0, TEXT("Кировоградская обл.")}, + {39, 325, 0, TEXT("Крым")}, + {39, 326, 0, TEXT("Луганская обл.")}, + {39, 327, 0, TEXT("Львовская обл.")}, + {39, 328, 0, TEXT("Николаевская обл.")}, + {39, 329, 0, TEXT("Одесская обл.")}, + {39, 330, 0, TEXT("Полтавская обл.")}, + {39, 331, 0, TEXT("Ровенская обл.")}, + {39, 332, 0, TEXT("Сумская обл.")}, + {39, 333, 0, TEXT("Тернопольская обл.")}, + {39, 334, 0, TEXT("Харьковская обл.")}, + {39, 335, 0, TEXT("Херсонская обл.")}, + {39, 336, 0, TEXT("Хмельницкая обл.")}, + {39, 337, 0, TEXT("Черкасская обл.")}, + {39, 338, 0, TEXT("Черниговская обл.")}, + {39, 339, 0, TEXT("Черновицкая обл.")}, + {40, 602, 0, TEXT("Бад Халл")}, + {40, 604, 0, TEXT("Брегенц")}, + {40, 603, 0, TEXT("Вена")}, + {40, 608, 0, TEXT("Грац")}, + {40, 606, 0, TEXT("Зальцбург")}, + {40, 3099, 0, TEXT("Зель-ам-Зее")}, + {40, 605, 0, TEXT("Инсбрук")}, + {40, 3174, 0, TEXT("Кирхберг")}, + {40, 609, 0, TEXT("Клагенфурт")}, + {40, 607, 0, TEXT("Линц")}, + {40, 610, 0, TEXT("Обдах")}, + {40, 611, 0, TEXT("Щтубайтал")}, + {40, 2541, 0, lpwszOther}, + {32, 612, 0, TEXT("Тирана")}, + {32, 2540, 0, lpwszOther}, + {33, 613, 0, TEXT("Андорра-ла-Велья")}, + {33, 2539, 0, lpwszOther}, + {340, 341, 0, TEXT("Минск")}, + {340, 342, 0, TEXT("Брестская обл.")}, + {340, 343, 0, TEXT("Витебская обл.")}, + {340, 344, 0, TEXT("Гомельская обл.")}, + {340, 345, 0, TEXT("Гродненская обл.")}, + {340, 346, 0, TEXT("Минская обл.")}, + {340, 347, 0, TEXT("Могилевская обл.")}, + {38, 760, 0, TEXT("Антверпен")}, + {38, 767, 0, TEXT("Арлон")}, + {38, 762, 0, TEXT("Брюгге")}, + {38, 761, 0, TEXT("Брюссель")}, + {38, 763, 0, TEXT("Гент")}, + {38, 769, 0, TEXT("Лувен")}, + {38, 765, 0, TEXT("Льеж")}, + {38, 764, 0, TEXT("Монс")}, + {38, 3117, 0, TEXT("Мортсель")}, + {38, 766, 0, TEXT("Намюр")}, + {38, 768, 0, TEXT("Хасселт")}, + {38, 2532, 0, lpwszOther}, + {41, 3098, 0, TEXT("Банско")}, + {41, 792, 0, TEXT("Благоевград")}, + {41, 770, 0, TEXT("Бургас")}, + {41, 771, 0, TEXT("Бяла")}, + {41, 773, 0, TEXT("Варна")}, + {41, 776, 0, TEXT("Велико-Тырново")}, + {41, 788, 0, TEXT("Видин")}, + {41, 789, 0, TEXT("Враца")}, + {41, 796, 0, TEXT("Габрово")}, + {41, 777, 0, TEXT("Димитровград")}, + {41, 781, 0, TEXT("Каварна")}, + {41, 786, 0, TEXT("Кырджали")}, + {41, 791, 0, TEXT("Кюстендил")}, + {41, 793, 0, TEXT("Лазарджик")}, + {41, 795, 0, TEXT("Ловеч")}, + {41, 787, 0, TEXT("Михайловград")}, + {41, 790, 0, TEXT("Перник")}, + {41, 3133, 0, TEXT("Пирдоп")}, + {41, 794, 0, TEXT("Плевен")}, + {41, 782, 0, TEXT("Пловдив")}, + {41, 780, 0, TEXT("Разград")}, + {41, 779, 0, TEXT("Русе")}, + {41, 774, 0, TEXT("Силистра")}, + {41, 784, 0, TEXT("Сливен")}, + {41, 772, 0, TEXT("София")}, + {41, 775, 0, TEXT("Толбухин")}, + {41, 3116, 0, TEXT("Тырново")}, + {41, 785, 0, TEXT("Хасково")}, + {41, 778, 0, TEXT("Шумен")}, + {41, 783, 0, TEXT("Ямбол")}, + {41, 2531, 0, lpwszOther}, + {42, 797, 0, TEXT("Баня-Лука")}, + {42, 799, 0, TEXT("Зеница")}, + {42, 798, 0, TEXT("Сараево")}, + {42, 800, 0, TEXT("Тузла")}, + {42, 2530, 0, lpwszOther}, + {45, 802, 0, TEXT("Абердин")}, + {45, 3075, 0, TEXT("Айслворт")}, + {45, 801, 0, TEXT("Алнвик")}, + {45, 804, 0, TEXT("Бидефорд")}, + {45, 803, 0, TEXT("Бирмингем")}, + {45, 805, 0, TEXT("Блоксвич")}, + {45, 3168, 0, TEXT("Бостон")}, + {45, 806, 0, TEXT("Брайтон")}, + {45, 807, 0, TEXT("Бредфорд")}, + {45, 808, 0, TEXT("Бристоль")}, + {45, 809, 0, TEXT("Вилленхолл")}, + {45, 3131, 0, TEXT("Воррингтон")}, + {45, 810, 0, TEXT("Вудбридж")}, + {45, 3342, 0, TEXT("Гилфорд")}, + {45, 811, 0, TEXT("Глазго")}, + {45, 812, 0, TEXT("Дадли")}, + {45, 813, 0, TEXT("Дарем")}, + {45, 814, 0, TEXT("Дуглас")}, + {45, 3089, 0, TEXT("Кардиф")}, + {45, 815, 0, TEXT("Кембридж")}, + {45, 816, 0, TEXT("Кентербери")}, + {45, 817, 0, TEXT("Ливерпуль")}, + {45, 818, 0, TEXT("Лидс")}, + {45, 819, 0, TEXT("Лондон")}, + {45, 820, 0, TEXT("Манчестер")}, + {45, 2976, 0, TEXT("Митчем")}, + {45, 2988, 0, TEXT("Мэйденхед")}, + {45, 821, 0, TEXT("Ноттингем")}, + {45, 3088, 0, TEXT("Ньюпорт")}, + {45, 822, 0, TEXT("Оксфорд")}, + {45, 823, 0, TEXT("Плимут")}, + {45, 824, 0, TEXT("Портсмут")}, + {45, 825, 0, TEXT("Престон")}, + {45, 3343, 0, TEXT("Райд")}, + {45, 2867, 0, TEXT("Ридинг")}, + {45, 2986, 0, TEXT("Сент-Албанс")}, + {45, 826, 0, TEXT("Стаффорд")}, + {45, 3063, 0, TEXT("Стокпорт")}, + {45, 827, 0, TEXT("Уэймут")}, + {45, 3140, 0, TEXT("Челтенхэм")}, + {45, 828, 0, TEXT("Честер")}, + {45, 829, 0, TEXT("Шеффилд")}, + {45, 830, 0, TEXT("Эдинбург")}, + {45, 2529, 0, lpwszOther}, + {44, 831, 0, TEXT("Будапешт")}, + {44, 832, 0, TEXT("Геделле")}, + {44, 836, 0, TEXT("Дебрецен")}, + {44, 835, 0, TEXT("Мишкольц")}, + {44, 834, 0, TEXT("Сегед")}, + {44, 833, 0, TEXT("Шиофок")}, + {44, 2528, 0, lpwszOther}, + {46, 3007, 0, TEXT("Аахен")}, + {46, 837, 0, TEXT("Аугсбург")}, + {46, 838, 0, TEXT("Баден-Баден")}, + {46, 3371, 0, TEXT("Бамберг")}, + {46, 839, 0, TEXT("Бергиш-Гладбах")}, + {46, 840, 0, TEXT("Берлин")}, + {46, 841, 0, TEXT("Билефельд")}, + {46, 3163, 0, TEXT("Бовенден")}, + {46, 842, 0, TEXT("Бонн")}, + {46, 843, 0, TEXT("Браденбург")}, + {46, 3015, 0, TEXT("Брауншвейг")}, + {46, 844, 0, TEXT("Бремен")}, + {46, 2921, 0, TEXT("Варштайн")}, + {46, 845, 0, TEXT("Веймар")}, + {46, 846, 0, TEXT("Вупперталь")}, + {46, 847, 0, TEXT("Гамбург")}, + {46, 848, 0, TEXT("Ганновер")}, + {46, 849, 0, TEXT("Гарделеген")}, + {46, 3010, 0, TEXT("Гейдельберг")}, + {46, 850, 0, TEXT("Гота")}, + {46, 851, 0, TEXT("Дармштадт")}, + {46, 3072, 0, TEXT("Дессау")}, + {46, 852, 0, TEXT("Детмольд")}, + {46, 853, 0, TEXT("Дортмунд")}, + {46, 854, 0, TEXT("Дрезден")}, + {46, 855, 0, TEXT("Дюссельдорф")}, + {46, 3082, 0, TEXT("Иффецхайм")}, + {46, 3309, 0, TEXT("Кассел")}, + {46, 856, 0, TEXT("Кельн")}, + {46, 857, 0, TEXT("Киль")}, + {46, 3138, 0, TEXT("Кобленц")}, + {46, 858, 0, TEXT("Крефельд")}, + {46, 859, 0, TEXT("Лейпциг")}, + {46, 2872, 0, TEXT("Лимбург")}, + {46, 2965, 0, TEXT("Линген")}, + {46, 3135, 0, TEXT("Любек")}, + {46, 3156, 0, TEXT("Мангейм")}, + {46, 3192, 0, TEXT("Меерсбург")}, + {46, 860, 0, TEXT("Мюнстер")}, + {46, 861, 0, TEXT("Мюнхен")}, + {46, 2864, 0, TEXT("Нойштадт")}, + {46, 862, 0, TEXT("Нюрнберг")}, + {46, 3009, 0, TEXT("Оффенбург")}, + {46, 2993, 0, TEXT("Падерборн")}, + {46, 863, 0, TEXT("Равенсбург")}, + {46, 864, 0, TEXT("Регенсбург")}, + {46, 865, 0, TEXT("Рейнен")}, + {46, 866, 0, TEXT("Росток")}, + {46, 3191, 0, TEXT("Саарбрюкен")}, + {46, 2974, 0, TEXT("Санкт-Августин")}, + {46, 3127, 0, TEXT("Тюринген")}, + {46, 867, 0, TEXT("Фрайберг")}, + {46, 868, 0, TEXT("Фрайбург")}, + {46, 869, 0, TEXT("Франкфурт-на-Майне")}, + {46, 3373, 0, TEXT("Хемнитц")}, + {46, 3313, 0, TEXT("Хильден")}, + {46, 870, 0, TEXT("Штутгарт")}, + {46, 3045, 0, TEXT("Эрланген")}, + {46, 2906, 0, TEXT("Эшборн")}, + {46, 2527, 0, lpwszOther}, + {48, 871, 0, TEXT("Афины")}, + {48, 873, 0, TEXT("Ираклион")}, + {48, 3147, 0, TEXT("Корфу")}, + {48, 872, 0, TEXT("Салоники")}, + {48, 3178, 0, TEXT("Халкидики")}, + {48, 2526, 0, lpwszOther}, + {49, 3006, 0, TEXT("Архус")}, + {49, 874, 0, TEXT("Копенгаген")}, + {49, 875, 0, TEXT("Оденсе")}, + {49, 3285, 0, TEXT("Ольборг")}, + {49, 876, 0, TEXT("Сванеке")}, + {49, 3126, 0, TEXT("Скиве")}, + {49, 2525, 0, lpwszOther}, + {50, 3377, 0, TEXT("Виклоу")}, + {50, 3067, 0, TEXT("Голвей")}, + {50, 877, 0, TEXT("Дублин")}, + {50, 3065, 0, TEXT("Килларней")}, + {50, 3066, 0, TEXT("Корк")}, + {50, 878, 0, TEXT("Лимерик")}, + {50, 3069, 0, TEXT("Нейс")}, + {50, 3068, 0, TEXT("Типперэри")}, + {50, 2524, 0, lpwszOther}, + {51, 879, 0, TEXT("Рейкьявик")}, + {51, 2523, 0, lpwszOther}, + {34, 880, 0, TEXT("Аликанте")}, + {34, 3125, 0, TEXT("Альмерия")}, + {34, 881, 0, TEXT("Барселона")}, + {34, 890, 0, TEXT("Бильбао")}, + {34, 3076, 0, TEXT("Бланес")}, + {34, 882, 0, TEXT("Валенсия")}, + {34, 3070, 0, TEXT("Ибица")}, + {34, 888, 0, TEXT("Кадис")}, + {34, 886, 0, TEXT("Картахена")}, + {34, 891, 0, TEXT("Ла-Корунья")}, + {34, 3310, 0, TEXT("Лорет де Мар")}, + {34, 883, 0, TEXT("Мадрид")}, + {34, 884, 0, TEXT("Малага")}, + {34, 885, 0, TEXT("Марбелья")}, + {34, 892, 0, TEXT("Овьедо")}, + {34, 3179, 0, TEXT("Пальма де Майорка")}, + {34, 3177, 0, TEXT("Сан-Агустин")}, + {34, 3289, 0, TEXT("Санта-Крус-де-Тенерифе")}, + {34, 889, 0, TEXT("Сарагоса")}, + {34, 887, 0, TEXT("Севилья")}, + {34, 893, 0, TEXT("Хихон")}, + {34, 2522, 0, lpwszOther}, + {52, 3318, 0, TEXT("Аоста")}, + {52, 3278, 0, TEXT("Беллариа")}, + {52, 906, 0, TEXT("Болонья")}, + {52, 894, 0, TEXT("Брешиа")}, + {52, 895, 0, TEXT("Венеция")}, + {52, 905, 0, TEXT("Верона")}, + {52, 896, 0, TEXT("Генуя")}, + {52, 897, 0, TEXT("Лекко")}, + {52, 3369, 0, TEXT("Ливорно")}, + {52, 3327, 0, TEXT("Марсала")}, + {52, 898, 0, TEXT("Милан")}, + {52, 899, 0, TEXT("Модена")}, + {52, 907, 0, TEXT("Неаполь")}, + {52, 908, 0, TEXT("Перуджа")}, + {52, 900, 0, TEXT("Пиза")}, + {52, 901, 0, TEXT("Рим")}, + {52, 3368, 0, TEXT("Сан-Ремо")}, + {52, 3384, 0, TEXT("Сиракуза")}, + {52, 3252, 0, TEXT("Терамо")}, + {52, 902, 0, TEXT("Триест")}, + {52, 903, 0, TEXT("Турин")}, + {52, 3130, 0, TEXT("Фано")}, + {52, 904, 0, TEXT("Флоренция")}, + {52, 2521, 0, lpwszOther}, + {53, 2939, 0, TEXT("Айзкраукле")}, + {53, 3054, 0, TEXT("Валка")}, + {53, 909, 0, TEXT("Даугавпилс")}, + {53, 2934, 0, TEXT("Екабпилс")}, + {53, 913, 0, TEXT("Елгава")}, + {53, 2935, 0, TEXT("Кокнесе")}, + {53, 912, 0, TEXT("Лиепая")}, + {53, 2905, 0, TEXT("Резекне")}, + {53, 911, 0, TEXT("Рига")}, + {53, 2936, 0, TEXT("Саласпилс")}, + {53, 2937, 0, TEXT("Смилтене")}, + {53, 910, 0, TEXT("Юрмала")}, + {53, 2520, 0, lpwszOther}, + {54, 914, 0, TEXT("Вильнюс")}, + {54, 915, 0, TEXT("Висагинас")}, + {54, 916, 0, TEXT("Каунас")}, + {54, 918, 0, TEXT("Клайпеда")}, + {54, 919, 0, TEXT("Паланга")}, + {54, 3173, 0, TEXT("Пеневежис")}, + {54, 917, 0, TEXT("Шауляй")}, + {54, 2519, 0, lpwszOther}, + {55, 920, 0, TEXT("Вадуц")}, + {55, 2518, 0, lpwszOther}, + {56, 3376, 0, TEXT("Бетцдорф")}, + {56, 921, 0, TEXT("Люксембург")}, + {56, 2517, 0, lpwszOther}, + {57, 3142, 0, TEXT("Битола")}, + {57, 922, 0, TEXT("Скопье")}, + {57, 2516, 0, lpwszOther}, + {58, 923, 0, TEXT("Валлетта")}, + {58, 3154, 0, TEXT("Мзида")}, + {58, 924, 0, TEXT("Слима")}, + {58, 2515, 0, lpwszOther}, + {59, 925, 0, TEXT("Бельцы")}, + {59, 926, 0, TEXT("Бендеры")}, + {59, 3234, 0, TEXT("Дубоссары")}, + {59, 3275, 0, TEXT("Кахул")}, + {59, 927, 0, TEXT("Кишинев")}, + {59, 3321, 0, TEXT("Резина")}, + {59, 928, 0, TEXT("Рыбница")}, + {59, 929, 0, TEXT("Тирасполь")}, + {59, 3281, 0, TEXT("Чадыр-Лунга")}, + {59, 2514, 0, lpwszOther}, + {36, 930, 0, TEXT("Монте-Карло")}, + {36, 2513, 0, lpwszOther}, + {60, 931, 0, TEXT("Амстердам")}, + {60, 933, 0, TEXT("Бреда")}, + {60, 932, 0, TEXT("Гаага")}, + {60, 934, 0, TEXT("Гауда")}, + {60, 935, 0, TEXT("Делфт")}, + {60, 2977, 0, TEXT("Донген")}, + {60, 3030, 0, TEXT("Зволле")}, + {60, 3091, 0, TEXT("Ниймеген")}, + {60, 936, 0, TEXT("Роттердам")}, + {60, 937, 0, TEXT("Утрехт")}, + {60, 3044, 0, TEXT("Эйндховен")}, + {60, 3380, 0, TEXT("Эншеде")}, + {60, 2512, 0, lpwszOther}, + {61, 3190, 0, TEXT("Кристиансанд")}, + {61, 2857, 0, TEXT("Лиллехаммер")}, + {61, 938, 0, TEXT("Осло")}, + {61, 3355, 0, TEXT("Ставангер")}, + {61, 939, 0, TEXT("Тронхейм")}, + {61, 2511, 0, lpwszOther}, + {62, 940, 0, TEXT("Белосток")}, + {62, 941, 0, TEXT("Варшава")}, + {62, 3164, 0, TEXT("Вроцлав")}, + {62, 942, 0, TEXT("Гданьск")}, + {62, 943, 0, TEXT("Гливице")}, + {62, 3237, 0, TEXT("Закопане")}, + {62, 3165, 0, TEXT("Зелена Гура")}, + {62, 944, 0, TEXT("Катовице")}, + {62, 945, 0, TEXT("Краков")}, + {62, 3008, 0, TEXT("Лодзь")}, + {62, 3150, 0, TEXT("Ольштын")}, + {62, 946, 0, TEXT("Познань")}, + {62, 947, 0, TEXT("Радом")}, + {62, 948, 0, TEXT("Сопот")}, + {62, 2958, 0, TEXT("Тыхы")}, + {62, 2510, 0, lpwszOther}, + {35, 949, 0, TEXT("Лиссабон")}, + {35, 950, 0, TEXT("Порто")}, + {35, 2509, 0, lpwszOther}, + {63, 952, 0, TEXT("Брашов")}, + {63, 951, 0, TEXT("Бухарест")}, + {63, 954, 0, TEXT("Констанца")}, + {63, 955, 0, TEXT("Плоешти")}, + {63, 953, 0, TEXT("Яссы")}, + {63, 2508, 0, lpwszOther}, + {64, 956, 0, TEXT("Сан-Марино")}, + {64, 2507, 0, lpwszOther}, + {74, 957, 0, TEXT("Белград")}, + {74, 960, 0, TEXT("Ниш")}, + {74, 958, 0, TEXT("Нови-Сад")}, + {74, 959, 0, TEXT("Сараево")}, + {74, 2506, 0, lpwszOther}, + {65, 961, 0, TEXT("Братислава")}, + {65, 962, 0, TEXT("Кошице")}, + {65, 3101, 0, TEXT("Липтов")}, + {65, 963, 0, TEXT("Попрад")}, + {65, 964, 0, TEXT("Прешов")}, + {65, 965, 0, TEXT("Ружемберок")}, + {65, 966, 0, TEXT("Тврдошин")}, + {65, 2505, 0, lpwszOther}, + {66, 968, 0, TEXT("Копар")}, + {66, 967, 0, TEXT("Любляна")}, + {66, 969, 0, TEXT("Марибор")}, + {66, 2504, 0, lpwszOther}, + {67, 970, 0, TEXT("Торсхавн")}, + {67, 2503, 0, lpwszOther}, + {68, 2888, 0, TEXT("Вантаа")}, + {68, 971, 0, TEXT("Васа")}, + {68, 979, 0, TEXT("Котка")}, + {68, 972, 0, TEXT("Коувола")}, + {68, 980, 0, TEXT("Лахти")}, + {68, 973, 0, TEXT("Оулу")}, + {68, 3375, 0, TEXT("Риихимяки")}, + {68, 3159, 0, TEXT("Руовеси")}, + {68, 974, 0, TEXT("Тампере")}, + {68, 975, 0, TEXT("Турку")}, + {68, 976, 0, TEXT("Хельсинки")}, + {68, 977, 0, TEXT("Эспо")}, + {68, 978, 0, TEXT("Ювяскюля")}, + {68, 2502, 0, lpwszOther}, + {37, 996, 0, TEXT("Авиньон")}, + {37, 983, 0, TEXT("Бержерак")}, + {37, 997, 0, TEXT("Блуа")}, + {37, 984, 0, TEXT("Бордо")}, + {37, 998, 0, TEXT("Дижон")}, + {37, 987, 0, TEXT("Канн")}, + {37, 988, 0, TEXT("Кастр")}, + {37, 993, 0, TEXT("Клермон-Ферран")}, + {37, 3037, 0, TEXT("Лилль")}, + {37, 989, 0, TEXT("Лион")}, + {37, 985, 0, TEXT("Марсель")}, + {37, 991, 0, TEXT("Мец")}, + {37, 3161, 0, TEXT("Мобеж")}, + {37, 990, 0, TEXT("Нанси")}, + {37, 994, 0, TEXT("Нант")}, + {37, 995, 0, TEXT("Ницца")}, + {37, 999, 0, TEXT("Орлеан")}, + {37, 981, 0, TEXT("Париж")}, + {37, 3374, 0, TEXT("Перпиньян")}, + {37, 992, 0, TEXT("Руан")}, + {37, 982, 0, TEXT("Страсбург")}, + {37, 986, 0, TEXT("Тулуза")}, + {37, 3314, 0, TEXT("Шамбери")}, + {37, 2501, 0, lpwszOther}, + {69, 1003, 0, TEXT("Дубровник")}, + {69, 1000, 0, TEXT("Загреб")}, + {69, 1001, 0, TEXT("Задар")}, + {69, 1004, 0, TEXT("Риека")}, + {69, 1002, 0, TEXT("Сплит")}, + {69, 2500, 0, lpwszOther}, + {70, 1005, 0, TEXT("Брно")}, + {70, 3291, 0, TEXT("Гавличкув-Брод")}, + {70, 1007, 0, TEXT("Градец-Кралове")}, + {70, 1008, 0, TEXT("Карлови-Вари")}, + {70, 3019, 0, TEXT("Кладрубы")}, + {70, 1010, 0, TEXT("Лоуни")}, + {70, 1009, 0, TEXT("Острава")}, + {70, 1015, 0, TEXT("Пльзень")}, + {70, 3105, 0, TEXT("Правчицка Брана")}, + {70, 1006, 0, TEXT("Прага")}, + {70, 3246, 0, TEXT("Тачов")}, + {70, 1011, 0, TEXT("Тршебич")}, + {70, 1012, 0, TEXT("Усти-над-Лабем")}, + {70, 1014, 0, TEXT("Ческе-Будеевице")}, + {70, 1013, 0, TEXT("Яблонец-над-Нисоу")}, + {70, 2499, 0, lpwszOther}, + {71, 1016, 0, TEXT("Арау")}, + {71, 1019, 0, TEXT("Баден")}, + {71, 1017, 0, TEXT("Базель")}, + {71, 1018, 0, TEXT("Берн")}, + {71, 1020, 0, TEXT("Биль")}, + {71, 1021, 0, TEXT("Винтертур")}, + {71, 1022, 0, TEXT("Давос")}, + {71, 3189, 0, TEXT("Делемонт")}, + {71, 1023, 0, TEXT("Женева")}, + {71, 1024, 0, TEXT("Золотурн")}, + {71, 1025, 0, TEXT("Лозанна")}, + {71, 1026, 0, TEXT("Локарно")}, + {71, 1027, 0, TEXT("Лугано")}, + {71, 1028, 0, TEXT("Люцерн")}, + {71, 1029, 0, TEXT("Монтре")}, + {71, 1030, 0, TEXT("Цюрих")}, + {71, 2498, 0, lpwszOther}, + {72, 2883, 0, TEXT("Арбога")}, + {72, 1031, 0, TEXT("Гетеборг")}, + {72, 1032, 0, TEXT("Кальмар")}, + {72, 1037, 0, TEXT("Лахольм")}, + {72, 1036, 0, TEXT("Лулео")}, + {72, 1042, 0, TEXT("Лунд")}, + {72, 1033, 0, TEXT("Мальме")}, + {72, 1034, 0, TEXT("Стокгольм")}, + {72, 1041, 0, TEXT("Умео")}, + {72, 1039, 0, TEXT("Фалун")}, + {72, 1043, 0, TEXT("Хельсинборг")}, + {72, 1040, 0, TEXT("Хернесанд")}, + {72, 1038, 0, TEXT("Эстерсунд")}, + {72, 2497, 0, lpwszOther}, + {73, 3013, 0, TEXT("Валга")}, + {73, 1044, 0, TEXT("Кейла")}, + {73, 1045, 0, TEXT("Кохтла-Ярве")}, + {73, 1046, 0, TEXT("Маарду")}, + {73, 1047, 0, TEXT("Мыйзакюла")}, + {73, 1048, 0, TEXT("Нарва")}, + {73, 1049, 0, TEXT("Пярну")}, + {73, 1050, 0, TEXT("Раквере")}, + {73, 1051, 0, TEXT("Силламяэ")}, + {73, 1052, 0, TEXT("Таллин")}, + {73, 1053, 0, TEXT("Тарту")}, + {73, 1054, 0, TEXT("Хаапсалу")}, + {0, 0, 0, NULL} +};//*/ + +/* +static const MRA_COUNTRY mracCountrys[] = +{ + {24, TEXT("Россия")}, + {81, TEXT("Азербайджан")}, + {82, TEXT("Армения")}, + {97, TEXT("Афганистан")}, + {96, TEXT("Бангладеш")}, + {99, TEXT("Бахрейн")}, + {100, TEXT("Бруней-Даруссалам")}, + {101, TEXT("Бутан")}, + {102, TEXT("Вьетнам")}, + {83, TEXT("Грузия")}, + {86, TEXT("Израиль")}, + {95, TEXT("Индия")}, + {103, TEXT("Индонезия")}, + {79, TEXT("Иордания")}, + {85, TEXT("Ирак")}, + {87, TEXT("Иран")}, + {104, TEXT("Йемен")}, + {84, TEXT("Казахстан")}, + {105, TEXT("Камбоджа")}, + {106, TEXT("Катар")}, + {107, TEXT("Кипр")}, + {92, TEXT("Киргизия (Кыргызстан)")}, + {76, TEXT("Китай")}, + {3215, TEXT("Кокосовые острова (Австр.)")}, + {29, TEXT("Корея (КНДР)")}, + {108, TEXT("Корея")}, + {88, TEXT("Кувейт")}, + {109, TEXT("Лаос")}, + {110, TEXT("Ливан")}, + {111, TEXT("Малайзия")}, + {112, TEXT("Мальдивы")}, + {113, TEXT("Монголия")}, + {114, TEXT("Мьянма")}, + {115, TEXT("Непал")}, + {116, TEXT("Объединенные Арабские Эмираты")}, + {117, TEXT("Оман")}, + {3216, TEXT("Остров Рождества (Австр.)")}, + {122, TEXT("Пакистан")}, + {89, TEXT("Палестина")}, + {94, TEXT("Саудовская Аравия")}, + {118, TEXT("Сингапур")}, + {78, TEXT("Сирия")}, + {91, TEXT("Таджикистан")}, + {119, TEXT("Таиланд")}, + {120, TEXT("Тайвань")}, + {132, TEXT("Тимор")}, + {90, TEXT("Туркмения")}, + {77, TEXT("Турция")}, + {93, TEXT("Узбекистан")}, + {121, TEXT("Филиппины")}, + {98, TEXT("Шри Ланка")}, + {75, TEXT("Япония")}, + {123, TEXT("Австралия")}, + {454, TEXT("Американское Самоа")}, + {124, TEXT("Вануату")}, + {453, TEXT("Гуам (США)")}, + {126, TEXT("Кирибати")}, + {127, TEXT("Маршалловы Острова")}, + {128, TEXT("Микронезия (Федеративные Штаты Микронезии)")}, + {129, TEXT("Науру")}, + {3220, TEXT("Ниуэ (Н.Зел.)")}, + {130, TEXT("Новая Зеландия")}, + {3218, TEXT("Новая Каледония (Фр.)")}, + {3221, TEXT("Острова Кука (Н.Зел.)")}, + {3230, TEXT("Острова Херд и Макдональд (Австр.)")}, + {131, TEXT("Палау")}, + {133, TEXT("Папуа - Новая Гвинея")}, + {3222, TEXT("Питкерн (Брит.)")}, + {125, TEXT("Самоа")}, + {3219, TEXT("Сев. Марианские острова (США)")}, + {134, TEXT("Соломоновы Острова")}, + {3223, TEXT("Токелау (Н.Зел.)")}, + {135, TEXT("Тонга")}, + {136, TEXT("Тувалу")}, + {3224, TEXT("Уоллис и Футуна острова (Фр.)")}, + {137, TEXT("Фиджи")}, + {3226, TEXT("Французская Полинезия")}, + {3225, TEXT("Французские Южные территории")}, + {138, TEXT("Канада")}, + {139, TEXT("США")}, + {3200, TEXT("Ангилья (Брит.)")}, + {140, TEXT("Антигуа и Барбуда")}, + {141, TEXT("Аргентина")}, + {3202, TEXT("Аруба (Нид.)")}, + {142, TEXT("Багамы")}, + {143, TEXT("Барбадос")}, + {146, TEXT("Белиз")}, + {3203, TEXT("Бермуды (Брит.)")}, + {144, TEXT("Боливия")}, + {145, TEXT("Бразилия")}, + {147, TEXT("Венесуэла")}, + {3204, TEXT("Виргинские острова (Брит.)")}, + {452, TEXT("Виргинские острова (США)")}, + {149, TEXT("Гаити")}, + {148, TEXT("Гайана")}, + {3205, TEXT("Гваделупа (Фр.)")}, + {173, TEXT("Гватемала")}, + {150, TEXT("Гондурас")}, + {151, TEXT("Гренада")}, + {152, TEXT("Гренландия (Дат.)")}, + {153, TEXT("Доминика")}, + {154, TEXT("Доминиканская Республика")}, + {155, TEXT("Колумбия")}, + {156, TEXT("Коста-Рика")}, + {157, TEXT("Куба")}, + {3208, TEXT("Мартиника (Фр.)")}, + {158, TEXT("Мексика")}, + {3209, TEXT("Монтсеррат (Брит)")}, + {3201, TEXT("Нидерландские Антилы")}, + {159, TEXT("Никарагуа")}, + {3207, TEXT("Остров Кайман (Брит.)")}, + {3211, TEXT("Острова Теркс и Кайкос (Брит.)")}, + {160, TEXT("Панама")}, + {161, TEXT("Парагвай")}, + {162, TEXT("Перу")}, + {163, TEXT("Сальвадор")}, + {164, TEXT("Сент-Винсент и Гренадины")}, + {165, TEXT("Сент-Китс и Невис")}, + {166, TEXT("Сент-Люсия")}, + {3210, TEXT("Сент-Пьер и Микелон (Фр.)")}, + {167, TEXT("Суринам")}, + {168, TEXT("Тринидат и Тобаго")}, + {169, TEXT("Уругвай")}, + {3212, TEXT("Фолклендские острова (Брит.)")}, + {3206, TEXT("Французская Гвиана")}, + {170, TEXT("Чили")}, + {171, TEXT("Эквадор")}, + {3213, TEXT("Юж. Джорджия и Юж. Сандвичевы о-ва (Брит.)")}, + {172, TEXT("Ямайка")}, + {174, TEXT("Алжир")}, + {175, TEXT("Ангола")}, + {176, TEXT("Бенин")}, + {177, TEXT("Ботсвана")}, + {3228, TEXT("Британская территория в Индийском океане")}, + {178, TEXT("Буркина-Фасо")}, + {179, TEXT("Бурунди")}, + {180, TEXT("Габон")}, + {181, TEXT("Гамбия")}, + {182, TEXT("Гана")}, + {183, TEXT("Гвинея")}, + {184, TEXT("Гвинея-Бисау")}, + {185, TEXT("Джибути")}, + {186, TEXT("Египет")}, + {187, TEXT("Замбия")}, + {3198, TEXT("Зап. Сахара")}, + {23, TEXT("Зимбабве")}, + {188, TEXT("Кабо-Верде")}, + {189, TEXT("Камерун")}, + {190, TEXT("Кения")}, + {191, TEXT("Коморы")}, + {193, TEXT("Конго (Заир)")}, + {192, TEXT("Конго")}, + {194, TEXT("Кот-д`Ивуар")}, + {195, TEXT("Лесото")}, + {196, TEXT("Либерия")}, + {197, TEXT("Ливия")}, + {198, TEXT("Маврикий")}, + {199, TEXT("Мавритания")}, + {200, TEXT("Мадагаскар")}, + {3229, TEXT("Майотт (Фр.)")}, + {201, TEXT("Малави")}, + {202, TEXT("Мали")}, + {203, TEXT("Марокко")}, + {204, TEXT("Мозамбик")}, + {205, TEXT("Намибия")}, + {206, TEXT("Нигер")}, + {207, TEXT("Нигерия")}, + {3227, TEXT("Остров Буве (Норв.)")}, + {3197, TEXT("Реюньон (Фр.)")}, + {208, TEXT("Руанда")}, + {209, TEXT("Сан-Томе и Принсипи")}, + {210, TEXT("Свазиленд")}, + {3199, TEXT("Святая Елена (Брит.)")}, + {211, TEXT("Сейшелы")}, + {212, TEXT("Сенегал")}, + {213, TEXT("Сомали")}, + {214, TEXT("Судан")}, + {215, TEXT("Сьерра-Леоне")}, + {216, TEXT("Танзания")}, + {217, TEXT("Того")}, + {218, TEXT("Тунис")}, + {219, TEXT("Уганда")}, + {220, TEXT("Центральноафриканская Республика")}, + {222, TEXT("Чад")}, + {223, TEXT("Экваториальная Гвинея")}, + {221, TEXT("Эритрея")}, + {224, TEXT("Эфиопия")}, + {225, TEXT("Южно-Африканская Республика (ЮАР)")}, + {39, TEXT("Украина")}, + {40, TEXT("Австрия")}, + {32, TEXT("Албания")}, + {33, TEXT("Андорра")}, + {340, TEXT("Белоруссия")}, + {38, TEXT("Бельгия")}, + {41, TEXT("Болгария")}, + {42, TEXT("Босния и Герцеговина")}, + {43, TEXT("Ватикан")}, + {45, TEXT("Великобритания")}, + {44, TEXT("Венгрия")}, + {46, TEXT("Германия")}, + {3193, TEXT("Гернси (Брит.)")}, + {47, TEXT("Гибралтар (Брит.)")}, + {48, TEXT("Греция")}, + {49, TEXT("Дания")}, + {3194, TEXT("Джерси (Брит.)")}, + {50, TEXT("Ирландия")}, + {51, TEXT("Исландия")}, + {34, TEXT("Испания")}, + {52, TEXT("Италия")}, + {53, TEXT("Латвия")}, + {54, TEXT("Литва")}, + {55, TEXT("Лихтенштейн")}, + {56, TEXT("Люксембург")}, + {57, TEXT("Македония")}, + {58, TEXT("Мальта")}, + {59, TEXT("Молдавия")}, + {36, TEXT("Монако")}, + {60, TEXT("Нидерланды")}, + {61, TEXT("Норвегия")}, + {3195, TEXT("Остров Мэн (Брит.)")}, + {62, TEXT("Польша")}, + {35, TEXT("Португалия")}, + {63, TEXT("Румыния")}, + {64, TEXT("Сан-Марино")}, + {74, TEXT("Сербия и Черногория")}, + {65, TEXT("Словакия")}, + {66, TEXT("Словения")}, + {67, TEXT("Фарерские о-ва (Дания)")}, + {68, TEXT("Финляндия")}, + {37, TEXT("Франция")}, + {69, TEXT("Хорватия")}, + {70, TEXT("Чехия")}, + {71, TEXT("Швейцария")}, + {72, TEXT("Швеция")}, + {3196, TEXT("Шпицберген (Норв.)")}, + {73, TEXT("Эстония")}, + {0, NULL} +}; + + + +static const MRA_CITY mracCitys[] = +{ + {24, 25, TEXT("Москва")}, + {24, 226, TEXT("Санкт-Петербург")}, + {24, 233, TEXT("Саха (Якутия)")}, + {24, 232, TEXT("Приморский край")}, + {24, 235, TEXT("Хабаровский край")}, + {24, 227, TEXT("Амурская обл.")}, + {24, 229, TEXT("Камчатская обл.")}, + {24, 231, TEXT("Магаданская обл.")}, + {24, 234, TEXT("Сахалинская обл.")}, + {24, 228, TEXT("Еврейская АО")}, + {24, 230, TEXT("Корякский АО")}, + {24, 236, TEXT("Чукотский АО")}, + {24, 237, TEXT("Башкортостан")}, + {24, 240, TEXT("Марий-Эл")}, + {24, 241, TEXT("Мордовия")}, + {24, 248, TEXT("Татарстан")}, + {24, 249, TEXT("Удмуртия")}, + {24, 251, TEXT("Чувашия")}, + {24, 238, TEXT("Кировская обл.")}, + {24, 242, TEXT("Нижегородская обл.")}, + {24, 243, TEXT("Оренбургская обл.")}, + {24, 244, TEXT("Пензенская обл.")}, + {24, 245, TEXT("Пермская обл.")}, + {24, 246, TEXT("Самарская обл.")}, + {24, 247, TEXT("Саратовская обл.")}, + {24, 250, TEXT("Ульяновская обл.")}, + {24, 239, TEXT("Коми-Пермяцкий АО")}, + {24, 255, TEXT("Карелия")}, + {24, 256, TEXT("Коми")}, + {24, 252, TEXT("Архангельская обл.")}, + {24, 253, TEXT("Вологодская обл.")}, + {24, 254, TEXT("Калининградская обл.")}, + {24, 257, TEXT("Ленинградская обл.")}, + {24, 258, TEXT("Мурманская обл.")}, + {24, 260, TEXT("Новгородская обл.")}, + {24, 261, TEXT("Псковская обл.")}, + {24, 259, TEXT("Ненецкий АО")}, + {24, 265, TEXT("Бурятия")}, + {24, 263, TEXT("Республика Алтай")}, + {24, 273, TEXT("Тыва")}, + {24, 275, TEXT("Хакасия")}, + {24, 264, TEXT("Алтайский край")}, + {24, 268, TEXT("Красноярский край")}, + {24, 266, TEXT("Иркутская обл.")}, + {24, 267, TEXT("Кемеровская обл.")}, + {24, 269, TEXT("Новосибирская обл.")}, + {24, 270, TEXT("Омская обл.")}, + {24, 272, TEXT("Томская обл.")}, + {24, 276, TEXT("Читинская обл.")}, + {24, 262, TEXT("Агинский Бурятский АО")}, + {24, 271, TEXT("Таймырский АО")}, + {24, 274, TEXT("Усть-Ордынский Бурятский АО")}, + {24, 277, TEXT("Эвенкийский АО")}, + {24, 278, TEXT("Курганская обл.")}, + {24, 279, TEXT("Свердловская обл.")}, + {24, 280, TEXT("Тюменская обл.")}, + {24, 282, TEXT("Челябинская обл.")}, + {24, 281, TEXT("Ханты-Мансийский АО - Югра")}, + {24, 283, TEXT("Ямало-Ненецкий АО")}, + {24, 284, TEXT("Белгородская обл.")}, + {24, 285, TEXT("Брянская обл.")}, + {24, 286, TEXT("Владимирская обл.")}, + {24, 287, TEXT("Воронежская обл.")}, + {24, 288, TEXT("Ивановская обл.")}, + {24, 289, TEXT("Калужская обл.")}, + {24, 290, TEXT("Костромская обл.")}, + {24, 291, TEXT("Курская обл.")}, + {24, 292, TEXT("Липецкая обл.")}, + {24, 293, TEXT("Московская обл.")}, + {24, 294, TEXT("Орловская обл.")}, + {24, 295, TEXT("Рязанская обл.")}, + {24, 296, TEXT("Смоленская обл.")}, + {24, 297, TEXT("Тамбовская обл.")}, + {24, 298, TEXT("Тверская обл.")}, + {24, 299, TEXT("Тульская обл.")}, + {24, 300, TEXT("Ярославская обл.")}, + {24, 301, TEXT("Адыгея")}, + {24, 304, TEXT("Дагестан")}, + {24, 305, TEXT("Ингушетия")}, + {24, 306, TEXT("Кабардино-Балкария")}, + {24, 307, TEXT("Калмыкия")}, + {24, 308, TEXT("Карачаево-Черкессия")}, + {24, 311, TEXT("Северная Осетия - Алания")}, + {24, 313, TEXT("Чечня")}, + {24, 309, TEXT("Краснодарский край")}, + {24, 312, TEXT("Ставропольский край")}, + {24, 302, TEXT("Астраханская обл.")}, + {24, 303, TEXT("Волгоградская обл.")}, + {24, 310, TEXT("Ростовская обл.")}, + {81, 1055, TEXT("Баку")}, + {81, 1058, TEXT("Гянджа")}, + {81, 1056, TEXT("Нахичевань")}, + {81, 1057, TEXT("Ханкенди")}, + {81, 3153, TEXT("Шеки")}, + {81, 2291, lpwszOther}, + {82, 2932, TEXT("Абовян")}, + {82, 1060, TEXT("Аштарак")}, + {82, 3084, TEXT("Ванадзор")}, + {82, 3011, TEXT("Гюмри")}, + {82, 3306, TEXT("Дилижан")}, + {82, 1059, TEXT("Ереван")}, + {82, 3145, TEXT("Ханкенди")}, + {82, 2292, lpwszOther}, + {97, 1061, TEXT("Кабул")}, + {97, 2293, lpwszOther}, + {96, 1062, TEXT("Дакка")}, + {96, 2294, lpwszOther}, + {99, 1063, TEXT("Манама")}, + {99, 2295, lpwszOther}, + {100, 1064, TEXT("Бандар-Сери-Бегаван")}, + {100, 2296, lpwszOther}, + {101, 1065, TEXT("Тхимпху")}, + {101, 2297, lpwszOther}, + {102, 1066, TEXT("Ханой")}, + {102, 2298, lpwszOther}, + {83, 1067, TEXT("Батуми")}, + {83, 3158, TEXT("Боржоми")}, + {83, 1068, TEXT("Поти")}, + {83, 3129, TEXT("Рустави")}, + {83, 1069, TEXT("Сухуми")}, + {83, 1070, TEXT("Тбилиси")}, + {83, 2299, lpwszOther}, + {86, 3345, TEXT("Ариэль")}, + {86, 1071, TEXT("Афула")}, + {86, 2992, TEXT("Ашдод")}, + {86, 3175, TEXT("Ашкелон")}, + {86, 3363, TEXT("Бат-Ям")}, + {86, 2884, TEXT("Беер-Яков")}, + {86, 3243, TEXT("Бейт-Шемеш")}, + {86, 1074, TEXT("Беэр-Шева")}, + {86, 3348, TEXT("Герцелия")}, + {86, 3241, TEXT("Димона")}, + {86, 1075, TEXT("Иерусалим")}, + {86, 3350, TEXT("Йокнеам-Иллит")}, + {86, 2982, TEXT("Кармиэль")}, + {86, 2971, TEXT("Кфар-Саба")}, + {86, 3136, TEXT("Назарет")}, + {86, 1080, TEXT("Натания")}, + {86, 3303, TEXT("Офаким")}, + {86, 3050, TEXT("Раанана")}, + {86, 3151, TEXT("Рамат Ган")}, + {86, 3141, TEXT("Реховот")}, + {86, 3012, TEXT("Ришон ле Цион")}, + {86, 1081, TEXT("Тверия")}, + {86, 1077, TEXT("Тель-Авив")}, + {86, 1079, TEXT("Хадера")}, + {86, 1078, TEXT("Хайфа")}, + {86, 1076, TEXT("Хеврон")}, + {86, 2929, TEXT("Цфат")}, + {86, 2928, TEXT("Эйлат")}, + {86, 2300, lpwszOther}, + {95, 3315, TEXT("Бангалор")}, + {95, 1082, TEXT("Дели")}, + {95, 1083, TEXT("Джайпур")}, + {95, 3144, TEXT("Калькутта")}, + {95, 3025, TEXT("Мумбаи")}, + {95, 3277, TEXT("Панаджи")}, + {95, 1084, TEXT("Ченнаи")}, + {95, 2301, lpwszOther}, + {103, 1085, TEXT("Джакарта")}, + {103, 2302, lpwszOther}, + {79, 1086, TEXT("Амман")}, + {79, 2303, lpwszOther}, + {85, 1087, TEXT("Багдад")}, + {85, 2304, lpwszOther}, + {87, 1088, TEXT("Тегеран")}, + {87, 2305, lpwszOther}, + {104, 1089, TEXT("Сана")}, + {104, 2306, lpwszOther}, + {84, 1090, TEXT("Актау")}, + {84, 1091, TEXT("Актюбинск")}, + {84, 1092, TEXT("Алма-Ата")}, + {84, 3242, TEXT("Аршалы")}, + {84, 1093, TEXT("Астана")}, + {84, 1094, TEXT("Атырау (Гурьев)")}, + {84, 1095, TEXT("Байконур")}, + {84, 3245, TEXT("Балхаш")}, + {84, 3083, TEXT("Жезказган")}, + {84, 1096, TEXT("Капчагай")}, + {84, 1097, TEXT("Караганда")}, + {84, 1098, TEXT("Кокшетау")}, + {84, 1099, TEXT("Кустанай")}, + {84, 2868, TEXT("Лисаковск")}, + {84, 1100, TEXT("Павлодар")}, + {84, 1101, TEXT("Петропавловск (Сев.-Каз. обл.)")}, + {84, 1102, TEXT("Рудный")}, + {84, 1103, TEXT("Семипалатинск")}, + {84, 1104, TEXT("Степногорск")}, + {84, 3166, TEXT("Талгар")}, + {84, 1105, TEXT("Талды-Курган")}, + {84, 2927, TEXT("Тараз")}, + {84, 1106, TEXT("Темиртау")}, + {84, 1107, TEXT("Уральск")}, + {84, 1108, TEXT("Усть-Каменогорск")}, + {84, 1109, TEXT("Чимкент")}, + {84, 1110, TEXT("Экибастуз")}, + {84, 2307, lpwszOther}, + {105, 1111, TEXT("Пномпень")}, + {105, 2308, lpwszOther}, + {106, 1112, TEXT("Доха")}, + {106, 2309, lpwszOther}, + {107, 1113, TEXT("Ларнака")}, + {107, 1114, TEXT("Лимассол")}, + {107, 1115, TEXT("Никосия")}, + {107, 2954, TEXT("Пафос")}, + {107, 2310, lpwszOther}, + {92, 1116, TEXT("Бишкек")}, + {92, 1117, TEXT("Джалал-Абад")}, + {92, 3027, TEXT("Кара-Балта")}, + {92, 1118, TEXT("Каракол")}, + {92, 1119, TEXT("Ош")}, + {92, 1120, TEXT("Талас")}, + {92, 2933, TEXT("Хайдаркен")}, + {92, 2311, lpwszOther}, + {76, 3214, TEXT("Аомынь (Макао)")}, + {76, 1121, TEXT("Гонконг")}, + {76, 2869, TEXT("Гуанчжоу")}, + {76, 3262, TEXT("Далянь")}, + {76, 1122, TEXT("Пекин")}, + {76, 1123, TEXT("Харбин")}, + {76, 1124, TEXT("Шанхай")}, + {76, 3043, TEXT("Шеньян")}, + {76, 2312, lpwszOther}, + {29, 1125, TEXT("Пхеньян")}, + {29, 2313, lpwszOther}, + {108, 1126, TEXT("Сеул")}, + {108, 3240, TEXT("Тейджон")}, + {108, 2314, lpwszOther}, + {88, 1127, TEXT("Эль-Кувейт")}, + {88, 2315, lpwszOther}, + {109, 1128, TEXT("Вьентьян")}, + {109, 2316, lpwszOther}, + {110, 1129, TEXT("Бейрут")}, + {110, 2317, lpwszOther}, + {111, 1130, TEXT("Джохор-Бару")}, + {111, 1131, TEXT("Куала-Лумпур")}, + {111, 2318, lpwszOther}, + {112, 1132, TEXT("Мале")}, + {112, 2319, lpwszOther}, + {113, 1133, TEXT("Улан-Батор")}, + {113, 1134, TEXT("Эрдэнэт")}, + {113, 2320, lpwszOther}, + {114, 1135, TEXT("Янгон")}, + {114, 2321, lpwszOther}, + {115, 1136, TEXT("Катманду")}, + {115, 2322, lpwszOther}, + {116, 1137, TEXT("Абу-Даби")}, + {116, 1138, TEXT("Дубай")}, + {116, 1139, TEXT("Шарджа")}, + {116, 2323, lpwszOther}, + {117, 1140, TEXT("Маскат")}, + {117, 2324, lpwszOther}, + {122, 1141, TEXT("Исламабад")}, + {122, 2325, lpwszOther}, + {89, 1072, TEXT("Ашдод")}, + {89, 1073, TEXT("Ашкелон")}, + {89, 1142, TEXT("Газа")}, + {89, 2326, lpwszOther}, + {94, 3250, TEXT("Медина")}, + {94, 1143, TEXT("Эр-Рияд")}, + {94, 2327, lpwszOther}, + {78, 1144, TEXT("Дамаск")}, + {78, 2328, lpwszOther}, + {91, 1145, TEXT("Душанбе")}, + {91, 3307, TEXT("Кайраккум")}, + {91, 3308, TEXT("Худжанд")}, + {91, 2329, lpwszOther}, + {119, 1146, TEXT("Бангкок")}, + {119, 1147, TEXT("Пхукет")}, + {119, 2330, lpwszOther}, + {120, 1148, TEXT("Тайбэй")}, + {120, 2331, lpwszOther}, + {132, 1149, TEXT("Дили")}, + {132, 2332, lpwszOther}, + {90, 1150, TEXT("Ашхабад")}, + {90, 3079, TEXT("Безмеин")}, + {90, 2333, lpwszOther}, + {77, 1152, TEXT("Анкара")}, + {77, 1153, TEXT("Анталия")}, + {77, 3080, TEXT("Бурса")}, + {77, 1151, TEXT("Мармарис")}, + {77, 1154, TEXT("Стамбул")}, + {77, 1155, TEXT("Трабзон")}, + {77, 2334, lpwszOther}, + {93, 3362, TEXT("Алмалык")}, + {93, 3137, TEXT("Андижан")}, + {93, 3273, TEXT("Асака")}, + {93, 1156, TEXT("Ахангаран")}, + {93, 1157, TEXT("Бухара")}, + {93, 3167, TEXT("Джизак")}, + {93, 3347, TEXT("Кунград")}, + {93, 1158, TEXT("Навои")}, + {93, 1159, TEXT("Наманган")}, + {93, 1160, TEXT("Самарканд")}, + {93, 1161, TEXT("Ташкент")}, + {93, 1162, TEXT("Ургенч")}, + {93, 1163, TEXT("Фергана")}, + {93, 1164, TEXT("Чирчик")}, + {93, 2335, lpwszOther}, + {121, 1165, TEXT("Манила")}, + {121, 3319, TEXT("Себу")}, + {121, 2336, lpwszOther}, + {98, 1166, TEXT("Коломбо")}, + {98, 2337, lpwszOther}, + {75, 3176, TEXT("Исесаки")}, + {75, 3339, TEXT("Корияма")}, + {75, 1167, TEXT("Саппоро")}, + {75, 1168, TEXT("Токио")}, + {75, 2338, lpwszOther}, + {123, 1914, TEXT("Аделаида")}, + {123, 2957, TEXT("Блэк Рок")}, + {123, 1915, TEXT("Брисбен")}, + {123, 3331, TEXT("Горокан")}, + {123, 1916, TEXT("Канберра")}, + {123, 3001, TEXT("Лидкомб")}, + {123, 1917, TEXT("Мельбурн")}, + {123, 3217, TEXT("Норфолк")}, + {123, 3064, TEXT("Перт")}, + {123, 3020, TEXT("Санта Люсиа")}, + {123, 1918, TEXT("Сидней")}, + {123, 3238, TEXT("Энеабба")}, + {123, 2339, lpwszOther}, + {454, 1192, TEXT("Паго-Паго")}, + {454, 2366, lpwszOther}, + {124, 1919, TEXT("Порт-Вила")}, + {124, 2340, lpwszOther}, + {453, 1193, TEXT("Аганья")}, + {453, 2368, lpwszOther}, + {126, 1921, TEXT("Баирики")}, + {126, 2342, lpwszOther}, + {127, 1922, TEXT("Маджуро")}, + {127, 2343, lpwszOther}, + {128, 1923, TEXT("Паликир")}, + {128, 2344, lpwszOther}, + {129, 1924, TEXT("Ярен")}, + {129, 2345, lpwszOther}, + {130, 1925, TEXT("Веллингтон")}, + {130, 1926, TEXT("Гамильтон")}, + {130, 1928, TEXT("Данидин")}, + {130, 1929, TEXT("Крайстчерч")}, + {130, 3235, TEXT("Кромвель")}, + {130, 1927, TEXT("Окленд")}, + {130, 3323, TEXT("Тауранга")}, + {130, 2346, lpwszOther}, + {131, 1930, TEXT("Корор")}, + {131, 2347, lpwszOther}, + {133, 1931, TEXT("Порт-Морсби")}, + {133, 2348, lpwszOther}, + {125, 1920, TEXT("Апиа")}, + {125, 2341, lpwszOther}, + {134, 1932, TEXT("Хониара")}, + {134, 2349, lpwszOther}, + {135, 1933, TEXT("Нукуалофа")}, + {135, 2350, lpwszOther}, + {136, 1934, TEXT("Фунафути")}, + {136, 2351, lpwszOther}, + {137, 1935, TEXT("Сува")}, + {137, 2352, lpwszOther}, + {138, 3055, TEXT("Барлингтон")}, + {138, 3049, TEXT("Броссард")}, + {138, 3330, TEXT("Бурнаби")}, + {138, 1169, TEXT("Ванкувер")}, + {138, 3106, TEXT("Ватерлоо")}, + {138, 1170, TEXT("Виннипег")}, + {138, 1171, TEXT("Галифакс")}, + {138, 1172, TEXT("Гамильтон")}, + {138, 3365, TEXT("Денвер")}, + {138, 1173, TEXT("Калгари")}, + {138, 3104, TEXT("Камлупс")}, + {138, 3366, TEXT("Каннингтон")}, + {138, 1174, TEXT("Квебек")}, + {138, 2964, TEXT("Кингстон")}, + {138, 3113, TEXT("Коквитлам")}, + {138, 1175, TEXT("Монреаль")}, + {138, 2920, TEXT("Ниагара-Фолс")}, + {138, 2889, TEXT("Норд-Йорк")}, + {138, 1176, TEXT("Оттава")}, + {138, 2903, TEXT("Порт Алберни")}, + {138, 1177, TEXT("Ричмонд")}, + {138, 1178, TEXT("Тимминс")}, + {138, 2946, TEXT("Торнхилл")}, + {138, 1179, TEXT("Торонто")}, + {138, 1180, TEXT("Эдмонтон")}, + {138, 2353, lpwszOther}, + {139, 407, TEXT("Вашингтон")}, + {139, 426, TEXT("Айдахо")}, + {139, 378, TEXT("Айова")}, + {139, 412, TEXT("Алабама")}, + {139, 446, TEXT("Аляска")}, + {139, 434, TEXT("Аризона")}, + {139, 416, TEXT("Арканзас")}, + {139, 428, TEXT("Вайоминг")}, + {139, 440, TEXT("Вашингтон")}, + {139, 352, TEXT("Вермонт")}, + {139, 394, TEXT("Виргиния")}, + {139, 374, TEXT("Висконсин")}, + {139, 448, TEXT("Гавайи")}, + {139, 390, TEXT("Делавер")}, + {139, 402, TEXT("Джорджия")}, + {139, 396, TEXT("Западная Виргиния")}, + {139, 370, TEXT("Иллинойс")}, + {139, 368, TEXT("Индиана")}, + {139, 444, TEXT("Калифорния")}, + {139, 388, TEXT("Канзас")}, + {139, 408, TEXT("Кентукки")}, + {139, 430, TEXT("Колорадо")}, + {139, 358, TEXT("Коннектикут")}, + {139, 418, TEXT("Луизиана")}, + {139, 354, TEXT("Массачусетс")}, + {139, 376, TEXT("Миннесота")}, + {139, 414, TEXT("Миссисипи")}, + {139, 380, TEXT("Миссури")}, + {139, 372, TEXT("Мичиган")}, + {139, 424, TEXT("Монтана")}, + {139, 348, TEXT("Мэн")}, + {139, 392, TEXT("Мэриленд")}, + {139, 386, TEXT("Небраска")}, + {139, 438, TEXT("Невада")}, + {139, 362, TEXT("Нью-Джерси")}, + {139, 360, TEXT("Нью-Йорк")}, + {139, 432, TEXT("Нью-Мексико")}, + {139, 350, TEXT("Нью-Хэмпшир")}, + {139, 366, TEXT("Огайо")}, + {139, 420, TEXT("Оклахома")}, + {139, 442, TEXT("Орегон")}, + {139, 364, TEXT("Пенсильвания")}, + {139, 450, TEXT("Пуэрто-Рико")}, + {139, 356, TEXT("Род-Айленд")}, + {139, 382, TEXT("Северная Дакота")}, + {139, 398, TEXT("Северная Каролина")}, + {139, 410, TEXT("Теннесси")}, + {139, 422, TEXT("Техас")}, + {139, 406, TEXT("Федеральный округ Колумбия")}, + {139, 404, TEXT("Флорида")}, + {139, 384, TEXT("Южная Дакота")}, + {139, 400, TEXT("Южная Каролина")}, + {139, 436, TEXT("Юта")}, + {140, 1238, TEXT("Сент-Джонс")}, + {140, 2442, lpwszOther}, + {141, 1239, TEXT("Буэнос-Айрес")}, + {141, 2441, lpwszOther}, + {142, 1240, TEXT("Нассау")}, + {142, 2440, lpwszOther}, + {143, 1241, TEXT("Бриджтаун")}, + {143, 2439, lpwszOther}, + {146, 1242, TEXT("Бельмопан")}, + {146, 2438, lpwszOther}, + {144, 1243, TEXT("Ла-Пас")}, + {144, 2437, lpwszOther}, + {145, 1244, TEXT("Бразилиа")}, + {145, 3094, TEXT("Пассо Фундо")}, + {145, 1245, TEXT("Рио-де-Жанейро")}, + {145, 1246, TEXT("Сан-Паулу")}, + {145, 2436, lpwszOther}, + {147, 1247, TEXT("Каракас")}, + {147, 2435, lpwszOther}, + {452, 1190, TEXT("Шарлотта-Амалия")}, + {452, 2364, lpwszOther}, + {149, 1248, TEXT("Порт-о-Пренс")}, + {149, 2434, lpwszOther}, + {148, 1249, TEXT("Джоржтаун")}, + {148, 2433, lpwszOther}, + {173, 1250, TEXT("Гватемала")}, + {173, 2432, lpwszOther}, + {150, 1251, TEXT("Тегусигальпа")}, + {150, 2431, lpwszOther}, + {151, 1252, TEXT("Сент-Джорджес")}, + {151, 2430, lpwszOther}, + {152, 1253, TEXT("Уманак")}, + {152, 2429, lpwszOther}, + {153, 1254, TEXT("Розо")}, + {153, 2428, lpwszOther}, + {154, 1255, TEXT("Санто-Доминго")}, + {154, 2427, lpwszOther}, + {155, 1256, TEXT("Богота")}, + {155, 2426, lpwszOther}, + {156, 1257, TEXT("Сан-Хосе")}, + {156, 2425, lpwszOther}, + {157, 1258, TEXT("Гавана")}, + {157, 2424, lpwszOther}, + {158, 1259, TEXT("Акапулько")}, + {158, 1260, TEXT("Мехико")}, + {158, 2423, lpwszOther}, + {159, 1261, TEXT("Манагуа")}, + {159, 2422, lpwszOther}, + {160, 1262, TEXT("Панама")}, + {160, 2421, lpwszOther}, + {161, 1263, TEXT("Асунсьон")}, + {161, 2420, lpwszOther}, + {162, 1264, TEXT("Лима")}, + {162, 2419, lpwszOther}, + {163, 1265, TEXT("Сан-Сальвадор")}, + {163, 2418, lpwszOther}, + {164, 1266, TEXT("Кингстаун")}, + {164, 2417, lpwszOther}, + {165, 1267, TEXT("Бастер")}, + {165, 2416, lpwszOther}, + {166, 1268, TEXT("Кастри")}, + {166, 2415, lpwszOther}, + {167, 1269, TEXT("Парамарибо")}, + {167, 2414, lpwszOther}, + {168, 1270, TEXT("Порт-оф-Спейн")}, + {168, 2413, lpwszOther}, + {169, 1271, TEXT("Монтевидео")}, + {169, 2412, lpwszOther}, + {170, 1272, TEXT("Сантьяго")}, + {170, 2411, lpwszOther}, + {171, 1273, TEXT("Гуаякиль")}, + {171, 1274, TEXT("Кито")}, + {171, 2410, lpwszOther}, + {172, 1275, TEXT("Кингстон")}, + {172, 2409, lpwszOther}, + {174, 1854, TEXT("Алжир")}, + {174, 2495, lpwszOther}, + {175, 1855, TEXT("Луанда")}, + {175, 2494, lpwszOther}, + {176, 1856, TEXT("Котону")}, + {176, 1857, TEXT("Порто-Ново")}, + {176, 2493, lpwszOther}, + {177, 1858, TEXT("Габороне")}, + {177, 2492, lpwszOther}, + {178, 1859, TEXT("Уагадугу")}, + {178, 2491, lpwszOther}, + {179, 1860, TEXT("Бужумбуру")}, + {179, 2490, lpwszOther}, + {180, 1861, TEXT("Либревиль")}, + {180, 2489, lpwszOther}, + {181, 1862, TEXT("Банжул")}, + {181, 2488, lpwszOther}, + {182, 1863, TEXT("Аккра")}, + {182, 2487, lpwszOther}, + {183, 1864, TEXT("Конакри")}, + {183, 2486, lpwszOther}, + {184, 1865, TEXT("Бисау")}, + {184, 2485, lpwszOther}, + {185, 1866, TEXT("Джибути")}, + {185, 2484, lpwszOther}, + {186, 3312, TEXT("Дахаб")}, + {186, 1867, TEXT("Каир")}, + {186, 1868, TEXT("Хургада")}, + {186, 2483, lpwszOther}, + {187, 1869, TEXT("Лусака")}, + {187, 2482, lpwszOther}, + {23, 1870, TEXT("Хараре")}, + {23, 2481, lpwszOther}, + {188, 1871, TEXT("Прая")}, + {188, 2480, lpwszOther}, + {189, 1872, TEXT("Яунде")}, + {189, 2479, lpwszOther}, + {190, 1873, TEXT("Найроби")}, + {190, 2478, lpwszOther}, + {191, 1874, TEXT("Морони")}, + {191, 2477, lpwszOther}, + {193, 1875, TEXT("Киншаса")}, + {193, 2476, lpwszOther}, + {192, 1876, TEXT("Браззавиль")}, + {192, 2475, lpwszOther}, + {194, 1877, TEXT("Ямусукро")}, + {194, 2474, lpwszOther}, + {195, 1878, TEXT("Масеру")}, + {195, 2473, lpwszOther}, + {196, 1879, TEXT("Монровия")}, + {196, 2472, lpwszOther}, + {197, 1880, TEXT("Триполи")}, + {197, 2471, lpwszOther}, + {198, 1881, TEXT("Порт-Луи")}, + {198, 2470, lpwszOther}, + {199, 1882, TEXT("Нуакшот")}, + {199, 2469, lpwszOther}, + {200, 1883, TEXT("Антананариву")}, + {200, 2468, lpwszOther}, + {201, 1884, TEXT("Лилонгве")}, + {201, 2467, lpwszOther}, + {202, 1885, TEXT("Бамако")}, + {202, 2466, lpwszOther}, + {203, 1886, TEXT("Агадир")}, + {203, 1887, TEXT("Рабат")}, + {203, 2465, lpwszOther}, + {204, 1888, TEXT("Мапуту")}, + {204, 2464, lpwszOther}, + {205, 1889, TEXT("Виндхук")}, + {205, 2463, lpwszOther}, + {206, 1890, TEXT("Ниамей")}, + {206, 2462, lpwszOther}, + {207, 1891, TEXT("Абуджа")}, + {207, 2461, lpwszOther}, + {208, 1892, TEXT("Кигали")}, + {208, 2460, lpwszOther}, + {209, 1893, TEXT("Сан-Томе")}, + {209, 2459, lpwszOther}, + {210, 1894, TEXT("Мбабане")}, + {210, 2458, lpwszOther}, + {211, 1895, TEXT("Виктория")}, + {211, 2457, lpwszOther}, + {212, 1896, TEXT("Дакар")}, + {212, 2456, lpwszOther}, + {213, 1897, TEXT("Могадишо")}, + {213, 2455, lpwszOther}, + {214, 1898, TEXT("Хартум")}, + {214, 2454, lpwszOther}, + {215, 1899, TEXT("Фритаун")}, + {215, 2453, lpwszOther}, + {216, 1900, TEXT("Дар-эс-Салам")}, + {216, 1901, TEXT("Додома")}, + {216, 2452, lpwszOther}, + {217, 1902, TEXT("Ломе")}, + {217, 2451, lpwszOther}, + {218, 1903, TEXT("Тунис")}, + {218, 2450, lpwszOther}, + {219, 1904, TEXT("Кампала")}, + {219, 2449, lpwszOther}, + {220, 1905, TEXT("Банги")}, + {220, 2448, lpwszOther}, + {222, 1906, TEXT("Нджамена")}, + {222, 2447, lpwszOther}, + {223, 1907, TEXT("Малабо")}, + {223, 2446, lpwszOther}, + {221, 1908, TEXT("Асмэра")}, + {221, 2445, lpwszOther}, + {224, 1909, TEXT("Аддис-Абеба")}, + {224, 2444, lpwszOther}, + {225, 1910, TEXT("Дурбан")}, + {225, 1913, TEXT("Йоханнесбург")}, + {225, 1912, TEXT("Кейптаун")}, + {225, 3033, TEXT("Пайнтаун")}, + {225, 1911, TEXT("Претория")}, + {225, 2443, lpwszOther}, + {39, 314, TEXT("Киев")}, + {39, 315, TEXT("Винницкая обл.")}, + {39, 316, TEXT("Волынская обл.")}, + {39, 317, TEXT("Днепропетровская обл.")}, + {39, 318, TEXT("Донецкая обл.")}, + {39, 319, TEXT("Житомирская обл.")}, + {39, 320, TEXT("Закарпатская обл.")}, + {39, 321, TEXT("Запорожская обл.")}, + {39, 322, TEXT("Ивано-Франковская обл.")}, + {39, 323, TEXT("Киевская обл.")}, + {39, 324, TEXT("Кировоградская обл.")}, + {39, 325, TEXT("Крым")}, + {39, 326, TEXT("Луганская обл.")}, + {39, 327, TEXT("Львовская обл.")}, + {39, 328, TEXT("Николаевская обл.")}, + {39, 329, TEXT("Одесская обл.")}, + {39, 330, TEXT("Полтавская обл.")}, + {39, 331, TEXT("Ровенская обл.")}, + {39, 332, TEXT("Сумская обл.")}, + {39, 333, TEXT("Тернопольская обл.")}, + {39, 334, TEXT("Харьковская обл.")}, + {39, 335, TEXT("Херсонская обл.")}, + {39, 336, TEXT("Хмельницкая обл.")}, + {39, 337, TEXT("Черкасская обл.")}, + {39, 338, TEXT("Черниговская обл.")}, + {39, 339, TEXT("Черновицкая обл.")}, + {40, 602, TEXT("Бад Халл")}, + {40, 604, TEXT("Брегенц")}, + {40, 603, TEXT("Вена")}, + {40, 608, TEXT("Грац")}, + {40, 606, TEXT("Зальцбург")}, + {40, 3099, TEXT("Зель-ам-Зее")}, + {40, 605, TEXT("Инсбрук")}, + {40, 3174, TEXT("Кирхберг")}, + {40, 609, TEXT("Клагенфурт")}, + {40, 607, TEXT("Линц")}, + {40, 610, TEXT("Обдах")}, + {40, 611, TEXT("Щтубайтал")}, + {40, 2541, lpwszOther}, + {32, 612, TEXT("Тирана")}, + {32, 2540, lpwszOther}, + {33, 613, TEXT("Андорра-ла-Велья")}, + {33, 2539, lpwszOther}, + {340, 341, TEXT("Минск")}, + {340, 342, TEXT("Брестская обл.")}, + {340, 343, TEXT("Витебская обл.")}, + {340, 344, TEXT("Гомельская обл.")}, + {340, 345, TEXT("Гродненская обл.")}, + {340, 346, TEXT("Минская обл.")}, + {340, 347, TEXT("Могилевская обл.")}, + {38, 760, TEXT("Антверпен")}, + {38, 767, TEXT("Арлон")}, + {38, 762, TEXT("Брюгге")}, + {38, 761, TEXT("Брюссель")}, + {38, 763, TEXT("Гент")}, + {38, 769, TEXT("Лувен")}, + {38, 765, TEXT("Льеж")}, + {38, 764, TEXT("Монс")}, + {38, 3117, TEXT("Мортсель")}, + {38, 766, TEXT("Намюр")}, + {38, 768, TEXT("Хасселт")}, + {38, 2532, lpwszOther}, + {41, 3098, TEXT("Банско")}, + {41, 792, TEXT("Благоевград")}, + {41, 770, TEXT("Бургас")}, + {41, 771, TEXT("Бяла")}, + {41, 773, TEXT("Варна")}, + {41, 776, TEXT("Велико-Тырново")}, + {41, 788, TEXT("Видин")}, + {41, 789, TEXT("Враца")}, + {41, 796, TEXT("Габрово")}, + {41, 777, TEXT("Димитровград")}, + {41, 781, TEXT("Каварна")}, + {41, 786, TEXT("Кырджали")}, + {41, 791, TEXT("Кюстендил")}, + {41, 793, TEXT("Лазарджик")}, + {41, 795, TEXT("Ловеч")}, + {41, 787, TEXT("Михайловград")}, + {41, 790, TEXT("Перник")}, + {41, 3133, TEXT("Пирдоп")}, + {41, 794, TEXT("Плевен")}, + {41, 782, TEXT("Пловдив")}, + {41, 780, TEXT("Разград")}, + {41, 779, TEXT("Русе")}, + {41, 774, TEXT("Силистра")}, + {41, 784, TEXT("Сливен")}, + {41, 772, TEXT("София")}, + {41, 775, TEXT("Толбухин")}, + {41, 3116, TEXT("Тырново")}, + {41, 785, TEXT("Хасково")}, + {41, 778, TEXT("Шумен")}, + {41, 783, TEXT("Ямбол")}, + {41, 2531, lpwszOther}, + {42, 797, TEXT("Баня-Лука")}, + {42, 799, TEXT("Зеница")}, + {42, 798, TEXT("Сараево")}, + {42, 800, TEXT("Тузла")}, + {42, 2530, lpwszOther}, + {45, 802, TEXT("Абердин")}, + {45, 3075, TEXT("Айслворт")}, + {45, 801, TEXT("Алнвик")}, + {45, 804, TEXT("Бидефорд")}, + {45, 803, TEXT("Бирмингем")}, + {45, 805, TEXT("Блоксвич")}, + {45, 3168, TEXT("Бостон")}, + {45, 806, TEXT("Брайтон")}, + {45, 807, TEXT("Бредфорд")}, + {45, 808, TEXT("Бристоль")}, + {45, 809, TEXT("Вилленхолл")}, + {45, 3131, TEXT("Воррингтон")}, + {45, 810, TEXT("Вудбридж")}, + {45, 3342, TEXT("Гилфорд")}, + {45, 811, TEXT("Глазго")}, + {45, 812, TEXT("Дадли")}, + {45, 813, TEXT("Дарем")}, + {45, 814, TEXT("Дуглас")}, + {45, 3089, TEXT("Кардиф")}, + {45, 815, TEXT("Кембридж")}, + {45, 816, TEXT("Кентербери")}, + {45, 817, TEXT("Ливерпуль")}, + {45, 818, TEXT("Лидс")}, + {45, 819, TEXT("Лондон")}, + {45, 820, TEXT("Манчестер")}, + {45, 2976, TEXT("Митчем")}, + {45, 2988, TEXT("Мэйденхед")}, + {45, 821, TEXT("Ноттингем")}, + {45, 3088, TEXT("Ньюпорт")}, + {45, 822, TEXT("Оксфорд")}, + {45, 823, TEXT("Плимут")}, + {45, 824, TEXT("Портсмут")}, + {45, 825, TEXT("Престон")}, + {45, 3343, TEXT("Райд")}, + {45, 2867, TEXT("Ридинг")}, + {45, 2986, TEXT("Сент-Албанс")}, + {45, 826, TEXT("Стаффорд")}, + {45, 3063, TEXT("Стокпорт")}, + {45, 827, TEXT("Уэймут")}, + {45, 3140, TEXT("Челтенхэм")}, + {45, 828, TEXT("Честер")}, + {45, 829, TEXT("Шеффилд")}, + {45, 830, TEXT("Эдинбург")}, + {45, 2529, lpwszOther}, + {44, 831, TEXT("Будапешт")}, + {44, 832, TEXT("Геделле")}, + {44, 836, TEXT("Дебрецен")}, + {44, 835, TEXT("Мишкольц")}, + {44, 834, TEXT("Сегед")}, + {44, 833, TEXT("Шиофок")}, + {44, 2528, lpwszOther}, + {46, 3007, TEXT("Аахен")}, + {46, 837, TEXT("Аугсбург")}, + {46, 838, TEXT("Баден-Баден")}, + {46, 3371, TEXT("Бамберг")}, + {46, 839, TEXT("Бергиш-Гладбах")}, + {46, 840, TEXT("Берлин")}, + {46, 841, TEXT("Билефельд")}, + {46, 3163, TEXT("Бовенден")}, + {46, 842, TEXT("Бонн")}, + {46, 843, TEXT("Браденбург")}, + {46, 3015, TEXT("Брауншвейг")}, + {46, 844, TEXT("Бремен")}, + {46, 2921, TEXT("Варштайн")}, + {46, 845, TEXT("Веймар")}, + {46, 846, TEXT("Вупперталь")}, + {46, 847, TEXT("Гамбург")}, + {46, 848, TEXT("Ганновер")}, + {46, 849, TEXT("Гарделеген")}, + {46, 3010, TEXT("Гейдельберг")}, + {46, 850, TEXT("Гота")}, + {46, 851, TEXT("Дармштадт")}, + {46, 3072, TEXT("Дессау")}, + {46, 852, TEXT("Детмольд")}, + {46, 853, TEXT("Дортмунд")}, + {46, 854, TEXT("Дрезден")}, + {46, 855, TEXT("Дюссельдорф")}, + {46, 3082, TEXT("Иффецхайм")}, + {46, 3309, TEXT("Кассел")}, + {46, 856, TEXT("Кельн")}, + {46, 857, TEXT("Киль")}, + {46, 3138, TEXT("Кобленц")}, + {46, 858, TEXT("Крефельд")}, + {46, 859, TEXT("Лейпциг")}, + {46, 2872, TEXT("Лимбург")}, + {46, 2965, TEXT("Линген")}, + {46, 3135, TEXT("Любек")}, + {46, 3156, TEXT("Мангейм")}, + {46, 3192, TEXT("Меерсбург")}, + {46, 860, TEXT("Мюнстер")}, + {46, 861, TEXT("Мюнхен")}, + {46, 2864, TEXT("Нойштадт")}, + {46, 862, TEXT("Нюрнберг")}, + {46, 3009, TEXT("Оффенбург")}, + {46, 2993, TEXT("Падерборн")}, + {46, 863, TEXT("Равенсбург")}, + {46, 864, TEXT("Регенсбург")}, + {46, 865, TEXT("Рейнен")}, + {46, 866, TEXT("Росток")}, + {46, 3191, TEXT("Саарбрюкен")}, + {46, 2974, TEXT("Санкт-Августин")}, + {46, 3127, TEXT("Тюринген")}, + {46, 867, TEXT("Фрайберг")}, + {46, 868, TEXT("Фрайбург")}, + {46, 869, TEXT("Франкфурт-на-Майне")}, + {46, 3373, TEXT("Хемнитц")}, + {46, 3313, TEXT("Хильден")}, + {46, 870, TEXT("Штутгарт")}, + {46, 3045, TEXT("Эрланген")}, + {46, 2906, TEXT("Эшборн")}, + {46, 2527, lpwszOther}, + {48, 871, TEXT("Афины")}, + {48, 873, TEXT("Ираклион")}, + {48, 3147, TEXT("Корфу")}, + {48, 872, TEXT("Салоники")}, + {48, 3178, TEXT("Халкидики")}, + {48, 2526, lpwszOther}, + {49, 3006, TEXT("Архус")}, + {49, 874, TEXT("Копенгаген")}, + {49, 875, TEXT("Оденсе")}, + {49, 3285, TEXT("Ольборг")}, + {49, 876, TEXT("Сванеке")}, + {49, 3126, TEXT("Скиве")}, + {49, 2525, lpwszOther}, + {50, 3377, TEXT("Виклоу")}, + {50, 3067, TEXT("Голвей")}, + {50, 877, TEXT("Дублин")}, + {50, 3065, TEXT("Килларней")}, + {50, 3066, TEXT("Корк")}, + {50, 878, TEXT("Лимерик")}, + {50, 3069, TEXT("Нейс")}, + {50, 3068, TEXT("Типперэри")}, + {50, 2524, lpwszOther}, + {51, 879, TEXT("Рейкьявик")}, + {51, 2523, lpwszOther}, + {34, 880, TEXT("Аликанте")}, + {34, 3125, TEXT("Альмерия")}, + {34, 881, TEXT("Барселона")}, + {34, 890, TEXT("Бильбао")}, + {34, 3076, TEXT("Бланес")}, + {34, 882, TEXT("Валенсия")}, + {34, 3070, TEXT("Ибица")}, + {34, 888, TEXT("Кадис")}, + {34, 886, TEXT("Картахена")}, + {34, 891, TEXT("Ла-Корунья")}, + {34, 3310, TEXT("Лорет де Мар")}, + {34, 883, TEXT("Мадрид")}, + {34, 884, TEXT("Малага")}, + {34, 885, TEXT("Марбелья")}, + {34, 892, TEXT("Овьедо")}, + {34, 3179, TEXT("Пальма де Майорка")}, + {34, 3177, TEXT("Сан-Агустин")}, + {34, 3289, TEXT("Санта-Крус-де-Тенерифе")}, + {34, 889, TEXT("Сарагоса")}, + {34, 887, TEXT("Севилья")}, + {34, 893, TEXT("Хихон")}, + {34, 2522, lpwszOther}, + {52, 3318, TEXT("Аоста")}, + {52, 3278, TEXT("Беллариа")}, + {52, 906, TEXT("Болонья")}, + {52, 894, TEXT("Брешиа")}, + {52, 895, TEXT("Венеция")}, + {52, 905, TEXT("Верона")}, + {52, 896, TEXT("Генуя")}, + {52, 897, TEXT("Лекко")}, + {52, 3369, TEXT("Ливорно")}, + {52, 3327, TEXT("Марсала")}, + {52, 898, TEXT("Милан")}, + {52, 899, TEXT("Модена")}, + {52, 907, TEXT("Неаполь")}, + {52, 908, TEXT("Перуджа")}, + {52, 900, TEXT("Пиза")}, + {52, 901, TEXT("Рим")}, + {52, 3368, TEXT("Сан-Ремо")}, + {52, 3384, TEXT("Сиракуза")}, + {52, 3252, TEXT("Терамо")}, + {52, 902, TEXT("Триест")}, + {52, 903, TEXT("Турин")}, + {52, 3130, TEXT("Фано")}, + {52, 904, TEXT("Флоренция")}, + {52, 2521, lpwszOther}, + {53, 2939, TEXT("Айзкраукле")}, + {53, 3054, TEXT("Валка")}, + {53, 909, TEXT("Даугавпилс")}, + {53, 2934, TEXT("Екабпилс")}, + {53, 913, TEXT("Елгава")}, + {53, 2935, TEXT("Кокнесе")}, + {53, 912, TEXT("Лиепая")}, + {53, 2905, TEXT("Резекне")}, + {53, 911, TEXT("Рига")}, + {53, 2936, TEXT("Саласпилс")}, + {53, 2937, TEXT("Смилтене")}, + {53, 910, TEXT("Юрмала")}, + {53, 2520, lpwszOther}, + {54, 914, TEXT("Вильнюс")}, + {54, 915, TEXT("Висагинас")}, + {54, 916, TEXT("Каунас")}, + {54, 918, TEXT("Клайпеда")}, + {54, 919, TEXT("Паланга")}, + {54, 3173, TEXT("Пеневежис")}, + {54, 917, TEXT("Шауляй")}, + {54, 2519, lpwszOther}, + {55, 920, TEXT("Вадуц")}, + {55, 2518, lpwszOther}, + {56, 3376, TEXT("Бетцдорф")}, + {56, 921, TEXT("Люксембург")}, + {56, 2517, lpwszOther}, + {57, 3142, TEXT("Битола")}, + {57, 922, TEXT("Скопье")}, + {57, 2516, lpwszOther}, + {58, 923, TEXT("Валлетта")}, + {58, 3154, TEXT("Мзида")}, + {58, 924, TEXT("Слима")}, + {58, 2515, lpwszOther}, + {59, 925, TEXT("Бельцы")}, + {59, 926, TEXT("Бендеры")}, + {59, 3234, TEXT("Дубоссары")}, + {59, 3275, TEXT("Кахул")}, + {59, 927, TEXT("Кишинев")}, + {59, 3321, TEXT("Резина")}, + {59, 928, TEXT("Рыбница")}, + {59, 929, TEXT("Тирасполь")}, + {59, 3281, TEXT("Чадыр-Лунга")}, + {59, 2514, lpwszOther}, + {36, 930, TEXT("Монте-Карло")}, + {36, 2513, lpwszOther}, + {60, 931, TEXT("Амстердам")}, + {60, 933, TEXT("Бреда")}, + {60, 932, TEXT("Гаага")}, + {60, 934, TEXT("Гауда")}, + {60, 935, TEXT("Делфт")}, + {60, 2977, TEXT("Донген")}, + {60, 3030, TEXT("Зволле")}, + {60, 3091, TEXT("Ниймеген")}, + {60, 936, TEXT("Роттердам")}, + {60, 937, TEXT("Утрехт")}, + {60, 3044, TEXT("Эйндховен")}, + {60, 3380, TEXT("Эншеде")}, + {60, 2512, lpwszOther}, + {61, 3190, TEXT("Кристиансанд")}, + {61, 2857, TEXT("Лиллехаммер")}, + {61, 938, TEXT("Осло")}, + {61, 3355, TEXT("Ставангер")}, + {61, 939, TEXT("Тронхейм")}, + {61, 2511, lpwszOther}, + {62, 940, TEXT("Белосток")}, + {62, 941, TEXT("Варшава")}, + {62, 3164, TEXT("Вроцлав")}, + {62, 942, TEXT("Гданьск")}, + {62, 943, TEXT("Гливице")}, + {62, 3237, TEXT("Закопане")}, + {62, 3165, TEXT("Зелена Гура")}, + {62, 944, TEXT("Катовице")}, + {62, 945, TEXT("Краков")}, + {62, 3008, TEXT("Лодзь")}, + {62, 3150, TEXT("Ольштын")}, + {62, 946, TEXT("Познань")}, + {62, 947, TEXT("Радом")}, + {62, 948, TEXT("Сопот")}, + {62, 2958, TEXT("Тыхы")}, + {62, 2510, lpwszOther}, + {35, 949, TEXT("Лиссабон")}, + {35, 950, TEXT("Порто")}, + {35, 2509, lpwszOther}, + {63, 952, TEXT("Брашов")}, + {63, 951, TEXT("Бухарест")}, + {63, 954, TEXT("Констанца")}, + {63, 955, TEXT("Плоешти")}, + {63, 953, TEXT("Яссы")}, + {63, 2508, lpwszOther}, + {64, 956, TEXT("Сан-Марино")}, + {64, 2507, lpwszOther}, + {74, 957, TEXT("Белград")}, + {74, 960, TEXT("Ниш")}, + {74, 958, TEXT("Нови-Сад")}, + {74, 959, TEXT("Сараево")}, + {74, 2506, lpwszOther}, + {65, 961, TEXT("Братислава")}, + {65, 962, TEXT("Кошице")}, + {65, 3101, TEXT("Липтов")}, + {65, 963, TEXT("Попрад")}, + {65, 964, TEXT("Прешов")}, + {65, 965, TEXT("Ружемберок")}, + {65, 966, TEXT("Тврдошин")}, + {65, 2505, lpwszOther}, + {66, 968, TEXT("Копар")}, + {66, 967, TEXT("Любляна")}, + {66, 969, TEXT("Марибор")}, + {66, 2504, lpwszOther}, + {67, 970, TEXT("Торсхавн")}, + {67, 2503, lpwszOther}, + {68, 2888, TEXT("Вантаа")}, + {68, 971, TEXT("Васа")}, + {68, 979, TEXT("Котка")}, + {68, 972, TEXT("Коувола")}, + {68, 980, TEXT("Лахти")}, + {68, 973, TEXT("Оулу")}, + {68, 3375, TEXT("Риихимяки")}, + {68, 3159, TEXT("Руовеси")}, + {68, 974, TEXT("Тампере")}, + {68, 975, TEXT("Турку")}, + {68, 976, TEXT("Хельсинки")}, + {68, 977, TEXT("Эспо")}, + {68, 978, TEXT("Ювяскюля")}, + {68, 2502, lpwszOther}, + {37, 996, TEXT("Авиньон")}, + {37, 983, TEXT("Бержерак")}, + {37, 997, TEXT("Блуа")}, + {37, 984, TEXT("Бордо")}, + {37, 998, TEXT("Дижон")}, + {37, 987, TEXT("Канн")}, + {37, 988, TEXT("Кастр")}, + {37, 993, TEXT("Клермон-Ферран")}, + {37, 3037, TEXT("Лилль")}, + {37, 989, TEXT("Лион")}, + {37, 985, TEXT("Марсель")}, + {37, 991, TEXT("Мец")}, + {37, 3161, TEXT("Мобеж")}, + {37, 990, TEXT("Нанси")}, + {37, 994, TEXT("Нант")}, + {37, 995, TEXT("Ницца")}, + {37, 999, TEXT("Орлеан")}, + {37, 981, TEXT("Париж")}, + {37, 3374, TEXT("Перпиньян")}, + {37, 992, TEXT("Руан")}, + {37, 982, TEXT("Страсбург")}, + {37, 986, TEXT("Тулуза")}, + {37, 3314, TEXT("Шамбери")}, + {37, 2501, lpwszOther}, + {69, 1003, TEXT("Дубровник")}, + {69, 1000, TEXT("Загреб")}, + {69, 1001, TEXT("Задар")}, + {69, 1004, TEXT("Риека")}, + {69, 1002, TEXT("Сплит")}, + {69, 2500, lpwszOther}, + {70, 1005, TEXT("Брно")}, + {70, 3291, TEXT("Гавличкув-Брод")}, + {70, 1007, TEXT("Градец-Кралове")}, + {70, 1008, TEXT("Карлови-Вари")}, + {70, 3019, TEXT("Кладрубы")}, + {70, 1010, TEXT("Лоуни")}, + {70, 1009, TEXT("Острава")}, + {70, 1015, TEXT("Пльзень")}, + {70, 3105, TEXT("Правчицка Брана")}, + {70, 1006, TEXT("Прага")}, + {70, 3246, TEXT("Тачов")}, + {70, 1011, TEXT("Тршебич")}, + {70, 1012, TEXT("Усти-над-Лабем")}, + {70, 1014, TEXT("Ческе-Будеевице")}, + {70, 1013, TEXT("Яблонец-над-Нисоу")}, + {70, 2499, lpwszOther}, + {71, 1016, TEXT("Арау")}, + {71, 1019, TEXT("Баден")}, + {71, 1017, TEXT("Базель")}, + {71, 1018, TEXT("Берн")}, + {71, 1020, TEXT("Биль")}, + {71, 1021, TEXT("Винтертур")}, + {71, 1022, TEXT("Давос")}, + {71, 3189, TEXT("Делемонт")}, + {71, 1023, TEXT("Женева")}, + {71, 1024, TEXT("Золотурн")}, + {71, 1025, TEXT("Лозанна")}, + {71, 1026, TEXT("Локарно")}, + {71, 1027, TEXT("Лугано")}, + {71, 1028, TEXT("Люцерн")}, + {71, 1029, TEXT("Монтре")}, + {71, 1030, TEXT("Цюрих")}, + {71, 2498, lpwszOther}, + {72, 2883, TEXT("Арбога")}, + {72, 1031, TEXT("Гетеборг")}, + {72, 1032, TEXT("Кальмар")}, + {72, 1037, TEXT("Лахольм")}, + {72, 1036, TEXT("Лулео")}, + {72, 1042, TEXT("Лунд")}, + {72, 1033, TEXT("Мальме")}, + {72, 1034, TEXT("Стокгольм")}, + {72, 1041, TEXT("Умео")}, + {72, 1039, TEXT("Фалун")}, + {72, 1043, TEXT("Хельсинборг")}, + {72, 1040, TEXT("Хернесанд")}, + {72, 1038, TEXT("Эстерсунд")}, + {72, 2497, lpwszOther}, + {73, 3013, TEXT("Валга")}, + {73, 1044, TEXT("Кейла")}, + {73, 1045, TEXT("Кохтла-Ярве")}, + {73, 1046, TEXT("Маарду")}, + {73, 1047, TEXT("Мыйзакюла")}, + {73, 1048, TEXT("Нарва")}, + {73, 1049, TEXT("Пярну")}, + {73, 1050, TEXT("Раквере")}, + {73, 1051, TEXT("Силламяэ")}, + {73, 1052, TEXT("Таллин")}, + {73, 1053, TEXT("Тарту")}, + {73, 1054, TEXT("Хаапсалу")}, + {0, NULL} +};//*/ + + + + + + +static const MRA_PLACE mrapPlaces[] = +{ + {24, 0, 0, L"Россия"}, + {81, 0, 0, L"Азербайджан"}, + {82, 0, 0, L"Армения"}, + {97, 0, 0, L"Афганистан"}, + {96, 0, 0, L"Бангладеш"}, + {99, 0, 0, L"Бахрейн"}, + {100, 0, 0, L"Бруней-Даруссалам"}, + {101, 0, 0, L"Бутан"}, + {102, 0, 0, L"Вьетнам"}, + {83, 0, 0, L"Грузия"}, + {86, 0, 0, L"Израиль"}, + {95, 0, 0, L"Индия"}, + {103, 0, 0, L"Индонезия"}, + {79, 0, 0, L"Иордания"}, + {85, 0, 0, L"Ирак"}, + {87, 0, 0, L"Иран"}, + {104, 0, 0, L"Йемен"}, + {84, 0, 0, L"Казахстан"}, + {105, 0, 0, L"Камбоджа"}, + {106, 0, 0, L"Катар"}, + {107, 0, 0, L"Кипр"}, + {92, 0, 0, L"Киргизия (Кыргызстан)"}, + {76, 0, 0, L"Китай"}, + {3215, 0, 0, L"Кокосовые острова (Австр.)"}, + {29, 0, 0, L"Корея (КНДР)"}, + {108, 0, 0, L"Корея"}, + {88, 0, 0, L"Кувейт"}, + {109, 0, 0, L"Лаос"}, + {110, 0, 0, L"Ливан"}, + {111, 0, 0, L"Малайзия"}, + {112, 0, 0, L"Мальдивы"}, + {113, 0, 0, L"Монголия"}, + {114, 0, 0, L"Мьянма"}, + {115, 0, 0, L"Непал"}, + {116, 0, 0, L"Объединенные Арабские Эмираты"}, + {117, 0, 0, L"Оман"}, + {3216, 0, 0, L"Остров Рождества (Австр.)"}, + {122, 0, 0, L"Пакистан"}, + {89, 0, 0, L"Палестина"}, + {94, 0, 0, L"Саудовская Аравия"}, + {118, 0, 0, L"Сингапур"}, + {78, 0, 0, L"Сирия"}, + {91, 0, 0, L"Таджикистан"}, + {119, 0, 0, L"Таиланд"}, + {120, 0, 0, L"Тайвань"}, + {132, 0, 0, L"Тимор"}, + {90, 0, 0, L"Туркмения"}, + {77, 0, 0, L"Турция"}, + {93, 0, 0, L"Узбекистан"}, + {121, 0, 0, L"Филиппины"}, + {98, 0, 0, L"Шри Ланка"}, + {75, 0, 0, L"Япония"}, + {123, 0, 0, L"Австралия"}, + {454, 0, 0, L"Американское Самоа"}, + {124, 0, 0, L"Вануату"}, + {453, 0, 0, L"Гуам (США)"}, + {126, 0, 0, L"Кирибати"}, + {127, 0, 0, L"Маршалловы Острова"}, + {128, 0, 0, L"Микронезия (Федеративные Штаты Микронезии)"}, + {129, 0, 0, L"Науру"}, + {3220, 0, 0, L"Ниуэ (Н.Зел.)"}, + {130, 0, 0, L"Новая Зеландия"}, + {3218, 0, 0, L"Новая Каледония (Фр.)"}, + {3221, 0, 0, L"Острова Кука (Н.Зел.)"}, + {3230, 0, 0, L"Острова Херд и Макдональд (Австр.)"}, + {131, 0, 0, L"Палау"}, + {133, 0, 0, L"Папуа - Новая Гвинея"}, + {3222, 0, 0, L"Питкерн (Брит.)"}, + {125, 0, 0, L"Самоа"}, + {3219, 0, 0, L"Сев. Марианские острова (США)"}, + {134, 0, 0, L"Соломоновы Острова"}, + {3223, 0, 0, L"Токелау (Н.Зел.)"}, + {135, 0, 0, L"Тонга"}, + {136, 0, 0, L"Тувалу"}, + {3224, 0, 0, L"Уоллис и Футуна острова (Фр.)"}, + {137, 0, 0, L"Фиджи"}, + {3226, 0, 0, L"Французская Полинезия"}, + {3225, 0, 0, L"Французские Южные территории"}, + {138, 0, 0, L"Канада"}, + {139, 0, 0, L"США"}, + {3200, 0, 0, L"Ангилья (Брит.)"}, + {140, 0, 0, L"Антигуа и Барбуда"}, + {141, 0, 0, L"Аргентина"}, + {3202, 0, 0, L"Аруба (Нид.)"}, + {142, 0, 0, L"Багамы"}, + {143, 0, 0, L"Барбадос"}, + {146, 0, 0, L"Белиз"}, + {3203, 0, 0, L"Бермуды (Брит.)"}, + {144, 0, 0, L"Боливия"}, + {145, 0, 0, L"Бразилия"}, + {147, 0, 0, L"Венесуэла"}, + {3204, 0, 0, L"Виргинские острова (Брит.)"}, + {452, 0, 0, L"Виргинские острова (США)"}, + {149, 0, 0, L"Гаити"}, + {148, 0, 0, L"Гайана"}, + {3205, 0, 0, L"Гваделупа (Фр.)"}, + {173, 0, 0, L"Гватемала"}, + {150, 0, 0, L"Гондурас"}, + {151, 0, 0, L"Гренада"}, + {152, 0, 0, L"Гренландия (Дат.)"}, + {153, 0, 0, L"Доминика"}, + {154, 0, 0, L"Доминиканская Республика"}, + {155, 0, 0, L"Колумбия"}, + {156, 0, 0, L"Коста-Рика"}, + {157, 0, 0, L"Куба"}, + {3208, 0, 0, L"Мартиника (Фр.)"}, + {158, 0, 0, L"Мексика"}, + {3209, 0, 0, L"Монтсеррат (Брит)"}, + {3201, 0, 0, L"Нидерландские Антилы"}, + {159, 0, 0, L"Никарагуа"}, + {3207, 0, 0, L"Остров Кайман (Брит.)"}, + {3211, 0, 0, L"Острова Теркс и Кайкос (Брит.)"}, + {160, 0, 0, L"Панама"}, + {161, 0, 0, L"Парагвай"}, + {162, 0, 0, L"Перу"}, + {163, 0, 0, L"Сальвадор"}, + {164, 0, 0, L"Сент-Винсент и Гренадины"}, + {165, 0, 0, L"Сент-Китс и Невис"}, + {166, 0, 0, L"Сент-Люсия"}, + {3210, 0, 0, L"Сент-Пьер и Микелон (Фр.)"}, + {167, 0, 0, L"Суринам"}, + {168, 0, 0, L"Тринидат и Тобаго"}, + {169, 0, 0, L"Уругвай"}, + {3212, 0, 0, L"Фолклендские острова (Брит.)"}, + {3206, 0, 0, L"Французская Гвиана"}, + {170, 0, 0, L"Чили"}, + {171, 0, 0, L"Эквадор"}, + {3213, 0, 0, L"Юж. Джорджия и Юж. Сандвичевы о-ва (Брит.)"}, + {172, 0, 0, L"Ямайка"}, + {174, 0, 0, L"Алжир"}, + {175, 0, 0, L"Ангола"}, + {176, 0, 0, L"Бенин"}, + {177, 0, 0, L"Ботсвана"}, + {3228, 0, 0, L"Британская территория в Индийском океане"}, + {178, 0, 0, L"Буркина-Фасо"}, + {179, 0, 0, L"Бурунди"}, + {180, 0, 0, L"Габон"}, + {181, 0, 0, L"Гамбия"}, + {182, 0, 0, L"Гана"}, + {183, 0, 0, L"Гвинея"}, + {184, 0, 0, L"Гвинея-Бисау"}, + {185, 0, 0, L"Джибути"}, + {186, 0, 0, L"Египет"}, + {187, 0, 0, L"Замбия"}, + {3198, 0, 0, L"Зап. Сахара"}, + {23, 0, 0, L"Зимбабве"}, + {188, 0, 0, L"Кабо-Верде"}, + {189, 0, 0, L"Камерун"}, + {190, 0, 0, L"Кения"}, + {191, 0, 0, L"Коморы"}, + {193, 0, 0, L"Конго (Заир)"}, + {192, 0, 0, L"Конго"}, + {194, 0, 0, L"Кот-д`Ивуар"}, + {195, 0, 0, L"Лесото"}, + {196, 0, 0, L"Либерия"}, + {197, 0, 0, L"Ливия"}, + {198, 0, 0, L"Маврикий"}, + {199, 0, 0, L"Мавритания"}, + {200, 0, 0, L"Мадагаскар"}, + {3229, 0, 0, L"Майотт (Фр.)"}, + {201, 0, 0, L"Малави"}, + {202, 0, 0, L"Мали"}, + {203, 0, 0, L"Марокко"}, + {204, 0, 0, L"Мозамбик"}, + {205, 0, 0, L"Намибия"}, + {206, 0, 0, L"Нигер"}, + {207, 0, 0, L"Нигерия"}, + {3227, 0, 0, L"Остров Буве (Норв.)"}, + {3197, 0, 0, L"Реюньон (Фр.)"}, + {208, 0, 0, L"Руанда"}, + {209, 0, 0, L"Сан-Томе и Принсипи"}, + {210, 0, 0, L"Свазиленд"}, + {3199, 0, 0, L"Святая Елена (Брит.)"}, + {211, 0, 0, L"Сейшелы"}, + {212, 0, 0, L"Сенегал"}, + {213, 0, 0, L"Сомали"}, + {214, 0, 0, L"Судан"}, + {215, 0, 0, L"Сьерра-Леоне"}, + {216, 0, 0, L"Танзания"}, + {217, 0, 0, L"Того"}, + {218, 0, 0, L"Тунис"}, + {219, 0, 0, L"Уганда"}, + {220, 0, 0, L"Центральноафриканская Республика"}, + {222, 0, 0, L"Чад"}, + {223, 0, 0, L"Экваториальная Гвинея"}, + {221, 0, 0, L"Эритрея"}, + {224, 0, 0, L"Эфиопия"}, + {225, 0, 0, L"Южно-Африканская Республика (ЮАР)"}, + {39, 0, 0, L"Украина"}, + {40, 0, 0, L"Австрия"}, + {32, 0, 0, L"Албания"}, + {33, 0, 0, L"Андорра"}, + {340, 0, 0, L"Белоруссия"}, + {38, 0, 0, L"Бельгия"}, + {41, 0, 0, L"Болгария"}, + {42, 0, 0, L"Босния и Герцеговина"}, + {43, 0, 0, L"Ватикан"}, + {45, 0, 0, L"Великобритания"}, + {44, 0, 0, L"Венгрия"}, + {46, 0, 0, L"Германия"}, + {3193, 0, 0, L"Гернси (Брит.)"}, + {47, 0, 0, L"Гибралтар (Брит.)"}, + {48, 0, 0, L"Греция"}, + {49, 0, 0, L"Дания"}, + {3194, 0, 0, L"Джерси (Брит.)"}, + {50, 0, 0, L"Ирландия"}, + {51, 0, 0, L"Исландия"}, + {34, 0, 0, L"Испания"}, + {52, 0, 0, L"Италия"}, + {53, 0, 0, L"Латвия"}, + {54, 0, 0, L"Литва"}, + {55, 0, 0, L"Лихтенштейн"}, + {56, 0, 0, L"Люксембург"}, + {57, 0, 0, L"Македония"}, + {58, 0, 0, L"Мальта"}, + {59, 0, 0, L"Молдавия"}, + {36, 0, 0, L"Монако"}, + {60, 0, 0, L"Нидерланды"}, + {61, 0, 0, L"Норвегия"}, + {3195, 0, 0, L"Остров Мэн (Брит.)"}, + {62, 0, 0, L"Польша"}, + {35, 0, 0, L"Португалия"}, + {63, 0, 0, L"Румыния"}, + {64, 0, 0, L"Сан-Марино"}, + {74, 0, 0, L"Сербия и Черногория"}, + {65, 0, 0, L"Словакия"}, + {66, 0, 0, L"Словения"}, + {67, 0, 0, L"Фарерские о-ва (Дания)"}, + {68, 0, 0, L"Финляндия"}, + {37, 0, 0, L"Франция"}, + {69, 0, 0, L"Хорватия"}, + {70, 0, 0, L"Чехия"}, + {71, 0, 0, L"Швейцария"}, + {72, 0, 0, L"Швеция"}, + {3196, 0, 0, L"Шпицберген (Норв.)"}, + {73, 0, 0, L"Эстония"}, + {24, 25, 0, L"Москва"}, + {24, 226, 0, L"Санкт-Петербург"}, + {24, 233, 0, L"Саха (Якутия)"}, + {24, 232, 0, L"Приморский край"}, + {24, 235, 0, L"Хабаровский край"}, + {24, 227, 0, L"Амурская обл."}, + {24, 229, 0, L"Камчатская обл."}, + {24, 231, 0, L"Магаданская обл."}, + {24, 234, 0, L"Сахалинская обл."}, + {24, 228, 0, L"Еврейская АО"}, + {24, 230, 0, L"Корякский АО"}, + {24, 236, 0, L"Чукотский АО"}, + {24, 237, 0, L"Башкортостан"}, + {24, 240, 0, L"Марий-Эл"}, + {24, 241, 0, L"Мордовия"}, + {24, 248, 0, L"Татарстан"}, + {24, 249, 0, L"Удмуртия"}, + {24, 251, 0, L"Чувашия"}, + {24, 238, 0, L"Кировская обл."}, + {24, 242, 0, L"Нижегородская обл."}, + {24, 243, 0, L"Оренбургская обл."}, + {24, 244, 0, L"Пензенская обл."}, + {24, 245, 0, L"Пермская обл."}, + {24, 246, 0, L"Самарская обл."}, + {24, 247, 0, L"Саратовская обл."}, + {24, 250, 0, L"Ульяновская обл."}, + {24, 239, 0, L"Коми-Пермяцкий АО"}, + {24, 255, 0, L"Карелия"}, + {24, 256, 0, L"Коми"}, + {24, 252, 0, L"Архангельская обл."}, + {24, 253, 0, L"Вологодская обл."}, + {24, 254, 0, L"Калининградская обл."}, + {24, 257, 0, L"Ленинградская обл."}, + {24, 258, 0, L"Мурманская обл."}, + {24, 260, 0, L"Новгородская обл."}, + {24, 261, 0, L"Псковская обл."}, + {24, 259, 0, L"Ненецкий АО"}, + {24, 265, 0, L"Бурятия"}, + {24, 263, 0, L"Республика Алтай"}, + {24, 273, 0, L"Тыва"}, + {24, 275, 0, L"Хакасия"}, + {24, 264, 0, L"Алтайский край"}, + {24, 268, 0, L"Красноярский край"}, + {24, 266, 0, L"Иркутская обл."}, + {24, 267, 0, L"Кемеровская обл."}, + {24, 269, 0, L"Новосибирская обл."}, + {24, 270, 0, L"Омская обл."}, + {24, 272, 0, L"Томская обл."}, + {24, 276, 0, L"Читинская обл."}, + {24, 262, 0, L"Агинский Бурятский АО"}, + {24, 271, 0, L"Таймырский АО"}, + {24, 274, 0, L"Усть-Ордынский Бурятский АО"}, + {24, 277, 0, L"Эвенкийский АО"}, + {24, 278, 0, L"Курганская обл."}, + {24, 279, 0, L"Свердловская обл."}, + {24, 280, 0, L"Тюменская обл."}, + {24, 282, 0, L"Челябинская обл."}, + {24, 281, 0, L"Ханты-Мансийский АО - Югра"}, + {24, 283, 0, L"Ямало-Ненецкий АО"}, + {24, 284, 0, L"Белгородская обл."}, + {24, 285, 0, L"Брянская обл."}, + {24, 286, 0, L"Владимирская обл."}, + {24, 287, 0, L"Воронежская обл."}, + {24, 288, 0, L"Ивановская обл."}, + {24, 289, 0, L"Калужская обл."}, + {24, 290, 0, L"Костромская обл."}, + {24, 291, 0, L"Курская обл."}, + {24, 292, 0, L"Липецкая обл."}, + {24, 293, 0, L"Московская обл."}, + {24, 294, 0, L"Орловская обл."}, + {24, 295, 0, L"Рязанская обл."}, + {24, 296, 0, L"Смоленская обл."}, + {24, 297, 0, L"Тамбовская обл."}, + {24, 298, 0, L"Тверская обл."}, + {24, 299, 0, L"Тульская обл."}, + {24, 300, 0, L"Ярославская обл."}, + {24, 301, 0, L"Адыгея"}, + {24, 304, 0, L"Дагестан"}, + {24, 305, 0, L"Ингушетия"}, + {24, 306, 0, L"Кабардино-Балкария"}, + {24, 307, 0, L"Калмыкия"}, + {24, 308, 0, L"Карачаево-Черкессия"}, + {24, 311, 0, L"Северная Осетия - Алания"}, + {24, 313, 0, L"Чечня"}, + {24, 309, 0, L"Краснодарский край"}, + {24, 312, 0, L"Ставропольский край"}, + {24, 302, 0, L"Астраханская обл."}, + {24, 303, 0, L"Волгоградская обл."}, + {24, 310, 0, L"Ростовская обл."}, + {81, 1055, 0, L"Баку"}, + {81, 1058, 0, L"Гянджа"}, + {81, 1056, 0, L"Нахичевань"}, + {81, 1057, 0, L"Ханкенди"}, + {81, 3153, 0, L"Шеки"}, + {81, 2291, 0, L"Другое"}, + {82, 2932, 0, L"Абовян"}, + {82, 1060, 0, L"Аштарак"}, + {82, 3084, 0, L"Ванадзор"}, + {82, 3011, 0, L"Гюмри"}, + {82, 3306, 0, L"Дилижан"}, + {82, 1059, 0, L"Ереван"}, + {82, 3145, 0, L"Ханкенди"}, + {82, 2292, 0, L"Другое"}, + {97, 1061, 0, L"Кабул"}, + {97, 2293, 0, L"Другое"}, + {96, 1062, 0, L"Дакка"}, + {96, 2294, 0, L"Другое"}, + {99, 1063, 0, L"Манама"}, + {99, 2295, 0, L"Другое"}, + {100, 1064, 0, L"Бандар-Сери-Бегаван"}, + {100, 2296, 0, L"Другое"}, + {101, 1065, 0, L"Тхимпху"}, + {101, 2297, 0, L"Другое"}, + {102, 1066, 0, L"Ханой"}, + {102, 2298, 0, L"Другое"}, + {83, 1067, 0, L"Батуми"}, + {83, 3158, 0, L"Боржоми"}, + {83, 1068, 0, L"Поти"}, + {83, 3129, 0, L"Рустави"}, + {83, 1069, 0, L"Сухуми"}, + {83, 1070, 0, L"Тбилиси"}, + {83, 2299, 0, L"Другое"}, + {86, 3345, 0, L"Ариэль"}, + {86, 1071, 0, L"Афула"}, + {86, 2992, 0, L"Ашдод"}, + {86, 3175, 0, L"Ашкелон"}, + {86, 3363, 0, L"Бат-Ям"}, + {86, 2884, 0, L"Беер-Яков"}, + {86, 3243, 0, L"Бейт-Шемеш"}, + {86, 1074, 0, L"Беэр-Шева"}, + {86, 3348, 0, L"Герцелия"}, + {86, 3241, 0, L"Димона"}, + {86, 1075, 0, L"Иерусалим"}, + {86, 3350, 0, L"Йокнеам-Иллит"}, + {86, 2982, 0, L"Кармиэль"}, + {86, 2971, 0, L"Кфар-Саба"}, + {86, 3136, 0, L"Назарет"}, + {86, 1080, 0, L"Натания"}, + {86, 3303, 0, L"Офаким"}, + {86, 3050, 0, L"Раанана"}, + {86, 3151, 0, L"Рамат Ган"}, + {86, 3141, 0, L"Реховот"}, + {86, 3012, 0, L"Ришон ле Цион"}, + {86, 1081, 0, L"Тверия"}, + {86, 1077, 0, L"Тель-Авив"}, + {86, 1079, 0, L"Хадера"}, + {86, 1078, 0, L"Хайфа"}, + {86, 1076, 0, L"Хеврон"}, + {86, 2929, 0, L"Цфат"}, + {86, 2928, 0, L"Эйлат"}, + {86, 2300, 0, L"Другое"}, + {95, 3315, 0, L"Бангалор"}, + {95, 1082, 0, L"Дели"}, + {95, 1083, 0, L"Джайпур"}, + {95, 3144, 0, L"Калькутта"}, + {95, 3025, 0, L"Мумбаи"}, + {95, 3277, 0, L"Панаджи"}, + {95, 1084, 0, L"Ченнаи"}, + {95, 2301, 0, L"Другое"}, + {103, 1085, 0, L"Джакарта"}, + {103, 2302, 0, L"Другое"}, + {79, 1086, 0, L"Амман"}, + {79, 2303, 0, L"Другое"}, + {85, 1087, 0, L"Багдад"}, + {85, 2304, 0, L"Другое"}, + {87, 1088, 0, L"Тегеран"}, + {87, 2305, 0, L"Другое"}, + {104, 1089, 0, L"Сана"}, + {104, 2306, 0, L"Другое"}, + {84, 1090, 0, L"Актау"}, + {84, 1091, 0, L"Актюбинск"}, + {84, 1092, 0, L"Алма-Ата"}, + {84, 3242, 0, L"Аршалы"}, + {84, 1093, 0, L"Астана"}, + {84, 1094, 0, L"Атырау (Гурьев)"}, + {84, 1095, 0, L"Байконур"}, + {84, 3245, 0, L"Балхаш"}, + {84, 3083, 0, L"Жезказган"}, + {84, 1096, 0, L"Капчагай"}, + {84, 1097, 0, L"Караганда"}, + {84, 1098, 0, L"Кокшетау"}, + {84, 1099, 0, L"Кустанай"}, + {84, 2868, 0, L"Лисаковск"}, + {84, 1100, 0, L"Павлодар"}, + {84, 1101, 0, L"Петропавловск (Сев.-Каз. обл.)"}, + {84, 1102, 0, L"Рудный"}, + {84, 1103, 0, L"Семипалатинск"}, + {84, 1104, 0, L"Степногорск"}, + {84, 3166, 0, L"Талгар"}, + {84, 1105, 0, L"Талды-Курган"}, + {84, 2927, 0, L"Тараз"}, + {84, 1106, 0, L"Темиртау"}, + {84, 1107, 0, L"Уральск"}, + {84, 1108, 0, L"Усть-Каменогорск"}, + {84, 1109, 0, L"Чимкент"}, + {84, 1110, 0, L"Экибастуз"}, + {84, 2307, 0, L"Другое"}, + {105, 1111, 0, L"Пномпень"}, + {105, 2308, 0, L"Другое"}, + {106, 1112, 0, L"Доха"}, + {106, 2309, 0, L"Другое"}, + {107, 1113, 0, L"Ларнака"}, + {107, 1114, 0, L"Лимассол"}, + {107, 1115, 0, L"Никосия"}, + {107, 2954, 0, L"Пафос"}, + {107, 2310, 0, L"Другое"}, + {92, 1116, 0, L"Бишкек"}, + {92, 1117, 0, L"Джалал-Абад"}, + {92, 3027, 0, L"Кара-Балта"}, + {92, 1118, 0, L"Каракол"}, + {92, 1119, 0, L"Ош"}, + {92, 1120, 0, L"Талас"}, + {92, 2933, 0, L"Хайдаркен"}, + {92, 2311, 0, L"Другое"}, + {76, 3214, 0, L"Аомынь (Макао)"}, + {76, 1121, 0, L"Гонконг"}, + {76, 2869, 0, L"Гуанчжоу"}, + {76, 3262, 0, L"Далянь"}, + {76, 1122, 0, L"Пекин"}, + {76, 1123, 0, L"Харбин"}, + {76, 1124, 0, L"Шанхай"}, + {76, 3043, 0, L"Шеньян"}, + {76, 2312, 0, L"Другое"}, + {29, 1125, 0, L"Пхеньян"}, + {29, 2313, 0, L"Другое"}, + {108, 1126, 0, L"Сеул"}, + {108, 3240, 0, L"Тейджон"}, + {108, 2314, 0, L"Другое"}, + {88, 1127, 0, L"Эль-Кувейт"}, + {88, 2315, 0, L"Другое"}, + {109, 1128, 0, L"Вьентьян"}, + {109, 2316, 0, L"Другое"}, + {110, 1129, 0, L"Бейрут"}, + {110, 2317, 0, L"Другое"}, + {111, 1130, 0, L"Джохор-Бару"}, + {111, 1131, 0, L"Куала-Лумпур"}, + {111, 2318, 0, L"Другое"}, + {112, 1132, 0, L"Мале"}, + {112, 2319, 0, L"Другое"}, + {113, 1133, 0, L"Улан-Батор"}, + {113, 1134, 0, L"Эрдэнэт"}, + {113, 2320, 0, L"Другое"}, + {114, 1135, 0, L"Янгон"}, + {114, 2321, 0, L"Другое"}, + {115, 1136, 0, L"Катманду"}, + {115, 2322, 0, L"Другое"}, + {116, 1137, 0, L"Абу-Даби"}, + {116, 1138, 0, L"Дубай"}, + {116, 1139, 0, L"Шарджа"}, + {116, 2323, 0, L"Другое"}, + {117, 1140, 0, L"Маскат"}, + {117, 2324, 0, L"Другое"}, + {122, 1141, 0, L"Исламабад"}, + {122, 2325, 0, L"Другое"}, + {89, 1072, 0, L"Ашдод"}, + {89, 1073, 0, L"Ашкелон"}, + {89, 1142, 0, L"Газа"}, + {89, 2326, 0, L"Другое"}, + {94, 3250, 0, L"Медина"}, + {94, 1143, 0, L"Эр-Рияд"}, + {94, 2327, 0, L"Другое"}, + {78, 1144, 0, L"Дамаск"}, + {78, 2328, 0, L"Другое"}, + {91, 1145, 0, L"Душанбе"}, + {91, 3307, 0, L"Кайраккум"}, + {91, 3308, 0, L"Худжанд"}, + {91, 2329, 0, L"Другое"}, + {119, 1146, 0, L"Бангкок"}, + {119, 1147, 0, L"Пхукет"}, + {119, 2330, 0, L"Другое"}, + {120, 1148, 0, L"Тайбэй"}, + {120, 2331, 0, L"Другое"}, + {132, 1149, 0, L"Дили"}, + {132, 2332, 0, L"Другое"}, + {90, 1150, 0, L"Ашхабад"}, + {90, 3079, 0, L"Безмеин"}, + {90, 2333, 0, L"Другое"}, + {77, 1152, 0, L"Анкара"}, + {77, 1153, 0, L"Анталия"}, + {77, 3080, 0, L"Бурса"}, + {77, 1151, 0, L"Мармарис"}, + {77, 1154, 0, L"Стамбул"}, + {77, 1155, 0, L"Трабзон"}, + {77, 2334, 0, L"Другое"}, + {93, 3362, 0, L"Алмалык"}, + {93, 3137, 0, L"Андижан"}, + {93, 3273, 0, L"Асака"}, + {93, 1156, 0, L"Ахангаран"}, + {93, 1157, 0, L"Бухара"}, + {93, 3167, 0, L"Джизак"}, + {93, 3347, 0, L"Кунград"}, + {93, 1158, 0, L"Навои"}, + {93, 1159, 0, L"Наманган"}, + {93, 1160, 0, L"Самарканд"}, + {93, 1161, 0, L"Ташкент"}, + {93, 1162, 0, L"Ургенч"}, + {93, 1163, 0, L"Фергана"}, + {93, 1164, 0, L"Чирчик"}, + {93, 2335, 0, L"Другое"}, + {121, 1165, 0, L"Манила"}, + {121, 3319, 0, L"Себу"}, + {121, 2336, 0, L"Другое"}, + {98, 1166, 0, L"Коломбо"}, + {98, 2337, 0, L"Другое"}, + {75, 3176, 0, L"Исесаки"}, + {75, 3339, 0, L"Корияма"}, + {75, 1167, 0, L"Саппоро"}, + {75, 1168, 0, L"Токио"}, + {75, 2338, 0, L"Другое"}, + {123, 1914, 0, L"Аделаида"}, + {123, 2957, 0, L"Блэк Рок"}, + {123, 1915, 0, L"Брисбен"}, + {123, 3331, 0, L"Горокан"}, + {123, 1916, 0, L"Канберра"}, + {123, 3001, 0, L"Лидкомб"}, + {123, 1917, 0, L"Мельбурн"}, + {123, 3217, 0, L"Норфолк"}, + {123, 3064, 0, L"Перт"}, + {123, 3020, 0, L"Санта Люсиа"}, + {123, 1918, 0, L"Сидней"}, + {123, 3238, 0, L"Энеабба"}, + {123, 2339, 0, L"Другое"}, + {454, 1192, 0, L"Паго-Паго"}, + {454, 2366, 0, L"Другое"}, + {124, 1919, 0, L"Порт-Вила"}, + {124, 2340, 0, L"Другое"}, + {453, 1193, 0, L"Аганья"}, + {453, 2368, 0, L"Другое"}, + {126, 1921, 0, L"Баирики"}, + {126, 2342, 0, L"Другое"}, + {127, 1922, 0, L"Маджуро"}, + {127, 2343, 0, L"Другое"}, + {128, 1923, 0, L"Паликир"}, + {128, 2344, 0, L"Другое"}, + {129, 1924, 0, L"Ярен"}, + {129, 2345, 0, L"Другое"}, + {130, 1925, 0, L"Веллингтон"}, + {130, 1926, 0, L"Гамильтон"}, + {130, 1928, 0, L"Данидин"}, + {130, 1929, 0, L"Крайстчерч"}, + {130, 3235, 0, L"Кромвель"}, + {130, 1927, 0, L"Окленд"}, + {130, 3323, 0, L"Тауранга"}, + {130, 2346, 0, L"Другое"}, + {131, 1930, 0, L"Корор"}, + {131, 2347, 0, L"Другое"}, + {133, 1931, 0, L"Порт-Морсби"}, + {133, 2348, 0, L"Другое"}, + {125, 1920, 0, L"Апиа"}, + {125, 2341, 0, L"Другое"}, + {134, 1932, 0, L"Хониара"}, + {134, 2349, 0, L"Другое"}, + {135, 1933, 0, L"Нукуалофа"}, + {135, 2350, 0, L"Другое"}, + {136, 1934, 0, L"Фунафути"}, + {136, 2351, 0, L"Другое"}, + {137, 1935, 0, L"Сува"}, + {137, 2352, 0, L"Другое"}, + {138, 3055, 0, L"Барлингтон"}, + {138, 3049, 0, L"Броссард"}, + {138, 3330, 0, L"Бурнаби"}, + {138, 1169, 0, L"Ванкувер"}, + {138, 3106, 0, L"Ватерлоо"}, + {138, 1170, 0, L"Виннипег"}, + {138, 1171, 0, L"Галифакс"}, + {138, 1172, 0, L"Гамильтон"}, + {138, 3365, 0, L"Денвер"}, + {138, 1173, 0, L"Калгари"}, + {138, 3104, 0, L"Камлупс"}, + {138, 3366, 0, L"Каннингтон"}, + {138, 1174, 0, L"Квебек"}, + {138, 2964, 0, L"Кингстон"}, + {138, 3113, 0, L"Коквитлам"}, + {138, 1175, 0, L"Монреаль"}, + {138, 2920, 0, L"Ниагара-Фолс"}, + {138, 2889, 0, L"Норд-Йорк"}, + {138, 1176, 0, L"Оттава"}, + {138, 2903, 0, L"Порт Алберни"}, + {138, 1177, 0, L"Ричмонд"}, + {138, 1178, 0, L"Тимминс"}, + {138, 2946, 0, L"Торнхилл"}, + {138, 1179, 0, L"Торонто"}, + {138, 1180, 0, L"Эдмонтон"}, + {138, 2353, 0, L"Другое"}, + {139, 407, 0, L"Вашингтон"}, + {139, 426, 0, L"Айдахо"}, + {139, 378, 0, L"Айова"}, + {139, 412, 0, L"Алабама"}, + {139, 446, 0, L"Аляска"}, + {139, 434, 0, L"Аризона"}, + {139, 416, 0, L"Арканзас"}, + {139, 428, 0, L"Вайоминг"}, + {139, 440, 0, L"Вашингтон"}, + {139, 352, 0, L"Вермонт"}, + {139, 394, 0, L"Виргиния"}, + {139, 374, 0, L"Висконсин"}, + {139, 448, 0, L"Гавайи"}, + {139, 390, 0, L"Делавер"}, + {139, 402, 0, L"Джорджия"}, + {139, 396, 0, L"Западная Виргиния"}, + {139, 370, 0, L"Иллинойс"}, + {139, 368, 0, L"Индиана"}, + {139, 444, 0, L"Калифорния"}, + {139, 388, 0, L"Канзас"}, + {139, 408, 0, L"Кентукки"}, + {139, 430, 0, L"Колорадо"}, + {139, 358, 0, L"Коннектикут"}, + {139, 418, 0, L"Луизиана"}, + {139, 354, 0, L"Массачусетс"}, + {139, 376, 0, L"Миннесота"}, + {139, 414, 0, L"Миссисипи"}, + {139, 380, 0, L"Миссури"}, + {139, 372, 0, L"Мичиган"}, + {139, 424, 0, L"Монтана"}, + {139, 348, 0, L"Мэн"}, + {139, 392, 0, L"Мэриленд"}, + {139, 386, 0, L"Небраска"}, + {139, 438, 0, L"Невада"}, + {139, 362, 0, L"Нью-Джерси"}, + {139, 360, 0, L"Нью-Йорк"}, + {139, 432, 0, L"Нью-Мексико"}, + {139, 350, 0, L"Нью-Хэмпшир"}, + {139, 366, 0, L"Огайо"}, + {139, 420, 0, L"Оклахома"}, + {139, 442, 0, L"Орегон"}, + {139, 364, 0, L"Пенсильвания"}, + {139, 450, 0, L"Пуэрто-Рико"}, + {139, 356, 0, L"Род-Айленд"}, + {139, 382, 0, L"Северная Дакота"}, + {139, 398, 0, L"Северная Каролина"}, + {139, 410, 0, L"Теннесси"}, + {139, 422, 0, L"Техас"}, + {139, 406, 0, L"Федеральный округ Колумбия"}, + {139, 404, 0, L"Флорида"}, + {139, 384, 0, L"Южная Дакота"}, + {139, 400, 0, L"Южная Каролина"}, + {139, 436, 0, L"Юта"}, + {140, 1238, 0, L"Сент-Джонс"}, + {140, 2442, 0, L"Другое"}, + {141, 1239, 0, L"Буэнос-Айрес"}, + {141, 2441, 0, L"Другое"}, + {142, 1240, 0, L"Нассау"}, + {142, 2440, 0, L"Другое"}, + {143, 1241, 0, L"Бриджтаун"}, + {143, 2439, 0, L"Другое"}, + {146, 1242, 0, L"Бельмопан"}, + {146, 2438, 0, L"Другое"}, + {144, 1243, 0, L"Ла-Пас"}, + {144, 2437, 0, L"Другое"}, + {145, 1244, 0, L"Бразилиа"}, + {145, 3094, 0, L"Пассо Фундо"}, + {145, 1245, 0, L"Рио-де-Жанейро"}, + {145, 1246, 0, L"Сан-Паулу"}, + {145, 2436, 0, L"Другое"}, + {147, 1247, 0, L"Каракас"}, + {147, 2435, 0, L"Другое"}, + {452, 1190, 0, L"Шарлотта-Амалия"}, + {452, 2364, 0, L"Другое"}, + {149, 1248, 0, L"Порт-о-Пренс"}, + {149, 2434, 0, L"Другое"}, + {148, 1249, 0, L"Джоржтаун"}, + {148, 2433, 0, L"Другое"}, + {173, 1250, 0, L"Гватемала"}, + {173, 2432, 0, L"Другое"}, + {150, 1251, 0, L"Тегусигальпа"}, + {150, 2431, 0, L"Другое"}, + {151, 1252, 0, L"Сент-Джорджес"}, + {151, 2430, 0, L"Другое"}, + {152, 1253, 0, L"Уманак"}, + {152, 2429, 0, L"Другое"}, + {153, 1254, 0, L"Розо"}, + {153, 2428, 0, L"Другое"}, + {154, 1255, 0, L"Санто-Доминго"}, + {154, 2427, 0, L"Другое"}, + {155, 1256, 0, L"Богота"}, + {155, 2426, 0, L"Другое"}, + {156, 1257, 0, L"Сан-Хосе"}, + {156, 2425, 0, L"Другое"}, + {157, 1258, 0, L"Гавана"}, + {157, 2424, 0, L"Другое"}, + {158, 1259, 0, L"Акапулько"}, + {158, 1260, 0, L"Мехико"}, + {158, 2423, 0, L"Другое"}, + {159, 1261, 0, L"Манагуа"}, + {159, 2422, 0, L"Другое"}, + {160, 1262, 0, L"Панама"}, + {160, 2421, 0, L"Другое"}, + {161, 1263, 0, L"Асунсьон"}, + {161, 2420, 0, L"Другое"}, + {162, 1264, 0, L"Лима"}, + {162, 2419, 0, L"Другое"}, + {163, 1265, 0, L"Сан-Сальвадор"}, + {163, 2418, 0, L"Другое"}, + {164, 1266, 0, L"Кингстаун"}, + {164, 2417, 0, L"Другое"}, + {165, 1267, 0, L"Бастер"}, + {165, 2416, 0, L"Другое"}, + {166, 1268, 0, L"Кастри"}, + {166, 2415, 0, L"Другое"}, + {167, 1269, 0, L"Парамарибо"}, + {167, 2414, 0, L"Другое"}, + {168, 1270, 0, L"Порт-оф-Спейн"}, + {168, 2413, 0, L"Другое"}, + {169, 1271, 0, L"Монтевидео"}, + {169, 2412, 0, L"Другое"}, + {170, 1272, 0, L"Сантьяго"}, + {170, 2411, 0, L"Другое"}, + {171, 1273, 0, L"Гуаякиль"}, + {171, 1274, 0, L"Кито"}, + {171, 2410, 0, L"Другое"}, + {172, 1275, 0, L"Кингстон"}, + {172, 2409, 0, L"Другое"}, + {174, 1854, 0, L"Алжир"}, + {174, 2495, 0, L"Другое"}, + {175, 1855, 0, L"Луанда"}, + {175, 2494, 0, L"Другое"}, + {176, 1856, 0, L"Котону"}, + {176, 1857, 0, L"Порто-Ново"}, + {176, 2493, 0, L"Другое"}, + {177, 1858, 0, L"Габороне"}, + {177, 2492, 0, L"Другое"}, + {178, 1859, 0, L"Уагадугу"}, + {178, 2491, 0, L"Другое"}, + {179, 1860, 0, L"Бужумбуру"}, + {179, 2490, 0, L"Другое"}, + {180, 1861, 0, L"Либревиль"}, + {180, 2489, 0, L"Другое"}, + {181, 1862, 0, L"Банжул"}, + {181, 2488, 0, L"Другое"}, + {182, 1863, 0, L"Аккра"}, + {182, 2487, 0, L"Другое"}, + {183, 1864, 0, L"Конакри"}, + {183, 2486, 0, L"Другое"}, + {184, 1865, 0, L"Бисау"}, + {184, 2485, 0, L"Другое"}, + {185, 1866, 0, L"Джибути"}, + {185, 2484, 0, L"Другое"}, + {186, 3312, 0, L"Дахаб"}, + {186, 1867, 0, L"Каир"}, + {186, 1868, 0, L"Хургада"}, + {186, 2483, 0, L"Другое"}, + {187, 1869, 0, L"Лусака"}, + {187, 2482, 0, L"Другое"}, + {23, 1870, 0, L"Хараре"}, + {23, 2481, 0, L"Другое"}, + {188, 1871, 0, L"Прая"}, + {188, 2480, 0, L"Другое"}, + {189, 1872, 0, L"Яунде"}, + {189, 2479, 0, L"Другое"}, + {190, 1873, 0, L"Найроби"}, + {190, 2478, 0, L"Другое"}, + {191, 1874, 0, L"Морони"}, + {191, 2477, 0, L"Другое"}, + {193, 1875, 0, L"Киншаса"}, + {193, 2476, 0, L"Другое"}, + {192, 1876, 0, L"Браззавиль"}, + {192, 2475, 0, L"Другое"}, + {194, 1877, 0, L"Ямусукро"}, + {194, 2474, 0, L"Другое"}, + {195, 1878, 0, L"Масеру"}, + {195, 2473, 0, L"Другое"}, + {196, 1879, 0, L"Монровия"}, + {196, 2472, 0, L"Другое"}, + {197, 1880, 0, L"Триполи"}, + {197, 2471, 0, L"Другое"}, + {198, 1881, 0, L"Порт-Луи"}, + {198, 2470, 0, L"Другое"}, + {199, 1882, 0, L"Нуакшот"}, + {199, 2469, 0, L"Другое"}, + {200, 1883, 0, L"Антананариву"}, + {200, 2468, 0, L"Другое"}, + {201, 1884, 0, L"Лилонгве"}, + {201, 2467, 0, L"Другое"}, + {202, 1885, 0, L"Бамако"}, + {202, 2466, 0, L"Другое"}, + {203, 1886, 0, L"Агадир"}, + {203, 1887, 0, L"Рабат"}, + {203, 2465, 0, L"Другое"}, + {204, 1888, 0, L"Мапуту"}, + {204, 2464, 0, L"Другое"}, + {205, 1889, 0, L"Виндхук"}, + {205, 2463, 0, L"Другое"}, + {206, 1890, 0, L"Ниамей"}, + {206, 2462, 0, L"Другое"}, + {207, 1891, 0, L"Абуджа"}, + {207, 2461, 0, L"Другое"}, + {208, 1892, 0, L"Кигали"}, + {208, 2460, 0, L"Другое"}, + {209, 1893, 0, L"Сан-Томе"}, + {209, 2459, 0, L"Другое"}, + {210, 1894, 0, L"Мбабане"}, + {210, 2458, 0, L"Другое"}, + {211, 1895, 0, L"Виктория"}, + {211, 2457, 0, L"Другое"}, + {212, 1896, 0, L"Дакар"}, + {212, 2456, 0, L"Другое"}, + {213, 1897, 0, L"Могадишо"}, + {213, 2455, 0, L"Другое"}, + {214, 1898, 0, L"Хартум"}, + {214, 2454, 0, L"Другое"}, + {215, 1899, 0, L"Фритаун"}, + {215, 2453, 0, L"Другое"}, + {216, 1900, 0, L"Дар-эс-Салам"}, + {216, 1901, 0, L"Додома"}, + {216, 2452, 0, L"Другое"}, + {217, 1902, 0, L"Ломе"}, + {217, 2451, 0, L"Другое"}, + {218, 1903, 0, L"Тунис"}, + {218, 2450, 0, L"Другое"}, + {219, 1904, 0, L"Кампала"}, + {219, 2449, 0, L"Другое"}, + {220, 1905, 0, L"Банги"}, + {220, 2448, 0, L"Другое"}, + {222, 1906, 0, L"Нджамена"}, + {222, 2447, 0, L"Другое"}, + {223, 1907, 0, L"Малабо"}, + {223, 2446, 0, L"Другое"}, + {221, 1908, 0, L"Асмэра"}, + {221, 2445, 0, L"Другое"}, + {224, 1909, 0, L"Аддис-Абеба"}, + {224, 2444, 0, L"Другое"}, + {225, 1910, 0, L"Дурбан"}, + {225, 1913, 0, L"Йоханнесбург"}, + {225, 1912, 0, L"Кейптаун"}, + {225, 3033, 0, L"Пайнтаун"}, + {225, 1911, 0, L"Претория"}, + {225, 2443, 0, L"Другое"}, + {39, 314, 0, L"Киев"}, + {39, 315, 0, L"Винницкая обл."}, + {39, 316, 0, L"Волынская обл."}, + {39, 317, 0, L"Днепропетровская обл."}, + {39, 318, 0, L"Донецкая обл."}, + {39, 319, 0, L"Житомирская обл."}, + {39, 320, 0, L"Закарпатская обл."}, + {39, 321, 0, L"Запорожская обл."}, + {39, 322, 0, L"Ивано-Франковская обл."}, + {39, 323, 0, L"Киевская обл."}, + {39, 324, 0, L"Кировоградская обл."}, + {39, 325, 0, L"Крым"}, + {39, 326, 0, L"Луганская обл."}, + {39, 327, 0, L"Львовская обл."}, + {39, 328, 0, L"Николаевская обл."}, + {39, 329, 0, L"Одесская обл."}, + {39, 330, 0, L"Полтавская обл."}, + {39, 331, 0, L"Ровенская обл."}, + {39, 332, 0, L"Сумская обл."}, + {39, 333, 0, L"Тернопольская обл."}, + {39, 334, 0, L"Харьковская обл."}, + {39, 335, 0, L"Херсонская обл."}, + {39, 336, 0, L"Хмельницкая обл."}, + {39, 337, 0, L"Черкасская обл."}, + {39, 338, 0, L"Черниговская обл."}, + {39, 339, 0, L"Черновицкая обл."}, + {40, 602, 0, L"Бад Халл"}, + {40, 604, 0, L"Брегенц"}, + {40, 603, 0, L"Вена"}, + {40, 608, 0, L"Грац"}, + {40, 606, 0, L"Зальцбург"}, + {40, 3099, 0, L"Зель-ам-Зее"}, + {40, 605, 0, L"Инсбрук"}, + {40, 3174, 0, L"Кирхберг"}, + {40, 609, 0, L"Клагенфурт"}, + {40, 607, 0, L"Линц"}, + {40, 610, 0, L"Обдах"}, + {40, 611, 0, L"Щтубайтал"}, + {40, 2541, 0, L"Другое"}, + {32, 612, 0, L"Тирана"}, + {32, 2540, 0, L"Другое"}, + {33, 613, 0, L"Андорра-ла-Велья"}, + {33, 2539, 0, L"Другое"}, + {340, 341, 0, L"Минск"}, + {340, 342, 0, L"Брестская обл."}, + {340, 343, 0, L"Витебская обл."}, + {340, 344, 0, L"Гомельская обл."}, + {340, 345, 0, L"Гродненская обл."}, + {340, 346, 0, L"Минская обл."}, + {340, 347, 0, L"Могилевская обл."}, + {38, 760, 0, L"Антверпен"}, + {38, 767, 0, L"Арлон"}, + {38, 762, 0, L"Брюгге"}, + {38, 761, 0, L"Брюссель"}, + {38, 763, 0, L"Гент"}, + {38, 769, 0, L"Лувен"}, + {38, 765, 0, L"Льеж"}, + {38, 764, 0, L"Монс"}, + {38, 3117, 0, L"Мортсель"}, + {38, 766, 0, L"Намюр"}, + {38, 768, 0, L"Хасселт"}, + {38, 2532, 0, L"Другое"}, + {41, 3098, 0, L"Банско"}, + {41, 792, 0, L"Благоевград"}, + {41, 770, 0, L"Бургас"}, + {41, 771, 0, L"Бяла"}, + {41, 773, 0, L"Варна"}, + {41, 776, 0, L"Велико-Тырново"}, + {41, 788, 0, L"Видин"}, + {41, 789, 0, L"Враца"}, + {41, 796, 0, L"Габрово"}, + {41, 777, 0, L"Димитровград"}, + {41, 781, 0, L"Каварна"}, + {41, 786, 0, L"Кырджали"}, + {41, 791, 0, L"Кюстендил"}, + {41, 793, 0, L"Лазарджик"}, + {41, 795, 0, L"Ловеч"}, + {41, 787, 0, L"Михайловград"}, + {41, 790, 0, L"Перник"}, + {41, 3133, 0, L"Пирдоп"}, + {41, 794, 0, L"Плевен"}, + {41, 782, 0, L"Пловдив"}, + {41, 780, 0, L"Разград"}, + {41, 779, 0, L"Русе"}, + {41, 774, 0, L"Силистра"}, + {41, 784, 0, L"Сливен"}, + {41, 772, 0, L"София"}, + {41, 775, 0, L"Толбухин"}, + {41, 3116, 0, L"Тырново"}, + {41, 785, 0, L"Хасково"}, + {41, 778, 0, L"Шумен"}, + {41, 783, 0, L"Ямбол"}, + {41, 2531, 0, L"Другое"}, + {42, 797, 0, L"Баня-Лука"}, + {42, 799, 0, L"Зеница"}, + {42, 798, 0, L"Сараево"}, + {42, 800, 0, L"Тузла"}, + {42, 2530, 0, L"Другое"}, + {45, 802, 0, L"Абердин"}, + {45, 3075, 0, L"Айслворт"}, + {45, 801, 0, L"Алнвик"}, + {45, 804, 0, L"Бидефорд"}, + {45, 803, 0, L"Бирмингем"}, + {45, 805, 0, L"Блоксвич"}, + {45, 3168, 0, L"Бостон"}, + {45, 806, 0, L"Брайтон"}, + {45, 807, 0, L"Бредфорд"}, + {45, 808, 0, L"Бристоль"}, + {45, 809, 0, L"Вилленхолл"}, + {45, 3131, 0, L"Воррингтон"}, + {45, 810, 0, L"Вудбридж"}, + {45, 3342, 0, L"Гилфорд"}, + {45, 811, 0, L"Глазго"}, + {45, 812, 0, L"Дадли"}, + {45, 813, 0, L"Дарем"}, + {45, 814, 0, L"Дуглас"}, + {45, 3089, 0, L"Кардиф"}, + {45, 815, 0, L"Кембридж"}, + {45, 816, 0, L"Кентербери"}, + {45, 817, 0, L"Ливерпуль"}, + {45, 818, 0, L"Лидс"}, + {45, 819, 0, L"Лондон"}, + {45, 820, 0, L"Манчестер"}, + {45, 2976, 0, L"Митчем"}, + {45, 2988, 0, L"Мэйденхед"}, + {45, 821, 0, L"Ноттингем"}, + {45, 3088, 0, L"Ньюпорт"}, + {45, 822, 0, L"Оксфорд"}, + {45, 823, 0, L"Плимут"}, + {45, 824, 0, L"Портсмут"}, + {45, 825, 0, L"Престон"}, + {45, 3343, 0, L"Райд"}, + {45, 2867, 0, L"Ридинг"}, + {45, 2986, 0, L"Сент-Албанс"}, + {45, 826, 0, L"Стаффорд"}, + {45, 3063, 0, L"Стокпорт"}, + {45, 827, 0, L"Уэймут"}, + {45, 3140, 0, L"Челтенхэм"}, + {45, 828, 0, L"Честер"}, + {45, 829, 0, L"Шеффилд"}, + {45, 830, 0, L"Эдинбург"}, + {45, 2529, 0, L"Другое"}, + {44, 831, 0, L"Будапешт"}, + {44, 832, 0, L"Геделле"}, + {44, 836, 0, L"Дебрецен"}, + {44, 835, 0, L"Мишкольц"}, + {44, 834, 0, L"Сегед"}, + {44, 833, 0, L"Шиофок"}, + {44, 2528, 0, L"Другое"}, + {46, 3007, 0, L"Аахен"}, + {46, 837, 0, L"Аугсбург"}, + {46, 838, 0, L"Баден-Баден"}, + {46, 3371, 0, L"Бамберг"}, + {46, 839, 0, L"Бергиш-Гладбах"}, + {46, 840, 0, L"Берлин"}, + {46, 841, 0, L"Билефельд"}, + {46, 3163, 0, L"Бовенден"}, + {46, 842, 0, L"Бонн"}, + {46, 843, 0, L"Браденбург"}, + {46, 3015, 0, L"Брауншвейг"}, + {46, 844, 0, L"Бремен"}, + {46, 2921, 0, L"Варштайн"}, + {46, 845, 0, L"Веймар"}, + {46, 846, 0, L"Вупперталь"}, + {46, 847, 0, L"Гамбург"}, + {46, 848, 0, L"Ганновер"}, + {46, 849, 0, L"Гарделеген"}, + {46, 3010, 0, L"Гейдельберг"}, + {46, 850, 0, L"Гота"}, + {46, 851, 0, L"Дармштадт"}, + {46, 3072, 0, L"Дессау"}, + {46, 852, 0, L"Детмольд"}, + {46, 853, 0, L"Дортмунд"}, + {46, 854, 0, L"Дрезден"}, + {46, 855, 0, L"Дюссельдорф"}, + {46, 3082, 0, L"Иффецхайм"}, + {46, 3309, 0, L"Кассел"}, + {46, 856, 0, L"Кельн"}, + {46, 857, 0, L"Киль"}, + {46, 3138, 0, L"Кобленц"}, + {46, 858, 0, L"Крефельд"}, + {46, 859, 0, L"Лейпциг"}, + {46, 2872, 0, L"Лимбург"}, + {46, 2965, 0, L"Линген"}, + {46, 3135, 0, L"Любек"}, + {46, 3156, 0, L"Мангейм"}, + {46, 3192, 0, L"Меерсбург"}, + {46, 860, 0, L"Мюнстер"}, + {46, 861, 0, L"Мюнхен"}, + {46, 2864, 0, L"Нойштадт"}, + {46, 862, 0, L"Нюрнберг"}, + {46, 3009, 0, L"Оффенбург"}, + {46, 2993, 0, L"Падерборн"}, + {46, 863, 0, L"Равенсбург"}, + {46, 864, 0, L"Регенсбург"}, + {46, 865, 0, L"Рейнен"}, + {46, 866, 0, L"Росток"}, + {46, 3191, 0, L"Саарбрюкен"}, + {46, 2974, 0, L"Санкт-Августин"}, + {46, 3127, 0, L"Тюринген"}, + {46, 867, 0, L"Фрайберг"}, + {46, 868, 0, L"Фрайбург"}, + {46, 869, 0, L"Франкфурт-на-Майне"}, + {46, 3373, 0, L"Хемнитц"}, + {46, 3313, 0, L"Хильден"}, + {46, 870, 0, L"Штутгарт"}, + {46, 3045, 0, L"Эрланген"}, + {46, 2906, 0, L"Эшборн"}, + {46, 2527, 0, L"Другое"}, + {48, 871, 0, L"Афины"}, + {48, 873, 0, L"Ираклион"}, + {48, 3147, 0, L"Корфу"}, + {48, 872, 0, L"Салоники"}, + {48, 3178, 0, L"Халкидики"}, + {48, 2526, 0, L"Другое"}, + {49, 3006, 0, L"Архус"}, + {49, 874, 0, L"Копенгаген"}, + {49, 875, 0, L"Оденсе"}, + {49, 3285, 0, L"Ольборг"}, + {49, 876, 0, L"Сванеке"}, + {49, 3126, 0, L"Скиве"}, + {49, 2525, 0, L"Другое"}, + {50, 3377, 0, L"Виклоу"}, + {50, 3067, 0, L"Голвей"}, + {50, 877, 0, L"Дублин"}, + {50, 3065, 0, L"Килларней"}, + {50, 3066, 0, L"Корк"}, + {50, 878, 0, L"Лимерик"}, + {50, 3069, 0, L"Нейс"}, + {50, 3068, 0, L"Типперэри"}, + {50, 2524, 0, L"Другое"}, + {51, 879, 0, L"Рейкьявик"}, + {51, 2523, 0, L"Другое"}, + {34, 880, 0, L"Аликанте"}, + {34, 3125, 0, L"Альмерия"}, + {34, 881, 0, L"Барселона"}, + {34, 890, 0, L"Бильбао"}, + {34, 3076, 0, L"Бланес"}, + {34, 882, 0, L"Валенсия"}, + {34, 3070, 0, L"Ибица"}, + {34, 888, 0, L"Кадис"}, + {34, 886, 0, L"Картахена"}, + {34, 891, 0, L"Ла-Корунья"}, + {34, 3310, 0, L"Лорет де Мар"}, + {34, 883, 0, L"Мадрид"}, + {34, 884, 0, L"Малага"}, + {34, 885, 0, L"Марбелья"}, + {34, 892, 0, L"Овьедо"}, + {34, 3179, 0, L"Пальма де Майорка"}, + {34, 3177, 0, L"Сан-Агустин"}, + {34, 3289, 0, L"Санта-Крус-де-Тенерифе"}, + {34, 889, 0, L"Сарагоса"}, + {34, 887, 0, L"Севилья"}, + {34, 893, 0, L"Хихон"}, + {34, 2522, 0, L"Другое"}, + {52, 3318, 0, L"Аоста"}, + {52, 3278, 0, L"Беллариа"}, + {52, 906, 0, L"Болонья"}, + {52, 894, 0, L"Брешиа"}, + {52, 895, 0, L"Венеция"}, + {52, 905, 0, L"Верона"}, + {52, 896, 0, L"Генуя"}, + {52, 897, 0, L"Лекко"}, + {52, 3369, 0, L"Ливорно"}, + {52, 3327, 0, L"Марсала"}, + {52, 898, 0, L"Милан"}, + {52, 899, 0, L"Модена"}, + {52, 907, 0, L"Неаполь"}, + {52, 908, 0, L"Перуджа"}, + {52, 900, 0, L"Пиза"}, + {52, 901, 0, L"Рим"}, + {52, 3368, 0, L"Сан-Ремо"}, + {52, 3384, 0, L"Сиракуза"}, + {52, 3252, 0, L"Терамо"}, + {52, 902, 0, L"Триест"}, + {52, 903, 0, L"Турин"}, + {52, 3130, 0, L"Фано"}, + {52, 904, 0, L"Флоренция"}, + {52, 2521, 0, L"Другое"}, + {53, 2939, 0, L"Айзкраукле"}, + {53, 3054, 0, L"Валка"}, + {53, 909, 0, L"Даугавпилс"}, + {53, 2934, 0, L"Екабпилс"}, + {53, 913, 0, L"Елгава"}, + {53, 2935, 0, L"Кокнесе"}, + {53, 912, 0, L"Лиепая"}, + {53, 2905, 0, L"Резекне"}, + {53, 911, 0, L"Рига"}, + {53, 2936, 0, L"Саласпилс"}, + {53, 2937, 0, L"Смилтене"}, + {53, 910, 0, L"Юрмала"}, + {53, 2520, 0, L"Другое"}, + {54, 914, 0, L"Вильнюс"}, + {54, 915, 0, L"Висагинас"}, + {54, 916, 0, L"Каунас"}, + {54, 918, 0, L"Клайпеда"}, + {54, 919, 0, L"Паланга"}, + {54, 3173, 0, L"Пеневежис"}, + {54, 917, 0, L"Шауляй"}, + {54, 2519, 0, L"Другое"}, + {55, 920, 0, L"Вадуц"}, + {55, 2518, 0, L"Другое"}, + {56, 3376, 0, L"Бетцдорф"}, + {56, 921, 0, L"Люксембург"}, + {56, 2517, 0, L"Другое"}, + {57, 3142, 0, L"Битола"}, + {57, 922, 0, L"Скопье"}, + {57, 2516, 0, L"Другое"}, + {58, 923, 0, L"Валлетта"}, + {58, 3154, 0, L"Мзида"}, + {58, 924, 0, L"Слима"}, + {58, 2515, 0, L"Другое"}, + {59, 925, 0, L"Бельцы"}, + {59, 926, 0, L"Бендеры"}, + {59, 3234, 0, L"Дубоссары"}, + {59, 3275, 0, L"Кахул"}, + {59, 927, 0, L"Кишинев"}, + {59, 3321, 0, L"Резина"}, + {59, 928, 0, L"Рыбница"}, + {59, 929, 0, L"Тирасполь"}, + {59, 3281, 0, L"Чадыр-Лунга"}, + {59, 2514, 0, L"Другое"}, + {36, 930, 0, L"Монте-Карло"}, + {36, 2513, 0, L"Другое"}, + {60, 931, 0, L"Амстердам"}, + {60, 933, 0, L"Бреда"}, + {60, 932, 0, L"Гаага"}, + {60, 934, 0, L"Гауда"}, + {60, 935, 0, L"Делфт"}, + {60, 2977, 0, L"Донген"}, + {60, 3030, 0, L"Зволле"}, + {60, 3091, 0, L"Ниймеген"}, + {60, 936, 0, L"Роттердам"}, + {60, 937, 0, L"Утрехт"}, + {60, 3044, 0, L"Эйндховен"}, + {60, 3380, 0, L"Эншеде"}, + {60, 2512, 0, L"Другое"}, + {61, 3190, 0, L"Кристиансанд"}, + {61, 2857, 0, L"Лиллехаммер"}, + {61, 938, 0, L"Осло"}, + {61, 3355, 0, L"Ставангер"}, + {61, 939, 0, L"Тронхейм"}, + {61, 2511, 0, L"Другое"}, + {62, 940, 0, L"Белосток"}, + {62, 941, 0, L"Варшава"}, + {62, 3164, 0, L"Вроцлав"}, + {62, 942, 0, L"Гданьск"}, + {62, 943, 0, L"Гливице"}, + {62, 3237, 0, L"Закопане"}, + {62, 3165, 0, L"Зелена Гура"}, + {62, 944, 0, L"Катовице"}, + {62, 945, 0, L"Краков"}, + {62, 3008, 0, L"Лодзь"}, + {62, 3150, 0, L"Ольштын"}, + {62, 946, 0, L"Познань"}, + {62, 947, 0, L"Радом"}, + {62, 948, 0, L"Сопот"}, + {62, 2958, 0, L"Тыхы"}, + {62, 2510, 0, L"Другое"}, + {35, 949, 0, L"Лиссабон"}, + {35, 950, 0, L"Порто"}, + {35, 2509, 0, L"Другое"}, + {63, 952, 0, L"Брашов"}, + {63, 951, 0, L"Бухарест"}, + {63, 954, 0, L"Констанца"}, + {63, 955, 0, L"Плоешти"}, + {63, 953, 0, L"Яссы"}, + {63, 2508, 0, L"Другое"}, + {64, 956, 0, L"Сан-Марино"}, + {64, 2507, 0, L"Другое"}, + {74, 957, 0, L"Белград"}, + {74, 960, 0, L"Ниш"}, + {74, 958, 0, L"Нови-Сад"}, + {74, 959, 0, L"Сараево"}, + {74, 2506, 0, L"Другое"}, + {65, 961, 0, L"Братислава"}, + {65, 962, 0, L"Кошице"}, + {65, 3101, 0, L"Липтов"}, + {65, 963, 0, L"Попрад"}, + {65, 964, 0, L"Прешов"}, + {65, 965, 0, L"Ружемберок"}, + {65, 966, 0, L"Тврдошин"}, + {65, 2505, 0, L"Другое"}, + {66, 968, 0, L"Копар"}, + {66, 967, 0, L"Любляна"}, + {66, 969, 0, L"Марибор"}, + {66, 2504, 0, L"Другое"}, + {67, 970, 0, L"Торсхавн"}, + {67, 2503, 0, L"Другое"}, + {68, 2888, 0, L"Вантаа"}, + {68, 971, 0, L"Васа"}, + {68, 979, 0, L"Котка"}, + {68, 972, 0, L"Коувола"}, + {68, 980, 0, L"Лахти"}, + {68, 973, 0, L"Оулу"}, + {68, 3375, 0, L"Риихимяки"}, + {68, 3159, 0, L"Руовеси"}, + {68, 974, 0, L"Тампере"}, + {68, 975, 0, L"Турку"}, + {68, 976, 0, L"Хельсинки"}, + {68, 977, 0, L"Эспо"}, + {68, 978, 0, L"Ювяскюля"}, + {68, 2502, 0, L"Другое"}, + {37, 996, 0, L"Авиньон"}, + {37, 983, 0, L"Бержерак"}, + {37, 997, 0, L"Блуа"}, + {37, 984, 0, L"Бордо"}, + {37, 998, 0, L"Дижон"}, + {37, 987, 0, L"Канн"}, + {37, 988, 0, L"Кастр"}, + {37, 993, 0, L"Клермон-Ферран"}, + {37, 3037, 0, L"Лилль"}, + {37, 989, 0, L"Лион"}, + {37, 985, 0, L"Марсель"}, + {37, 991, 0, L"Мец"}, + {37, 3161, 0, L"Мобеж"}, + {37, 990, 0, L"Нанси"}, + {37, 994, 0, L"Нант"}, + {37, 995, 0, L"Ницца"}, + {37, 999, 0, L"Орлеан"}, + {37, 981, 0, L"Париж"}, + {37, 3374, 0, L"Перпиньян"}, + {37, 992, 0, L"Руан"}, + {37, 982, 0, L"Страсбург"}, + {37, 986, 0, L"Тулуза"}, + {37, 3314, 0, L"Шамбери"}, + {37, 2501, 0, L"Другое"}, + {69, 1003, 0, L"Дубровник"}, + {69, 1000, 0, L"Загреб"}, + {69, 1001, 0, L"Задар"}, + {69, 1004, 0, L"Риека"}, + {69, 1002, 0, L"Сплит"}, + {69, 2500, 0, L"Другое"}, + {70, 1005, 0, L"Брно"}, + {70, 3291, 0, L"Гавличкув-Брод"}, + {70, 1007, 0, L"Градец-Кралове"}, + {70, 1008, 0, L"Карлови-Вари"}, + {70, 3019, 0, L"Кладрубы"}, + {70, 1010, 0, L"Лоуни"}, + {70, 1009, 0, L"Острава"}, + {70, 1015, 0, L"Пльзень"}, + {70, 3105, 0, L"Правчицка Брана"}, + {70, 1006, 0, L"Прага"}, + {70, 3246, 0, L"Тачов"}, + {70, 1011, 0, L"Тршебич"}, + {70, 1012, 0, L"Усти-над-Лабем"}, + {70, 1014, 0, L"Ческе-Будеевице"}, + {70, 1013, 0, L"Яблонец-над-Нисоу"}, + {70, 2499, 0, L"Другое"}, + {71, 1016, 0, L"Арау"}, + {71, 1019, 0, L"Баден"}, + {71, 1017, 0, L"Базель"}, + {71, 1018, 0, L"Берн"}, + {71, 1020, 0, L"Биль"}, + {71, 1021, 0, L"Винтертур"}, + {71, 1022, 0, L"Давос"}, + {71, 3189, 0, L"Делемонт"}, + {71, 1023, 0, L"Женева"}, + {71, 1024, 0, L"Золотурн"}, + {71, 1025, 0, L"Лозанна"}, + {71, 1026, 0, L"Локарно"}, + {71, 1027, 0, L"Лугано"}, + {71, 1028, 0, L"Люцерн"}, + {71, 1029, 0, L"Монтре"}, + {71, 1030, 0, L"Цюрих"}, + {71, 2498, 0, L"Другое"}, + {72, 2883, 0, L"Арбога"}, + {72, 1031, 0, L"Гетеборг"}, + {72, 1032, 0, L"Кальмар"}, + {72, 1037, 0, L"Лахольм"}, + {72, 1036, 0, L"Лулео"}, + {72, 1042, 0, L"Лунд"}, + {72, 1033, 0, L"Мальме"}, + {72, 1034, 0, L"Стокгольм"}, + {72, 1041, 0, L"Умео"}, + {72, 1039, 0, L"Фалун"}, + {72, 1043, 0, L"Хельсинборг"}, + {72, 1040, 0, L"Хернесанд"}, + {72, 1038, 0, L"Эстерсунд"}, + {72, 2497, 0, L"Другое"}, + {73, 3013, 0, L"Валга"}, + {73, 1044, 0, L"Кейла"}, + {73, 1045, 0, L"Кохтла-Ярве"}, + {73, 1046, 0, L"Маарду"}, + {73, 1047, 0, L"Мыйзакюла"}, + {73, 1048, 0, L"Нарва"}, + {73, 1049, 0, L"Пярну"}, + {73, 1050, 0, L"Раквере"}, + {73, 1051, 0, L"Силламяэ"}, + {73, 1052, 0, L"Таллин"}, + {73, 1053, 0, L"Тарту"}, + {73, 1054, 0, L"Хаапсалу"}, + {24, 233, 474, L"Алдан"}, + {24, 233, 2809, L"Верхоянск"}, + {24, 233, 2804, L"Вилюйск"}, + {24, 233, 475, L"Ленск"}, + {24, 233, 477, L"Мирный"}, + {24, 233, 476, L"Нерюнгри"}, + {24, 233, 2806, L"Олекминск"}, + {24, 233, 3115, L"Покровск"}, + {24, 233, 2808, L"Среднеколымск"}, + {24, 233, 2807, L"Томмот"}, + {24, 233, 2805, L"Удачный"}, + {24, 233, 478, L"Усть-Нера"}, + {24, 233, 479, L"Якутск"}, + {24, 233, 2263, L"Другое"}, + {24, 232, 2819, L"Арсеньев"}, + {24, 232, 464, L"Артем"}, + {24, 232, 465, L"Большой Камень"}, + {24, 232, 466, L"Владивосток"}, + {24, 232, 2817, L"Дальнегорск"}, + {24, 232, 2818, L"Дальнереченск"}, + {24, 232, 3359, L"Кавалерово"}, + {24, 232, 467, L"Камень-Рыболов"}, + {24, 232, 468, L"Лесозаводск"}, + {24, 232, 469, L"Лучегорск"}, + {24, 232, 470, L"Находка"}, + {24, 232, 471, L"Партизанск"}, + {24, 232, 472, L"Пластун"}, + {24, 232, 2816, L"Спасск-Дальний"}, + {24, 232, 473, L"Уссурийск"}, + {24, 232, 2258, L"Другое"}, + {24, 235, 487, L"Амурск"}, + {24, 235, 2821, L"Бикин"}, + {24, 235, 488, L"Ванино"}, + {24, 235, 2820, L"Вяземский"}, + {24, 235, 489, L"Комсомольск-на-Амуре"}, + {24, 235, 490, L"Николаевск-на-Амуре"}, + {24, 235, 491, L"Советская Гавань"}, + {24, 235, 3353, L"Солнечный"}, + {24, 235, 492, L"Хабаровск"}, + {24, 235, 2280, L"Другое"}, + {24, 227, 455, L"Белогорск"}, + {24, 227, 456, L"Благовещенск"}, + {24, 227, 2814, L"Завитинск"}, + {24, 227, 2813, L"Зея"}, + {24, 227, 2815, L"Райчихинск"}, + {24, 227, 2812, L"Свободный"}, + {24, 227, 2811, L"Сковородино"}, + {24, 227, 457, L"Тында"}, + {24, 227, 2217, L"Шимановск"}, + {24, 227, 2218, L"Другое"}, + {24, 229, 460, L"Елизово"}, + {24, 229, 2822, L"Ключи"}, + {24, 229, 459, L"Петропавловск-Камч."}, + {24, 229, 2234, L"Другое"}, + {24, 231, 462, L"Магадан"}, + {24, 231, 2823, L"Сусуман"}, + {24, 231, 463, L"Ягодное"}, + {24, 231, 2246, L"Другое"}, + {24, 234, 480, L"Александровск-Сахалинский"}, + {24, 234, 2829, L"Анива"}, + {24, 234, 2833, L"Горнозаводск"}, + {24, 234, 2825, L"Долинск"}, + {24, 234, 481, L"Корсаков"}, + {24, 234, 482, L"Красногорск"}, + {24, 234, 2826, L"Курильск"}, + {24, 234, 2832, L"Лесогорск"}, + {24, 234, 2836, L"Макаров"}, + {24, 234, 2830, L"Невельск"}, + {24, 234, 483, L"Оха"}, + {24, 234, 2828, L"Поронайск"}, + {24, 234, 2824, L"Северо-Курильск"}, + {24, 234, 2827, L"Томари"}, + {24, 234, 2831, L"Углегорск"}, + {24, 234, 484, L"Холмск"}, + {24, 234, 2834, L"Чехов"}, + {24, 234, 2835, L"Шахтерск"}, + {24, 234, 485, L"Южно-Курильск"}, + {24, 234, 486, L"Южно-Сахалинск"}, + {24, 234, 2264, L"Другое"}, + {24, 228, 458, L"Биробиджан"}, + {24, 228, 2810, L"Облучье"}, + {24, 228, 2226, L"Другое"}, + {24, 230, 461, L"Полана"}, + {24, 230, 2239, L"Другое"}, + {24, 236, 493, L"Анадырь"}, + {24, 236, 2287, L"Другое"}, + {24, 237, 2850, L"Агидель"}, + {24, 237, 2851, L"Агидель"}, + {24, 237, 2657, L"Баймак"}, + {24, 237, 2662, L"Белебей"}, + {24, 237, 494, L"Белорецк"}, + {24, 237, 2658, L"Бирск"}, + {24, 237, 2660, L"Благовещенск"}, + {24, 237, 2659, L"Давлеканово"}, + {24, 237, 2663, L"Дюртюли"}, + {24, 237, 495, L"Ишимбай"}, + {24, 237, 496, L"Кумертау"}, + {24, 237, 2655, L"Мелеуз"}, + {24, 237, 497, L"Нефтекамск"}, + {24, 237, 2654, L"Октябрьский"}, + {24, 237, 499, L"Салават"}, + {24, 237, 2656, L"Сибай"}, + {24, 237, 498, L"Стерлитамак"}, + {24, 237, 500, L"Туймазы"}, + {24, 237, 2661, L"Туймазы"}, + {24, 237, 501, L"Уфа"}, + {24, 237, 502, L"Учалы"}, + {24, 237, 2664, L"Янаул"}, + {24, 237, 2220, L"Другое"}, + {24, 240, 509, L"Волжск"}, + {24, 240, 510, L"Звенигово"}, + {24, 240, 511, L"Йошкар-Ола"}, + {24, 240, 512, L"Козьмодемьянск"}, + {24, 240, 2247, L"Другое"}, + {24, 241, 513, L"Зубова Поляна"}, + {24, 241, 2147, L"Инсар"}, + {24, 241, 2150, L"Ковылкино"}, + {24, 241, 2148, L"Краснослободск"}, + {24, 241, 2910, L"Лямбирь"}, + {24, 241, 515, L"Рузаевка"}, + {24, 241, 514, L"Саранск"}, + {24, 241, 2149, L"Темников"}, + {24, 241, 2923, L"Чамзинка"}, + {24, 241, 2248, L"Другое"}, + {24, 248, 2569, L"Агрыз"}, + {24, 248, 2575, L"Азнакаево"}, + {24, 248, 569, L"Альметьевск"}, + {24, 248, 570, L"Апастово"}, + {24, 248, 2571, L"Болгар"}, + {24, 248, 571, L"Бугульма"}, + {24, 248, 2570, L"Буинск"}, + {24, 248, 572, L"Джалиль"}, + {24, 248, 573, L"Елабуга"}, + {24, 248, 2576, L"Заинск"}, + {24, 248, 574, L"Зеленодольск"}, + {24, 248, 575, L"Казань"}, + {24, 248, 2577, L"Лениногорск"}, + {24, 248, 2572, L"Мамадыш"}, + {24, 248, 576, L"Менделеевск"}, + {24, 248, 2573, L"Мензелинск"}, + {24, 248, 577, L"Набережные Челны"}, + {24, 248, 578, L"Нижнекамск"}, + {24, 248, 579, L"Нурлат"}, + {24, 248, 2574, L"Тетюши"}, + {24, 248, 580, L"Чистополь"}, + {24, 248, 2271, L"Другое"}, + {24, 249, 3311, L"Вавож"}, + {24, 249, 581, L"Воткинск"}, + {24, 249, 582, L"Глазов"}, + {24, 249, 583, L"Игра"}, + {24, 249, 584, L"Ижевск"}, + {24, 249, 2665, L"Камбарка"}, + {24, 249, 585, L"Можга"}, + {24, 249, 586, L"Сарапул"}, + {24, 249, 587, L"Ува"}, + {24, 249, 2277, L"Другое"}, + {24, 251, 2158, L"Алатырь"}, + {24, 251, 2156, L"Канаш"}, + {24, 251, 2151, L"Козловка"}, + {24, 251, 2152, L"Марьинский Посад"}, + {24, 251, 2155, L"Новочебоксарск"}, + {24, 251, 2153, L"Цивильск"}, + {24, 251, 592, L"Чебоксары"}, + {24, 251, 2157, L"Шумерля"}, + {24, 251, 2154, L"Ядрин"}, + {24, 251, 2286, L"Другое"}, + {24, 238, 2168, L"Белая Холуница"}, + {24, 238, 503, L"Вятские Поляны"}, + {24, 238, 2164, L"Зуевка"}, + {24, 238, 504, L"Киров"}, + {24, 238, 505, L"Кирово-Чепецк"}, + {24, 238, 2160, L"Кирс"}, + {24, 238, 506, L"Котельнич"}, + {24, 238, 2167, L"Луза"}, + {24, 238, 2159, L"Малмыж"}, + {24, 238, 2169, L"Мураши"}, + {24, 238, 2163, L"Нолинск"}, + {24, 238, 2170, L"Омутнинск"}, + {24, 238, 2166, L"Слободской"}, + {24, 238, 2165, L"Советск"}, + {24, 238, 2162, L"Сосновка"}, + {24, 238, 2171, L"Уржум"}, + {24, 238, 2161, L"Халтурин"}, + {24, 238, 507, L"Яранск"}, + {24, 238, 2237, L"Другое"}, + {24, 242, 516, L"Арзамас"}, + {24, 242, 517, L"Балахна"}, + {24, 242, 2139, L"Богородск"}, + {24, 242, 518, L"Бор"}, + {24, 242, 519, L"Вахтан"}, + {24, 242, 520, L"Ветлуга"}, + {24, 242, 2140, L"Володарск"}, + {24, 242, 2138, L"Ворсма"}, + {24, 242, 521, L"Выкса"}, + {24, 242, 2137, L"Горбатов"}, + {24, 242, 522, L"Городец"}, + {24, 242, 523, L"Дзержинск"}, + {24, 242, 524, L"Заволжье"}, + {24, 242, 2891, L"Ильиногорск"}, + {24, 242, 525, L"Кстово"}, + {24, 242, 2145, L"Кулебаки"}, + {24, 242, 2143, L"Лукоянов"}, + {24, 242, 2144, L"Лысково"}, + {24, 242, 2146, L"Навашино"}, + {24, 242, 526, L"Нижний Новгород"}, + {24, 242, 527, L"Павлово"}, + {24, 242, 2135, L"Первомайск"}, + {24, 242, 528, L"Саров"}, + {24, 242, 529, L"Семенов"}, + {24, 242, 530, L"Сергач"}, + {24, 242, 2141, L"Урень"}, + {24, 242, 2136, L"Чкаловск"}, + {24, 242, 2897, L"Шатки"}, + {24, 242, 2142, L"Шахунья"}, + {24, 242, 2251, L"Другое"}, + {24, 243, 2678, L"Абдулино"}, + {24, 243, 2673, L"Бугуруслан"}, + {24, 243, 531, L"Бузулук"}, + {24, 243, 532, L"Гай"}, + {24, 243, 2674, L"Кувандык"}, + {24, 243, 2675, L"Медногорск"}, + {24, 243, 533, L"Новотроицк"}, + {24, 243, 535, L"Оренбург"}, + {24, 243, 536, L"Орск"}, + {24, 243, 3360, L"Саракташ"}, + {24, 243, 2677, L"Соль-Илецк"}, + {24, 243, 2676, L"Сорочинск"}, + {24, 243, 537, L"Тоцкое"}, + {24, 243, 538, L"Ясный"}, + {24, 243, 2254, L"Другое"}, + {24, 244, 539, L"Беднодемьяновск"}, + {24, 244, 2597, L"Белинский"}, + {24, 244, 2595, L"Городище"}, + {24, 244, 2593, L"Каменка"}, + {24, 244, 540, L"Кузнецк"}, + {24, 244, 2598, L"Нижний Ломов"}, + {24, 244, 2592, L"Никольск"}, + {24, 244, 541, L"Пенза"}, + {24, 244, 3304, L"Русский Камешкир"}, + {24, 244, 2596, L"Сердобск"}, + {24, 244, 2594, L"Сурск"}, + {24, 244, 2256, L"Другое"}, + {24, 245, 2690, L"Александровск"}, + {24, 245, 542, L"Березники"}, + {24, 245, 2679, L"Верещагино"}, + {24, 245, 2680, L"Горнозаводск"}, + {24, 245, 2687, L"Гремячинск"}, + {24, 245, 2686, L"Губаха"}, + {24, 245, 543, L"Добрянка"}, + {24, 245, 544, L"Кизел"}, + {24, 245, 2681, L"Красновишерск"}, + {24, 245, 545, L"Краснокамск"}, + {24, 245, 546, L"Кунгур"}, + {24, 245, 547, L"Лысьва"}, + {24, 245, 548, L"Нытва"}, + {24, 245, 2683, L"Оса"}, + {24, 245, 2684, L"Оханск"}, + {24, 245, 2682, L"Очер"}, + {24, 245, 549, L"Пермь"}, + {24, 245, 550, L"Соликамск"}, + {24, 245, 2685, L"Усолье"}, + {24, 245, 551, L"Чайковский"}, + {24, 245, 2689, L"Чердынь"}, + {24, 245, 2688, L"Чермоз"}, + {24, 245, 552, L"Чернушка"}, + {24, 245, 553, L"Чусовой"}, + {24, 245, 2257, L"Другое"}, + {24, 246, 554, L"Волжский"}, + {24, 246, 555, L"Жигулевск"}, + {24, 246, 2599, L"Кинель"}, + {24, 246, 3293, L"Красный Яр"}, + {24, 246, 2602, L"Нефтегорск"}, + {24, 246, 556, L"Новокуйбышевск"}, + {24, 246, 2600, L"Октябрьск"}, + {24, 246, 557, L"Отрадный"}, + {24, 246, 558, L"Похвистнево"}, + {24, 246, 559, L"Самара"}, + {24, 246, 560, L"Сызрань"}, + {24, 246, 561, L"Тольятти"}, + {24, 246, 2601, L"Чапаевск"}, + {24, 246, 562, L"Шигоны"}, + {24, 246, 2261, L"Другое"}, + {24, 247, 2613, L"Аркадак"}, + {24, 247, 2606, L"Аткарск"}, + {24, 247, 563, L"Балаково"}, + {24, 247, 564, L"Балашов"}, + {24, 247, 565, L"Вольск"}, + {24, 247, 2608, L"Ершов"}, + {24, 247, 2607, L"Калининск"}, + {24, 247, 2609, L"Красноармейск"}, + {24, 247, 2610, L"Красный Кут"}, + {24, 247, 2605, L"Маркс"}, + {24, 247, 566, L"Новоузенск"}, + {24, 247, 2603, L"Петровск"}, + {24, 247, 2604, L"Пугачев"}, + {24, 247, 2612, L"Ртищево"}, + {24, 247, 567, L"Саратов"}, + {24, 247, 2611, L"Хвалынск"}, + {24, 247, 568, L"Энгельс"}, + {24, 247, 3267, L"Энгельс-12"}, + {24, 247, 2262, L"Другое"}, + {24, 250, 2614, L"Барыш"}, + {24, 250, 588, L"Димитровград"}, + {24, 250, 2615, L"Инза"}, + {24, 250, 589, L"Новоспасское"}, + {24, 250, 2616, L"Новоульяновск"}, + {24, 250, 590, L"Сенгилей"}, + {24, 250, 591, L"Ульяновск"}, + {24, 250, 2278, L"Другое"}, + {24, 239, 508, L"Кудымкар"}, + {24, 239, 2238, L"Другое"}, + {24, 255, 1355, L"Беломорск"}, + {24, 255, 1356, L"Кемь"}, + {24, 255, 1357, L"Кондопога"}, + {24, 255, 1358, L"Костомукша"}, + {24, 255, 1359, L"Коткозеро"}, + {24, 255, 1360, L"Лахденпохья"}, + {24, 255, 1362, L"Лоухи"}, + {24, 255, 1361, L"Медвежьегорск"}, + {24, 255, 3286, L"Муезерский"}, + {24, 255, 1937, L"Олонец"}, + {24, 255, 1363, L"Петрозаводск"}, + {24, 255, 1938, L"Питкяранта"}, + {24, 255, 3287, L"Пряжа"}, + {24, 255, 1936, L"Пудож"}, + {24, 255, 1364, L"Сегежа"}, + {24, 255, 1365, L"Сортавала"}, + {24, 255, 1939, L"Суоярви"}, + {24, 255, 2201, L"Другое"}, + {24, 256, 1366, L"Воркута"}, + {24, 256, 1367, L"Вуктыл"}, + {24, 256, 2202, L"Емва"}, + {24, 256, 1368, L"Инта"}, + {24, 256, 1940, L"Микунь"}, + {24, 256, 1369, L"Печора"}, + {24, 256, 1941, L"Сосногорск"}, + {24, 256, 1370, L"Сыктывкар"}, + {24, 256, 1371, L"Усинск"}, + {24, 256, 1372, L"Ухта"}, + {24, 256, 2203, L"Другое"}, + {24, 252, 593, L"Архангельск"}, + {24, 252, 594, L"Вельск"}, + {24, 252, 1945, L"Каргополь"}, + {24, 252, 595, L"Коряжма"}, + {24, 252, 596, L"Котлас"}, + {24, 252, 1944, L"Мезень"}, + {24, 252, 597, L"Мирный"}, + {24, 252, 598, L"Новодвинск"}, + {24, 252, 1946, L"Няндома"}, + {24, 252, 599, L"Онега"}, + {24, 252, 600, L"Пинега"}, + {24, 252, 601, L"Северодвинск"}, + {24, 252, 1942, L"Сольвычегодск"}, + {24, 252, 3239, L"Холмогоры"}, + {24, 252, 1943, L"Шенкурск"}, + {24, 252, 2204, L"Другое"}, + {24, 253, 1950, L"Бабаево"}, + {24, 253, 1949, L"Белозерск"}, + {24, 253, 1338, L"Великий Устюг"}, + {24, 253, 1339, L"Вологда"}, + {24, 253, 1951, L"Вытегра"}, + {24, 253, 1340, L"Грязовец"}, + {24, 253, 1952, L"Кадников"}, + {24, 253, 2871, L"Кадуй"}, + {24, 253, 1341, L"Кириллов"}, + {24, 253, 1955, L"Красавино"}, + {24, 253, 1342, L"Михайловка"}, + {24, 253, 1947, L"Никольск"}, + {24, 253, 1343, L"Сокол"}, + {24, 253, 1953, L"Тотьма"}, + {24, 253, 1954, L"Устюжна"}, + {24, 253, 1948, L"Харовск"}, + {24, 253, 1344, L"Череповец"}, + {24, 253, 2205, L"Другое"}, + {24, 254, 2838, L"Багратионовск"}, + {24, 254, 1345, L"Балтийск"}, + {24, 254, 2846, L"Гвардейск"}, + {24, 254, 2843, L"Гурьевск"}, + {24, 254, 1346, L"Гусев"}, + {24, 254, 1347, L"Зеленоградск"}, + {24, 254, 1348, L"Калининград"}, + {24, 254, 2842, L"Краснознаменск"}, + {24, 254, 2845, L"Ладушкин"}, + {24, 254, 2848, L"Мамоново"}, + {24, 254, 2837, L"Неман"}, + {24, 254, 2844, L"Нестеров"}, + {24, 254, 1349, L"Озерск"}, + {24, 254, 2841, L"Полесск"}, + {24, 254, 2839, L"Правдинск"}, + {24, 254, 1350, L"Приморск"}, + {24, 254, 1351, L"Светлогорск"}, + {24, 254, 1352, L"Светлый"}, + {24, 254, 2840, L"Славск"}, + {24, 254, 1353, L"Советск"}, + {24, 254, 1354, L"Черняховск"}, + {24, 254, 2231, L"Другое"}, + {24, 257, 1985, L"Бокситогорск"}, + {24, 257, 1374, L"Волхов"}, + {24, 257, 1373, L"Всеволожск"}, + {24, 257, 1375, L"Выборг"}, + {24, 257, 1995, L"Высоцк"}, + {24, 257, 1376, L"Гатчина"}, + {24, 257, 1378, L"Ивангород"}, + {24, 257, 1993, L"Каменногорск"}, + {24, 257, 1379, L"Кингисепп"}, + {24, 257, 1380, L"Кириши"}, + {24, 257, 1381, L"Кировск"}, + {24, 257, 1384, L"Кузьмоловский"}, + {24, 257, 1984, L"Лодейное Поле"}, + {24, 257, 1990, L"Луга"}, + {24, 257, 1994, L"Любань"}, + {24, 257, 1386, L"Никольское"}, + {24, 257, 1987, L"Новая Ладога"}, + {24, 257, 1996, L"Отрадное"}, + {24, 257, 1986, L"Пикалево"}, + {24, 257, 1983, L"Подпорожье"}, + {24, 257, 1992, L"Приморск"}, + {24, 257, 1988, L"Приозерск"}, + {24, 257, 3071, L"Пушкин"}, + {24, 257, 1989, L"Светогорск"}, + {24, 257, 1389, L"Сертолово"}, + {24, 257, 1991, L"Сланцы"}, + {24, 257, 1391, L"Сосновый Бор"}, + {24, 257, 1392, L"Тихвин"}, + {24, 257, 1393, L"Тосно"}, + {24, 257, 1394, L"Шлиссельбург"}, + {24, 257, 2207, L"Другое"}, + {24, 258, 1395, L"Апатиты"}, + {24, 258, 1959, L"Заполярный"}, + {24, 258, 1396, L"Зареченск"}, + {24, 258, 1397, L"Кандалакша"}, + {24, 258, 1398, L"Кировск"}, + {24, 258, 1399, L"Ковдор"}, + {24, 258, 1958, L"Кола"}, + {24, 258, 1400, L"Мончегорск"}, + {24, 258, 1401, L"Мурманск"}, + {24, 258, 1402, L"Мурмаши"}, + {24, 258, 1403, L"Оленегорск"}, + {24, 258, 1404, L"Полярные Зори"}, + {24, 258, 1956, L"Полярный"}, + {24, 258, 1957, L"Североморск"}, + {24, 258, 3288, L"Снежногорск"}, + {24, 258, 2206, L"Другое"}, + {24, 260, 1406, L"Батецкий"}, + {24, 260, 2001, L"Боровичи"}, + {24, 260, 2003, L"Валдай"}, + {24, 260, 1407, L"Великий Новгород"}, + {24, 260, 1408, L"Крестцы"}, + {24, 260, 2002, L"Малая Вишера"}, + {24, 260, 1409, L"Окуловка"}, + {24, 260, 2000, L"Пестово"}, + {24, 260, 1997, L"Сольцы"}, + {24, 260, 1410, L"Старая Русса"}, + {24, 260, 1998, L"Холм"}, + {24, 260, 1999, L"Чудово"}, + {24, 260, 2208, L"Другое"}, + {24, 261, 1412, L"Великие Луки"}, + {24, 261, 2004, L"Гдов"}, + {24, 261, 2009, L"Дно"}, + {24, 261, 2005, L"Невель"}, + {24, 261, 1413, L"Новоржев"}, + {24, 261, 2006, L"Опочка"}, + {24, 261, 2008, L"Остров"}, + {24, 261, 1414, L"Печоры"}, + {24, 261, 1415, L"Порхов"}, + {24, 261, 1411, L"Псков"}, + {24, 261, 1416, L"Пустошка"}, + {24, 261, 2007, L"Пыталово"}, + {24, 261, 1417, L"Себеж"}, + {24, 261, 2209, L"Другое"}, + {24, 259, 1405, L"Нарьян-Мар"}, + {24, 259, 2250, L"Другое"}, + {24, 265, 2764, L"Бабушкин"}, + {24, 265, 2760, L"Гусиноозерск"}, + {24, 265, 2762, L"Закаменск"}, + {24, 265, 2763, L"Кяхта"}, + {24, 265, 2761, L"Северобайкальск"}, + {24, 265, 1446, L"Улан-Удэ"}, + {24, 265, 2222, L"Другое"}, + {24, 263, 1439, L"Горно-Алтайск"}, + {24, 263, 2215, L"Другое"}, + {24, 273, 2766, L"Ак-Довурак"}, + {24, 273, 1494, L"Кызыл"}, + {24, 273, 2768, L"Новый Шагонар"}, + {24, 273, 2767, L"Туран"}, + {24, 273, 2765, L"Чадан"}, + {24, 273, 2275, L"Другое"}, + {24, 275, 2769, L"Абаза"}, + {24, 275, 1496, L"Абакан"}, + {24, 275, 1497, L"Саяногорск"}, + {24, 275, 2770, L"Сорск"}, + {24, 275, 2771, L"Черногорск"}, + {24, 275, 2281, L"Другое"}, + {24, 264, 1440, L"Алейск"}, + {24, 264, 1441, L"Барнаул"}, + {24, 264, 1442, L"Белокуриха"}, + {24, 264, 1443, L"Бийск"}, + {24, 264, 2728, L"Горняк"}, + {24, 264, 2731, L"Заринск"}, + {24, 264, 2729, L"Змеиногорск"}, + {24, 264, 2732, L"Камень-на-Оби"}, + {24, 264, 3292, L"Кулунда"}, + {24, 264, 2730, L"Новоалтайск"}, + {24, 264, 1444, L"Рубцовск"}, + {24, 264, 1445, L"Славгород"}, + {24, 264, 3231, L"Яровое"}, + {24, 264, 2216, L"Другое"}, + {24, 268, 2781, L"Артемовск"}, + {24, 268, 1469, L"Ачинск"}, + {24, 268, 2784, L"Боготол"}, + {24, 268, 2773, L"Бородино"}, + {24, 268, 2774, L"Дивногорск"}, + {24, 268, 3122, L"Емельяновск"}, + {24, 268, 2772, L"Енисейск"}, + {24, 268, 3294, L"Железногорск"}, + {24, 268, 2777, L"Заозерный"}, + {24, 268, 1470, L"Игарка"}, + {24, 268, 2778, L"Иланский"}, + {24, 268, 2782, L"Канск"}, + {24, 268, 2783, L"Кодинский"}, + {24, 268, 1471, L"Красноярск"}, + {24, 268, 1472, L"Лесосибирск"}, + {24, 268, 1473, L"Минусинск"}, + {24, 268, 2775, L"Назарово"}, + {24, 268, 2776, L"Сосновоборск"}, + {24, 268, 2780, L"Ужур"}, + {24, 268, 2779, L"Уяр"}, + {24, 268, 2785, L"Шарыпово"}, + {24, 268, 1474, L"Шушенское"}, + {24, 268, 2242, L"Другое"}, + {24, 266, 2792, L"Алзамай"}, + {24, 266, 1447, L"Ангарск"}, + {24, 266, 1448, L"Байкальск"}, + {24, 266, 2791, L"Бирюсинск"}, + {24, 266, 1450, L"Бодайбо"}, + {24, 266, 1451, L"Братск"}, + {24, 266, 2793, L"Вихоревка"}, + {24, 266, 2789, L"Железногорск-Илимский"}, + {24, 266, 2786, L"Зима"}, + {24, 266, 1452, L"Иркутск"}, + {24, 266, 2794, L"Киренск"}, + {24, 266, 2787, L"Нижнеудинск"}, + {24, 266, 1449, L"Саянск"}, + {24, 266, 2790, L"Свирск"}, + {24, 266, 1453, L"Слюдянка"}, + {24, 266, 2788, L"Тайшет"}, + {24, 266, 1454, L"Тулун"}, + {24, 266, 1455, L"Усолье-Сибирское"}, + {24, 266, 2908, L"Усольск"}, + {24, 266, 1456, L"Усть-Илимск"}, + {24, 266, 1457, L"Усть-Кут"}, + {24, 266, 1458, L"Хужир"}, + {24, 266, 1459, L"Черемхово"}, + {24, 266, 2795, L"Шелехов"}, + {24, 266, 2229, L"Другое"}, + {24, 267, 2737, L"Анжеро-Суджинск"}, + {24, 267, 2740, L"Белово"}, + {24, 267, 2746, L"Березовский"}, + {24, 267, 2739, L"Гурьевск"}, + {24, 267, 2742, L"Калтан"}, + {24, 267, 1460, L"Кемерово"}, + {24, 267, 1461, L"Киселевск"}, + {24, 267, 2738, L"Ленинск-Кузнецкий"}, + {24, 267, 2745, L"Мариинск"}, + {24, 267, 1462, L"Междуреченск"}, + {24, 267, 1463, L"Мыски"}, + {24, 267, 1464, L"Новокузнецк"}, + {24, 267, 2744, L"Осинники"}, + {24, 267, 3358, L"Полысаево"}, + {24, 267, 1465, L"Прокопьевск"}, + {24, 267, 1466, L"Салаир"}, + {24, 267, 2743, L"Тайга"}, + {24, 267, 2741, L"Таштагол"}, + {24, 267, 1467, L"Топки"}, + {24, 267, 1468, L"Юрга"}, + {24, 267, 2236, L"Другое"}, + {24, 269, 1475, L"Баган"}, + {24, 269, 1476, L"Барабинск"}, + {24, 269, 1477, L"Бердск"}, + {24, 269, 2750, L"Болотное"}, + {24, 269, 1478, L"Искитим"}, + {24, 269, 2752, L"Карасук"}, + {24, 269, 2751, L"Каргат"}, + {24, 269, 3107, L"Краснообск"}, + {24, 269, 2753, L"Куйбышев"}, + {24, 269, 2755, L"Купино"}, + {24, 269, 1479, L"Новосибирск"}, + {24, 269, 2759, L"Обь"}, + {24, 269, 2756, L"Татарск"}, + {24, 269, 2758, L"Тогучин"}, + {24, 269, 2757, L"Черепаново"}, + {24, 269, 2754, L"Чулым"}, + {24, 269, 2252, L"Другое"}, + {24, 270, 2733, L"Исилькуль"}, + {24, 270, 1480, L"Калачинск"}, + {24, 270, 1481, L"Марьяновка"}, + {24, 270, 2735, L"Называевск"}, + {24, 270, 1482, L"Омск"}, + {24, 270, 2734, L"Тара"}, + {24, 270, 2736, L"Тюкалинск"}, + {24, 270, 2253, L"Другое"}, + {24, 272, 1488, L"Асино"}, + {24, 272, 1489, L"Белый Яр"}, + {24, 272, 3295, L"Каргасок"}, + {24, 272, 1491, L"Колпашево"}, + {24, 272, 1492, L"Северск"}, + {24, 272, 1493, L"Стрежевой"}, + {24, 272, 1490, L"Томск"}, + {24, 272, 2273, L"Другое"}, + {24, 276, 2803, L"Балей"}, + {24, 276, 2799, L"Борзя"}, + {24, 276, 1499, L"Краснокаменск"}, + {24, 276, 2801, L"Могоча"}, + {24, 276, 2800, L"Нерчинск"}, + {24, 276, 2802, L"Петровск-Забайкальский"}, + {24, 276, 2798, L"Сретенск"}, + {24, 276, 2796, L"Хилок"}, + {24, 276, 1498, L"Чита"}, + {24, 276, 2797, L"Шилка"}, + {24, 276, 2285, L"Другое"}, + {24, 262, 1438, L"Агинское"}, + {24, 262, 2213, L"Другое"}, + {24, 271, 3233, L"Диксон"}, + {24, 271, 1485, L"Дудинка"}, + {24, 271, 1487, L"Кайеркан"}, + {24, 271, 1483, L"Норильск"}, + {24, 271, 1484, L"Талнах"}, + {24, 271, 1486, L"Хатанга"}, + {24, 271, 2269, L"Другое"}, + {24, 274, 1495, L"Усть-Ордынский"}, + {24, 274, 2279, L"Другое"}, + {24, 277, 1500, L"Тура"}, + {24, 277, 2288, L"Другое"}, + {24, 278, 2668, L"Далматово"}, + {24, 278, 2667, L"Катайск"}, + {24, 278, 1524, L"Курган"}, + {24, 278, 2669, L"Куртамыш"}, + {24, 278, 2666, L"Макушино"}, + {24, 278, 2671, L"Петухово"}, + {24, 278, 1525, L"Шадринск"}, + {24, 278, 2670, L"Шумиха"}, + {24, 278, 2672, L"Щучье"}, + {24, 278, 2243, L"Другое"}, + {24, 279, 1526, L"Алапаевск"}, + {24, 279, 1527, L"Арамиль"}, + {24, 279, 2691, L"Артемовский"}, + {24, 279, 1528, L"Асбест"}, + {24, 279, 2924, L"Белоярский"}, + {24, 279, 2707, L"Березовский"}, + {24, 279, 1529, L"Богданович"}, + {24, 279, 2698, L"Верхний Тагил"}, + {24, 279, 1530, L"Верхняя Пышма"}, + {24, 279, 1531, L"Верхняя Салда"}, + {24, 279, 1532, L"Верхняя Синячиха"}, + {24, 279, 2696, L"Верхняя Тура"}, + {24, 279, 2692, L"Верхотурье"}, + {24, 279, 2706, L"Волчанск"}, + {24, 279, 2709, L"Дегтярск"}, + {24, 279, 1533, L"Екатеринбург"}, + {24, 279, 1534, L"Заречный"}, + {24, 279, 1535, L"Ивдель"}, + {24, 279, 1536, L"Ирбит"}, + {24, 279, 1537, L"Каменск-Уральский"}, + {24, 279, 1538, L"Камышлов"}, + {24, 279, 2708, L"Карпинск"}, + {24, 279, 1539, L"Качканар"}, + {24, 279, 2712, L"Кировград"}, + {24, 279, 1540, L"Краснотурьинск"}, + {24, 279, 2694, L"Красноуральск"}, + {24, 279, 2693, L"Красноуфимск"}, + {24, 279, 1541, L"Кушва"}, + {24, 279, 2711, L"Михайловск"}, + {24, 279, 2713, L"Михайловск"}, + {24, 279, 1542, L"Невьянск"}, + {24, 279, 2702, L"Нижние Серги"}, + {24, 279, 1543, L"Нижний Тагил"}, + {24, 279, 2695, L"Нижняя Салда"}, + {24, 279, 2697, L"Нижняя Тура"}, + {24, 279, 2699, L"Новая Ляля"}, + {24, 279, 2909, L"Новоуральск"}, + {24, 279, 1544, L"Первоуральск"}, + {24, 279, 1545, L"Полевской"}, + {24, 279, 1546, L"Ревда"}, + {24, 279, 1547, L"Реж"}, + {24, 279, 3296, L"Рефтинский"}, + {24, 279, 2700, L"Североуральск"}, + {24, 279, 1548, L"Серов"}, + {24, 279, 2710, L"Среднеуральск"}, + {24, 279, 2701, L"Сухой Лог"}, + {24, 279, 2703, L"Сысерть"}, + {24, 279, 1549, L"Тавда"}, + {24, 279, 2704, L"Талица"}, + {24, 279, 2705, L"Туринск"}, + {24, 279, 2265, L"Другое"}, + {24, 280, 1550, L"Заводоуковск"}, + {24, 280, 1551, L"Ишим"}, + {24, 280, 3326, L"Сургут"}, + {24, 280, 1552, L"Тобольск"}, + {24, 280, 1553, L"Тюмень"}, + {24, 280, 2748, L"Ялуторовск"}, + {24, 280, 2276, L"Другое"}, + {24, 282, 1564, L"Аша"}, + {24, 282, 2723, L"Бакал"}, + {24, 282, 2724, L"Верхнеуральск"}, + {24, 282, 2716, L"Верхний Уфалей"}, + {24, 282, 3297, L"Всеволожск"}, + {24, 282, 2725, L"Еманжелинск"}, + {24, 282, 1565, L"Златоуст"}, + {24, 282, 2722, L"Карабаш"}, + {24, 282, 1566, L"Карталы"}, + {24, 282, 2718, L"Касли"}, + {24, 282, 2720, L"Катав-Ивановск"}, + {24, 282, 1567, L"Копейск"}, + {24, 282, 2721, L"Коркино"}, + {24, 282, 2715, L"Куса"}, + {24, 282, 1568, L"Кыштым"}, + {24, 282, 1569, L"Магнитогорск"}, + {24, 282, 1570, L"Миасс"}, + {24, 282, 2726, L"Миньяр"}, + {24, 282, 2717, L"Нязепетровск"}, + {24, 282, 3100, L"Озерск"}, + {24, 282, 1571, L"Пласт"}, + {24, 282, 2719, L"Сатка"}, + {24, 282, 2727, L"Сим"}, + {24, 282, 1572, L"Снежинск"}, + {24, 282, 3332, L"Трехгорный"}, + {24, 282, 1573, L"Троицк"}, + {24, 282, 1574, L"Усть-Катав"}, + {24, 282, 1575, L"Чебаркуль"}, + {24, 282, 1576, L"Челябинск"}, + {24, 282, 1577, L"Южноуральск"}, + {24, 282, 2714, L"Юрюзань"}, + {24, 282, 2283, L"Другое"}, + {24, 281, 2749, L"Белоярский"}, + {24, 281, 1554, L"Игрим"}, + {24, 281, 1555, L"Когалым"}, + {24, 281, 1556, L"Лангепас"}, + {24, 281, 1561, L"Мегион"}, + {24, 281, 1562, L"Нефтеюганск"}, + {24, 281, 1559, L"Нижневартовск"}, + {24, 281, 2852, L"Нягань"}, + {24, 281, 2853, L"Нягань"}, + {24, 281, 2854, L"Пыть-Ях"}, + {24, 281, 1560, L"Радужный"}, + {24, 281, 1563, L"Советский"}, + {24, 281, 2747, L"Сургут"}, + {24, 281, 1557, L"Урай"}, + {24, 281, 1558, L"Ханты-Мансийск"}, + {24, 281, 3344, L"Югорск"}, + {24, 281, 2282, L"Другое"}, + {24, 283, 3298, L"Губкинский"}, + {24, 283, 1578, L"Лабытнанги"}, + {24, 283, 2856, L"Муравленко"}, + {24, 283, 1579, L"Надым"}, + {24, 283, 1580, L"Новый Уренгой"}, + {24, 283, 1581, L"Ноябрьск"}, + {24, 283, 1582, L"Салехард"}, + {24, 283, 1583, L"Уренгой"}, + {24, 283, 2289, L"Другое"}, + {24, 284, 1625, L"Алексеевка"}, + {24, 284, 1626, L"Белгород"}, + {24, 284, 2172, L"Валуйки"}, + {24, 284, 2173, L"Грайворон"}, + {24, 284, 1627, L"Губкин"}, + {24, 284, 2174, L"Короча"}, + {24, 284, 2175, L"Новый Оскол"}, + {24, 284, 1628, L"Старый Оскол"}, + {24, 284, 1629, L"Шебекино"}, + {24, 284, 2221, L"Другое"}, + {24, 285, 1630, L"Брянск"}, + {24, 285, 3283, L"Дебрянск"}, + {24, 285, 1631, L"Дятьково"}, + {24, 285, 2013, L"Жуковка"}, + {24, 285, 2015, L"Злынка"}, + {24, 285, 1632, L"Карачев"}, + {24, 285, 1633, L"Клинцы"}, + {24, 285, 1634, L"Мглин"}, + {24, 285, 2016, L"Новозыбков"}, + {24, 285, 2018, L"Почеп"}, + {24, 285, 2017, L"Севск"}, + {24, 285, 2020, L"Сельцо"}, + {24, 285, 2014, L"Стародуб"}, + {24, 285, 2010, L"Сураж"}, + {24, 285, 2012, L"Трубчевск"}, + {24, 285, 2011, L"Унеча"}, + {24, 285, 2019, L"Фокино"}, + {24, 285, 2210, L"Другое"}, + {24, 286, 1635, L"Александров"}, + {24, 286, 1636, L"Владимир"}, + {24, 286, 2021, L"Вязники"}, + {24, 286, 1637, L"Головино"}, + {24, 286, 2022, L"Гороховец"}, + {24, 286, 1638, L"Гусь-Хрустальный"}, + {24, 286, 2023, L"Камешково"}, + {24, 286, 2031, L"Карабаново"}, + {24, 286, 2024, L"Киржач"}, + {24, 286, 1639, L"Ковров"}, + {24, 286, 1640, L"Кольчугино"}, + {24, 286, 2026, L"Костерево"}, + {24, 286, 3299, L"Красная Горбатка"}, + {24, 286, 2033, L"Лакинск"}, + {24, 286, 2025, L"Меленки"}, + {24, 286, 1641, L"Муром"}, + {24, 286, 1642, L"Петушки"}, + {24, 286, 2027, L"Покров"}, + {24, 286, 2211, L"Радужный"}, + {24, 286, 2028, L"Собинка"}, + {24, 286, 2032, L"Струнино"}, + {24, 286, 2029, L"Судогда"}, + {24, 286, 1643, L"Суздаль"}, + {24, 286, 2030, L"Юрьев-Польский"}, + {24, 286, 2212, L"Другое"}, + {24, 287, 1644, L"Бобров"}, + {24, 287, 1645, L"Богучар"}, + {24, 287, 1646, L"Борисоглебск"}, + {24, 287, 1647, L"Бутурлиновка"}, + {24, 287, 1648, L"Воронеж"}, + {24, 287, 2178, L"Калач"}, + {24, 287, 2176, L"Лиски"}, + {24, 287, 1649, L"Нововоронеж"}, + {24, 287, 2177, L"Новохоперск"}, + {24, 287, 2180, L"Острогожск"}, + {24, 287, 1650, L"Павловск"}, + {24, 287, 2181, L"Поворино"}, + {24, 287, 1651, L"Россошь"}, + {24, 287, 2179, L"Семилуки"}, + {24, 287, 2182, L"Эртиль"}, + {24, 287, 2224, L"Другое"}, + {24, 288, 1652, L"Вичуга"}, + {24, 288, 2036, L"Гаврилов Посад"}, + {24, 288, 1657, L"Заволжск"}, + {24, 288, 1653, L"Иваново"}, + {24, 288, 1656, L"Кинешма"}, + {24, 288, 2040, L"Комсомольск"}, + {24, 288, 2037, L"Кохма"}, + {24, 288, 2043, L"Наволоки"}, + {24, 288, 3300, L"Палех"}, + {24, 288, 2039, L"Плес"}, + {24, 288, 2038, L"Приволжск"}, + {24, 288, 2042, L"Пучеж"}, + {24, 288, 2044, L"Родники"}, + {24, 288, 1655, L"Тейково"}, + {24, 288, 2034, L"Фурманов"}, + {24, 288, 1654, L"Шуя"}, + {24, 288, 2041, L"Южа"}, + {24, 288, 2035, L"Юрьевец"}, + {24, 288, 2227, L"Другое"}, + {24, 289, 2050, L"Балабаново"}, + {24, 289, 2051, L"Боровск"}, + {24, 289, 3301, L"Воротынск"}, + {24, 289, 2052, L"Жиздра"}, + {24, 289, 1660, L"Жуковка"}, + {24, 289, 1658, L"Калуга"}, + {24, 289, 2046, L"Киров"}, + {24, 289, 1661, L"Козельск"}, + {24, 289, 2053, L"Кондрово"}, + {24, 289, 2049, L"Людиново"}, + {24, 289, 1659, L"Малоярославец"}, + {24, 289, 2054, L"Медынь"}, + {24, 289, 2055, L"Мещовск"}, + {24, 289, 2047, L"Мосальск"}, + {24, 289, 1662, L"Обнинск"}, + {24, 289, 2057, L"Сосенский"}, + {24, 289, 2056, L"Спас-Демянск"}, + {24, 289, 2045, L"Сухиничи"}, + {24, 289, 1663, L"Таруса"}, + {24, 289, 2131, L"Чекалин"}, + {24, 289, 2048, L"Юхнов"}, + {24, 289, 2233, L"Другое"}, + {24, 290, 1664, L"Буй"}, + {24, 290, 1665, L"Волгореченск"}, + {24, 290, 1666, L"Галич"}, + {24, 290, 2059, L"Кологрив"}, + {24, 290, 1667, L"Кострома"}, + {24, 290, 3302, L"Красное-на-Волге"}, + {24, 290, 1668, L"Макарьев"}, + {24, 290, 2060, L"Мантурово"}, + {24, 290, 1669, L"Нерехта"}, + {24, 290, 2061, L"Нея"}, + {24, 290, 2062, L"Солигалич"}, + {24, 290, 2058, L"Чухлома"}, + {24, 290, 1670, L"Шарья"}, + {24, 290, 2240, L"Другое"}, + {24, 291, 1671, L"Дмитриев-Льговский"}, + {24, 291, 1673, L"Железногорск"}, + {24, 291, 3279, L"Железногорск"}, + {24, 291, 1672, L"Курск"}, + {24, 291, 2187, L"Курчатов"}, + {24, 291, 2188, L"Льгов"}, + {24, 291, 2184, L"Обоянь"}, + {24, 291, 2185, L"Рыльск"}, + {24, 291, 2183, L"Суджа"}, + {24, 291, 2189, L"Фатеж"}, + {24, 291, 2186, L"Щигры"}, + {24, 291, 2244, L"Другое"}, + {24, 292, 2194, L"Грязи"}, + {24, 292, 2193, L"Данков"}, + {24, 292, 1674, L"Елец"}, + {24, 292, 2190, L"Задонск"}, + {24, 292, 2195, L"Лебедянь"}, + {24, 292, 1675, L"Липецк"}, + {24, 292, 2192, L"Усмань"}, + {24, 292, 2191, L"Чаплыгин"}, + {24, 292, 2245, L"Другое"}, + {24, 293, 1733, L"Апрелевка"}, + {24, 293, 1732, L"Балашиха"}, + {24, 293, 1731, L"Бронницы"}, + {24, 293, 1730, L"Верея"}, + {24, 293, 2063, L"Видное"}, + {24, 293, 2064, L"Волоколамск"}, + {24, 293, 1729, L"Воскресенск"}, + {24, 293, 1728, L"Высоковск"}, + {24, 293, 1727, L"Голицыно"}, + {24, 293, 2065, L"Дедовск"}, + {24, 293, 1726, L"Дзержинский"}, + {24, 293, 1725, L"Дмитров"}, + {24, 293, 1724, L"Долгопрудный"}, + {24, 293, 1723, L"Домодедово"}, + {24, 293, 2066, L"Дрезна"}, + {24, 293, 1722, L"Дубна"}, + {24, 293, 1721, L"Егорьевск"}, + {24, 293, 1720, L"Железнодорожный"}, + {24, 293, 1719, L"Жуковский"}, + {24, 293, 2067, L"Зарайск"}, + {24, 293, 1718, L"Звенигород"}, + {24, 293, 1715, L"Ивантеевка"}, + {24, 293, 1717, L"Истра"}, + {24, 293, 2068, L"Калининград"}, + {24, 293, 2069, L"Кашира"}, + {24, 293, 1716, L"Климовск"}, + {24, 293, 1714, L"Клин"}, + {24, 293, 1713, L"Коломна"}, + {24, 293, 1712, L"Королев"}, + {24, 293, 1711, L"Красноармейск"}, + {24, 293, 1710, L"Красногорск"}, + {24, 293, 2070, L"Краснозаводск"}, + {24, 293, 2071, L"Куровское"}, + {24, 293, 1709, L"Ликино-Дулево"}, + {24, 293, 1708, L"Лобня"}, + {24, 293, 2072, L"Лосино-Петровский"}, + {24, 293, 1707, L"Луховицы"}, + {24, 293, 1706, L"Лыткарино"}, + {24, 293, 1705, L"Люберцы"}, + {24, 293, 1704, L"Менделеево"}, + {24, 293, 1703, L"Можайск"}, + {24, 293, 1702, L"Мытищи"}, + {24, 293, 1701, L"Наро-Фоминск"}, + {24, 293, 1700, L"Ногинск"}, + {24, 293, 1698, L"Одинцово"}, + {24, 293, 2073, L"Ожерелье"}, + {24, 293, 2074, L"Озеры"}, + {24, 293, 1699, L"Орехово-Зуево"}, + {24, 293, 1697, L"Павловский Посад"}, + {24, 293, 1696, L"Подольск"}, + {24, 293, 1695, L"Протвино"}, + {24, 293, 1694, L"Пушкино"}, + {24, 293, 1693, L"Пущино"}, + {24, 293, 1692, L"Раменское"}, + {24, 293, 1691, L"Реутов"}, + {24, 293, 1690, L"Решетников"}, + {24, 293, 2075, L"Рошаль"}, + {24, 293, 2076, L"Руза"}, + {24, 293, 1689, L"Сергиев Посад"}, + {24, 293, 1688, L"Серпухов"}, + {24, 293, 1687, L"Солнечногорск"}, + {24, 293, 1686, L"Ступино"}, + {24, 293, 2077, L"Сходня"}, + {24, 293, 2078, L"Талдом"}, + {24, 293, 1685, L"Троицк"}, + {24, 293, 1684, L"Фрязино"}, + {24, 293, 1683, L"Химки"}, + {24, 293, 1682, L"Хотьково"}, + {24, 293, 1681, L"Черноголовка"}, + {24, 293, 1680, L"Чехов"}, + {24, 293, 1679, L"Шатура"}, + {24, 293, 1678, L"Щелково"}, + {24, 293, 2080, L"Щербинка"}, + {24, 293, 1677, L"Электрогорск"}, + {24, 293, 1676, L"Электросталь"}, + {24, 293, 2079, L"Электроугли"}, + {24, 293, 3031, L"Юбилейный"}, + {24, 293, 2081, L"Яхрома"}, + {24, 293, 2249, L"Другое"}, + {24, 294, 2083, L"Болхов"}, + {24, 294, 2082, L"Дмитровск-Орловский"}, + {24, 294, 3160, L"Залегощь"}, + {24, 294, 1736, L"Ливны"}, + {24, 294, 2084, L"Малоархангельск"}, + {24, 294, 1737, L"Мценск"}, + {24, 294, 2085, L"Новосиль"}, + {24, 294, 1735, L"Орел"}, + {24, 294, 2255, L"Другое"}, + {24, 295, 1740, L"Гусь-Железный"}, + {24, 295, 1741, L"Касимов"}, + {24, 295, 2086, L"Кораблино"}, + {24, 295, 2087, L"Михайлов"}, + {24, 295, 2089, L"Новомичуринск"}, + {24, 295, 2091, L"Рыбное"}, + {24, 295, 2093, L"Ряжск"}, + {24, 295, 1738, L"Рязань"}, + {24, 295, 3305, L"Сапожок"}, + {24, 295, 1739, L"Сасово"}, + {24, 295, 2090, L"Скопин"}, + {24, 295, 2088, L"Спас-Клепики"}, + {24, 295, 2092, L"Спасск-Рязанский"}, + {24, 295, 2094, L"Шацк"}, + {24, 295, 3320, L"Шилово"}, + {24, 295, 2260, L"Другое"}, + {24, 296, 2095, L"Велиж"}, + {24, 296, 1743, L"Вязьма"}, + {24, 296, 1744, L"Гагарин"}, + {24, 296, 2096, L"Демидов"}, + {24, 296, 1745, L"Десногорск"}, + {24, 296, 1746, L"Дорогубуж"}, + {24, 296, 2097, L"Духовщина"}, + {24, 296, 2098, L"Ельня"}, + {24, 296, 2099, L"Починок"}, + {24, 296, 2100, L"Рославль"}, + {24, 296, 2101, L"Рудня"}, + {24, 296, 1747, L"Сафоново"}, + {24, 296, 1742, L"Смоленск"}, + {24, 296, 2102, L"Сычевка"}, + {24, 296, 1748, L"Ярцево"}, + {24, 296, 2267, L"Другое"}, + {24, 297, 2198, L"Жердевка"}, + {24, 297, 2199, L"Кирсанов"}, + {24, 297, 1752, L"Котовск"}, + {24, 297, 1751, L"Мичуринск"}, + {24, 297, 2196, L"Моршанск"}, + {24, 297, 1750, L"Рассказово"}, + {24, 297, 3271, L"Сатинка"}, + {24, 297, 1749, L"Тамбов"}, + {24, 297, 3272, L"Тулиновка"}, + {24, 297, 2197, L"Уварово"}, + {24, 297, 2270, L"Другое"}, + {24, 298, 2103, L"Андреаполь"}, + {24, 298, 2104, L"Бежецк"}, + {24, 298, 2105, L"Белый"}, + {24, 298, 2106, L"Бологое"}, + {24, 298, 2107, L"Весьегонск"}, + {24, 298, 1753, L"Вышний Волочек"}, + {24, 298, 2108, L"Западная Двина"}, + {24, 298, 2109, L"Зубцов"}, + {24, 298, 2110, L"Калязин"}, + {24, 298, 2111, L"Кашин"}, + {24, 298, 1758, L"Кимры"}, + {24, 298, 1756, L"Конаково"}, + {24, 298, 2112, L"Красный Холм"}, + {24, 298, 1759, L"Кувшиново"}, + {24, 298, 1760, L"Лихославль"}, + {24, 298, 1761, L"Нелидово"}, + {24, 298, 2113, L"Осташков"}, + {24, 298, 1757, L"Ржев"}, + {24, 298, 2114, L"Старица"}, + {24, 298, 1754, L"Тверь"}, + {24, 298, 2115, L"Торжок"}, + {24, 298, 2116, L"Торопец"}, + {24, 298, 1755, L"Удомля"}, + {24, 298, 2272, L"Другое"}, + {24, 299, 2127, L"Алексин"}, + {24, 299, 2126, L"Белев"}, + {24, 299, 2118, L"Богородицк"}, + {24, 299, 2122, L"Болохово"}, + {24, 299, 2129, L"Венев"}, + {24, 299, 1762, L"Донской"}, + {24, 299, 2128, L"Ефремов"}, + {24, 299, 3354, L"Заокский"}, + {24, 299, 2124, L"Киреевск"}, + {24, 299, 1763, L"Климовск"}, + {24, 299, 2123, L"Липки"}, + {24, 299, 1764, L"Новомосковск"}, + {24, 299, 2117, L"Плавск"}, + {24, 299, 2130, L"Северо-Задонск"}, + {24, 299, 2120, L"Советск"}, + {24, 299, 2119, L"Сокольники"}, + {24, 299, 2125, L"Суворов"}, + {24, 299, 1765, L"Тула"}, + {24, 299, 1766, L"Узловая"}, + {24, 299, 2121, L"Щекино"}, + {24, 299, 1767, L"Ясногорск"}, + {24, 299, 2274, L"Другое"}, + {24, 300, 3053, L"Большое Село"}, + {24, 300, 3268, L"Брейтово"}, + {24, 300, 1773, L"Гаврилов-Ям"}, + {24, 300, 2132, L"Данилов"}, + {24, 300, 3269, L"Красные Ткачи"}, + {24, 300, 2133, L"Любим"}, + {24, 300, 3270, L"Мокеевское"}, + {24, 300, 1774, L"Мышкин"}, + {24, 300, 2994, L"Некоуз"}, + {24, 300, 1775, L"Переславль-Залесский"}, + {24, 300, 2134, L"Пошехонье"}, + {24, 300, 1769, L"Ростов"}, + {24, 300, 1771, L"Рыбинск"}, + {24, 300, 1772, L"Тутаев"}, + {24, 300, 1770, L"Углич"}, + {24, 300, 1768, L"Ярославль"}, + {24, 300, 2290, L"Другое"}, + {24, 301, 2849, L"Адыгейск"}, + {24, 301, 1776, L"Майкоп"}, + {24, 301, 2214, L"Другое"}, + {24, 304, 2617, L"Буйнакск"}, + {24, 304, 1791, L"Гуниб"}, + {24, 304, 1788, L"Дербент"}, + {24, 304, 2619, L"Избербаш"}, + {24, 304, 1789, L"Каспийск"}, + {24, 304, 2618, L"Кизилюрт"}, + {24, 304, 1790, L"Кизляр"}, + {24, 304, 1792, L"Махачкала"}, + {24, 304, 2620, L"Хасавюрт"}, + {24, 304, 2225, L"Другое"}, + {24, 305, 3052, L"Магас"}, + {24, 305, 1787, L"Назрань"}, + {24, 305, 2228, L"Другое"}, + {24, 306, 2621, L"Баксан"}, + {24, 306, 1794, L"Майский"}, + {24, 306, 1793, L"Нальчик"}, + {24, 306, 2622, L"Нарткала"}, + {24, 306, 1795, L"Прохладный"}, + {24, 306, 2623, L"Терек"}, + {24, 306, 2624, L"Тырныауз"}, + {24, 306, 3274, L"Чегем"}, + {24, 306, 2230, L"Другое"}, + {24, 307, 2567, L"Городовиково"}, + {24, 307, 2568, L"Лагань"}, + {24, 307, 3324, L"Троицкое"}, + {24, 307, 1796, L"Элиста"}, + {24, 307, 2232, L"Другое"}, + {24, 308, 1799, L"Домбай"}, + {24, 308, 1798, L"Карачаевск"}, + {24, 308, 2626, L"Теберда"}, + {24, 308, 2625, L"Усть-Джегута"}, + {24, 308, 1797, L"Черкесск"}, + {24, 308, 2235, L"Другое"}, + {24, 311, 2630, L"Алагир"}, + {24, 311, 2631, L"Ардон"}, + {24, 311, 2628, L"Беслан"}, + {24, 311, 1839, L"Владикавказ"}, + {24, 311, 2629, L"Дигора"}, + {24, 311, 2627, L"Моздок"}, + {24, 311, 2266, L"Другое"}, + {24, 313, 2632, L"Аргун"}, + {24, 313, 1853, L"Грозный"}, + {24, 313, 2633, L"Гудермес"}, + {24, 313, 2284, L"Другое"}, + {24, 309, 2636, L"Абинск"}, + {24, 309, 1800, L"Анапа"}, + {24, 309, 1801, L"Апшеронск"}, + {24, 309, 1802, L"Армавир"}, + {24, 309, 1803, L"Белореченск"}, + {24, 309, 1804, L"Геленджик"}, + {24, 309, 1805, L"Горячий Ключ"}, + {24, 309, 2637, L"Гулькевичи"}, + {24, 309, 1806, L"Динская"}, + {24, 309, 1807, L"Ейск"}, + {24, 309, 2638, L"Кореновск"}, + {24, 309, 1808, L"Краснодар"}, + {24, 309, 1809, L"Кропоткин"}, + {24, 309, 1810, L"Крымск"}, + {24, 309, 1811, L"Курганинск"}, + {24, 309, 3232, L"Лабинск"}, + {24, 309, 2639, L"Новокубанск"}, + {24, 309, 1812, L"Новороссийск"}, + {24, 309, 1813, L"Пластуновская"}, + {24, 309, 1814, L"Приморско-Ахтарск"}, + {24, 309, 3102, L"Северская"}, + {24, 309, 1815, L"Славянск-на-Кубани"}, + {24, 309, 1816, L"Сочи"}, + {24, 309, 3266, L"Староминская"}, + {24, 309, 3039, L"Тамань"}, + {24, 309, 1817, L"Темрюк"}, + {24, 309, 2635, L"Тимашевск"}, + {24, 309, 1818, L"Тихорецк"}, + {24, 309, 1819, L"Туапсе"}, + {24, 309, 1820, L"Усть-Лабинск"}, + {24, 309, 2634, L"Хадыженск"}, + {24, 309, 2241, L"Другое"}, + {24, 312, 1840, L"Александровское"}, + {24, 312, 2644, L"Благодарный"}, + {24, 312, 1841, L"Буденновск"}, + {24, 312, 1842, L"Георгиевск"}, + {24, 312, 1843, L"Ессентуки"}, + {24, 312, 1844, L"Железноводск"}, + {24, 312, 2647, L"Зеленокумск"}, + {24, 312, 2641, L"Изобильный"}, + {24, 312, 2642, L"Ипатово"}, + {24, 312, 1845, L"Кисловодск"}, + {24, 312, 1846, L"Кочубеевское"}, + {24, 312, 3367, L"Курсавка"}, + {24, 312, 3265, L"Левокумское"}, + {24, 312, 1847, L"Лермонтов"}, + {24, 312, 1848, L"Минеральные Воды"}, + {24, 312, 1849, L"Невинномысск"}, + {24, 312, 2645, L"Нефтекумск"}, + {24, 312, 2643, L"Новоалександровск"}, + {24, 312, 1850, L"Новопавловск"}, + {24, 312, 1851, L"Новоселицкое"}, + {24, 312, 1852, L"Пятигорск"}, + {24, 312, 2646, L"Светлоград"}, + {24, 312, 2640, L"Ставрополь"}, + {24, 312, 2268, L"Другое"}, + {24, 302, 1777, L"Астрахань"}, + {24, 302, 1778, L"Ахтубинск"}, + {24, 302, 3383, L"Знаменск"}, + {24, 302, 2578, L"Камызяк"}, + {24, 302, 2579, L"Нариманов"}, + {24, 302, 1786, L"Харабали"}, + {24, 302, 2219, L"Другое"}, + {24, 303, 1779, L"Волгоград"}, + {24, 303, 1780, L"Волжский"}, + {24, 303, 2584, L"Дубовка"}, + {24, 303, 1781, L"Жирновск"}, + {24, 303, 1782, L"Калач-на-Дону"}, + {24, 303, 1783, L"Камышин"}, + {24, 303, 2588, L"Котельниково"}, + {24, 303, 2591, L"Котово"}, + {24, 303, 2587, L"Краснослободск"}, + {24, 303, 2582, L"Ленинск"}, + {24, 303, 2590, L"Михайловка"}, + {24, 303, 1784, L"Николаевск"}, + {24, 303, 2581, L"Новоаннинский"}, + {24, 303, 2583, L"Палласовка"}, + {24, 303, 2580, L"Петров Вал"}, + {24, 303, 2589, L"Серафимович"}, + {24, 303, 2585, L"Суровикино"}, + {24, 303, 1785, L"Урюпинск"}, + {24, 303, 2586, L"Фролово"}, + {24, 303, 2223, L"Другое"}, + {24, 310, 1821, L"Азов"}, + {24, 310, 1822, L"Аксай"}, + {24, 310, 1823, L"Багаевская"}, + {24, 310, 1824, L"Батайск"}, + {24, 310, 1825, L"Белая Калитва"}, + {24, 310, 1826, L"Волгодонск"}, + {24, 310, 1827, L"Гуково"}, + {24, 310, 2651, L"Донецк"}, + {24, 310, 1828, L"Зерноград"}, + {24, 310, 3264, L"Каменоломни"}, + {24, 310, 2652, L"Каменск-Шахтинский"}, + {24, 310, 2649, L"Константиновск"}, + {24, 310, 2648, L"Красный Сулин"}, + {24, 310, 1829, L"Миллерово"}, + {24, 310, 2653, L"Морозовск"}, + {24, 310, 1830, L"Новочеркасск"}, + {24, 310, 1831, L"Новошахтинск"}, + {24, 310, 1832, L"Пролетарск"}, + {24, 310, 1833, L"Ростов-на-Дону"}, + {24, 310, 1834, L"Сальск"}, + {24, 310, 1835, L"Семикаракорск"}, + {24, 310, 1836, L"Таганрог"}, + {24, 310, 1837, L"Усть-Донецкий"}, + {24, 310, 3263, L"Целина"}, + {24, 310, 2650, L"Цимлянск"}, + {24, 310, 1838, L"Шахты"}, + {24, 310, 2259, L"Другое"}, + {139, 407, 407, L" столица"}, + {139, 426, 427, L"Бойсе"}, + {139, 426, 2354, L"Другое"}, + {139, 378, 3109, L"Айова Сити"}, + {139, 378, 379, L"Де-Мойн"}, + {139, 378, 2963, L"Декора"}, + {139, 378, 2355, L"Другое"}, + {139, 412, 3236, L"Бирмингем"}, + {139, 412, 413, L"Монтгомери"}, + {139, 412, 1181, L"Хантсвилл"}, + {139, 412, 2356, L"Другое"}, + {139, 446, 1182, L"Анкоридж"}, + {139, 446, 447, L"Джуно"}, + {139, 446, 1183, L"Фэрбенкс"}, + {139, 446, 2357, L"Другое"}, + {139, 434, 2917, L"Темпе"}, + {139, 434, 1184, L"Тусон"}, + {139, 434, 435, L"Финикс"}, + {139, 434, 3061, L"Чандлер"}, + {139, 434, 2358, L"Другое"}, + {139, 416, 417, L"Литл-Рок"}, + {139, 416, 2359, L"Другое"}, + {139, 428, 3017, L"Ларами"}, + {139, 428, 429, L"Шайенн"}, + {139, 428, 2360, L"Другое"}, + {139, 440, 2956, L"Беллевью"}, + {139, 440, 2967, L"Бремертон"}, + {139, 440, 3385, L"Ванкувер"}, + {139, 440, 2865, L"Линден"}, + {139, 440, 441, L"Олимпия"}, + {139, 440, 3352, L"Порт Орчард"}, + {139, 440, 2876, L"Редмонт"}, + {139, 440, 3003, L"Рентон"}, + {139, 440, 1185, L"Сиэтл"}, + {139, 440, 2983, L"Снохомиш"}, + {139, 440, 1186, L"Такома"}, + {139, 440, 3152, L"Фрайди Харбор"}, + {139, 440, 2886, L"Эверет"}, + {139, 440, 2361, L"Другое"}, + {139, 352, 353, L"Монтпильер"}, + {139, 352, 2861, L"Норвич"}, + {139, 352, 2362, L"Другое"}, + {139, 394, 1188, L"Александрия"}, + {139, 394, 1187, L"Арлингтон"}, + {139, 394, 2969, L"Даллес"}, + {139, 394, 1189, L"Манассас"}, + {139, 394, 3114, L"Норфолк"}, + {139, 394, 2885, L"Ньюпорт-Ньюс"}, + {139, 394, 2979, L"Раунд Хил"}, + {139, 394, 3338, L"Рестон"}, + {139, 394, 395, L"Ричмонд"}, + {139, 394, 3005, L"Уоррентон"}, + {139, 394, 2991, L"Херндон"}, + {139, 394, 2996, L"Центрвиль"}, + {139, 394, 3097, L"Чантилли"}, + {139, 394, 2981, L"Шарлотесвиль"}, + {139, 394, 2363, L"Другое"}, + {139, 374, 2995, L"Грин-Бей"}, + {139, 374, 375, L"Мадисон"}, + {139, 374, 2365, L"Другое"}, + {139, 448, 449, L"Гонолулу"}, + {139, 448, 1191, L"Хило"}, + {139, 448, 2367, L"Другое"}, + {139, 390, 3021, L"Вильмингтон"}, + {139, 390, 391, L"Довер"}, + {139, 390, 2973, L"Льюис"}, + {139, 390, 2369, L"Другое"}, + {139, 402, 403, L"Атланта"}, + {139, 402, 2370, L"Другое"}, + {139, 396, 397, L"Чарлстон"}, + {139, 396, 2371, L"Другое"}, + {139, 370, 2911, L"Вестмонт"}, + {139, 370, 3074, L"Гарвард"}, + {139, 370, 371, L"Спрингфилд"}, + {139, 370, 2930, L"Урбана"}, + {139, 370, 1194, L"Чикаго"}, + {139, 370, 2372, L"Другое"}, + {139, 368, 369, L"Индианаполис"}, + {139, 368, 1195, L"Эвансвил"}, + {139, 368, 2373, L"Другое"}, + {139, 444, 2959, L"Анахайм"}, + {139, 444, 2961, L"Аптос"}, + {139, 444, 2912, L"Артезия"}, + {139, 444, 2899, L"Беверли Хилз"}, + {139, 444, 1196, L"Беркли"}, + {139, 444, 3249, L"Бреа"}, + {139, 444, 3014, L"Брисбейн"}, + {139, 444, 3048, L"Венис"}, + {139, 444, 2901, L"Вест-Голливуд"}, + {139, 444, 2926, L"Вестлейк Вилладж"}, + {139, 444, 2922, L"Гардена"}, + {139, 444, 1203, L"Глендейл"}, + {139, 444, 2978, L"Денвиль"}, + {139, 444, 2990, L"Дублин"}, + {139, 444, 3077, L"Дэвис"}, + {139, 444, 2918, L"Ирвайн"}, + {139, 444, 2881, L"Карсон"}, + {139, 444, 3247, L"Кипресс"}, + {139, 444, 3092, L"Коста Меса"}, + {139, 444, 2948, L"Купертино"}, + {139, 444, 1197, L"Лонг-Бич"}, + {139, 444, 1198, L"Лос-Анджелес"}, + {139, 444, 3058, L"Лос-Гатос"}, + {139, 444, 3328, L"Марина-дель-Рей"}, + {139, 444, 2874, L"Маунтин-Вью"}, + {139, 444, 2998, L"Милпитас"}, + {139, 444, 3087, L"Монтерей"}, + {139, 444, 2947, L"Окленд"}, + {139, 444, 2900, L"Пало Альто"}, + {139, 444, 1199, L"Пасадена"}, + {139, 444, 3335, L"Редвуд"}, + {139, 444, 2966, L"Розамонд"}, + {139, 444, 445, L"Сакраменто"}, + {139, 444, 1200, L"Сан-Диего"}, + {139, 444, 3317, L"Сан-Мартин"}, + {139, 444, 1201, L"Сан-Франциско"}, + {139, 444, 1202, L"Сан-Хосе"}, + {139, 444, 2878, L"Саннивейл"}, + {139, 444, 2925, L"Санта-Барбара"}, + {139, 444, 2875, L"Санта-Клара"}, + {139, 444, 1204, L"Санта-Круз"}, + {139, 444, 2859, L"Санта-Моника"}, + {139, 444, 3157, L"Студио Сити"}, + {139, 444, 3146, L"Торранс"}, + {139, 444, 2970, L"Тысяча Дубов"}, + {139, 444, 2949, L"Универсал-Сити"}, + {139, 444, 3057, L"Форт Брэгг"}, + {139, 444, 3032, L"Фостер-Сити"}, + {139, 444, 3381, L"Фремонт"}, + {139, 444, 3028, L"Фуллертон"}, + {139, 444, 2858, L"Эмервиль"}, + {139, 444, 3040, L"Эскондидо"}, + {139, 444, 2374, L"Другое"}, + {139, 388, 3041, L"Лоуренс"}, + {139, 388, 389, L"Топика"}, + {139, 388, 2375, L"Другое"}, + {139, 408, 3004, L"Лексингтон"}, + {139, 408, 1205, L"Луисвилл"}, + {139, 408, 409, L"Франкфорт"}, + {139, 408, 2376, L"Другое"}, + {139, 430, 1206, L"Боулдер"}, + {139, 430, 3095, L"Грили"}, + {139, 430, 431, L"Денвер"}, + {139, 430, 1207, L"Колорадо-Спрингс"}, + {139, 430, 3046, L"Литлтон"}, + {139, 430, 2377, L"Другое"}, + {139, 358, 2968, L"Дариен"}, + {139, 358, 3018, L"Денбери"}, + {139, 358, 2882, L"Стэмфорд"}, + {139, 358, 359, L"Хартфорд"}, + {139, 358, 3047, L"Шелтон"}, + {139, 358, 2378, L"Другое"}, + {139, 418, 419, L"Батон-Руж"}, + {139, 418, 1208, L"Новый Орлеан"}, + {139, 418, 2408, L"Другое"}, + {139, 354, 2931, L"Аттлеборо"}, + {139, 354, 3334, L"Билерика"}, + {139, 354, 355, L"Бостон"}, + {139, 354, 3059, L"Вестгемптон"}, + {139, 354, 2919, L"Вобурн"}, + {139, 354, 2902, L"Дедхэм"}, + {139, 354, 1209, L"Кеймбридж"}, + {139, 354, 3336, L"Нидхем"}, + {139, 354, 2985, L"Ньютонвиль"}, + {139, 354, 3022, L"Уолтхэм"}, + {139, 354, 2407, L"Другое"}, + {139, 376, 1210, L"Миннеаполис"}, + {139, 376, 2980, L"Плимут"}, + {139, 376, 377, L"Сент-Пол"}, + {139, 376, 3035, L"Эден Прейри"}, + {139, 376, 2406, L"Другое"}, + {139, 414, 415, L"Джэксон"}, + {139, 414, 2405, L"Другое"}, + {139, 380, 381, L"Джефферсон-Сити"}, + {139, 380, 3062, L"Канзас Сити"}, + {139, 380, 3038, L"Ли Саммит"}, + {139, 380, 1211, L"Сент-Луис"}, + {139, 380, 2895, L"Эллисвил"}, + {139, 380, 2404, L"Другое"}, + {139, 372, 3357, L"Вест Блюмфельд"}, + {139, 372, 1212, L"Гранд-Рапидс"}, + {139, 372, 1213, L"Детройт"}, + {139, 372, 3103, L"Каламазу"}, + {139, 372, 373, L"Лансинг"}, + {139, 372, 2987, L"Новай"}, + {139, 372, 2887, L"Сагино"}, + {139, 372, 2403, L"Другое"}, + {139, 424, 1214, L"Грейт-Фолс"}, + {139, 424, 425, L"Хелина"}, + {139, 424, 2402, L"Другое"}, + {139, 348, 349, L"Огаста"}, + {139, 348, 3000, L"Ярмут"}, + {139, 348, 2401, L"Другое"}, + {139, 392, 393, L"Аннаполис"}, + {139, 392, 1215, L"Балтимор"}, + {139, 392, 3143, L"Гринбелт"}, + {139, 392, 3337, L"Колледж Парк"}, + {139, 392, 2904, L"Маунт Эйри"}, + {139, 392, 3329, L"Роквилль"}, + {139, 392, 2400, L"Другое"}, + {139, 386, 387, L"Линкольн"}, + {139, 386, 1216, L"Омаха"}, + {139, 386, 2399, L"Другое"}, + {139, 438, 439, L"Карсон-Сити"}, + {139, 438, 1217, L"Лас-Вегас"}, + {139, 438, 2890, L"Рено"}, + {139, 438, 2398, L"Другое"}, + {139, 362, 1219, L"Атлантик-Сити"}, + {139, 362, 1218, L"Ньюарк"}, + {139, 362, 3276, L"Оклин"}, + {139, 362, 3073, L"Принстон"}, + {139, 362, 2955, L"Рузерфорд"}, + {139, 362, 3349, L"Сомервиль"}, + {139, 362, 363, L"Трентон"}, + {139, 362, 3078, L"Хакеттстоун"}, + {139, 362, 3248, L"Черри Хилл"}, + {139, 362, 2397, L"Другое"}, + {139, 360, 3134, L"Баффало"}, + {139, 360, 3081, L"Бингхэмптон"}, + {139, 360, 2997, L"Бруклин"}, + {139, 360, 2999, L"Варвик"}, + {139, 360, 3139, L"Ирвингтон"}, + {139, 360, 3060, L"Итака"}, + {139, 360, 1220, L"Нью-Йорк"}, + {139, 360, 361, L"Олбани"}, + {139, 360, 2914, L"Погкипси"}, + {139, 360, 3056, L"Саратога Спрингс"}, + {139, 360, 2396, L"Другое"}, + {139, 432, 1222, L"Альбукерке"}, + {139, 432, 433, L"Санта-Фе"}, + {139, 432, 2395, L"Другое"}, + {139, 350, 2989, L"Амхерст"}, + {139, 350, 351, L"Конкорд"}, + {139, 350, 2950, L"Лондондерри"}, + {139, 350, 1221, L"Манчестер"}, + {139, 350, 3111, L"Рочестер"}, + {139, 350, 2898, L"Салем"}, + {139, 350, 2938, L"Хадсон"}, + {139, 350, 2394, L"Другое"}, + {139, 366, 2953, L"Варрен"}, + {139, 366, 3112, L"Гроув Сити"}, + {139, 366, 1223, L"Кливленд"}, + {139, 366, 367, L"Колумбус"}, + {139, 366, 2951, L"Лавленд"}, + {139, 366, 2862, L"Оберлин"}, + {139, 366, 3034, L"Рейнольдсбург"}, + {139, 366, 2860, L"Цинциннати"}, + {139, 366, 2393, L"Другое"}, + {139, 420, 421, L"Оклахома-Сити"}, + {139, 420, 1224, L"Талса"}, + {139, 420, 2392, L"Другое"}, + {139, 442, 2877, L"Кламат-Фолс"}, + {139, 442, 2945, L"Коттедж-Гроув"}, + {139, 442, 1225, L"Портленд"}, + {139, 442, 443, L"Сейлем"}, + {139, 442, 1226, L"Юджин"}, + {139, 442, 2391, L"Другое"}, + {139, 364, 3316, L"Вифлием"}, + {139, 364, 3282, L"Колледжвиль"}, + {139, 364, 2972, L"Нью Фридом"}, + {139, 364, 1227, L"Питтсбург"}, + {139, 364, 2893, L"Рандор"}, + {139, 364, 3110, L"Слиппери Рок"}, + {139, 364, 1228, L"Филадельфия"}, + {139, 364, 365, L"Харрисберг"}, + {139, 364, 2390, L"Другое"}, + {139, 450, 451, L"Понсе"}, + {139, 450, 3093, L"Сан-Хуан"}, + {139, 450, 2389, L"Другое"}, + {139, 356, 357, L"Провиденс"}, + {139, 356, 2388, L"Другое"}, + {139, 382, 383, L"Бисмарк"}, + {139, 382, 2387, L"Другое"}, + {139, 398, 2960, L"Вильмингтон"}, + {139, 398, 2915, L"Дурхам"}, + {139, 398, 399, L"Роли"}, + {139, 398, 2386, L"Другое"}, + {139, 410, 2863, L"Мемфис"}, + {139, 410, 411, L"Нашвилл"}, + {139, 410, 1229, L"Ноксвилл"}, + {139, 410, 2385, L"Другое"}, + {139, 422, 3085, L"Бедфорд"}, + {139, 422, 2913, L"Брейди"}, + {139, 422, 1233, L"Даллас"}, + {139, 422, 2916, L"Ирвинг"}, + {139, 422, 3123, L"Кингсвилл"}, + {139, 422, 2873, L"Конрой"}, + {139, 422, 3096, L"Корпус Кристи"}, + {139, 422, 423, L"Остин"}, + {139, 422, 1232, L"Сан-Антонио"}, + {139, 422, 3023, L"Уайли"}, + {139, 422, 1231, L"Хьюстон"}, + {139, 422, 1230, L"Эль-Пасо"}, + {139, 422, 2384, L"Другое"}, + {139, 406, 2383, L"Другое"}, + {139, 404, 2879, L"Бока-Рейтон"}, + {139, 404, 2880, L"Гейнсвил"}, + {139, 404, 3086, L"Джексонвиль"}, + {139, 404, 3002, L"Киссимми"}, + {139, 404, 3124, L"Корал Гейблс"}, + {139, 404, 2894, L"Корал-Спрингс"}, + {139, 404, 3290, L"Лейк-Ворт"}, + {139, 404, 1234, L"Майами"}, + {139, 404, 1236, L"Орландо"}, + {139, 404, 3372, L"Пинеллас Парк"}, + {139, 404, 2952, L"Пунта-Горда"}, + {139, 404, 3340, L"Сарасота"}, + {139, 404, 1235, L"Сент-Питерсберг"}, + {139, 404, 405, L"Таллахасси"}, + {139, 404, 2962, L"Форт Лаудердейл"}, + {139, 404, 2382, L"Другое"}, + {139, 384, 385, L"Пирр"}, + {139, 384, 2381, L"Другое"}, + {139, 400, 401, L"Колумбия"}, + {139, 400, 3090, L"Спартанбург"}, + {139, 400, 1237, L"Чарлстон"}, + {139, 400, 2380, L"Другое"}, + {139, 436, 3036, L"Кейсвилл"}, + {139, 436, 3024, L"Линдон"}, + {139, 436, 3108, L"Орем"}, + {139, 436, 2866, L"Сент-Джордж"}, + {139, 436, 437, L"Солт-Лейк-Сити"}, + {139, 436, 2379, L"Другое"}, + {39, 315, 614, L"Винница"}, + {39, 315, 615, L"Хмельник"}, + {39, 315, 2566, L"Другое"}, + {39, 316, 2940, L"Ковель"}, + {39, 316, 616, L"Луцк"}, + {39, 316, 2565, L"Другое"}, + {39, 317, 617, L"Днепродзержинск"}, + {39, 317, 618, L"Днепропетровск"}, + {39, 317, 619, L"Кривой Рог"}, + {39, 317, 620, L"Никополь"}, + {39, 317, 621, L"Новомосковск"}, + {39, 317, 622, L"Орджоникидзе"}, + {39, 317, 623, L"Павлоград"}, + {39, 317, 2564, L"Другое"}, + {39, 318, 624, L"Артемовск"}, + {39, 318, 625, L"Горловка"}, + {39, 318, 626, L"Донецк"}, + {39, 318, 627, L"Дружковка"}, + {39, 318, 628, L"Енакиево"}, + {39, 318, 629, L"Константиновка"}, + {39, 318, 630, L"Краматорск"}, + {39, 318, 2944, L"Красноармейск"}, + {39, 318, 631, L"Макеевка"}, + {39, 318, 632, L"Мариуполь"}, + {39, 318, 633, L"Николаевка"}, + {39, 318, 634, L"Славянск"}, + {39, 318, 635, L"Харцызск"}, + {39, 318, 2563, L"Другое"}, + {39, 319, 636, L"Бердичев"}, + {39, 319, 637, L"Житомир"}, + {39, 319, 2942, L"Коростень"}, + {39, 319, 638, L"Коростышев"}, + {39, 319, 2907, L"Малин"}, + {39, 319, 639, L"Новоград-Волынский"}, + {39, 319, 2562, L"Другое"}, + {39, 320, 640, L"Берегово"}, + {39, 320, 641, L"Воловец"}, + {39, 320, 3119, L"Мукачево"}, + {39, 320, 3162, L"Свалява"}, + {39, 320, 642, L"Ужгород"}, + {39, 320, 643, L"Хуст"}, + {39, 320, 2561, L"Другое"}, + {39, 321, 644, L"Бердянск"}, + {39, 321, 3128, L"Гуляйполе"}, + {39, 321, 645, L"Запорожье"}, + {39, 321, 646, L"Мелитополь"}, + {39, 321, 3121, L"Приморск"}, + {39, 321, 3378, L"Энергодар"}, + {39, 321, 2560, L"Другое"}, + {39, 322, 3379, L"Галич"}, + {39, 322, 647, L"Ивано-Франковск"}, + {39, 322, 3170, L"Яремче"}, + {39, 322, 2559, L"Другое"}, + {39, 323, 648, L"Белая Церковь"}, + {39, 323, 649, L"Борисполь"}, + {39, 323, 651, L"Бровары"}, + {39, 323, 650, L"Васильков"}, + {39, 323, 652, L"Ирпень"}, + {39, 323, 3341, L"Переяслав-Хмельницкий"}, + {39, 323, 653, L"Славутич"}, + {39, 323, 654, L"Фастов"}, + {39, 323, 655, L"Чернобыль"}, + {39, 323, 2558, L"Другое"}, + {39, 324, 656, L"Александрия"}, + {39, 324, 657, L"Кировоград"}, + {39, 324, 658, L"Светловодск"}, + {39, 324, 2557, L"Другое"}, + {39, 325, 659, L"Алушта"}, + {39, 325, 2984, L"Армянск"}, + {39, 325, 3042, L"Балаклава"}, + {39, 325, 660, L"Бахчисарай"}, + {39, 325, 662, L"Гурзуф"}, + {39, 325, 3382, L"Джанкой"}, + {39, 325, 663, L"Евпатория"}, + {39, 325, 667, L"Керчь"}, + {39, 325, 666, L"Коктебель"}, + {39, 325, 668, L"Мысовое"}, + {39, 325, 669, L"Саки"}, + {39, 325, 665, L"Севастополь"}, + {39, 325, 661, L"Симферополь"}, + {39, 325, 3370, L"Старый Крым"}, + {39, 325, 670, L"Судак"}, + {39, 325, 664, L"Феодосия"}, + {39, 325, 3148, L"Черноморское"}, + {39, 325, 671, L"Ялта"}, + {39, 325, 2556, L"Другое"}, + {39, 326, 672, L"Алчевск"}, + {39, 326, 673, L"Антрацит"}, + {39, 326, 674, L"Лисичанск"}, + {39, 326, 675, L"Луганск"}, + {39, 326, 3364, L"Молодогвардейск"}, + {39, 326, 676, L"Петровское"}, + {39, 326, 677, L"Ровеньки"}, + {39, 326, 678, L"Рубежное"}, + {39, 326, 679, L"Северодонецк"}, + {39, 326, 680, L"Стаханов"}, + {39, 326, 2555, L"Другое"}, + {39, 327, 3284, L"Дрогобыч"}, + {39, 327, 681, L"Львов"}, + {39, 327, 682, L"Трускавец"}, + {39, 327, 2554, L"Другое"}, + {39, 328, 3322, L"Вознесенск"}, + {39, 328, 2870, L"Жовтневое"}, + {39, 328, 683, L"Николаев"}, + {39, 328, 3118, L"Очаков"}, + {39, 328, 3325, L"Южноукраинск"}, + {39, 328, 2553, L"Другое"}, + {39, 329, 684, L"Белгород-Днестровский"}, + {39, 329, 685, L"Измаил"}, + {39, 329, 689, L"Ильичевск"}, + {39, 329, 686, L"Одесса"}, + {39, 329, 688, L"Рени"}, + {39, 329, 687, L"Слободка"}, + {39, 329, 2552, L"Другое"}, + {39, 330, 690, L"Гадяч"}, + {39, 330, 691, L"Комсомольск"}, + {39, 330, 693, L"Кременчуг"}, + {39, 330, 694, L"Лубны"}, + {39, 330, 695, L"Миргород"}, + {39, 330, 692, L"Полтава"}, + {39, 330, 2551, L"Другое"}, + {39, 331, 696, L"Здолбунов"}, + {39, 331, 697, L"Ровно"}, + {39, 331, 3361, L"Сарны"}, + {39, 331, 2550, L"Другое"}, + {39, 332, 3356, L"Бурынь"}, + {39, 332, 698, L"Конотоп"}, + {39, 332, 700, L"Ромны"}, + {39, 332, 699, L"Сумы"}, + {39, 332, 701, L"Шостка"}, + {39, 332, 2549, L"Другое"}, + {39, 333, 702, L"Бережаны"}, + {39, 333, 3171, L"Борщев"}, + {39, 333, 703, L"Тернополь"}, + {39, 333, 704, L"Чортков"}, + {39, 333, 2548, L"Другое"}, + {39, 334, 705, L"Изюм"}, + {39, 334, 3346, L"Купянск"}, + {39, 334, 3351, L"Купянск"}, + {39, 334, 706, L"Лозовая"}, + {39, 334, 708, L"Мерефа"}, + {39, 334, 707, L"Харьков"}, + {39, 334, 709, L"Чугуев"}, + {39, 334, 2547, L"Другое"}, + {39, 335, 710, L"Геническ"}, + {39, 335, 711, L"Каховка"}, + {39, 335, 712, L"Новая Каховка"}, + {39, 335, 3280, L"Скадовск"}, + {39, 335, 713, L"Херсон"}, + {39, 335, 2546, L"Другое"}, + {39, 336, 714, L"Каменец-Подольский"}, + {39, 336, 715, L"Красилов"}, + {39, 336, 2941, L"Нетишин"}, + {39, 336, 716, L"Полонное"}, + {39, 336, 3120, L"Сатанов"}, + {39, 336, 2943, L"Славута"}, + {39, 336, 717, L"Хмельницкий"}, + {39, 336, 3155, L"Чемировцы"}, + {39, 336, 2542, L"Другое"}, + {39, 337, 3169, L"Золотоноша"}, + {39, 337, 3016, L"Канев"}, + {39, 337, 3333, L"Полонное"}, + {39, 337, 718, L"Умань"}, + {39, 337, 719, L"Христиновка"}, + {39, 337, 720, L"Черкассы"}, + {39, 337, 2545, L"Другое"}, + {39, 338, 721, L"Нежин"}, + {39, 338, 722, L"Прилуки"}, + {39, 338, 723, L"Чернигов"}, + {39, 338, 2544, L"Другое"}, + {39, 339, 724, L"Черновцы"}, + {39, 339, 2543, L"Другое"}, + {340, 342, 725, L"Барановичи"}, + {340, 342, 726, L"Белоозерск"}, + {340, 342, 727, L"Береза"}, + {340, 342, 728, L"Брест"}, + {340, 342, 3172, L"Дрогичин"}, + {340, 342, 729, L"Кобрин"}, + {340, 342, 730, L"Ляховичи"}, + {340, 342, 731, L"Малорита"}, + {340, 342, 732, L"Пинск"}, + {340, 342, 2538, L"Другое"}, + {340, 343, 733, L"Браслав"}, + {340, 343, 735, L"Витебск"}, + {340, 343, 734, L"Новолукомоль"}, + {340, 343, 736, L"Новополоцк"}, + {340, 343, 737, L"Орша"}, + {340, 343, 738, L"Толочин"}, + {340, 343, 2537, L"Другое"}, + {340, 344, 739, L"Гомель"}, + {340, 344, 740, L"Жлобин"}, + {340, 344, 741, L"Мозырь"}, + {340, 344, 742, L"Речица"}, + {340, 344, 743, L"Рогачев"}, + {340, 344, 744, L"Светлогорск"}, + {340, 344, 2536, L"Другое"}, + {340, 345, 745, L"Волковыск"}, + {340, 345, 746, L"Гродно"}, + {340, 345, 747, L"Лида"}, + {340, 345, 3244, L"Слоним"}, + {340, 345, 748, L"Сморгонь"}, + {340, 345, 2535, L"Другое"}, + {340, 346, 3149, L"Березино"}, + {340, 346, 749, L"Борисов"}, + {340, 346, 750, L"Вилейка"}, + {340, 346, 751, L"Жодино"}, + {340, 346, 752, L"Марьина Горка"}, + {340, 346, 753, L"Молодечно"}, + {340, 346, 2896, L"Слуцк"}, + {340, 346, 754, L"Смолевичи"}, + {340, 346, 755, L"Солигорск"}, + {340, 346, 756, L"Червень"}, + {340, 346, 2534, L"Другое"}, + {340, 347, 757, L"Бобруйск"}, + {340, 347, 758, L"Могилев"}, + {340, 347, 759, L"Осиповичи"}, + {340, 347, 2533, L"Другое"}, + {0, 0, 0, NULL} +}; + + + + + +#endif // !defined(AFX_MRA_PLACES_H__INCLUDED_) \ No newline at end of file diff --git a/protocols/MRA/src/MraPopUp.cpp b/protocols/MRA/src/MraPopUp.cpp new file mode 100644 index 0000000000..af399eee9e --- /dev/null +++ b/protocols/MRA/src/MraPopUp.cpp @@ -0,0 +1,309 @@ +#include "Mra.h" +#include "MraPopUp.h" + +#define POPUPS_TYPES_COUNT 7 +static LPCWSTR lpcwszPopupsTypes[] = +{ + L"None", + L"Debug", + L"Information", + L"Question", + L"Warning", + L"Error", + L"NewMail", + NULL +}; + +INT_PTR CALLBACK MraPopupDlgProcOpts(HWND hWndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + CMraProto *ppro = (CMraProto*)GetWindowLongPtr(hWndDlg, GWLP_USERDATA); + + switch (msg) { + case WM_INITDIALOG: + TranslateDialogDefault(hWndDlg); + SetWindowLongPtr(hWndDlg, GWLP_USERDATA, lParam); + ppro = (CMraProto*)lParam; + { + HWND hWndCombo = GetDlgItem(hWndDlg, IDC_COMBO_POPUP_TYPE); + SendMessage(hWndCombo, CB_RESETCONTENT, 0, 0); + + for (size_t i = 0; i < POPUPS_TYPES_COUNT; i++) { + DWORD dwItem = SendMessage(hWndCombo, CB_ADDSTRING, 0, (LPARAM)TranslateW(lpcwszPopupsTypes[i])); + SendMessage(hWndCombo, CB_SETITEMDATA, dwItem, i); + } + SendMessage(hWndCombo, CB_SETCURSEL, 0, 0); + SendMessage(hWndDlg, WM_COMMAND, MAKELONG(IDC_COMBO_POPUP_TYPE, CBN_SELCHANGE), 0); + } + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_COMBO_POPUP_TYPE: + if (HIWORD(wParam) == CBN_SELCHANGE) { + BOOL bEnabled, bUseWinColors; + char szBuff[MAX_PATH]; + DWORD dwType = GET_CURRENT_COMBO_DATA(hWndDlg, IDC_COMBO_POPUP_TYPE); + + bEnabled = GetBit(ppro->mraGetDword(NULL, "PopupsEventFilter", MRA_DEFAULT_POPUPS_EVENT_FILTER), dwType); + CHECK_DLG_BUTTON(hWndDlg, IDC_CHK_ENABLE, bEnabled); + + mir_snprintf(szBuff, SIZEOF(szBuff), "PopupType%SUseWinColors", lpcwszPopupsTypes[dwType]); + bUseWinColors = ppro->mraGetByte(NULL, szBuff, MRA_DEFAULT_POPUP_USE_WIN_COLORS); + CHECK_DLG_BUTTON(hWndDlg, IDC_CHK_USE_WIN_COLORS, bUseWinColors); + EnableWindow(GetDlgItem(hWndDlg, IDC_CHK_USE_WIN_COLORS), bEnabled); + + mir_snprintf(szBuff, SIZEOF(szBuff), "PopupType%SColorBack", lpcwszPopupsTypes[dwType]); + SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_POPUP_BACKCOLOR, CPM_SETCOLOUR, 0, ppro->mraGetDword(NULL, szBuff, MRA_DEFAULT_POPUP_COLOR_BACK)); + EnableWindow(GetDlgItem(hWndDlg, IDC_POPUP_BACKCOLOR), (bEnabled && bUseWinColors == FALSE)); + + mir_snprintf(szBuff, SIZEOF(szBuff), "PopupType%SColorText", lpcwszPopupsTypes[dwType]); + SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_POPUP_TEXTCOLOR, CPM_SETCOLOUR, 0, ppro->mraGetDword(NULL, szBuff, MRA_DEFAULT_POPUP_COLOR_TEXT)); + EnableWindow(GetDlgItem(hWndDlg, IDC_POPUP_TEXTCOLOR), (bEnabled && bUseWinColors == FALSE)); + + mir_snprintf(szBuff, SIZEOF(szBuff), "PopupType%STimeout", lpcwszPopupsTypes[dwType]); + SetDlgItemInt(hWndDlg, IDC_POPUP_TIMEOUT, ppro->mraGetDword(NULL, szBuff, MRA_DEFAULT_POPUP_TIMEOUT), FALSE); + EnableWindow(GetDlgItem(hWndDlg, IDC_POPUP_TIMEOUT), bEnabled); + } + break; + + case IDC_PREVIEW: + { + for (size_t i = 0; i < POPUPS_TYPES_COUNT; i++) { + ppro->MraPopupShowFromAgentW(i, 0, TranslateW(lpcwszPopupsTypes[i])); + } + } + break; + + case IDC_CHK_ENABLE: + case IDC_CHK_USE_WIN_COLORS: + { + BOOL bEnabled = IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_CHK_ENABLE); + BOOL bUseWinColors = IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_CHK_USE_WIN_COLORS); + + EnableWindow(GetDlgItem(hWndDlg, IDC_CHK_USE_WIN_COLORS), bEnabled); + EnableWindow(GetDlgItem(hWndDlg, IDC_POPUP_BACKCOLOR), (bEnabled && bUseWinColors == FALSE)); + EnableWindow(GetDlgItem(hWndDlg, IDC_POPUP_TEXTCOLOR), (bEnabled && bUseWinColors == FALSE)); + EnableWindow(GetDlgItem(hWndDlg, IDC_POPUP_TIMEOUT), bEnabled); + } + default: + if ((LOWORD(wParam) == IDC_POPUP_TIMEOUT) && (HIWORD(wParam) != EN_CHANGE || (HWND)lParam != GetFocus())) + return FALSE; + SendMessage(GetParent(hWndDlg), PSM_CHANGED, 0, 0); + } + break; + + case WM_NOTIFY: + switch (((LPNMHDR)lParam)->code) { + case PSN_APPLY: + { + char szBuff[MAX_PATH]; + DWORD dwType = GET_CURRENT_COMBO_DATA(hWndDlg, IDC_COMBO_POPUP_TYPE); + DWORD dwPopupsEventFilter = ppro->mraGetDword(NULL, "PopupsEventFilter", MRA_DEFAULT_POPUPS_EVENT_FILTER); + if (IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_CHK_ENABLE)) + dwPopupsEventFilter |= (1<mraSetDword(NULL, "PopupsEventFilter", dwPopupsEventFilter); + + mir_snprintf(szBuff, SIZEOF(szBuff), "PopupType%SUseWinColors", lpcwszPopupsTypes[dwType]); + ppro->mraSetByte(NULL, szBuff, IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_CHK_USE_WIN_COLORS)); + + mir_snprintf(szBuff, SIZEOF(szBuff), "PopupType%SColorBack", lpcwszPopupsTypes[dwType]); + ppro->mraSetDword(NULL, szBuff, SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_POPUP_BACKCOLOR, CPM_GETCOLOUR, 0, 0)); + + mir_snprintf(szBuff, SIZEOF(szBuff), "PopupType%SColorText", lpcwszPopupsTypes[dwType]); + ppro->mraSetDword(NULL, szBuff, SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_POPUP_TEXTCOLOR, CPM_GETCOLOUR, 0, 0)); + + mir_snprintf(szBuff, SIZEOF(szBuff), "PopupType%STimeout", lpcwszPopupsTypes[dwType]); + ppro->mraSetDword(NULL, szBuff, GetDlgItemInt(hWndDlg, IDC_POPUP_TIMEOUT, NULL, FALSE)); + } + return TRUE; + } + break; + } + return FALSE; +} + +int CMraProto::OnPopupOptInit(WPARAM wParam, LPARAM lParam) +{ + if ( ServiceExists(MS_POPUP_ADDPOPUP)) { + OPTIONSDIALOGPAGE odp = {0}; + odp.cbSize = sizeof(odp); + odp.dwInitParam = (LPARAM)this; + odp.position = 100000000; + odp.hInstance = masMraSettings.hInstance; + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_POPUPS); + odp.pszTitle = m_szModuleName; + odp.pszGroup = LPGEN("Popups"); + odp.groupPosition = 900000000; + odp.flags = ODPF_BOLDGROUPS; + odp.nIDBottomSimpleControl = IDC_GROUPMAIN; + odp.pfnDlgProc = MraPopupDlgProcOpts; + Options_AddPage(wParam, &odp); + } + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// ShowPopup - popup plugin support + +struct MraPopupData +{ + CMraProto *ppro; + int iPopupType; +}; + +void CALLBACK MraPopupThreadMarandaCallback(ULONG_PTR dwParam) +{ + if (dwParam == 0) + return; + + MraPopupData* dat = (MraPopupData*)((POPUPDATAW*)dwParam)->PluginData; + if (dat->iPopupType == MRA_POPUP_TYPE_EMAIL_STATUS && dat->ppro->hWndEMailPopupStatus) { + // 1: PUDeletePopUp(hWndDlg); + // 1: PUAddPopUpW((POPUPDATAW*)dwParam); + // 2: PUChangeW(hWndEMailPopupStatus, (POPUPDATAW*)dwParam); //- crash :/ + PUChangeTextW(dat->ppro->hWndEMailPopupStatus, ((POPUPDATAW*)dwParam)->lpwzText); + } + else PUAddPopUpW((POPUPDATAW*)dwParam); + + mir_free((void*)dwParam); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Popup plugin window proc + +LRESULT CALLBACK MraPopupDlgProc(HWND hWndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + MraPopupData* dat = (MraPopupData*)PUGetPluginData(hWndDlg); + + switch (msg) { + case UM_INITPOPUP: + if (dat->iPopupType == MRA_POPUP_TYPE_EMAIL_STATUS) { + // update/load avatar + dat->ppro->MraAvatarsQueueGetAvatarSimple(dat->ppro->hAvatarsQueueHandle, GAIF_FORCE, PUGetContact(hWndDlg), 0); + + // delete old email popup + if (dat->ppro->hWndEMailPopupStatus) + PUDeletePopUp(dat->ppro->hWndEMailPopupStatus); + + dat->ppro->hWndEMailPopupStatus = hWndDlg; + } + break; + + case WM_COMMAND: + if (HIWORD(wParam) == STN_CLICKED) { //It was a click on the Popup. + if (dat->iPopupType == MRA_POPUP_TYPE_EMAIL_STATUS) { + CallProtoService(dat->ppro->m_szModuleName, MRA_GOTO_INBOX, 0, 0); + dat->ppro->hWndEMailPopupStatus = NULL; + } + } + PUDeletePopUp(hWndDlg); + break; + + case WM_CONTEXTMENU: + if (dat->iPopupType == MRA_POPUP_TYPE_EMAIL_STATUS) + dat->ppro->hWndEMailPopupStatus = NULL; + PUDeletePopUp(hWndDlg); + break; + + case UM_FREEPLUGINDATA: + if (dat->iPopupType == MRA_POPUP_TYPE_EMAIL_STATUS) + dat->ppro->hWndEMailPopupStatus = NULL; + mir_free(dat); + break; + } + return DefWindowProc(hWndDlg, msg, wParam, lParam); +} + +void CMraProto::MraPopupShowFromContactW(HANDLE hContact, DWORD dwType, DWORD dwFlags, LPWSTR lpszMessage) +{ + WCHAR szNick[MAX_EMAIL_LEN], szEMail[MAX_EMAIL_LEN], szTitle[MAX_CONTACTNAME]; + + mraGetStaticStringW(hContact, "Nick", szNick, SIZEOF(szNick), NULL); + mraGetStaticStringW(hContact, "e-mail", szEMail, SIZEOF(szEMail), NULL); + if (hContact) { + mir_sntprintf(szTitle, SIZEOF(szTitle), L"%s <%s>", szNick, szEMail); + }else { + mir_sntprintf(szTitle, SIZEOF(szTitle), L"%s: %s <%s>", m_tszUserName, szNick, szEMail); + } + MraPopupShowW(hContact, dwType, dwFlags, szTitle, lpszMessage); +} + + +void CMraProto::MraPopupShowW(HANDLE hContact, DWORD dwType, DWORD dwFlags, LPWSTR lpszTitle, LPWSTR lpszMessage) +{ + if (mraGetByte(NULL, "PopupsEnabled", MRA_DEFAULT_POPUPS_ENABLED)) + if (GetBit(mraGetDword(NULL, "PopupsEventFilter", MRA_DEFAULT_POPUPS_EVENT_FILTER), dwType)) + if ( ServiceExists(MS_POPUP_ADDPOPUPW)) { + BOOL bUseWinColors; + char szBuff[MAX_PATH]; + POPUPDATAW *ppd = (POPUPDATAW*)mir_calloc(sizeof(POPUPDATAW)); + + //if ( ServiceExists(MS_POPUP2_SHOW) == FALSE)// yapp used + if (dwType == MRA_POPUP_TYPE_EMAIL_STATUS && hWndEMailPopupStatus) { + // delete old email popup + PUDeletePopUp(hWndEMailPopupStatus); + hWndEMailPopupStatus = NULL; + } + + // load icon + switch (dwType) { + case MRA_POPUP_TYPE_NONE:// proto icon + ppd->lchIcon = (HICON)LoadImage(masMraSettings.hInstance, MAKEINTRESOURCE(IDI_MRA), IMAGE_ICON, 0, 0, LR_SHARED); + break; + case MRA_POPUP_TYPE_DEBUG:// IDI_APPLICATION + ppd->lchIcon = (HICON)LoadImage(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_SHARED); + break; + case MRA_POPUP_TYPE_INFORMATION:// IDI_INFORMATION + ppd->lchIcon = (HICON)LoadImage(NULL, IDI_INFORMATION, IMAGE_ICON, 0, 0, LR_SHARED); + break; + case MRA_POPUP_TYPE_QUESTION:// IDI_QUESTION + ppd->lchIcon = (HICON)LoadImage(NULL, IDI_QUESTION, IMAGE_ICON, 0, 0, LR_SHARED); + break; + case MRA_POPUP_TYPE_WARNING:// IDI_WARNING + ppd->lchIcon = (HICON)LoadImage(NULL, IDI_WARNING, IMAGE_ICON, 0, 0, LR_SHARED); + break; + case MRA_POPUP_TYPE_ERROR:// IDI_ERROR + ppd->lchIcon = (HICON)LoadImage(NULL, IDI_ERROR, IMAGE_ICON, 0, 0, LR_SHARED); + break; + case MRA_POPUP_TYPE_EMAIL_STATUS: + ppd->lchIcon = (HICON)LoadImage(masMraSettings.hInstance, MAKEINTRESOURCE(IDI_MAIL_NOTIFY), IMAGE_ICON, 0, 0, LR_SHARED); + break; + } + + MraPopupData *dat = (MraPopupData*)mir_calloc( sizeof(MraPopupData)); + dat->iPopupType = dwType; + dat->ppro = this; + + ppd->lchContact = hContact; + if (lpszTitle) + lstrcpynW(ppd->lpwzContactName, lpszTitle, SIZEOF(ppd->lpwzContactName)); + if (lpszMessage) + lstrcpynW(ppd->lpwzText, lpszMessage, SIZEOF(ppd->lpwzText)); + ppd->PluginWindowProc = (WNDPROC)MraPopupDlgProc; + ppd->PluginData = dat; + + mir_snprintf(szBuff, SIZEOF(szBuff), "PopupType%SUseWinColors", lpcwszPopupsTypes[dwType]); + bUseWinColors = mraGetByte(NULL, szBuff, MRA_DEFAULT_POPUP_USE_WIN_COLORS); + if (bUseWinColors) { + ppd->colorBack = GetSysColor(COLOR_BTNFACE); + ppd->colorText = GetSysColor(COLOR_WINDOWTEXT); + } + else { + mir_snprintf(szBuff, SIZEOF(szBuff), "PopupType%SColorBack", lpcwszPopupsTypes[dwType]); + ppd->colorBack = mraGetDword(NULL, szBuff, MRA_DEFAULT_POPUP_COLOR_BACK); + + mir_snprintf(szBuff, SIZEOF(szBuff), "PopupType%SColorText", lpcwszPopupsTypes[dwType]); + ppd->colorText = mraGetDword(NULL, szBuff, MRA_DEFAULT_POPUP_COLOR_TEXT); + } + + mir_snprintf(szBuff, SIZEOF(szBuff), "PopupType%STimeout", lpcwszPopupsTypes[dwType]); + ppd->iSeconds = mraGetDword(NULL, szBuff, MRA_DEFAULT_POPUP_TIMEOUT); + + MraPopupThreadMarandaCallback((ULONG_PTR)ppd); + } + else if (dwFlags & MRA_POPUP_ALLOW_MSGBOX) + MessageBox(NULL, lpszMessage, lpszTitle, MB_OK+(dwType == MRA_POPUP_TYPE_WARNING)?MB_ICONERROR:MB_ICONINFORMATION); +} diff --git a/protocols/MRA/src/MraPopUp.h b/protocols/MRA/src/MraPopUp.h new file mode 100644 index 0000000000..722dac168c --- /dev/null +++ b/protocols/MRA/src/MraPopUp.h @@ -0,0 +1,22 @@ +#if !defined(AFX_MRA_POPUP_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_) +#define AFX_MRA_POPUP_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_ + + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + + +#define MRA_POPUP_ALLOW_MSGBOX 1 +#define MRA_POPUP_ALLOW_ENTER 2 + +#define MRA_POPUP_TYPE_NONE 0 // proto icon +#define MRA_POPUP_TYPE_DEBUG 1 // IDI_APPLICATION +#define MRA_POPUP_TYPE_INFORMATION 2 // IDI_INFORMATION +#define MRA_POPUP_TYPE_QUESTION 3 // IDI_QUESTION +#define MRA_POPUP_TYPE_WARNING 4 // IDI_WARNING +#define MRA_POPUP_TYPE_ERROR 5 // IDI_ERROR +#define MRA_POPUP_TYPE_EMAIL_STATUS 6 // + +#endif // !defined(AFX_MRA_POPUP_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_) diff --git a/protocols/MRA/src/MraProto.cpp b/protocols/MRA/src/MraProto.cpp new file mode 100644 index 0000000000..f1b826767c --- /dev/null +++ b/protocols/MRA/src/MraProto.cpp @@ -0,0 +1,739 @@ +#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; +} + +static int MraExtraIconsRebuildAll(WPARAM, LPARAM) +{ + for (int i=0; i < g_Instances.getCount(); i++) + g_Instances[i]->MraExtraIconsRebuild(0, 0); + return 0; +} + +CMraProto::CMraProto(const char* _module, const TCHAR* _displayName) : + m_bLoggedIn(false) +{ + m_iVersion = 2; + m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE; + m_szModuleName = mir_strdup(_module); + m_tszUserName = mir_tstrdup(_displayName); + + InitializeCriticalSectionAndSpinCount(&csCriticalSectionSend, 0); + MraSendQueueInitialize(0, &hSendQueueHandle); + MraFilesQueueInitialize(0, &hFilesQueueHandle); + MraMPopSessionQueueInitialize(&hMPopSessionQueue); + MraAvatarsQueueInitialize(&hAvatarsQueueHandle); + + CreateObjectSvc(PS_ICQ_SETCUSTOMSTATUS, &CMraProto::MraSetXStatus); + CreateObjectSvc(PS_ICQ_SETCUSTOMSTATUSEX, &CMraProto::MraSetXStatusEx); + CreateObjectSvc(PS_ICQ_GETCUSTOMSTATUS, &CMraProto::MraGetXStatus); + CreateObjectSvc(PS_ICQ_GETCUSTOMSTATUSEX, &CMraProto::MraGetXStatusEx); + CreateObjectSvc(PS_ICQ_GETCUSTOMSTATUSICON, &CMraProto::MraGetXStatusIcon); + + CreateObjectSvc(PS_SET_LISTENINGTO, &CMraProto::MraSetListeningTo); + + CreateObjectSvc(PS_CREATEACCMGRUI, &CMraProto::MraCreateAccMgrUI); + CreateObjectSvc(PS_GETAVATARCAPS, &CMraProto::MraGetAvatarCaps); + CreateObjectSvc(PS_GETAVATARINFOT, &CMraProto::MraGetAvatarInfo); + CreateObjectSvc(PS_GETMYAVATART, &CMraProto::MraGetMyAvatar); + + CreateObjectSvc(MS_ICQ_SENDSMS, &CMraProto::MraSendSMS); + CreateObjectSvc(MRA_SEND_NUDGE, &CMraProto::MraSendNudge); + + if ( ServiceExists(MS_NUDGE_SEND)) + heNudgeReceived = CreateHookableEvent(MS_NUDGE); + + TCHAR name[128]; + mir_sntprintf( name, SIZEOF(name), TranslateT("%s connection"), m_tszUserName); + + NETLIBUSER nlu = {0}; + nlu.cbSize = sizeof(nlu); + nlu.flags = NUF_INCOMING | NUF_OUTGOING | NUF_HTTPCONNS | NUF_UNICODE; + nlu.szSettingsModule = m_szModuleName; + nlu.ptszDescriptiveName = name; + hNetlibUser = (HANDLE)CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu); + + HookEvent(ME_SYSTEM_PRESHUTDOWN, &CMraProto::OnPreShutdown); + HookEvent(ME_CLIST_EXTRA_LIST_REBUILD, &CMraProto::MraExtraIconsRebuild); + + InitContactMenu(); + + // xstatus menu + InitXStatusIcons(); + for (size_t i = 0; i < MRA_XSTATUS_COUNT; i++) { + char szServiceName[100]; + mir_snprintf(szServiceName, SIZEOF(szServiceName), "/menuXStatus%ld", i); + CreateObjectSvcParam(szServiceName, &CMraProto::MraXStatusMenu, i); + } + + mir_snprintf(szNewMailSound, SIZEOF(szNewMailSound), "%s: %s", m_szModuleName, MRA_SOUND_NEW_EMAIL); + SkinAddNewSoundEx(szNewMailSound, m_szModuleName, MRA_SOUND_NEW_EMAIL); + + HookEvent(ME_CLIST_PREBUILDSTATUSMENU, &CMraProto::MraRebuildStatusMenu); + MraRebuildStatusMenu(0, 0); + MraExtraIconsRebuild(0, 0); + + hExtraXstatusIcon = ExtraIcon_Register("MRAXstatus", "Mail.ru Xstatus", "MRA_xstatus25", MraExtraIconsRebuildAll, MraExtraIconsApplyAll, NULL, NULL); + hExtraInfo = ExtraIcon_Register("MRAStatus", "Mail.ru extra info", "MRA_xstatus49", MraExtraIconsRebuildAll, MraExtraIconsApplyAll, NULL, NULL); + + bHideXStatusUI = FALSE; + m_iXStatus = mraGetByte(NULL, DBSETTING_XSTATUSID, MRA_MIR_XSTATUS_NONE); + if ( !IsXStatusValid(m_iXStatus)) + m_iXStatus = MRA_MIR_XSTATUS_NONE; + + bChatExists = MraChatRegister(); +} + +CMraProto::~CMraProto() +{ + Netlib_CloseHandle(hNetlibUser); + + DestroyXStatusIcons(); + + if (heNudgeReceived) + DestroyHookableEvent(heNudgeReceived); + + MraMPopSessionQueueDestroy(hMPopSessionQueue); + MraFilesQueueDestroy(hFilesQueueHandle); + MraSendQueueDestroy(hSendQueueHandle); + DeleteCriticalSection(&csCriticalSectionSend); +} + +INT_PTR CMraProto::MraCreateAccMgrUI(WPARAM wParam,LPARAM lParam) +{ + return (int)CreateDialogParam(masMraSettings.hInstance, MAKEINTRESOURCE(IDD_MRAACCOUNT), + (HWND)lParam, DlgProcAccount, LPARAM(this)); +} + +int CMraProto::OnModulesLoaded(WPARAM, LPARAM) +{ + hHookExtraIconsApply = HookEvent(ME_CLIST_EXTRA_IMAGE_APPLY, &CMraProto::MraExtraIconsApply); + HookEvent(ME_OPT_INITIALISE, &CMraProto::OnOptionsInit); + HookEvent(ME_DB_CONTACT_DELETED, &CMraProto::MraContactDeleted); + HookEvent(ME_DB_CONTACT_SETTINGCHANGED, &CMraProto::MraDbSettingChanged); + HookEvent(ME_CLIST_PREBUILDCONTACTMENU, &CMraProto::MraRebuildContactMenu); + HookEvent(ME_WAT_NEWSTATUS, &CMraProto::MraMusicChanged); + + // всех в offline // тк unsaved values сохраняются их нужно инициализировать + for (HANDLE hContact = db_find_first(); hContact != NULL; hContact = db_find_next(hContact)) + SetContactBasicInfoW(hContact, SCBIFSI_LOCK_CHANGES_EVENTS, (SCBIF_ID|SCBIF_GROUP_ID|SCBIF_SERVER_FLAG|SCBIF_STATUS), -1, -1, 0, 0, ID_STATUS_OFFLINE, NULL, 0, NULL, 0, NULL, 0); + + // unsaved values + DB_MraCreateResidentSetting("Status");// NOTE: XStatus cannot be temporary + DB_MraCreateResidentSetting("LogonTS"); + DB_MraCreateResidentSetting("ContactID"); + DB_MraCreateResidentSetting("GroupID"); + DB_MraCreateResidentSetting("ContactFlags"); + DB_MraCreateResidentSetting("ContactSeverFlags"); + DB_MraCreateResidentSetting("HooksLocked"); + DB_MraCreateResidentSetting(DBSETTING_CAPABILITIES); + DB_MraCreateResidentSetting(DBSETTING_XSTATUSNAME); + DB_MraCreateResidentSetting(DBSETTING_XSTATUSMSG); + DB_MraCreateResidentSetting(DBSETTING_BLOGSTATUSTIME); + DB_MraCreateResidentSetting(DBSETTING_BLOGSTATUSID); + DB_MraCreateResidentSetting(DBSETTING_BLOGSTATUS); + DB_MraCreateResidentSetting(DBSETTING_BLOGSTATUSMUSIC); + + // destroy all chat sessions + if (bChatExists) + MraChatSessionDestroy(NULL); + + return 0; +} + +int CMraProto::OnPreShutdown(WPARAM, LPARAM) +{ + SetStatus(ID_STATUS_OFFLINE); + MraAvatarsQueueDestroy(hAvatarsQueueHandle); hAvatarsQueueHandle = NULL; + + if (hThreadWorker) { + if (IsThreadAlive(hThreadWorker)) + WaitForSingleObjectEx(hThreadWorker, (WAIT_FOR_THREAD_TIMEOUT*1000), FALSE); + hThreadWorker = NULL; + } + + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void CMraProto::CreateObjectSvc(const char *szService, ServiceFunc serviceProc) +{ + char str[ MAXMODULELABELLENGTH ]; + strcpy( str, m_szModuleName ); + strcat( str, szService ); + ::CreateServiceFunctionObj( str, ( MIRANDASERVICEOBJ )*( void** )&serviceProc, this ); +} + +void CMraProto::CreateObjectSvcParam( const char *szService, ServiceFuncParam serviceProc, LPARAM lParam ) +{ + char str[ MAXMODULELABELLENGTH ]; + strcpy( str, m_szModuleName ); + strcat( str, szService ); + ::CreateServiceFunctionObjParam( str, ( MIRANDASERVICEOBJPARAM )*( void** )&serviceProc, this, lParam ); +} + +HANDLE CMraProto::HookEvent(const char* szEvent, EventFunc handler) +{ + return ::HookEventObj( szEvent, ( MIRANDAHOOKOBJ )*( void** )&handler, this ); +} + +HANDLE CMraProto::CreateHookableEvent(const char *szService) +{ + char str[ MAXMODULELABELLENGTH ]; + strcpy( str, m_szModuleName ); + strcat( str, szService ); + return ::CreateHookableEvent( str ); +} + +void CMraProto::ForkThread(ThreadFunc pFunc, void *param) +{ + UINT threadID; + CloseHandle(( HANDLE )::mir_forkthreadowner(( pThreadFuncOwner ) *( void** )&pFunc, this, param, &threadID )); +} + +HANDLE CMraProto::ForkThreadEx(ThreadFunc pFunc, void *param, UINT* threadID) +{ + UINT lthreadID; + return ( HANDLE )::mir_forkthreadowner(( pThreadFuncOwner ) *( void** )&pFunc, this, param, threadID ? threadID : <hreadID); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +HANDLE CMraProto::AddToListByEmail(LPCTSTR plpsEMail, LPCTSTR plpsNick, LPCTSTR plpsFirstName, LPCTSTR plpsLastName, DWORD dwFlags) +{ + if (!plpsEMail) + return NULL; + + BOOL bAdded; + HANDLE hContact = MraHContactFromEmail( _T2A(plpsEMail), lstrlen(plpsEMail), TRUE, TRUE, &bAdded); + if (hContact) { + if (plpsNick) + mraSetStringW(hContact, "Nick", plpsNick); + if (plpsFirstName) + mraSetStringW(hContact, "FirstName", plpsFirstName); + if (plpsLastName) + mraSetStringW(hContact, "LastName", plpsLastName); + + if (dwFlags & PALF_TEMPORARY) + DBWriteContactSettingByte(hContact, "CList", "Hidden", 1); + else + DBDeleteContactSetting(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 = CallService(MS_DB_EVENT_GETBLOBSIZE, (WPARAM)hDbEvent, 0)) != -1) { + dbei.pBlob = (PBYTE)alloca(dbei.cbBlob); + if ( CallService(MS_DB_EVENT_GET, (WPARAM)hDbEvent, (LPARAM)&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::SendAwayMsg(HANDLE, HANDLE, const char* ) { return 1; } +int CMraProto::SendUrl(HANDLE, int, const char*) { return 1; } + +///////////////////////////////////////////////////////////////////////////////////////// + +int CMraProto::Authorize(HANDLE hDBEvent) +{ + if (!m_bLoggedIn) return 1; + + DBEVENTINFO dbei = {0}; + dbei.cbSize = sizeof(dbei); + if ((dbei.cbBlob = CallService(MS_DB_EVENT_GETBLOBSIZE, (WPARAM)hDBEvent, 0)) == -1) + return 1; + + dbei.pBlob = (PBYTE)alloca(dbei.cbBlob); + if ( CallService(MS_DB_EVENT_GET, (WPARAM)hDBEvent, (LPARAM)&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 lpszEMail = lpszLastName + lstrlenA(lpszLastName) + 1; + MraAuthorize(lpszEMail, lstrlenA(lpszEMail)); + return 0; +} + +int CMraProto::AuthDeny(HANDLE hDBEvent, const TCHAR* szReason) +{ + if (!m_bLoggedIn) return 1; + + DBEVENTINFO dbei = {0}; + dbei.cbSize = sizeof(dbei); + if ((dbei.cbBlob = CallService(MS_DB_EVENT_GETBLOBSIZE, (WPARAM)hDBEvent, 0)) == -1) + return 1; + + dbei.pBlob = (PBYTE)alloca(dbei.cbBlob); + if ( CallService(MS_DB_EVENT_GET, (WPARAM)hDBEvent, (LPARAM)&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 lpszEMail = lpszLastName + lstrlenA(lpszLastName) + 1; + + MraMessageW(FALSE, NULL, 0, 0, lpszEMail, lstrlenA(lpszEMail), szReason, lstrlen(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; + } +} + +HICON CMraProto::GetIcon(int iconIndex) +{ + UINT id; + + switch (iconIndex & 0xFFFF) { + case PLI_PROTOCOL: id = IDI_MRA; break; // IDI_TM is the main icon for the protocol + default: return NULL; + } + + return (HICON)LoadImage(masMraSettings.hInstance, MAKEINTRESOURCE(id), IMAGE_ICON, + GetSystemMetrics((iconIndex & PLIF_SMALL) ? SM_CXSMICON : SM_CXICON), + GetSystemMetrics((iconIndex & PLIF_SMALL) ? SM_CYSMICON : SM_CYICON), 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, _T2A(email), lstrlen(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, NULL, 0, NULL, 0, + pszNick, lstrlen(pszNick), pszFirstName, lstrlen(pszFirstName), pszLastName, lstrlen(pszLastName), 0, 0, 0, 0, 0, 0, 0, 0, 0); + } + + return NULL; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +int CMraProto::RecvContacts(HANDLE hContact, PROTORECVEVENT* pre) +{ + DBEVENTINFO dbei = {0}; + dbei.cbSize = 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; + CallService(MS_DB_EVENT_ADD, (WPARAM)hContact, (LPARAM)&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; + CHAR szEMail[MAX_EMAIL_LEN]; + LPWSTR lpwszData, lpwszDataCurrent, lpwszNick; + size_t dwDataBuffSize, dwEMailSize, dwStringSize, dwNickSize; + + dwDataBuffSize = (nContacts*(MAX_EMAIL_LEN*2)); + lpwszData = (LPWSTR)mir_calloc((dwDataBuffSize*sizeof(WCHAR))); + if (lpwszData) { + lpwszDataCurrent = lpwszData; + if ( mraGetStaticStringA(hContact, "e-mail", szEMail, SIZEOF(szEMail), &dwEMailSize)) { + for (int i = 0; i < nContacts; i++) { + if ( IsContactMra( hContactsList[i] )) + if ( mraGetStaticStringW(hContactsList[i], "e-mail", lpwszDataCurrent, dwDataBuffSize-(lpwszDataCurrent-lpwszData), &dwStringSize)) { + lpwszDataCurrent += dwStringSize; + *lpwszDataCurrent++ = ';'; + + lpwszNick = GetContactNameW(hContactsList[i]); + dwNickSize = lstrlenW(lpwszNick); + memmove(lpwszDataCurrent, lpwszNick, dwNickSize*sizeof(WCHAR)); + lpwszDataCurrent += dwNickSize; + *lpwszDataCurrent++ = ';'; + } + } + + bSlowSend = mraGetByte(NULL, "SlowSend", MRA_DEFAULT_SLOW_SEND); + iRet = MraMessageW(bSlowSend, hContact, ACKTYPE_CONTACTS, MESSAGE_FLAG_CONTACT, szEMail, dwEMailSize, lpwszData, (lpwszDataCurrent-lpwszData), NULL, 0); + if (bSlowSend == FALSE) + ProtoBroadcastAckAsync(hContact, ACKTYPE_CONTACTS, ACKRESULT_SUCCESS, (HANDLE)iRet, 0); + } + mir_free(lpwszData); + } + } + else ProtoBroadcastAckAsync(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) { + ProtoBroadcastAckAsync(hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, NULL, (LPARAM)"You cannot send when you are offline."); + return 0; + } + + CHAR szEMail[MAX_EMAIL_LEN]; + 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) { + ProtoBroadcastAckAsync(hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, NULL, (LPARAM)"Cant allocate buffer for convert to unicode."); + return 0; + } + + size_t dwEMailSize; + if ( mraGetStaticStringA(hContact, "e-mail", szEMail, SIZEOF(szEMail), &dwEMailSize)) { + BOOL bSlowSend = mraGetByte(NULL, "SlowSend", MRA_DEFAULT_SLOW_SEND); + if ( mraGetByte(NULL, "RTFSendEnable", MRA_DEFAULT_RTF_SEND_ENABLE) && (MraContactCapabilitiesGet(hContact) & FEATURE_FLAG_RTF_MESSAGE)) + dwFlags |= MESSAGE_FLAG_RTF; + + iRet = MraMessageW(bSlowSend, hContact, ACKTYPE_MESSAGE, dwFlags, szEMail, dwEMailSize, lpwszMessage, lstrlen(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 = mraGetWord(hContact, "ApparentMode", 0); + + // Dont send redundant updates + if (mode != dwOldMode) { + CHAR szEMail[MAX_EMAIL_LEN], szPhones[MAX_EMAIL_LEN]; + WCHAR wszNick[MAX_EMAIL_LEN]; + DWORD dwID, dwGroupID, dwContactFlag = 0; + size_t dwEMailSize, dwNickSize, dwPhonesSize; + + GetContactBasicInfoW(hContact, &dwID, &dwGroupID, &dwContactFlag, NULL, NULL, szEMail, SIZEOF(szEMail), &dwEMailSize, wszNick, SIZEOF(wszNick), &dwNickSize, szPhones, SIZEOF(szPhones), &dwPhonesSize); + + dwContactFlag &= ~(CONTACT_FLAG_INVISIBLE | CONTACT_FLAG_VISIBLE); + switch (mode) { + case ID_STATUS_OFFLINE: + dwContactFlag |= CONTACT_FLAG_INVISIBLE; + break; + case ID_STATUS_ONLINE: + dwContactFlag |= CONTACT_FLAG_VISIBLE; + break; + } + + if (MraModifyContactW(hContact, dwID, dwContactFlag, dwGroupID, szEMail, dwEMailSize, wszNick, dwNickSize, szPhones, dwPhonesSize)) { + SetContactBasicInfoW(hContact, 0, SCBIF_FLAG, 0, 0, dwContactFlag, 0, 0, NULL, 0, NULL, 0, NULL, 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) { + // функция сама проверяет принадлежность контакта к MRA + for (HANDLE hContact = db_find_first();hContact != NULL;hContact = db_find_next(hContact)) + SetContactBasicInfoW(hContact, SCBIFSI_LOCK_CHANGES_EVENTS, (SCBIF_ID|SCBIF_GROUP_ID|SCBIF_SERVER_FLAG|SCBIF_STATUS), -1, -1, 0, 0, ID_STATUS_OFFLINE, NULL, 0, NULL, 0, NULL, 0); + } + Netlib_CloseHandle(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, NULL, 0, NULL, 0); + 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); + ProtoBroadcastAckAsync(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], szBlogStatus[MICBLOG_STATUS_MAX+4], szTime[64]; + DWORD dwTime; + size_t dwStatusDescSize; + int iRet = 0; + + if ( mraGetStaticStringW(hContact, DBSETTING_BLOGSTATUS, szBlogStatus, SIZEOF(szBlogStatus), NULL)) { + SYSTEMTIME tt = {0}; + dwTime = mraGetDword(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; + + dwStatusDescSize = mir_sntprintf(szStatusDesc, SIZEOF(szStatusDesc), _T("%s%s"), szTime, szBlogStatus); + iRet = GetTickCount(); + ProtoBroadcastAckAsync(hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)iRet, (LPARAM)szStatusDesc, (dwStatusDescSize+1)*sizeof(TCHAR)); + } + 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, NULL, 0, msg, dwStatusDescSize); + } + return 0; +} + +int CMraProto::UserIsTyping(HANDLE hContact, int type) +{ + if (!m_bLoggedIn || !hContact || type == PROTOTYPE_SELFTYPING_OFF) + return 1; + + CHAR szEMail[MAX_EMAIL_LEN]; + size_t dwEMailSize; + + if ( MraGetContactStatus(hContact) != ID_STATUS_OFFLINE && m_iStatus != ID_STATUS_INVISIBLE) + if ( mraGetStaticStringA(hContact, "e-mail", szEMail, SIZEOF(szEMail), &dwEMailSize)) + if ( MraMessageW(FALSE, hContact, 0, MESSAGE_FLAG_NOTIFY, szEMail, dwEMailSize, L" ", 1, 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: + InitMainMenu(); + break; + } + return 1; +} diff --git a/protocols/MRA/src/MraProto.h b/protocols/MRA/src/MraProto.h new file mode 100644 index 0000000000..7c3302119c --- /dev/null +++ b/protocols/MRA/src/MraProto.h @@ -0,0 +1,377 @@ +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define SCBIFSI_LOCK_CHANGES_EVENTS 1 +#define SCBIF_ID 1 +#define SCBIF_GROUP_ID 2 +#define SCBIF_FLAG 4 +#define SCBIF_SERVER_FLAG 8 +#define SCBIF_STATUS 16 +#define SCBIF_EMAIL 32 +#define SCBIF_NICK 64 +#define SCBIF_PHONES 128 + +#define MAIN_MENU_ITEMS_COUNT 15 +#define CONTACT_MENU_ITEMS_COUNT 10 +#define ADV_ICON_MAX 5 + +struct MRA_FILES_QUEUE_ITEM; + +struct CMraProto; +typedef void (__cdecl CMraProto::*ThreadFunc)(void*); +typedef int (__cdecl CMraProto::*EventFunc)(WPARAM, LPARAM); +typedef INT_PTR (__cdecl CMraProto::*ServiceFunc)(WPARAM, LPARAM); +typedef INT_PTR (__cdecl CMraProto::*ServiceFuncParam)(WPARAM, LPARAM, LPARAM); + +BOOL DB_GetStaticStringA(HANDLE hContact, LPCSTR lpszModule, LPCSTR lpszValueName, LPSTR lpszRetBuff, size_t dwRetBuffSize, size_t *pdwRetBuffSize); +BOOL DB_GetStaticStringW(HANDLE hContact, LPCSTR lpszModule, LPCSTR lpszValueName, LPWSTR lpszRetBuff, size_t dwRetBuffSize, size_t *pdwRetBuffSize); + +BOOL DB_SetStringExA(HANDLE hContact, LPCSTR lpszModule, LPCSTR lpszValueName, LPCSTR lpszValue, size_t dwValueSize); +BOOL DB_SetStringExW(HANDLE hContact, LPCSTR lpszModule, LPCSTR lpszValueName, LPCWSTR lpwszValue, size_t dwValueSize); + +int DB_WriteContactSettingBlob(HANDLE hContact, LPCSTR lpszModule, LPCSTR lpszValueName, LPVOID lpValue, size_t dwValueSize); +BOOL DB_GetContactSettingBlob(HANDLE hContact, LPCSTR lpszModule, LPCSTR lpszValueName, LPVOID lpRet, size_t dwRetBuffSize, size_t *pdwRetBuffSize); + +struct CMraProto : public PROTO_INTERFACE, public MZeroedObject +{ + CMraProto(const char*, const TCHAR*); + ~CMraProto(); + + // ==================================================================================== + // PROTO_INTERFACE + // ==================================================================================== + + virtual HANDLE __cdecl AddToList(int flags, PROTOSEARCHRESULT* psr); + virtual HANDLE __cdecl AddToListByEvent(int flags, int iContact, HANDLE hDbEvent); + + virtual int __cdecl Authorize(HANDLE hDBEvent); + virtual int __cdecl AuthDeny(HANDLE hContact, const TCHAR* szReason); + virtual int __cdecl AuthRecv(HANDLE hContact, PROTORECVEVENT*); + virtual int __cdecl AuthRequest(HANDLE hContact, const TCHAR* szMessage); + + virtual HANDLE __cdecl ChangeInfo(int iInfoType, void* pInfoData); + + virtual HANDLE __cdecl FileAllow(HANDLE hContact, HANDLE hTransfer, const TCHAR* szPath); + virtual int __cdecl FileCancel(HANDLE hContact, HANDLE hTransfer); + virtual int __cdecl FileDeny(HANDLE hContact, HANDLE hTransfer, const TCHAR* szReason); + virtual int __cdecl FileResume(HANDLE hTransfer, int* action, const TCHAR** szFilename); + + virtual DWORD_PTR __cdecl GetCaps(int type, HANDLE hContact = NULL); + virtual HICON __cdecl GetIcon(int iconIndex); + virtual int __cdecl GetInfo(HANDLE hContact, int infoType); + + virtual HANDLE __cdecl SearchBasic(const TCHAR* id); + virtual HANDLE __cdecl SearchByEmail(const TCHAR* email); + virtual HANDLE __cdecl SearchByName(const TCHAR* nick, const TCHAR* firstName, const TCHAR* lastName); + virtual HWND __cdecl SearchAdvanced(HWND owner); + virtual HWND __cdecl CreateExtendedSearchUI(HWND owner); + + virtual int __cdecl RecvContacts(HANDLE hContact, PROTORECVEVENT*); + virtual int __cdecl RecvFile(HANDLE hContact, PROTORECVFILET*); + virtual int __cdecl RecvMsg(HANDLE hContact, PROTORECVEVENT*); + virtual int __cdecl RecvUrl(HANDLE hContact, PROTORECVEVENT*); + + virtual int __cdecl SendContacts(HANDLE hContact, int flags, int nContacts, HANDLE* hContactsList); + virtual HANDLE __cdecl SendFile(HANDLE hContact, const TCHAR* szDescription, TCHAR** ppszFiles); + virtual int __cdecl SendMsg(HANDLE hContact, int flags, const char* msg); + virtual int __cdecl SendUrl(HANDLE hContact, int flags, const char* url); + + virtual int __cdecl SetApparentMode(HANDLE hContact, int mode); + virtual int __cdecl SetStatus(int iNewStatus); + + virtual HANDLE __cdecl GetAwayMsg(HANDLE hContact); + virtual int __cdecl RecvAwayMsg(HANDLE hContact, int mode, PROTORECVEVENT* evt); + virtual int __cdecl SendAwayMsg(HANDLE hContact, HANDLE hProcess, const char* msg); + virtual int __cdecl SetAwayMsg(int m_iStatus, const TCHAR* msg); + + virtual int __cdecl UserIsTyping(HANDLE hContact, int type); + + virtual int __cdecl OnEvent(PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM lParam); + + void CreateObjectSvc(const char* szService, ServiceFunc serviceProc); + void CreateObjectSvcParam(const char* szService, ServiceFuncParam serviceProc, LPARAM lParam); + HANDLE CreateHookableEvent(const char* szService); + void ForkThread(ThreadFunc, void*); + HANDLE ForkThreadEx(ThreadFunc, void*, UINT* threadID = NULL); + HANDLE HookEvent(const char*, EventFunc); + + void ShowFormattedErrorMessage(LPWSTR lpwszErrText, DWORD dwErrorCode); + void MraPopupShowW(HANDLE hContact, DWORD dwType, DWORD dwFlags, LPWSTR lpszTitle, LPWSTR lpszMessage); + void MraPopupShowFromContactW(HANDLE hContact, DWORD dwType, DWORD dwFlags, LPWSTR lpszMessage); + __forceinline void MraPopupShowFromAgentW(DWORD dwType, DWORD dwFlags, LPWSTR lpszMessage) { + MraPopupShowFromContactW(NULL, dwType, dwFlags, lpszMessage); } + + __forceinline void mraDelValue(HANDLE Contact, const char *valueName) { + db_unset(Contact, m_szModuleName, valueName); } + + __forceinline DWORD mraGetDword(HANDLE Contact, const char *valueName, DWORD parDefltValue) { + return db_get_dw(Contact, m_szModuleName, valueName, parDefltValue); } + __forceinline void mraSetDword(HANDLE Contact, const char *valueName, DWORD parValue) { + db_set_dw(Contact, m_szModuleName, valueName, parValue); } + + __forceinline WORD mraGetWord(HANDLE Contact, const char *valueName, WORD parDefltValue) { + return db_get_w(Contact, m_szModuleName, valueName, parDefltValue); } + __forceinline void mraSetWord(HANDLE Contact, const char *valueName, WORD parValue) { + db_set_w(Contact, m_szModuleName, valueName, parValue); } + + __forceinline BYTE mraGetByte(HANDLE Contact, const char *valueName, BYTE parDefltValue) { + return db_get_b(Contact, m_szModuleName, valueName, parDefltValue); } + __forceinline void mraSetByte(HANDLE Contact, const char *valueName, BYTE parValue) { + db_set_b(Contact, m_szModuleName, valueName, parValue); } + + __forceinline BOOL mraGetStaticStringA(HANDLE Contact, const char *ValueName, char *Ret, size_t RetBuffSize, size_t *pRetBuffSize) { + return DB_GetStaticStringA(Contact, m_szModuleName, ValueName, Ret, RetBuffSize, pRetBuffSize); } + __forceinline BOOL mraGetStaticStringW(HANDLE Contact, const char *ValueName, WCHAR *Ret, size_t RetBuffSize, size_t *pRetBuffSize) { + return DB_GetStaticStringW(Contact, m_szModuleName, ValueName, Ret, RetBuffSize, pRetBuffSize); } + + __forceinline BOOL mraSetStringA(HANDLE Contact, const char *valueName, const char *parValue) { + return DB_SetStringExA(Contact, m_szModuleName, valueName, parValue, lstrlenA(parValue)); } + __forceinline BOOL mraSetStringW(HANDLE Contact, const char *valueName, const WCHAR *parValue) { + return DBWriteContactSettingWString(Contact, m_szModuleName, valueName, parValue); } + + __forceinline BOOL mraSetLPSStringA(HANDLE Contact, const char *valueName, MRA_LPS *parValue) { + return DB_SetStringExA(Contact, m_szModuleName, valueName, parValue->lpszData, parValue->dwSize); } + __forceinline BOOL mraSetLPSStringW(HANDLE Contact, const char *valueName, MRA_LPS *parValue) { + return DB_SetStringExW(Contact, m_szModuleName, valueName, parValue->lpwszData, parValue->dwSize/sizeof(WCHAR)); } + + __forceinline BOOL mraSetStringExA(HANDLE Contact, const char *valueName, const char *parValue, size_t parValueSize) { + return DB_SetStringExA(Contact, m_szModuleName, valueName, parValue, parValueSize); } + __forceinline BOOL mraSetStringExW(HANDLE Contact, const char *valueName, const WCHAR *parValue, size_t parValueSize) { + return DB_SetStringExW(Contact, m_szModuleName, valueName, parValue, parValueSize); } + + __forceinline BOOL mraWriteContactSettingBlob(HANDLE hContact, const char *lpszValueName, LPVOID lpbValue, size_t dwValueSize) { + return DB_WriteContactSettingBlob(hContact, m_szModuleName, lpszValueName, lpbValue, dwValueSize); } + __forceinline BOOL mraGetContactSettingBlob(HANDLE hContact, const char *lpszValueName, LPVOID lpbRet, size_t dwRetBuffSize, size_t *pdwRetBuffSize) { + return DB_GetContactSettingBlob(hContact, m_szModuleName, lpszValueName, lpbRet, dwRetBuffSize, pdwRetBuffSize); } + + // ====| Services |==================================================================== + INT_PTR __cdecl MraSetXStatus(WPARAM, LPARAM); + INT_PTR __cdecl MraSetXStatusEx(WPARAM, LPARAM); + INT_PTR __cdecl MraGetXStatus(WPARAM, LPARAM); + INT_PTR __cdecl MraGetXStatusEx(WPARAM, LPARAM); + INT_PTR __cdecl MraGetXStatusIcon(WPARAM, LPARAM); + INT_PTR __cdecl MraXStatusMenu(WPARAM, LPARAM, LPARAM param); + + INT_PTR __cdecl MraSetListeningTo(WPARAM, LPARAM); + + INT_PTR __cdecl MraSendNudge(WPARAM, LPARAM); + + INT_PTR __cdecl MraGetAvatarCaps(WPARAM, LPARAM); + INT_PTR __cdecl MraGetAvatarInfo(WPARAM, LPARAM); + INT_PTR __cdecl MraGetMyAvatar(WPARAM, LPARAM); + + INT_PTR __cdecl MraSendSMS(WPARAM, LPARAM); + + INT_PTR __cdecl MraGotoInbox(WPARAM, LPARAM); + INT_PTR __cdecl MraShowInboxStatus(WPARAM, LPARAM); + INT_PTR __cdecl MraEditProfile(WPARAM, LPARAM); + INT_PTR __cdecl MraZhuki(WPARAM, LPARAM); + INT_PTR __cdecl MraChat(WPARAM, LPARAM); + INT_PTR __cdecl MraWebSearch(WPARAM, LPARAM); + INT_PTR __cdecl MraUpdateAllUsersInfo(WPARAM, LPARAM); + INT_PTR __cdecl MraCheckUpdatesUsersAvt(WPARAM, LPARAM); + INT_PTR __cdecl MraRequestAuthForAll(WPARAM, LPARAM); + + INT_PTR __cdecl MraRequestAuthorization(WPARAM, LPARAM); + INT_PTR __cdecl MraGrantAuthorization(WPARAM, LPARAM); + INT_PTR __cdecl MraSendPostcard(WPARAM, LPARAM); + INT_PTR __cdecl MraViewAlbum(WPARAM, LPARAM); + INT_PTR __cdecl MraReadBlog(WPARAM, LPARAM); + INT_PTR __cdecl MraReplyBlogStatus(WPARAM, LPARAM); + INT_PTR __cdecl MraViewVideo(WPARAM, LPARAM); + INT_PTR __cdecl MraAnswers(WPARAM, LPARAM); + INT_PTR __cdecl MraWorld(WPARAM, LPARAM); + INT_PTR __cdecl MraCreateAccMgrUI(WPARAM, LPARAM); + + // ====| Events |====================================================================== + int __cdecl OnModulesLoaded(WPARAM, LPARAM); + int __cdecl OnPreShutdown(WPARAM, LPARAM); + int __cdecl OnOptionsInit(WPARAM, LPARAM); + int __cdecl OnPopupOptInit(WPARAM, LPARAM); + + int __cdecl MraChatGcEventHook(WPARAM, LPARAM); + + int __cdecl MraExtraIconsApply(WPARAM, LPARAM); + int __cdecl MraExtraIconsRebuild(WPARAM, LPARAM); + + int __cdecl MraContactDeleted(WPARAM, LPARAM); + int __cdecl MraDbSettingChanged(WPARAM, LPARAM); + int __cdecl MraRebuildContactMenu(WPARAM, LPARAM); + int __cdecl MraRebuildStatusMenu(WPARAM, LPARAM); + int __cdecl MraMusicChanged(WPARAM, LPARAM); + + // ====| Data |======================================================================== + bool m_bLoggedIn; + + HANDLE hSendQueueHandle, hFilesQueueHandle, hMPopSessionQueue; + + HANDLE hNetlibUser, heNudgeReceived, hHookExtraIconsApply; + HANDLE hThreadWorker; + HANDLE hConnection; + DWORD dwThreadWorkerLastPingTime; + DWORD dwThreadWorkerRunning; + DWORD dwCMDNum; + + HANDLE hAvatarsQueueHandle; + + HANDLE hMainMenuItems[MAIN_MENU_ITEMS_COUNT+4]; + HANDLE hContactMenuItems[CONTACT_MENU_ITEMS_COUNT+4]; + HANDLE hAdvancedStatusItems[ADV_ICON_MAX+4]; + + HWND hWndEMailPopupStatus; + DWORD dwEmailMessagesTotal, dwEmailMessagesUnread; + + BOOL bHideXStatusUI; + HANDLE hXStatusMenuItems[MRA_XSTATUS_COUNT+4]; + HANDLE hXStatusAdvancedStatusIcons[MRA_XSTATUS_COUNT+4]; + HANDLE hXStatusAdvancedStatusItems[MRA_XSTATUS_COUNT+4]; + HANDLE hExtraXstatusIcon; + HANDLE hExtraInfo; + + char szNewMailSound[MAX_PATH]; + + CRITICAL_SECTION csCriticalSectionSend; + + HANDLE AddToListByEmail(LPCTSTR plpsEMail, LPCTSTR plpsNick, LPCTSTR plpsFirstName, LPCTSTR plpsLastName, DWORD dwFlags); + + DWORD MraMessageW(BOOL bAddToQueue, HANDLE hContact, DWORD dwAckType, DWORD dwFlags, LPSTR lpszEMail, size_t dwEMailSize, LPCWSTR lpwszMessage, size_t dwMessageSize, LPBYTE lpbMultiChatData, size_t dwMultiChatDataSize); + DWORD MraMessageAskW(DWORD dwMsgID, DWORD dwFlags, LPSTR lpszEMail, size_t dwEMailSize, LPWSTR lpwszMessage, size_t dwMessageSize, LPSTR lpwszMessageRTF, size_t dwMessageRTFSize); + DWORD MraMessageRecv(LPSTR lpszFrom, size_t dwFromSize, DWORD dwMsgID); + DWORD MraAddContactW(HANDLE hContact, DWORD dwContactFlag, DWORD dwGroupID, LPSTR lpszEMail, size_t dwEMailSize, LPWSTR lpwszCustomName, size_t dwCustomNameSize, LPSTR lpszPhones, size_t dwPhonesSize, LPWSTR lpwszAuthMessage, size_t dwAuthMessageSize, DWORD dwActions); + DWORD MraModifyContactW(HANDLE hContact, DWORD dwID, DWORD dwContactFlag, DWORD dwGroupID, LPSTR lpszEMail, size_t dwEMailSize, LPWSTR lpwszCustomName, size_t dwCustomNameSize, LPSTR lpszPhones, size_t dwPhonesSize); + DWORD MraOfflineMessageDel(DWORDLONG dwMsgUIDL); + DWORD MraAuthorize(LPSTR lpszEMail, size_t dwEMailSize); + DWORD MraChangeStatusW(DWORD dwStatus, LPSTR lpszStatusUri, size_t dwStatusUriSize, LPCWSTR lpwszStatusTitle, size_t dwStatusTitleSize, LPCWSTR lpwszStatusDesc, size_t dwStatusDescSize, DWORD dwFutureFlags); + DWORD MraFileTransfer(LPSTR lpszEMail, size_t dwEMailSize, DWORD dwIdRequest, DWORD dwFilesTotalSize, LPWSTR lpwszFiles, size_t dwFilesSize, LPSTR lpszAddreses, size_t dwAddresesSize); + DWORD MraFileTransferAck(DWORD dwStatus, LPSTR lpszEMail, size_t dwEMailSize, DWORD dwIdRequest, LPBYTE lpbDescription, size_t dwDescriptionSize); + HANDLE MraWPRequestW(HANDLE hContact, DWORD dwAckType, DWORD dwRequestFlags, LPSTR lpszUser, size_t dwUserSize, LPSTR lpszDomain, size_t dwDomainSize, LPCWSTR lpwszNickName, size_t dwNickNameSize, LPCWSTR lpwszFirstName, size_t dwFirstNameSize, LPCWSTR lpwszLastName, size_t dwLastNameSize, DWORD dwSex, DWORD dwDate1, DWORD dwDate2, DWORD dwCityID, DWORD dwZodiak, DWORD dwBirthdayMonth, DWORD dwBirthdayDay, DWORD dwCountryID, DWORD dwOnline); + HANDLE MraWPRequestA(HANDLE hContact, DWORD dwAckType, DWORD dwRequestFlags, LPSTR lpszUser, size_t dwUserSize, LPSTR lpszDomain, size_t dwDomainSize, LPSTR lpszNickName, size_t dwNickNameSize, LPSTR lpszFirstName, size_t dwFirstNameSize, LPSTR lpszLastName, size_t dwLastNameSize, DWORD dwSex, DWORD dwDate1, DWORD dwDate2, DWORD dwCityID, DWORD dwZodiak, DWORD dwBirthdayMonth, DWORD dwBirthdayDay, DWORD dwCountryID, DWORD dwOnline); + HANDLE MraWPRequestByEMail(HANDLE hContact, DWORD dwAckType, LPCSTR lpszEMail, size_t dwEMailSize); + DWORD MraGame(LPSTR lpszEMail, size_t dwEMailSize, DWORD dwGameSessionID, DWORD dwGameMsg, DWORD dwGameMsgID, LPSTR lpszData, size_t dwDataSize); + DWORD MraLogin2W(LPSTR lpszLogin, size_t dwLoginSize, LPSTR lpszPassword, size_t dwPasswordSize, DWORD dwStatus, LPSTR lpszStatusUri, size_t dwStatusUriSize, LPWSTR lpwszStatusTitle, size_t dwStatusTitleSize, LPWSTR lpwszStatusDesc, size_t dwStatusDescSize, DWORD dwFutureFlags, LPSTR dwUserAgentFormatted, size_t dwUserAgentFormattedSize, LPSTR lpszUserAgent, size_t dwUserAgentSize); + DWORD MraSMSW(HANDLE hContact, LPSTR lpszPhone, size_t dwPhoneSize, LPWSTR lpwszMessage, size_t dwMessageSize); + DWORD MraProxy(LPSTR lpszEMail, size_t dwEMailSize, DWORD dwIDRequest, DWORD dwDataType, LPSTR lpszData, size_t dwDataSize, LPSTR lpszAddreses, size_t dwAddresesSize, MRA_GUID mguidSessionID); + DWORD MraProxyAck(DWORD dwStatus, LPSTR lpszEMail, size_t dwEMailSize, DWORD dwIDRequest, DWORD dwDataType, LPSTR lpszData, size_t dwDataSize, LPSTR lpszAddreses, size_t dwAddresesSize, MRA_GUID mguidSessionID); + DWORD MraChangeUserBlogStatus(DWORD dwFlags, LPWSTR lpwszText, size_t dwTextSize, DWORDLONG dwBlogStatusID); + + DWORD MraSendPacket(HANDLE hConnection, DWORD dwCMDNum, DWORD dwType, LPVOID lpData, size_t dwDataSize); + DWORD MraSendCMD(DWORD dwType, LPVOID lpData, size_t dwDataSize); + DWORD MraSendQueueCMD(HANDLE hSendQueueHandle, DWORD dwFlags, HANDLE hContact, DWORD dwAckType, LPBYTE lpbDataQueue, size_t dwDataQueueSize, DWORD dwType, LPVOID lpData, size_t dwDataSize); + + DWORD MraSendNewStatus(DWORD dwStatusMir, DWORD dwXStatusMir, LPCWSTR lpwszStatusTitle, size_t dwStatusTitleSize, LPCWSTR lpwszStatusDesc, size_t dwStatusDescSize); + + void MraAddrListStoreToContact(HANDLE hContact, MRA_ADDR_LIST *pmalAddrList); + + void DB_MraCreateResidentSetting(LPSTR lpszValueName); + + DWORD GetContactFlags(HANDLE hContact); + DWORD SetContactFlags(HANDLE hContact, DWORD dwContactFlag); + DWORD GetContactBasicInfoW(HANDLE hContact, DWORD *pdwID, DWORD *pdwGroupID, DWORD *pdwContactFlag, DWORD *pdwContactSeverFlags, DWORD *pdwStatus, LPSTR lpszEMail, size_t dwEMailSize, size_t *pdwEMailSize, LPWSTR lpwszNick, size_t dwNickSize, size_t *pdwNickSize, LPSTR lpszPhones, size_t dwPhonesSize, size_t *pdwPhonesSize); + DWORD SetContactBasicInfoW(HANDLE hContact, DWORD dwSetInfoFlags, DWORD dwFlags, DWORD dwID, DWORD dwGroupID, DWORD dwContactFlag, DWORD dwContactSeverFlags, DWORD dwStatus, LPSTR lpszEMail, size_t dwEMailSize, LPWSTR lpwszNick, size_t dwNickSize, LPSTR lpszPhones, size_t dwPhonesSize); + + DWORD GetContactEMailCount(HANDLE hContact, BOOL bMRAOnly); + BOOL GetContactFirstEMail(HANDLE hContact, BOOL bMRAOnly, LPSTR lpszRetBuff, size_t dwRetBuffSize, size_t *pdwRetBuffSize); + + BOOL IsContactMra(HANDLE hContact); + BOOL IsEMailMy(LPSTR lpszEMail, size_t dwEMailSize); + BOOL IsEMailChatAgent(LPSTR lpszEMail, size_t dwEMailSize); + BOOL IsContactChatAgent(HANDLE hContact); + + HANDLE MraHContactFromEmail(LPSTR lpszEMail, size_t dwEMailSize, BOOL bAddIfNeeded, BOOL bTemporary, BOOL *pbAdded); + BOOL MraUpdateContactInfo(HANDLE hContact); + DWORD MraSetXStatusInternal(DWORD dwXStatus); + DWORD MraGetContactStatus(HANDLE hContact); + DWORD MraSetContactStatus(HANDLE hContact, DWORD dwNewStatus); + DWORD MraContactCapabilitiesGet(HANDLE hContact); + void MraContactCapabilitiesSet(HANDLE hContact, DWORD dwFutureFlags); + void MraUpdateEmailStatus(LPSTR lpszFrom, size_t dwFromSize, LPSTR lpszSubject, size_t dwSubjectSize, DWORD dwDate, DWORD dwUIDL); + DWORD MraConvertToRTFW(LPCWSTR lpwszMessage, size_t dwMessageSize, LPSTR lpszMessageRTF, size_t dwMessageRTFBuffSize, size_t *pdwMessageRTFSize); + + void MraThreadClean(); + DWORD StartConnect(); + void __cdecl MraThreadProc(LPVOID lpParameter); + DWORD MraGetNLBData(LPSTR lpszHost, size_t dwHostBuffSize, WORD *pwPort); + DWORD MraNetworkDispatcher(); + DWORD MraCommandDispatcher(struct mrim_packet_header_t *pmaHeader, DWORD *pdwPingPeriod, DWORD *pdwNextPingSendTickTime, BOOL *pbContinue); + + DWORD MraRecvCommand_Message(DWORD dwTime, DWORD dwFlags, MRA_LPS *plpsFrom, MRA_LPS *plpsText, MRA_LPS *plpsRFTText, MRA_LPS *plpsMultiChatData); + + void InitXStatusIcons(); + void DestroyXStatusIcons(); + void SetExtraIcons(HANDLE hContact); + + #define MESSAGE_NOT_SPAM 1 + #define MESSAGE_SPAM 2 + + DWORD MraAntiSpamReceivedMessageW(LPSTR lpszEMail, size_t dwEMailSize, DWORD dwMessageFlags, LPWSTR lpwszMessage, size_t dwMessageSize); + BOOL MraAntiSpamHasMessageBadWordsW(LPWSTR lpwszMessage, size_t dwMessageSize); + + void InitMainMenu(); + void InitContactMenu(); + void CListCreateMenu(LONG lPosition, LONG lPopupPosition, HICON hMainIcon, LPSTR pszContactOwner, BOOL bIsStatus, const struct GUI_DISPLAY_ITEM *pgdiItems, size_t dwCount, HANDLE *hResult); + void CListShowMenuItem(HANDLE hMenuItem, BOOL bShow); + + DWORD ProtoBroadcastAckAsync(HANDLE hContact, int type, int hResult, HANDLE hProcess, LPARAM lParam, size_t paramSize = 0); + DWORD CreateBlobFromContact(HANDLE hContact, LPWSTR lpwszRequestReason, size_t dwRequestReasonSize, LPBYTE lpbBuff, size_t dwBuffSize, size_t *pdwBuffSizeRet); + + BOOL SetPassDB(LPSTR lpszBuff, size_t dwBuffSize); + BOOL GetPassDB(LPSTR lpszBuff, size_t dwBuffSize, size_t *pdwBuffSize); + BOOL GetPassDB_v1(LPSTR lpszBuff, size_t dwBuffSize, size_t *pdwBuffSize); + BOOL GetPassDB_v2(LPSTR lpszBuff, size_t dwBuffSize, size_t *pdwBuffSize); + + BOOL MraRequestXStatusDetails(DWORD dwXStatus); + BOOL MraSendReplyBlogStatus(HANDLE hContact); + DWORD MraSelectEMailDlgShow(HANDLE hContact, DWORD dwType); + + DWORD MraMrimProxyConnect(HANDLE hMraMrimProxyData, HANDLE *phConnection); + + DWORD MraMPopSessionQueueAddUrl(HANDLE hMPopSessionQueue, LPSTR lpszUrl, size_t dwUrlSize); + DWORD MraMPopSessionQueueAddUrlAndEMail(HANDLE hMPopSessionQueue, LPSTR lpszUrl, size_t dwUrlSize, LPSTR lpszEMail, size_t dwEMailSize); + DWORD MraMPopSessionQueueStart(HANDLE hMPopSessionQueue); + void MraMPopSessionQueueFlush(HANDLE hMPopSessionQueue); + + size_t MraFilesQueueGetLocalAddressesList(LPSTR lpszBuff, size_t dwBuffSize, DWORD dwPort); + DWORD MraFilesQueueAddReceive(HANDLE hFilesQueueHandle, DWORD dwFlags, HANDLE hContact, DWORD dwIDRequest, LPWSTR lpwszFiles, size_t dwFilesSize, LPSTR lpszAddreses, size_t dwAddresesSize); + DWORD MraFilesQueueAddSend(HANDLE hFilesQueueHandle, DWORD dwFlags, HANDLE hContact, LPWSTR *plpwszFiles, size_t dwFilesCount, DWORD *pdwIDRequest); + DWORD MraFilesQueueCancel(HANDLE hFilesQueueHandle, DWORD dwIDRequest, BOOL bSendDecline); + DWORD MraFilesQueueStartMrimProxy(HANDLE hFilesQueueHandle, DWORD dwIDRequest); + DWORD MraFilesQueueSendMirror(HANDLE hFilesQueueHandle, DWORD dwIDRequest, LPSTR lpszAddreses, size_t dwAddresesSize); + BOOL MraFilesQueueHandCheck(HANDLE hConnection, MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem); + HANDLE MraFilesQueueConnectOut(MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem); + HANDLE MraFilesQueueConnectIn(MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem); + DWORD MraFilesQueueAccept(HANDLE hFilesQueueHandle, DWORD dwIDRequest, LPCWSTR lpwszPath, size_t dwPathSize); + + void __cdecl MraFilesQueueRecvThreadProc(LPVOID lpParameter); + void __cdecl MraFilesQueueSendThreadProc(LPVOID lpParameter); + + BOOL bChatExists; + void MraChatDllError(); + BOOL MraChatRegister(); + INT_PTR MraChatSessionNew(HANDLE hContactChatSession); + void MraChatSessionDestroy(HANDLE hContactChatSession); + void MraChatSendPrivateMessage(LPWSTR lpwszEMail); + + INT_PTR MraChatSessionEventSendByHandle(HANDLE hContactChatSession, DWORD dwType, DWORD dwFlags, LPSTR lpszUID, size_t dwUIDSize, LPWSTR lpwszStatus, LPWSTR lpwszMessage, DWORD_PTR dwItemData, DWORD dwTime); + INT_PTR MraChatSessionInvite(HANDLE hContactChatSession, LPSTR lpszEMailInMultiChat, size_t dwEMailInMultiChatSize, DWORD dwTime); + INT_PTR MraChatSessionMembersAdd(HANDLE hContactChatSession, LPSTR lpszEMailInMultiChat, size_t dwEMailInMultiChatSize, DWORD dwTime); + INT_PTR MraChatSessionJoinUser(HANDLE hContactChatSession, LPSTR lpszEMailInMultiChat, size_t dwEMailInMultiChatSize, DWORD dwTime); + INT_PTR MraChatSessionLeftUser(HANDLE hContactChatSession, LPSTR lpszEMailInMultiChat, size_t dwEMailInMultiChatSize, DWORD dwTime); + INT_PTR MraChatSessionSetIviter(HANDLE hContactChatSession, LPSTR lpszEMailInMultiChat, size_t dwEMailInMultiChatSize); + INT_PTR MraChatSessionSetOwner(HANDLE hContactChatSession, LPSTR lpszEMailInMultiChat, size_t dwEMailInMultiChatSize); + INT_PTR MraChatSessionMessageAdd(HANDLE hContactChatSession, LPSTR lpszEMailInMultiChat, size_t dwEMailInMultiChatSize, LPWSTR lpwszMessage, size_t dwMessageSize, DWORD dwTime); + + DWORD MraAvatarsQueueInitialize(HANDLE *phAvatarsQueueHandle); + void MraAvatarsQueueClear(HANDLE hAvatarsQueueHandle); + void MraAvatarsQueueDestroy(HANDLE hAvatarsQueueHandle); + DWORD MraAvatarsQueueAdd(HANDLE hAvatarsQueueHandle, DWORD dwFlags, HANDLE hContact, DWORD *pdwAvatarsQueueID); + BOOL MraAvatarsGetContactTime (HANDLE hContact, LPSTR lpszValueName, SYSTEMTIME *pstTime); + void MraAvatarsSetContactTime (HANDLE hContact, LPSTR lpszValueName, SYSTEMTIME *pstTime); + DWORD MraAvatarsGetFileName(HANDLE hAvatarsQueueHandle, HANDLE hContact, DWORD dwFormat, LPTSTR lpszPath, size_t dwPathSize, size_t *pdwPathSizeRet); + DWORD MraAvatarsQueueGetAvatar(HANDLE hAvatarsQueueHandle, DWORD dwFlags, HANDLE hContact, DWORD *pdwAvatarsQueueID, DWORD *pdwFormat, LPTSTR lpszPath); + DWORD MraAvatarsQueueGetAvatarSimple(HANDLE hAvatarsQueueHandle, DWORD dwFlags, HANDLE hContact, DWORD dwSourceID); + DWORD MraAvatarsDeleteContactAvatarFile(HANDLE hAvatarsQueueHandle, HANDLE hContact); + + void __cdecl MraAvatarsThreadProc(LPVOID lpParameter); + +}; diff --git a/protocols/MRA/src/MraRTFMsg.cpp b/protocols/MRA/src/MraRTFMsg.cpp new file mode 100644 index 0000000000..9866e44a99 --- /dev/null +++ b/protocols/MRA/src/MraRTFMsg.cpp @@ -0,0 +1,259 @@ +#include "Mra.h" +#include "MraRTFMsg.h" + + +#define COLORTABLE_COUNT 8 +#define RTF_COLORTBLCOLOURS "\\red255\\green0\\blue0;\\red0\\green255\\blue0;\\red0\\green0\\blue255;\\red255\\green0\\blue255;\\red255\\green255\\blue0;\\red0\\green255\\blue255;\\red0\\green0\\blue0;\\red255\\green255\\blue255;" +static const LPSTR lpszColours[COLORTABLE_COUNT] = +{ + "red", + "green", + "blue", + "magenta", + "yellow", + "cyan", + "black", + "white" +}; + +#define CRLF "\r\n" +#define PAR "\\par " + + +#define BB_COLOR_TAG "[color=" +#define SYMBOLS_COUNT 19 +static const LPSTR lpszSimbols[SYMBOLS_COUNT] = +{ + "\r\n", + "\\", + "{", + "}", + "[b]", + "[/b]", + "[u]", + "[/u]", + "[i]", + "[/i]", + "[/color]", + "[color = red]", + "[color = green]", + "[color = blue]", + "[color = magenta]", + "[color = yellow]", + "[color = cyan]", + "[color = black]", + "[color = white]", +}; + +static const size_t dwcSimbolsCount[SYMBOLS_COUNT] = +{ + 2, + 1, + 1, + 1, + 3, + 4, + 3, + 4, + 3, + 4, + 8, + 11, + 13, + 12, + 15, + 14, + 12, + 13, + 13, +}; + +static const LPSTR lpszRTFTags[SYMBOLS_COUNT] = +{ + "\\par", + "\\\\", + "\\{", + "\\}", + "{\\b ", + "}", + "{\\ul ", + "}", + "{\\i ", + "}", + "}", + "{\\cf2 ", + "{\\cf3 ", + "{\\cf4 ", + "{\\cf5 ", + "{\\cf6 ", + "{\\cf7 ", + "{\\cf8 ", + "{\\cf9 ", +}; + +static const size_t dwcRTFTagsCount[SYMBOLS_COUNT] = +{ + 4, 2, 2, 2, 4, 1, 5, 1, 4, 1, 1, 6, 6, 6, 6, 6, 6, 6, 6 +}; + +DWORD MraTextToRTFData(LPSTR lpszMessage, size_t dwMessageSize, LPSTR lpszMessageConverted, size_t dwMessageConvertedBuffSize, size_t *pdwMessageConvertedSize); + +BOOL MraIsMessageFlashAnimation(LPCWSTR lpwszMessage, size_t dwMessageSize) +{ + dwMessageSize *= sizeof(WCHAR); + LPWSTR lpwszFound = (LPWSTR)MemoryFind(0, lpwszMessage, dwMessageSize, L"id = flas", 28); + if (lpwszFound) + if (MemoryFind(((lpwszFound-lpwszMessage)+32), lpwszMessage, dwMessageSize, L"'", 18)) + return TRUE; + + return FALSE; +} + +DWORD MraTextToRTFData(LPSTR lpszMessage, size_t dwMessageSize, LPSTR lpszMessageConverted, size_t dwMessageConvertedBuffSize, size_t *pdwMessageConvertedSize) +{ + if (lpszMessage && dwMessageSize && lpszMessageConverted && dwMessageConvertedBuffSize) { + BYTE tm, bCurByte; + LPSTR lpszMessageConvertedCur, lpszMessageConvertedMax; + size_t i; + + lpszMessageConvertedCur = lpszMessageConverted; + lpszMessageConvertedMax = (lpszMessageConverted+dwMessageConvertedBuffSize); + for (i = 0; i < dwMessageSize && lpszMessageConvertedMax-lpszMessageConvertedCur > 3; i++) { + *((WORD*)lpszMessageConvertedCur) = *((WORD*)"\\'"); + bCurByte = (*((BYTE*)lpszMessage+i)); + tm = (bCurByte>>4)&0xf; + lpszMessageConvertedCur[2] = (tm>9)? ('a'+tm-10):('0'+tm); + + tm = bCurByte&0xf; + lpszMessageConvertedCur[3] = (tm>9)? ('a'+tm-10):('0'+tm); + lpszMessageConvertedCur += 4; + (*((BYTE*)lpszMessageConvertedCur)) = 0; + } + if (pdwMessageConvertedSize) + *pdwMessageConvertedSize = lpszMessageConvertedCur - lpszMessageConverted; + return NO_ERROR; + } + + if (pdwMessageConvertedSize) + *pdwMessageConvertedSize = 0; + return ERROR_INVALID_HANDLE; +} + +DWORD MraSymbolsToRTFTags(DWORD dwFlags, LPSTR lpszMessage, size_t dwMessageSize, LPSTR lpszMessageConverted, size_t dwMessageConvertedBuffSize, size_t *pdwMessageConvertedSize) +{ + DWORD dwRetErrorCode = NO_ERROR; + LPSTR lpszFounded[SYMBOLS_COUNT], lpszMessageConvertedCur, lpszMessageCur, lpszMessageCurPrev, lpszMessageConvertedMax; + size_t i, dwFirstFoundIndex = 0, dwFoundCount = 0, dwMemPartToCopy; + + lpszMessageCurPrev = lpszMessage; + lpszMessageConvertedCur = lpszMessageConverted; + lpszMessageConvertedMax = (lpszMessageConverted+dwMessageConvertedBuffSize); + for (i = 0; i < SYMBOLS_COUNT; i++) { // loking for first time + lpszFounded[i] = (LPSTR)MemoryFind((lpszMessageCurPrev-lpszMessage), lpszMessage, dwMessageSize, lpszSimbols[i], dwcSimbolsCount[i]); + if (lpszFounded[i]) dwFoundCount++; + } + + while (dwFoundCount) { + for (i = 0;i (lpszMessageConvertedCur+(dwMemPartToCopy+dwcRTFTagsCount[dwFirstFoundIndex]))) { + MraTextToRTFData(lpszMessageCurPrev, dwMemPartToCopy, lpszMessageConvertedCur, (lpszMessageConvertedMax-lpszMessageConvertedCur), &i);lpszMessageConvertedCur += i; + memmove(lpszMessageConvertedCur, lpszRTFTags[dwFirstFoundIndex], dwcRTFTagsCount[dwFirstFoundIndex]);lpszMessageConvertedCur += dwcRTFTagsCount[dwFirstFoundIndex]; + lpszMessageCurPrev = (lpszFounded[dwFirstFoundIndex]+dwcSimbolsCount[dwFirstFoundIndex]); + + for (i = 0;i dwMessageRTFBuffSize) { + if (pdwMessageRTFSize) + *pdwMessageRTFSize = dwMessageSize; + return ERROR_BUFFER_OVERFLOW; + } + + mir_ptr lpszMessage((LPSTR)mir_calloc(dwMessageSize+32)); + if (!lpszMessage) + return GetLastError(); + + LPSTR lpszMessageRTFCur = lpszMessageRTF; + size_t dwtm; + DWORD dwRTFFontColour, dwFontSize; + LOGFONT lf = {0}; + + WideCharToMultiByte(MRA_CODE_PAGE, 0, lpwszMessage, dwMessageSize, lpszMessage, (dwMessageSize+32), NULL, NULL); + + dwRTFFontColour = mraGetDword(NULL, "RTFFontColour", MRA_DEFAULT_RTF_FONT_COLOUR); + if ( !mraGetContactSettingBlob(NULL, "RTFFont", &lf, sizeof(LOGFONT), NULL)) { + HDC hDC = GetDC(NULL);// kegl + lf.lfCharSet = MRA_DEFAULT_RTF_FONT_CHARSET; + lf.lfHeight = -MulDiv(MRA_DEFAULT_RTF_FONT_SIZE, GetDeviceCaps(hDC, LOGPIXELSY), 72); + lstrcpynW(lf.lfFaceName, MRA_DEFAULT_RTF_FONT_NAME, LF_FACESIZE); + ReleaseDC(NULL, hDC); + } + dwFontSize = ((-lf.lfHeight)+(((-lf.lfHeight)+4)/8)); + + lpszMessageRTFCur += mir_snprintf(lpszMessageRTFCur, (dwMessageRTFBuffSize-((size_t)lpszMessageRTFCur-(size_t)lpszMessageRTF)), "{\\rtf1\\ansi\\ansicpg1251\\deff0\\deflang1049{\\fonttbl{\\f0\\fnil\\fcharset%lu %s;}}\r\n", lf.lfCharSet, lf.lfFaceName); + + if (MemoryFind(0, lpszMessage, dwMessageSize, BB_COLOR_TAG, (sizeof(BB_COLOR_TAG)-1))) + lpszMessageRTFCur += mir_snprintf(lpszMessageRTFCur, (dwMessageRTFBuffSize-((size_t)lpszMessageRTFCur-(size_t)lpszMessageRTF)), "{\\colortbl;\\red%lu\\green%lu\\blue%lu;%s}\r\n", (*((RGBTRIPLE*)&dwRTFFontColour)).rgbtBlue, (*((RGBTRIPLE*)&dwRTFFontColour)).rgbtGreen, (*((RGBTRIPLE*)&dwRTFFontColour)).rgbtRed, RTF_COLORTBLCOLOURS); + else + lpszMessageRTFCur += mir_snprintf(lpszMessageRTFCur, (dwMessageRTFBuffSize-((size_t)lpszMessageRTFCur-(size_t)lpszMessageRTF)), "{\\colortbl;\\red%lu\\green%lu\\blue%lu;}\r\n", (*((RGBTRIPLE*)&dwRTFFontColour)).rgbtBlue, (*((RGBTRIPLE*)&dwRTFFontColour)).rgbtGreen, (*((RGBTRIPLE*)&dwRTFFontColour)).rgbtRed); + + LPSTR lpszNotfink = "", + lpszBold = ((lf.lfWeight == FW_BOLD)? "\\b1":lpszNotfink), + lpszItalic = (lf.lfItalic? "\\i1":lpszNotfink), + lpszUnderline = (lf.lfUnderline? "\\ul1":lpszNotfink), + lpszStrikeOut = (lf.lfStrikeOut? "\\strike1":lpszNotfink); + lpszMessageRTFCur += mir_snprintf(lpszMessageRTFCur, (dwMessageRTFBuffSize-((size_t)lpszMessageRTFCur-(size_t)lpszMessageRTF)), "\\viewkind4\\uc1\\pard\\cf1\\f0\\fs%lu%s%s%s%s", dwFontSize, lpszBold, lpszItalic, lpszUnderline, lpszStrikeOut); + + if ( !MraSymbolsToRTFTags(0, lpszMessage, dwMessageSize, lpszMessageRTFCur, (dwMessageRTFBuffSize-(lpszMessageRTFCur-lpszMessageRTF)), &dwtm)) { + lpszMessageRTFCur += dwtm; + if ((lpszMessageRTF+dwMessageRTFBuffSize) >= (lpszMessageRTFCur+sizeof(PAR)+sizeof(CRLF)+2)) { + memmove(lpszMessageRTFCur, PAR, sizeof(PAR));lpszMessageRTFCur += (sizeof(PAR)-1); + memmove(lpszMessageRTFCur, CRLF, sizeof(CRLF));lpszMessageRTFCur += (sizeof(CRLF)-1); + memmove(lpszMessageRTFCur, "}", 2);lpszMessageRTFCur += 2; + if (pdwMessageRTFSize) (*pdwMessageRTFSize) = (lpszMessageRTFCur-lpszMessageRTF); + DebugPrintCRLFA(lpszMessageRTF); + return NO_ERROR; + } + + if (pdwMessageRTFSize) *pdwMessageRTFSize = dwMessageRTFBuffSize+1024; + return ERROR_BUFFER_OVERFLOW; + } + + return 0; +} + + + diff --git a/protocols/MRA/src/MraRTFMsg.h b/protocols/MRA/src/MraRTFMsg.h new file mode 100644 index 0000000000..1dadb5a801 --- /dev/null +++ b/protocols/MRA/src/MraRTFMsg.h @@ -0,0 +1,11 @@ +#if !defined(AFX_MRA_RTFMSG_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_) +#define AFX_MRA_RTFMSG_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_ + + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +BOOL MraIsMessageFlashAnimation (LPCWSTR lpwszMessage, size_t dwMessageSize); + +#endif // !defined(AFX_MRA_RTFMSG_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_) diff --git a/protocols/MRA/src/MraSelectEMail.cpp b/protocols/MRA/src/MraSelectEMail.cpp new file mode 100644 index 0000000000..a3c9bfd313 --- /dev/null +++ b/protocols/MRA/src/MraSelectEMail.cpp @@ -0,0 +1,158 @@ +#include "Mra.h" +#include "MraSelectEMail.h" +#include "BuffToLowerCase.h" + +struct MraSelectEMailDlgData +{ + CMraProto *ppro; + HANDLE hContact; + DWORD dwType; +}; + +void AddContactEMailToListParam(HANDLE hContact, BOOL bMRAOnly, LPSTR lpszModule, LPSTR lpszValueName, HWND hWndList) +{ + CHAR szBuff[MAX_PATH], szEMail[MAX_EMAIL_LEN]; + WCHAR wszBuff[MAX_PATH]; + size_t i, dwEMailSize; + + if (DB_GetStaticStringA(hContact, lpszModule, lpszValueName, szEMail, SIZEOF(szEMail), &dwEMailSize)) { + if (bMRAOnly == FALSE || IsEMailMR(szEMail, dwEMailSize)) { + MultiByteToWideChar(MRA_CODE_PAGE, 0, szEMail, (dwEMailSize+1), wszBuff, SIZEOF(wszBuff)); + if (SendMessage(hWndList, LB_FINDSTRING, -1, (LPARAM)wszBuff) == LB_ERR) SendMessage(hWndList, LB_ADDSTRING, 0, (LPARAM)wszBuff); + } + } + + for (i = 0;TRUE;i++) { + mir_snprintf(szBuff, SIZEOF(szBuff), "%s%lu", lpszValueName, i); + if (DB_GetStaticStringA(hContact, lpszModule, szBuff, szEMail, SIZEOF(szEMail), &dwEMailSize)) { + if (bMRAOnly == FALSE || IsEMailMR(szEMail, dwEMailSize)) { + MultiByteToWideChar(MRA_CODE_PAGE, 0, szEMail, (dwEMailSize+1), wszBuff, SIZEOF(wszBuff)); + if (SendMessage(hWndList, LB_FINDSTRING, -1, (LPARAM)wszBuff) == LB_ERR) SendMessage(hWndList, LB_ADDSTRING, 0, (LPARAM)wszBuff); + } + } + else if (i > EMAILS_MIN_COUNT) + break; + } +} + +INT_PTR CALLBACK MraSelectEMailDlgProc(HWND hWndDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + MraSelectEMailDlgData *dat = (MraSelectEMailDlgData*)GetWindowLongPtr(hWndDlg, GWLP_USERDATA); + + switch (message) { + case WM_INITDIALOG: + TranslateDialogDefault(hWndDlg); + dat = (MraSelectEMailDlgData*)lParam; + { + HWND hWndList; + BOOL bMRAOnly; + LPSTR lpszProto; + + SetWindowLongPtr(hWndDlg, GWLP_USERDATA, (LONG_PTR)lParam); + hWndList = GetDlgItem(hWndDlg, IDC_LIST_EMAILS); + + switch (dat->dwType) { + case MRA_SELECT_EMAIL_TYPE_SEND_POSTCARD: + bMRAOnly = FALSE; + break; + case MRA_SELECT_EMAIL_TYPE_VIEW_ALBUM: + case MRA_SELECT_EMAIL_TYPE_READ_BLOG: + bMRAOnly = TRUE; + break; + default: + bMRAOnly = FALSE; + break; + } + + if (dat->hContact) + lpszProto = (LPSTR)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)dat->hContact, 0); + else + lpszProto = dat->ppro->m_szModuleName; + + AddContactEMailToListParam(dat->hContact, bMRAOnly, lpszProto, "e-mail", hWndList); + AddContactEMailToListParam(dat->hContact, bMRAOnly, "UserInfo", "e-mail", hWndList); + AddContactEMailToListParam(dat->hContact, bMRAOnly, "UserInfo", "Mye-mail", hWndList); + AddContactEMailToListParam(dat->hContact, bMRAOnly, "UserInfo", "Companye-mail", hWndList); + AddContactEMailToListParam(dat->hContact, bMRAOnly, "UserInfo", "MyCompanye-mail", hWndList); + } + return TRUE; + + case WM_CLOSE: + DestroyWindow(hWndDlg); + break; + + case WM_DESTROY: + SetWindowLongPtr(hWndDlg, GWLP_USERDATA, (LONG_PTR)0); + mir_free(dat); + EndDialog(hWndDlg, NO_ERROR); + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_LIST_EMAILS: + if (HIWORD(wParam) == LBN_DBLCLK) + SendMessage(hWndDlg, WM_COMMAND, MAKEWPARAM(IDOK, BN_CLICKED), (LPARAM)GetDlgItem(hWndDlg, IDOK)); + break; + + case IDOK: + { + CHAR szEMail[MAX_EMAIL_LEN]; + WCHAR wszBuff[MAX_PATH]; + size_t dwEMailSize; + + dwEMailSize = SendMessage(GetDlgItem(hWndDlg, IDC_LIST_EMAILS), LB_GETTEXT, SendMessage(GetDlgItem(hWndDlg, IDC_LIST_EMAILS), LB_GETCURSEL, 0, 0), (LPARAM)wszBuff); + WideCharToMultiByte(MRA_CODE_PAGE, 0, wszBuff, (dwEMailSize+1), szEMail, SIZEOF(szEMail), NULL, NULL); + BuffToLowerCase(szEMail, szEMail, dwEMailSize); + + switch (dat->dwType) { + case MRA_SELECT_EMAIL_TYPE_SEND_POSTCARD: + { + size_t dwUrlSize; + CHAR szUrl[BUFF_SIZE_URL]; + dwUrlSize = mir_snprintf(szUrl, SIZEOF(szUrl), "http://cards.mail.ru/event.html?rcptname = %s&rcptemail = %s", GetContactNameA(dat->hContact), szEMail); + dat->ppro->MraMPopSessionQueueAddUrl(dat->ppro->hMPopSessionQueue, szUrl, dwUrlSize); + } + break; + case MRA_SELECT_EMAIL_TYPE_VIEW_ALBUM: + dat->ppro->MraMPopSessionQueueAddUrlAndEMail(dat->ppro->hMPopSessionQueue, MRA_FOTO_URL, sizeof(MRA_FOTO_URL), szEMail, dwEMailSize); + break; + case MRA_SELECT_EMAIL_TYPE_READ_BLOG: + dat->ppro->MraMPopSessionQueueAddUrlAndEMail(dat->ppro->hMPopSessionQueue, MRA_BLOGS_URL, sizeof(MRA_BLOGS_URL), szEMail, dwEMailSize); + break; + case MRA_SELECT_EMAIL_TYPE_VIEW_VIDEO: + dat->ppro->MraMPopSessionQueueAddUrlAndEMail(dat->ppro->hMPopSessionQueue, MRA_VIDEO_URL, sizeof(MRA_VIDEO_URL), szEMail, dwEMailSize); + break; + case MRA_SELECT_EMAIL_TYPE_ANSWERS: + dat->ppro->MraMPopSessionQueueAddUrlAndEMail(dat->ppro->hMPopSessionQueue, MRA_ANSWERS_URL, sizeof(MRA_ANSWERS_URL), szEMail, dwEMailSize); + break; + case MRA_SELECT_EMAIL_TYPE_WORLD: + dat->ppro->MraMPopSessionQueueAddUrlAndEMail(dat->ppro->hMPopSessionQueue, MRA_WORLD_URL, sizeof(MRA_WORLD_URL), szEMail, dwEMailSize); + break; + } + } + //break; + case IDCANCEL: + DestroyWindow(hWndDlg); + break; + default: + break; + } + break; + default: + break; + } + + return FALSE; +} + +DWORD CMraProto::MraSelectEMailDlgShow(HANDLE hContact, DWORD dwType) +{ + MraSelectEMailDlgData *dat = (MraSelectEMailDlgData*)mir_calloc(sizeof(MraSelectEMailDlgData)); + if (dat) { + dat->ppro = this; + dat->hContact = hContact; + dat->dwType = dwType; + DialogBoxParam(masMraSettings.hInstance, MAKEINTRESOURCE(IDD_DIALOG_SELECT_EMAIL), NULL, MraSelectEMailDlgProc, (LPARAM)dat); + } + return 0; +} diff --git a/protocols/MRA/src/MraSelectEMail.h b/protocols/MRA/src/MraSelectEMail.h new file mode 100644 index 0000000000..c031ee72ab --- /dev/null +++ b/protocols/MRA/src/MraSelectEMail.h @@ -0,0 +1,19 @@ +#if !defined(AFX_MRA_SELECT_EMAIL_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_) +#define AFX_MRA_SELECT_EMAIL_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_ + + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + + +#define MRA_SELECT_EMAIL_TYPE_SEND_POSTCARD 1 +#define MRA_SELECT_EMAIL_TYPE_VIEW_ALBUM 2 +#define MRA_SELECT_EMAIL_TYPE_READ_BLOG 3 +#define MRA_SELECT_EMAIL_TYPE_VIEW_VIDEO 4 +#define MRA_SELECT_EMAIL_TYPE_ANSWERS 5 +#define MRA_SELECT_EMAIL_TYPE_WORLD 6 + + +#endif // !defined(AFX_MRA_SELECT_EMAIL_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_) diff --git a/protocols/MRA/src/MraSendCommand.cpp b/protocols/MRA/src/MraSendCommand.cpp new file mode 100644 index 0000000000..158427cbe4 --- /dev/null +++ b/protocols/MRA/src/MraSendCommand.cpp @@ -0,0 +1,688 @@ +#include "Mra.h" +#include "MraSendCommand.h" +#include "MraRTFMsg.h" +#include "proto.h" + +static void SetUL(LPBYTE *plpBuff, DWORD dwData) +{ + (*(DWORD*)(*plpBuff)) = dwData; + (*plpBuff) += sizeof(DWORD); +} + +static void SetUIDL(LPBYTE *plpBuff, DWORDLONG dwData) +{ + (*(DWORDLONG*)(*plpBuff)) = dwData; + (*plpBuff) += sizeof(DWORDLONG); +} + +static void SetGUID(LPBYTE *plpBuff, MRA_GUID guidData) +{ + (*(MRA_GUID*)(*plpBuff)) = guidData; + (*plpBuff) += sizeof(MRA_GUID); +} + +static void SetLPS(LPBYTE *plpBuff, LPCSTR lpszData, DWORD dwSize) +{ + (*(DWORD*)(*plpBuff)) = dwSize; + (*plpBuff) += sizeof(DWORD); + memmove((*plpBuff), lpszData, dwSize); + (*plpBuff) += dwSize; +} + +static void SetLPSW(LPBYTE *plpBuff, LPCWSTR lpwszData, DWORD dwSize) +{ + dwSize *= sizeof(WCHAR); + (*(DWORD*)(*plpBuff)) = dwSize; + (*plpBuff) += sizeof(DWORD); + memmove((*plpBuff), lpwszData, dwSize); + (*plpBuff) += dwSize; +} + +static void SetLPSWtoA(LPBYTE *plpBuff, LPCWSTR lpwszData, DWORD dwSize) +{ + dwSize = WideCharToMultiByte(MRA_CODE_PAGE, 0, lpwszData, dwSize, (LPSTR)((*plpBuff)+sizeof(DWORD)), (dwSize*sizeof(WCHAR)), NULL, NULL); + (*(DWORD*)(*plpBuff)) = dwSize; + (*plpBuff) += (sizeof(DWORD)+dwSize); +} + +static void SetLPSLowerCase(LPBYTE *plpBuff, LPCSTR lpszData, DWORD dwSize) +{ + (*(DWORD*)(*plpBuff)) = dwSize; + (*plpBuff) += sizeof(DWORD); + BuffToLowerCase((*plpBuff), lpszData, dwSize); + (*plpBuff) += dwSize; +} + +static void SetLPSLowerCaseW(LPBYTE *plpBuff, LPCWSTR lpwszData, DWORD dwSize) +{ + dwSize *= sizeof(WCHAR); + (*(DWORD*)(*plpBuff)) = dwSize; + (*plpBuff) += sizeof(DWORD); + memmove((*plpBuff), lpwszData, dwSize); + CharLowerBuff((LPWSTR)(*plpBuff), (dwSize/sizeof(WCHAR))); + (*plpBuff) += dwSize; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +DWORD CMraProto::MraMessageW(BOOL bAddToQueue, HANDLE hContact, DWORD dwAckType, DWORD dwFlags, LPSTR lpszEMail, size_t dwEMailSize, LPCWSTR lpwszMessage, size_t dwMessageSize, LPBYTE lpbMultiChatData, size_t dwMultiChatDataSize) +{ + Netlib_Logf(hNetlibUser, "Sending message: flags %08x, to '%S', message '%S'\n", dwFlags, lpszEMail, lpwszMessage); + + DWORD dwRet = 0; + LPBYTE lpbData, lpbDataCurrent; + LPSTR lpszMessageConverted = (LPSTR)lpwszMessage; + LPSTR lpszMessageRTF = NULL; + size_t dwMessageConvertedSize = (dwMessageSize*sizeof(WCHAR)), dwMessageRTFSize = 0; + + if ( MraIsMessageFlashAnimation(lpwszMessage, dwMessageSize)) + dwFlags |= MESSAGE_FLAG_FLASH; + + // pack auth message + if (dwFlags & MESSAGE_FLAG_AUTHORIZE) { + LPBYTE lpbAuthMsgBuff; + size_t dwMessageConvertedBuffSize = (((((dwMessageSize*sizeof(WCHAR))+1024)+2)/3)*4); + + lpszMessageConverted = (LPSTR)mir_calloc(dwMessageConvertedBuffSize); + lpbAuthMsgBuff = (LPBYTE)mir_calloc(((dwMessageSize*sizeof(WCHAR))+1024)); + if (lpszMessageConverted && lpbAuthMsgBuff) { + lpbDataCurrent = lpbAuthMsgBuff; + SetUL(&lpbDataCurrent, 2); + SetLPSW(&lpbDataCurrent, NULL, 0);//***deb possible nick here + SetLPSW(&lpbDataCurrent, lpwszMessage, dwMessageSize); + + BASE64EncodeUnSafe(lpbAuthMsgBuff, (lpbDataCurrent-lpbAuthMsgBuff), lpszMessageConverted, dwMessageConvertedBuffSize, &dwMessageConvertedSize); + } + else { + mir_free(lpszMessageConverted); + lpszMessageConverted = (LPSTR)lpwszMessage; + } + mir_free(lpbAuthMsgBuff); + } + // messages with Flash + else if (dwFlags & MESSAGE_FLAG_FLASH) { + size_t dwRFTBuffSize = (((dwMessageSize*sizeof(WCHAR))*4)+8192), dwRTFDataSize; + + dwFlags |= MESSAGE_FLAG_RTF; + lpszMessageRTF = (LPSTR)mir_calloc(dwRFTBuffSize); + mir_ptr lpbRTFData((char*)mir_calloc(dwRFTBuffSize)); + if (lpszMessageRTF && lpbRTFData) { + DWORD dwBackColour = mraGetDword(NULL, "RTFBackgroundColour", MRA_DEFAULT_RTF_BACKGROUND_COLOUR); + lpbDataCurrent = (LPBYTE)lpszMessageRTF; + + WideCharToMultiByte(MRA_CODE_PAGE, 0, lpwszMessage, dwMessageSize, (LPSTR)lpbRTFData, dwRFTBuffSize, NULL, NULL); + + SetUL(&lpbDataCurrent, 4); + SetLPS(&lpbDataCurrent, (LPSTR)lpbRTFData, dwMessageSize);// сообщение что у собеседника плохая версия :) + SetLPS(&lpbDataCurrent, (LPSTR)&dwBackColour, sizeof(DWORD));// цвет фона + SetLPS(&lpbDataCurrent, (LPSTR)lpbRTFData, dwMessageSize);// сам мульт ANSI + SetLPSW(&lpbDataCurrent, lpwszMessage, dwMessageSize);// сам мульт UNICODE + + dwRTFDataSize = dwRFTBuffSize; + if ( compress2((LPBYTE)(LPSTR)lpbRTFData, (DWORD*)&dwRTFDataSize, (LPBYTE)lpszMessageRTF, (lpbDataCurrent-(LPBYTE)lpszMessageRTF), Z_BEST_COMPRESSION) == Z_OK) + BASE64EncodeUnSafe(lpbRTFData, dwRTFDataSize, lpszMessageRTF, dwRFTBuffSize, &dwMessageRTFSize); + } + } + // standart message + else if ((dwFlags & (MESSAGE_FLAG_CONTACT | MESSAGE_FLAG_NOTIFY | MESSAGE_FLAG_SMS)) == 0) { + // Only if message is simple text message or RTF or ALARM + if (dwFlags & MESSAGE_FLAG_RTF) { // add RFT part + size_t dwRFTBuffSize = (((dwMessageSize*sizeof(WCHAR))*16)+8192), dwRTFDataSize; + + lpszMessageRTF = (LPSTR)mir_calloc(dwRFTBuffSize); + mir_ptr lpbRTFData((char*)mir_calloc(dwRFTBuffSize)); + if (lpszMessageRTF && lpbRTFData) { + if ( !MraConvertToRTFW(lpwszMessage, dwMessageSize, (LPSTR)lpbRTFData, dwRFTBuffSize, &dwRTFDataSize)) { + DWORD dwBackColour = mraGetDword(NULL, "RTFBackgroundColour", MRA_DEFAULT_RTF_BACKGROUND_COLOUR); + lpbDataCurrent = (LPBYTE)lpszMessageRTF; + + SetUL(&lpbDataCurrent, 2); + SetLPS(&lpbDataCurrent, (LPSTR)lpbRTFData, dwRTFDataSize); + SetLPS(&lpbDataCurrent, (LPSTR)&dwBackColour, sizeof(DWORD)); + + dwRTFDataSize = dwRFTBuffSize; + if ( compress2((LPBYTE)(LPSTR)lpbRTFData, (DWORD*)&dwRTFDataSize, (LPBYTE)lpszMessageRTF, (lpbDataCurrent-(LPBYTE)lpszMessageRTF), Z_BEST_COMPRESSION) == Z_OK) + BASE64EncodeUnSafe(lpbRTFData, dwRTFDataSize, lpszMessageRTF, dwRFTBuffSize, &dwMessageRTFSize); + } + } + } + } + + if (lpszMessageRTF == NULL || dwMessageRTFSize == 0) dwFlags &= ~(MESSAGE_FLAG_RTF|MESSAGE_FLAG_FLASH); + if (lpbMultiChatData == NULL || dwMultiChatDataSize == 0) dwFlags &= ~MESSAGE_FLAG_MULTICHAT; + + lpbData = (LPBYTE)mir_calloc((sizeof(DWORD)+dwEMailSize+dwMessageConvertedSize+dwMessageRTFSize+dwMultiChatDataSize+128)); + if (lpbData) { + lpbDataCurrent = lpbData; + SetUL(&lpbDataCurrent, dwFlags); + SetLPSLowerCase(&lpbDataCurrent, lpszEMail, dwEMailSize); + SetLPS(&lpbDataCurrent, lpszMessageConverted, dwMessageConvertedSize); + SetLPS(&lpbDataCurrent, lpszMessageRTF, dwMessageRTFSize); + if (dwFlags&MESSAGE_FLAG_MULTICHAT) SetLPS(&lpbDataCurrent, (LPSTR)lpbMultiChatData, dwMultiChatDataSize); + + if (bAddToQueue) + dwRet = MraSendQueueCMD(hSendQueueHandle, 0, hContact, dwAckType, (LPBYTE)lpwszMessage, (dwMessageSize*sizeof(WCHAR)), MRIM_CS_MESSAGE, lpbData, (lpbDataCurrent-lpbData)); + else + dwRet = MraSendCMD(MRIM_CS_MESSAGE, lpbData, (lpbDataCurrent-lpbData)); + mir_free(lpbData); + } + + if (lpszMessageConverted != (LPSTR)lpwszMessage) + mir_free(lpszMessageConverted); + mir_free(lpszMessageRTF); + + return dwRet; +} + +// Send confirmation +DWORD CMraProto::MraMessageAskW(DWORD dwMsgID, DWORD dwFlags, LPSTR lpszEMail, size_t dwEMailSize, LPWSTR lpwszMessage, size_t dwMessageSize, LPSTR lpwszMessageRTF, size_t dwMessageRTFSize) +{ + DWORD dwRet = 0; + + if (lpszEMail && dwEMailSize>4 && lpwszMessage && dwMessageSize) { + LPBYTE lpbData, lpbDataCurrent; + lpbData = (LPBYTE)mir_calloc((sizeof(DWORD)+sizeof(DWORD)+dwEMailSize+dwMessageSize+dwMessageRTFSize+32)); + if (lpbData) { + lpbDataCurrent = lpbData; + SetUL(&lpbDataCurrent, dwMsgID);//UL msg_id + SetUL(&lpbDataCurrent, dwFlags);//UL flags + SetLPSLowerCase(&lpbDataCurrent, lpszEMail, dwEMailSize);// LPS from e-mail ANSI + SetLPS(&lpbDataCurrent, (LPSTR)lpwszMessage, dwMessageSize);// LPS message UNICODE + if (dwFlags&MESSAGE_FLAG_RTF) + SetLPS(&lpbDataCurrent, (LPSTR)lpwszMessageRTF, dwMessageRTFSize);// LPS //rtf-formatted message ( >= 1.1) - MESSAGE_FLAG_RTF + + dwRet = MraSendCMD(MRIM_CS_MESSAGE_ACK, lpbData, (lpbDataCurrent-lpbData)); + mir_free(lpbData); + } + } + + return dwRet; +} + +DWORD CMraProto::MraMessageRecv(LPSTR lpszFrom, size_t dwFromSize, DWORD dwMsgID) +{ + DWORD dwRet = 0; + + if (lpszFrom && dwFromSize>4) { + LPBYTE lpbData, lpbDataCurrent; + lpbData = (LPBYTE)mir_calloc((dwFromSize+sizeof(DWORD)+32)); + if (lpbData) { + lpbDataCurrent = lpbData; + SetLPSLowerCase(&lpbDataCurrent, lpszFrom, dwFromSize); + SetUL(&lpbDataCurrent, dwMsgID); + + dwRet = MraSendCMD(MRIM_CS_MESSAGE_RECV, lpbData, (lpbDataCurrent-lpbData)); + mir_free(lpbData); + } + } + return dwRet; +} + +// Adds new contact +DWORD CMraProto::MraAddContactW(HANDLE hContact, DWORD dwContactFlag, DWORD dwGroupID, LPSTR lpszEMail, size_t dwEMailSize, LPWSTR lpwszCustomName, size_t dwCustomNameSize, LPSTR lpszPhones, size_t dwPhonesSize, LPWSTR lpwszAuthMessage, size_t dwAuthMessageSize, DWORD dwActions) +{ + DWORD dwRet = 0; + + if (lpszEMail && dwEMailSize>4) { + LPBYTE lpbData = (LPBYTE)mir_calloc((sizeof(DWORD)+sizeof(DWORD)+dwEMailSize+(dwCustomNameSize*sizeof(WCHAR))+dwPhonesSize+(((((dwAuthMessageSize*sizeof(WCHAR))+1024)+2)/3)*4)+32)+sizeof(DWORD)); + if (lpbData) { + dwContactFlag |= CONTACT_FLAG_UNICODE_NAME; + + LPBYTE lpbDataCurrent = lpbData; + SetUL(&lpbDataCurrent, dwContactFlag); + SetUL(&lpbDataCurrent, dwGroupID); + SetLPSLowerCase(&lpbDataCurrent, lpszEMail, dwEMailSize); + SetLPSW(&lpbDataCurrent, lpwszCustomName, dwCustomNameSize); + SetLPS(&lpbDataCurrent, lpszPhones, dwPhonesSize); + + // pack auth message + LPBYTE lpbAuthMsgBuff, lpbAuthMessageConverted, lpbAuthDataCurrent; + size_t dwAuthMessageConvertedBuffSize = (((((dwAuthMessageSize*sizeof(WCHAR))+1024)+2)/3)*4), dwAuthMessageConvertedSize = 0; + + lpbAuthMessageConverted = (LPBYTE)mir_calloc(dwAuthMessageConvertedBuffSize); + lpbAuthMsgBuff = (LPBYTE)mir_calloc(((dwAuthMessageSize*sizeof(WCHAR))+1024)); + if (lpbAuthMessageConverted && lpbAuthMsgBuff) { + lpbAuthDataCurrent = lpbAuthMsgBuff; + SetUL(&lpbAuthDataCurrent, 2); + SetLPSW(&lpbAuthDataCurrent, NULL, 0);//***deb possible nick here + SetLPSW(&lpbAuthDataCurrent, lpwszAuthMessage, dwAuthMessageSize); + + BASE64EncodeUnSafe(lpbAuthMsgBuff, (lpbAuthDataCurrent-lpbAuthMsgBuff), lpbAuthMessageConverted, dwAuthMessageConvertedBuffSize, &dwAuthMessageConvertedSize); + } + SetLPS(&lpbDataCurrent, (LPSTR)lpbAuthMessageConverted, dwAuthMessageConvertedSize); + mir_free(lpbAuthMsgBuff); + mir_free(lpbAuthMessageConverted); + + SetUL(&lpbDataCurrent, dwActions); + + dwRet = MraSendQueueCMD(hSendQueueHandle, 0, hContact, ACKTYPE_ADDED, NULL, 0, MRIM_CS_ADD_CONTACT, lpbData, (lpbDataCurrent-lpbData)); + mir_free(lpbData); + } + } + return dwRet; +} + +// change contact +DWORD CMraProto::MraModifyContactW(HANDLE hContact, DWORD dwID, DWORD dwContactFlag, DWORD dwGroupID, LPSTR lpszEMail, size_t dwEMailSize, LPWSTR lpwszCustomName, size_t dwCustomNameSize, LPSTR lpszPhones, size_t dwPhonesSize) +{ + DWORD dwRet = 0; + if (dwID != -1) { + LPBYTE lpbData = (LPBYTE)mir_calloc((sizeof(DWORD)+sizeof(DWORD)+sizeof(DWORD)+dwEMailSize+(dwCustomNameSize*sizeof(WCHAR))+dwPhonesSize+32)); + if (lpbData) + { + dwContactFlag |= CONTACT_FLAG_UNICODE_NAME; + + LPBYTE lpbDataCurrent = lpbData; + SetUL(&lpbDataCurrent, dwID); + SetUL(&lpbDataCurrent, dwContactFlag); + SetUL(&lpbDataCurrent, dwGroupID); + SetLPSLowerCase(&lpbDataCurrent, lpszEMail, dwEMailSize); + SetLPSW(&lpbDataCurrent, lpwszCustomName, dwCustomNameSize); + SetLPS(&lpbDataCurrent, lpszPhones, dwPhonesSize); + + dwRet = MraSendQueueCMD(hSendQueueHandle, 0, hContact, ACKTYPE_ADDED, NULL, 0, MRIM_CS_MODIFY_CONTACT, lpbData, (lpbDataCurrent-lpbData)); + mir_free(lpbData); + } + } + return dwRet; +} + +// remove stored message +DWORD CMraProto::MraOfflineMessageDel(DWORDLONG dwMsgUIDL) +{ + return MraSendCMD(MRIM_CS_DELETE_OFFLINE_MESSAGE, &dwMsgUIDL, sizeof(DWORDLONG)); +} + +// autorize a user & add him to a roster +DWORD CMraProto::MraAuthorize(LPSTR lpszEMail, size_t dwEMailSize) +{ + DWORD dwRet = 0; + + if (lpszEMail && dwEMailSize>4) { + LPBYTE lpbData; + lpbData = (LPBYTE)mir_calloc((dwEMailSize+32)); + if (lpbData) { + LPBYTE lpbDataCurrent = lpbData; + SetLPSLowerCase(&lpbDataCurrent, lpszEMail, dwEMailSize); + dwRet = MraSendCMD(MRIM_CS_AUTHORIZE, lpbData, (lpbDataCurrent-lpbData)); + mir_free(lpbData); + } + } + return dwRet; +} + +// change status +DWORD CMraProto::MraChangeStatusW(DWORD dwStatus, LPSTR lpszStatusUri, size_t dwStatusUriSize, LPCWSTR lpwszStatusTitle, size_t dwStatusTitleSize, LPCWSTR lpwszStatusDesc, size_t dwStatusDescSize, DWORD dwFutureFlags) +{ + DWORD dwRet = 0; + + if (dwStatusUriSize > SPEC_STATUS_URI_MAX) dwStatusUriSize = SPEC_STATUS_URI_MAX; + if (dwStatusTitleSize > STATUS_TITLE_MAX) dwStatusTitleSize = STATUS_TITLE_MAX; + if (dwStatusDescSize > STATUS_DESC_MAX) dwStatusDescSize = STATUS_DESC_MAX; + + LPBYTE lpbData = (LPBYTE)mir_calloc((sizeof(DWORD)+dwStatusUriSize+(dwStatusTitleSize*sizeof(WCHAR))+(dwStatusDescSize*sizeof(WCHAR))+sizeof(DWORD)+32)); + if (lpbData) { + LPBYTE lpbDataCurrent = lpbData; + SetUL(&lpbDataCurrent, dwStatus); + SetLPS(&lpbDataCurrent, lpszStatusUri, dwStatusUriSize); + SetLPSW(&lpbDataCurrent, lpwszStatusTitle, dwStatusTitleSize); + SetLPSW(&lpbDataCurrent, lpwszStatusDesc, dwStatusDescSize); + SetUL(&lpbDataCurrent, dwFutureFlags); + + dwRet = MraSendCMD(MRIM_CS_CHANGE_STATUS, lpbData, (lpbDataCurrent-lpbData)); + mir_free(lpbData); + } + return dwRet; +} + +// Отправка файлов +DWORD CMraProto::MraFileTransfer(LPSTR lpszEMail, size_t dwEMailSize, DWORD dwIDRequest, DWORD dwFilesTotalSize, LPWSTR lpwszFiles, size_t dwFilesSize, LPSTR lpszAddreses, size_t dwAddressesSize) +{ + DWORD dwRet = 0; + + if (lpszEMail && dwEMailSize>4) { + int dwFilesSizeA = WideCharToMultiByte(MRA_CODE_PAGE, 0, lpwszFiles, dwFilesSize, NULL, 0, NULL, NULL); + LPBYTE lpbData = (LPBYTE)mir_calloc((dwEMailSize+dwFilesSizeA+(dwFilesSize*sizeof(WCHAR))+dwAddressesSize+MAX_PATH)); + if (lpbData) { + LPBYTE lpbDataCurrent = lpbData; + SetLPSLowerCase(&lpbDataCurrent, lpszEMail, dwEMailSize); + SetUL(&lpbDataCurrent, dwIDRequest); + SetUL(&lpbDataCurrent, dwFilesTotalSize); + SetUL(&lpbDataCurrent, sizeof(DWORD)*5 + dwFilesSizeA + dwFilesSize*sizeof(WCHAR) + DWORD(dwAddressesSize)); + + SetLPSWtoA(&lpbDataCurrent, lpwszFiles, dwFilesSize); + SetUL(&lpbDataCurrent, sizeof(DWORD)*2 + dwFilesSize*sizeof(WCHAR)); + + SetUL(&lpbDataCurrent, 1); + SetLPSW(&lpbDataCurrent, lpwszFiles, dwFilesSize); + + SetLPS(&lpbDataCurrent, lpszAddreses, dwAddressesSize); + + dwRet = MraSendCMD(MRIM_CS_FILE_TRANSFER, lpbData, lpbDataCurrent-lpbData); + mir_free(lpbData); + } + } + return dwRet; +} + +// Ответ на отправку файлов +DWORD CMraProto::MraFileTransferAck(DWORD dwStatus, LPSTR lpszEMail, size_t dwEMailSize, DWORD dwIDRequest, LPBYTE lpbDescription, size_t dwDescriptionSize) +{ + DWORD dwRet = 0; + + if (lpszEMail && dwEMailSize>4) { + LPBYTE lpbData = (LPBYTE)mir_calloc((dwEMailSize+dwDescriptionSize+32)); + if (lpbData) { + LPBYTE lpbDataCurrent = lpbData; + SetUL(&lpbDataCurrent, dwStatus); + SetLPSLowerCase(&lpbDataCurrent, lpszEMail, dwEMailSize); + SetUL(&lpbDataCurrent, dwIDRequest); + SetLPS(&lpbDataCurrent, (LPSTR)lpbDescription, dwDescriptionSize); + + dwRet = MraSendCMD(MRIM_CS_FILE_TRANSFER_ACK, lpbData, (lpbDataCurrent-lpbData)); + mir_free(lpbData); + } + } + return dwRet; +} + +// Поиск контакта +HANDLE CMraProto::MraWPRequestW(HANDLE hContact, DWORD dwAckType, DWORD dwRequestFlags, LPSTR lpszUser, size_t dwUserSize, LPSTR lpszDomain, size_t dwDomainSize, LPCWSTR lpwszNickName, size_t dwNickNameSize, LPCWSTR lpwszFirstName, size_t dwFirstNameSize, LPCWSTR lpwszLastName, size_t dwLastNameSize, DWORD dwSex, DWORD dwDate1, DWORD dwDate2, DWORD dwCityID, DWORD dwZodiak, DWORD dwBirthdayMonth, DWORD dwBirthdayDay, DWORD dwCountryID, DWORD dwOnline) +{ + DWORD dwRet = 0; + LPBYTE lpbData = (LPBYTE)mir_calloc(((dwUserSize+dwDomainSize+dwNickNameSize+dwFirstNameSize+dwLastNameSize)*sizeof(WCHAR))+4096); + if (lpbData) { + CHAR szBuff[MAX_PATH]; + size_t dwBuffSize; + + LPBYTE lpbDataCurrent = lpbData; + + if (GetBit(dwRequestFlags, MRIM_CS_WP_REQUEST_PARAM_USER)) { SetUL(&lpbDataCurrent, MRIM_CS_WP_REQUEST_PARAM_USER);SetLPSLowerCase(&lpbDataCurrent, lpszUser, dwUserSize); } + if (GetBit(dwRequestFlags, MRIM_CS_WP_REQUEST_PARAM_DOMAIN)) { SetUL(&lpbDataCurrent, MRIM_CS_WP_REQUEST_PARAM_DOMAIN);SetLPSLowerCase(&lpbDataCurrent, lpszDomain, dwDomainSize); } + if (GetBit(dwRequestFlags, MRIM_CS_WP_REQUEST_PARAM_NICKNAME)) { SetUL(&lpbDataCurrent, MRIM_CS_WP_REQUEST_PARAM_NICKNAME);SetLPSW(&lpbDataCurrent, lpwszNickName, dwNickNameSize); } + if (GetBit(dwRequestFlags, MRIM_CS_WP_REQUEST_PARAM_FIRSTNAME)) { SetUL(&lpbDataCurrent, MRIM_CS_WP_REQUEST_PARAM_FIRSTNAME);SetLPSW(&lpbDataCurrent, lpwszFirstName, dwFirstNameSize); } + if (GetBit(dwRequestFlags, MRIM_CS_WP_REQUEST_PARAM_LASTNAME)) { SetUL(&lpbDataCurrent, MRIM_CS_WP_REQUEST_PARAM_LASTNAME);SetLPSW(&lpbDataCurrent, lpwszLastName, dwLastNameSize); } + + if (GetBit(dwRequestFlags, MRIM_CS_WP_REQUEST_PARAM_SEX)) { + dwBuffSize = mir_snprintf(szBuff, SIZEOF(szBuff), "%lu", dwSex); + SetUL(&lpbDataCurrent, MRIM_CS_WP_REQUEST_PARAM_SEX); + SetLPS(&lpbDataCurrent, szBuff, dwBuffSize); + } + + if (GetBit(dwRequestFlags, MRIM_CS_WP_REQUEST_PARAM_DATE1)) { + dwBuffSize = mir_snprintf(szBuff, SIZEOF(szBuff), "%lu", dwDate1); + SetUL(&lpbDataCurrent, MRIM_CS_WP_REQUEST_PARAM_DATE1); + SetLPS(&lpbDataCurrent, szBuff, dwBuffSize); + } + + if (GetBit(dwRequestFlags, MRIM_CS_WP_REQUEST_PARAM_DATE2)) { + dwBuffSize = mir_snprintf(szBuff, SIZEOF(szBuff), "%lu", dwDate2); + SetUL(&lpbDataCurrent, MRIM_CS_WP_REQUEST_PARAM_DATE2); + SetLPS(&lpbDataCurrent, szBuff, dwBuffSize); + } + + if (GetBit(dwRequestFlags, MRIM_CS_WP_REQUEST_PARAM_CITY_ID)) { + dwBuffSize = mir_snprintf(szBuff, SIZEOF(szBuff), "%lu", dwCityID); + SetUL(&lpbDataCurrent, MRIM_CS_WP_REQUEST_PARAM_CITY_ID); + SetLPS(&lpbDataCurrent, szBuff, dwBuffSize); + } + + if (GetBit(dwRequestFlags, MRIM_CS_WP_REQUEST_PARAM_ZODIAC)) { + dwBuffSize = mir_snprintf(szBuff, SIZEOF(szBuff), "%lu", dwZodiak); + SetUL(&lpbDataCurrent, MRIM_CS_WP_REQUEST_PARAM_ZODIAC); + SetLPS(&lpbDataCurrent, szBuff, dwBuffSize); + } + + if (GetBit(dwRequestFlags, MRIM_CS_WP_REQUEST_PARAM_BIRTHDAY_MONTH)) { + dwBuffSize = mir_snprintf(szBuff, SIZEOF(szBuff), "%lu", dwBirthdayMonth); + SetUL(&lpbDataCurrent, MRIM_CS_WP_REQUEST_PARAM_BIRTHDAY_MONTH); + SetLPS(&lpbDataCurrent, szBuff, dwBuffSize); + } + + if (GetBit(dwRequestFlags, MRIM_CS_WP_REQUEST_PARAM_BIRTHDAY_DAY)) { + dwBuffSize = mir_snprintf(szBuff, SIZEOF(szBuff), "%lu", dwBirthdayDay); + SetUL(&lpbDataCurrent, MRIM_CS_WP_REQUEST_PARAM_BIRTHDAY_DAY); + SetLPS(&lpbDataCurrent, szBuff, dwBuffSize); + } + + if (GetBit(dwRequestFlags, MRIM_CS_WP_REQUEST_PARAM_COUNTRY_ID)) { + dwBuffSize = mir_snprintf(szBuff, SIZEOF(szBuff), "%lu", dwCountryID); + SetUL(&lpbDataCurrent, MRIM_CS_WP_REQUEST_PARAM_COUNTRY_ID); + SetLPS(&lpbDataCurrent, szBuff, dwBuffSize); + } + + if (GetBit(dwRequestFlags, MRIM_CS_WP_REQUEST_PARAM_ONLINE)) { + dwBuffSize = mir_snprintf(szBuff, SIZEOF(szBuff), "%lu", dwOnline); + SetUL(&lpbDataCurrent, MRIM_CS_WP_REQUEST_PARAM_ONLINE); + SetLPS(&lpbDataCurrent, szBuff, dwBuffSize); + } + + dwRet = MraSendQueueCMD(hSendQueueHandle, 0, hContact, dwAckType, NULL, 0, MRIM_CS_WP_REQUEST, lpbData, (lpbDataCurrent-lpbData)); + mir_free(lpbData); + } + return (HANDLE)dwRet; +} + +// Поиск контакта по EMail +HANDLE CMraProto::MraWPRequestByEMail(HANDLE hContact, DWORD dwAckType, LPCSTR lpszEMail, size_t dwEMailSize) +{ + HANDLE dwRet = 0; + + if (lpszEMail && dwEMailSize>4) { + size_t dwUserSize, dwDomainSize; + LPSTR lpszDomain = (LPSTR)MemoryFindByte(0, lpszEMail, dwEMailSize, '@'); + if (lpszDomain) { + LPSTR lpszUser = (LPSTR)lpszEMail; + dwUserSize = (lpszDomain-lpszEMail); + lpszDomain++; + dwDomainSize = (dwEMailSize-(dwUserSize+1)); + + DWORD dwRequestFlags = 0; + SetBit(dwRequestFlags, MRIM_CS_WP_REQUEST_PARAM_USER); + SetBit(dwRequestFlags, MRIM_CS_WP_REQUEST_PARAM_DOMAIN); + + dwRet = MraWPRequestW(hContact, dwAckType, dwRequestFlags, lpszUser, dwUserSize, lpszDomain, dwDomainSize, NULL, 0, NULL, 0, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + } + } + return dwRet; +} + +// Отправка файлов +DWORD CMraProto::MraGame(LPSTR lpszEMail, size_t dwEMailSize, DWORD dwGameSessionID, DWORD dwGameMsg, DWORD dwGameMsgID, LPSTR lpszData, size_t dwDataSize) +{ + DWORD dwRet = 0; + + if (lpszEMail && dwEMailSize>4) { + LPBYTE lpbData = (LPBYTE)mir_calloc((dwEMailSize+(sizeof(DWORD)*4)+dwDataSize+32)); + if (lpbData) { + LPBYTE lpbDataCurrent = lpbData; + SetLPSLowerCase(&lpbDataCurrent, lpszEMail, dwEMailSize); + SetUL(&lpbDataCurrent, dwGameSessionID); + SetUL(&lpbDataCurrent, dwGameMsg); + SetUL(&lpbDataCurrent, dwGameMsgID); + SetUL(&lpbDataCurrent, _time32(NULL)); + SetLPS(&lpbDataCurrent, lpszData, dwDataSize); + + dwRet = MraSendCMD(MRIM_CS_GAME, lpbData, (lpbDataCurrent-lpbData)); + mir_free(lpbData); + } + } + return dwRet; +} + +// Авторизация +DWORD CMraProto::MraLogin2W(LPSTR lpszLogin, size_t dwLoginSize, LPSTR lpszPassword, size_t dwPasswordSize, DWORD dwStatus, LPSTR lpszStatusUri, size_t dwStatusUriSize, LPWSTR lpwszStatusTitle, size_t dwStatusTitleSize, LPWSTR lpwszStatusDesc, size_t dwStatusDescSize, DWORD dwFutureFlags, LPSTR dwUserAgentFormatted, size_t dwUserAgentFormattedSize, LPSTR lpszUserAgent, size_t dwUserAgentSize) +{ + DWORD dwRet = 0; + + if (dwStatusUriSize>SPEC_STATUS_URI_MAX) dwStatusUriSize = SPEC_STATUS_URI_MAX; + if (dwStatusTitleSize>STATUS_TITLE_MAX) dwStatusTitleSize = STATUS_TITLE_MAX; + if (dwStatusDescSize>STATUS_DESC_MAX) dwStatusDescSize = STATUS_DESC_MAX; + if (dwUserAgentFormattedSize>USER_AGENT_MAX) dwUserAgentFormattedSize = USER_AGENT_MAX; + if (dwUserAgentSize>MAX_CLIENT_DESCRIPTION) dwUserAgentSize = MAX_CLIENT_DESCRIPTION; + + LPBYTE lpbData = (LPBYTE)mir_calloc((dwLoginSize+dwPasswordSize+sizeof(DWORD)+dwStatusUriSize+(dwStatusTitleSize*sizeof(WCHAR))+(dwStatusDescSize*sizeof(WCHAR))+2+sizeof(DWORD)+(sizeof(DWORD)*2)+dwUserAgentFormattedSize+dwUserAgentSize+32)); + if (lpbData) { + LPBYTE lpbDataCurrent = lpbData; + SetLPS(&lpbDataCurrent, lpszLogin, dwLoginSize); + SetLPS(&lpbDataCurrent, lpszPassword, dwPasswordSize); + SetUL(&lpbDataCurrent, dwStatus); + SetLPS(&lpbDataCurrent, lpszStatusUri, dwStatusUriSize); + SetLPSW(&lpbDataCurrent, lpwszStatusTitle, dwStatusTitleSize); + SetLPSW(&lpbDataCurrent, lpwszStatusDesc, dwStatusDescSize); + SetUL(&lpbDataCurrent, dwFutureFlags); + SetLPS(&lpbDataCurrent, dwUserAgentFormatted, dwUserAgentFormattedSize); + SetLPS(&lpbDataCurrent, "ru", 2); + SetLPS(&lpbDataCurrent, NULL, 0); + SetLPS(&lpbDataCurrent, NULL, 0); + SetLPS(&lpbDataCurrent, lpszUserAgent, dwUserAgentSize);// LPS client description /max 256 + + dwRet = MraSendCMD(MRIM_CS_LOGIN2, lpbData, (lpbDataCurrent-lpbData)); + mir_free(lpbData); + } + return dwRet; +} + +// Отправка SMS +DWORD CMraProto::MraSMSW(HANDLE hContact, LPSTR lpszPhone, size_t dwPhoneSize, LPWSTR lpwszMessage, size_t dwMessageSize) +{ + DWORD dwRet = 0; + LPBYTE lpbData = (LPBYTE)mir_calloc((dwPhoneSize+(dwMessageSize*sizeof(WCHAR))+32)); + LPBYTE lpbDataQueue = (LPBYTE)mir_calloc((dwPhoneSize+(dwMessageSize*sizeof(WCHAR))+32)); + LPSTR lpszPhoneLocal = (LPSTR)mir_calloc((dwPhoneSize+32)); + if (lpbData && lpbDataQueue && lpszPhoneLocal) { + lpszPhoneLocal[0] = '+'; + dwPhoneSize = 1+CopyNumber((lpszPhoneLocal+1), lpszPhone, dwPhoneSize); + + LPBYTE lpbDataCurrent = lpbData; + SetUL(&lpbDataCurrent, 0); + SetLPS(&lpbDataCurrent, lpszPhoneLocal, dwPhoneSize); + SetLPSW(&lpbDataCurrent, lpwszMessage, dwMessageSize); + + (*(DWORD*)lpbDataQueue) = dwPhoneSize; + memmove((lpbDataQueue+sizeof(DWORD)), lpszPhoneLocal, (dwPhoneSize+1)); + memmove((lpbDataQueue+sizeof(DWORD)+dwPhoneSize+1), lpwszMessage, ((dwMessageSize*sizeof(WCHAR))+1)); + + dwRet = MraSendQueueCMD(hSendQueueHandle, 0, hContact, ICQACKTYPE_SMS, lpbDataQueue, (dwPhoneSize+(dwMessageSize*sizeof(WCHAR))+sizeof(DWORD)+2), MRIM_CS_SMS, lpbData, (lpbDataCurrent-lpbData)); + mir_free(lpbData); + mir_free(lpszPhoneLocal); + } + else { + mir_free(lpbData); + mir_free(lpbDataQueue); + mir_free(lpszPhoneLocal); + } + return dwRet; +} + +// Соединение с прокси +DWORD CMraProto::MraProxy(LPSTR lpszEMail, size_t dwEMailSize, DWORD dwIDRequest, DWORD dwDataType, LPSTR lpszData, size_t dwDataSize, LPSTR lpszAddreses, size_t dwAddressesSize, MRA_GUID mguidSessionID) +{ + DWORD dwRet = 0; + + if (lpszEMail && dwEMailSize>4) { + LPBYTE lpbData = (LPBYTE)mir_calloc((dwEMailSize+(sizeof(DWORD)*2)+dwDataSize+dwAddressesSize+sizeof(MRA_GUID)+32)); + if (lpbData) { + LPBYTE lpbDataCurrent = lpbData; + SetLPSLowerCase(&lpbDataCurrent, lpszEMail, dwEMailSize); + SetUL(&lpbDataCurrent, dwIDRequest); + SetUL(&lpbDataCurrent, dwDataType); + SetLPS(&lpbDataCurrent, lpszData, dwDataSize); + SetLPS(&lpbDataCurrent, lpszAddreses, dwAddressesSize); + SetGUID(&lpbDataCurrent, mguidSessionID); + + dwRet = MraSendCMD(MRIM_CS_PROXY, lpbData, (lpbDataCurrent-lpbData)); + mir_free(lpbData); + } + } + return dwRet; +} + +// Ответ на соединение с прокси +DWORD CMraProto::MraProxyAck(DWORD dwStatus, LPSTR lpszEMail, size_t dwEMailSize, DWORD dwIDRequest, DWORD dwDataType, LPSTR lpszData, size_t dwDataSize, LPSTR lpszAddreses, size_t dwAddressesSize, MRA_GUID mguidSessionID) +{ + DWORD dwRet = 0; + + if (lpszEMail && dwEMailSize>4) { + LPBYTE lpbData = (LPBYTE)mir_calloc((dwEMailSize+(sizeof(DWORD)*3)+dwDataSize+dwAddressesSize+sizeof(MRA_GUID)+32)); + if (lpbData) { + LPBYTE lpbDataCurrent = lpbData; + SetUL(&lpbDataCurrent, dwStatus); + SetLPSLowerCase(&lpbDataCurrent, lpszEMail, dwEMailSize); + SetUL(&lpbDataCurrent, dwIDRequest); + SetUL(&lpbDataCurrent, dwDataType); + SetLPS(&lpbDataCurrent, lpszData, dwDataSize); + SetLPS(&lpbDataCurrent, lpszAddreses, dwAddressesSize); + SetGUID(&lpbDataCurrent, mguidSessionID); + + dwRet = MraSendCMD(MRIM_CS_PROXY_ACK, lpbData, (lpbDataCurrent-lpbData)); + mir_free(lpbData); + } + } + return dwRet; +} + +// Отправка сообщения в микроблог +DWORD CMraProto::MraChangeUserBlogStatus(DWORD dwFlags, LPWSTR lpwszText, size_t dwTextSize, DWORDLONG dwBlogStatusID) +{ + DWORD dwRet = 0; + if (dwTextSize > MICBLOG_STATUS_MAX) + dwTextSize = MICBLOG_STATUS_MAX; + + LPBYTE lpbData = (LPBYTE)mir_calloc((sizeof(DWORD)+(dwTextSize*sizeof(WCHAR))+sizeof(DWORDLONG)+32)); + if (lpbData) { + LPBYTE lpbDataCurrent = lpbData; + SetUL(&lpbDataCurrent, dwFlags); + SetLPSW(&lpbDataCurrent, lpwszText, dwTextSize); + SetUIDL(&lpbDataCurrent, dwBlogStatusID); + + dwRet = MraSendCMD(MRIM_CS_CHANGE_USER_BLOG_STATUS, lpbData, (lpbDataCurrent-lpbData)); + mir_free(lpbData); + } + + return dwRet; +} + +DWORD CMraProto::MraSendPacket(HANDLE hConnection, DWORD dwCMDNum, DWORD dwType, LPVOID lpData, size_t dwDataSize) +{ + DWORD dwRet; + + LPBYTE lpbData = (LPBYTE)mir_calloc((dwDataSize+sizeof(mrim_packet_header_t))); + if (lpbData) { + mrim_packet_header_t *pmaHeader = (mrim_packet_header_t*)lpbData; + pmaHeader->magic = CS_MAGIC; + pmaHeader->proto = (PROTO_VERSION_MAJOR<<16) + PROTO_VERSION_MINOR; // Версия протокола + pmaHeader->seq = dwCMDNum;// Sequence + pmaHeader->msg = dwType;// Тип пакета + pmaHeader->dlen = dwDataSize;// Длина данных + + Netlib_Logf(hNetlibUser, "Sending packet %08x\n", dwType); + + memmove((lpbData+sizeof(mrim_packet_header_t)), lpData, dwDataSize); + dwRet = Netlib_Send(hConnection, (LPSTR)lpbData, (dwDataSize+sizeof(mrim_packet_header_t)), 0); + mir_free(lpbData); + } + return dwRet; +} + +DWORD CMraProto::MraSendCMD(DWORD dwType, LPVOID lpData, size_t dwDataSize) +{ + DWORD dwRet = InterlockedIncrement((LONG volatile*)&dwCMDNum); + + mir_cslock l(csCriticalSectionSend); // guarding winsock internal buffers + return !MraSendPacket(hConnection, dwRet, dwType, lpData, dwDataSize) ? 0 : dwRet; +} + + +DWORD CMraProto::MraSendQueueCMD(HANDLE hSendQueueHandle, DWORD dwFlags, HANDLE hContact, DWORD dwAckType, LPBYTE lpbDataQueue, size_t dwDataQueueSize, DWORD dwType, LPVOID lpData, size_t dwDataSize) +{ + DWORD dwRet = InterlockedIncrement((LONG volatile*)&dwCMDNum); + if ( !MraSendQueueAdd(hSendQueueHandle, dwRet, dwFlags, hContact, dwAckType, lpbDataQueue, dwDataQueueSize)) { + mir_cslock l(csCriticalSectionSend); // guarding winsock internal buffers + if ( !MraSendPacket(hConnection, dwRet, dwType, lpData, dwDataSize)) { + MraSendQueueFree(hSendQueueHandle, dwRet); + dwRet = 0; + } + } + return dwRet; +} diff --git a/protocols/MRA/src/MraSendCommand.h b/protocols/MRA/src/MraSendCommand.h new file mode 100644 index 0000000000..dd1eb9a2b0 --- /dev/null +++ b/protocols/MRA/src/MraSendCommand.h @@ -0,0 +1,10 @@ +#if !defined(AFX_MRA_SENDCOMMAND_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_) +#define AFX_MRA_SENDCOMMAND_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_ + + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + +#endif // !defined(AFX_MRA_SENDCOMMAND_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_) diff --git a/protocols/MRA/src/MraSendQueue.cpp b/protocols/MRA/src/MraSendQueue.cpp new file mode 100644 index 0000000000..53d6f1345d --- /dev/null +++ b/protocols/MRA/src/MraSendQueue.cpp @@ -0,0 +1,168 @@ +#include "Mra.h" +#include "MraSendQueue.h" + +struct MRA_SEND_QUEUE : public LIST_MT +{ + DWORD dwSendTimeOutInterval; +}; + +struct MRA_SEND_QUEUE_ITEM : public LIST_MT_ITEM +{ + // internal + FILETIME ftSendTime; + + // external + DWORD dwCMDNum; + DWORD dwFlags; + HANDLE hContact; + DWORD dwAckType; + LPBYTE lpbData; + size_t dwDataSize; +}; + +#define FILETIME_SECOND ((DWORDLONG)10000000) + +DWORD MraSendQueueInitialize(DWORD dwSendTimeOutInterval, HANDLE *phSendQueueHandle) +{ + if (!phSendQueueHandle) + return ERROR_INVALID_HANDLE; + + MRA_SEND_QUEUE *pmrasqSendQueue = (MRA_SEND_QUEUE*)mir_calloc(sizeof(MRA_SEND_QUEUE)); + if (!pmrasqSendQueue) + return GetLastError(); + + DWORD dwRetErrorCode = ListMTInitialize(pmrasqSendQueue, 0); + if (dwRetErrorCode == NO_ERROR) { + pmrasqSendQueue->dwSendTimeOutInterval = dwSendTimeOutInterval; + *phSendQueueHandle = (HANDLE)pmrasqSendQueue; + } + return dwRetErrorCode; +} + +void MraSendQueueDestroy(HANDLE hSendQueueHandle) +{ + if (!hSendQueueHandle) + return; + + MRA_SEND_QUEUE *pmrasqSendQueue = (MRA_SEND_QUEUE*)hSendQueueHandle; + MRA_SEND_QUEUE_ITEM *pmrasqiSendQueueItem; + { + mt_lock l(pmrasqSendQueue); + while ( !ListMTItemGetFirst(pmrasqSendQueue, NULL, (LPVOID*)&pmrasqiSendQueueItem)) { + ListMTItemDelete(pmrasqSendQueue, pmrasqiSendQueueItem); + mir_free(pmrasqiSendQueueItem); + } + } + + ListMTDestroy(pmrasqSendQueue); + mir_free(pmrasqSendQueue); +} + + +DWORD MraSendQueueAdd(HANDLE hSendQueueHandle, DWORD dwCMDNum, DWORD dwFlags, HANDLE hContact, DWORD dwAckType, LPBYTE lpbData, size_t dwDataSize) +{ + if (!hSendQueueHandle || !dwCMDNum) + return ERROR_INVALID_HANDLE; + + MRA_SEND_QUEUE *pmrasqSendQueue = (MRA_SEND_QUEUE*)hSendQueueHandle; + MRA_SEND_QUEUE_ITEM *pmrasqiSendQueueItem; + + pmrasqiSendQueueItem = (MRA_SEND_QUEUE_ITEM*)mir_calloc(sizeof(MRA_SEND_QUEUE_ITEM)); + if (!pmrasqiSendQueueItem) + return GetLastError(); + + GetSystemTimeAsFileTime(&pmrasqiSendQueueItem->ftSendTime); + pmrasqiSendQueueItem->dwCMDNum = dwCMDNum; + pmrasqiSendQueueItem->dwFlags = dwFlags; + pmrasqiSendQueueItem->hContact = hContact; + pmrasqiSendQueueItem->dwAckType = dwAckType; + pmrasqiSendQueueItem->lpbData = lpbData; + pmrasqiSendQueueItem->dwDataSize = dwDataSize; + + mt_lock l(pmrasqSendQueue); + ListMTItemAdd(pmrasqSendQueue, pmrasqiSendQueueItem, pmrasqiSendQueueItem); + return 0; +} + +DWORD MraSendQueueFree(HANDLE hSendQueueHandle, DWORD dwCMDNum) +{ + if (!hSendQueueHandle) + return ERROR_INVALID_HANDLE; + + MRA_SEND_QUEUE *pmrasqSendQueue = (MRA_SEND_QUEUE*)hSendQueueHandle; + MRA_SEND_QUEUE_ITEM *pmrasqiSendQueueItem; + LIST_MT_ITERATOR lmtiIterator; + + mt_lock l(pmrasqSendQueue); + ListMTIteratorMoveFirst(pmrasqSendQueue, &lmtiIterator); + do { + if ( !ListMTIteratorGet(&lmtiIterator, NULL, (LPVOID*)&pmrasqiSendQueueItem)) + if (pmrasqiSendQueueItem->dwCMDNum == dwCMDNum) { + ListMTItemDelete(pmrasqSendQueue, pmrasqiSendQueueItem); + mir_free(pmrasqiSendQueueItem); + return 0; + } + } + while (ListMTIteratorMoveNext(&lmtiIterator)); + + return ERROR_NOT_FOUND; +} + +DWORD MraSendQueueFind(HANDLE hSendQueueHandle, DWORD dwCMDNum, DWORD *pdwFlags, HANDLE *phContact, DWORD *pdwAckType, LPBYTE *plpbData, size_t *pdwDataSize) +{ + if (!hSendQueueHandle) + return ERROR_INVALID_HANDLE; + + MRA_SEND_QUEUE *pmrasqSendQueue = (MRA_SEND_QUEUE*)hSendQueueHandle; + MRA_SEND_QUEUE_ITEM *pmrasqiSendQueueItem; + LIST_MT_ITERATOR lmtiIterator; + + mt_lock l(pmrasqSendQueue); + ListMTIteratorMoveFirst(pmrasqSendQueue, &lmtiIterator); + do { + if ( !ListMTIteratorGet(&lmtiIterator, NULL, (LPVOID*)&pmrasqiSendQueueItem)) + if (pmrasqiSendQueueItem->dwCMDNum == dwCMDNum) { + if (pdwFlags) (*pdwFlags) = pmrasqiSendQueueItem->dwFlags; + if (phContact) (*phContact) = pmrasqiSendQueueItem->hContact; + if (pdwAckType) (*pdwAckType) = pmrasqiSendQueueItem->dwAckType; + if (plpbData) (*plpbData) = pmrasqiSendQueueItem->lpbData; + if (pdwDataSize) (*pdwDataSize) = pmrasqiSendQueueItem->dwDataSize; + return 0; + } + } + while (ListMTIteratorMoveNext(&lmtiIterator)); + + return ERROR_NOT_FOUND; +} + +DWORD MraSendQueueFindOlderThan(HANDLE hSendQueueHandle, DWORD dwTime, DWORD *pdwCMDNum, DWORD *pdwFlags, HANDLE *phContact, DWORD *pdwAckType, LPBYTE *plpbData, size_t *pdwDataSize) +{ + if (!hSendQueueHandle) + return ERROR_INVALID_HANDLE; + + FILETIME ftExpireTime; + GetSystemTimeAsFileTime(&ftExpireTime); + (*((DWORDLONG*)&ftExpireTime))-=((DWORDLONG)dwTime*FILETIME_SECOND); + + MRA_SEND_QUEUE *pmrasqSendQueue = (MRA_SEND_QUEUE*)hSendQueueHandle; + mt_lock l(pmrasqSendQueue); + + LIST_MT_ITERATOR lmtiIterator; + ListMTIteratorMoveFirst(pmrasqSendQueue, &lmtiIterator); + do { + MRA_SEND_QUEUE_ITEM *pmrasqiSendQueueItem; + if ( !ListMTIteratorGet(&lmtiIterator, NULL, (LPVOID*)&pmrasqiSendQueueItem)) + if ((*((DWORDLONG*)&ftExpireTime))>(*((DWORDLONG*)&pmrasqiSendQueueItem->ftSendTime))) { + if (pdwCMDNum) *pdwCMDNum = pmrasqiSendQueueItem->dwCMDNum; + if (pdwFlags) *pdwFlags = pmrasqiSendQueueItem->dwFlags; + if (phContact) *phContact = pmrasqiSendQueueItem->hContact; + if (pdwAckType) *pdwAckType = pmrasqiSendQueueItem->dwAckType; + if (plpbData) *plpbData = pmrasqiSendQueueItem->lpbData; + if (pdwDataSize) *pdwDataSize = pmrasqiSendQueueItem->dwDataSize; + return 0; + } + } + while (ListMTIteratorMoveNext(&lmtiIterator)); + + return ERROR_NOT_FOUND; +} diff --git a/protocols/MRA/src/MraSendQueue.h b/protocols/MRA/src/MraSendQueue.h new file mode 100644 index 0000000000..0e7f7ae51a --- /dev/null +++ b/protocols/MRA/src/MraSendQueue.h @@ -0,0 +1,23 @@ +#if !defined(AFX_MRA_SENDQUEUE_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_) +#define AFX_MRA_SENDQUEUE_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_ + + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + + +DWORD MraSendQueueInitialize(DWORD dwSendTimeOutInterval, HANDLE *phSendQueueHandle); +void MraSendQueueDestroy(HANDLE hSendQueueHandle); + +DWORD MraSendQueueAdd(HANDLE hSendQueueHandle, DWORD dwCMDNum, DWORD dwFlags, HANDLE hContact, DWORD dwAckType, LPBYTE lpbData, size_t dwDataSize); +DWORD MraSendQueueFree(HANDLE hSendQueueHandle, DWORD dwCMDNum); + +DWORD MraSendQueueFind(HANDLE hSendQueueHandle, DWORD dwCMDNum, DWORD *pdwFlags, HANDLE *phContact, DWORD *pdwAckType, LPBYTE *plpbData, size_t *pdwDataSize); +DWORD MraSendQueueFindOlderThan(HANDLE hSendQueueHandle, DWORD dwTime, DWORD *pdwCMDNum, DWORD *pdwFlags, HANDLE *phContact, DWORD *pdwAckType, LPBYTE *plpbData, size_t *pdwDataSize); + + + + +#endif // !defined(AFX_MRA_SENDQUEUE_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_) diff --git a/protocols/MRA/src/Mra_functions.cpp b/protocols/MRA/src/Mra_functions.cpp new file mode 100644 index 0000000000..7083da1b8d --- /dev/null +++ b/protocols/MRA/src/Mra_functions.cpp @@ -0,0 +1,1834 @@ +#include "Mra.h" + +#define MRA_PASS_CRYPT_VER 2 + +struct SetXStatusData +{ + CMraProto *ppro; + DWORD dwXStatus; + DWORD dwCountdown; + HICON hDlgIcon; +}; + +struct SetBlogStatusData +{ + CMraProto *ppro; + HANDLE hContact; +}; + +#define RECURSION_DATA_STACK_ITEMS_MIN 128 +struct RECURSION_DATA_STACK_ITEM +{ + HANDLE hFind; + DWORD dwFileNameLen; + WIN32_FIND_DATA w32fdFindFileData; +}; + +LRESULT CALLBACK MessageEditSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + +DWORD MraGetSelfVersionString(LPSTR lpszSelfVersion, size_t dwSelfVersionSize, size_t *pdwSelfVersionSizeRet) +{ + if (!lpszSelfVersion || !dwSelfVersionSize) + return ERROR_INVALID_HANDLE; + + WORD v[4]; + DWORD dwMirVer = CallService(MS_SYSTEM_GETFILEVERSION, 0, (LPARAM)v); + LPSTR lpszUnicode = (IsUnicodeEnv()? " Unicode":""), + lpszSecIM = ( ServiceExists("SecureIM/IsContactSecured")? " + SecureIM":""); + size_t dwSelfVersionSizeRet; + + dwSelfVersionSizeRet = mir_snprintf(lpszSelfVersion, dwSelfVersionSize, "Miranda NG %lu.%lu.%lu.%lu%s (MRA v%lu.%lu.%lu.%lu)%s, version: %lu.%lu", + v[0], v[1], v[2], v[3], lpszUnicode, + __FILEVERSION_STRING, lpszSecIM, PROTO_VERSION_MAJOR, PROTO_VERSION_MINOR); + + if (pdwSelfVersionSizeRet) + *pdwSelfVersionSizeRet = dwSelfVersionSizeRet; + return 0; +} + +DWORD GetParamValue(LPSTR lpszData, size_t dwDataSize, LPSTR lpszParamName, size_t dwParamNameSize, LPSTR lpszParamValue, size_t dwParamValueSize, size_t *pParamValueSizeRet) +{ + if (!lpszData || !dwDataSize || !lpszParamName || !dwParamNameSize || !lpszParamValue || !dwParamValueSize) + return ERROR_INVALID_HANDLE; + + char szData[USER_AGENT_MAX+4096]; + LPSTR lpszParamDataStart, lpszParamDataEnd; + + dwDataSize = ((dwDataSizedwAddrCount = 0; + pmalAddrList->pmaliAddress = (MRA_ADDR_LIST_ITEM*)mir_calloc(sizeof(MRA_ADDR_LIST_ITEM)*dwAllocatedCount); + lpszCurrentItem = lpszAddreses; + + while (TRUE) { + lpszEndItem = (LPSTR)MemoryFindByte((lpszCurrentItem-lpszAddreses), lpszAddreses, dwAddresesSize, ';'); + if (lpszEndItem == NULL) lpszEndItem = (lpszAddreses+dwAddresesSize); + if (!lpszEndItem) + break; + + lpszDelimiter = (LPSTR)MemoryFindByte((lpszCurrentItem-lpszAddreses), lpszAddreses, dwAddresesSize, ':'); + if (!lpszDelimiter) + break; + + if (pmalAddrList->dwAddrCount == dwAllocatedCount) { + dwAllocatedCount += ALLOCATED_COUNT; + pmalAddrList->pmaliAddress = (MRA_ADDR_LIST_ITEM*)mir_realloc(pmalAddrList->pmaliAddress, (sizeof(MRA_ADDR_LIST_ITEM)*dwAllocatedCount)); + } + + (*lpszDelimiter) = 0; + pmalAddrList->pmaliAddress[pmalAddrList->dwAddrCount].dwAddr = inet_addr(lpszCurrentItem); + pmalAddrList->pmaliAddress[pmalAddrList->dwAddrCount].dwPort = StrToUNum32((lpszDelimiter+1), (lpszEndItem-(lpszDelimiter+1))); + (*lpszDelimiter) = ':'; + pmalAddrList->dwAddrCount++; + lpszCurrentItem = (lpszEndItem+1); + + if (lpszEndItem == lpszAddreses + dwAddresesSize) + break; + } + pmalAddrList->pmaliAddress = (MRA_ADDR_LIST_ITEM*)mir_realloc(pmalAddrList->pmaliAddress, (sizeof(MRA_ADDR_LIST_ITEM)*pmalAddrList->dwAddrCount)); + return NO_ERROR; +} + +DWORD MraAddrListGetToBuff(MRA_ADDR_LIST *pmalAddrList, LPSTR lpszBuff, size_t dwBuffSize, size_t *pdwBuffSizeRet) +{ + if (!pmalAddrList || !lpszBuff || !dwBuffSize) + return ERROR_INVALID_HANDLE; + + LPSTR lpszCurPos = lpszBuff; + + for (size_t i = 0;idwAddrCount;i++) + lpszCurPos += mir_snprintf(lpszCurPos, (dwBuffSize-((size_t)lpszCurPos-(size_t)lpszBuff)), "%s:%lu;", + inet_ntoa((*((in_addr*)&pmalAddrList->pmaliAddress[i].dwAddr))), pmalAddrList->pmaliAddress[i].dwPort); + + if (pdwBuffSizeRet) + *pdwBuffSizeRet = lpszCurPos - lpszBuff; + return NO_ERROR; +} + +void CMraProto::MraAddrListStoreToContact(HANDLE hContact, MRA_ADDR_LIST *pmalAddrList) +{ + if (!hContact || !pmalAddrList) + return; + + if (!pmalAddrList->dwAddrCount) + return; + + mraSetDword(hContact, "OldIP", mraGetDword(hContact, "IP", 0)); + mraSetDword(hContact, "IP", HTONL(pmalAddrList->pmaliAddress[0].dwAddr)); + if (pmalAddrList->dwAddrCount > 1) { + mraSetDword(hContact, "OldRealIP", mraGetDword(hContact, "RealIP", 0)); + mraSetDword(hContact, "RealIP", HTONL(pmalAddrList->pmaliAddress[1].dwAddr)); + } +} + +void MraAddrListFree(MRA_ADDR_LIST *pmalAddrList) +{ + if (pmalAddrList) { + mir_free(pmalAddrList->pmaliAddress); + pmalAddrList->dwAddrCount = 0; + } +} + +void CMraProto::DB_MraCreateResidentSetting(LPSTR lpszValueName) +{ + char szSetting[2*MAX_PATH]; + mir_snprintf(szSetting, SIZEOF(szSetting), "%s/%s", m_szModuleName, lpszValueName); + CallService(MS_DB_SETSETTINGRESIDENT, TRUE, (WPARAM)szSetting); +} + +BOOL DB_GetStaticStringA(HANDLE hContact, LPCSTR lpszModule, LPCSTR lpszValueName, LPSTR lpszRetBuff, size_t dwRetBuffSize, size_t *pdwRetBuffSize) +{ + BOOL bRet = FALSE; + size_t dwReadedStringLen, dwRetBuffSizeLocal; + DBVARIANT dbv = {0}; + DBCONTACTGETSETTING sVal = {0}; + + dbv.type = DBVT_WCHAR; + sVal.pValue = &dbv; + sVal.szModule = lpszModule; + sVal.szSetting = lpszValueName; + if (CallService(MS_DB_CONTACT_GETSETTING_STR, (WPARAM)hContact, (LPARAM)&sVal) == 0) + { + dwReadedStringLen = lstrlenW(dbv.pwszVal); + if (lpszRetBuff && (dwRetBuffSize>dwReadedStringLen)) + { + dwRetBuffSizeLocal = WideCharToMultiByte(MRA_CODE_PAGE, 0, dbv.pwszVal, dwReadedStringLen, lpszRetBuff, dwRetBuffSize, NULL, NULL); + (*((CHAR*)(lpszRetBuff+dwRetBuffSizeLocal))) = 0; + bRet = TRUE; + }else { + dwRetBuffSizeLocal = dwReadedStringLen; + if (lpszRetBuff && dwRetBuffSize >= sizeof(WORD)) (*((WORD*)lpszRetBuff)) = 0; + } + if (pdwRetBuffSize) (*pdwRetBuffSize) = dwRetBuffSizeLocal; + + DBFreeVariant(&dbv); + }else { + if (lpszRetBuff && dwRetBuffSize >= sizeof(WORD)) (*((WORD*)lpszRetBuff)) = 0; + if (pdwRetBuffSize) (*pdwRetBuffSize) = 0; + } + return bRet; +} + + +BOOL DB_GetStaticStringW(HANDLE hContact, LPCSTR lpszModule, LPCSTR lpszValueName, LPWSTR lpwszRetBuff, size_t dwRetBuffSize, size_t *pdwRetBuffSize) +{// sizes in wchars + BOOL bRet = FALSE; + size_t dwReadedStringLen; + DBVARIANT dbv = {0}; + DBCONTACTGETSETTING sVal = {0}; + + dbv.type = DBVT_WCHAR; + sVal.pValue = &dbv; + sVal.szModule = lpszModule; + sVal.szSetting = lpszValueName; + if (CallService(MS_DB_CONTACT_GETSETTING_STR, (WPARAM)hContact, (LPARAM)&sVal) == 0) + { + dwReadedStringLen = lstrlenW(dbv.pwszVal); + if (lpwszRetBuff && (dwRetBuffSize>dwReadedStringLen)) + { + memmove(lpwszRetBuff, dbv.pszVal, (dwReadedStringLen*sizeof(WCHAR)));//include null terminated + (*((WCHAR*)(lpwszRetBuff+dwReadedStringLen))) = 0; + bRet = TRUE; + }else { + if (lpwszRetBuff && dwRetBuffSize >= sizeof(WCHAR)) (*((WCHAR*)lpwszRetBuff)) = 0; + } + if (pdwRetBuffSize) (*pdwRetBuffSize) = dwReadedStringLen; + + DBFreeVariant(&dbv); + }else { + if (lpwszRetBuff && dwRetBuffSize >= sizeof(WCHAR)) (*((WCHAR*)lpwszRetBuff)) = 0; + if (pdwRetBuffSize) (*pdwRetBuffSize) = 0; + } + return bRet; +} + +BOOL DB_SetStringExA(HANDLE hContact, LPCSTR lpszModule, LPCSTR lpszValueName, LPCSTR lpszValue, size_t dwValueSize) +{ + BOOL bRet = FALSE; + + if (lpszValue && dwValueSize) { + LPWSTR lpwszValueLocal; + size_t dwValueSizeLocal; + + dwValueSizeLocal = (dwValueSize+MAX_PATH); + lpwszValueLocal = (LPWSTR)mir_calloc((dwValueSizeLocal*sizeof(WCHAR))); + + if (lpwszValueLocal) { + DBCONTACTWRITESETTING cws = {0}; + + cws.szModule = lpszModule; + cws.szSetting = lpszValueName; + cws.value.type = DBVT_WCHAR; + cws.value.pwszVal = (WCHAR*)lpwszValueLocal; + + dwValueSizeLocal = MultiByteToWideChar(MRA_CODE_PAGE, 0, lpszValue, dwValueSize, lpwszValueLocal, dwValueSizeLocal); + lpwszValueLocal[dwValueSizeLocal] = 0; + bRet = (CallService(MS_DB_CONTACT_WRITESETTING, (WPARAM)hContact, (LPARAM)&cws) == 0); + + mir_free(lpwszValueLocal); + } + } + else { + bRet = TRUE; + DBDeleteContactSetting(hContact, lpszModule, lpszValueName); + } + return bRet; +} + +BOOL DB_SetStringExW(HANDLE hContact, LPCSTR lpszModule, LPCSTR lpszValueName, LPCWSTR lpwszValue, size_t dwValueSize) +{ + BOOL bRet = FALSE; + + if (lpwszValue && dwValueSize) { + LPWSTR lpwszValueLocal = (LPWSTR)mir_calloc(((dwValueSize+MAX_PATH)*sizeof(WCHAR))); + + if (lpwszValueLocal) { + DBCONTACTWRITESETTING cws = {0}; + + cws.szModule = lpszModule; + cws.szSetting = lpszValueName; + cws.value.type = DBVT_WCHAR; + cws.value.pwszVal = (WCHAR*)lpwszValueLocal; + memmove(lpwszValueLocal, lpwszValue, (dwValueSize*sizeof(WCHAR))); + bRet = (CallService(MS_DB_CONTACT_WRITESETTING, (WPARAM)hContact, (LPARAM)&cws) == 0); + + mir_free(lpwszValueLocal); + } + } + else { + bRet = TRUE; + DBDeleteContactSetting(hContact, lpszModule, lpszValueName); + } + return bRet; +} + +int DB_WriteContactSettingBlob(HANDLE hContact, LPCSTR lpszModule, LPCSTR lpszValueName, LPVOID lpValue, size_t dwValueSize) +{ + DBCONTACTWRITESETTING cws = {0}; + + cws.szModule = lpszModule; + cws.szSetting = lpszValueName; + cws.value.type = DBVT_BLOB; + cws.value.pbVal = (LPBYTE)lpValue; + cws.value.cpbVal = (WORD)dwValueSize; + return CallService(MS_DB_CONTACT_WRITESETTING, (WPARAM)hContact, (LPARAM)&cws); +} + +BOOL DB_GetContactSettingBlob(HANDLE hContact, LPCSTR lpszModule, LPCSTR lpszValueName, LPVOID lpRet, size_t dwRetBuffSize, size_t *pdwRetBuffSize) +{ + BOOL bRet = FALSE; + DBVARIANT dbv; + DBCONTACTGETSETTING sVal = {0}; + + sVal.pValue = &dbv; + sVal.szModule = lpszModule; + sVal.szSetting = lpszValueName; + if (CallService(MS_DB_CONTACT_GETSETTING, (WPARAM)hContact, (LPARAM)&sVal) == 0) + { + if (dbv.type == DBVT_BLOB) + { + if (dwRetBuffSize >= dbv.cpbVal) + { + memmove(lpRet, dbv.pbVal, dbv.cpbVal); + bRet = TRUE; + } + if (pdwRetBuffSize) (*pdwRetBuffSize) = dbv.cpbVal; + } + DBFreeVariant(&dbv); + } + else { + if (pdwRetBuffSize) (*pdwRetBuffSize) = 0; + bRet = FALSE; + } + return(bRet); +} + +DWORD CMraProto::GetContactFlags(HANDLE hContact) +{ + DWORD dwRet = 0; + + if (IsContactMra(hContact)) + { + CHAR szEMail[MAX_EMAIL_LEN]; + size_t dwEMailSize; + + dwRet = mraGetDword(hContact, "ContactFlags", 0); + dwRet &= ~(CONTACT_FLAG_REMOVED|CONTACT_FLAG_GROUP|CONTACT_FLAG_INVISIBLE|CONTACT_FLAG_VISIBLE|CONTACT_FLAG_IGNORE|CONTACT_FLAG_SHADOW|CONTACT_FLAG_MULTICHAT); + dwRet |= CONTACT_FLAG_UNICODE_NAME; + + if (mraGetStaticStringA(hContact, "e-mail", szEMail, SIZEOF(szEMail), &dwEMailSize)) + { + if (IsEMailChatAgent(szEMail, dwEMailSize)) + { + dwRet |= CONTACT_FLAG_MULTICHAT; + } + } + + if (db_get_b(hContact, "CList", "Hidden", 0)) dwRet |= CONTACT_FLAG_SHADOW; + + switch (mraGetWord(hContact, "ApparentMode", 0)) { + case ID_STATUS_OFFLINE: + dwRet |= CONTACT_FLAG_INVISIBLE; + break; + case ID_STATUS_ONLINE: + dwRet |= CONTACT_FLAG_VISIBLE; + break; + } + + if (CallService(MS_IGNORE_ISIGNORED, (WPARAM)hContact, IGNOREEVENT_MESSAGE)) dwRet |= CONTACT_FLAG_IGNORE; + } + return(dwRet); +} + +DWORD CMraProto::SetContactFlags(HANDLE hContact, DWORD dwContactFlag) +{ + if ( !IsContactMra(hContact)) + return ERROR_INVALID_HANDLE; + + mraSetDword(hContact, "ContactFlags", dwContactFlag); + + if (dwContactFlag&CONTACT_FLAG_SHADOW) + DBWriteContactSettingByte(hContact, "CList", "Hidden", 1); + else + DBDeleteContactSetting(hContact, "CList", "Hidden"); + + switch (dwContactFlag&(CONTACT_FLAG_INVISIBLE|CONTACT_FLAG_VISIBLE)) { + case CONTACT_FLAG_INVISIBLE: + mraSetWord(hContact, "ApparentMode", ID_STATUS_OFFLINE); + break; + case CONTACT_FLAG_VISIBLE: + mraSetWord(hContact, "ApparentMode", ID_STATUS_ONLINE); + break; + default: + mraSetWord(hContact, "ApparentMode", 0); + break; + } + + if (dwContactFlag&CONTACT_FLAG_IGNORE) + CallService(MS_IGNORE_IGNORE, (WPARAM)hContact, IGNOREEVENT_MESSAGE); + else + CallService(MS_IGNORE_UNIGNORE, (WPARAM)hContact, IGNOREEVENT_MESSAGE); + + return 0; +} + +DWORD CMraProto::GetContactBasicInfoW(HANDLE hContact, DWORD *pdwID, DWORD *pdwGroupID, DWORD *pdwContactFlag, DWORD *pdwContactSeverFlags, DWORD *pdwStatus, LPSTR lpszEMail, size_t dwEMailSize, size_t *pdwEMailSize, LPWSTR lpwszNick, size_t dwNickSize, size_t *pdwNickSize, LPSTR lpszPhones, size_t dwPhonesSize, size_t *pdwPhonesSize) +{ + if ( !IsContactMra(hContact)) + return ERROR_INVALID_HANDLE; + + if (pdwID) + *pdwID = mraGetDword(hContact, "ContactID", -1); + if (pdwGroupID) + *pdwGroupID = mraGetDword(hContact, "GroupID", -1); + if (pdwContactSeverFlags) + *pdwContactSeverFlags = mraGetDword(hContact, "ContactSeverFlags", 0); + if (pdwStatus) + *pdwStatus = MraGetContactStatus(hContact); + if (pdwContactFlag) + *pdwContactFlag = GetContactFlags(hContact); + if (lpszEMail && pdwEMailSize) + mraGetStaticStringA(hContact, "e-mail", lpszEMail, dwEMailSize, pdwEMailSize); + if (lpwszNick && pdwNickSize) + DB_GetStaticStringW(hContact, "CList", "MyHandle", lpwszNick, dwNickSize, pdwNickSize); + + if (lpszPhones && pdwPhonesSize) { + char szPhone[MAX_PATH], szValue[MAX_PATH]; + size_t dwPhoneSize, dwCopied = 0; + + for (size_t i = 0; i < 3; i++) { + mir_snprintf(szValue, SIZEOF(szValue), "MyPhone%lu", i); + if ( DB_GetStaticStringA(hContact, "UserInfo", szValue, szPhone, SIZEOF(szPhone), &dwPhoneSize)) { + if (dwCopied) + *((LPBYTE)(lpszPhones+dwCopied++)) = ','; + dwCopied += CopyNumber((lpszPhones+dwCopied), szPhone, dwPhoneSize); + } + } + *pdwPhonesSize = dwCopied; + } + return 0; +} + +DWORD CMraProto::SetContactBasicInfoW(HANDLE hContact, DWORD dwSetInfoFlags, DWORD dwFlags, DWORD dwID, DWORD dwGroupID, DWORD dwContactFlag, DWORD dwContactSeverFlags, DWORD dwStatus, LPSTR lpszEMail, size_t dwEMailSize, LPWSTR lpwszNick, size_t dwNickSize, LPSTR lpszPhones, size_t dwPhonesSize) +{ + if ( !IsContactMra(hContact)) + return ERROR_INVALID_HANDLE; + + // LOCK + if (dwSetInfoFlags & SCBIFSI_LOCK_CHANGES_EVENTS) + mraSetDword(hContact, "HooksLocked", TRUE); + + // поля которые нужны, и изменения которых не отслеживаются + if (dwFlags & SCBIF_ID) + mraSetDword(hContact, "ContactID", dwID); + + if (dwFlags & SCBIF_EMAIL) + if (lpszEMail && dwEMailSize) + mraSetStringExA(hContact, "e-mail", lpszEMail, dwEMailSize); + + // поля изменения которых отслеживаются + if (dwFlags & SCBIF_GROUP_ID) + mraSetDword(hContact, "GroupID", dwGroupID); + + if (dwFlags & SCBIF_NICK) { + if ((dwFlags & SCBIF_FLAG) && ((dwContactFlag&CONTACT_FLAG_UNICODE_NAME) == 0)) + { + if (lpwszNick && dwNickSize) + DB_SetStringExA(hContact, "CList", "MyHandle", (LPSTR)lpwszNick, dwNickSize); + } + else { + if (lpwszNick && dwNickSize) + DB_SetStringExW(hContact, "CList", "MyHandle", lpwszNick, dwNickSize); + } + } + + if (dwFlags & SCBIF_PHONES) { + if (lpszPhones && dwPhonesSize) { + char szPhone[MAX_PATH], szValue[MAX_PATH]; + LPSTR lpszCurPhone, lpszPhoneNext; + size_t i, dwCurPhoneSize; + + i = 0; + lpszCurPhone = lpszPhones; + lpszPhoneNext = lpszPhones; + while (lpszPhoneNext) { + lpszPhoneNext = (LPSTR)MemoryFindByte((lpszCurPhone-lpszPhones), lpszPhones, dwPhonesSize, ','); + if (lpszPhoneNext) + dwCurPhoneSize = lpszPhoneNext - lpszCurPhone; + else + dwCurPhoneSize = (lpszPhones + dwPhonesSize) - lpszCurPhone; + + szPhone[0] = '+'; + memmove((szPhone+1), lpszCurPhone, min(dwCurPhoneSize, (SIZEOF(szPhone)-1))); + mir_snprintf(szValue, SIZEOF(szValue), "MyPhone%lu", i); + DB_SetStringExA(hContact, "UserInfo", szValue, szPhone, (1+dwCurPhoneSize)); + + i++; + lpszCurPhone = (lpszPhoneNext+1); + } + } + } + + if (dwFlags & SCBIF_FLAG) + SetContactFlags(hContact, dwContactFlag); + + if (dwFlags & SCBIF_SERVER_FLAG) + mraSetDword(hContact, "ContactSeverFlags", dwContactSeverFlags); + + if (dwFlags & SCBIF_STATUS) + MraSetContactStatus(hContact, dwStatus); + + SetExtraIcons(hContact); + // UNLOCK + if (dwSetInfoFlags & SCBIFSI_LOCK_CHANGES_EVENTS) + mraSetDword(hContact, "HooksLocked", FALSE); + + return 0; +} + +HANDLE CMraProto::MraHContactFromEmail(LPSTR lpszEMail, size_t dwEMailSize, BOOL bAddIfNeeded, BOOL bTemporary, BOOL *pbAdded) +{ + HANDLE hContact = NULL; + + if (lpszEMail && dwEMailSize) + { + BOOL bFound = FALSE; + CHAR szEMailLocal[MAX_EMAIL_LEN]; + size_t dwEMailLocalSize; + + if (dwEMailSize == -1) dwEMailSize = lstrlenA(lpszEMail); + //check not already on list + for (hContact = db_find_first();hContact != NULL;hContact = db_find_next(hContact)) + { + if (IsContactMra(hContact)) + if (mraGetStaticStringA(hContact, "e-mail", szEMailLocal, SIZEOF(szEMailLocal), &dwEMailLocalSize)) + if (CompareStringA( MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), NORM_IGNORECASE, szEMailLocal, dwEMailLocalSize, lpszEMail, dwEMailSize) == CSTR_EQUAL) + { + if (bTemporary == FALSE) DBDeleteContactSetting(hContact, "CList", "NotOnList"); + bFound = TRUE; + break; + } + } + + if (bFound == FALSE && bAddIfNeeded) + {//not already there: add + if (IsEMailChatAgent(lpszEMail, dwEMailSize)) + { + GCSESSION gcw = {0}; + WCHAR wszEMail[MAX_EMAIL_LEN] = {0}; + + gcw.cbSize = sizeof(GCSESSION); + gcw.iType = GCW_CHATROOM; + gcw.pszModule = m_szModuleName; + gcw.ptszName = wszEMail; + gcw.ptszID = (LPWSTR)wszEMail; + gcw.dwFlags = GC_UNICODE; + MultiByteToWideChar(MRA_CODE_PAGE, 0, lpszEMail, dwEMailSize, wszEMail, SIZEOF(wszEMail)); + + if (CallServiceSync(MS_GC_NEWSESSION, NULL, (LPARAM)&gcw) == 0) + { + BOOL bChatAdded = FALSE; + for (hContact = db_find_first();hContact != NULL;hContact = db_find_next(hContact)) + { + if (IsContactMra(hContact)) + if (mraGetStaticStringA(hContact, "ChatRoomID", szEMailLocal, SIZEOF(szEMailLocal), &dwEMailLocalSize)) + if (CompareStringA( MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), NORM_IGNORECASE, szEMailLocal, dwEMailLocalSize, lpszEMail, dwEMailSize) == CSTR_EQUAL) + { + bChatAdded = TRUE; + break; + } + } + if (bChatAdded == FALSE) hContact = NULL; + } + }else { + hContact = (HANDLE)CallService(MS_DB_CONTACT_ADD, 0, 0); + CallService(MS_PROTO_ADDTOCONTACT, (WPARAM)hContact, (LPARAM)m_szModuleName); + } + + if (hContact) { + if (IsEMailChatAgent(lpszEMail, dwEMailSize)) + SetContactBasicInfoW(hContact, SCBIFSI_LOCK_CHANGES_EVENTS, (SCBIF_ID|SCBIF_GROUP_ID|SCBIF_SERVER_FLAG|SCBIF_STATUS|SCBIF_EMAIL), -1, -1, 0, CONTACT_INTFLAG_NOT_AUTHORIZED, ID_STATUS_ONLINE, lpszEMail, dwEMailSize, NULL, 0, NULL, 0); + else { + if (bTemporary) + DBWriteContactSettingByte(hContact, "CList", "NotOnList", 1); + mraSetStringExA(hContact, "MirVer", MIRVER_UNKNOWN, (sizeof(MIRVER_UNKNOWN)-1)); + SetContactBasicInfoW(hContact, SCBIFSI_LOCK_CHANGES_EVENTS, (SCBIF_ID|SCBIF_GROUP_ID|SCBIF_SERVER_FLAG|SCBIF_STATUS|SCBIF_EMAIL), -1, -1, 0, CONTACT_INTFLAG_NOT_AUTHORIZED, ID_STATUS_OFFLINE, lpszEMail, dwEMailSize, NULL, 0, NULL, 0); + } + } + } + + if (pbAdded) (*pbAdded) = (bFound == FALSE && bAddIfNeeded && hContact); + } + return hContact; +} + +BOOL CMraProto::MraUpdateContactInfo(HANDLE hContact) +{ + BOOL bRet = FALSE; + + if (m_bLoggedIn && hContact) + if (IsContactMra(hContact)) { + CHAR szEMail[MAX_EMAIL_LEN]; + size_t dwEMailSize; + + if (mraGetStaticStringA(hContact, "e-mail", szEMail, SIZEOF(szEMail), &dwEMailSize)) { + MraAvatarsQueueGetAvatarSimple(hAvatarsQueueHandle, GAIF_FORCE, hContact, 0); + + if (MraWPRequestByEMail(hContact, ACKTYPE_GETINFO, szEMail, dwEMailSize)) + bRet = TRUE; + } + } + return bRet; +} + +DWORD CMraProto::MraContactCapabilitiesGet(HANDLE hContact) +{ + return mraGetDword(hContact, DBSETTING_CAPABILITIES, 0); +} + +void CMraProto::MraContactCapabilitiesSet(HANDLE hContact, DWORD dwFutureFlags) +{ + mraSetDword(hContact, DBSETTING_CAPABILITIES, dwFutureFlags); +} + +DWORD CMraProto::MraGetContactStatus(HANDLE hContact) +{ + return mraGetWord(hContact, "Status", ID_STATUS_OFFLINE); +} + +DWORD CMraProto::MraSetContactStatus(HANDLE hContact, DWORD dwNewStatus) +{ + DWORD dwOldStatus = MraGetContactStatus(hContact); + + if (dwNewStatus != dwOldStatus) + { + BOOL bChatAgent; + + bChatAgent = IsContactChatAgent(hContact); + + if (dwNewStatus == ID_STATUS_OFFLINE) + { + if (hContact) + { + mraSetByte(hContact, DBSETTING_XSTATUSID, MRA_MIR_XSTATUS_NONE); + mraDelValue(hContact, DBSETTING_XSTATUSNAME); + mraDelValue(hContact, DBSETTING_XSTATUSMSG); + mraDelValue(hContact, DBSETTING_BLOGSTATUSTIME); + mraDelValue(hContact, DBSETTING_BLOGSTATUSID); + mraDelValue(hContact, DBSETTING_BLOGSTATUS); + mraDelValue(hContact, DBSETTING_BLOGSTATUSMUSIC); + MraContactCapabilitiesSet(hContact, 0); + if (bChatAgent) MraChatSessionDestroy(hContact); + } + mraSetDword(hContact, "LogonTS", 0); + mraDelValue(hContact, "IP"); + mraDelValue(hContact, "RealIP"); + }else { + if (dwOldStatus == ID_STATUS_OFFLINE) + { + DWORD dwTime = (DWORD)_time32(NULL); + + mraSetDword(hContact, "LogonTS", dwTime); + mraSetDword(hContact, "OldLogonTS", dwTime); + + if (bChatAgent) MraChatSessionNew(hContact); + } + MraAvatarsQueueGetAvatarSimple(hAvatarsQueueHandle, 0, hContact, 0); + } + + mraSetWord(hContact, "Status", (WORD)dwNewStatus); + } + return(dwOldStatus); +} + +void CMraProto::MraUpdateEmailStatus(LPSTR lpszFrom, size_t dwFromSize, LPSTR lpszSubject, size_t dwSubjectSize, DWORD dwDate, DWORD dwUIDL) +{ + BOOL bTrayIconNewMailNotify; + WCHAR szStatusText[MAX_SECONDLINE]; + + bTrayIconNewMailNotify = mraGetByte(NULL, "TrayIconNewMailNotify", MRA_DEFAULT_TRAYICON_NEW_MAIL_NOTIFY); + + if (dwEmailMessagesUnread) + { + LPSTR lpszEMail; + size_t dwEMailSize; + HANDLE hContact = NULL; + WCHAR szMailBoxStatus[MAX_SECONDLINE]; + + mir_sntprintf(szMailBoxStatus, SIZEOF(szMailBoxStatus), TranslateW(L"Unread mail is available: %lu/%lu messages"), dwEmailMessagesUnread, dwEmailMessagesTotal); + + if ((lpszFrom && dwFromSize) || (lpszSubject && dwSubjectSize)) + { + WCHAR szFrom[MAX_PATH] = {0}, szSubject[MAX_PATH] = {0}; + + if (GetEMailFromString(lpszFrom, dwFromSize, &lpszEMail, &dwEMailSize)) + { + hContact = MraHContactFromEmail(lpszEMail, dwEMailSize, FALSE, TRUE, NULL); + } + + dwFromSize = MultiByteToWideChar(MRA_CODE_PAGE, 0, lpszFrom, dwFromSize, szFrom, SIZEOF(szFrom)); + szFrom[dwFromSize] = 0; + + dwSubjectSize = MultiByteToWideChar(MRA_CODE_PAGE, 0, lpszSubject, dwSubjectSize, szSubject, SIZEOF(szSubject)); + szSubject[dwSubjectSize] = 0; + + mir_sntprintf(szStatusText, SIZEOF(szStatusText), TranslateW(L"From: %s\r\nSubject: %s\r\n%s"), szFrom, szSubject, szMailBoxStatus); + }else { + lstrcpynW(szStatusText, szMailBoxStatus, SIZEOF(szStatusText)); + } + + if (bTrayIconNewMailNotify) { + char szServiceFunction[MAX_PATH], *pszServiceFunctionName; + CLISTEVENT cle = {0}; + + cle.cbSize = sizeof(cle); + //cle.hContact; + //cle.hDbEvent; + cle.lpszProtocol = m_szModuleName; + cle.hIcon = IconLibGetIcon( gdiMenuItems[0].hIconHandle ); + cle.flags = (CLEF_UNICODE|CLEF_PROTOCOLGLOBAL); + cle.pszService = ""; + cle.ptszTooltip = szStatusText; + + if (mraGetByte(NULL, "TrayIconNewMailClkToInbox", MRA_DEFAULT_TRAYICON_NEW_MAIL_CLK_TO_INBOX)) + { + strncpy(szServiceFunction, m_szModuleName, MAX_PATH); + pszServiceFunctionName = szServiceFunction+strlen(m_szModuleName); + memmove(pszServiceFunctionName, MRA_GOTO_INBOX, sizeof(MRA_GOTO_INBOX)); + cle.pszService = szServiceFunction; + } + CallService(MS_CLIST_ADDEVENT, 0, (LPARAM)&cle); + } + + SkinPlaySound(szNewMailSound); + if (hContact) + {// update user info + MraUpdateContactInfo(hContact); + MraPopupShowFromContactW(hContact, MRA_POPUP_TYPE_EMAIL_STATUS, (MRA_POPUP_ALLOW_ENTER), szStatusText); + }else { + MraPopupShowFromAgentW(MRA_POPUP_TYPE_EMAIL_STATUS, (MRA_POPUP_ALLOW_ENTER), szStatusText); + } + }else { + if (mraGetByte(NULL, "IncrementalNewMailNotify", MRA_DEFAULT_INC_NEW_MAIL_NOTIFY)) + { + if (bTrayIconNewMailNotify) CallService(MS_CLIST_REMOVEEVENT, 0, (LPARAM)m_szModuleName); + PUDeletePopUp(hWndEMailPopupStatus); + hWndEMailPopupStatus = NULL; + }else { + mir_sntprintf(szStatusText, SIZEOF(szStatusText), TranslateW(L"No unread mail is available\r\nTotal messages: %lu"), dwEmailMessagesTotal); + MraPopupShowFromAgentW(MRA_POPUP_TYPE_EMAIL_STATUS, (MRA_POPUP_ALLOW_ENTER), szStatusText); + } + } +} + + +BOOL IsUnicodeEnv() +{// Are we running under unicode Miranda core ? + return TRUE; +} + + +BOOL IsHTTPSProxyUsed(HANDLE hNetlibUser) +{ + BOOL bRet = FALSE; + NETLIBUSERSETTINGS nlus = {0}; + + nlus.cbSize = sizeof(nlus); + if (CallService(MS_NETLIB_GETUSERSETTINGS, (WPARAM)hNetlibUser, (LPARAM)&nlus)) + { + if (nlus.useProxy && nlus.proxyType == PROXYTYPE_HTTPS) bRet = TRUE; + } + return(bRet); +} + +// определяет принадлежность контакта данной копии плагина +BOOL CMraProto::IsContactMra(HANDLE hContact) +{ + return(CallService(MS_PROTO_ISPROTOONCONTACT, (WPARAM)hContact, (LPARAM)m_szModuleName)); +} + +// определяется является ли контакт контактом MRA протокола, не зависимо от того какому плагину он принадлежит +BOOL IsContactMraProto(HANDLE hContact) +{ + BOOL bRet = FALSE; + LPSTR lpszProto = (LPSTR)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + + if (lpszProto) + { + WCHAR szBuff[MAX_PATH]; + + if (DB_GetStaticStringW(hContact, lpszProto, "AvatarLastCheckTime", szBuff, SIZEOF(szBuff), NULL)) + if (DB_GetStaticStringW(hContact, lpszProto, "AvatarLastModifiedTime", szBuff, SIZEOF(szBuff), NULL)) + { + bRet = TRUE; + } + } + return(bRet); +} + +BOOL CMraProto::IsEMailMy(LPSTR lpszEMail, size_t dwEMailSize) +{ + BOOL bRet = FALSE; + + if (lpszEMail) + { + CHAR szEMailMy[MAX_EMAIL_LEN]; + size_t dwEMailMySize; + + if (mraGetStaticStringA(NULL, "e-mail", szEMailMy, SIZEOF(szEMailMy), &dwEMailMySize)) + { + if (dwEMailSize == 0) dwEMailSize = lstrlenA(lpszEMail); + + if (dwEMailMySize == dwEMailSize) + if (CompareStringA( MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), NORM_IGNORECASE, lpszEMail, dwEMailSize, szEMailMy, dwEMailMySize) == CSTR_EQUAL) + { + bRet = TRUE; + } + } + } +return(bRet); +} + + +BOOL CMraProto::IsEMailChatAgent(LPSTR lpszEMail, size_t dwEMailSize) +{ + BOOL bRet = FALSE; + + if (lpszEMail) + { + if (dwEMailSize == 0) dwEMailSize = lstrlenA(lpszEMail); + if ((sizeof(MAILRU_CHAT_CONF_DOMAIN)-1)'))) + { + if (plpszEMail) (*plpszEMail) = lpszEMailStart; + if (pdwEMailSize) (*pdwEMailSize) = (lpszEMailEnd-lpszEMailStart); + + bRet = TRUE; + } + } + } + + if (bRet == FALSE) + { + if (plpszEMail) (*plpszEMail) = NULL; + if (pdwEMailSize) (*pdwEMailSize) = 0; + } + +return(bRet); +} + + +DWORD GetContactEMailCountParam(HANDLE hContact, BOOL bMRAOnly, LPSTR lpszModule, LPSTR lpszValueName) +{ + DWORD dwRet = 0; + CHAR szBuff[MAX_PATH], szEMail[MAX_EMAIL_LEN]; + size_t i, dwEMailSize; + + if (DB_GetStaticStringA(hContact, lpszModule, lpszValueName, szEMail, SIZEOF(szEMail), &dwEMailSize)) + { + if (bMRAOnly == FALSE || IsEMailMR(szEMail, dwEMailSize)) dwRet++; + } + + for (i = 0;TRUE;i++) + { + mir_snprintf(szBuff, SIZEOF(szBuff), "%s%lu", lpszValueName, i); + if (DB_GetStaticStringA(hContact, lpszModule, szBuff, szEMail, SIZEOF(szEMail), &dwEMailSize)) + { + if (bMRAOnly == FALSE || IsEMailMR(szEMail, dwEMailSize)) dwRet++; + }else { + if (i>EMAILS_MIN_COUNT) break; + } + } +return(dwRet); +} + + +DWORD CMraProto::GetContactEMailCount(HANDLE hContact, BOOL bMRAOnly) +{ + DWORD dwRet = 0; + LPSTR lpszProto; + + if (hContact) + lpszProto = (LPSTR)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + else + lpszProto = m_szModuleName; + + dwRet += GetContactEMailCountParam(hContact, bMRAOnly, lpszProto, "e-mail"); + dwRet += GetContactEMailCountParam(hContact, bMRAOnly, "UserInfo", "e-mail"); + dwRet += GetContactEMailCountParam(hContact, bMRAOnly, "UserInfo", "Mye-mail"); + dwRet += GetContactEMailCountParam(hContact, bMRAOnly, "UserInfo", "Companye-mail"); + dwRet += GetContactEMailCountParam(hContact, bMRAOnly, "UserInfo", "MyCompanye-mail"); + +return(dwRet); +} + + + +BOOL GetContactFirstEMailParam(HANDLE hContact, BOOL bMRAOnly, LPSTR lpszModule, LPSTR lpszValueName, LPSTR lpszRetBuff, size_t dwRetBuffSize, size_t *pdwRetBuffSize) +{ + BOOL bRet = FALSE; + CHAR szBuff[MAX_PATH], szEMail[MAX_EMAIL_LEN]; + size_t i, dwEMailSize; + + if (DB_GetStaticStringA(hContact, lpszModule, lpszValueName, szEMail, SIZEOF(szEMail), &dwEMailSize)) + { + if (bMRAOnly == FALSE || IsEMailMR(szEMail, dwEMailSize)) + { + lstrcpynA(lpszRetBuff, szEMail, dwRetBuffSize); + if (pdwRetBuffSize) (*pdwRetBuffSize) = dwEMailSize; + bRet = TRUE; + } + } + + for (i = 0;bRet == FALSE;i++) + { + mir_snprintf(szBuff, SIZEOF(szBuff), "%s%lu", lpszValueName, i); + if (DB_GetStaticStringA(hContact, lpszModule, szBuff, szEMail, SIZEOF(szEMail), &dwEMailSize)) + { + if (bMRAOnly == FALSE || IsEMailMR(szEMail, dwEMailSize)) + { + lstrcpynA(lpszRetBuff, szEMail, dwRetBuffSize); + if (pdwRetBuffSize) (*pdwRetBuffSize) = dwEMailSize; + bRet = TRUE; + break; + } + }else { + if (i>EMAILS_MIN_COUNT) break; + } + } +return(bRet); +} + + +BOOL CMraProto::GetContactFirstEMail(HANDLE hContact, BOOL bMRAOnly, LPSTR lpszRetBuff, size_t dwRetBuffSize, size_t *pdwRetBuffSize) +{ + BOOL bRet = FALSE; + LPSTR lpszProto; + + if (hContact) + lpszProto = (LPSTR)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + else + lpszProto = m_szModuleName; + + bRet = GetContactFirstEMailParam(hContact, bMRAOnly, lpszProto, "e-mail", lpszRetBuff, dwRetBuffSize, pdwRetBuffSize); + if (bRet == FALSE) bRet = GetContactFirstEMailParam(hContact, bMRAOnly, "UserInfo", "e-mail", lpszRetBuff, dwRetBuffSize, pdwRetBuffSize); + if (bRet == FALSE) bRet = GetContactFirstEMailParam(hContact, bMRAOnly, "UserInfo", "Mye-mail", lpszRetBuff, dwRetBuffSize, pdwRetBuffSize); + if (bRet == FALSE) bRet = GetContactFirstEMailParam(hContact, bMRAOnly, "UserInfo", "Companye-mail", lpszRetBuff, dwRetBuffSize, pdwRetBuffSize); + if (bRet == FALSE) bRet = GetContactFirstEMailParam(hContact, bMRAOnly, "UserInfo", "MyCompanye-mail", lpszRetBuff, dwRetBuffSize, pdwRetBuffSize); + + return bRet; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void CMraProto::ShowFormattedErrorMessage(LPWSTR lpwszErrText, DWORD dwErrorCode) +{ + WCHAR szErrorText[2048], szErrDescription[1024]; + size_t dwErrDescriptionSize; + + if (dwErrorCode == NO_ERROR) + mir_sntprintf(szErrorText, SIZEOF(szErrorText), L"%s", TranslateW(lpwszErrText)); + else { + dwErrDescriptionSize = (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErrorCode, 0, szErrDescription, (SIZEOF(szErrDescription)-sizeof(WCHAR)), NULL)-2); + szErrDescription[dwErrDescriptionSize] = 0; + mir_sntprintf(szErrorText, SIZEOF(szErrorText), L"%s %lu: %s", TranslateW(lpwszErrText), dwErrorCode, szErrDescription); + } + MraPopupShowFromAgentW(MRA_POPUP_TYPE_ERROR, 0, szErrorText); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static void FakeThread(void* param) +{ + Sleep(100); + CallService(MS_PROTO_BROADCASTACK, 0, (LPARAM)param); + mir_free(param); +} + +DWORD CMraProto::ProtoBroadcastAckAsync(HANDLE hContact, int type, int hResult, HANDLE hProcess, LPARAM lParam, size_t paramSize) +{ + ACKDATA* ack = (ACKDATA*)mir_calloc(sizeof(ACKDATA) + paramSize); + ack->cbSize = sizeof(ACKDATA); + ack->szModule = m_szModuleName; ack->hContact = hContact; + ack->type = type; ack->result = hResult; + ack->hProcess = hProcess; ack->lParam = lParam; + if (paramSize) + memcpy(ack+1, (void*)lParam, paramSize); + mir_forkthread(FakeThread, ack); + return 0; +} + +DWORD CMraProto::CreateBlobFromContact(HANDLE hContact, LPWSTR lpwszRequestReason, size_t dwRequestReasonSize, LPBYTE lpbBuff, size_t dwBuffSize, size_t *pdwBuffSizeRet) +{ + DWORD dwRetErrorCode; + size_t dwBuffSizeRet = ((sizeof(DWORD)*2)+dwRequestReasonSize+5), dwSize; + + if (dwBuffSize >= dwBuffSizeRet) { + PBYTE pCurBlob = lpbBuff; + + *(DWORD*)pCurBlob = 0; pCurBlob += sizeof(DWORD); + *(DWORD*)pCurBlob = (DWORD)hContact; pCurBlob += sizeof(DWORD); + + mraGetStaticStringA(hContact, "Nick", (LPSTR)pCurBlob, (dwBuffSize-(pCurBlob-lpbBuff)), &dwSize); + *(pCurBlob+dwSize) = 0; + pCurBlob += (dwSize+1); + + mraGetStaticStringA(hContact, "FirstName", (LPSTR)pCurBlob, (dwBuffSize-(pCurBlob-lpbBuff)), &dwSize); + *(pCurBlob+dwSize) = 0; + pCurBlob += (dwSize+1); + + mraGetStaticStringA(hContact, "LastName", (LPSTR)pCurBlob, (dwBuffSize-(pCurBlob-lpbBuff)), &dwSize); + *(pCurBlob+dwSize) = 0; + pCurBlob += (dwSize+1); + + mraGetStaticStringA(hContact, "e-mail", (LPSTR)pCurBlob, (dwBuffSize-(pCurBlob-lpbBuff)), &dwSize); + *(pCurBlob+dwSize) = 0; + pCurBlob += (dwSize+1); + + dwSize = WideCharToMultiByte(MRA_CODE_PAGE, 0, lpwszRequestReason, dwRequestReasonSize, (LPSTR)pCurBlob, (dwBuffSize-(pCurBlob-lpbBuff)), NULL, NULL); + *(pCurBlob+dwSize) = 0; + pCurBlob += (dwSize+1); + + dwBuffSizeRet = (pCurBlob-lpbBuff); + dwRetErrorCode = NO_ERROR; + } + else dwRetErrorCode = ERROR_INSUFFICIENT_BUFFER; + + if (pdwBuffSizeRet) + *pdwBuffSizeRet = dwBuffSizeRet; + return dwRetErrorCode; +} + +void CMraProto::CListShowMenuItem(HANDLE hMenuItem, BOOL bShow) +{ + CLISTMENUITEM mi = {0}; + + mi.cbSize = sizeof(mi); + mi.flags = CMIM_FLAGS; + if (bShow == FALSE) mi.flags |= CMIF_HIDDEN; + + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuItem, (LPARAM)&mi); +} + +int ExtraSetIcon(HANDLE hExtraIcon, HANDLE hContact, HANDLE hImage, int iColumnType) +{ + if (hImage == NULL) + hImage = INVALID_HANDLE_VALUE; + + if (hExtraIcon) + return ExtraIcon_SetIcon(hExtraIcon, hContact, hImage); + + IconExtraColumn iec; + iec.cbSize = sizeof(iec); + iec.ColumnType = iColumnType; + iec.hImage = hImage; + return CallService(MS_CLIST_EXTRA_SET_ICON, (WPARAM)hContact, (LPARAM)&iec); +} + +size_t CopyNumber(LPCVOID lpcOutBuff, LPCVOID lpcBuff, size_t dwLen) +{ + BYTE btChar; + LPBYTE lpbOutBuff = (LPBYTE)lpcOutBuff, lpbInBuff = (LPBYTE)lpcBuff; + + for (size_t i = 0; i < dwLen; i++) { + btChar = (*lpbInBuff++); + if (btChar >= '0' && btChar <= '9') (*lpbOutBuff++) = btChar; + } + *lpbOutBuff = 0; + + return lpbOutBuff-(LPBYTE)lpcOutBuff; +} + +void EnableControlsArray(HWND hWndDlg, WORD *pwControlsList, size_t dwControlsListCount, BOOL bEnabled) +{ + for (size_t i = 0; i < dwControlsListCount; i++) + EnableWindow(GetDlgItem(hWndDlg, pwControlsList[i]), bEnabled); +} + +LRESULT CALLBACK MessageEditSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + LRESULT lrRet = 0; + WNDPROC OldMessageEditProc = (WNDPROC)GetWindowLongPtr(hwnd, GWLP_USERDATA); + + if (msg == WM_CHAR) + if (GetKeyState(VK_CONTROL) & 0x8000) { + if (wParam == '\n') { + PostMessage(GetParent(hwnd), WM_COMMAND, IDOK, 0); + return 0; + } + if (wParam == 1) { // ctrl-a + SendMessage(hwnd, EM_SETSEL, 0, -1); + return 0; + } + if (wParam == 23) { // ctrl-w + SendMessage(GetParent(hwnd), WM_CLOSE, 0, 0); + return 0; + } + } + + if (OldMessageEditProc) + lrRet = CallWindowProc(OldMessageEditProc, hwnd, msg, wParam, lParam); + + return lrRet; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +INT_PTR CALLBACK SetXStatusDlgProc(HWND hWndDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + INT_PTR iRet = FALSE; + SetXStatusData *dat = (SetXStatusData*)GetWindowLongPtr(hWndDlg, GWLP_USERDATA); + + switch (message) { + case WM_INITDIALOG:// set our xStatus + TranslateDialogDefault(hWndDlg); + + dat = (SetXStatusData*)lParam; + if (dat) { + char szValueName[MAX_PATH]; + HWND hWndEdit; + WCHAR szBuff[STATUS_TITLE_MAX+STATUS_DESC_MAX]; + WNDPROC OldMessageEditProc; + + dat->hDlgIcon = IconLibGetIcon(dat->ppro->hXStatusAdvancedStatusIcons[dat->dwXStatus]); + dat->dwCountdown = 5; + + hWndEdit = GetDlgItem(hWndDlg, IDC_XTITLE); + OldMessageEditProc = (WNDPROC)SetWindowLongPtr(hWndEdit, GWLP_WNDPROC, (LONG_PTR)MessageEditSubclassProc); + SetWindowLongPtr(hWndEdit, GWLP_USERDATA, (LONG_PTR)OldMessageEditProc); + + hWndEdit = GetDlgItem(hWndDlg, IDC_XMSG); + OldMessageEditProc = (WNDPROC)SetWindowLongPtr(hWndEdit, GWLP_WNDPROC, (LONG_PTR)MessageEditSubclassProc); + SetWindowLongPtr(hWndEdit, GWLP_USERDATA, (LONG_PTR)OldMessageEditProc); + + SetWindowLongPtr(hWndDlg, GWLP_USERDATA, (LONG_PTR)dat); + SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_XTITLE, EM_LIMITTEXT, STATUS_TITLE_MAX, 0); + SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_XMSG, EM_LIMITTEXT, STATUS_DESC_MAX, 0); + SendMessage(hWndDlg, WM_SETICON, ICON_BIG, (LPARAM)dat->hDlgIcon); + SendMessage(hWndDlg, WM_SETTEXT, 0, (LPARAM)TranslateW(lpcszXStatusNameDef[dat->dwXStatus])); + + mir_snprintf(szValueName, SIZEOF(szValueName), "XStatus%ldName", dat->dwXStatus); + if (dat->ppro->mraGetStaticStringW(NULL, szValueName, szBuff, (STATUS_TITLE_MAX+1), NULL)) + SET_DLG_ITEM_TEXT(hWndDlg, IDC_XTITLE, szBuff); // custom xstatus name + else // default xstatus name + SET_DLG_ITEM_TEXT(hWndDlg, IDC_XTITLE, TranslateW(lpcszXStatusNameDef[dat->dwXStatus])); + + mir_snprintf(szValueName, SIZEOF(szValueName), "XStatus%ldMsg", dat->dwXStatus); + if (dat->ppro->mraGetStaticStringW(NULL, szValueName, szBuff, (STATUS_DESC_MAX+1), NULL)) + SET_DLG_ITEM_TEXT(hWndDlg, IDC_XMSG, szBuff); // custom xstatus description + else // default xstatus description + SET_DLG_ITEM_TEXT(hWndDlg, IDC_XMSG, L""); + + SendMessage(hWndDlg, WM_TIMER, 0, 0); + SetTimer(hWndDlg, 1, 1000, 0); + iRet = TRUE; + } + break; + + case WM_TIMER: + if (dat->dwCountdown != -1) { + WCHAR szBuff[MAX_PATH]; + mir_sntprintf(szBuff, SIZEOF(szBuff), L"%s %ld", TranslateW(L"Closing in"), dat->dwCountdown); + SET_DLG_ITEM_TEXT(hWndDlg, IDOK, szBuff); + dat->dwCountdown--; + break; + } + + case WM_CLOSE: + DestroyWindow(hWndDlg); + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDOK: + DestroyWindow(hWndDlg); + break; + case IDC_XTITLE: + case IDC_XMSG: + KillTimer(hWndDlg, 1); + SET_DLG_ITEM_TEXTW(hWndDlg, IDOK, TranslateW(L"OK")); + break; + } + break; + + case WM_DESTROY: + if (dat) { // set our xStatus + char szValueName[MAX_PATH]; + HWND hWndEdit; + WCHAR szBuff[STATUS_TITLE_MAX+STATUS_DESC_MAX]; + size_t dwBuffSize; + WNDPROC OldMessageEditProc; + CLISTMENUITEM mi = {0}; + + SetWindowLongPtr(hWndDlg, GWLP_USERDATA, (LONG_PTR)0); + + hWndEdit = GetDlgItem(hWndDlg, IDC_XTITLE); + OldMessageEditProc = (WNDPROC)GetWindowLongPtr(hWndEdit, GWLP_USERDATA); + SetWindowLongPtr(hWndEdit, GWLP_WNDPROC, (LONG_PTR)OldMessageEditProc); + SetWindowLongPtr(hWndEdit, GWLP_USERDATA, (LONG_PTR)0); + + hWndEdit = GetDlgItem(hWndDlg, IDC_XMSG); + OldMessageEditProc = (WNDPROC)GetWindowLongPtr(hWndEdit, GWLP_USERDATA); + SetWindowLongPtr(hWndEdit, GWLP_WNDPROC, (LONG_PTR)OldMessageEditProc); + SetWindowLongPtr(hWndEdit, GWLP_USERDATA, (LONG_PTR)0); + + dwBuffSize = GET_DLG_ITEM_TEXT(hWndDlg, IDC_XMSG, szBuff, (STATUS_DESC_MAX+1)); + mir_snprintf(szValueName, SIZEOF(szValueName), "XStatus%ldMsg", dat->dwXStatus); + dat->ppro->mraSetStringExW(NULL, szValueName, szBuff, dwBuffSize); + dat->ppro->mraSetStringExW(NULL, DBSETTING_XSTATUSMSG, szBuff, dwBuffSize); + + dwBuffSize = GET_DLG_ITEM_TEXT(hWndDlg, IDC_XTITLE, szBuff, (STATUS_TITLE_MAX+1)); + if (dwBuffSize == 0) { // user delete all text + lstrcpynW(szBuff, TranslateW(lpcszXStatusNameDef[dat->dwXStatus]), (STATUS_TITLE_MAX+1)); + dwBuffSize = lstrlenW(szBuff); + } + mir_snprintf(szValueName, SIZEOF(szValueName), "XStatus%dName", dat->dwXStatus); + dat->ppro->mraSetStringExW(NULL, szValueName, szBuff, dwBuffSize); + dat->ppro->mraSetStringExW(NULL, DBSETTING_XSTATUSNAME, szBuff, dwBuffSize); + + mi.cbSize = sizeof(mi); + mi.flags = (CMIM_NAME|CMIF_UNICODE); + mi.ptszName = szBuff; + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)dat->ppro->hXStatusMenuItems[dat->dwXStatus], (LPARAM)&mi); + + dat->ppro->MraSetXStatusInternal(dat->dwXStatus); + + mir_free(dat); + } + EndDialog(hWndDlg, NO_ERROR); + break; + } + return iRet; +} + +BOOL CMraProto::MraRequestXStatusDetails(DWORD dwXStatus) +{ + if ( IsXStatusValid(dwXStatus)) { + SetXStatusData *dat = (SetXStatusData*)mir_calloc(sizeof(SetXStatusData)); + dat->dwXStatus = dwXStatus; + dat->ppro = this; + return DialogBoxParam(masMraSettings.hInstance, MAKEINTRESOURCE(IDD_SETXSTATUS), NULL, SetXStatusDlgProc, (LPARAM)dat) != -1; + } + + return FALSE; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +INT_PTR CALLBACK SendReplyBlogStatusDlgProc(HWND hWndDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + INT_PTR iRet = FALSE; + SetBlogStatusData *dat = (SetBlogStatusData*)GetWindowLongPtr(hWndDlg, GWLP_USERDATA); + + switch (message) { + case WM_INITDIALOG:// set our xStatus + TranslateDialogDefault(hWndDlg); + + dat = (SetBlogStatusData*)lParam; + if (dat) { + WCHAR szBuff[MICBLOG_STATUS_MAX]; + SYSTEMTIME stBlogStatusTime = {0}; + + SetWindowLongPtr(hWndDlg, GWLP_USERDATA, (LONG_PTR)dat); + + HWND hWndEdit = GetDlgItem(hWndDlg, IDC_MSG_TO_SEND); + WNDPROC OldMessageEditProc = (WNDPROC)SetWindowLongPtr(hWndEdit, GWLP_WNDPROC, (LONG_PTR)MessageEditSubclassProc); + SetWindowLongPtr(hWndEdit, GWLP_USERDATA, (LONG_PTR)OldMessageEditProc); + SendMessage(hWndEdit, EM_LIMITTEXT, MICBLOG_STATUS_MAX, 0); + + SendMessage(hWndDlg, WM_SETICON, ICON_BIG, (LPARAM)IconLibGetIcon(gdiMenuItems[5].hIconHandle)); + + // blog status message + if (dat->ppro->mraGetStaticStringW(dat->hContact, DBSETTING_BLOGSTATUS, szBuff, SIZEOF(szBuff), NULL)) + SET_DLG_ITEM_TEXT(hWndDlg, IDC_USER_BLOG_STATUS_MSG, szBuff); + + // reply to some user blog + if (dat->hContact) { + mir_sntprintf(szBuff, SIZEOF(szBuff), TranslateW(L"Reply to %s blog status"), GetContactNameW(dat->hContact)); + SendMessage(hWndDlg, WM_SETTEXT, 0, (LPARAM)szBuff); + } + else SendMessage(hWndDlg, WM_SETTEXT, 0, (LPARAM)TranslateW(L"Set my blog status")); + + DWORD dwTime = dat->ppro->mraGetDword(dat->hContact, DBSETTING_BLOGSTATUSTIME, 0); + if (dwTime && MakeLocalSystemTimeFromTime32(dwTime, &stBlogStatusTime)) + mir_sntprintf(szBuff, SIZEOF(szBuff), L"%s: %04ld.%02ld.%02ld %02ld:%02ld", TranslateW(L"Writed"), stBlogStatusTime.wYear, stBlogStatusTime.wMonth, stBlogStatusTime.wDay, stBlogStatusTime.wHour, stBlogStatusTime.wMinute); + else + szBuff[0] = 0; + + SET_DLG_ITEM_TEXT(hWndDlg, IDC_STATIC_WRITED_TIME, szBuff); + EnableWindow(GetDlgItem(hWndDlg, IDC_CHK_NOTIFY), (dat->hContact == NULL)); + iRet = TRUE; + } + break; + + case WM_CLOSE: + DestroyWindow(hWndDlg); + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDOK: + { + DWORD dwFlags; + WCHAR szBuff[MICBLOG_STATUS_MAX]; + size_t dwBuffSize; + DWORDLONG dwBlogStatusID; + + dwBuffSize = GET_DLG_ITEM_TEXT(hWndDlg, IDC_MSG_TO_SEND, szBuff, SIZEOF(szBuff)); + if (dat->hContact) { + dwFlags = (MRIM_BLOG_STATUS_REPLY|MRIM_BLOG_STATUS_NOTIFY); + dat->ppro->mraGetContactSettingBlob(dat->hContact, DBSETTING_BLOGSTATUSID, &dwBlogStatusID, sizeof(DWORDLONG), NULL); + } + else { + dwFlags = MRIM_BLOG_STATUS_UPDATE; + if (IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_CHK_NOTIFY)) dwFlags |= MRIM_BLOG_STATUS_NOTIFY; + dwBlogStatusID = 0; + } + dat->ppro->MraChangeUserBlogStatus(dwFlags, szBuff, dwBuffSize, dwBlogStatusID); + } + case IDCANCEL: + DestroyWindow(hWndDlg); + break; + + case IDC_MSG_TO_SEND: + if (HIWORD(wParam) == EN_CHANGE) { + WCHAR wszBuff[MAX_PATH]; + size_t dwMessageSize = GET_DLG_ITEM_TEXT_LENGTH(hWndDlg, IDC_MSG_TO_SEND); + + EnableWindow(GetDlgItem(hWndDlg, IDOK), dwMessageSize); + mir_sntprintf(wszBuff, SIZEOF(wszBuff), L"%d/%d", dwMessageSize, MICBLOG_STATUS_MAX); + SET_DLG_ITEM_TEXTW(hWndDlg, IDC_STATIC_CHARS_COUNTER, wszBuff); + } + break; + } + break; + + case WM_DESTROY: + if (dat) { + HWND hWndEdit; + WNDPROC OldMessageEditProc; + + SetWindowLongPtr(hWndDlg, GWLP_USERDATA, (LONG_PTR)0); + + hWndEdit = GetDlgItem(hWndDlg, IDC_MSG_TO_SEND); + OldMessageEditProc = (WNDPROC)GetWindowLongPtr(hWndEdit, GWLP_USERDATA); + SetWindowLongPtr(hWndEdit, GWLP_WNDPROC, (LONG_PTR)OldMessageEditProc); + SetWindowLongPtr(hWndEdit, GWLP_USERDATA, (LONG_PTR)0); + mir_free(dat); + } + EndDialog(hWndDlg, NO_ERROR); + break; + } + return iRet; +} + +BOOL CMraProto::MraSendReplyBlogStatus(HANDLE hContact) +{ + SetBlogStatusData* dat = (SetBlogStatusData*)mir_calloc( sizeof(SetBlogStatusData)); + dat->ppro = this; + dat->hContact = hContact; + return CreateDialogParam(masMraSettings.hInstance, MAKEINTRESOURCE(IDD_MINIBLOG), NULL, SendReplyBlogStatusDlgProc, (LPARAM)dat) != NULL; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +DWORD GetYears(CONST PSYSTEMTIME pcstSystemTime) +{ + DWORD dwRet = 0; + + if (pcstSystemTime) { + SYSTEMTIME stTime; + GetLocalTime(&stTime); + dwRet = stTime.wYear - pcstSystemTime->wYear; + // день рожденья будет в след месяце + if (stTime.wMonthwMonth) + dwRet--; + // др ещё будет в этом месяце или уже был... + else { + // др в этом месяце + if (stTime.wMonth == pcstSystemTime->wMonth) + // ещё только будет, не сегодня + if (stTime.wDaywDay) + dwRet--; + } + } + return dwRet; +} + +DWORD FindFile(LPWSTR lpszFolder, DWORD dwFolderLen, LPWSTR lpszFileName, DWORD dwFileNameLen, LPWSTR lpszRetFilePathName, DWORD dwRetFilePathLen, DWORD *pdwRetFilePathLen) +{ + DWORD dwRetErrorCode; + + if (lpszFolder && dwFolderLen && lpszFileName && dwFileNameLen) { + WCHAR szPath[32768]; + DWORD dwPathLen, dwRecDeepAllocated, dwRecDeepCurPos, dwFilePathLen; + RECURSION_DATA_STACK_ITEM *prdsiItems; + + if (dwFolderLen == -1) dwFolderLen = lstrlenW(lpszFolder); + if (dwFileNameLen == -1) dwFileNameLen = lstrlenW(lpszFileName); + + dwRecDeepCurPos = 0; + dwRecDeepAllocated = RECURSION_DATA_STACK_ITEMS_MIN; + prdsiItems = (RECURSION_DATA_STACK_ITEM*)mir_calloc(dwRecDeepAllocated*sizeof(RECURSION_DATA_STACK_ITEM)); + if (prdsiItems) { + dwPathLen = dwFolderLen; + memmove(szPath, lpszFolder, (dwPathLen*sizeof(WCHAR))); + if (szPath[(dwPathLen-1)] != '\\') { + szPath[dwPathLen] = '\\'; + dwPathLen++; + } + szPath[dwPathLen] = 0; + lstrcatW(szPath, L"*.*"); + + prdsiItems[dwRecDeepCurPos].dwFileNameLen = 0; + prdsiItems[dwRecDeepCurPos].hFind = FindFirstFileEx(szPath, FindExInfoStandard, &prdsiItems[dwRecDeepCurPos].w32fdFindFileData, FindExSearchNameMatch, NULL, 0); + if (prdsiItems[dwRecDeepCurPos].hFind != INVALID_HANDLE_VALUE) { + dwRetErrorCode = ERROR_FILE_NOT_FOUND; + do { + dwPathLen-=prdsiItems[dwRecDeepCurPos].dwFileNameLen; + + while (dwRetErrorCode == ERROR_FILE_NOT_FOUND && FindNextFile(prdsiItems[dwRecDeepCurPos].hFind, &prdsiItems[dwRecDeepCurPos].w32fdFindFileData)) { + if (prdsiItems[dwRecDeepCurPos].w32fdFindFileData.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) {// folder + if (CompareString( MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), NORM_IGNORECASE, prdsiItems[dwRecDeepCurPos].w32fdFindFileData.cFileName, -1, L".", 1) != CSTR_EQUAL) + if (CompareString( MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), NORM_IGNORECASE, prdsiItems[dwRecDeepCurPos].w32fdFindFileData.cFileName, -1, L"..", 2) != CSTR_EQUAL) { + prdsiItems[dwRecDeepCurPos].dwFileNameLen = (lstrlenW(prdsiItems[dwRecDeepCurPos].w32fdFindFileData.cFileName)+1); + memmove((szPath+dwPathLen), prdsiItems[dwRecDeepCurPos].w32fdFindFileData.cFileName, (prdsiItems[dwRecDeepCurPos].dwFileNameLen*sizeof(WCHAR))); + lstrcatW(szPath, L"\\*.*"); + dwPathLen += prdsiItems[dwRecDeepCurPos].dwFileNameLen; + + dwRecDeepCurPos++; + if (dwRecDeepCurPos == dwRecDeepAllocated) { // need more space + dwRecDeepAllocated += RECURSION_DATA_STACK_ITEMS_MIN; + prdsiItems = (RECURSION_DATA_STACK_ITEM*)mir_realloc(prdsiItems, dwRecDeepAllocated*sizeof(RECURSION_DATA_STACK_ITEM)); + if (prdsiItems == NULL) { + dwRecDeepCurPos = 0; + dwRetErrorCode = GetLastError(); + break; + } + } + prdsiItems[dwRecDeepCurPos].hFind = FindFirstFileEx(szPath, FindExInfoStandard, &prdsiItems[dwRecDeepCurPos].w32fdFindFileData, FindExSearchNameMatch, NULL, 0); + } + } + else {// file + if (CompareString( MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), NORM_IGNORECASE, prdsiItems[dwRecDeepCurPos].w32fdFindFileData.cFileName, -1, lpszFileName, dwFileNameLen) == CSTR_EQUAL) { + prdsiItems[dwRecDeepCurPos].dwFileNameLen = lstrlenW(prdsiItems[dwRecDeepCurPos].w32fdFindFileData.cFileName); + memmove((szPath+dwPathLen), prdsiItems[dwRecDeepCurPos].w32fdFindFileData.cFileName, ((prdsiItems[dwRecDeepCurPos].dwFileNameLen+1)*sizeof(WCHAR))); + dwFilePathLen = (dwPathLen+prdsiItems[dwRecDeepCurPos].dwFileNameLen); + + if (pdwRetFilePathLen) (*pdwRetFilePathLen) = dwFilePathLen; + if (lpszRetFilePathName && dwRetFilePathLen) { + dwFilePathLen = min(dwFilePathLen, dwRetFilePathLen); + memmove(lpszRetFilePathName, szPath, ((dwFilePathLen+1)*sizeof(WCHAR))); + } + + dwRetErrorCode = NO_ERROR; + } + } + } + + if (prdsiItems) FindClose(prdsiItems[dwRecDeepCurPos].hFind); + dwRecDeepCurPos--; + } + while (dwRecDeepCurPos != -1); + } + mir_free(prdsiItems); + } + else dwRetErrorCode = GetLastError(); + } + else dwRetErrorCode = ERROR_INVALID_HANDLE; + + return dwRetErrorCode; +} + + +DWORD MemFillRandom(LPVOID lpBuff, size_t dwBuffSize) +{ + DWORD dwRetErrorCode; + + if (lpBuff && dwBuffSize) { + HCRYPTPROV hCryptProv = NULL; + + if (CryptAcquireContext(&hCryptProv, NULL, MS_STRONG_PROV, PROV_RSA_FULL, 0) == FALSE && GetLastError() == NTE_BAD_KEYSET) + CryptAcquireContext(&hCryptProv, NULL, MS_STRONG_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET); + + if (hCryptProv) { + if (CryptGenRandom(hCryptProv, dwBuffSize, (BYTE*)lpBuff)) + dwRetErrorCode = NO_ERROR; + else + dwRetErrorCode = GetLastError(); + } + else dwRetErrorCode = GetLastError(); + + CryptReleaseContext(hCryptProv, 0); + } + else dwRetErrorCode = ERROR_INVALID_HANDLE; + + return dwRetErrorCode; +} + +BOOL CMraProto::SetPassDB(LPSTR lpszBuff, size_t dwBuffSize) +{ + BOOL bRet = FALSE; + BYTE btRandomData[256], btCryptedPass[256] = {0}, bthmacSHA1[SHA1HashSize] = {0}; + char szEMail[MAX_EMAIL_LEN] = {0}; + size_t dwEMailSize; + +#if /*defined (_DEBUG) ||*/ defined (REL_DEB) + + mraSetStringExA(NULL, "Pass", lpszBuff, dwBuffSize); + bRet = TRUE; +#else + if (dwBuffSize < 128) + if (mraGetStaticStringA(NULL, "e-mail", szEMail, SIZEOF(szEMail), &dwEMailSize)) { + MemFillRandom(btRandomData, sizeof(btRandomData)); + + SHA1GetDigest(lpszBuff, dwBuffSize, &btCryptedPass[1]); + + //BASE64EncodeUnSafe(lpszBuff, dwBuffSize, &btCryptedPass[(1+SHA1HashSize)], (sizeof(btCryptedPass)-1), &dwBuffSize); + memmove(&btCryptedPass[(1+SHA1HashSize)], lpszBuff, dwBuffSize); + btCryptedPass[0] = (BYTE)dwBuffSize; + //memmove(&btCryptedPass[1], lpszBuff, dwBuffSize); + + hmac_sha1(btRandomData, sizeof(btRandomData), (BYTE*)szEMail, dwEMailSize, bthmacSHA1); + + RC4(btCryptedPass, sizeof(btCryptedPass), bthmacSHA1, SHA1HashSize); + RC4(btCryptedPass, sizeof(btCryptedPass), btRandomData, sizeof(btRandomData)); + CopyMemoryReverseDWORD(btCryptedPass, btCryptedPass, sizeof(btCryptedPass)); + RC4(btCryptedPass, sizeof(btCryptedPass), bthmacSHA1, SHA1HashSize); + + + mraSetDword(NULL, "pCryptVer", MRA_PASS_CRYPT_VER); + mraWriteContactSettingBlob(NULL, "pCryptData", btRandomData, sizeof(btRandomData)); + mraWriteContactSettingBlob(NULL, "pCryptPass", btCryptedPass, sizeof(btCryptedPass)); + + bRet = TRUE; + } +#endif +return(bRet); +} + + +BOOL CMraProto::GetPassDB_v1(LPSTR lpszBuff, size_t dwBuffSize, size_t *pdwBuffSize) +{ + BYTE btRandomData[256] = {0}, btCryptedPass[256] = {0}, bthmacSHA1[SHA1HashSize] = {0}; + char szEMail[MAX_EMAIL_LEN] = {0}; + size_t dwRandomDataSize, dwCryptedPass, dwEMailSize, dwPassSize; + + if (mraGetDword(NULL, "pCryptVer", 0) == 1) + if (mraGetContactSettingBlob(NULL, "pCryptData", btRandomData, sizeof(btRandomData), &dwRandomDataSize)) + if (dwRandomDataSize == sizeof(btRandomData)) + if (mraGetContactSettingBlob(NULL, "pCryptPass", btCryptedPass, sizeof(btCryptedPass), &dwCryptedPass)) + if (dwCryptedPass == sizeof(btCryptedPass)) + if (mraGetStaticStringA(NULL, "e-mail", szEMail, SIZEOF(szEMail), &dwEMailSize)) { + hmac_sha1(btRandomData, sizeof(btRandomData), (BYTE*)szEMail, dwEMailSize, bthmacSHA1); + + RC4(btCryptedPass, sizeof(btCryptedPass), bthmacSHA1, SHA1HashSize); + CopyMemoryReverseDWORD(btCryptedPass, btCryptedPass, sizeof(btCryptedPass)); + RC4(btCryptedPass, sizeof(btCryptedPass), btRandomData, dwRandomDataSize); + RC4(btCryptedPass, sizeof(btCryptedPass), bthmacSHA1, SHA1HashSize); + + dwPassSize = (*btCryptedPass); + BASE64DecodeUnSafe(&btCryptedPass[(1+SHA1HashSize)], dwPassSize, &btCryptedPass[(1+SHA1HashSize)], (sizeof(btCryptedPass)-1), &dwPassSize); + SHA1GetDigest(&btCryptedPass[(1+SHA1HashSize)], dwPassSize, btRandomData); + if (MemoryCompare(&btCryptedPass[1], SHA1HashSize, btRandomData, SHA1HashSize) == CMEM_EQUAL) + if (dwBuffSize >= dwPassSize) { + memmove(lpszBuff, &btCryptedPass[(1+SHA1HashSize)], dwPassSize); + *(lpszBuff + dwPassSize) = 0; + + if (pdwBuffSize) + *pdwBuffSize = dwPassSize; + return TRUE; + } + } + + return FALSE; +} + + +BOOL CMraProto::GetPassDB_v2(LPSTR lpszBuff, size_t dwBuffSize, size_t *pdwBuffSize) +{ + BYTE btRandomData[256] = {0}, btCryptedPass[256] = {0}, bthmacSHA1[SHA1HashSize] = {0}; + char szEMail[MAX_EMAIL_LEN] = {0}; + size_t dwRandomDataSize, dwCryptedPass, dwEMailSize, dwPassSize; + + if (mraGetDword(NULL, "pCryptVer", 0) == 2) + if (mraGetContactSettingBlob(NULL, "pCryptData", btRandomData, sizeof(btRandomData), &dwRandomDataSize)) + if (dwRandomDataSize == sizeof(btRandomData)) + if (mraGetContactSettingBlob(NULL, "pCryptPass", btCryptedPass, sizeof(btCryptedPass), &dwCryptedPass)) + if (dwCryptedPass == sizeof(btCryptedPass)) + if (mraGetStaticStringA(NULL, "e-mail", szEMail, SIZEOF(szEMail), &dwEMailSize)) { + hmac_sha1(btRandomData, sizeof(btRandomData), (BYTE*)szEMail, dwEMailSize, bthmacSHA1); + + RC4(btCryptedPass, sizeof(btCryptedPass), bthmacSHA1, SHA1HashSize); + CopyMemoryReverseDWORD(btCryptedPass, btCryptedPass, sizeof(btCryptedPass)); + RC4(btCryptedPass, sizeof(btCryptedPass), btRandomData, dwRandomDataSize); + RC4(btCryptedPass, sizeof(btCryptedPass), bthmacSHA1, SHA1HashSize); + + dwPassSize = ((*btCryptedPass)&0xff); + SHA1GetDigest(&btCryptedPass[(1+SHA1HashSize)], dwPassSize, btRandomData); + if (MemoryCompare(&btCryptedPass[1], SHA1HashSize, btRandomData, SHA1HashSize) == CMEM_EQUAL) + if (dwBuffSize >= dwPassSize) + { + memmove(lpszBuff, &btCryptedPass[(1+SHA1HashSize)], dwPassSize); + (*(lpszBuff+dwPassSize)) = 0; + + if (pdwBuffSize) (*pdwBuffSize) = dwPassSize; + return TRUE; + } + } + + return FALSE; +} + +BOOL CMraProto::GetPassDB(LPSTR lpszBuff, size_t dwBuffSize, size_t *pdwBuffSize) +{ + #if /*defined (_DEBUG) ||*/ defined (REL_DEB) + mraGetStaticStringA(NULL, "Pass", lpszBuff, dwBuffSize, pdwBuffSize); + return TRUE; + #else + switch (mraGetDword(NULL, "pCryptVer", 0)) { + case 1: + return GetPassDB_v1(lpszBuff, dwBuffSize, pdwBuffSize); + case 2: + return GetPassDB_v2(lpszBuff, dwBuffSize, pdwBuffSize); + default: + return FALSE; + } + #endif +} + +DWORD ReplaceInBuff(LPVOID lpInBuff, size_t dwInBuffSize, size_t dwReplaceItemsCount, LPVOID *plpInReplaceItems, size_t *pdwInReplaceItemsCounts, LPVOID *plpOutReplaceItems, size_t *pdwOutReplaceItemsCounts, LPVOID lpOutBuff, size_t dwOutBuffSize, size_t *pdwOutBuffSize) +{ + DWORD dwRetErrorCode = NO_ERROR; + LPBYTE *plpbtFounded; + #ifdef _DEBUG //check tables + for (size_t i = 0;i(lpbtOutBuffCur+(dwMemPartToCopy+pdwInReplaceItemsCounts[dwFirstFoundIndex]))) + { + memmove(lpbtOutBuffCur, lpbtInBuffCurPrev, dwMemPartToCopy);lpbtOutBuffCur += dwMemPartToCopy; + memmove(lpbtOutBuffCur, plpOutReplaceItems[dwFirstFoundIndex], pdwOutReplaceItemsCounts[dwFirstFoundIndex]);lpbtOutBuffCur += pdwOutReplaceItemsCounts[dwFirstFoundIndex]; + lpbtInBuffCurPrev = (plpbtFounded[dwFirstFoundIndex]+pdwInReplaceItemsCounts[dwFirstFoundIndex]); + + for (i = 0;i")}; +static const size_t dwXMLSymbolsCount[] = {sizeof(TCHAR), sizeof(TCHAR), sizeof(TCHAR), sizeof(TCHAR), sizeof(TCHAR)}; + +//Decode XML coded string. The function translate special xml code into standard characters. +DWORD DecodeXML(LPTSTR lptszMessage, size_t dwMessageSize, LPTSTR lptszMessageConverted, size_t dwMessageConvertedBuffSize, size_t *pdwMessageConvertedSize) +{ + DWORD dwRet = ReplaceInBuff(lptszMessage, (dwMessageSize*sizeof(TCHAR)), SIZEOF(lpszXMLTags), (LPVOID*)lpszXMLTags, (size_t*)dwXMLTagsCount, (LPVOID*)lpszXMLSymbols, (size_t*)dwXMLSymbolsCount, lptszMessageConverted, (dwMessageConvertedBuffSize*sizeof(TCHAR)), pdwMessageConvertedSize); + if (pdwMessageConvertedSize) + *pdwMessageConvertedSize /= sizeof(TCHAR); + return dwRet; +} + +//Encode XML coded string. The function translate special saved xml characters into special characters. +DWORD EncodeXML(LPTSTR lptszMessage, size_t dwMessageSize, LPTSTR lptszMessageConverted, size_t dwMessageConvertedBuffSize, size_t *pdwMessageConvertedSize) +{ + DWORD dwRet = ReplaceInBuff(lptszMessage, (dwMessageSize*sizeof(TCHAR)), SIZEOF(lpszXMLTags), (LPVOID*)lpszXMLSymbols, (size_t*)dwXMLSymbolsCount, (LPVOID*)lpszXMLTags, (size_t*)dwXMLTagsCount, lptszMessageConverted, (dwMessageConvertedBuffSize*sizeof(TCHAR)), pdwMessageConvertedSize); + if (pdwMessageConvertedSize) + *pdwMessageConvertedSize /= sizeof(TCHAR); + return dwRet; +} diff --git a/protocols/MRA/src/Mra_options.cpp b/protocols/MRA/src/Mra_options.cpp new file mode 100644 index 0000000000..c692f3e244 --- /dev/null +++ b/protocols/MRA/src/Mra_options.cpp @@ -0,0 +1,259 @@ +#include "Mra.h" + +INT_PTR CALLBACK DlgProcOptsAccount(HWND hWndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + CMraProto *ppro = (CMraProto*)GetWindowLongPtr(hWndDlg, GWLP_USERDATA); + WCHAR szBuff[MAX_EMAIL_LEN]; + + switch (msg) { + case WM_INITDIALOG: + TranslateDialogDefault(hWndDlg); + SetWindowLongPtr(hWndDlg, GWLP_USERDATA, lParam); + ppro = (CMraProto*)lParam; + + if ( ppro->mraGetStaticStringW(NULL, "e-mail", szBuff, SIZEOF(szBuff), NULL)) + SET_DLG_ITEM_TEXTW(hWndDlg, IDC_LOGIN, szBuff); + + SET_DLG_ITEM_TEXTW(hWndDlg, IDC_PASSWORD, (LPWSTR)L""); + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_NEW_ACCOUNT_LINK: + CallService(MS_UTILS_OPENURL, TRUE, (LPARAM)MRA_REGISTER_URL); + return TRUE; + + case IDC_LOOKUPLINK: + CallService(MS_UTILS_OPENURL, TRUE, (LPARAM)MRA_FORGOT_PASSWORD_URL); + return TRUE; + } + if ((LOWORD(wParam) == IDC_LOGIN || LOWORD(wParam) == IDC_PASSWORD) && (HIWORD(wParam) != EN_CHANGE || (HWND)lParam != GetFocus())) + return 0; + + SendMessage(GetParent(hWndDlg), PSM_CHANGED, 0, 0); + break; + + case WM_NOTIFY: + switch (((LPNMHDR)lParam)->code) { + case PSN_APPLY: + GET_DLG_ITEM_TEXT(hWndDlg, IDC_LOGIN, szBuff, SIZEOF(szBuff)); + ppro->mraSetStringW(NULL, "e-mail", szBuff); + + if (GET_DLG_ITEM_TEXTA(hWndDlg, IDC_PASSWORD, (LPSTR)szBuff, SIZEOF(szBuff))) { + ppro->SetPassDB((LPSTR)szBuff, lstrlenA((LPSTR)szBuff)); + SecureZeroMemory(szBuff, sizeof(szBuff)); + } + return TRUE; + } + break; + } + return FALSE; +} + +INT_PTR CALLBACK DlgProcAccount(HWND hWndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + CMraProto *ppro = (CMraProto*)GetWindowLongPtr(hWndDlg, GWLP_USERDATA); + WCHAR szBuff[MAX_EMAIL_LEN]; + + switch (msg) { + case WM_INITDIALOG: + TranslateDialogDefault(hWndDlg); + SetWindowLongPtr(hWndDlg, GWLP_USERDATA, lParam); + ppro = (CMraProto*)lParam; + + if ( ppro->mraGetStaticStringW(NULL, "e-mail", szBuff, SIZEOF(szBuff), NULL)) + SET_DLG_ITEM_TEXTW(hWndDlg, IDC_LOGIN, szBuff); + + SET_DLG_ITEM_TEXTW(hWndDlg, IDC_PASSWORD, (LPWSTR)L""); + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_NEW_ACCOUNT_LINK: + CallService(MS_UTILS_OPENURL, TRUE, (LPARAM)MRA_REGISTER_URL); + return TRUE; + } + if ( HIWORD(wParam) == EN_CHANGE && (HWND)lParam == GetFocus()) + { + switch(LOWORD(wParam)) + { + case IDC_LOGIN: + case IDC_PASSWORD: + SendMessage(GetParent(hWndDlg), PSM_CHANGED, 0, 0); + } + } + break; + + case WM_NOTIFY: + switch (((LPNMHDR)lParam)->code) { + case PSN_APPLY: + GET_DLG_ITEM_TEXT(hWndDlg, IDC_LOGIN, szBuff, SIZEOF(szBuff)); + ppro->mraSetStringW(NULL, "e-mail", szBuff); + + if (GET_DLG_ITEM_TEXTA(hWndDlg, IDC_PASSWORD, (LPSTR)szBuff, SIZEOF(szBuff))) { + ppro->SetPassDB((LPSTR)szBuff, lstrlenA((LPSTR)szBuff)); + SecureZeroMemory(szBuff, sizeof(szBuff)); + } + return TRUE; + } + break; + } + return FALSE; +} + +INT_PTR CALLBACK DlgProcOptsConnections(HWND hWndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + CMraProto *ppro = (CMraProto*)GetWindowLongPtr(hWndDlg, GWLP_USERDATA); + WCHAR szBuff[MAX_PATH]; + + switch (msg) { + case WM_INITDIALOG: + TranslateDialogDefault(hWndDlg); + SetWindowLongPtr(hWndDlg, GWLP_USERDATA, lParam); + ppro = (CMraProto*)lParam; + + if (ppro->mraGetStaticStringW(NULL, "Server", szBuff, SIZEOF(szBuff), NULL)) + SET_DLG_ITEM_TEXT(hWndDlg, IDC_SERVER, szBuff); + else + SET_DLG_ITEM_TEXTA(hWndDlg, IDC_SERVER, MRA_DEFAULT_SERVER); + + SetDlgItemInt(hWndDlg, IDC_SERVERPORT, ppro->mraGetWord(NULL, "ServerPort", MRA_DEFAULT_SERVER_PORT), FALSE); + // if set SSL proxy, setting will ignored + + //CHECK_DLG_BUTTON(hWndDlg, IDC_KEEPALIVE, mraGetByte(NULL, "keepalive", 0)); + CHECK_DLG_BUTTON(hWndDlg, IDC_AUTO_ADD_CONTACTS_TO_SERVER, ppro->mraGetByte(NULL, "AutoAddContactsToServer", MRA_DEFAULT_AUTO_ADD_CONTACTS_TO_SERVER)); + CHECK_DLG_BUTTON(hWndDlg, IDC_AUTO_AUTH_REQ_ON_LOGON, ppro->mraGetByte(NULL, "AutoAuthRequestOnLogon", MRA_DEFAULT_AUTO_AUTH_REQ_ON_LOGON)); + CHECK_DLG_BUTTON(hWndDlg, IDC_AUTO_AUTH_GRAND_IN_CLIST, ppro->mraGetByte(NULL, "AutoAuthGrandUsersInCList", MRA_DEFAULT_AUTO_AUTH_GRAND_IN_CLIST)); + CHECK_DLG_BUTTON(hWndDlg, IDC_AUTO_AUTH_GRAND_NEW_USERS, ppro->mraGetByte(NULL, "AutoAuthGrandNewUsers", MRA_DEFAULT_AUTO_AUTH_GRAND_NEW_USERS)); + CHECK_DLG_BUTTON(hWndDlg, IDC_AUTO_AUTH_GRAND_NEW_USERS_DISABLE_SPAM_CHECK, ppro->mraGetByte(NULL, "AutoAuthGrandNewUsersDisableSPAMCheck", MRA_DEFAULT_AUTO_AUTH_GRAND_NEW_USERS_DISABLE_SPAM_CHECK)); + EnableWindow(GetDlgItem(hWndDlg, IDC_AUTO_AUTH_GRAND_NEW_USERS_DISABLE_SPAM_CHECK), IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_AUTO_AUTH_GRAND_NEW_USERS)); + + CHECK_DLG_BUTTON(hWndDlg, IDC_SLOWSEND, ppro->mraGetByte(NULL, "SlowSend", MRA_DEFAULT_SLOW_SEND)); + CHECK_DLG_BUTTON(hWndDlg, IDC_INCREMENTAL_NEW_MAIL_NOTIFY, ppro->mraGetByte(NULL, "IncrementalNewMailNotify", MRA_DEFAULT_INC_NEW_MAIL_NOTIFY)); + CHECK_DLG_BUTTON(hWndDlg, IDC_TRAYICON_NEW_MAIL_NOTIFY, ppro->mraGetByte(NULL, "TrayIconNewMailNotify", MRA_DEFAULT_TRAYICON_NEW_MAIL_NOTIFY)); + CHECK_DLG_BUTTON(hWndDlg, IDC_TRAYICON_NEW_MAIL_NOTIFY_CLICK_TO_INBOX, ppro->mraGetByte(NULL, "TrayIconNewMailClkToInbox", MRA_DEFAULT_TRAYICON_NEW_MAIL_CLK_TO_INBOX)); + EnableWindow(GetDlgItem(hWndDlg, IDC_TRAYICON_NEW_MAIL_NOTIFY_CLICK_TO_INBOX), ppro->mraGetByte(NULL, "TrayIconNewMailNotify", MRA_DEFAULT_TRAYICON_NEW_MAIL_NOTIFY)); + + CHECK_DLG_BUTTON(hWndDlg, IDC_HIDE_MENU_ITEMS_FOR_NON_MRA, ppro->mraGetByte(NULL, "HideMenuItemsForNonMRAContacts", MRA_DEFAULT_HIDE_MENU_ITEMS_FOR_NON_MRA)); + + CHECK_DLG_BUTTON(hWndDlg, IDC_RTF_RECEIVE_ENABLE, ppro->mraGetByte(NULL, "RTFReceiveEnable", MRA_DEFAULT_RTF_RECEIVE_ENABLE)); + + CHECK_DLG_BUTTON(hWndDlg, IDC_RTF_SEND_ENABLE, ppro->mraGetByte(NULL, "RTFSendEnable", MRA_DEFAULT_RTF_SEND_ENABLE)); + EnableWindow(GetDlgItem(hWndDlg, IDC_RTF_SEND_SMART), ppro->mraGetByte(NULL, "RTFSendEnable", MRA_DEFAULT_RTF_SEND_ENABLE)); + EnableWindow(GetDlgItem(hWndDlg, IDC_BUTTON_FONT), ppro->mraGetByte(NULL, "RTFSendEnable", MRA_DEFAULT_RTF_SEND_ENABLE)); + EnableWindow(GetDlgItem(hWndDlg, IDC_RTF_BGCOLOUR), ppro->mraGetByte(NULL, "RTFSendEnable", MRA_DEFAULT_RTF_SEND_ENABLE)); + SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_RTF_BGCOLOUR, CPM_SETCOLOUR, 0, ppro->mraGetDword(NULL, "RTFBackgroundColour", MRA_DEFAULT_RTF_BACKGROUND_COLOUR)); + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_BUTTON_DEFAULT: + SET_DLG_ITEM_TEXTA(hWndDlg, IDC_SERVER, MRA_DEFAULT_SERVER); + SetDlgItemInt(hWndDlg, IDC_SERVERPORT, MRA_DEFAULT_SERVER_PORT, FALSE); + break; + case IDC_AUTO_AUTH_GRAND_NEW_USERS: + EnableWindow(GetDlgItem(hWndDlg, IDC_AUTO_AUTH_GRAND_NEW_USERS_DISABLE_SPAM_CHECK), IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_AUTO_AUTH_GRAND_NEW_USERS)); + break; + case IDC_TRAYICON_NEW_MAIL_NOTIFY: + EnableWindow(GetDlgItem(hWndDlg, IDC_TRAYICON_NEW_MAIL_NOTIFY_CLICK_TO_INBOX), IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_TRAYICON_NEW_MAIL_NOTIFY)); + break; + case IDC_RTF_SEND_ENABLE: + EnableWindow(GetDlgItem(hWndDlg, IDC_RTF_SEND_SMART), IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_RTF_SEND_ENABLE)); + EnableWindow(GetDlgItem(hWndDlg, IDC_BUTTON_FONT), IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_RTF_SEND_ENABLE)); + EnableWindow(GetDlgItem(hWndDlg, IDC_RTF_BGCOLOUR), IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_RTF_SEND_ENABLE)); + break; + case IDC_BUTTON_FONT: + { + LOGFONT lf = {0}; + CHOOSEFONT cf = {0}; + + cf.lStructSize = sizeof(cf); + cf.lpLogFont = &lf; + cf.rgbColors = ppro->mraGetDword(NULL, "RTFFontColour", MRA_DEFAULT_RTF_FONT_COLOUR); + cf.Flags = (CF_SCREENFONTS|CF_EFFECTS|CF_FORCEFONTEXIST|CF_INITTOLOGFONTSTRUCT); + if (ppro->mraGetContactSettingBlob(NULL, "RTFFont", &lf, sizeof(LOGFONT), NULL) == FALSE) { + HDC hDC = GetDC(NULL);// kegl + lf.lfCharSet = MRA_DEFAULT_RTF_FONT_CHARSET; + lf.lfHeight = -MulDiv(MRA_DEFAULT_RTF_FONT_SIZE, GetDeviceCaps(hDC, LOGPIXELSY), 72); + lstrcpynW(lf.lfFaceName, MRA_DEFAULT_RTF_FONT_NAME, LF_FACESIZE); + ReleaseDC(NULL, hDC); + } + + if (ChooseFont(&cf)) { + ppro->mraWriteContactSettingBlob(NULL, "RTFFont", &lf, sizeof(LOGFONT)); + ppro->mraSetDword(NULL, "RTFFontColour", cf.rgbColors); + } + } + break; + } + + if ((LOWORD(wParam) == IDC_SERVER || LOWORD(wParam) == IDC_SERVERPORT) && (HIWORD(wParam) != EN_CHANGE || (HWND)lParam != GetFocus())) return FALSE; + SendMessage(GetParent(hWndDlg), PSM_CHANGED, 0, 0); + break; + case WM_NOTIFY: + switch (((LPNMHDR)lParam)->code) { + case PSN_APPLY: + GET_DLG_ITEM_TEXT(hWndDlg, IDC_SERVER, szBuff, SIZEOF(szBuff)); + ppro->mraSetStringW(NULL, "Server", szBuff); + ppro->mraSetWord(NULL, "ServerPort", (WORD)GetDlgItemInt(hWndDlg, IDC_SERVERPORT, NULL, FALSE)); + ppro->mraSetByte(NULL, "AutoAddContactsToServer", IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_AUTO_ADD_CONTACTS_TO_SERVER)); + ppro->mraSetByte(NULL, "AutoAuthRequestOnLogon", IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_AUTO_AUTH_REQ_ON_LOGON)); + ppro->mraSetByte(NULL, "AutoAuthGrandUsersInCList", IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_AUTO_AUTH_GRAND_IN_CLIST)); + ppro->mraSetByte(NULL, "AutoAuthGrandNewUsers", IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_AUTO_AUTH_GRAND_NEW_USERS)); + ppro->mraSetByte(NULL, "AutoAuthGrandNewUsersDisableSPAMCheck", IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_AUTO_AUTH_GRAND_NEW_USERS_DISABLE_SPAM_CHECK)); + + ppro->mraSetByte(NULL, "SlowSend", IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_SLOWSEND)); + ppro->mraSetByte(NULL, "IncrementalNewMailNotify", IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_INCREMENTAL_NEW_MAIL_NOTIFY)); + ppro->mraSetByte(NULL, "TrayIconNewMailNotify", IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_TRAYICON_NEW_MAIL_NOTIFY)); + ppro->mraSetByte(NULL, "TrayIconNewMailClkToInbox", IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_TRAYICON_NEW_MAIL_NOTIFY_CLICK_TO_INBOX)); + + ppro->mraSetByte(NULL, "HideMenuItemsForNonMRAContacts", IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_HIDE_MENU_ITEMS_FOR_NON_MRA)); + + ppro->mraSetByte(NULL, "RTFReceiveEnable", IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_RTF_RECEIVE_ENABLE)); + ppro->mraSetByte(NULL, "RTFSendEnable", IS_DLG_BUTTON_CHECKED(hWndDlg, IDC_RTF_SEND_ENABLE)); + ppro->mraSetDword(NULL, "RTFBackgroundColour", SEND_DLG_ITEM_MESSAGE(hWndDlg, IDC_RTF_BGCOLOUR, CPM_GETCOLOUR, 0, 0)); + return TRUE; + } + break; + } + return FALSE; +} + +int CMraProto::OnOptionsInit(WPARAM wParam, LPARAM lParam) +{ + OPTIONSDIALOGPAGE odp = {0}; + odp.cbSize = sizeof(odp); + odp.dwInitParam = (LPARAM)this; + odp.hInstance = masMraSettings.hInstance; + odp.ptszTitle = m_tszUserName; + odp.ptszGroup = LPGENT("Network"); + odp.flags = ODPF_BOLDGROUPS | ODPF_TCHAR; + + odp.ptszTab = LPGENT("Account"); + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_ACCOUNT); + odp.pfnDlgProc = DlgProcOptsAccount; + Options_AddPage(wParam, &odp); + + odp.ptszTab = LPGENT("Connections"); + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_CONNECTIONS); + odp.pfnDlgProc = DlgProcOptsConnections; + Options_AddPage(wParam, &odp); + + odp.ptszTab = LPGENT("Anti spam"); + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_ANTISPAM); + odp.pfnDlgProc = MraAntiSpamDlgProcOpts; + Options_AddPage(wParam, &odp); + + odp.ptszTab = LPGENT("Files"); + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_FILES); + odp.pfnDlgProc = MraFilesQueueDlgProcOpts; + Options_AddPage(wParam, &odp); + + odp.ptszTab = LPGENT("Avatars"); + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_AVATRS); + odp.pfnDlgProc = MraAvatarsQueueDlgProcOpts; + Options_AddPage(wParam, &odp); + + OnPopupOptInit(wParam, lParam); + return 0; +} diff --git a/protocols/MRA/src/Mra_proto.cpp b/protocols/MRA/src/Mra_proto.cpp new file mode 100644 index 0000000000..0e6753fb7d --- /dev/null +++ b/protocols/MRA/src/Mra_proto.cpp @@ -0,0 +1,2224 @@ +#include "Mra.h" +#include "MraOfflineMsg.h" +#include "MraRTFMsg.h" +#include "MraPlaces.h" + +DWORD GetUL(LPBYTE *plpData); +DWORDLONG GetUIDL(LPBYTE *plpData); +MRA_GUID GetGUID(LPBYTE *plpData); +DWORD GetLPS(LPBYTE lpbData, DWORD dwDataSize, LPBYTE *plpCurrentData, MRA_LPS *plpsString); + +DWORD CMraProto::StartConnect() +{ + if ( !InterlockedExchangeAdd((volatile LONG*)&masMraSettings.dwGlobalPluginRunning, 0)) + return ERROR_OPERATION_ABORTED; + + // поток ещё/уже не работал, поставили статус что работает и запускаем + if (InterlockedCompareExchange((volatile LONG*)&dwThreadWorkerRunning, TRUE, FALSE) == FALSE) { + char szPass[MAX_PATH]; + size_t dwEMailSize = 0, dwPasswordSize = 0; + + mraGetStaticStringA(NULL, "e-mail", NULL, 0, &dwEMailSize); + + if (dwEMailSize > 5 && GetPassDB(szPass, sizeof(szPass), &dwPasswordSize)) { + InterlockedExchange((volatile LONG*)&dwThreadWorkerLastPingTime, GetTickCount()); + hThreadWorker = ForkThreadEx(&CMraProto::MraThreadProc, NULL); + if (hThreadWorker == NULL) { + DWORD dwRetErrorCode = GetLastError(); + InterlockedExchange((volatile LONG*)&dwThreadWorkerRunning, FALSE); + SetStatus(ID_STATUS_OFFLINE); + return dwRetErrorCode; + } + } + else { + MraThreadClean(); + if (dwEMailSize <= 5) + MraPopupShowFromAgentW(MRA_POPUP_TYPE_WARNING, 0, TranslateW(L"Please, setup e-mail in options")); + else + MraPopupShowFromAgentW(MRA_POPUP_TYPE_WARNING, 0, TranslateW(L"Please, setup password in options")); + } + SecureZeroMemory(szPass, sizeof(szPass)); + } + + return 0; +} + +void CMraProto::MraThreadProc(LPVOID lpParameter) +{ + DWORD dwRetErrorCode = NO_ERROR; + + BOOL bConnected = FALSE; + char szHost[MAX_PATH]; + DWORD dwConnectReTryCount, dwCurConnectReTryCount; + NETLIBOPENCONNECTION nloc = {0}; + + SleepEx(100, FALSE);// to prevent high CPU load by some status plugins like allwaysonline + + dwConnectReTryCount = mraGetDword(NULL, "ConnectReTryCountMRIM", MRA_DEFAULT_CONN_RETRY_COUNT_MRIM); + + nloc.cbSize = sizeof(nloc); + nloc.flags = NLOCF_V2; + nloc.szHost = szHost; + nloc.timeout = mraGetDword(NULL, "TimeOutConnectMRIM", MRA_DEFAULT_TIMEOUT_CONN_MRIM); + if (nloc.timeoutMRA_TIMEOUT_CONN_МАХ) nloc.timeout = MRA_TIMEOUT_CONN_МАХ; + + InterlockedExchange((volatile LONG*)&dwThreadWorkerLastPingTime, GetTickCount()); + if (MraGetNLBData((LPSTR)nloc.szHost, MAX_PATH, &nloc.wPort) == NO_ERROR) { + dwCurConnectReTryCount = dwConnectReTryCount; + do { + InterlockedExchange((volatile LONG*)&dwThreadWorkerLastPingTime, GetTickCount()); + hConnection = (HANDLE)CallService(MS_NETLIB_OPENCONNECTION, (WPARAM)hNetlibUser, (LPARAM)&nloc); + } + while (--dwCurConnectReTryCount && hConnection == NULL); + + if (hConnection) + bConnected = TRUE; + } + + if (bConnected == FALSE) + if (mraGetByte(NULL, "NLBFailDirectConnect", MRA_DEFAULT_NLB_FAIL_DIRECT_CONNECT)) { + if (IsHTTPSProxyUsed(hNetlibUser)) + nloc.wPort = MRA_SERVER_PORT_HTTPS; + else { + nloc.wPort = mraGetWord(NULL, "ServerPort", MRA_DEFAULT_SERVER_PORT); + if (nloc.wPort == MRA_SERVER_PORT_STANDART_NLB) nloc.wPort = MRA_SERVER_PORT_STANDART; + } + + for (DWORD i = 1;(iMRA_TIMEOUT_CONN_МАХ) nloc.timeout = MRA_TIMEOUT_CONN_МАХ; + + dwCurConnectReTryCount = dwConnectReTryCount; + do { + InterlockedExchange((volatile LONG*)&dwThreadWorkerLastPingTime, GetTickCount()); + nls.hReadConns[0] = (HANDLE)CallService(MS_NETLIB_OPENCONNECTION, (WPARAM)hNetlibUser, (LPARAM)&nloc); + } + while (--dwCurConnectReTryCount && nls.hReadConns[0] == NULL); + + if (nls.hReadConns[0]) { + nls.cbSize = sizeof(nls); + nls.dwTimeout = 1000 * mraGetDword(NULL, "TimeOutReceiveNLB", MRA_DEFAULT_TIMEOUT_RECV_NLB); + InterlockedExchange((volatile LONG*)&dwThreadWorkerLastPingTime, GetTickCount()); + + while (m_iStatus != ID_STATUS_OFFLINE && bContinue) { + switch (CallService(MS_NETLIB_SELECT, 0, (LPARAM)&nls)) { + case SOCKET_ERROR: + case 0:// Time out + bContinue = FALSE; + break; + case 1: + dwBytesReceived = Netlib_Recv(nls.hReadConns[0], (LPSTR)(btBuff+dwRcvBuffSizeUsed), (SIZEOF(btBuff)-dwRcvBuffSizeUsed), 0); + if (dwBytesReceived && dwBytesReceived != SOCKET_ERROR) + dwRcvBuffSizeUsed += dwBytesReceived; + else + bContinue = FALSE; + break; + } + InterlockedExchange((volatile LONG*)&dwThreadWorkerLastPingTime, GetTickCount()); + } + Netlib_CloseHandle(nls.hReadConns[0]); + + if (dwRcvBuffSizeUsed) { + lpszPort = (LPSTR)MemoryFindByte(0, btBuff, dwRcvBuffSizeUsed, ':'); + if (lpszPort) { + (*lpszPort) = 0; + lpszPort++; + + lstrcpynA(lpszHost, (LPSTR)btBuff, dwHostBuffSize); + 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 dwSelectRet, dwBytesReceived, dwDataCurrentBuffSize, dwDataCurrentBuffSizeUsed, dwPingPeriod = MAXDWORD, dwNextPingSendTickTime = MAXDWORD; + size_t dwRcvBuffSize = BUFF_SIZE_RCV, dwRcvBuffSizeUsed = 0, dwDataCurrentBuffOffset = 0; + LPBYTE lpbBufferRcv; + mrim_packet_header_t *pmaHeader; + + NETLIBSELECT nls = {0}; + nls.cbSize = sizeof(nls); + nls.dwTimeout = NETLIB_SELECT_TIMEOUT; + nls.hReadConns[0] = hConnection; + + lpbBufferRcv = (LPBYTE)mir_calloc(dwRcvBuffSize); + + dwCMDNum = 0; + MraSendCMD(MRIM_CS_HELLO, NULL, 0); + InterlockedExchange((volatile LONG*)&dwThreadWorkerLastPingTime, GetTickCount()); + while (m_iStatus != ID_STATUS_OFFLINE && bContinue) + { + dwSelectRet = CallService(MS_NETLIB_SELECT, 0, (LPARAM)&nls); + switch (dwSelectRet) { + case SOCKET_ERROR: + if (m_iStatus != ID_STATUS_OFFLINE) { + dwRetErrorCode = GetLastError(); + ShowFormattedErrorMessage(L"Disconnected, socket error", dwRetErrorCode); + } + bContinue = FALSE; + break; + + case 0:// Time out + case 1: + dwBytesReceived = GetTickCount(); + InterlockedExchange((volatile LONG*)&dwThreadWorkerLastPingTime, dwBytesReceived); + // server ping + if (dwNextPingSendTickTime <= dwBytesReceived) { + dwNextPingSendTickTime = (dwBytesReceived+(dwPingPeriod*1000)); + MraSendCMD(MRIM_CS_PING, NULL, 0); + } + { + DWORD dwCMDNum, dwFlags, dwAckType; + HANDLE 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: + ProtoBroadcastAckAsync(hContact, dwAckType, ACKRESULT_FAILED, (HANDLE)dwCMDNum, (LPARAM)"Undefined message deliver error, time out"); + break; + case ACKTYPE_GETINFO: + ProtoBroadcastAckAsync(hContact, dwAckType, ACKRESULT_FAILED, (HANDLE)1, 0); + break; + case ACKTYPE_SEARCH: + ProtoBroadcastAckAsync(hContact, dwAckType, ACKRESULT_SUCCESS, (HANDLE)dwCMDNum, 0); + break; + case ICQACKTYPE_SMS: + mir_free(lpbData); + break; + } + MraSendQueueFree(hSendQueueHandle, dwCMDNum); + } + } + + if (dwSelectRet == 0) // Time out + break; + + // expand receive buffer dynamically + if ((dwRcvBuffSize - dwRcvBuffSizeUsed) < BUFF_SIZE_RCV_MIN_FREE) { + dwRcvBuffSize += BUFF_SIZE_RCV; + lpbBufferRcv = (LPBYTE)mir_realloc(lpbBufferRcv, dwRcvBuffSize); + } + + dwBytesReceived = Netlib_Recv(nls.hReadConns[0], (LPSTR)(lpbBufferRcv+dwRcvBuffSizeUsed), (dwRcvBuffSize-dwRcvBuffSizeUsed), 0); + if (dwBytesReceived && dwBytesReceived != SOCKET_ERROR) { + dwRcvBuffSizeUsed += dwBytesReceived; + + while (TRUE) { + dwDataCurrentBuffSize = (dwRcvBuffSize-dwDataCurrentBuffOffset); + dwDataCurrentBuffSizeUsed = (dwRcvBuffSizeUsed-dwDataCurrentBuffOffset); + pmaHeader = (mrim_packet_header_t*)(lpbBufferRcv+dwDataCurrentBuffOffset); + + // packet header received + if (dwDataCurrentBuffSizeUsed >= sizeof(mrim_packet_header_t)) { + // packet OK + if (pmaHeader->magic == CS_MAGIC) { + // full packet received, may be more than one + if ((dwDataCurrentBuffSizeUsed-sizeof(mrim_packet_header_t)) >= pmaHeader->dlen) { + + MraCommandDispatcher(pmaHeader, &dwPingPeriod, &dwNextPingSendTickTime, &bContinue); + + // 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; + } + } + // not all packet received, continue receiving + else { + if (dwDataCurrentBuffOffset) { + memmove(lpbBufferRcv, (lpbBufferRcv+dwDataCurrentBuffOffset), dwDataCurrentBuffSizeUsed); + dwRcvBuffSizeUsed = dwDataCurrentBuffSizeUsed; + dwDataCurrentBuffOffset = 0; + } + DebugPrintCRLFW(L"Not all packet received, continue receiving"); + break; + } + } + // bad packet + else { + DebugPrintCRLFW(L"Bad packet"); + dwDataCurrentBuffOffset = 0; + dwRcvBuffSizeUsed = 0; + break; + } + } + // packet to small, continue receiving + else { + DebugPrintCRLFW(L"Packet to small, continue receiving"); + memmove(lpbBufferRcv, (lpbBufferRcv+dwDataCurrentBuffOffset), dwDataCurrentBuffSizeUsed); + dwRcvBuffSizeUsed = dwDataCurrentBuffSizeUsed; + dwDataCurrentBuffOffset = 0; + break; + } + } + } + // disconnected + else { + if (m_iStatus != ID_STATUS_OFFLINE) { + dwRetErrorCode = GetLastError(); + ShowFormattedErrorMessage(L"Disconnected, socket read error", dwRetErrorCode); + } + bContinue = FALSE; + } + break; + }// end switch + }// end while + mir_free(lpbBufferRcv); + + return dwRetErrorCode; +} + +DWORD CMraProto::MraCommandDispatcher(mrim_packet_header_t *pmaHeader, DWORD *pdwPingPeriod, DWORD *pdwNextPingSendTickTime, BOOL *pbContinue) +{ + WCHAR szBuff[4096] = {0}; + DWORD dwDataSize, dwTemp, dwAckType; + size_t dwStringSize; + MRA_LPS lpsString = {0}, lpsEMail = {0}; + HANDLE hContact = NULL; + LPBYTE lpbData, lpbDataCurrent; + + lpbData = ((((LPBYTE)pmaHeader))+sizeof(mrim_packet_header_t)); + lpbDataCurrent = lpbData; + dwDataSize = pmaHeader->dlen; + + Netlib_Logf(hNetlibUser, "Received packet %x\n", pmaHeader->msg); + + switch (pmaHeader->msg) { + case MRIM_CS_HELLO_ACK://Подтверждение установки соединения// UL ## ping_period ## Ожидаемая частота подтверждения соединения (в секундах) + //bit of a security hole here, since it's easy to extract a password from an edit box + if (GetPassDB((LPSTR)szBuff, SIZEOF(szBuff), &dwStringSize)) { + CHAR szEMail[MAX_EMAIL_LEN], szSelfVersionString[MAX_PATH], szUserAgentFormated[USER_AGENT_MAX+MAX_PATH], szValueName[MAX_PATH]; + WCHAR wszStatusTitle[STATUS_TITLE_MAX+4], wszStatusDesc[STATUS_DESC_MAX+4]; + DWORD dwStatus, dwXStatus, dwXStatusMir, dwFutureFlags; + LPWSTR lpwszStatusTitle, lpwszStatusDesc; + size_t dwEMailSize, dwSelfVersionSize, dwStatusTitleSize, dwStatusDescSize, dwUserAgentFormattedSize; + + dwXStatusMir = m_iXStatus; + dwStatus = GetMraStatusFromMiradaStatus(m_iDesiredStatus, dwXStatusMir, &dwXStatus); + if ( IsXStatusValid(dwXStatusMir)) {// xstatuses + mir_snprintf(szValueName, SIZEOF(szValueName), "XStatus%ldName", dwXStatusMir); + if (mraGetStaticStringW(NULL, szValueName, wszStatusTitle, (STATUS_TITLE_MAX+1), &dwStatusTitleSize)) + lpwszStatusTitle = wszStatusTitle; + else { // default xstatus name + lpwszStatusTitle = TranslateW(lpcszXStatusNameDef[dwXStatusMir]); + dwStatusTitleSize = lstrlenW(lpwszStatusTitle); + } + + mir_snprintf(szValueName, SIZEOF(szValueName), "XStatus%ldMsg", dwXStatusMir); + if (mraGetStaticStringW(NULL, szValueName, wszStatusDesc, (STATUS_DESC_MAX+1), &dwStatusDescSize)) + lpwszStatusDesc = wszStatusDesc; + else { // default xstatus description + lpwszStatusDesc = NULL; + dwStatusDescSize = 0; + } + } + else { // not xstatuses + lpwszStatusTitle = GetStatusModeDescriptionW(m_iDesiredStatus); + dwStatusTitleSize = lstrlenW(lpwszStatusTitle); + lpwszStatusDesc = NULL; + dwStatusDescSize = 0; + } + + MraGetSelfVersionString(szSelfVersionString, SIZEOF(szSelfVersionString), &dwSelfVersionSize); + if ( mraGetStaticStringA(NULL, "MirVerCustom", szUserAgentFormated, SIZEOF(szUserAgentFormated), &dwUserAgentFormattedSize) == FALSE) { + dwUserAgentFormattedSize = mir_snprintf(szUserAgentFormated, SIZEOF(szUserAgentFormated), + "client=\"magent\" name=\"Miranda NG\" title=\"%s\" version=\"777.%lu.%lu.%lu\" build=\"%lu\" protocol=\"%lu.%lu\"", + szSelfVersionString, __FILEVERSION_STRING, PROTO_VERSION_MAJOR, PROTO_VERSION_MINOR); + } + + dwFutureFlags = ((mraGetByte(NULL, "RTFReceiveEnable", MRA_DEFAULT_RTF_RECEIVE_ENABLE)? FEATURE_FLAG_RTF_MESSAGE:0)|MRA_FEATURE_FLAGS); + + if (mraGetStaticStringA(NULL, "e-mail", szEMail, SIZEOF(szEMail), &dwEMailSize)) + MraLogin2W(szEMail, dwEMailSize, (LPSTR)szBuff, dwStringSize, dwStatus, lpcszStatusUri[dwXStatus], lstrlenA(lpcszStatusUri[dwXStatus]), lpwszStatusTitle, dwStatusTitleSize, lpwszStatusDesc, dwStatusDescSize, dwFutureFlags, szUserAgentFormated, dwUserAgentFormattedSize, szSelfVersionString, dwSelfVersionSize); + else + *pbContinue = FALSE; + + SecureZeroMemory(szBuff, sizeof(szBuff)); + } + else *pbContinue = FALSE; + + *pdwPingPeriod = GetUL(&lpbDataCurrent); + break; + + case MRIM_CS_LOGIN_ACK: // Successful authorization + m_bLoggedIn = TRUE; + *pdwNextPingSendTickTime = 0; // force send ping + MraSendCMD(MRIM_CS_PING, NULL, 0); + SetStatus(m_iDesiredStatus); + MraAvatarsQueueGetAvatarSimple(hAvatarsQueueHandle, GAIF_FORCE, NULL, 0); + break; + + case MRIM_CS_LOGIN_REJ: // Unsuccessful authorization //LPS ## reason ## причина отказа + ProtoBroadcastAckAsync(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPASSWORD); + + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsString); + dwStringSize = MultiByteToWideChar(MRA_CODE_PAGE, 0, lpsString.lpszData, lpsString.dwSize, szBuff, SIZEOF(szBuff)); + szBuff[dwStringSize] = 0; + MraPopupShowW(NULL, MRA_POPUP_TYPE_ERROR, 0, TranslateW(L"Logon error: invalid login/password"), szBuff); + *pbContinue = FALSE; + break; + + case MRIM_CS_MESSAGE_ACK:// Message delivery + { + DWORD dwMsgID, dwFlags; + MRA_LPS lpsText, lpsRTFText, lpsMultiChatData; + + dwMsgID = GetUL(&lpbDataCurrent); + dwFlags = GetUL(&lpbDataCurrent); + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsEMail);//LPS ## from ## Адрес отправителя + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsText);//LPS ## message ## текстовая версия сообщения + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsRTFText);//LPS ## rtf-message ## форматированная версия сообщения + if (dwFlags&MESSAGE_FLAG_MULTICHAT) GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsMultiChatData); // LPS multichat_data + + // подтверждаем получение, только если удалось его обработать + if (MraRecvCommand_Message((DWORD)_time32(NULL), dwFlags, &lpsEMail, &lpsText, &lpsRTFText, &lpsMultiChatData) == NO_ERROR) + if ((dwFlags&MESSAGE_FLAG_NORECV) == 0) + MraMessageRecv(lpsEMail.lpszData, lpsEMail.dwSize, dwMsgID); + } + break; + + case MRIM_CS_MESSAGE_STATUS: + if ( !MraSendQueueFind(hSendQueueHandle, pmaHeader->seq, NULL, &hContact, &dwAckType, (LPBYTE*)&lpsString.lpszData, &lpsString.dwSize)) { + dwTemp = GetUL(&lpbDataCurrent); + switch (dwTemp) { + case MESSAGE_DELIVERED:// Message delivered directly to user + ProtoBroadcastAckAsync(hContact, dwAckType, ACKRESULT_SUCCESS, (HANDLE)pmaHeader->seq, 0); + break;//***deb возможны сбои из-за асинхронности тк там передаётся указатель + case MESSAGE_REJECTED_NOUSER:// Message rejected - no such user + ProtoBroadcastAckAsync(hContact, dwAckType, ACKRESULT_FAILED, (HANDLE)pmaHeader->seq, (LPARAM)"Message rejected - no such user"); + break; + case MESSAGE_REJECTED_INTERR:// Internal server error + ProtoBroadcastAckAsync(hContact, dwAckType, ACKRESULT_FAILED, (HANDLE)pmaHeader->seq, (LPARAM)"Internal server error"); + break; + case MESSAGE_REJECTED_LIMIT_EXCEEDED:// Offline messages limit exceeded + ProtoBroadcastAckAsync(hContact, dwAckType, ACKRESULT_FAILED, (HANDLE)pmaHeader->seq, (LPARAM)"Offline messages limit exceeded"); + break; + case MESSAGE_REJECTED_TOO_LARGE:// Message is too large + ProtoBroadcastAckAsync(hContact, dwAckType, ACKRESULT_FAILED, (HANDLE)pmaHeader->seq, (LPARAM)"Message is too large"); + break; + case MESSAGE_REJECTED_DENY_OFFMSG:// User does not accept offline messages + ProtoBroadcastAckAsync(hContact, dwAckType, ACKRESULT_FAILED, (HANDLE)pmaHeader->seq, (LPARAM)"User does not accept offline messages"); + break; + case MESSAGE_REJECTED_DENY_OFFFLSH:// User does not accept offline flash animation + ProtoBroadcastAckAsync(hContact, dwAckType, ACKRESULT_FAILED, (HANDLE)pmaHeader->seq, (LPARAM)"User does not accept offline flash animation"); + break; + default: + dwTemp = mir_snprintf((LPSTR)szBuff, SIZEOF(szBuff), "Undefined message delivery error, code: %lu", dwTemp); + ProtoBroadcastAckAsync(hContact, dwAckType, ACKRESULT_FAILED, (HANDLE)pmaHeader->seq, (LPARAM)szBuff, dwTemp+1); + break; + } + MraSendQueueFree(hSendQueueHandle, pmaHeader->seq); + } + // not found in queue + else if ( GetUL(&lpbDataCurrent) != MESSAGE_DELIVERED) + MraPopupShowFromAgentW(MRA_POPUP_TYPE_DEBUG, 0, TranslateW(L"MRIM_CS_MESSAGE_STATUS: not found in queue")); + break; + + case MRIM_CS_CONNECTION_PARAMS:// Изменение параметров соединения + *pdwPingPeriod = GetUL(&lpbDataCurrent); + *pdwNextPingSendTickTime = 0; // force send ping + MraSendCMD(MRIM_CS_PING, NULL, 0); + break; + + case MRIM_CS_USER_INFO: + while (lpbDataCurrent < lpbData + dwDataSize) { + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsString); + if ( !_strnicmp(lpsString.lpszData, "MESSAGES.TOTAL", 14)) { + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsString); + dwEmailMessagesTotal = StrToUNum32(lpsString.lpszData, lpsString.dwSize); + } + else if ( !_strnicmp(lpsString.lpszData, "MESSAGES.UNREAD", 15)) { + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsString); + dwEmailMessagesUnread = StrToUNum32(lpsString.lpszData, lpsString.dwSize); + } + else if ( !_strnicmp(lpsString.lpszData, "MRIM.NICKNAME", 13)) { + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsString); + mraSetLPSStringW(NULL, "Nick", &lpsString); + } + else if ( !_strnicmp(lpsString.lpszData, "client.endpoint", 15)) { + LPSTR lpszDelimiter; + + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsString); + dwStringSize = WideCharToMultiByte(MRA_CODE_PAGE, 0, lpsString.lpwszData, lpsString.dwSize, (LPSTR)szBuff, sizeof(szBuff), NULL, NULL); + lpszDelimiter = (LPSTR)MemoryFind(0, szBuff, dwStringSize, ":", 1); + if (lpszDelimiter) { + (*lpszDelimiter) = 0; + lpszDelimiter = (LPSTR)szBuff; + mraSetDword(NULL, "IP", HTONL(inet_addr(lpszDelimiter))); + } + } + else if ( !_strnicmp(lpsString.lpszData, "connect.xml", 11)) { + DebugPrintA(lpsString.lpszData); + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsString); + DebugPrintCRLFW(lpsString.lpwszData); + } + else if ( !_strnicmp(lpsString.lpszData, "micblog.show_title", 18)) { + DebugPrintA(lpsString.lpszData); + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsString); + DebugPrintCRLFW(lpsString.lpwszData); + } + else if ( !_strnicmp(lpsString.lpszData, "micblog.status.id", 17)) { + DWORDLONG dwBlogStatusID; + + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsString); + dwBlogStatusID = StrToUNum64(lpsString.lpszData, lpsString.dwSize); + mraWriteContactSettingBlob(NULL, DBSETTING_BLOGSTATUSID, &dwBlogStatusID, sizeof(DWORDLONG)); + } + else if ( !_strnicmp(lpsString.lpszData, "micblog.status.time", 19)) { + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsString); + mraSetDword(NULL, DBSETTING_BLOGSTATUSTIME, StrToUNum32(lpsString.lpszData, lpsString.dwSize)); + } + else if ( !_strnicmp(lpsString.lpszData, "micblog.status.text", 19)) { + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsString); + mraSetLPSStringW(NULL, DBSETTING_BLOGSTATUS, &lpsString); + } + else if ( !_strnicmp(lpsString.lpszData, "HAS_MYMAIL", 10)) { + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsString); + //mraSetDword(NULL, DBSETTING_BLOGSTATUSTIME, StrToUNum32(lpsString.lpszData, lpsString.dwSize)); + } + else if ( !_strnicmp(lpsString.lpszData, "mrim.status.open_search", 23)) { + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsString); + //mraSetDword(NULL, DBSETTING_BLOGSTATUSTIME, StrToUNum32(lpsString.lpszData, lpsString.dwSize)); + } + else if ( !_strnicmp(lpsString.lpszData, "rb.target.cookie", 16)) { + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsString); + //mraSetDword(NULL, DBSETTING_BLOGSTATUSTIME, StrToUNum32(lpsString.lpszData, lpsString.dwSize)); + } + else if ( !_strnicmp(lpsString.lpszData, "show_web_history_link", 21)) { + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsString); + //mraSetDword(NULL, DBSETTING_BLOGSTATUSTIME, StrToUNum32(lpsString.lpszData, lpsString.dwSize)); + } + else if ( !_strnicmp(lpsString.lpszData, "friends_suggest", 15)) { + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsString); + //mraSetDword(NULL, DBSETTING_BLOGSTATUSTIME, StrToUNum32(lpsString.lpszData, lpsString.dwSize)); + } + else if ( !_strnicmp(lpsString.lpszData, "timestamp", 9)) { + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsString); + //mraSetDword(NULL, DBSETTING_BLOGSTATUSTIME, StrToUNum32(lpsString.lpszData, lpsString.dwSize)); + } + else if ( !_strnicmp(lpsString.lpszData, "trusted_update", 14)) { + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsString); + //mraSetDword(NULL, DBSETTING_BLOGSTATUSTIME, StrToUNum32(lpsString.lpszData, lpsString.dwSize)); + } + else { + #ifdef _DEBUG + LPSTR lpszCurrentPos = (LPSTR)szBuff; + memmove(lpszCurrentPos, lpsString.lpszData, lpsString.dwSize); + lpszCurrentPos += lpsString.dwSize; + *((WORD*)lpszCurrentPos) = *((WORD*)": "); + lpszCurrentPos += sizeof(WORD); + + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsString); + memmove(lpszCurrentPos, lpsString.lpszData, lpsString.dwSize); + lpszCurrentPos += lpsString.dwSize; + *((WORD*)lpszCurrentPos) = *((WORD*)szCRLF); + lpszCurrentPos += sizeof(WORD);(*((WORD*)lpszCurrentPos)) = 0; + + DebugPrintCRLFA((LPSTR)szBuff); + DebugBreak(); + #endif + } + } + MraUpdateEmailStatus(NULL, 0, NULL, 0, 0, 0); + break; + + case MRIM_CS_OFFLINE_MESSAGE_ACK://Сообщение доставленное, пока пользователь не был подключен к сети + { + DWORD dwTime, dwFlags; + MRA_LPS lpsText, lpsRTFText, lpsMultiChatData; + LPBYTE lpbBuff = NULL; + DWORDLONG dwMsgUIDL = GetUIDL(&lpbDataCurrent); + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsString); + + if (MraOfflineMessageGet(&lpsString, &dwTime, &dwFlags, &lpsEMail, &lpsText, &lpsRTFText, &lpsMultiChatData, &lpbBuff) == NO_ERROR) { + dwTemp = MraRecvCommand_Message(dwTime, dwFlags, &lpsEMail, &lpsText, &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); + + mir_free(lpbBuff); + } + break; + + case MRIM_CS_AUTHORIZE_ACK: // Auth confirmation + { + BOOL bAdded; + BYTE btBuff[BUFF_SIZE_BLOB]; + DBEVENTINFO dbei = {0}; + + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsEMail); + hContact = MraHContactFromEmail(lpsEMail.lpszData, lpsEMail.dwSize, TRUE, TRUE, &bAdded); + if (bAdded) MraUpdateContactInfo(hContact); + + if (IsEMailChatAgent(lpsEMail.lpszData, lpsEMail.dwSize) == FALSE) { + dbei.cbSize = sizeof(dbei); + dbei.szModule = m_szModuleName; + dbei.timestamp = (DWORD)_time32(NULL); + dbei.flags = 0; + dbei.eventType = EVENTTYPE_ADDED; + //dbei.cbBlob = 0; + CreateBlobFromContact(hContact, NULL, 0, (LPBYTE)&btBuff, SIZEOF(btBuff), &dwStringSize); + dbei.cbBlob = dwStringSize; + dbei.pBlob = btBuff; + + CallService(MS_DB_EVENT_ADD, (WPARAM)NULL, (LPARAM)&dbei); + } + + GetContactBasicInfoW(hContact, NULL, NULL, NULL, &dwTemp, NULL, NULL, 0, NULL, NULL, 0, NULL, NULL, 0, NULL); + dwTemp &= ~CONTACT_INTFLAG_NOT_AUTHORIZED; + SetContactBasicInfoW(hContact, SCBIFSI_LOCK_CHANGES_EVENTS, SCBIF_SERVER_FLAG, 0, 0, 0, dwTemp, 0, NULL, 0, NULL, 0, NULL, 0); + mraSetDword(hContact, "HooksLocked", TRUE); + DBDeleteContactSetting(hContact, "CList", "NotOnList"); + mraSetDword(hContact, "HooksLocked", FALSE); + } + break; + + case MRIM_CS_MPOP_SESSION: // Web auth key + if ( GetUL(&lpbDataCurrent)) { + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsString); + MraMPopSessionQueueSetNewMPopKey(hMPopSessionQueue, lpsString.lpszData, lpsString.dwSize); + MraMPopSessionQueueStart(hMPopSessionQueue); + } + else { //error + MraPopupShowFromAgentW(MRA_POPUP_TYPE_WARNING, 0, TranslateW(L"Server error: cant get MPOP key for web authorize")); + MraMPopSessionQueueFlush(hMPopSessionQueue); + } + break; + + ///////////////////////////////////////////////////////////////////////////////////// + case MRIM_CS_FILE_TRANSFER: + { + BOOL bAdded; + DWORD dwIDRequest, dwFilesTotalSize; + MRA_LPS lpsFiles = {0}, lpsFilesW = {0}, lpsAddreses = {0}; + + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsEMail);// LPS TO/FROM ANSI + dwIDRequest = GetUL(&lpbDataCurrent);// DWORD id_request + dwFilesTotalSize = GetUL(&lpbDataCurrent);// DWORD FILESIZE + if ( GetUL(&lpbDataCurrent)) { + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsFiles);// LPS Files (FileName;FileSize;FileName;FileSize;) ANSI + if ( GetUL(&lpbDataCurrent)) { // LPS DESCRIPTION + dwTemp = GetUL(&lpbDataCurrent); + DebugBreakIf(dwTemp != 1); + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsFilesW);// LPS Files (FileName;FileSize;FileName;FileSize;) UNICODE + } + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsAddreses);// LPS Conn (IP:Port;IP:Port;) ANSI + } + + hContact = MraHContactFromEmail(lpsEMail.lpszData, lpsEMail.dwSize, TRUE, TRUE, &bAdded); + if (bAdded) MraUpdateContactInfo(hContact); + + bAdded = FALSE; + if (lpsFilesW.dwSize == 0) { + lpsFilesW.lpwszData = (LPWSTR)mir_calloc((lpsFiles.dwSize+MAX_PATH)*sizeof(WCHAR)); + if (lpsFilesW.lpwszData) { + lpsFilesW.dwSize = MultiByteToWideChar(MRA_CODE_PAGE, 0, lpsFiles.lpszData, lpsFiles.dwSize, lpsFilesW.lpwszData, (lpsFiles.dwSize+MAX_PATH)); + bAdded = TRUE; + } + } + + if (lpsFilesW.dwSize) + MraFilesQueueAddReceive(hFilesQueueHandle, 0, hContact, dwIDRequest, lpsFilesW.lpwszData, lpsFilesW.dwSize, lpsAddreses.lpszData, lpsAddreses.dwSize); + if (bAdded) + mir_free(lpsFilesW.lpwszData); + } + break; + + case MRIM_CS_FILE_TRANSFER_ACK: + dwAckType = GetUL(&lpbDataCurrent);// DWORD status + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsEMail);// LPS TO/FROM + dwTemp = GetUL(&lpbDataCurrent);// DWORD id_request + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsString);// LPS DESCRIPTION + + switch (dwAckType) { + case FILE_TRANSFER_STATUS_OK:// игнорируем, мы и так уже слушаем порт(ждём), то что кто то согласился ничего не меняет + //hContact = MraHContactFromEmail(lpsEMail.lpszData, lpsEMail.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, lpsString.lpszData, lpsString.dwSize); + break; + default:// ## unknown error + mir_sntprintf(szBuff, SIZEOF(szBuff), TranslateW(L"MRIM_CS_FILE_TRANSFER_ACK: unknown error, code: %lu"), dwAckType); + ShowFormattedErrorMessage(szBuff, NO_ERROR); + break; + } + break; + + ///////////////////////////////////////////////////////////////////////////////////// + case MRIM_CS_USER_STATUS://Смена статуса другого пользователя + { + BOOL bAdded; + DWORD dwStatus, dwXStatus, dwFutureFlags; + MRA_LPS lpsSpecStatusUri, lpsStatusTitle, lpsStatusDesc, lpsUserAgentFormated; + + dwStatus = GetUL(&lpbDataCurrent); + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsSpecStatusUri); + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsStatusTitle); + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsStatusDesc); + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsEMail); + dwFutureFlags = GetUL(&lpbDataCurrent);// com_support ( >= 1.14) + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsUserAgentFormated); + + if ((hContact = MraHContactFromEmail(lpsEMail.lpszData, lpsEMail.dwSize, TRUE, TRUE, &bAdded))) { + if (bAdded) + MraUpdateContactInfo(hContact); + + dwTemp = GetMiradaStatusFromMraStatus(dwStatus, GetMraXStatusIDFromMraUriStatus(lpsSpecStatusUri.lpszData, lpsSpecStatusUri.dwSize), &dwXStatus); + + MraContactCapabilitiesSet(hContact, dwFutureFlags); + mraSetByte(hContact, DBSETTING_XSTATUSID, (BYTE)dwXStatus); + mraSetLPSStringW(hContact, DBSETTING_XSTATUSNAME, &lpsStatusTitle); + mraSetLPSStringW(hContact, DBSETTING_XSTATUSMSG, &lpsStatusDesc); + + if (dwTemp != ID_STATUS_OFFLINE) { // пишем клиента только если юзер не отключён, иначе не затираем старое + if (lpsUserAgentFormated.dwSize) { + if (mraGetByte(NULL, "MirVerRaw", MRA_DEFAULT_MIRVER_RAW) == FALSE) { + MraGetVersionStringFromFormatted(lpsUserAgentFormated.lpszData, lpsUserAgentFormated.dwSize, (LPSTR)szBuff, SIZEOF(szBuff), &dwStringSize); + lpsUserAgentFormated.lpszData = (LPSTR)szBuff; + lpsUserAgentFormated.dwSize = dwStringSize; + } + } + else { // хз чё за клиент + lpsUserAgentFormated.lpszData = MIRVER_UNKNOWN; + lpsUserAgentFormated.dwSize = (sizeof(MIRVER_UNKNOWN)-1); + } + mraSetLPSStringA(hContact, "MirVer", &lpsUserAgentFormated); + } + + if (dwTemp == MraGetContactStatus(hContact)) {// меняем шило на шило, подозрительно? ;) + if (dwTemp == ID_STATUS_OFFLINE) { // was/now invisible + WCHAR szEMail[MAX_EMAIL_LEN]; + + mraGetStaticStringW(hContact, "e-mail", szEMail, SIZEOF(szEMail), NULL); + mir_sntprintf(szBuff, SIZEOF(szBuff), L"%s <%s> - %s", GetContactNameW(hContact), szEMail, TranslateW(L"invisible status changed")); + MraPopupShowFromContactW(hContact, MRA_POPUP_TYPE_INFORMATION, 0, szBuff); + + MraSetContactStatus(hContact, ID_STATUS_INVISIBLE); + } + } + MraSetContactStatus(hContact, dwTemp); + SetExtraIcons(hContact); + } + } + break; + + case MRIM_CS_LOGOUT:// Пользователь отключен из-за параллельного входа с его логином. + if ( GetUL(&lpbDataCurrent) == LOGOUT_NO_RELOGIN_FLAG) + ShowFormattedErrorMessage(L"Another user connected with your login", NO_ERROR); + *pbContinue = FALSE; + break; + + case MRIM_CS_ADD_CONTACT_ACK: + case MRIM_CS_MODIFY_CONTACT_ACK: + if ( !MraSendQueueFind(hSendQueueHandle, pmaHeader->seq, NULL, &hContact, &dwAckType, (LPBYTE*)&lpsString.lpszData, &lpsString.dwSize)) { + dwTemp = GetUL(&lpbDataCurrent); + switch (dwTemp) { + case CONTACT_OPER_SUCCESS:// ## добавление произведено успешно + if (pmaHeader->msg == MRIM_CS_ADD_CONTACT_ACK) SetContactBasicInfoW(hContact, 0, (SCBIF_ID|SCBIF_SERVER_FLAG), GetUL(&lpbDataCurrent), 0, 0, CONTACT_INTFLAG_NOT_AUTHORIZED, 0, NULL, 0, NULL, 0, NULL, 0); + break; + case CONTACT_OPER_ERROR:// ## переданные данные были некорректны + ShowFormattedErrorMessage(L"Sended data is 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, NULL, 0, NULL, 0, NULL, 0); + ShowFormattedErrorMessage(L"User does not registred", NO_ERROR); + break; + case CONTACT_OPER_INVALID_INFO:// ## некорректное имя пользователя + ShowFormattedErrorMessage(L"Invalid user name", NO_ERROR); + break; + case CONTACT_OPER_USER_EXISTS:// ## пользователь уже есть в контакт-листе + ShowFormattedErrorMessage(L"User allready added", NO_ERROR); + break; + case CONTACT_OPER_GROUP_LIMIT:// ## превышено максимально допустимое количество групп (20) + ShowFormattedErrorMessage(L"Group limit is 20", NO_ERROR); + break; + default:// ## unknown error + mir_sntprintf(szBuff, SIZEOF(szBuff), TranslateW(L"MRIM_CS_*_CONTACT_ACK: unknown server error, code: %lu"), dwTemp); + MraPopupShowFromAgentW(MRA_POPUP_TYPE_DEBUG, 0, szBuff); + break; + } + MraSendQueueFree(hSendQueueHandle, pmaHeader->seq); + } + else MraPopupShowFromAgentW(MRA_POPUP_TYPE_DEBUG, 0, TranslateW(L"MRIM_CS_*_CONTACT_ACK: not found in queue")); + break; + + case MRIM_CS_ANKETA_INFO: + if ( !MraSendQueueFind(hSendQueueHandle, pmaHeader->seq, NULL, &hContact, &dwAckType, (LPBYTE*)&lpsString.lpszData, &lpsString.dwSize)) { + switch (GetUL(&lpbDataCurrent)) { + case MRIM_ANKETA_INFO_STATUS_OK:// поиск успешно завершен + { + DWORD dwFeildsNum, dwMaxRows, dwServerTime, dwStatus; + size_t i; + MRA_LPS *pmralpsFeilds, *pmralpsValues; + + dwFeildsNum = GetUL(&lpbDataCurrent); + dwMaxRows = GetUL(&lpbDataCurrent); + dwServerTime = GetUL(&lpbDataCurrent); + + pmralpsFeilds = (MRA_LPS*)mir_calloc(((dwFeildsNum*2)+4)*sizeof(MRA_LPS)); + if (pmralpsFeilds) { + pmralpsValues = (pmralpsFeilds+dwFeildsNum); + // read headers name + for (i = 0; i < dwFeildsNum; i++) { + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &pmralpsFeilds[i]); + DebugPrintCRLFA(pmralpsFeilds[i].lpszData); + } + + while (lpbDataCurrent < lpbData+dwDataSize) { + // read values + for (i = 0;i 9) {// calc "Age" + SYSTEMTIME stTime = {0}; + + stTime.wYear = (WORD)StrToUNum32(pmralpsValues[i].lpszData, 4); + stTime.wMonth = (WORD)StrToUNum32((pmralpsValues[i].lpszData+5), 2); + stTime.wDay = (WORD)StrToUNum32((pmralpsValues[i].lpszData+8), 2); + mraSetWord(hContact, "BirthYear", stTime.wYear); + mraSetByte(hContact, "BirthMonth", (BYTE)stTime.wMonth); + mraSetByte(hContact, "BirthDay", (BYTE)stTime.wDay); + + mraSetWord(hContact, "Age", (WORD)GetYears(&stTime)); + } + else { + mraDelValue(hContact, "BirthYear"); + mraDelValue(hContact, "BirthMonth"); + mraDelValue(hContact, "BirthDay"); + mraDelValue(hContact, "Age"); + } + } + else if ( !_strnicmp(pmralpsFeilds[i].lpszData, "City_id", 7)) { + dwTemp = StrToUNum32(pmralpsValues[i].lpszData, pmralpsValues[i].dwSize); + if (dwTemp) { + for (size_t j = 0;mrapPlaces[j].lpszData;j++) { + if (mrapPlaces[j].dwCityID == dwTemp) { + mraSetStringW(hContact, "City", mrapPlaces[j].lpszData); + break; + } + } + } + else mraDelValue(hContact, "City"); + } + else if ( !_strnicmp(pmralpsFeilds[i].lpszData, "Location", 8)) + mraSetLPSStringW(hContact, "About", &pmralpsValues[i]); + else if ( !_strnicmp(pmralpsFeilds[i].lpszData, "Zodiac", 6)) + ; + else if ( !_strnicmp(pmralpsFeilds[i].lpszData, "BMonth", 6)) + ; + else if ( !_strnicmp(pmralpsFeilds[i].lpszData, "BDay", 4)) + ; + else if ( !_strnicmp(pmralpsFeilds[i].lpszData, "Country_id", 10)) { + dwTemp = StrToUNum32(pmralpsValues[i].lpszData, pmralpsValues[i].dwSize); + if (dwTemp) { + for (size_t j = 0; mrapPlaces[j].lpszData; j++) { + if (mrapPlaces[j].dwCountryID == dwTemp) { + mraSetStringW(hContact, "Country", mrapPlaces[j].lpszData); + break; + } + } + } + else mraDelValue(hContact, "Country"); + } + else if ( !_strnicmp(pmralpsFeilds[i].lpszData, "Phone", 5)) { + mraDelValue(hContact, "Phone"); + mraDelValue(hContact, "Cellular"); + mraDelValue(hContact, "Fax"); + + if (pmralpsValues[i].dwSize) { + lpsString.lpszData = pmralpsValues[i].lpszData; + LPSTR lpszCurPos = (LPSTR)MemoryFindByte(0, pmralpsValues[i].lpszData, pmralpsValues[i].dwSize, ','); + if (lpszCurPos) + lpsString.dwSize = (lpszCurPos-lpsString.lpszData); + else + lpsString.dwSize = ((pmralpsValues[i].lpszData+pmralpsValues[i].dwSize)-lpsString.lpszData); + + mraSetLPSStringA(hContact, "Phone", &lpsString); + + if (lpszCurPos) { + lpsString.lpszData = (++lpszCurPos); + lpszCurPos = (LPSTR)MemoryFindByte((lpszCurPos-pmralpsValues[i].lpszData), pmralpsValues[i].lpszData, pmralpsValues[i].dwSize, ','); + if (lpszCurPos) + lpsString.dwSize = (lpszCurPos-lpsString.lpszData); + else + lpsString.dwSize = ((pmralpsValues[i].lpszData+pmralpsValues[i].dwSize)-lpsString.lpszData); + + mraSetLPSStringA(hContact, "Cellular", &lpsString); + } + + if (lpszCurPos) { + lpsString.lpszData = (++lpszCurPos); + lpszCurPos = (LPSTR)MemoryFindByte((lpszCurPos-pmralpsValues[i].lpszData), pmralpsValues[i].lpszData, pmralpsValues[i].dwSize, ','); + if (lpszCurPos) + lpsString.dwSize = (lpszCurPos-lpsString.lpszData); + else + lpsString.dwSize = ((pmralpsValues[i].lpszData+pmralpsValues[i].dwSize)-lpsString.lpszData); + + mraSetLPSStringA(hContact, "Fax", &lpsString); + } + } + } + else if ( !_strnicmp(pmralpsFeilds[i].lpszData, "mrim_status", 11)) { + if (pmralpsValues[i].dwSize) { + DWORD dwID, dwContactSeverFlags; + + GetContactBasicInfoW(hContact, &dwID, NULL, NULL, &dwContactSeverFlags, NULL, NULL, 0, NULL, NULL, 0, NULL, NULL, 0, NULL); + // для авторизованного нам и так присылают правильный статус + if (dwID == -1 || (dwContactSeverFlags & CONTACT_INTFLAG_NOT_AUTHORIZED)) { + dwStatus = StrHexToUNum32(pmralpsValues[i].lpszData, pmralpsValues[i].dwSize); + MraSetContactStatus(hContact, GetMiradaStatusFromMraStatus(dwStatus, MRA_MIR_XSTATUS_NONE, NULL)); + mraSetByte(hContact, DBSETTING_XSTATUSID, (BYTE)MRA_MIR_XSTATUS_NONE); + } + } + } + else if ( !_strnicmp(pmralpsFeilds[i].lpszData, "status_uri", 10)) { + if (pmralpsValues[i].dwSize) { + DWORD dwID, dwContactSeverFlags, dwXStatus; + + GetContactBasicInfoW(hContact, &dwID, NULL, NULL, &dwContactSeverFlags, NULL, NULL, 0, NULL, NULL, 0, NULL, NULL, 0, NULL); + if (dwID == -1 || dwContactSeverFlags&CONTACT_INTFLAG_NOT_AUTHORIZED) { + MraSetContactStatus(hContact, GetMiradaStatusFromMraStatus(dwStatus, GetMraXStatusIDFromMraUriStatus(pmralpsValues[i].lpszData, pmralpsValues[i].dwSize), &dwXStatus)); + mraSetByte(hContact, DBSETTING_XSTATUSID, (BYTE)dwXStatus); + } + } + } + else if ( !_strnicmp(pmralpsFeilds[i].lpszData, "status_title", 12)) { + if (pmralpsValues[i].dwSize) { + DWORD dwID, dwContactSeverFlags; + + GetContactBasicInfoW(hContact, &dwID, NULL, NULL, &dwContactSeverFlags, NULL, NULL, 0, NULL, NULL, 0, NULL, NULL, 0, NULL); + if (dwID == -1 || dwContactSeverFlags&CONTACT_INTFLAG_NOT_AUTHORIZED) + mraSetLPSStringW(hContact, DBSETTING_XSTATUSNAME, &pmralpsValues[i]); + } + } + else if ( !_strnicmp(pmralpsFeilds[i].lpszData, "status_desc", 11)) { + if (pmralpsValues[i].dwSize) { + DWORD dwID, dwContactSeverFlags; + + GetContactBasicInfoW(hContact, &dwID, NULL, NULL, &dwContactSeverFlags, NULL, NULL, 0, NULL, NULL, 0, NULL, NULL, 0, NULL); + if (dwID == -1 || dwContactSeverFlags&CONTACT_INTFLAG_NOT_AUTHORIZED) + mraSetLPSStringW(hContact, DBSETTING_XSTATUSMSG, &pmralpsValues[i]); + } + } + else {// for DEBUG ONLY + #ifdef _DEBUG + DebugPrintCRLFA(pmralpsFeilds[i].lpszData); + DebugPrintCRLFA(pmralpsValues[i].lpszData); + //DebugBreak(); + #endif + } + } + } + else if (dwAckType == ACKTYPE_SEARCH) { + WCHAR szNick[MAX_EMAIL_LEN] = {0}, + szFirstName[MAX_EMAIL_LEN] = {0}, + szLastName[MAX_EMAIL_LEN] = {0}, + szEMail[MAX_EMAIL_LEN] = {0}; + MRA_LPS mralpsUsernameValue = {0}; + PROTOSEARCHRESULT psr = {0}; + + psr.cbSize = sizeof(psr); + psr.flags = PSR_UNICODE; + psr.nick = szNick; + psr.firstName = szFirstName; + psr.lastName = szLastName; + psr.email = szEMail; + psr.id = szEMail; + + for (i = 0;iseq, (LPARAM)&psr); + } + }// end while + + mir_free(pmralpsFeilds); + } + } + + switch (dwAckType) { + case ACKTYPE_GETINFO: + ProtoBroadcastAckAsync(hContact, dwAckType, ACKRESULT_SUCCESS, (HANDLE)1, 0); + break; + case ACKTYPE_SEARCH: + default: + ProtoBroadcastAckAsync(hContact, dwAckType, ACKRESULT_SUCCESS, (HANDLE)pmaHeader->seq, 0); + break; + } + break; + + case MRIM_ANKETA_INFO_STATUS_NOUSER:// не найдено ни одной подходящей записи + SetContactBasicInfoW(hContact, 0, SCBIF_SERVER_FLAG, 0, 0, 0, -1, 0, NULL, 0, NULL, 0, NULL, 0); + case MRIM_ANKETA_INFO_STATUS_DBERR:// ошибка базы данных + case MRIM_ANKETA_INFO_STATUS_RATELIMERR:// слишком много запросов, поиск временно запрещен + switch (dwAckType) { + case ACKTYPE_GETINFO: + ProtoBroadcastAckAsync(hContact, dwAckType, ACKRESULT_FAILED, (HANDLE)1, 0); + break; + case ACKTYPE_SEARCH: + ProtoBroadcastAckAsync(hContact, dwAckType, ACKRESULT_SUCCESS, (HANDLE)pmaHeader->seq, 0); + break; + default: + DebugBreak(); + break; + } + break; + default:// unknown + DebugBreak(); + break; + } + MraSendQueueFree(hSendQueueHandle, pmaHeader->seq); + } + else MraPopupShowFromAgentW(MRA_POPUP_TYPE_DEBUG, 0, TranslateW(L"MRIM_ANKETA_INFO: not found in queue")); + break; + + case MRIM_CS_MAILBOX_STATUS: + dwTemp = GetUL(&lpbDataCurrent); + if (dwTemp > dwEmailMessagesTotal) + dwEmailMessagesTotal += (dwTemp - dwEmailMessagesUnread); + + dwAckType = dwEmailMessagesUnread;// save old value + dwEmailMessagesUnread = dwTemp;// store new value + if (mraGetByte(NULL, "IncrementalNewMailNotify", MRA_DEFAULT_INC_NEW_MAIL_NOTIFY) == 0 || dwAckType 1) { // все параметры правильно инициализированны! + #ifdef _DEBUG + memmove(szBuff, mralpsGroupName.lpszData, mralpsGroupName.dwSize); + szBuff[(mralpsGroupName.dwSize/sizeof(WCHAR))] = 0; + DebugPrintW(szBuff); + + mir_snprintf((LPSTR)szBuff, SIZEOF(szBuff), ": flags: %lu (", dwGroupFlags); + DebugPrintA((LPSTR)szBuff); + if (dwGroupFlags&CONTACT_FLAG_REMOVED) DebugPrintA("CONTACT_FLAG_REMOVED, "); + if (dwGroupFlags&CONTACT_FLAG_GROUP) DebugPrintA("CONTACT_FLAG_GROUP, "); + if (dwGroupFlags&CONTACT_FLAG_INVISIBLE) DebugPrintA("CONTACT_FLAG_INVISIBLE, "); + if (dwGroupFlags&CONTACT_FLAG_VISIBLE) DebugPrintA("CONTACT_FLAG_VISIBLE, "); + if (dwGroupFlags&CONTACT_FLAG_IGNORE) DebugPrintA("CONTACT_FLAG_IGNORE, "); + if (dwGroupFlags&CONTACT_FLAG_SHADOW) DebugPrintA("CONTACT_FLAG_SHADOW, "); + if (dwGroupFlags&CONTACT_FLAG_AUTHORIZED) DebugPrintA("CONTACT_FLAG_AUTHORIZED, "); + if (dwGroupFlags&CONTACT_FLAG_MULTICHAT) DebugPrintA("CONTACT_FLAG_MULTICHAT, "); + if (dwGroupFlags&CONTACT_FLAG_UNICODE_NAME) DebugPrintA("CONTACT_FLAG_UNICODE_NAME, "); + if (dwGroupFlags&CONTACT_FLAG_PHONE) DebugPrintA("CONTACT_FLAG_PHONE, "); + DebugPrintCRLFA(")"); + #endif//*/ + } + dwID++; + }// end for (processing groups) + + DebugPrintCRLFW(L"Contacts:"); + DebugPrintCRLFA(szContactMask); + dwID = 20; + while (lpbDataCurrent < lpbData + dwDataSize) { + dwControlParam = 0; + for (j = 0; j < dwContactMaskSize; j++) { //enumerating parameters + switch (szContactMask[j]) { + case 's'://LPS + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsString); + break; + case 'u'://UL + dwTemp = GetUL(&lpbDataCurrent); + break; + case 'z'://sz + lpsString.lpszData = (LPSTR)lpbDataCurrent; + lpsString.dwSize = lstrlenA((LPSTR)lpbDataCurrent); + lpbDataCurrent += lpsString.dwSize; + DebugBreak(); + break; + } + + if (j == 0 && szContactMask[j] == 'u') { // Flags + dwContactFlag = dwTemp; + dwControlParam++; + } + else if (j == 1 && szContactMask[j] == 'u') { // Group id + dwGroupID = dwTemp; + dwControlParam++; + } + else if (j == 2 && szContactMask[j] == 's') { // Email + lpsEMail = lpsString; + dwControlParam++; + } + else if (j == 3 && szContactMask[j] == 's') { // Nick + mralpsNick = lpsString; + dwControlParam++; + } + else if (j == 4 && szContactMask[j] == 'u') { // Server flags + dwContactSeverFlags = dwTemp; + dwControlParam++; + } + else if (j == 5 && szContactMask[j] == 'u') { // Status + dwStatus = dwTemp; + dwControlParam++; + } + else if (j == 6 && szContactMask[j] == 's') { // Custom Phone number, + mralpsCustomPhones = lpsString; + dwControlParam++; + } + else if (j == 7 && szContactMask[j] == 's') { // spec_status_uri + lpsSpecStatusUri = lpsString; + dwControlParam++; + } + else if (j == 8 && szContactMask[j] == 's') { // status_title + lpsStatusTitle = lpsString; + dwControlParam++; + } + else if (j == 9 && szContactMask[j] == 's') { // status_desc + lpsStatusDesc = lpsString; + dwControlParam++; + } + else if (j == 10 && szContactMask[j] == 'u') { // com_support (future flags) + dwFutureFlags = dwTemp; + dwControlParam++; + } + else if (j == 11 && szContactMask[j] == 's') { // user_agent (formated string) + lpsUserAgentFormated = lpsString; + dwControlParam++; + } + else if (j == 12 && szContactMask[j] == 'u') { // BlogStatusID + dwBlogStatusID.LowPart = dwTemp; + dwControlParam++; + } + else if (j == 13 && szContactMask[j] == 'u') { // BlogStatusID + dwBlogStatusID.HighPart = dwTemp; + dwControlParam++; + } + else if (j == 14 && szContactMask[j] == 'u') { // BlogStatusTime + dwBlogStatusTime = dwTemp; + dwControlParam++; + } + else if (j == 15 && szContactMask[j] == 's') { // BlogStatus + lpsBlogStatus = lpsString; + dwControlParam++; + } + else if (j == 16 && szContactMask[j] == 's') { // BlogStatusMusic + lpsBlogStatusMusic = lpsString; + dwControlParam++; + } + else if (j == 17 && szContactMask[j] == 's') { // BlogStatusSender // ignory + lpsString = lpsString; + dwControlParam++; + } + else if (j == 18 && szContactMask[j] == 's') { // geo data ? + lpsString = lpsString; + dwControlParam++; + } + else if (j == 19 && szContactMask[j] == 's') { // ?????? ? + lpsString = lpsString; + dwControlParam++; + DebugBreakIf(lpsString.dwSize); + } + else { + if (szContactMask[j] == 's') { + if (lpsString.dwSize) + DebugPrintCRLFW(lpsString.lpwszData); + } + else if (szContactMask[j] == 'u') { + mir_snprintf((LPSTR)szBuff, SIZEOF(szBuff), "%lu, ", dwTemp);//; + DebugPrintCRLFA((LPSTR)szBuff); + } + else DebugBreak(); + } + } + + #ifdef _DEBUG + mir_snprintf((LPSTR)szBuff, SIZEOF(szBuff), "ID: %lu, Group id: %lu, ", dwID, dwGroupID); + DebugPrintA((LPSTR)szBuff); + + memmove(szBuff, lpsEMail.lpszData, lpsEMail.dwSize); + szBuff[(lpsEMail.dwSize/sizeof(WCHAR))] = 0; + DebugPrintA((LPSTR)szBuff); + + mir_snprintf((LPSTR)szBuff, SIZEOF(szBuff), ": flags: %lu (", dwContactFlag); + DebugPrintA((LPSTR)szBuff); + if (dwContactFlag&CONTACT_FLAG_REMOVED) DebugPrintA("CONTACT_FLAG_REMOVED, "); + if (dwContactFlag&CONTACT_FLAG_GROUP) DebugPrintA("CONTACT_FLAG_GROUP, "); + if (dwContactFlag&CONTACT_FLAG_INVISIBLE) DebugPrintA("CONTACT_FLAG_INVISIBLE, "); + if (dwContactFlag&CONTACT_FLAG_VISIBLE) DebugPrintA("CONTACT_FLAG_VISIBLE, "); + if (dwContactFlag&CONTACT_FLAG_IGNORE) DebugPrintA("CONTACT_FLAG_IGNORE, "); + if (dwContactFlag&CONTACT_FLAG_SHADOW) DebugPrintA("CONTACT_FLAG_SHADOW, "); + if (dwContactFlag&CONTACT_FLAG_AUTHORIZED) DebugPrintA("CONTACT_FLAG_AUTHORIZED, "); + if (dwContactFlag&CONTACT_FLAG_MULTICHAT) DebugPrintA("CONTACT_FLAG_MULTICHAT, "); + if (dwContactFlag&CONTACT_FLAG_UNICODE_NAME)DebugPrintA("CONTACT_FLAG_UNICODE_NAME, "); + if (dwContactFlag&CONTACT_FLAG_PHONE) DebugPrintA("CONTACT_FLAG_PHONE, "); + DebugPrintA(")"); + + mir_snprintf((LPSTR)szBuff, SIZEOF(szBuff), ": server flags: %lu (", dwContactSeverFlags); + DebugPrintA((LPSTR)szBuff); + if (dwContactSeverFlags&CONTACT_INTFLAG_NOT_AUTHORIZED) DebugPrintA("CONTACT_INTFLAG_NOT_AUTHORIZED, "); + DebugPrintCRLFA(")"); + #endif + + // add/modify contact + if (dwGroupID != 103)//***deb filtering phone/sms contats + if ( _strnicmp(lpsEMail.lpszData, "phone", 5)) + if (dwControlParam>5)// все параметры правильно инициализированны! + if ((dwContactFlag&(CONTACT_FLAG_GROUP|CONTACT_FLAG_REMOVED)) == 0) { + hContact = MraHContactFromEmail(lpsEMail.lpszData, lpsEMail.dwSize, TRUE, FALSE, &bAdded); + if (hContact) { + // already in list, remove the duplicate + if (GetContactBasicInfoW(hContact, &dwTemp, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, 0, NULL, NULL, 0, NULL) == NO_ERROR && dwTemp != -1) { + dwTemp = dwTemp; + DebugBreak(); + } + else { + dwTemp = GetMiradaStatusFromMraStatus(dwStatus, GetMraXStatusIDFromMraUriStatus(lpsSpecStatusUri.lpszData, lpsSpecStatusUri.dwSize), &dwXStatus); + if ((dwContactFlag&CONTACT_FLAG_UNICODE_NAME)) + mralpsNick.dwSize /= sizeof(WCHAR); + + 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, NULL, 0, mralpsNick.lpwszData, mralpsNick.dwSize, mralpsCustomPhones.lpszData, mralpsCustomPhones.dwSize); + // request user info from server + MraUpdateContactInfo(hContact); + } + else { //****deb - check group ID param + SetContactBasicInfoW(hContact, SCBIFSI_LOCK_CHANGES_EVENTS, (SCBIF_ID|SCBIF_GROUP_ID|SCBIF_SERVER_FLAG|SCBIF_STATUS), dwID, dwGroupID, dwContactFlag, dwContactSeverFlags, dwTemp, NULL, 0, mralpsNick.lpwszData, mralpsNick.dwSize, mralpsCustomPhones.lpszData, mralpsCustomPhones.dwSize); + if (mralpsNick.dwSize == 0) { // set the server-side nick + lstrcpynW(szBuff, GetContactNameW(hContact), SIZEOF(szBuff)); + mralpsNick.lpwszData = szBuff; + mralpsNick.dwSize = lstrlenW(mralpsNick.lpwszData); + + MraModifyContactW(hContact, dwID, dwContactFlag, dwGroupID, lpsEMail.lpszData, lpsEMail.dwSize, mralpsNick.lpwszData, mralpsNick.dwSize, mralpsCustomPhones.lpszData, mralpsCustomPhones.dwSize); + } + } + + MraContactCapabilitiesSet(hContact, dwFutureFlags); + mraSetByte(hContact, DBSETTING_XSTATUSID, (BYTE)dwXStatus); + mraSetLPSStringW(hContact, DBSETTING_XSTATUSNAME, &lpsStatusTitle); + mraSetLPSStringW(hContact, DBSETTING_XSTATUSMSG, &lpsStatusDesc); + mraSetDword(hContact, DBSETTING_BLOGSTATUSTIME, dwBlogStatusTime); + mraWriteContactSettingBlob(hContact, DBSETTING_BLOGSTATUSID, &dwBlogStatusID.QuadPart, sizeof(DWORDLONG)); + mraSetLPSStringW(hContact, DBSETTING_BLOGSTATUS, &lpsBlogStatus); + mraSetLPSStringW(hContact, DBSETTING_BLOGSTATUSMUSIC, &lpsBlogStatusMusic); + if ( IsXStatusValid(dwXStatus)) + SetExtraIcons(hContact); + + if (dwTemp != ID_STATUS_OFFLINE) { // пишем клиента только если юзер не отключён, иначе не затираем старое + if (lpsUserAgentFormated.dwSize) { + if (mraGetByte(NULL, "MirVerRaw", MRA_DEFAULT_MIRVER_RAW) == FALSE) { + MraGetVersionStringFromFormatted(lpsUserAgentFormated.lpszData, lpsUserAgentFormated.dwSize, (LPSTR)szBuff, SIZEOF(szBuff), &dwStringSize); + lpsUserAgentFormated.lpszData = (LPSTR)szBuff; + lpsUserAgentFormated.dwSize = dwStringSize; + } + } + else { + lpsUserAgentFormated.lpszData = MIRVER_UNKNOWN; + lpsUserAgentFormated.dwSize = (sizeof(MIRVER_UNKNOWN)-1); + } + mraSetLPSStringA(hContact, "MirVer", &lpsUserAgentFormated); + } + + if (dwContactSeverFlags & CONTACT_INTFLAG_NOT_AUTHORIZED) + if (mraGetByte(NULL, "AutoAuthRequestOnLogon", MRA_DEFAULT_AUTO_AUTH_REQ_ON_LOGON)) + CallProtoService(m_szModuleName, MRA_REQ_AUTH, (WPARAM)hContact, 0); + } + } + } + dwID++; + }// end while (processing contacts) + + // post processing contact list + { + CHAR szEMail[MAX_EMAIL_LEN], szPhones[MAX_EMAIL_LEN]; + WCHAR wszAuthMessage[MAX_PATH], wszNick[MAX_EMAIL_LEN]; + size_t dwEMailSize, dwNickSize, dwPhonesSize, dwAuthMessageSize; + + if (mraGetStaticStringW(NULL, "AuthMessage", wszAuthMessage, SIZEOF(wszAuthMessage), &dwAuthMessageSize) == FALSE) { // def auth message + lstrcpynW(wszAuthMessage, TranslateW(MRA_DEFAULT_AUTH_MESSAGE), SIZEOF(wszAuthMessage)); + dwAuthMessageSize = lstrlenW(wszAuthMessage); + } + + for (hContact = db_find_first();hContact != NULL;hContact = db_find_next(hContact)) { + if (GetContactBasicInfoW(hContact, &dwID, NULL, NULL, NULL, NULL, szEMail, SIZEOF(szEMail), &dwEMailSize, NULL, 0, NULL, NULL, 0, NULL) == NO_ERROR) + if (dwID == -1) { + if (IsEMailChatAgent(szEMail, dwEMailSize)) {// чат: ещё раз запросим авторизацию, пометим как видимый в списке, постоянный + DBDeleteContactSetting(hContact, "CList", "Hidden"); + DBDeleteContactSetting(hContact, "CList", "NotOnList"); + SetExtraIcons(hContact); + MraSetContactStatus(hContact, ID_STATUS_ONLINE); + + lstrcpynW(szBuff, GetContactNameW(hContact), SIZEOF(szBuff)); + MraAddContactW(hContact, (CONTACT_FLAG_VISIBLE|CONTACT_FLAG_MULTICHAT|CONTACT_FLAG_UNICODE_NAME), -1, szEMail, dwEMailSize, szBuff, lstrlenW(szBuff), NULL, 0, NULL, 0, 0); + } + else { + if (db_get_b(hContact, "CList", "NotOnList", 0) == 0) { // set extra icons and upload contact + SetExtraIcons(hContact); + if (mraGetByte(NULL, "AutoAddContactsToServer", MRA_DEFAULT_AUTO_ADD_CONTACTS_TO_SERVER)) { //add all contacts to server + GetContactBasicInfoW(hContact, NULL, &dwGroupID, NULL, NULL, NULL, NULL, 0, NULL, wszNick, SIZEOF(wszNick), &dwNickSize, szPhones, SIZEOF(szPhones), &dwPhonesSize); + MraAddContactW(hContact, (CONTACT_FLAG_VISIBLE|CONTACT_FLAG_UNICODE_NAME), dwGroupID, szEMail, dwEMailSize, wszNick, dwNickSize, szPhones, dwPhonesSize, wszAuthMessage, dwAuthMessageSize, 0); + } + } + } + MraUpdateContactInfo(hContact); + } + } + } + } + else { // контакт лист почемуто не получили + // всех в offline и id в нестандарт + for (HANDLE hContact = db_find_first();hContact != NULL;hContact = db_find_next(hContact)) { + SetContactBasicInfoW(hContact, SCBIFSI_LOCK_CHANGES_EVENTS, (SCBIF_ID|SCBIF_GROUP_ID|SCBIF_SERVER_FLAG|SCBIF_STATUS), -1, -2, 0, 0, ID_STATUS_OFFLINE, NULL, 0, NULL, 0, NULL, 0); + // 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 { + mir_sntprintf(szBuff, SIZEOF(szBuff), TranslateW(L"MRIM_CS_CONTACT_LIST2: unknown server error, code: %lu"), dwTemp); + MraPopupShowFromAgentW(MRA_POPUP_TYPE_DEBUG, 0, szBuff); + } + } + break; + + case MRIM_CS_SMS_ACK: + dwTemp = GetUL(&lpbDataCurrent); + if ( MraSendQueueFind(hSendQueueHandle, pmaHeader->seq, NULL, &hContact, &dwAckType, (LPBYTE*)&lpsString.lpszData, &lpsString.dwSize) == NO_ERROR) { + char szEMail[MAX_EMAIL_LEN]; + LPSTR lpszPhone; + LPWSTR lpwszMessage; + size_t dwEMailSize, dwPhoneSize, dwMessageSize; + + if (mraGetStaticStringA(NULL, "e-mail", szEMail, SIZEOF(szEMail), &dwEMailSize)) { + dwPhoneSize = (*(DWORD*)lpsString.lpszData); + dwMessageSize = lpsString.dwSize-(dwPhoneSize+sizeof(DWORD)+2); + lpszPhone = (lpsString.lpszData+sizeof(DWORD)); + lpwszMessage = (LPWSTR)(lpszPhone+dwPhoneSize+1); + + dwTemp = mir_snprintf((LPSTR)szBuff, SIZEOF(szBuff), "Mail.ruYesMail.ru, Russia%s-1-1955988055-%s%s0\r\n", szEMail, lpszPhone, lpszPhone); + ProtoBroadcastAckAsync(NULL, dwAckType, ACKRESULT_SENTREQUEST, (HANDLE)pmaHeader->seq, (LPARAM)szBuff, dwTemp+1); + } + + mir_free(lpsString.lpszData); + MraSendQueueFree(hSendQueueHandle, pmaHeader->seq); + } + else MraPopupShowFromAgentW(MRA_POPUP_TYPE_DEBUG, 0, TranslateW(L"MRIM_CS_SMS_ACK: not found in queue")); + break; + + case MRIM_CS_PROXY: + { + DWORD dwIDRequest; + MRA_LPS lpsAddreses = {0}; + MRA_GUID mguidSessionID; + + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsEMail);// LPS to + dwIDRequest = GetUL(&lpbDataCurrent);// DWORD id_request + dwAckType = GetUL(&lpbDataCurrent);// DWORD data_type + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsString);// LPS user_data + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsAddreses);// LPS lps_ip_port + mguidSessionID = GetGUID(&lpbDataCurrent);// DWORD session_id[4] + + if (dwAckType == MRIM_PROXY_TYPE_FILES) { // файлы, on file recv + // set proxy info to file transfer context + if ( !MraMrimProxySetData(MraFilesQueueItemProxyByID(hFilesQueueHandle, dwIDRequest), lpsEMail.lpszData, lpsEMail.dwSize, dwIDRequest, dwAckType, lpsString.lpszData, lpsString.dwSize, lpsAddreses.lpszData, lpsAddreses.dwSize, &mguidSessionID)) + MraFilesQueueStartMrimProxy(hFilesQueueHandle, dwIDRequest); + else { // empty/invalid session + MraProxyAck(PROXY_STATUS_ERROR, lpsEMail.lpszData, lpsEMail.dwSize, dwIDRequest, dwAckType, lpsString.lpszData, lpsString.dwSize, lpsAddreses.lpszData, lpsAddreses.dwSize, mguidSessionID); + DebugBreak(); + } + } + } + break; + + case MRIM_CS_PROXY_ACK: + { + DWORD dwIDRequest; + HANDLE hMraMrimProxyData; + MRA_LPS lpsAddreses = {0}; + MRA_GUID mguidSessionID; + + dwTemp = GetUL(&lpbDataCurrent);// DWORD status + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsEMail);// LPS to + dwIDRequest = GetUL(&lpbDataCurrent);// DWORD id_request + dwAckType = GetUL(&lpbDataCurrent);// DWORD data_type + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsString);// LPS user_data + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsAddreses);// LPS lps_ip_port + mguidSessionID = GetGUID(&lpbDataCurrent);// DWORD session_id[4] + + 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, lpsEMail.lpszData, lpsEMail.dwSize, dwIDRequest, dwAckType, lpsString.lpszData, lpsString.dwSize, lpsAddreses.lpszData, lpsAddreses.dwSize, &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: + DebugBreak(); + break; + } + } + else DebugBreak(); + } + } + break; + + case MRIM_CS_PROXY_HELLO: + // DWORD[4] Session_id + DebugBreak(); + break; + + case MRIM_CS_PROXY_HELLO_ACK: + DebugBreak(); + break; + + case MRIM_CS_NEW_MAIL: + { + DWORD dwDate, dwUIDL; + + dwTemp = GetUL(&lpbDataCurrent);// UL unread count + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsEMail);// LPS from + GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsString);// LPS subject + dwDate = GetUL(&lpbDataCurrent);// UL date + dwUIDL = GetUL(&lpbDataCurrent);// UL uidl + + if (dwTemp > dwEmailMessagesTotal) + dwEmailMessagesTotal += (dwTemp-dwEmailMessagesUnread); + + dwAckType = dwEmailMessagesUnread;// save old value + dwEmailMessagesUnread = dwTemp;// store new value + if (mraGetByte(NULL, "IncrementalNewMailNotify", MRA_DEFAULT_INC_NEW_MAIL_NOTIFY) == 0 || dwAckTypelpszData == NULL || plpsRFTText->dwSize == 0) + dwFlags &= ~MESSAGE_FLAG_RTF; + } + else dwFlags &= ~MESSAGE_FLAG_RTF; + } + + if (dwFlags & MESSAGE_FLAG_MULTICHAT) { + if (plpsMultiChatData) { + if (plpsMultiChatData->lpszData == NULL || plpsMultiChatData->dwSize == 0) + dwFlags &= ~MESSAGE_FLAG_MULTICHAT; + } + else dwFlags &= ~MESSAGE_FLAG_MULTICHAT; + } + + // pre processing - extracting/decoding + if (dwFlags & MESSAGE_FLAG_AUTHORIZE) { // extract auth message из обычного текста + size_t dwAuthPartsCount, dwAuthBuffSize = (plpsText->dwSize+32), dwAuthDataSize; + LPBYTE lpbAuthData, lpbDataCurrent; + MRA_LPS lpsAuthFrom, lpsAuthMessage; + + lpbAuthData = (LPBYTE)mir_calloc(dwAuthBuffSize); + if (lpbAuthData) { + BASE64DecodeFormated(plpsText->lpszData, plpsText->dwSize, lpbAuthData, dwAuthBuffSize, &dwAuthDataSize); + + lpbDataCurrent = lpbAuthData; + dwAuthPartsCount = GetUL(&lpbDataCurrent); + if ( !GetLPS(lpbAuthData, dwAuthDataSize, &lpbDataCurrent, &lpsAuthFrom)) + if ( !GetLPS(lpbAuthData, dwAuthDataSize, &lpbDataCurrent, &lpsAuthMessage)) { + if (dwFlags&MESSAGE_FLAG_v1p16 && (dwFlags&MESSAGE_FLAG_CP1251) == 0) { // unicode text + memmove(lpbAuthData, lpsAuthMessage.lpszData, lpsAuthMessage.dwSize); + lpwszMessage = (LPWSTR)lpbAuthData; + dwMessageSize = (lpsAuthMessage.dwSize/sizeof(WCHAR)); + } + else { // преобразуем в юникод текст только если он в АНСИ и если это не Флэш мультик и будильник тоже не нуждается в этом + lpwszMessage = (LPWSTR)mir_calloc(((lpsAuthMessage.dwSize+MAX_PATH)*sizeof(WCHAR))); + if (lpwszMessage) { + dwMessageSize = MultiByteToWideChar(MRA_CODE_PAGE, 0, lpsAuthMessage.lpszData, lpsAuthMessage.dwSize, lpwszMessage, (lpsAuthMessage.dwSize+MAX_PATH)); + (*(lpwszMessage+dwMessageSize)) = 0; + } + else dwRetErrorCode = GetLastError(); + } + } + if (lpwszMessage != (LPWSTR)lpbAuthData) + mir_free(lpbAuthData); + } + } + else { + // unicode text + if ((dwFlags & (MESSAGE_FLAG_ALARM|MESSAGE_FLAG_FLASH|MESSAGE_FLAG_v1p16)) && (dwFlags & MESSAGE_FLAG_CP1251) == 0) { + lpwszMessage = plpsText->lpwszData; + dwMessageSize = (plpsText->dwSize/sizeof(WCHAR)); + } + else { + lpwszMessage = (LPWSTR)mir_calloc(((plpsText->dwSize+MAX_PATH)*sizeof(WCHAR))); + if (lpwszMessage) { + dwMessageSize = MultiByteToWideChar(MRA_CODE_PAGE, 0, plpsText->lpszData, plpsText->dwSize, lpwszMessage, (plpsText->dwSize+MAX_PATH)); + (*(lpwszMessage+dwMessageSize)) = 0; + } + else dwRetErrorCode = GetLastError(); + } + + 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) //MESSAGE_FLAG_FLASH there + if (plpsRFTText->lpszData && plpsRFTText->dwSize) { // decode RTF + size_t dwRTFPartsCount, dwCompressedSize, dwRFTBuffSize = ((plpsRFTText->dwSize*16)+8192), dwRTFDataSize; + LPBYTE lpbRTFData, lpbCompressed, lpbDataCurrent; + MRA_LPS lpsRTFString, lpsBackColour, lpsString; + + lpbRTFData = (LPBYTE)mir_calloc(dwRFTBuffSize); + lpbCompressed = (LPBYTE)mir_calloc((plpsRFTText->dwSize+32)); + if (lpbRTFData && lpbCompressed) { + BASE64DecodeFormated(plpsRFTText->lpszData, plpsRFTText->dwSize, lpbCompressed, (plpsRFTText->dwSize+32), &dwCompressedSize); + dwRTFDataSize = dwRFTBuffSize; + if ( uncompress(lpbRTFData, (DWORD*)&dwRTFDataSize, lpbCompressed, dwCompressedSize) == Z_OK) { + lpbDataCurrent = lpbRTFData; + dwRTFPartsCount = GetUL(&lpbDataCurrent);// колличество частей в некоторых случаях больше 2, тогда нужно игнорировать первый текст, тк там сообщения об ущербности + if (GetLPS(lpbRTFData, dwRTFDataSize, &lpbDataCurrent, &lpsRTFString) == NO_ERROR) + if (GetLPS(lpbRTFData, dwRTFDataSize, &lpbDataCurrent, &lpsBackColour) == NO_ERROR) { + dwBackColour = (*(DWORD*)lpsBackColour.lpszData); + if (dwFlags & MESSAGE_FLAG_FLASH) { + if (dwRTFPartsCount == 3) { // ansi text only + GetLPS(lpbRTFData, dwRTFDataSize, &lpbDataCurrent, &lpsString); + lpwszMessage = (LPWSTR)mir_calloc(((lpsString.dwSize+MAX_PATH)*sizeof(WCHAR))); + if (lpwszMessage) { + memmove(lpwszMessage, lpsString.lpszData, lpsString.dwSize); + dwMessageSize = MultiByteToWideChar(MRA_CODE_PAGE, 0, lpsString.lpszData, lpsString.dwSize, lpwszMessage, (lpsString.dwSize+MAX_PATH)); + (*(lpwszMessage+dwMessageSize)) = 0; + } + else dwRetErrorCode = GetLastError(); + } + else if (dwRTFPartsCount == 4) { + GetLPS(lpbRTFData, dwRTFDataSize, &lpbDataCurrent, &lpsString); + GetLPS(lpbRTFData, dwRTFDataSize, &lpbDataCurrent, &lpsString); + lpwszMessage = (LPWSTR)mir_calloc(lpsString.dwSize); + if (lpwszMessage) { + memmove(lpwszMessage, lpsString.lpszData, lpsString.dwSize); + dwMessageSize = lpsString.dwSize; + } + else dwRetErrorCode = GetLastError(); + } + else DebugBreak(); + } + else { // RTF text + if (dwRTFPartsCount > 2) { + GetLPS(lpbRTFData, dwRTFDataSize, &lpbDataCurrent, &lpsString); + DebugBreak(); + } + + lpszMessageExt = (LPSTR)mir_calloc(lpsRTFString.dwSize); + if (lpszMessageExt) { + memmove(lpszMessageExt, lpsRTFString.lpszData, lpsRTFString.dwSize); + dwMessageExtSize = lpsRTFString.dwSize; + } + else DebugBreak(); + } + } + }else { + mir_free(lpszMessageExt); + dwMessageExtSize = 0; + DebugBreak(); + } + } + mir_free(lpbCompressed); + mir_free(lpbRTFData); + } + } + } + + Netlib_Logf(hNetlibUser, "Processing message: %08X, from '%s', text '%S'\n", dwFlags, plpsFrom->lpszData, lpwszMessage); + + // processing + if (dwRetErrorCode == NO_ERROR) + if (MraAntiSpamReceivedMessageW(plpsFrom->lpszData, plpsFrom->dwSize, dwFlags, lpwszMessage, dwMessageSize) == MESSAGE_NOT_SPAM) { + if (dwFlags & (MESSAGE_FLAG_SMS | MESSAGE_SMS_DELIVERY_REPORT)) {// SMS //if (IsPhone(plpsFrom->lpszData, plpsFrom->dwSize)) + char szPhone[MAX_EMAIL_LEN], szEMail[MAX_EMAIL_LEN], szTime[MAX_PATH]; + LPSTR lpszMessageUTF, lpszBuff; + LPWSTR lpwszMessageXMLEncoded; + size_t dwBuffLen, dwMessageXMLEncodedSize; + INTERNET_TIME itTime; + + dwBuffLen = ((dwMessageSize+MAX_PATH)*6); + lpszMessageUTF = (LPSTR)mir_calloc(dwBuffLen); + lpwszMessageXMLEncoded = (LPWSTR)mir_calloc((dwBuffLen*sizeof(WCHAR))); + if (lpszMessageUTF && lpwszMessageXMLEncoded) { + InternetTimeGetCurrentTime(&itTime); + InternetTimeGetString(&itTime, szTime, SIZEOF(szTime), NULL); + CopyNumber(szPhone, plpsFrom->lpszData, plpsFrom->dwSize); + mraGetStaticStringA(NULL, "e-mail", szEMail, SIZEOF(szEMail), NULL); + + EncodeXML(lpwszMessage, dwMessageSize, lpwszMessageXMLEncoded, dwBuffLen, &dwMessageXMLEncodedSize); + WideCharToMultiByte(CP_UTF8, 0, lpwszMessageXMLEncoded, dwMessageXMLEncodedSize, lpszMessageUTF, dwBuffLen, NULL, NULL); + lpszBuff = (LPSTR)lpwszMessageXMLEncoded; + + if (dwFlags & MESSAGE_SMS_DELIVERY_REPORT) { + dwBuffLen = mir_snprintf(lpszBuff, (dwBuffLen*sizeof(WCHAR)), "%s-1-1955988055-%s%sNo%s015%s", szEMail, szPhone, szPhone, szTime, lpszMessageUTF); + ProtoBroadcastAckAsync(NULL, ICQACKTYPE_SMS, ACKRESULT_FAILED, (HANDLE)0, (LPARAM)lpszBuff, dwBuffLen+1); + } + else { // new sms + dwBuffLen = mir_snprintf(lpszBuff, (dwBuffLen*sizeof(WCHAR)), "Mail.ru%s%sMail.ru%s", szEMail, szPhone, lpszMessageUTF, szTime); + ProtoBroadcastAckAsync(NULL, ICQACKTYPE_SMS, ACKRESULT_SUCCESS, (HANDLE)0, (LPARAM)lpszBuff, dwBuffLen+1); + } + } + else dwRetErrorCode = GetLastError(); + + mir_free(lpwszMessageXMLEncoded); + mir_free(lpszMessageUTF); + } + else { + ccs.hContact = MraHContactFromEmail(plpsFrom->lpszData, plpsFrom->dwSize, TRUE, TRUE, &bAdded); + if (bAdded) + MraUpdateContactInfo(ccs.hContact); + + // user typing + if (dwFlags & MESSAGE_FLAG_NOTIFY) + CallService(MS_PROTO_CONTACTISTYPING, (WPARAM)ccs.hContact, MAILRU_CONTACTISTYPING_TIMEOUT); + else { // text/contact/auth // typing OFF + CallService(MS_PROTO_CONTACTISTYPING, (WPARAM)ccs.hContact, PROTOTYPE_CONTACTTYPING_OFF); + + if (dwFlags & MESSAGE_FLAG_MULTICHAT) { + LPBYTE lpbMultiChatData, lpbDataCurrent; + size_t dwMultiChatDataSize; + DWORD dwMultiChatEventType; + MRA_LPS lpsEMailInMultiChat, lpsString, lpsMultichatName; + + lpbMultiChatData = (LPBYTE)plpsMultiChatData->lpszData; + dwMultiChatDataSize = plpsMultiChatData->dwSize; + lpbDataCurrent = lpbMultiChatData; + + dwMultiChatEventType = GetUL(&lpbDataCurrent);// type + GetLPS(lpbMultiChatData, dwMultiChatDataSize, &lpbDataCurrent, &lpsMultichatName);// multichat_name + GetLPS(lpbMultiChatData, dwMultiChatDataSize, &lpbDataCurrent, &lpsEMailInMultiChat); + + switch (dwMultiChatEventType) { + case MULTICHAT_MESSAGE: + MraChatSessionMessageAdd(ccs.hContact, lpsEMailInMultiChat.lpszData, lpsEMailInMultiChat.dwSize, lpwszMessage, dwMessageSize, dwTime);// LPS sender + break; + case MULTICHAT_ADD_MEMBERS: + MraChatSessionMembersAdd(ccs.hContact, lpsEMailInMultiChat.lpszData, lpsEMailInMultiChat.dwSize, dwTime);// LPS sender + GetLPS(lpbMultiChatData, dwMultiChatDataSize, &lpbDataCurrent, &lpsString);// CLPS members + MraChatSessionSetIviter(ccs.hContact, lpsEMailInMultiChat.lpszData, lpsEMailInMultiChat.dwSize); + case MULTICHAT_MEMBERS: + { + LPBYTE lpbMultiChatDataLocal, lpbDataCurrentLocal; + size_t i, dwMultiChatMembersCount, dwMultiChatDataLocalSize; + + if (dwMultiChatEventType == MULTICHAT_MEMBERS) lpsString = lpsEMailInMultiChat; + + lpbMultiChatDataLocal = (LPBYTE)lpsString.lpszData; + dwMultiChatDataLocalSize = lpsString.dwSize; + lpbDataCurrentLocal = lpbMultiChatDataLocal; + + dwMultiChatMembersCount = GetUL(&lpbDataCurrentLocal);// count + for (i = 0; i < dwMultiChatMembersCount; i++) + if (GetLPS(lpbMultiChatDataLocal, dwMultiChatDataLocalSize, &lpbDataCurrentLocal, &lpsString) == NO_ERROR) + MraChatSessionJoinUser(ccs.hContact, lpsString.lpszData, lpsString.dwSize, ((dwMultiChatEventType == MULTICHAT_MEMBERS)? 0:dwTime)); + + if (dwMultiChatEventType == MULTICHAT_MEMBERS) { + GetLPS(lpbMultiChatData, dwMultiChatDataSize, &lpbDataCurrent, &lpsEMailInMultiChat);// [ LPS owner ] + MraChatSessionSetOwner(ccs.hContact, lpsEMailInMultiChat.lpszData, lpsEMailInMultiChat.dwSize); + } + } + break; + case MULTICHAT_ATTACHED: + MraChatSessionJoinUser(ccs.hContact, lpsEMailInMultiChat.lpszData, lpsEMailInMultiChat.dwSize, dwTime);// LPS member + break; + case MULTICHAT_DETACHED: + MraChatSessionLeftUser(ccs.hContact, lpsEMailInMultiChat.lpszData, lpsEMailInMultiChat.dwSize, dwTime);// LPS member + break; + case MULTICHAT_INVITE: + MraChatSessionInvite(ccs.hContact, lpsEMailInMultiChat.lpszData, lpsEMailInMultiChat.dwSize, dwTime);// LPS sender + MraAddContactW(ccs.hContact, (CONTACT_FLAG_VISIBLE|CONTACT_FLAG_MULTICHAT|CONTACT_FLAG_UNICODE_NAME), -1, plpsFrom->lpszData, plpsFrom->dwSize, lpsMultichatName.lpwszData, (lpsMultichatName.dwSize/sizeof(WCHAR)), NULL, 0, NULL, 0, 0); + break; + default: + DebugBreak(); + break; + } + } + else if (dwFlags & MESSAGE_FLAG_AUTHORIZE) { // auth request + BYTE btBuff[BUFF_SIZE_BLOB]; + BOOL bAutoGrantAuth = FALSE; + + if ( IsEMailChatAgent(plpsFrom->lpszData, plpsFrom->dwSize)) + bAutoGrantAuth = FALSE; + else { + // temporary contact + if (db_get_b(ccs.hContact, "CList", "NotOnList", 0)) { + if (mraGetByte(NULL, "AutoAuthGrandNewUsers", MRA_DEFAULT_AUTO_AUTH_GRAND_NEW_USERS)) + bAutoGrantAuth = TRUE; + } + else if (mraGetByte(NULL, "AutoAuthGrandUsersInCList", MRA_DEFAULT_AUTO_AUTH_GRAND_IN_CLIST)) + bAutoGrantAuth = TRUE; + } + + if (bAdded) + DBWriteContactSettingByte(ccs.hContact, "CList", "Hidden", 1); + + if (bAutoGrantAuth) { // auto grant auth + DBEVENTINFO dbei = {0}; + + dbei.cbSize = sizeof(dbei); + dbei.szModule = m_szModuleName; + dbei.timestamp = _time32(NULL); + dbei.flags = DBEF_READ; + dbei.eventType = EVENTTYPE_AUTHREQUEST; + dbei.pBlob = (PBYTE)btBuff; + + CreateBlobFromContact(ccs.hContact, lpwszMessage, dwMessageSize, btBuff, SIZEOF(btBuff), (size_t*)&dbei.cbBlob); + CallService(MS_DB_EVENT_ADD, (WPARAM)NULL, (LPARAM)&dbei); + MraAuthorize(plpsFrom->lpszData, plpsFrom->dwSize); + } + else { + ccs.szProtoService = PSR_AUTH; + pre.szMessage = (LPSTR)btBuff; + CreateBlobFromContact(ccs.hContact, lpwszMessage, dwMessageSize, btBuff, SIZEOF(btBuff), (size_t*)&pre.lParam); + CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs); + } + } + else { + DBDeleteContactSetting(ccs.hContact, "CList", "Hidden"); + + if (dwFlags & MESSAGE_FLAG_CONTACT) { // contacts received + LPBYTE lpbBuffer, lpbBufferCurPos; + + lpbBuffer = (LPBYTE)mir_calloc((dwMessageSize+MAX_PATH)); + if (lpbBuffer) { + ccs.szProtoService = PSR_CONTACTS; + pre.flags = 0; + pre.szMessage = (LPSTR)lpbBuffer; + pre.lParam = WideCharToMultiByte(MRA_CODE_PAGE, 0, lpwszMessage, dwMessageSize, (LPSTR)lpbBuffer, (dwMessageSize+MAX_PATH), NULL, NULL); + + lpbBufferCurPos = lpbBuffer; + while (TRUE) { // цикл замены ; на 0 + lpbBufferCurPos = (LPBYTE)MemoryFindByte((lpbBufferCurPos-lpbBuffer), lpbBuffer, pre.lParam, ';'); + if (!lpbBufferCurPos) + break; + + // found + (*lpbBufferCurPos) = 0; + lpbBufferCurPos++; + } + CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs); + mir_free(lpbBuffer); + } + else dwRetErrorCode = GetLastError(); + } + else if (dwFlags & MESSAGE_FLAG_ALARM) { // alarm + if (heNudgeReceived) + NotifyEventHooks(heNudgeReceived, (WPARAM)ccs.hContact, NULL); + else { + pre.flags = 0; + pre.szMessage = (LPSTR)TranslateTS(MRA_ALARM_MESSAGE); + //pre.lParam = lstrlenA(pre.szMessage); + ccs.szProtoService = PSR_MESSAGE; + CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs); + } + } + else { // standart message// flash animation + // пишем в ANSI, всё равно RTF + if ((dwFlags & MESSAGE_FLAG_RTF) && (dwFlags & MESSAGE_FLAG_FLASH) == 0 && lpszMessageExt && dwMessageExtSize && mraGetByte(NULL, "RTFReceiveEnable", MRA_DEFAULT_RTF_RECEIVE_ENABLE)) { + pre.flags = 0; + pre.szMessage = lpszMessageExt; + //pre.lParam = dwMessageExtSize; + ccs.szProtoService = PSR_MESSAGE; + CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs); + } + else { + // some plugins can change pre.szMessage pointer and we failed to free it + LPSTR lpszMessageUTF = (LPSTR)mir_calloc(((dwMessageSize+MAX_PATH)*sizeof(WCHAR))); + if (lpszMessageUTF) { + pre.szMessage = lpszMessageUTF; + pre.flags = PREF_UTF; + WideCharToMultiByte(CP_UTF8, 0, lpwszMessage, dwMessageSize, lpszMessageUTF, ((dwMessageSize+MAX_PATH)*sizeof(WCHAR)), NULL, NULL); + ccs.szProtoService = PSR_MESSAGE; + CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs); + mir_free(lpszMessageUTF); + } + else dwRetErrorCode = GetLastError(); + } + + if (dwFlags & MESSAGE_FLAG_SYSTEM) + MraPopupShowW(ccs.hContact, MRA_POPUP_TYPE_INFORMATION, 0, TranslateW(L"Mail.ru System notify"), (LPWSTR)pre.szMessage); + } + } + } + } + } + else dwRetErrorCode = ERROR_ACCESS_DENIED; + + if (lpwszMessage != plpsText->lpwszData && lpwszMessage != (LPWSTR)lpszMessageExt) + mir_free(lpwszMessage); + mir_free(lpszMessageExt); + + return dwRetErrorCode; +} + +DWORD GetMraXStatusIDFromMraUriStatus(LPSTR lpszStatusUri, size_t dwStatusUriSize) +{ + if (lpszStatusUri) + for (size_t i = 0; lpcszStatusUri[i]; i++) + if ( !_strnicmp(lpcszStatusUri[i], lpszStatusUri, dwStatusUriSize)) + 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 GetMiradaStatusFromMraStatus(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_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; + } + + if (dwMraStatus & STATUS_FLAG_INVISIBLE) + return ID_STATUS_INVISIBLE; + + return ID_STATUS_OFFLINE; +} + +DWORD GetUL(LPBYTE *plpData) +{ + DWORD dwRet = *(DWORD*)(*plpData); + plpData[0] += sizeof(DWORD); + return dwRet; +} + +DWORDLONG GetUIDL(LPBYTE *plpData) +{ + DWORDLONG dwRet = *(DWORDLONG*)(*plpData); + plpData[0] += sizeof(DWORDLONG); + return dwRet; +} + +MRA_GUID GetGUID(LPBYTE *plpData) +{ + MRA_GUID guidRet = *(MRA_GUID*)(*plpData); + plpData[0] += sizeof(MRA_GUID); + return guidRet; +} + +DWORD GetLPS(LPBYTE lpbData, DWORD dwDataSize, LPBYTE *plpCurrentData, MRA_LPS *plpsString) +{ + LPBYTE lpbDataEnd = (lpbData+dwDataSize); + + // хотябы длинна данных есть + if (lpbDataEnd >= ((*plpCurrentData)+sizeof(DWORD))) { + // все длинна данных в буфере равна или меньше размера буфера + if (lpbDataEnd >= ((*plpCurrentData)+sizeof(DWORD)+(*(DWORD*)(*plpCurrentData)))) { + plpsString->dwSize = (*(DWORD*)(*plpCurrentData)); + plpsString->lpszData = (LPSTR)((*plpCurrentData)+sizeof(DWORD)); + (*plpCurrentData) += (sizeof(DWORD)+plpsString->dwSize); + return NO_ERROR; + } + } + + plpsString->dwSize = 0; + plpsString->lpszData = NULL; + return ERROR_INVALID_USER_BUFFER; +} diff --git a/protocols/MRA/src/Mra_svcs.cpp b/protocols/MRA/src/Mra_svcs.cpp new file mode 100644 index 0000000000..28c761a5c4 --- /dev/null +++ b/protocols/MRA/src/Mra_svcs.cpp @@ -0,0 +1,1117 @@ +#include "Mra.h" +#include "proto.h" + +const LPSTR lpcszStatusUri[] = +{ + "", // offline // "status_0", + "STATUS_ONLINE", // "status_1", + "STATUS_AWAY", // "status_2", + "STATUS_INVISIBLE", // "status_3", + "status_dnd", + "status_chat", + "status_4", + "status_5", + "status_6", + "status_7", + "status_8", + "status_9", + "status_10", + "status_11", + "status_12", + "status_13", + "status_14", + "status_15", + "status_16", + "status_17", + "status_18", + "status_19", + "status_20", + "status_21", + "status_22", + "status_23", + "status_24", + //"status_25", // chat/dnd + "status_26", + "status_27", + "status_28", + "status_29", + "status_30", + //"status_31", // chat/dnd + "status_32", + "status_33", + "status_34", + "status_35", + "status_36", + "status_37", + "status_38", + "status_39", + "status_40", + "status_41", + "status_42", + "status_43", + "status_44", + "status_45", + "status_46", + "status_47", + "status_48", + "status_49", + "status_50", + "status_51", + "status_52", + "status_53", + "status_dating", + //"status_127", 145, 154 + NULL +}; + +const LPWSTR lpcszXStatusNameDef[] = +{ + L"None", + L"Sick", + L"Home", + L"Eating", + L"Compass", + L"On WC", + L"Cooking", + L"Walking", + L"Alien", + L"Shrimp", + L"Got lost", + L"Crazy", + L"Duck", + L"Playing", + L"Smoking", + L"Office", + L"Meeting", + L"Beer", + L"Coffee", + L"Working", + L"Relaxing", + L"On the phone", + L"In institute", + L"At school", + L"Wrong number", + L"Laughing", + L"Malicious", + L"Imp", + L"Blind", + L"Disappointed", + L"Almost crying", + L"Fearful", + L"Angry", + L"Vampire", + L"Ass", + L"Love", + L"Sleeping", + L"Cool!", + L"Peace!", + L"Cock a snook", + L"Get out", + L"Death", + L"Rocket", + L"Devil-fish", + L"Heavy metal", + L"Things look bad", + L"Squirrel", + L"Star", + L"Music", + L"Dating", + NULL +}; + +////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void CMraProto::SetExtraIcons(HANDLE hContact) +{ + if (!hHookExtraIconsApply) + return; + + DWORD dwID, dwGroupID, dwContactSeverFlags; + if ( GetContactBasicInfoW(hContact, &dwID, &dwGroupID, NULL, &dwContactSeverFlags, NULL, NULL, 0, NULL, NULL, 0, NULL, NULL, 0, NULL)) + return; + + DWORD dwIconID = -1; + DWORD dwXStatus = MRA_MIR_XSTATUS_NONE; + + if (m_bLoggedIn) { + dwXStatus = mraGetByte(hContact, DBSETTING_XSTATUSID, MRA_MIR_XSTATUS_NONE); + if (dwID == -1) + dwIconID = (dwContactSeverFlags == -1) ? ADV_ICON_DELETED : ADV_ICON_NOT_ON_SERVER; + else { + if (dwGroupID == 103) + dwIconID = ADV_ICON_PHONE; + else { + if (dwContactSeverFlags) + if (dwContactSeverFlags == -1) + dwIconID = ADV_ICON_DELETED; + else + dwIconID = ADV_ICON_NOT_AUTHORIZED; + } + } + } + + if (dwIconID == -1) { + size_t dwBlogStatusMsgSize = 0; + + mraGetStaticStringW(hContact, DBSETTING_BLOGSTATUS, NULL, 0, &dwBlogStatusMsgSize); + if (dwBlogStatusMsgSize) dwIconID = ADV_ICON_BLOGSTATUS; + } + + ExtraSetIcon(hExtraXstatusIcon, hContact, (( IsXStatusValid(dwXStatus) || dwXStatus == MRA_MIR_XSTATUS_UNKNOWN)? hXStatusAdvancedStatusItems[dwXStatus]:NULL), EXTRA_ICON_ADV1); + ExtraSetIcon(hExtraInfo, hContact, ((dwIconID != -1) ? hAdvancedStatusItems[dwIconID]:NULL), EXTRA_ICON_ADV2); +} + +INT_PTR CMraProto::MraXStatusMenu(WPARAM wParam, LPARAM lParam, LPARAM param) +{ + if ( MraRequestXStatusDetails(param) == FALSE) + MraSetXStatusInternal(param); + return 0; +} + +INT_PTR CMraProto::MraGotoInbox(WPARAM wParam, LPARAM lParam) +{ + MraMPopSessionQueueAddUrl(hMPopSessionQueue, MRA_WIN_INBOX_URL, sizeof(MRA_WIN_INBOX_URL)); + return 0; +} + +INT_PTR CMraProto::MraShowInboxStatus(WPARAM wParam, LPARAM lParam) +{ + MraUpdateEmailStatus(NULL, 0, NULL, 0, 0, 0); + return 0; +} + +INT_PTR CMraProto::MraSendSMS(WPARAM wParam, LPARAM lParam) +{ + if (!m_bLoggedIn || !wParam || !lParam) + return 0; + + mir_ptr lpwszMessageXMLEncoded( mir_utf8decodeW((LPSTR)lParam)); + size_t dwBuffLen = lstrlenA((LPSTR)lParam) + MAX_PATH; + LPWSTR lpwszMessageXMLDecoded = (LPWSTR)mir_calloc((dwBuffLen*sizeof(WCHAR))); + if (lpwszMessageXMLEncoded && lpwszMessageXMLDecoded) { + size_t dwMessageXMLDecodedSize; + DecodeXML(lpwszMessageXMLEncoded, lstrlen(lpwszMessageXMLEncoded), lpwszMessageXMLDecoded, dwBuffLen, &dwMessageXMLDecodedSize); + if (dwMessageXMLDecodedSize) + MraSMSW(NULL, (LPSTR)wParam , lstrlenA((LPSTR)wParam), lpwszMessageXMLDecoded, dwMessageXMLDecodedSize); + } + mir_free(lpwszMessageXMLDecoded); + return 0; +} + +INT_PTR CMraProto::MraEditProfile(WPARAM wParam, LPARAM lParam) +{ + MraMPopSessionQueueAddUrl(hMPopSessionQueue, MRA_EDIT_PROFILE_URL, sizeof(MRA_EDIT_PROFILE_URL)); + return 0; +} + +INT_PTR CMraProto::MraZhuki(WPARAM wParam, LPARAM lParam) +{ + MraMPopSessionQueueAddUrl(hMPopSessionQueue, MRA_ZHUKI_URL, sizeof(MRA_ZHUKI_URL)); + return 0; +} + +INT_PTR CMraProto::MraChat(WPARAM wParam, LPARAM lParam) +{ + MraMPopSessionQueueAddUrl(hMPopSessionQueue, MRA_CHAT_URL, sizeof(MRA_CHAT_URL)); + return 0; +} + +INT_PTR CMraProto::MraWebSearch(WPARAM wParam, LPARAM lParam) +{ + CallService(MS_UTILS_OPENURL, TRUE, (LPARAM)MRA_SEARCH_URL); + return 0; +} + +INT_PTR CMraProto::MraUpdateAllUsersInfo(WPARAM wParam, LPARAM lParam) +{ + if ( MessageBox(NULL, TranslateT("Are you sure?"), TranslateW(MRA_UPD_ALL_USERS_INFO_STR), MB_YESNO | MB_ICONQUESTION) == IDYES ) { + for (HANDLE hContact = db_find_first(); + hContact != NULL; + hContact = db_find_next(hContact)) { + size_t dwEMailSize; + CHAR szEMail[MAX_EMAIL_LEN]; + if ( IsContactMra(hContact)) + if ( mraGetStaticStringA(hContact, "e-mail", szEMail, SIZEOF(szEMail), &dwEMailSize)) + MraWPRequestByEMail(hContact, ACKTYPE_GETINFO, szEMail, dwEMailSize); + } + } + return 0; +} + +INT_PTR CMraProto::MraCheckUpdatesUsersAvt(WPARAM wParam, LPARAM lParam) +{ + if ( MessageBox(NULL, TranslateT("Are you sure?"), TranslateW(MRA_CHK_USERS_AVATARS_STR), MB_YESNO | MB_ICONQUESTION) == IDYES) { + for (HANDLE hContact = db_find_first(); + hContact != NULL; + hContact = db_find_next(hContact)) { + size_t dwEMailSize; + CHAR szEMail[MAX_EMAIL_LEN]; + + if (IsContactMra(hContact)) + if (mraGetStaticStringA(hContact, "e-mail", szEMail, SIZEOF(szEMail), &dwEMailSize)) + if (IsEMailChatAgent(szEMail, dwEMailSize) == FALSE)// только для оптимизации, MraAvatarsQueueGetAvatarSimple сама умеет фильтровать чатконтакты + MraAvatarsQueueGetAvatarSimple(hAvatarsQueueHandle, 0/*GAIF_FORCE*/, hContact, 0); + } + } + return 0; +} + +INT_PTR CMraProto::MraRequestAuthForAll(WPARAM wParam, LPARAM lParam) +{ + if ( MessageBox(NULL, TranslateT("Are you sure?"), TranslateW(MRA_REQ_AUTH_FOR_ALL_STR), MB_YESNO | MB_ICONQUESTION) == IDYES) { + for (HANDLE hContact = db_find_first(); + hContact != NULL; + hContact = db_find_next(hContact)) { + DWORD dwContactSeverFlags; + if (GetContactBasicInfoW(hContact, NULL, NULL, NULL, &dwContactSeverFlags, NULL, NULL, 0, NULL, NULL, 0, NULL, NULL, 0, NULL) == NO_ERROR) + if (dwContactSeverFlags&CONTACT_INTFLAG_NOT_AUTHORIZED && dwContactSeverFlags != -1) + MraRequestAuthorization((WPARAM)hContact, 0); + } + } + return 0; +} + +INT_PTR CMraProto::MraRequestAuthorization(WPARAM wParam, LPARAM lParam) +{ + if (wParam) { + WCHAR wszAuthMessage[MAX_PATH]; + + if (mraGetStaticStringW(NULL, "AuthMessage", wszAuthMessage, SIZEOF(wszAuthMessage), NULL) == FALSE) + lstrcpynW(wszAuthMessage, TranslateW(MRA_DEFAULT_AUTH_MESSAGE), SIZEOF(wszAuthMessage)); + + CHAR szEMail[MAX_EMAIL_LEN]; + size_t dwEMailSize, dwMessageSize; + + dwMessageSize = lstrlen(wszAuthMessage); + if (dwMessageSize) { + HANDLE hContact = (HANDLE)wParam; + if ( mraGetStaticStringA(hContact, "e-mail", szEMail, SIZEOF(szEMail), &dwEMailSize)) { + BOOL bSlowSend = mraGetByte(NULL, "SlowSend", MRA_DEFAULT_SLOW_SEND); + int iRet = MraMessageW(bSlowSend, hContact, ACKTYPE_AUTHREQ, MESSAGE_FLAG_AUTHORIZE, szEMail, dwEMailSize, wszAuthMessage, dwMessageSize, NULL, 0); + if (bSlowSend == FALSE) + ProtoBroadcastAckAsync(hContact, ACKTYPE_AUTHREQ, ACKRESULT_SUCCESS, (HANDLE)iRet, 0); + + return 0; + } + } + + return 1; + } + return 0; +} + +INT_PTR CMraProto::MraGrantAuthorization(WPARAM wParam, LPARAM lParam) +{ + if (!m_bLoggedIn || !wParam) + return 0; + + CHAR szEMail[MAX_EMAIL_LEN]; + size_t dwEMailSize; + + // send without reason, do we need any ? + if (mraGetStaticStringA((HANDLE)wParam, "e-mail", szEMail, SIZEOF(szEMail), &dwEMailSize)) + MraAuthorize(szEMail, dwEMailSize); + + return 0; +} + +INT_PTR CMraProto::MraSendPostcard(WPARAM wParam, LPARAM lParam) +{ + if (!m_bLoggedIn) + return 0; + + DWORD dwContactEMailCount = GetContactEMailCount((HANDLE)wParam, FALSE); + if (dwContactEMailCount) { + if (dwContactEMailCount == 1) { + size_t dwUrlSize, dwEMailSize; + CHAR szUrl[BUFF_SIZE_URL], szEMail[MAX_EMAIL_LEN]; + + if ( GetContactFirstEMail((HANDLE)wParam, FALSE, szEMail, SIZEOF(szEMail), &dwEMailSize)) { + BuffToLowerCase(szEMail, szEMail, dwEMailSize); + dwUrlSize = mir_snprintf(szUrl, SIZEOF(szUrl), "http://cards.mail.ru/event.html?rcptname = %s&rcptemail = %s", GetContactNameA((HANDLE)wParam), szEMail); + MraMPopSessionQueueAddUrl(hMPopSessionQueue, szUrl, dwUrlSize); + } + } + else MraSelectEMailDlgShow((HANDLE)wParam, MRA_SELECT_EMAIL_TYPE_SEND_POSTCARD); + } + return 0; +} + +INT_PTR CMraProto::MraViewAlbum(WPARAM wParam, LPARAM lParam) +{ + if (!m_bLoggedIn) + return 0; + + DWORD dwContactEMailMRCount = GetContactEMailCount((HANDLE)wParam, TRUE); + if (dwContactEMailMRCount) { + if (dwContactEMailMRCount == 1) { + size_t dwEMailSize; + CHAR szEMail[MAX_EMAIL_LEN]; + if (GetContactFirstEMail((HANDLE)wParam, TRUE, szEMail, SIZEOF(szEMail), &dwEMailSize)) + MraMPopSessionQueueAddUrlAndEMail(hMPopSessionQueue, MRA_FOTO_URL, sizeof(MRA_FOTO_URL), szEMail, dwEMailSize); + } + else MraSelectEMailDlgShow((HANDLE)wParam, MRA_SELECT_EMAIL_TYPE_VIEW_ALBUM); + } + return 0; +} + +INT_PTR CMraProto::MraReadBlog(WPARAM wParam, LPARAM lParam) +{ + if (!m_bLoggedIn) + return 0; + + DWORD dwContactEMailMRCount = GetContactEMailCount((HANDLE)wParam, TRUE); + if (dwContactEMailMRCount) + if (dwContactEMailMRCount == 1) { + CHAR szEMail[MAX_EMAIL_LEN]; + size_t dwEMailSize; + if (GetContactFirstEMail((HANDLE)wParam, TRUE, szEMail, SIZEOF(szEMail), &dwEMailSize)) + MraMPopSessionQueueAddUrlAndEMail(hMPopSessionQueue, MRA_BLOGS_URL, sizeof(MRA_BLOGS_URL), szEMail, dwEMailSize); + } + else MraSelectEMailDlgShow((HANDLE)wParam, MRA_SELECT_EMAIL_TYPE_READ_BLOG); + + return 0; +} + +INT_PTR CMraProto::MraReplyBlogStatus(WPARAM wParam, LPARAM lParam) +{ + if (!m_bLoggedIn) + return 0; + + size_t dwBlogStatusMsgSize = 0; + mraGetStaticStringW((HANDLE)wParam, DBSETTING_BLOGSTATUS, NULL, 0, &dwBlogStatusMsgSize); + if (dwBlogStatusMsgSize || wParam == 0) + MraSendReplyBlogStatus((HANDLE)wParam); + + return 0; +} + +INT_PTR CMraProto::MraViewVideo(WPARAM wParam, LPARAM lParam) +{ + if (!m_bLoggedIn) + return 0; + + DWORD dwContactEMailMRCount = GetContactEMailCount((HANDLE)wParam, TRUE); + if (dwContactEMailMRCount) { + if (dwContactEMailMRCount == 1) { + CHAR szEMail[MAX_EMAIL_LEN]; + size_t dwEMailSize; + if (GetContactFirstEMail((HANDLE)wParam, TRUE, szEMail, SIZEOF(szEMail), &dwEMailSize)) + MraMPopSessionQueueAddUrlAndEMail(hMPopSessionQueue, MRA_VIDEO_URL, sizeof(MRA_VIDEO_URL), szEMail, dwEMailSize); + } + else MraSelectEMailDlgShow((HANDLE)wParam, MRA_SELECT_EMAIL_TYPE_VIEW_VIDEO); + } + return 0; +} + +INT_PTR CMraProto::MraAnswers(WPARAM wParam, LPARAM lParam) +{ + if (!m_bLoggedIn) + return 0; + + DWORD dwContactEMailMRCount = GetContactEMailCount((HANDLE)wParam, TRUE); + if (dwContactEMailMRCount) { + if (dwContactEMailMRCount == 1) { + CHAR szEMail[MAX_EMAIL_LEN]; + size_t dwEMailSize; + if (GetContactFirstEMail((HANDLE)wParam, TRUE, szEMail, SIZEOF(szEMail), &dwEMailSize)) + MraMPopSessionQueueAddUrlAndEMail(hMPopSessionQueue, MRA_ANSWERS_URL, sizeof(MRA_ANSWERS_URL), szEMail, dwEMailSize); + } + else MraSelectEMailDlgShow((HANDLE)wParam, MRA_SELECT_EMAIL_TYPE_ANSWERS); + } + return 0; +} + +INT_PTR CMraProto::MraWorld(WPARAM wParam, LPARAM lParam) +{ + if (!m_bLoggedIn) + return 0; + + DWORD dwContactEMailMRCount = GetContactEMailCount((HANDLE)wParam, TRUE); + if (dwContactEMailMRCount) { + if (dwContactEMailMRCount == 1) { + CHAR szEMail[MAX_EMAIL_LEN]; + size_t dwEMailSize; + if (GetContactFirstEMail((HANDLE)wParam, TRUE, szEMail, SIZEOF(szEMail), &dwEMailSize)) + MraMPopSessionQueueAddUrlAndEMail(hMPopSessionQueue, MRA_WORLD_URL, sizeof(MRA_WORLD_URL), szEMail, dwEMailSize); + } + else MraSelectEMailDlgShow((HANDLE)wParam, MRA_SELECT_EMAIL_TYPE_WORLD); + } + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +int CMraProto::MraContactDeleted(WPARAM wParam, LPARAM lParam) +{ + HANDLE hContact = (HANDLE)wParam; + if (!m_bLoggedIn || !hContact) + return 0; + + if ( IsContactMra(hContact)) { + CHAR szEMail[MAX_EMAIL_LEN]; + DWORD dwID, dwGroupID; + size_t dwEMailSize; + GetContactBasicInfoW(hContact, &dwID, &dwGroupID, NULL, NULL, NULL, szEMail, SIZEOF(szEMail), &dwEMailSize, NULL, 0, NULL, NULL, 0, NULL); + + MraSetContactStatus(hContact, ID_STATUS_OFFLINE); + if ( !db_get_b(hContact, "CList", "NotOnList", 0) || dwID != -1) + MraModifyContactW(hContact, dwID, CONTACT_FLAG_REMOVED, dwGroupID, szEMail, dwEMailSize, NULL, 0, NULL, 0); + MraAvatarsDeleteContactAvatarFile(hAvatarsQueueHandle, hContact); + } + return 0; +} + +int CMraProto::MraDbSettingChanged(WPARAM wParam, LPARAM lParam) +{ + if (!m_bLoggedIn || !lParam) + return 0; + + HANDLE hContact = (HANDLE)wParam; + DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING*)lParam; + + if (hContact) { + // это наш контакт, он не временный (есть в списке на сервере) и его обновление разрешено + if ( IsContactMra(hContact) && !db_get_b(hContact, "CList", "NotOnList", 0) && mraGetDword(hContact, "HooksLocked", FALSE) == FALSE) { + CHAR szEMail[MAX_EMAIL_LEN], szPhones[MAX_EMAIL_LEN]; + WCHAR wszNick[MAX_EMAIL_LEN]; + DWORD dwID, dwGroupID, dwContactFlag; + size_t dwEMailSize, dwNickSize, dwPhonesSize; + + if ( CompareStringA( MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), NORM_IGNORECASE, cws->szModule, -1, "CList", 5) == CSTR_EQUAL) { + // MyHandle setting + if (CompareStringA( MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), NORM_IGNORECASE, cws->szSetting, -1, "MyHandle", 8) == CSTR_EQUAL) { + LPWSTR lpwszNewNick; + + // allways store custom nick + if (cws->value.type == DBVT_DELETED) { + lstrcpynW(wszNick, GetContactNameW(hContact), SIZEOF(wszNick)); + lpwszNewNick = wszNick; + dwNickSize = lstrlenW(lpwszNewNick); + DB_SetStringExW(hContact, "CList", "MyHandle", lpwszNewNick, dwNickSize); + } + else if (cws->value.pszVal) { + switch (cws->value.type) { + case DBVT_WCHAR: + lpwszNewNick = cws->value.pwszVal; + dwNickSize = lstrlenW(lpwszNewNick); + break; + case DBVT_UTF8: + lpwszNewNick = wszNick; + dwNickSize = MultiByteToWideChar(CP_UTF8, 0, cws->value.pszVal, -1, wszNick, SIZEOF(wszNick)); + break; + case DBVT_ASCIIZ: + lpwszNewNick = wszNick; + dwNickSize = MultiByteToWideChar(MRA_CODE_PAGE, 0, cws->value.pszVal, -1, wszNick, SIZEOF(wszNick)); + break; + default: + lpwszNewNick = NULL; + dwNickSize = 0; + break; + } + if (lpwszNewNick) + if (GetContactBasicInfoW(hContact, &dwID, &dwGroupID, &dwContactFlag, NULL, NULL, szEMail, SIZEOF(szEMail), &dwEMailSize, NULL, 0, NULL, szPhones, SIZEOF(szPhones), &dwPhonesSize) == NO_ERROR) + MraModifyContactW(hContact, dwID, dwContactFlag, dwGroupID, szEMail, dwEMailSize, lpwszNewNick, dwNickSize, szPhones, dwPhonesSize); + } + } + // Group setting + else if ( CompareStringA( MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), NORM_IGNORECASE, cws->szSetting, -1, "Group", 5) == CSTR_EQUAL ) { + // manage group on server + switch (cws->value.type) { + case DBVT_ASCIIZ: + break; + case DBVT_DELETED: + break; + } + } + // NotOnList setting. Has a temporary contact just been added permanently? + else if ( CompareStringA( MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), NORM_IGNORECASE, cws->szSetting, -1, "NotOnList", 9) == CSTR_EQUAL) { + if (cws->value.type == DBVT_DELETED || (cws->value.type == DBVT_BYTE && cws->value.bVal == 0)) { + WCHAR wszAuthMessage[MAX_PATH]; + size_t dwAuthMessageSize; + if ( mraGetStaticStringW(NULL, "AuthMessage", wszAuthMessage, SIZEOF(wszAuthMessage), &dwAuthMessageSize) == FALSE) { + lstrcpynW(wszAuthMessage, TranslateW(MRA_DEFAULT_AUTH_MESSAGE), SIZEOF(wszAuthMessage)); + dwAuthMessageSize = lstrlenW(wszAuthMessage); + } + + DBDeleteContactSetting(hContact, "CList", "Hidden"); + GetContactBasicInfoW(hContact, NULL, &dwGroupID, &dwContactFlag, NULL, NULL, szEMail, SIZEOF(szEMail), &dwEMailSize, wszNick, SIZEOF(wszNick), &dwNickSize, szPhones, SIZEOF(szPhones), &dwPhonesSize); + MraAddContactW(hContact, dwContactFlag, dwGroupID, szEMail, dwEMailSize, wszNick, dwNickSize, szPhones, dwPhonesSize, wszAuthMessage, dwAuthMessageSize, 0); + } + } + // Hidden setting + else if ( CompareStringA( MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), NORM_IGNORECASE, cws->szSetting, -1, "Hidden" , 6) == CSTR_EQUAL) { + GetContactBasicInfoW(hContact, &dwID, &dwGroupID, &dwContactFlag, NULL, NULL, szEMail, SIZEOF(szEMail), &dwEMailSize, wszNick, SIZEOF(wszNick), &dwNickSize, szPhones, SIZEOF(szPhones), &dwPhonesSize); + if (cws->value.type == DBVT_DELETED || (cws->value.type == DBVT_BYTE && cws->value.bVal == 0)) + dwContactFlag &= ~CONTACT_FLAG_SHADOW; + else + dwContactFlag |= CONTACT_FLAG_SHADOW; + + MraModifyContactW(hContact, dwID, dwContactFlag, dwGroupID, szEMail, dwEMailSize, wszNick, dwNickSize, szPhones, dwPhonesSize); + } + } + // Ignore section + else if ( CompareStringA( MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), NORM_IGNORECASE, cws->szModule, -1, "Ignore", 6) == CSTR_EQUAL) { + if ( CompareStringA( MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), NORM_IGNORECASE, cws->szSetting, -1, "Mask1", 5) == CSTR_EQUAL) { + GetContactBasicInfoW(hContact, &dwID, &dwGroupID, &dwContactFlag, NULL, NULL, szEMail, SIZEOF(szEMail), &dwEMailSize, wszNick, SIZEOF(wszNick), &dwNickSize, szPhones, SIZEOF(szPhones), &dwPhonesSize); + if (cws->value.type == DBVT_DELETED || (cws->value.type == DBVT_DWORD && cws->value.dVal&IGNOREEVENT_MESSAGE) == 0) + dwContactFlag &= ~CONTACT_FLAG_IGNORE; + else + dwContactFlag |= CONTACT_FLAG_IGNORE; + + MraModifyContactW(hContact, dwID, dwContactFlag, dwGroupID, szEMail, dwEMailSize, wszNick, dwNickSize, szPhones, dwPhonesSize); + } + } + // User info section + else if (CompareStringA( MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), NORM_IGNORECASE, cws->szModule, -1, "UserInfo", 8) == CSTR_EQUAL) { + if ( CompareStringA( MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), NORM_IGNORECASE, cws->szSetting, -1, "MyPhone0", 8) == CSTR_EQUAL || + CompareStringA( MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), NORM_IGNORECASE, cws->szSetting, -1, "MyPhone1", 8) == CSTR_EQUAL || + CompareStringA( MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), NORM_IGNORECASE, cws->szSetting, -1, "MyPhone2", 8) == CSTR_EQUAL) { + GetContactBasicInfoW(hContact, &dwID, &dwGroupID, &dwContactFlag, NULL, NULL, szEMail, SIZEOF(szEMail), &dwEMailSize, wszNick, SIZEOF(wszNick), &dwNickSize, szPhones, SIZEOF(szPhones), &dwPhonesSize); + MraModifyContactW(hContact, dwID, dwContactFlag, dwGroupID, szEMail, dwEMailSize, wszNick, dwNickSize, szPhones, dwPhonesSize); + } + } + } + } + // not contact + else { + if ( CompareStringA( MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), NORM_IGNORECASE, cws->szModule, -1, "CListGroups", 11) == CSTR_EQUAL) { + // manage group on server + switch (cws->value.type) { + case DBVT_ASCIIZ: + break; + case DBVT_DELETED: + break; + } + } + } + + return 0; +} + +int CMraProto::MraRebuildContactMenu(WPARAM wParam, LPARAM lParam) +{ + BOOL bIsContactMRA, bHasEMail, bHasEMailMR, bChatAgent; + DWORD dwContactSeverFlags = 0; + size_t dwBlogStatusMsgSize = 0; + HANDLE hContact = (HANDLE)wParam; + + // proto own contact + bIsContactMRA = IsContactMra(hContact); + if (bIsContactMRA) { + bHasEMail = TRUE; + bHasEMailMR = TRUE; + bChatAgent = IsContactChatAgent(hContact); + GetContactBasicInfoW(hContact, NULL, NULL, NULL, &dwContactSeverFlags, NULL, NULL, 0, NULL, NULL, 0, NULL, NULL, 0, NULL); + mraGetStaticStringW(hContact, DBSETTING_BLOGSTATUS, NULL, 0, &dwBlogStatusMsgSize); + } + // non proto contact + else { + bHasEMail = FALSE; + bHasEMailMR = FALSE; + bChatAgent = FALSE; + if (mraGetByte(NULL, "HideMenuItemsForNonMRAContacts", MRA_DEFAULT_HIDE_MENU_ITEMS_FOR_NON_MRA) == FALSE) + if (IsContactMraProto(hContact) == FALSE)// избегаем добавления менюшек в контакты других копий MRA + if (GetContactEMailCount(hContact, FALSE)) { + bHasEMail = TRUE; + if (GetContactEMailCount(hContact, TRUE)) bHasEMailMR = TRUE; + } + } + + //"Request authorization" + CListShowMenuItem(hContactMenuItems[0], (m_bLoggedIn && bIsContactMRA));// && (dwContactSeverFlags&CONTACT_INTFLAG_NOT_AUTHORIZED) + + //"Grant authorization" + CListShowMenuItem(hContactMenuItems[1], (m_bLoggedIn && bIsContactMRA && bChatAgent == FALSE)); + + //"&Send postcard" + CListShowMenuItem(hContactMenuItems[2], (m_bLoggedIn && bHasEMail && bChatAgent == FALSE)); + + //"&View Album" + CListShowMenuItem(hContactMenuItems[3], (m_bLoggedIn && bHasEMailMR && bChatAgent == FALSE)); + + //"&Read Blog" + CListShowMenuItem(hContactMenuItems[4], (m_bLoggedIn && bHasEMailMR && bChatAgent == FALSE)); + + //"Reply Blog Status" + CListShowMenuItem(hContactMenuItems[5], (m_bLoggedIn && dwBlogStatusMsgSize && bChatAgent == FALSE)); + + //"View Video" + CListShowMenuItem(hContactMenuItems[6], (m_bLoggedIn && bHasEMailMR && bChatAgent == FALSE)); + + //"Answers" + CListShowMenuItem(hContactMenuItems[7], (m_bLoggedIn && bHasEMailMR && bChatAgent == FALSE)); + + //"World" + CListShowMenuItem(hContactMenuItems[8], (m_bLoggedIn && bHasEMailMR && bChatAgent == FALSE)); + + //"Send &Nudge" + if (heNudgeReceived == NULL) + CListShowMenuItem(hContactMenuItems[9], (m_bLoggedIn && bIsContactMRA)); + + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Extra icons + +int CMraProto::MraExtraIconsApply(WPARAM wParam, LPARAM lParam) +{ + SetExtraIcons((HANDLE)wParam); + return 0; +} + +int CMraProto::MraExtraIconsRebuild(WPARAM wParam, LPARAM lParam) +{ + for (size_t i = 0; i < ADV_ICON_MAX; i++) + hAdvancedStatusItems[i] = (HANDLE)CallService(MS_CLIST_EXTRA_ADD_ICON, (WPARAM)IconLibGetIcon(gdiExtraStatusIconsItems[i].hIconHandle), 0); + + for (size_t i = 0; i < MRA_XSTATUS_COUNT+1; i++) + hXStatusAdvancedStatusItems[i] = (HANDLE)CallService(MS_CLIST_EXTRA_ADD_ICON, (WPARAM)IconLibGetIcon(hXStatusAdvancedStatusIcons[i]), 0); + + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +int CMraProto::MraRebuildStatusMenu(WPARAM wParam, LPARAM lParam) +{ + CHAR szServiceFunction[MAX_PATH*2], *pszServiceFunctionName, szValueName[MAX_PATH]; + strncpy(szServiceFunction, m_szModuleName, sizeof(szServiceFunction)); + pszServiceFunctionName = szServiceFunction + strlen(m_szModuleName); + + WCHAR szItem[MAX_PATH+64], szStatusTitle[STATUS_TITLE_MAX+4]; + mir_sntprintf(szItem, SIZEOF(szItem), L"%s Custom Status", m_tszUserName); + + CLISTMENUITEM mi = {0}; + mi.cbSize = sizeof(mi); + mi.position = 2000060000; + mi.popupPosition = 500085000; + mi.ptszPopupName = szItem; + mi.flags = (CMIF_UNICODE|CMIF_ICONFROMICOLIB); + mi.pszService = szServiceFunction; + mi.pszContactOwner = m_szModuleName; + + for (size_t i = 0; i < MRA_XSTATUS_COUNT; i++) { + mir_snprintf(pszServiceFunctionName, 100, "/menuXStatus%ld", i); + mi.position++; + if (i) { + mir_snprintf(szValueName, SIZEOF(szValueName), "XStatus%ldName", i); + if (mraGetStaticStringW(NULL, szValueName, szStatusTitle, (STATUS_TITLE_MAX+1), NULL)) { + szStatusTitle[STATUS_TITLE_MAX] = 0; + mi.ptszName = szStatusTitle; + } + else mi.ptszName = lpcszXStatusNameDef[i]; + + mi.icolibItem = hXStatusAdvancedStatusIcons[i]; + } + else { + mi.ptszName = lpcszXStatusNameDef[i]; + mi.hIcon = NULL; + } + hXStatusMenuItems[i] = Menu_AddStatusMenuItem(&mi); + } + return 0; +} + +INT_PTR CMraProto::MraSetListeningTo(WPARAM wParam, LPARAM lParam) +{ + LISTENINGTOINFO *pliInfo = (LISTENINGTOINFO*)lParam; + + if (pliInfo == NULL || pliInfo->cbSize != sizeof(LISTENINGTOINFO)) + { + MraChangeUserBlogStatus(MRIM_BLOG_STATUS_MUSIC, NULL, 0, 0); + mraDelValue(NULL, DBSETTING_BLOGSTATUSMUSIC); + } + else if (pliInfo->dwFlags & LTI_UNICODE) { + LPWSTR pwszListeningTo; + WCHAR wszListeningTo[MICBLOG_STATUS_MAX+4]; + size_t dwListeningToSize; + + if ( ServiceExists(MS_LISTENINGTO_GETPARSEDTEXT)) { + pwszListeningTo = (LPWSTR)CallService(MS_LISTENINGTO_GETPARSEDTEXT, (WPARAM)L"%track%. %title% - %artist% - %player%", (LPARAM)pliInfo); + dwListeningToSize = lstrlenW(pwszListeningTo); + } + else { + pwszListeningTo = wszListeningTo; + dwListeningToSize = mir_sntprintf(pwszListeningTo, SIZEOF(wszListeningTo), L"%s. %s - %s - %s", pliInfo->ptszTrack?pliInfo->ptszTrack:L"", pliInfo->ptszTitle?pliInfo->ptszTitle:L"", pliInfo->ptszArtist?pliInfo->ptszArtist:L"", pliInfo->ptszPlayer?pliInfo->ptszPlayer:L""); + } + + mraSetStringExW(NULL, DBSETTING_BLOGSTATUSMUSIC, pwszListeningTo, dwListeningToSize); + MraChangeUserBlogStatus(MRIM_BLOG_STATUS_MUSIC, pwszListeningTo, dwListeningToSize, 0); + + if (pwszListeningTo != wszListeningTo) + mir_free(pwszListeningTo); + } + + return 0; +} + +int CMraProto::MraMusicChanged(WPARAM wParam, LPARAM lParam) +{ + switch (wParam) { + case WAT_EVENT_PLAYERSTATUS: + // stopped + if (1 == lParam) { + mraDelValue(NULL, DBSETTING_BLOGSTATUSMUSIC); + MraChangeUserBlogStatus(MRIM_BLOG_STATUS_MUSIC, NULL, 0, 0); + } + break; + + case WAT_EVENT_NEWTRACK: + { + SONGINFO *psiSongInfo; + if (WAT_RES_OK == CallService(MS_WAT_GETMUSICINFO, WAT_INF_UNICODE, (LPARAM)&psiSongInfo)) { + WCHAR wszMusic[MICBLOG_STATUS_MAX+4]; + size_t dwMusicSize; + + dwMusicSize = mir_sntprintf(wszMusic, SIZEOF(wszMusic), L"%ld. %s - %s - %s", psiSongInfo->track, psiSongInfo->artist, psiSongInfo->title, psiSongInfo->player); + mraSetStringExW(NULL, DBSETTING_BLOGSTATUSMUSIC, wszMusic, dwMusicSize); + MraChangeUserBlogStatus(MRIM_BLOG_STATUS_MUSIC, wszMusic, dwMusicSize, 0); + } + } + break; + } + + return 0; +} + +DWORD CMraProto::MraSetXStatusInternal(DWORD dwXStatus) +{ + DWORD dwOldStatusMode; + + if ( IsXStatusValid(dwXStatus)) { + CHAR szValueName[MAX_PATH]; + WCHAR szBuff[4096]; + size_t dwBuffSize; + + // obsolete (TODO: remove in next version) + mir_snprintf(szValueName, SIZEOF(szValueName), "XStatus%ldName", dwXStatus); + if (mraGetStaticStringW(NULL, szValueName, szBuff, SIZEOF(szBuff), &dwBuffSize) == FALSE) { + lstrcpynW(szBuff, lpcszXStatusNameDef[dwXStatus], SIZEOF(szBuff)); + dwBuffSize = lstrlenW(szBuff); + } + if (dwBuffSize>STATUS_TITLE_MAX) dwBuffSize = STATUS_TITLE_MAX; + mraSetStringExW(NULL, DBSETTING_XSTATUSNAME, szBuff, dwBuffSize); + + // obsolete (TODO: remove in next version) + mir_snprintf(szValueName, SIZEOF(szValueName), "XStatus%ldMsg", dwXStatus); + if (mraGetStaticStringW(NULL, szValueName, szBuff, SIZEOF(szBuff), &dwBuffSize)) { + if (dwBuffSize>STATUS_DESC_MAX) dwBuffSize = STATUS_DESC_MAX; + mraSetStringExW(NULL, DBSETTING_XSTATUSMSG, szBuff, dwBuffSize); + } + else mraDelValue(NULL, DBSETTING_XSTATUSMSG); + } + else { + mraDelValue(NULL, DBSETTING_XSTATUSNAME); + mraDelValue(NULL, DBSETTING_XSTATUSMSG); + dwXStatus = MRA_MIR_XSTATUS_NONE; + } + + dwOldStatusMode = InterlockedExchange((volatile LONG*)&m_iXStatus, dwXStatus); + mraSetByte(NULL, DBSETTING_XSTATUSID, (BYTE)dwXStatus); + + MraSendNewStatus(m_iStatus, dwXStatus, NULL, 0, NULL, 0); + + return dwOldStatusMode; +} + +// obsolete (TODO: remove in next version) +INT_PTR CMraProto::MraSetXStatus(WPARAM wParam, LPARAM lParam) +{ + INT_PTR iRet = 0; + if ( IsXStatusValid(wParam) || wParam == MRA_MIR_XSTATUS_NONE) { + MraSetXStatusInternal(wParam); + iRet = wParam; + } + return iRet; +} + +INT_PTR CMraProto::MraSetXStatusEx(WPARAM wParam, LPARAM lParam) +{ + INT_PTR iRet = 1; + DWORD dwXStatus; + ICQ_CUSTOM_STATUS *pData = (ICQ_CUSTOM_STATUS*)lParam; + + if (pData->cbSize >= sizeof(ICQ_CUSTOM_STATUS)) { + iRet = 0; + + if (pData->flags & CSSF_MASK_STATUS) { + dwXStatus = *pData->status; + if ( IsXStatusValid(dwXStatus) == FALSE && dwXStatus != MRA_MIR_XSTATUS_NONE) + iRet = 1; + } + else dwXStatus = m_iXStatus; + + if (pData->flags & (CSSF_MASK_NAME|CSSF_MASK_MESSAGE) && iRet == 0) { + if ( IsXStatusValid(dwXStatus) || dwXStatus == MRA_MIR_XSTATUS_NONE) { + CHAR szValueName[MAX_PATH]; + size_t dwBuffSize; + + // set custom status name + if (pData->flags & CSSF_MASK_NAME) { + mir_snprintf(szValueName, SIZEOF(szValueName), "XStatus%ldName", dwXStatus); + if (pData->flags & CSSF_UNICODE) { + dwBuffSize = lstrlenW(pData->pwszName); + if (dwBuffSize>STATUS_TITLE_MAX) dwBuffSize = STATUS_TITLE_MAX; + + mraSetStringExW(NULL, szValueName, pData->pwszName, dwBuffSize); + mraSetStringExW(NULL, DBSETTING_XSTATUSNAME, pData->pwszName, dwBuffSize); + } + else { + dwBuffSize = lstrlenA(pData->pszName); + if (dwBuffSize > STATUS_TITLE_MAX) + dwBuffSize = STATUS_TITLE_MAX; + + mraSetStringExA(NULL, szValueName, pData->pszName, dwBuffSize); + mraSetStringExA(NULL, DBSETTING_XSTATUSNAME, pData->pszName, dwBuffSize); + } + } + + // set custom status message + if (pData->flags & CSSF_MASK_MESSAGE) { + mir_snprintf(szValueName, SIZEOF(szValueName), "XStatus%ldMsg", dwXStatus); + if (pData->flags & CSSF_UNICODE) { + dwBuffSize = lstrlenW(pData->pwszMessage); + if (dwBuffSize>STATUS_TITLE_MAX) dwBuffSize = STATUS_DESC_MAX; + + mraSetStringExW(NULL, szValueName, pData->pwszMessage, dwBuffSize); + mraSetStringExW(NULL, DBSETTING_XSTATUSMSG, pData->pwszMessage, dwBuffSize); + } + else { + dwBuffSize = lstrlenA(pData->pszMessage); + if (dwBuffSize>STATUS_TITLE_MAX) dwBuffSize = STATUS_DESC_MAX; + + mraSetStringExA(NULL, szValueName, pData->pszMessage, dwBuffSize); + mraSetStringExA(NULL, DBSETTING_XSTATUSMSG, pData->pszMessage, dwBuffSize); + } + } + } + // неудача только если мы не ставили Хстатус и попытались записать сообщения для "нет" статуса + else if ( !(pData->flags & CSSF_MASK_STATUS)) + iRet = 1; + } + + // set/update xstatus code and/or message + if (pData->flags & (CSSF_MASK_STATUS|CSSF_MASK_NAME|CSSF_MASK_MESSAGE) && iRet == 0) + MraSetXStatusInternal(dwXStatus); + + // hide menu items + if (pData->flags & CSSF_DISABLE_UI) { + bHideXStatusUI = (*pData->wParam)? FALSE:TRUE; + for (DWORD i = 0; i < MRA_XSTATUS_COUNT; i++) + CListShowMenuItem(hXStatusMenuItems[i], !bHideXStatusUI); + } + } + return iRet; +} + +INT_PTR CMraProto::MraGetXStatus(WPARAM wParam, LPARAM lParam) +{ + if (m_bLoggedIn) { + if (wParam) *((CHAR**)wParam) = DBSETTING_XSTATUSNAME; + if (lParam) *((CHAR**)lParam) = DBSETTING_XSTATUSMSG; + return m_iXStatus; + } + + return 0; +} + +INT_PTR CMraProto::MraGetXStatusEx(WPARAM wParam, LPARAM lParam) +{ + INT_PTR iRet = 1; + HANDLE hContact = (HANDLE)wParam; + ICQ_CUSTOM_STATUS *pData = (ICQ_CUSTOM_STATUS*)lParam; + + if (pData->cbSize >= sizeof(ICQ_CUSTOM_STATUS)) { + DWORD dwXStatus; + + iRet = 0; + + // fill status member + if (pData->flags & CSSF_MASK_STATUS) + *pData->status = m_iXStatus; + + // fill status name member + if (pData->flags & CSSF_MASK_NAME) { + if (pData->flags & CSSF_DEFAULT_NAME) { + dwXStatus = (*pData->wParam); + if ( IsXStatusValid(dwXStatus)) { + if (pData->flags & CSSF_UNICODE) { + lstrcpynW(pData->pwszName, lpcszXStatusNameDef[dwXStatus], (STATUS_TITLE_MAX+1)); + } + else { + size_t dwStatusTitleSize = lstrlenW( lpcszXStatusNameDef[dwXStatus] ); + if (dwStatusTitleSize>STATUS_TITLE_MAX) dwStatusTitleSize = STATUS_TITLE_MAX; + + WideCharToMultiByte(MRA_CODE_PAGE, 0, lpcszXStatusNameDef[dwXStatus], (DWORD)dwStatusTitleSize, pData->pszName, MAX_PATH, NULL, NULL ); + (*((CHAR*)(pData->pszName+dwStatusTitleSize))) = 0; + } + } + else iRet = 1; + } + else { + if (pData->flags & CSSF_UNICODE) + mraGetStaticStringW(hContact, DBSETTING_XSTATUSNAME, pData->pwszName, (STATUS_TITLE_MAX+1), NULL); + else + mraGetStaticStringA(hContact, DBSETTING_XSTATUSNAME, pData->pszName, (STATUS_TITLE_MAX+1), NULL); + } + } + + // fill status message member + if (pData->flags & CSSF_MASK_MESSAGE) { + if (pData->flags & CSSF_UNICODE) + mraGetStaticStringW(hContact, DBSETTING_XSTATUSMSG, pData->pwszMessage, (STATUS_DESC_MAX+1), NULL); + else + mraGetStaticStringA(hContact, DBSETTING_XSTATUSMSG, pData->pszMessage, (STATUS_DESC_MAX+1), NULL); + } + + if (pData->flags & CSSF_DISABLE_UI) + if (pData->wParam) + *pData->wParam = bHideXStatusUI; + + if (pData->flags & CSSF_STATUSES_COUNT) + if (pData->wParam) + *pData->wParam = MRA_XSTATUS_COUNT-1; + + //**deb можно оптимизировать, данный параметр возможно уже был вычислен при получении самих текстов + if (pData->flags & CSSF_STR_SIZES) { + if (pData->wParam) mraGetStaticStringW(hContact, DBSETTING_XSTATUSNAME, NULL, 0, (size_t*)pData->wParam); + if (pData->lParam) mraGetStaticStringW(hContact, DBSETTING_XSTATUSMSG, NULL, 0, (size_t*)pData->lParam); + } + } + return iRet; +} + +INT_PTR CMraProto::MraGetXStatusIcon(WPARAM wParam, LPARAM lParam) +{ + if (wParam == 0) + wParam = m_iXStatus; + + return (INT_PTR)IconLibGetIconEx(hXStatusAdvancedStatusIcons[wParam], lParam); +} + +DWORD CMraProto::MraSendNewStatus(DWORD dwStatusMir, DWORD dwXStatusMir, LPCWSTR lpwszStatusTitle, size_t dwStatusTitleSize, LPCWSTR lpwszStatusDesc, size_t dwStatusDescSize) +{ + if (!m_bLoggedIn) + return 0; + + CHAR szValueName[MAX_PATH]; + WCHAR wszStatusTitle[STATUS_TITLE_MAX+4], wszStatusDesc[STATUS_DESC_MAX+4]; + DWORD dwStatus, dwXStatus; + + dwStatus = GetMraStatusFromMiradaStatus(dwStatusMir, dwXStatusMir, &dwXStatus); + if ( IsXStatusValid(dwXStatusMir)) { + if (lpwszStatusTitle == NULL || dwStatusTitleSize == 0) { + mir_snprintf(szValueName, SIZEOF(szValueName), "XStatus%ldName", dwXStatusMir); + // custom xstatus name + if (mraGetStaticStringW(NULL, szValueName, wszStatusTitle, (STATUS_TITLE_MAX+1), &dwStatusTitleSize)) + lpwszStatusTitle = wszStatusTitle; + // default xstatus name + else { + lpwszStatusTitle = TranslateW(lpcszXStatusNameDef[dwXStatusMir]); + dwStatusTitleSize = lstrlenW(lpwszStatusTitle); + } + } + + if (lpwszStatusDesc == NULL || dwStatusDescSize == 0) { + mir_snprintf(szValueName, SIZEOF(szValueName), "XStatus%ldMsg", dwXStatusMir); + // custom xstatus description + if (mraGetStaticStringW(NULL, szValueName, wszStatusDesc, (STATUS_DESC_MAX+1), &dwStatusDescSize)) + lpwszStatusDesc = wszStatusDesc; + // default xstatus description + else { + lpwszStatusDesc = NULL; + dwStatusDescSize = 0; + } + } + } + else { + if (lpwszStatusTitle == NULL || dwStatusTitleSize == 0) { + lpwszStatusTitle = GetStatusModeDescriptionW(dwStatusMir); + dwStatusTitleSize = lstrlenW(lpwszStatusTitle); + } + } + + MraChangeStatusW(dwStatus, lpcszStatusUri[dwXStatus], lstrlenA(lpcszStatusUri[dwXStatus]), lpwszStatusTitle, dwStatusTitleSize, lpwszStatusDesc, dwStatusDescSize, ((mraGetByte(NULL, "RTFReceiveEnable", MRA_DEFAULT_RTF_RECEIVE_ENABLE)? FEATURE_FLAG_RTF_MESSAGE:0)|MRA_FEATURE_FLAGS)); + return 0; +} + +INT_PTR CMraProto::MraSendNudge(WPARAM wParam, LPARAM lParam) +{ + if (m_bLoggedIn && wParam) { + CHAR szEMail[MAX_EMAIL_LEN]; + LPWSTR lpwszAlarmMessage = TranslateW(MRA_ALARM_MESSAGE); + size_t dwEMailSize; + HANDLE hContact = (HANDLE)wParam; + + if (mraGetStaticStringA(hContact, "e-mail", szEMail, SIZEOF(szEMail), &dwEMailSize)) + if (MraMessageW(FALSE, hContact, 0, (MESSAGE_FLAG_RTF|MESSAGE_FLAG_ALARM), szEMail, dwEMailSize, lpwszAlarmMessage, lstrlenW(lpwszAlarmMessage), NULL, 0)) + return 0; + } + return 1; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Avatars + +INT_PTR CMraProto::MraGetAvatarCaps(WPARAM wParam, LPARAM lParam) +{ + switch (wParam) { + case AF_MAXSIZE: + return -1; + + case AF_PROPORTION: + return PIP_NONE; + + case AF_FORMATSUPPORTED: + return 0; // no formats to set + + case AF_ENABLED: + return 1; // allways on + + case AF_DONTNEEDDELAYS: + return 0; // need delay + + case AF_MAXFILESIZE: + return 0; + + case AF_DELAYAFTERFAIL: + return 5000; + } + + return 0; +} + + +INT_PTR CMraProto::MraGetAvatarInfo(WPARAM wParam, LPARAM lParam) +{ + if (lParam) { + PROTO_AVATAR_INFORMATIONT *ppai = (PROTO_AVATAR_INFORMATIONT*)lParam; + return (INT_PTR)MraAvatarsQueueGetAvatar(hAvatarsQueueHandle, (DWORD)wParam, ppai->hContact, NULL, (DWORD*)&ppai->format, ppai->filename); + } + return GAIR_NOAVATAR; +} + + +INT_PTR CMraProto::MraGetMyAvatar(WPARAM wParam, LPARAM lParam) +{ + if ( MraAvatarsGetFileName(hAvatarsQueueHandle, NULL, GetContactAvatarFormat(NULL, PA_FORMAT_DEFAULT), (LPTSTR)wParam, (size_t)lParam, NULL) == NO_ERROR) { + LPSTR lpsz = (LPSTR)wParam; + return 0; + } + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////////////// + +INT_PTR LoadModules(void) +{ + DebugPrintCRLFW(L"MRA/LoadModules - DONE"); + return 0; +} + +void UnloadModules() +{ + DebugPrintCRLFW(L"MRA/UnloadModules - DONE"); +} diff --git a/protocols/MRA/src/Sdk/Base64.h b/protocols/MRA/src/Sdk/Base64.h new file mode 100644 index 0000000000..d3cce03e9a --- /dev/null +++ b/protocols/MRA/src/Sdk/Base64.h @@ -0,0 +1,380 @@ +/* + * Copyright (c) 2003 Rozhuk Ivan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + + +#if !defined(AFX_BASE64__H__INCLUDED_) +#define AFX_BASE64__H__INCLUDED_ + + + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + + +//typedef unsigned char BYTE; +// +// BASE64 coding: +// 214 46 138 +// 11010100 00101110 10001010 +// ! ! ! +// ---------->>> convert 3 8bit to 4 6bit +// 110101 000010 111010 001010 +// 53 2 58 10 +// this numbers is offset in array coding below... +// + //01234567890123456789012345 +static BYTE *pbtCodingTableBASE64=(BYTE*)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; //52...63 +static BYTE btDeCodingTableBASE64[256]={64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,62,64,64,64,63,52,53,54,55,56,57,58,59,60,61,64,64,64,64,64,64,64,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,64,64,64,64,64,64,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64}; + + + + +__inline void BASE64CopyUnSafe(LPCVOID lpcSource,LPCVOID lpcDestination,size_t dwSize,size_t *pdwCopyedSize) +{// копируем только б64 символы + LPBYTE lpbSource,lpbDestination; + + lpbSource=(LPBYTE)lpcSource; + lpbDestination=(LPBYTE)lpcDestination; + while(dwSize--) + { + if ((*lpbSource)>32 && (*lpbSource)<128) (*lpbDestination++)=(*lpbSource); + lpbSource++; + } + if (pdwCopyedSize) (*pdwCopyedSize)=((size_t)lpbDestination-(size_t)lpcDestination); +} + + + +__inline DWORD BASE64EncodeUnSafe(LPCVOID lpcSource,size_t dwSourceSize,LPCVOID lpcDestination,size_t dwDestinationSize,size_t *pdwEncodedSize) +{// BASE64 кодирование + DWORD dwRetErrorCode; + size_t dwEncodedSize=((dwSourceSize*4+11)/12*4+1);//(((dwSourceSize+2)/3)*4); + + if ((dwDestinationSize>2]; // c1 + *(lpbtDestination++)=pbtCodingTableBASE64[(((*lpbtSource)<<4)&060) | ((lpbtSource[1]>>4)&017)]; // c2 + *(lpbtDestination++)=pbtCodingTableBASE64[((lpbtSource[1]<<2)&074) | ((lpbtSource[2]>>6)&03)]; // c3 + *(lpbtDestination++)=pbtCodingTableBASE64[lpbtSource[2] & 077]; // c4 + lpbtSource+=3; + } + + // If dwSourceSize was not a multiple of 3, then we have encoded too many characters. Adjust appropriately. + if(i==(dwSourceSize+1)) + {// There were only 2 bytes in that last group + lpbtDestination[-1]='='; + }else + if(i==(dwSourceSize+2)) + {// There was only 1 byte in that last group + lpbtDestination[-1]='='; + lpbtDestination[-2]='='; + } + + (*lpbtDestination)=0; + dwEncodedSize=(lpbtDestination-((LPBYTE)lpcDestination)); + +#else + __asm{ + push ebx // сохраняем регистр + push edi // сохраняем регистр + push esi // сохраняем регистр + + mov ebx,pbtCodingTableBASE64// ebx = адрес таблицы перекодировки + mov ecx,dwSourceSize // ecx = длинна входного буффера + mov edi,lpcDestination // edi = адрес выходного буффера + mov esi,lpcSource // esi = указатель на входной буффер + cld + jmp short read_loop_cmp + + //////////Code function/////////////////////////////////////////// + // функция кодировки + // eax - входящий буффер, используется только 3 байта //in buff, 3 byte used + // eax - выходящий буффер, используется 4 байта //out buff, 4 byte used + code_func: + // третья версия функции разложения, + // меняем местами два крайних байта + bswap eax + rol eax,6 + shl al,2 + ror eax,10 + shr ax,2 + shr al,2 + xlat + rol eax,8 + xlat + rol eax,8 + xlat + rol eax,8 + xlat + rol eax,8 + bswap eax// 188-235 + ret + ////////////////////////////////////////////////////////////////// + + /////////////Read & converting cycle////////////////////////////// + read_loop: + lodsd // читаем 4 байта + dec esi // используем только 3 + and eax,0x00FFFFFF + //==================================================== + // третья версия функции разложения, + // меняем местами два крайних байта + bswap eax + rol eax,6 + shl al,2 + ror eax,10 + shr ax,2 + shr al,2 + xlat + rol eax,8 + xlat + rol eax,8 + xlat + rol eax,8 + xlat + rol eax,8 + bswap eax + //==================================================== + stosd + sub ecx,3 + + read_loop_cmp: + cmp ecx,3 // проверяем, чтобы длинна была как минимум 4 байта + jg short read_loop // если длинна 3 и более байт, то продолжаем дальше + + ///////////////////////////////////////////////////////////////// + xor eax,eax // обнуляем регистр + cmp ecx,3 // сравниваем длинну с 3 + je short tree_byte_tail// если длинна 3 байта, то переходим к функции обрабатывающей остаток такой длинны + cmp ecx,2 // сравниваем длинну с 2 + je short two_byte_tail // если длинна 2 байта, то переходим к функции обрабатывающей остаток такой длинны + // иначе, длинна остатка равна 1 + //////////tail 1 byte//////////////////////////////////////////// + mov al,byte ptr [esi] // читаем 1 байт + call code_func // преобразуем + and eax,0x0000FFFF // обнуляем последние два байта + or eax,0x3D3D0000 // записываем в последние два байта 61("=") + jmp short end_tail_handler // + + //////////tail 2 byte//////////////////////////////////////////// + two_byte_tail: + mov ax,word ptr [esi] // читаем 2 байта + call code_func // преобразуем + and eax,0x00FFFFFF // обнуляем последний байт + or eax,0x3D000000 // записываем в последний байт 61("=") + jmp short end_tail_handler // + + //////////tail 3 byte//////////////////////////////////////////// + tree_byte_tail: + lodsw + ror eax,16 + mov al,byte ptr [esi] // читаем 1 байт + rol eax,16 + call code_func // преобразуем + + end_tail_handler: + stosd // записываем 4 байта, уже закодированных + + sub edi,lpcDestination // вычисляем колличество байт, записанных в выходной буффер + mov dwEncodedSize,edi // записываем колличество байт в возвращаемую переменную + pop esi // восстанавливаем содержимое регистра + pop edi // восстанавливаем содержимое регистра + pop ebx // восстанавливаем содержимое регистра + } +#endif + dwRetErrorCode=NO_ERROR; + }else{ + dwRetErrorCode=ERROR_INVALID_HANDLE; + } + } + if (pdwEncodedSize) (*pdwEncodedSize)=dwEncodedSize; + +return(dwRetErrorCode); +} + + +__inline DWORD BASE64Encode(LPCVOID lpcSource,size_t dwSourceSize,LPCVOID lpcDestination,size_t dwDestinationSize,size_t *pdwEncodedSize) +{// BASE64 кодирование + DWORD dwRetErrorCode; + + __try + { + dwRetErrorCode=BASE64EncodeUnSafe(lpcSource,dwSourceSize,lpcDestination,dwDestinationSize,pdwEncodedSize); + }__except(EXCEPTION_EXECUTE_HANDLER){ + dwRetErrorCode=ERROR_INVALID_ADDRESS; + } +return(dwRetErrorCode); +} + + + +__inline DWORD BASE64DecodeUnSafe(LPCVOID lpcSource,size_t dwSourceSize,LPCVOID lpcDestination,size_t dwDestinationSize,size_t *pdwDecodedSize) +{// BASE64 декодирование + DWORD dwRetErrorCode; + size_t dwDecodedSize=((dwSourceSize>>2)*3);// ((dwSourceSize/4)*3); + + if ((dwDestinationSize3) + { +#ifdef _WIN64 + LPBYTE lpbtSource=(LPBYTE)lpcSource,lpbtDestination=(LPBYTE)lpcDestination; + + for(size_t i=0;i> 4); + *(lpbtDestination++)=(unsigned char) (btDeCodingTableBASE64[lpbtSource[1]] << 4 | btDeCodingTableBASE64[lpbtSource[2]] >> 2); + *(lpbtDestination++)=(unsigned char) (btDeCodingTableBASE64[lpbtSource[2]] << 6 | btDeCodingTableBASE64[lpbtSource[3]]); + lpbtSource+=4; + } + + dwDecodedSize=(lpbtDestination-((LPBYTE)lpcDestination)); + if ((*((BYTE*)lpcSource+(dwSourceSize-1)))=='=') dwDecodedSize--; + if ((*((BYTE*)lpcSource+(dwSourceSize-2)))=='=') dwDecodedSize--; + + +#else + __asm{ + push ebx // сохраняем регистр + push edi // сохраняем регистр + push esi // сохраняем регистр + + mov ebx,offset btDeCodingTableBASE64// ebx = адрес таблицы перекодировки + mov ecx,dwSourceSize // ecx = длинна входного буффера + mov edi,lpcDestination // edi = адрес выходного буффера + mov esi,lpcSource // esi = указатель на входной буффер + cld + + read_loop: + lodsd // читаем 4 байта + //===============bit conversion==================================== + // eax - входящий буффер, используется только 4 байта //in buff, 4 byte used + // eax - выходящий буффер, используется только 3 байта //out buff, 3 byte used + // третья версия функции сложения бит + bswap eax + + ror eax,8 + xlat + + ror eax,8 + xlat + + ror eax,8 + xlat + + ror eax,8 + xlat + + shl al,2 + shl ax,2 + rol eax,10 + shr al,2 + ror eax,6 + bswap eax + mov edx,eax + //234-250 + //=============================================================== + stosd + dec edi + sub ecx,4 + cmp ecx,3 + jg short read_loop + + sub edi,lpcDestination // вычисляем колличество байт, записанных в выходной буффер + mov dwDecodedSize,edi // записываем колличество байт в возвращаемую переменную + pop esi // восстанавливаем содержимое регистра + pop edi // восстанавливаем содержимое регистра + pop ebx // восстанавливаем содержимое регистра + } + + if ((*((BYTE*)lpcSource+(dwSourceSize-1)))=='=') dwDecodedSize--; + if ((*((BYTE*)lpcSource+(dwSourceSize-2)))=='=') dwDecodedSize--; +#endif + dwRetErrorCode=NO_ERROR; + }else{// во входном буффере слишком мало данных + dwRetErrorCode=ERROR_INSUFFICIENT_BUFFER; + } + }else{ + dwRetErrorCode=ERROR_INVALID_HANDLE; + } + } + + if (pdwDecodedSize) (*pdwDecodedSize)=dwDecodedSize; +return(dwRetErrorCode); +} + + +__inline DWORD BASE64Decode(LPCVOID lpcSource,size_t dwSourceSize,LPCVOID lpcDestination,size_t dwDestinationSize,size_t *pdwDecodedSize) +{// BASE64 декодирование + DWORD dwRetErrorCode; + + __try + { + dwRetErrorCode=BASE64DecodeUnSafe(lpcSource,dwSourceSize,lpcDestination,dwDestinationSize,pdwDecodedSize); + }__except(EXCEPTION_EXECUTE_HANDLER){ + dwRetErrorCode=ERROR_INVALID_ADDRESS; + } +return(dwRetErrorCode); +} + + +__inline DWORD BASE64DecodeFormated(LPCVOID lpcSource,size_t dwSourceSize,LPCVOID lpcDestination,size_t dwDestinationSize,size_t *pdwDecodedSize) +{// BASE64 декодирование и игнорирование форматирования + DWORD dwRetErrorCode; + + if (dwSourceSize<=dwDestinationSize) + { + BASE64CopyUnSafe(lpcSource,lpcDestination,dwSourceSize,&dwSourceSize); + dwRetErrorCode=BASE64DecodeUnSafe(lpcDestination,dwSourceSize,lpcDestination,dwDestinationSize,pdwDecodedSize); + }else{// во входном буффере слишком мало данных + dwRetErrorCode=ERROR_INSUFFICIENT_BUFFER; + } + +return(dwRetErrorCode); +} + + + +#endif // !defined(AFX_BASE64__H__INCLUDED_) diff --git a/protocols/MRA/src/Sdk/BuffToLowerCase.h b/protocols/MRA/src/Sdk/BuffToLowerCase.h new file mode 100644 index 0000000000..3d7909bf41 --- /dev/null +++ b/protocols/MRA/src/Sdk/BuffToLowerCase.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2003 Rozhuk Ivan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + + +#if !defined(AFX_BUFFTOLOWERCASE__H__INCLUDED_) +#define AFX_BUFFTOLOWERCASE__H__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + + +__inline BOOL BuffToLowerCase(LPCVOID lpcOutBuff,LPCVOID lpcBuff,size_t dwLen) +{ + BOOL bRet=TRUE; + +#if defined(_WIN64) || !defined(_WIN32) + if (lpcOutBuff && lpcBuff && dwLen) + { + BYTE bt; + LPBYTE lpbtIn=(LPBYTE)lpcBuff,lpbtOut=(LPBYTE)lpcOutBuff; + + for(size_t i=dwLen;i;i--) + { + bt=(*(lpbtIn++)); + if (bt>='A' && bt<='Z') bt|=32; + (*(lpbtOut++))=bt; + } + } +#else + __asm + { + mov ecx,dwLen + test ecx,ecx + jz short end_func + + push ebx // сохраняем регистр + push edi // сохраняем регистр + push esi // сохраняем регистр + mov esi,lpcBuff + mov edi,lpcOutBuff + mov bl,'A' + mov bh,'Z' + mov ah,32 + cld + + lowcaseloop: + lodsb + cmp al,bl + jl short savebyte + cmp al,bh + jg short savebyte + or al,ah + + savebyte: + stosb + + dec ecx + jnz short lowcaseloop + + pop esi // восстанавливаем содержимое регистра + pop edi // восстанавливаем содержимое регистра + pop ebx // восстанавливаем содержимое регистра + end_func: + } +#endif +return(bRet); +} + + + + +#endif // !defined(AFX_BUFFTOLOWERCASE__H__INCLUDED_) \ No newline at end of file diff --git a/protocols/MRA/src/Sdk/DebugFunctions.h b/protocols/MRA/src/Sdk/DebugFunctions.h new file mode 100644 index 0000000000..6bd9df5b5a --- /dev/null +++ b/protocols/MRA/src/Sdk/DebugFunctions.h @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2004 Rozhuk Ivan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + + + +#if !defined(AFX_DEBUG_FUNCTIONS__H__INCLUDED_) +#define AFX_DEBUG_FUNCTIONS__H__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#ifndef szCRLF +#define szCRLF TEXT("\r\n") +#endif +////////////////////////////////////////////////////////////////////////// +////////////////////////////DebugPrint//////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +// DebugBuildPrint(Helo world); +// Отображение текста в Debug окне во время отладки +#ifdef _DEBUG + #define DebugPrintA(szText) OutputDebugStringA((szText)) + #define DebugPrintW(szText) OutputDebugStringW((szText)) + #define DebugPrintCRLFA(szText) OutputDebugStringA((szText));OutputDebugStringA("\r\n") + #define DebugPrintCRLFW(szText) OutputDebugStringW((szText));OutputDebugStringW(L"\r\n") +#else + #define DebugPrintA(szText) + #define DebugPrintW(szText) + #define DebugPrintCRLFA(szText) + #define DebugPrintCRLFW(szText) +#endif //_DEBUG + + +#ifdef UNICODE + #define DebugPrint DebugPrintW + #define DebugPrintCRLF DebugPrintCRLFW +#else + #define DebugPrint DebugPrintA + #define DebugPrintCRLF DebugPrintCRLFA +#endif +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + + + + +////////////////////////////////////////////////////////////////////////// +////////////////////////////DebugBuildPrint/////////////////////////////// +////////////////////////////////////////////////////////////////////////// +// #pragma DebugBuildPrint(Helo world); +// Отображение сообщений в Build окне во время компиляции +#ifdef _DEBUG + #pragma warning(disable:4081) + #define chSTR2(x) #x + #define chSTR(x) chSTR2(x) + #define DebugBuildPrint(szText) message(__FILE__ "(" chSTR(__LINE__) "): " #szText) + #pragma warning(default:4081) +#else + #define DebugBuildPrint(szText) +#endif //_DEBUG +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + + + + +////////////////////////////////////////////////////////////////////////// +////////////////////////////DebugBufferFill/////////////////////////////// +////////////////////////////////////////////////////////////////////////// +// DebugBufferFill(szString,sizeof(szString)); +// Полностью заполняет переданный буффер символом "A", применяется +// для выходного буффера на входе в функцию. +#ifdef _DEBUG + #define DebugBufferFill(lpBuffer,dwSize) memset(lpBuffer,'A',dwSize) +#else + #define DebugBufferFill(lpBuffer,dwSize) +#endif //_DEBUG +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + + + + +////////////////////////////////////////////////////////////////////////// +////////////////////////////DebugBreak//////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +// DebugBreak(); +// Точка останова, более удобная альтернатива API +#if defined(_DEBUG) + #if defined(_X86_) + #define DebugBreak() _asm{int 3} + #else + #include + #define DebugBreak() __debugbreak() + #endif +#else + #define DebugBreak() +#endif //_DEBUG +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////// +////////////////////////////DebugBreakIf////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +// DebugBreakIf(); +// Точка останова, более удобная альтернатива API, срабатывает при условии +#if defined(_DEBUG) + #define DebugBreakIf(a) if ((a)) DebugBreak(); +#else + #define DebugBreakIf(a) +#endif //_DEBUG +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + + + + +#endif // !defined(AFX_DEBUG_FUNCTIONS__H__INCLUDED_) diff --git a/protocols/MRA/src/Sdk/FIFOMT.h b/protocols/MRA/src/Sdk/FIFOMT.h new file mode 100644 index 0000000000..acff96f500 --- /dev/null +++ b/protocols/MRA/src/Sdk/FIFOMT.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2003 Rozhuk Ivan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + + + +#if !defined(AFX_FIFO_MT__H__INCLUDED_) +#define AFX_FIFO_MT__H__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + +#include +#include + + + + + +typedef LIST_MT FIFO_MT, *PFIFO_MT, *LPFIFO_MT; +typedef PCLIST_MT PCFIFO_MT, LPCFIFO_MT; + +typedef LIST_MT_ITEM FIFO_MT_ITEM, *PFIFO_MT_ITEM, *LPFIFO_MT_ITEM; +typedef PCLIST_MT_ITEM PCFIFO_MT_ITEM, LPCFIFO_MT_ITEM; + +typedef LIST_MT_ITERATOR FIFO_MT_ITERATOR, *PFIFO_MT_ITERATOR, *LPFIFO_MT_ITERATOR; +typedef PCLIST_MT_ITERATOR PCFIFO_MT_ITERATOR, LPCFIFO_MT_ITERATOR; + + + + + + +#define FifoMTInitialize(pcpmtFifoMT,dwSpinCount) ListMTInitialize(pcpmtFifoMT,dwSpinCount) +#define FifoMTDestroy(pcpmtFifoMT) ListMTDestroy(pcpmtFifoMT) + + +__inline size_t FifoMTItemPush(PCFIFO_MT pcpmtFifoMT,PCFIFO_MT_ITEM pcffmtiFifoItem,LPVOID lpData) +{ + mt_lock l(pcpmtFifoMT); + return ListMTItemAdd(pcpmtFifoMT,pcffmtiFifoItem,lpData); +} + + +__inline DWORD FifoMTItemPop(PCFIFO_MT pcpmtFifoMT,PFIFO_MT_ITEM *ppffmtiFifoItem,LPVOID *plpData) +{ + DWORD dwRetErrorCode; + PLIST_MT_ITEM plmtiItem; + + mt_lock l(pcpmtFifoMT); + if ((dwRetErrorCode=ListMTItemGetFirst(pcpmtFifoMT,&plmtiItem,plpData))==NO_ERROR) + { + if (ppffmtiFifoItem) (*ppffmtiFifoItem)=plmtiItem; + return ListMTItemDelete(pcpmtFifoMT,plmtiItem); + } + + return dwRetErrorCode; +} + + +__inline DWORD FifoMTItemGetFirst(PCFIFO_MT pcpmtFifoMT,PFIFO_MT_ITEM *ppffmtiFifoItem,LPVOID *plpData) +{ + mt_lock l(pcpmtFifoMT); + return ListMTItemGetFirst(pcpmtFifoMT,ppffmtiFifoItem,plpData); +} + + +__inline DWORD FifoMTItemGetLast(PCFIFO_MT pcpmtFifoMT,PFIFO_MT_ITEM *ppffmtiFifoItem,LPVOID *plpData) +{ + mt_lock l(pcpmtFifoMT); + return ListMTItemGetLast(pcpmtFifoMT,ppffmtiFifoItem,plpData); +} + + +#define FifoMTGetCount(pcpmtFifoMT) ListMTGetCount(pcpmtFifoMT) + +#define FifoMTTryLock(pcpmtFifoMT) ListMTTryLock(pcpmtFifoMT) +#define FifoMTLock(pcpmtFifoMT) ListMTLock(pcpmtFifoMT) +#define FifoMTUnLock(pcpmtFifoMT) ListMTUnLock(pcpmtFifoMT) + +#define FifoMTItemSwap(pcpmtFifoMT,pcffmtiFifoItem1,pcffmtiFifoItem2) ListMTItemSwap(pcpmtFifoMT,pcffmtiFifoItem1,pcffmtiFifoItem2) + +#define FifoMTIteratorMoveFirst(pcpmtFifoMT,pffmtiIterator) ListMTIteratorMoveFirst(pcpmtFifoMT,pffmtiIterator) +#define FifoMTIteratorMoveLast(pcpmtFifoMT,pffmtiIterator) ListMTIteratorMoveLast(pcpmtFifoMT,pffmtiIterator) +#define FifoMTIteratorMovePrev(pffmtiIterator) ListMTIteratorMovePrev(pffmtiIterator) +#define FifoMTIteratorMoveNext(pffmtiIterator) ListMTIteratorMoveNext(pffmtiIterator) +#define FifoMTIteratorGet(pffmtiIterator,ppffmtiFifoItem,plpData) ListMTIteratorGet(pffmtiIterator,ppffmtiFifoItem,plpData) + + + + +#endif // !defined(AFX_FIFO_MT__H__INCLUDED_) diff --git a/protocols/MRA/src/Sdk/InterlockedFunctions.h b/protocols/MRA/src/Sdk/InterlockedFunctions.h new file mode 100644 index 0000000000..742f904944 --- /dev/null +++ b/protocols/MRA/src/Sdk/InterlockedFunctions.h @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2003 Rozhuk Ivan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + + + +#if !defined(AFX_INTERLOCKED_FUNCTIONS__H__INCLUDED_) +#define AFX_INTERLOCKED_FUNCTIONS__H__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + + + + +#ifdef InterlockedCompareExchange +#ifndef InterlockedAnd +LONG FORCEINLINE InterlockedAnd(LONG volatile *Destination,LONG Value) +{ + LONG Old; + + do + { + Old=*Destination; + }while(InterlockedCompareExchange(Destination,(Old&Value),Old)!=Old); +return(Old); +} +#endif //InterlockedAnd + + +#ifndef InterlockedOr +LONG FORCEINLINE InterlockedOr(LONG volatile *Destination,LONG Value) +{ + LONG Old; + + do + { + Old=*Destination; + }while(InterlockedCompareExchange(Destination,(Old|Value),Old)!=Old); +return(Old); +} +#endif //InterlockedOr + + +#ifndef InterlockedXor +LONG FORCEINLINE InterlockedXor(LONG volatile *Destination,LONG Value) +{ + LONG Old; + + do + { + Old=*Destination; + }while(InterlockedCompareExchange(Destination,(Old^Value),Old)!=Old); +return(Old); +} +#endif //InterlockedXor +#endif //InterlockedCompareExchange + + + + + +#ifdef InterlockedCompareExchange64 +#ifndef InterlockedAnd64 +LONGLONG FORCEINLINE InterlockedAnd64(LONGLONG volatile *Destination,LONGLONG Value) +{ + LONGLONG Old; + + do + { + Old=*Destination; + }while(InterlockedCompareExchange64(Destination,(Old&Value),Old)!=Old); +return(Old); +} +#endif //InterlockedAnd64 + + +#ifndef InterlockedOr64 +LONGLONG FORCEINLINE InterlockedOr64(LONGLONG volatile *Destination,LONGLONG Value) +{ + LONGLONG Old; + + do + { + Old=*Destination; + }while(InterlockedCompareExchange64(Destination,(Old|Value),Old)!=Old); +return(Old); +} +#endif //InterlockedOr64 + + +#ifndef InterlockedXor64 +LONGLONG FORCEINLINE InterlockedXor64(LONGLONG volatile *Destination,LONGLONG Value) +{ + LONGLONG Old; + + do + { + Old=*Destination; + }while(InterlockedCompareExchange64(Destination,(Old^Value),Old)!=Old); +return(Old); +} +#endif //InterlockedXor64 +#endif //InterlockedCompareExchange64 + + + + + +#ifndef InterlockedIncrementPointer +#if defined(_WIN64) +#define InterlockedIncrementPointer(lpAddend) (LPVOID)InterlockedIncrement64((LONGLONG volatile*)lpAddend) +#else +#define InterlockedIncrementPointer(lpAddend) (LPVOID)InterlockedIncrement((LONG volatile*)lpAddend) +#endif +#endif //InterlockedIncrementPointer + + +#ifndef InterlockedDecrementPointer +#if defined(_WIN64) +#define InterlockedDecrementPointer(lpAddend) (LPVOID)InterlockedDecrement64((LONGLONG volatile*)lpAddend) +#else +#define InterlockedDecrementPointer(lpAddend) (LPVOID)InterlockedDecrement((LONG volatile*)lpAddend) +#endif +#endif //InterlockedDecrementPointer + + + + + +#endif // !defined(AFX_INTERLOCKED_FUNCTIONS__H__INCLUDED_) diff --git a/protocols/MRA/src/Sdk/InternetTime.h b/protocols/MRA/src/Sdk/InternetTime.h new file mode 100644 index 0000000000..c6abf16786 --- /dev/null +++ b/protocols/MRA/src/Sdk/InternetTime.h @@ -0,0 +1,473 @@ +/* + * Copyright (c) 2003 Rozhuk Ivan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + + + +#if !defined(AFX_INTERNET_TIME_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_) +#define AFX_INTERNET_TIME_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_ + + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + +#include +#include +#include + + + +typedef struct +{ + LONG lTimeZone; + SYSTEMTIME stTime; +} INTERNET_TIME; + + +static LPCSTR lpcszenmMonthEnum[13]= {"---","Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}; +static LPCSTR lpcszenmDayOfWeakEnum[7]= {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; + +#define CRLF "\r\n" +#define LF "\n" +//WSP++ +#define LWSHT "\r\n\t" +#define LWSSP "\r\n " +//WSP-- + +//FWS++ +#define FWSHT LWSHT +#define FWSSP LWSSP +//FWS-- + +#define SEPARATOR "\r\n\r\n" + + +//DWORD InternetTimeGetTime (LPCSTR lpszTime,size_t dwTimeSize,INTERNET_TIME *pitTime); +//BOOL SkeepSPWSP (LPCSTR lpszBuff,size_t dwBuffSize,LPSTR *plpszRetBuff,size_t *pdwRetBuffSize); +//BOOL WSP2SP (LPCSTR lpszBuff,size_t dwBuffSize,LPSTR lpszRetBuff,size_t *pdwRetBuffSize); + + + + + +__inline BOOL SkeepSPWSP(LPCSTR lpszBuff,size_t dwBuffSize,LPSTR *plpszRetBuff,size_t *pdwRetBuffSize) +{ + BOOL bRet=TRUE; + + if (lpszBuff && dwBuffSize && (plpszRetBuff || pdwRetBuffSize)) + { + while ((*lpszBuff)<33 && dwBuffSize) + { + dwBuffSize--; + lpszBuff++; + } + + if (plpszRetBuff) (*plpszRetBuff)=(LPSTR)lpszBuff; + if (pdwRetBuffSize) (*pdwRetBuffSize)=dwBuffSize; + }else{ + bRet=FALSE; + } +return(bRet); +} + + +__inline BOOL WSP2SP(LPCSTR lpszBuff,size_t dwBuffSize,LPSTR lpszRetBuff,size_t *pdwRetBuffSize) +{// WSP->SP + BOOL bRet=TRUE; + + if (lpszBuff && dwBuffSize && lpszRetBuff) + { + LPSTR lpszCurReadPos,pCRLF,lpszCurWritePos; + size_t dwToCopy,dwRetBuffSize; + + pCRLF=(LPSTR)lpszBuff; + lpszCurReadPos=(LPSTR)lpszBuff; + lpszCurWritePos=lpszRetBuff; + dwRetBuffSize=0; + + while(pCRLF) + { + pCRLF=(LPSTR)MemoryFind((pCRLF-lpszBuff),lpszBuff,(dwBuffSize-1),CRLF,2); + if (pCRLF) + { + pCRLF+=2; + if ((*pCRLF)==9 || (*pCRLF)==32)// LWS: || + { + dwToCopy=((pCRLF-2)-lpszCurReadPos); + pCRLF++; + + memmove((LPVOID)lpszCurWritePos,(CONST VOID*)lpszCurReadPos,dwToCopy); + dwRetBuffSize+=(dwToCopy+1); + lpszCurWritePos+=dwToCopy; + lpszCurWritePos[0]=32; + lpszCurWritePos++; + lpszCurReadPos=pCRLF; + } + }else{ + dwToCopy=((lpszBuff+dwBuffSize)-lpszCurReadPos); + dwRetBuffSize+=dwToCopy; + memmove((LPVOID)lpszCurWritePos,(CONST VOID*)lpszCurReadPos,dwToCopy); + } + } + + if (pdwRetBuffSize) (*pdwRetBuffSize)=dwRetBuffSize; + }else{ + bRet=FALSE; + } +return(bRet); +} + + + +__inline BOOL HT2SP(LPCSTR lpszBuff,size_t dwBuffSize,LPSTR lpszRetBuff,size_t *pdwRetBuffSize) +{// HT->SP + BOOL bRet=TRUE; + + if (lpszBuff && dwBuffSize && lpszRetBuff) + { + LPSTR lpszCurReadPos,pHT,lpszCurWritePos; + size_t dwToCopy,dwRetBuffSize; + + pHT=(LPSTR)lpszBuff; + lpszCurReadPos=(LPSTR)lpszBuff; + lpszCurWritePos=lpszRetBuff; + dwRetBuffSize=0; + + while(pHT) + { + pHT=(LPSTR)MemoryFind((pHT-lpszBuff),lpszBuff,dwBuffSize,"\t",1); + if (pHT) + { + dwToCopy=(pHT-lpszCurReadPos); + pHT++; + + dwRetBuffSize+=(dwToCopy+1); + memmove((LPVOID)lpszCurWritePos,(CONST VOID*)lpszCurReadPos,dwToCopy); + lpszCurWritePos+=dwToCopy; + lpszCurWritePos[0]=32; + lpszCurWritePos++; + lpszCurReadPos=pHT; + }else{ + dwToCopy=((lpszBuff+dwBuffSize)-lpszCurReadPos); + dwRetBuffSize+=dwToCopy; + memmove((LPVOID)lpszCurWritePos,(CONST VOID*)lpszCurReadPos,dwToCopy); + } + } + + if (pdwRetBuffSize) (*pdwRetBuffSize)=dwRetBuffSize; + }else{ + bRet=FALSE; + } +return(bRet); +} + + + + +__inline BOOL CleanUnneededSP(LPCSTR lpszBuff,size_t dwBuffSize,LPSTR lpszRetBuff,size_t *pdwRetBuffSize) +{// nSP->SP, SPCRLF->CRLF, CRLFSP->CRLF + BOOL bRet=TRUE; + + if (lpszBuff && dwBuffSize && lpszRetBuff) + { + LPSTR lpszCurReadPos,pSP,pSPStart,pSPEnd,lpszCurWritePos,pEnd; + size_t dwToCopy,dwRetBuffSize; + + pSP=(LPSTR)lpszBuff; + lpszCurReadPos=(LPSTR)lpszBuff; + lpszCurWritePos=lpszRetBuff; + pEnd=((LPSTR)lpszBuff+dwBuffSize); + dwRetBuffSize=0; + + while(pSP) + { + pSP=(LPSTR)MemoryFind((pSP-lpszBuff),lpszBuff,dwBuffSize," ",1); + if (pSP) + { + dwToCopy=(pSP-lpszCurReadPos); + pSPStart=pSP; + pSPEnd=pSP; + while((*pSPEnd)==32 && pSPEndlpszBuff) + { + if ((*((WORD*)(pSPStart-2)))!=(*((WORD*)CRLF))) dwToCopy++; + }else{// buff start + if (pSPStart>lpszBuff) dwToCopy++; + } + + // check SP on line end + if ((pSPEnd+1)<=pEnd) + { + if ((*((WORD*)pSPEnd))!=(*((WORD*)CRLF))) dwToCopy++; + }else{// buff start + if (pSPEnd>lpszBuff) dwToCopy++; + } + + memmove((LPVOID)lpszCurWritePos,(CONST VOID*)lpszCurReadPos,dwToCopy); + lpszCurWritePos+=dwToCopy; + dwRetBuffSize+=dwToCopy; + lpszCurReadPos=pSPEnd; + pSP=pSPEnd; + }else{ + dwToCopy=((lpszBuff+dwBuffSize)-lpszCurReadPos); + dwRetBuffSize+=dwToCopy; + memmove((LPVOID)lpszCurWritePos,(CONST VOID*)lpszCurReadPos,dwToCopy); + } + } + + if (pdwRetBuffSize) (*pdwRetBuffSize)=dwRetBuffSize; + }else{ + bRet=FALSE; + } +return(bRet); +} + + + + +__inline size_t CopyText(LPVOID lpOutBuff,LPCVOID lpcBuff,size_t dwLen) +{ + size_t dwRet=0; + + if (lpOutBuff && lpcBuff && dwLen) + { + BYTE bt; + LPBYTE lpbtIn=(LPBYTE)lpcBuff,lpbtOut=(LPBYTE)lpOutBuff; + + for(size_t i=dwLen;i;i--) + { + bt=(*(lpbtIn++)); + if (bt<127 && (bt>31 || bt==9 || bt==10 || bt==13)) + { + (*(lpbtOut++))=bt; + dwRet++; + } + } + } +return(dwRet); +} + + +__inline void InternetTimeGetCurrentTime(INTERNET_TIME *pitTime) +{ + TIME_ZONE_INFORMATION tzi={0}; + GetTimeZoneInformation(&tzi); + pitTime->lTimeZone=tzi.Bias; + GetSystemTime(&pitTime->stTime); +} + + +__inline DWORD InternetTimeGetString(INTERNET_TIME *pitTime,LPSTR lpszBuff,size_t dwBuffSize,size_t *pdwBuffSizeRet) +{// Переводит время из MAILTIME в строковое + DWORD dwRet=NO_ERROR; + + if (dwBuffSize>31) + { + LPSTR lpszCurPos=lpszBuff; + size_t dwTimeLen=0,dwtm; + + // day of weak// date of mounth// mounth name// year// hours // minutes// seconds + dwtm=wsprintfA(lpszCurPos,"%s, %02lu %s %04lu %02lu:%02lu:%02lu ",lpcszenmDayOfWeakEnum[pitTime->stTime.wDayOfWeek],pitTime->stTime.wDay,lpcszenmMonthEnum[pitTime->stTime.wMonth],pitTime->stTime.wYear,pitTime->stTime.wHour,pitTime->stTime.wMinute,pitTime->stTime.wSecond); + lpszCurPos+=dwtm; + dwTimeLen+=dwtm; + + // time zone + if (pitTime->lTimeZone) + { + if (pitTime->lTimeZone < 0) + {// нужно добавить плюсик, минус добавляется автоматом + (*((BYTE*)lpszCurPos))='+'; + lpszCurPos++; + dwTimeLen++; + } + + dwtm=wsprintfA(lpszCurPos,"%04ld",-(((pitTime->lTimeZone/60)*100)+pitTime->lTimeZone%60)); + lpszCurPos+=dwtm; + dwTimeLen+=dwtm; + }else{ + dwtm=wsprintfA(lpszCurPos,"GMT"); + lpszCurPos+=dwtm; + dwTimeLen+=dwtm; + } + + if (pdwBuffSizeRet) (*pdwBuffSizeRet)=dwTimeLen; + }else{// переданный буффер слишком мал + if (pdwBuffSizeRet) (*pdwBuffSizeRet)=32; + dwRet=ERROR_INSUFFICIENT_BUFFER; + } +return(dwRet); +} + + + +__inline DWORD InternetTimeGetTime(LPCSTR lpszTime,size_t dwTimeSize,INTERNET_TIME *pitTime) +{// Переводит время из строкового в INTERNET_TIME + DWORD dwRet=NO_ERROR; + + if (lpszTime && dwTimeSize && dwTimeSize<4097 && pitTime) + {// = Thu, 21 May 1998 05:33:29 -0700 = + char sztmBuff[4096]; + LPSTR lpszCurPos=sztmBuff,lpszTemp; + size_t i,dwCurSize=4096,dwTemp; + + memset(pitTime, 0, sizeof(INTERNET_TIME)); + WSP2SP((LPSTR)lpszTime,dwTimeSize,lpszCurPos,&dwCurSize); + + if (dwCurSize>3) + {// день недели + if (lpszCurPos[3]==',') + { + for (i=0;i<8;i++) + { + if (CompareStringA(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),NORM_IGNORECASE,lpcszenmDayOfWeakEnum[i],3,lpszCurPos,3)==CSTR_EQUAL) + { + pitTime->stTime.wDayOfWeek=(unsigned short)i; + break; + } + } + + lpszCurPos+=4; + dwCurSize-=4; + } + + if (dwCurSize>2) + {// день месяца + SkeepSPWSP(lpszCurPos,dwCurSize,&lpszCurPos,&dwCurSize); + if ((lpszTemp=(LPSTR)MemoryFindByte(0,lpszCurPos,dwCurSize,' '))) + { + dwTemp=(lpszTemp-lpszCurPos); + pitTime->stTime.wDay=(unsigned short)StrToUNum32(lpszCurPos,dwTemp); + + lpszCurPos=(lpszTemp+1); + dwCurSize-=(dwTemp+1); + + if (dwCurSize>3) + {// месяц + SkeepSPWSP(lpszCurPos,dwCurSize,&lpszCurPos,&dwCurSize); + + for (i=1;i<14;i++) + { + if (CompareStringA(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),NORM_IGNORECASE,lpcszenmMonthEnum[i],3,lpszCurPos,3)==CSTR_EQUAL) + { + pitTime->stTime.wMonth=(unsigned short)i; + break; + } + } + + lpszCurPos+=3; + dwCurSize-=3; + + + if (dwCurSize>3) + {// год + SkeepSPWSP(lpszCurPos,dwCurSize,&lpszCurPos,&dwCurSize); + if ((lpszTemp=(LPSTR)MemoryFindByte(0,lpszCurPos,dwCurSize,' '))) + { + dwTemp=(lpszTemp-lpszCurPos); + pitTime->stTime.wYear=(unsigned short)StrToUNum32(lpszCurPos,dwTemp); + + lpszCurPos=(lpszTemp+1); + dwCurSize-=(dwTemp+1); + + if (dwCurSize>2) + { // часы + SkeepSPWSP(lpszCurPos,dwCurSize,&lpszCurPos,&dwCurSize); + if ((lpszTemp=(LPSTR)MemoryFindByte(0,lpszCurPos,dwCurSize,':'))) + { + dwTemp=(lpszTemp-lpszCurPos); + pitTime->stTime.wHour=(unsigned short)StrToUNum32(lpszCurPos,dwTemp); + + lpszCurPos=(lpszTemp+1); + dwCurSize-=(dwTemp+1); + + if (dwCurSize>2) + {// минуты + SkeepSPWSP(lpszCurPos,dwCurSize,&lpszCurPos,&dwCurSize); + if ((lpszTemp=(LPSTR)MemoryFindByte(0,lpszCurPos,dwCurSize,':'))) + { + dwTemp=(lpszTemp-lpszCurPos); + pitTime->stTime.wMinute=(unsigned short)StrToUNum32(lpszCurPos,dwTemp); + + lpszCurPos=(lpszTemp+1); + dwCurSize-=(dwTemp+1); + + if (dwCurSize>2) + {// секунды, они есть + if ((lpszTemp=(LPSTR)MemoryFindByte(0,lpszCurPos,dwCurSize,' '))) + { + dwTemp=(lpszTemp-lpszCurPos); + pitTime->stTime.wSecond=(unsigned short)StrToUNum32(lpszCurPos,dwTemp); + + lpszCurPos=(lpszTemp+1); + dwCurSize-=(dwTemp+1); + } + }else{// зоны нет + if (dwCurSize) + { + pitTime->stTime.wSecond=(unsigned short)StrToUNum32(lpszCurPos,dwCurSize); + lpszCurPos+=dwCurSize; + dwCurSize=0; + } + } + }else{ + if ((lpszTemp=(LPSTR)MemoryFindByte(0,lpszCurPos,dwCurSize,' '))) + { + dwTemp=(lpszTemp-lpszCurPos); + pitTime->stTime.wMinute=(unsigned short)StrToUNum32(lpszCurPos,dwTemp); + + lpszCurPos=(lpszTemp+1); + dwCurSize-=(dwTemp+1); + } + } + + if (dwCurSize) + {// часовой пояс + SkeepSPWSP(lpszCurPos,dwCurSize,&lpszCurPos,&dwCurSize); + pitTime->lTimeZone=(LONG)StrToNum(lpszCurPos,dwCurSize); + if (pitTime->lTimeZone>1300 || pitTime->lTimeZone<-1200) pitTime->lTimeZone=2400; + } + } + } + } + } + } + } + } + } + } + }else{ + dwRet=ERROR_INVALID_HANDLE; + } +return(dwRet); +} + + + +#endif // !defined(AFX_INTERNET_TIME_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_) diff --git a/protocols/MRA/src/Sdk/ListMT.h b/protocols/MRA/src/Sdk/ListMT.h new file mode 100644 index 0000000000..38d9247488 --- /dev/null +++ b/protocols/MRA/src/Sdk/ListMT.h @@ -0,0 +1,360 @@ +/* + * Copyright (c) 2003 Rozhuk Ivan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + + + +#if !defined(AFX_LIST_MT__H__INCLUDED_) +#define AFX_LIST_MT__H__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + +#include + +#if defined(_MSC_VER) +#if _MSC_VER >= 800 +#if _MSC_VER >= 1200 +#pragma warning(push) +#endif +#pragma warning(disable:4312) // warning C4312: 'type cast' : conversion from 'LONG' to 'PVOID' of greater size +#endif +#endif + + +// структура для работы со списком, элемент списка +typedef struct _LIST_MT_ITEM +{ +#ifdef __cplusplus + _LIST_MT_ITEM *plmtiPrev; // *предыдущий элемент в списке + _LIST_MT_ITEM *plmtiNext; // *следующий элемент в списке +#else + LPVOID *plmtiPrev; // *предыдущий элемент в списке + LPVOID *plmtiNext; // *следующий элемент в списке +#endif + LPVOID lpListMT; // указатель на заголовок списка, см структуру ниже + LPVOID lpData; // указатель на данные, связанные с элементом списка +}LIST_MT_ITEM, *PLIST_MT_ITEM, *LPLIST_MT_ITEM; +typedef CONST PLIST_MT_ITEM PCLIST_MT_ITEM, LPCLIST_MT_ITEM; + + +// структура для работы со списком, заголовок списка +typedef struct _LIST_MT +{ + size_t nCount; // *колличество элементов в списке + PLIST_MT_ITEM plmtiFirst; // *указывает на первый элемент в списке + PLIST_MT_ITEM plmtiLast; // *указывает на последний элемент в списке + CRITICAL_SECTION cs; // *section for exclysive access to List +}LIST_MT, *PLIST_MT, *LPLIST_MT; +typedef CONST PLIST_MT PCLIST_MT, LPCLIST_MT; + + +// структура для работы с итератором +typedef struct _LIST_MT_ITERATOR +{ + PLIST_MT_ITEM plmtListMTItem; +}LIST_MT_ITERATOR, *PLIST_MT_ITERATOR, *LPLIST_MT_ITERATOR; +//typedef LIST_MT_ITEM LIST_MT_ITERATOR, *PLIST_MT_ITERATOR, *LPLIST_MT_ITERATOR; +typedef CONST PLIST_MT_ITERATOR PCLIST_MT_ITERATOR, LPCLIST_MT_ITERATOR; + + + + +__inline DWORD ListMTInitialize(PCLIST_MT pclmtListMT,DWORD dwSpinCount) +{ + DWORD dwRetErrorCode; + +#if (_WIN32_WINNT >= 0x0403) + if (InitializeCriticalSectionAndSpinCount(&pclmtListMT->cs,((dwSpinCount)? (dwSpinCount | 0x80000000):0L))) +#else + InitializeCriticalSection(&pclmtListMT->cs); + if (TRUE) +#endif + { + InterlockedExchangePointer((volatile PVOID*)&pclmtListMT->nCount,NULL); + pclmtListMT->plmtiFirst=NULL; + pclmtListMT->plmtiLast=NULL; + dwRetErrorCode=NO_ERROR; + }else{ + dwRetErrorCode=GetLastError(); + } +return(dwRetErrorCode); +} + + +__inline void ListMTDestroy(PCLIST_MT pclmtListMT) +{ + InterlockedExchangePointer((volatile PVOID*)&pclmtListMT->nCount,NULL); + pclmtListMT->plmtiFirst=NULL; + pclmtListMT->plmtiLast=NULL; + DeleteCriticalSection(&pclmtListMT->cs); + SecureZeroMemory(&pclmtListMT->cs,sizeof(CRITICAL_SECTION)); +} + + +__inline BOOL ListMTTryLock(PCLIST_MT pclmtListMT) +{ +#if (_WIN32_WINNT >= 0x0400) + return(TryEnterCriticalSection(&pclmtListMT->cs)); +#else + return(FALSE); +#endif +} + +class mt_lock +{ + PCLIST_MT m_list; + +public: + __forceinline mt_lock(PCLIST_MT _pList) : + m_list( _pList ) + { EnterCriticalSection(&_pList->cs); + } + + __forceinline ~mt_lock() + { LeaveCriticalSection(&m_list->cs); + } +}; + +__inline size_t ListMTGetCount(PCLIST_MT pclmtListMT) +{ + return((size_t)InterlockedCompareExchangePointer((LPVOID*)&pclmtListMT->nCount,NULL,NULL)); +} + + +__inline size_t ListMTItemAdd(PCLIST_MT pclmtListMT,PCLIST_MT_ITEM pclmtListMTItem,LPVOID lpData) +{ + size_t dwRet=(size_t)InterlockedIncrementPointer(&pclmtListMT->nCount);//pclmtListMT->nCount++; + pclmtListMTItem->lpData=lpData; + pclmtListMTItem->lpListMT=pclmtListMT; + + if (pclmtListMT->plmtiLast) + {// add node to end of list + pclmtListMTItem->plmtiPrev=pclmtListMT->plmtiLast; + pclmtListMTItem->plmtiNext=NULL; + pclmtListMT->plmtiLast->plmtiNext=pclmtListMTItem; + pclmtListMT->plmtiLast=pclmtListMTItem; + }else{// add the first node to the linked list + pclmtListMTItem->plmtiPrev=NULL; + pclmtListMTItem->plmtiNext=NULL; + pclmtListMT->plmtiFirst=pclmtListMTItem; + pclmtListMT->plmtiLast=pclmtListMTItem; + } + +return(dwRet); +} + + +__inline DWORD ListMTItemDelete(PCLIST_MT pclmtListMT,PCLIST_MT_ITEM pclmtListMTItem) +{ + DWORD dwRetErrorCode; + + if (pclmtListMTItem->lpListMT==pclmtListMT && pclmtListMT) + {// Данный элемент принадлежит к этому списку, можно удалить. + PLIST_MT_ITEM plmtiPrevNode=pclmtListMTItem->plmtiPrev,plmtiNextNode=pclmtListMTItem->plmtiNext; + + if (plmtiPrevNode || plmtiNextNode) + { + if (plmtiPrevNode && plmtiNextNode==NULL) + {// This is the start node in the list to delete + // отключился последний подключившийся + plmtiPrevNode->plmtiNext=NULL; + pclmtListMT->plmtiLast=plmtiPrevNode; + }else{ + if (plmtiPrevNode==NULL && plmtiNextNode) + {// This is the end node in the list to delete + // отключился первый подключившийся + plmtiNextNode->plmtiPrev=NULL; + pclmtListMT->plmtiFirst=plmtiNextNode; + }else{// оключился клиент не первый и не последний + //if (plmtiPrev && plmtiNext) + {// Neither start node nor end node in the list + plmtiPrevNode->plmtiNext=plmtiNextNode; + plmtiNextNode->plmtiPrev=plmtiPrevNode; + } + } + } + }else{// This is the only node in the list to delete + pclmtListMT->plmtiFirst=NULL; + pclmtListMT->plmtiLast=NULL; + } + + pclmtListMTItem->lpListMT=NULL; + InterlockedDecrementPointer(&pclmtListMT->nCount);// pclmtListMT->nCount--; + dwRetErrorCode=NO_ERROR; + }else{// попытались удалить элемент не относящийся к данному списку + dwRetErrorCode=ERROR_INVALID_HANDLE; + } +return(dwRetErrorCode); +} + + +__inline LPVOID ListMTItemDataGet(PCLIST_MT_ITEM pclmtListMTItem) +{ + return(pclmtListMTItem->lpData); +} + + +__inline void ListMTItemDataSet(PCLIST_MT_ITEM pclmtListMTItem, LPVOID lpData) +{ + pclmtListMTItem->lpData=lpData; +} + + +__inline DWORD ListMTItemGetFirst(PCLIST_MT pclmtListMT,PLIST_MT_ITEM *pplmtListMTItem,LPVOID *plpData) +{// если нужно гарантировать эксклюзивный доступ, то есть ListMTLock и ListMTUnLock + DWORD dwRetErrorCode; + + if (pclmtListMT->plmtiFirst) + { + if (pplmtListMTItem) (*pplmtListMTItem)=pclmtListMT->plmtiFirst; + if (plpData) (*plpData)=pclmtListMT->plmtiFirst->lpData; + dwRetErrorCode=NO_ERROR; + }else{ + dwRetErrorCode=ERROR_NO_MORE_ITEMS; + } +return(dwRetErrorCode); +} + + +__inline DWORD ListMTItemGetLast(PCLIST_MT pclmtListMT,PLIST_MT_ITEM *pplmtListMTItem,LPVOID *plpData) +{// если нужно гарантировать эксклюзивный доступ, то есть ListMTLock и ListMTUnLock + DWORD dwRetErrorCode; + + if (pclmtListMT->plmtiLast) + { + if (pplmtListMTItem) (*pplmtListMTItem)=pclmtListMT->plmtiLast; + if (plpData) (*plpData)=pclmtListMT->plmtiLast->lpData; + dwRetErrorCode=NO_ERROR; + }else{ + dwRetErrorCode=ERROR_NO_MORE_ITEMS; + } +return(dwRetErrorCode); +} + + + +__inline void ListMTItemSwap(PCLIST_MT pclmtListMT,PCLIST_MT_ITEM pclmtListMTItem1,PCLIST_MT_ITEM pclmtListMTItem2) +{// поменять два элемента списка местами, даже если они из разных списков + + if (pclmtListMTItem1!=pclmtListMTItem2) + {// это разные элементы списка + PLIST_MT_ITEM lpTemp; + + lpTemp=pclmtListMTItem1->plmtiPrev; + if ((pclmtListMTItem1->plmtiPrev=pclmtListMTItem2->plmtiPrev)==NULL) + {// pclmtListMTItem2 был первым, обновляем заголвок листа, теперь первый pclmtListMTItem1 + pclmtListMT->plmtiFirst=pclmtListMTItem1; + } + + if ((pclmtListMTItem2->plmtiPrev=lpTemp)==NULL) + {// pclmtListMTItem1 был первым, обновляем заголвок листа, теперь первый pclmtListMTItem2 + pclmtListMT->plmtiFirst=pclmtListMTItem2; + } + + + lpTemp=pclmtListMTItem1->plmtiNext; + if ((pclmtListMTItem1->plmtiNext=pclmtListMTItem2->plmtiNext)==NULL) + {// pclmtListMTItem2 был последним, обновляем заголвок листа, теперь последний pclmtListMTItem1 + pclmtListMT->plmtiLast=pclmtListMTItem1; + } + + if ((pclmtListMTItem2->plmtiNext=lpTemp)==NULL) + {// pclmtListMTItem1 был последним, обновляем заголвок листа, теперь последний pclmtListMTItem2 + pclmtListMT->plmtiLast=pclmtListMTItem2; + } + } +} + + +__inline BOOL ListMTIteratorMoveFirst(PCLIST_MT pclmtListMT,PCLIST_MT_ITERATOR pclmtiIterator) +{// если нужно гарантировать эксклюзивный доступ, то есть ListMTLock и ListMTUnLock + return((pclmtiIterator->plmtListMTItem=pclmtListMT->plmtiFirst)? TRUE:FALSE); +} + + +__inline BOOL ListMTIteratorMoveLast(PCLIST_MT pclmtListMT,PCLIST_MT_ITERATOR pclmtiIterator) +{// если нужно гарантировать эксклюзивный доступ, то есть ListMTLock и ListMTUnLock + return((pclmtiIterator->plmtListMTItem=pclmtListMT->plmtiLast)? TRUE:FALSE); +} + + +__inline BOOL ListMTIteratorMovePrev(PCLIST_MT_ITERATOR pclmtiIterator) +{// если нужно гарантировать эксклюзивный доступ, то есть ListMTLock и ListMTUnLock + BOOL bRet=FALSE; + + if (pclmtiIterator->plmtListMTItem) + { + if (pclmtiIterator->plmtListMTItem=pclmtiIterator->plmtListMTItem->plmtiPrev) bRet=TRUE; + } +return(bRet); +} + + +__inline BOOL ListMTIteratorMoveNext(PCLIST_MT_ITERATOR pclmtiIterator) +{// если нужно гарантировать эксклюзивный доступ, то есть ListMTLock и ListMTUnLock + BOOL bRet=FALSE; + + if (pclmtiIterator->plmtListMTItem) + { + if (pclmtiIterator->plmtListMTItem=pclmtiIterator->plmtListMTItem->plmtiNext) bRet=TRUE; + } +return(bRet); +} + + +__inline DWORD ListMTIteratorGet(PCLIST_MT_ITERATOR pclmtiIterator,PLIST_MT_ITEM *pplmtListMTItem,LPVOID *plpData) +{// если нужно гарантировать эксклюзивный доступ, то есть ListMTLock и ListMTUnLock + DWORD dwRetErrorCode; + + if (pclmtiIterator->plmtListMTItem) + { + if (pplmtListMTItem) (*pplmtListMTItem)=pclmtiIterator->plmtListMTItem; + if (plpData) (*plpData)=pclmtiIterator->plmtListMTItem->lpData; + dwRetErrorCode=NO_ERROR; + }else{ + dwRetErrorCode=ERROR_NO_MORE_ITEMS; + } +return(dwRetErrorCode); +} + + + +#if defined(_MSC_VER) +#if _MSC_VER >= 800 +#if _MSC_VER >= 1200 +#pragma warning(pop) +#else +#pragma warning(default:4312) // warning C4312: 'type cast' : conversion from 'LONG' to 'PVOID' of greater size +#endif +#endif +#endif + + + +#endif // !defined(AFX_LIST_MT__H__INCLUDED_) diff --git a/protocols/MRA/src/Sdk/MemoryCompare.h b/protocols/MRA/src/Sdk/MemoryCompare.h new file mode 100644 index 0000000000..17ef96f35a --- /dev/null +++ b/protocols/MRA/src/Sdk/MemoryCompare.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2003 Rozhuk Ivan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + + + +#if !defined(AFX_MEMORYCOMPARE__H__INCLUDED_) +#define AFX_MEMORYCOMPARE__H__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + +// If the string pointed to by lpString1 is less than the string pointed +// to by lpString2, the return value is negative. +// If the string pointed to by lpString1 is greater than the string pointed +// to by lpString2, the return value is positive. +// If the strings are equal, the return value is zero. +// +// lpString1> ret=1=CSTR_LESS_THAN +// lpString1=lpString2 >> ret=2=CSTR_EQUAL +// lpString1>lpString2 >> ret=3=CSTR_GREATER_THAN + +#define CMEM_EQUAL 0 +#define CMEM_GREATER_THAN 1 +#define CMEM_LESS_THAN 2 + + +__inline unsigned int MemoryCompare(const void *pBuff1,size_t dwBuff1Size,const void *pBuff2,size_t dwBuff2Size) +{ + unsigned int uiRet; + + if (dwBuff1Size==dwBuff2Size) + { + if (pBuff1==pBuff2) + { + uiRet=CMEM_EQUAL; + }else{ + if (pBuff1 && pBuff2) + { + int iRet; + + iRet=memcmp(pBuff1,pBuff2,dwBuff1Size); + if (iRet==0) + { + uiRet=CMEM_EQUAL; + }else{ + if (iRet<0) + { + uiRet=CMEM_GREATER_THAN; + }else{ + uiRet=CMEM_LESS_THAN; + } + } + }else{ + if (pBuff1) + {//pBuff2==NULL + uiRet=CMEM_GREATER_THAN; + }else{//pBuff1==NULL + uiRet=CMEM_LESS_THAN; + } + } + } + }else{ + if (dwBuff1Size + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + + +#if !defined(AFX_MEMORYFIND__H__INCLUDED_) +#define AFX_MEMORYFIND__H__INCLUDED_ + + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + + +__inline void *MemoryFind(size_t dwFrom,const void *pBuff,size_t dwBuffSize,const void *pWhatFind,size_t dwWhatFindSize) +{ + void *pRet=NULL; + + if (pBuff && dwBuffSize && pWhatFind && dwWhatFindSize && (dwFrom+dwWhatFindSize)<=dwBuffSize) + { + if (dwWhatFindSize==1) + {// MemoryFindByte + pRet=(void*)memchr((const void*)(((size_t)pBuff)+dwFrom),(*((unsigned char*)pWhatFind)),(dwBuffSize-dwFrom)); + }else{ + void *pCurPos; + + pCurPos=(void*)(((size_t)pBuff)+dwFrom); + + if ((dwFrom+dwWhatFindSize)==dwBuffSize) + {// only MemoryCompare + if (memcmp(pCurPos,pWhatFind,dwWhatFindSize)==0) pRet=pCurPos; + }else{ + dwBuffSize-=(dwWhatFindSize-1); + + while(pCurPos) + { + pCurPos=memchr(pCurPos,(*((unsigned char*)pWhatFind)),(dwBuffSize-(((size_t)pCurPos)-((size_t)pBuff)))); + if (pCurPos) + { + if (memcmp(pCurPos,pWhatFind,dwWhatFindSize)==0) + { + pRet=pCurPos; + break; + }else{ + pCurPos=(void*)(((size_t)pCurPos)+1); + } + } + } + } + } + } +return(pRet); +} + + +#endif // !defined(AFX_MEMORYFIND__H__INCLUDED_) diff --git a/protocols/MRA/src/Sdk/MemoryFindByte.h b/protocols/MRA/src/Sdk/MemoryFindByte.h new file mode 100644 index 0000000000..a18a721b9d --- /dev/null +++ b/protocols/MRA/src/Sdk/MemoryFindByte.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2003 Rozhuk Ivan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + + + +#if !defined(AFX_MEMORYFINDBYTE__H__INCLUDED_) +#define AFX_MEMORYFINDBYTE__H__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + + +__inline void *MemoryFindByte(size_t dwFrom,const void *pBuff,size_t dwBuffSize,unsigned char chWhatFind) +{ + void *pRet=NULL; + + if (pBuff && dwBuffSize && dwFromdwFrom + jae short end_func + + std //; count 'up' on string this time + sub ecx,eax //; уменьшаем длинну на dwFrom(нач смещен) + add edi,ecx //; сдвигаем начало на dwSourceSize(на конец) + mov al,chWhatFind //; al=search byte + repne scasb //; find that byte + inc edi //; di points to byte which stopped scan + cmp [edi],al //; see if we have a hit + jne short end_func //; yes, point to byte + mov pRet,edi //; ax=pointer to byte + end_func: + + cld + pop esi // восстанавливаем содержимое регистра + pop edi // восстанавливаем содержимое регистра + pop ebx // восстанавливаем содержимое регистра + } +return(pRet); +} +#endif + + +#endif // !defined(AFX_MEMORYFINDBYTE__H__INCLUDED_) diff --git a/protocols/MRA/src/Sdk/MemoryReplace.h b/protocols/MRA/src/Sdk/MemoryReplace.h new file mode 100644 index 0000000000..c911ccfbe1 --- /dev/null +++ b/protocols/MRA/src/Sdk/MemoryReplace.h @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2010 Rozhuk Ivan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + + +#if !defined(AFX_MEMORY_REPLACE__H__INCLUDED_) +#define AFX_MEMORY_REPLACE__H__INCLUDED_ + + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + +#ifndef DebugBreak +#define DebugBreak() +#endif + + +#ifdef MEMALLOC +#define MEMORY_REPLACE_MEMALLOC(Size) MEMALLOC(Size) +#define MEMORY_REPLACE_MEMFREE(Mem) MEMFREE(Mem) +#else +#define MEMORY_REPLACE_MEMALLOC(Size) malloc(((Size)+sizeof(void*))) +#define MEMORY_REPLACE_MEMFREE(Mem) if ((Mem)) {free((void*)(Mem));(Mem)=NULL;} +#endif + + +// 0 - all ok +// -1 - bad params +// -2 - small dst buff +// -3 - memory allocation failed + +__inline int MemoryReplaceEx(void *pSrcBuff,size_t dwSrcBuffSize,size_t dwReplaceItemsCount,void **ppInReplaceItems,size_t *pdwInReplaceItemsCounts,void **ppOutReplaceItems,size_t *pdwOutReplaceItemsCounts,void *pDstBuff,size_t dwDstBuffSize,size_t *pdwDstBuffSize,size_t *pdwReplacesCount) +{ + int iRet=-1; + + if (pSrcBuff && dwSrcBuffSize && (dwReplaceItemsCount==0 || (dwReplaceItemsCount && ppInReplaceItems && pdwInReplaceItemsCounts && ppOutReplaceItems && pdwOutReplaceItemsCounts)) && pDstBuff && dwDstBuffSize) + { + if (dwReplaceItemsCount==0) + {// no replace, copy mem + if (dwDstBuffSize>=dwSrcBuffSize) + { + memmove(pDstBuff,pSrcBuff,dwSrcBuffSize); + if (pdwDstBuffSize) (*pdwDstBuffSize)=dwSrcBuffSize; + if (pdwReplacesCount) (*pdwReplacesCount)=0; + iRet=0; + }else{// small dst buff + iRet=-2; + } + }else{ + unsigned char **ppFounded; + + ppFounded=(unsigned char**)MEMORY_REPLACE_MEMALLOC((sizeof(unsigned char*)*dwReplaceItemsCount)); + if (ppFounded) + { + unsigned char *pDstBuffCur,*pSrcBuffCur,*pSrcBuffCurPrev,*pDstBuffMax; + size_t i,dwFirstFoundedIndex,dwFoundedCount,dwMemPartToCopy,dwReplacesCount; + + pSrcBuffCurPrev=(unsigned char*)pSrcBuff; + pDstBuffCur=(unsigned char*)pDstBuff; + pDstBuffMax=(((unsigned char*)pDstBuff)+dwDstBuffSize); + dwFirstFoundedIndex=0; + dwFoundedCount=0; + dwReplacesCount=0; + + for(i=0;i(pDstBuffCur+(dwMemPartToCopy+pdwInReplaceItemsCounts[dwFirstFoundedIndex]))) + { + dwReplacesCount++; + memmove(pDstBuffCur,pSrcBuffCurPrev,dwMemPartToCopy);pDstBuffCur+=dwMemPartToCopy; + memmove(pDstBuffCur,ppOutReplaceItems[dwFirstFoundedIndex],pdwOutReplaceItemsCounts[dwFirstFoundedIndex]);pDstBuffCur+=pdwOutReplaceItemsCounts[dwFirstFoundedIndex]; + pSrcBuffCurPrev=(ppFounded[dwFirstFoundedIndex]+pdwInReplaceItemsCounts[dwFirstFoundedIndex]); + + for(i=0;i + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + + + +#if !defined(AFX_RC4__H__INCLUDED_) +#define AFX_RC4__H__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + + +__inline void RC4(LPBYTE lpBuff,size_t dwBuffSize,LPBYTE lpKey,size_t dwKeySize) +{// RC4 +// www.codeproject.com/cpp/crypt_routine.asp%3Fdf%3D100%26forumid%3D4418%26exp%3D0%26select%3D251879+RC4+c%2B%2B+source+DWORD&hl=ru&gl=ru&ct=clnk&cd=2 +// http://www.thecodeproject.com/cpp/crypt_routine.asp +// http://forum.ixbt.com/topic.cgi?id=40:3020 + + //we will consider size of sbox 256 bytes + //(extra byte are only to prevent any mishep just in case) + BYTE temp; + BYTE Sbox[260]={0},Sbox2[260]={0}; + size_t i,j,t,x; + + i=j=t=x=0; + temp=0; + + //initialize sbox i + for(i=0;i<256;i++) Sbox[i]=(BYTE)i; + + j=0; + //whether user has sent any inpur lpKey + //initialize the sbox2 with user lpKey + for(i=0;i<256;i++) + { + if (j==dwKeySize) j=0; + Sbox2[i]=lpKey[j++]; + } + + j=0; //Initialize j + //scramble sbox1 with sbox2 + for(i=0;i<256;i++) + { + j=(j+(unsigned long)Sbox[i]+(unsigned long)Sbox2[i]) % 256U; + temp=Sbox[i]; + Sbox[i]=Sbox[j]; + Sbox[j]=temp; + } + + i=j=0; + for(x=0;x + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + + +#if !defined(AFX__SHA1_H__INCLUDED_) +#define AFX__SHA1_H__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + + +// see +// RFC 3174 - SHA1 +// RFC 2104 - HMAC +// RFC 2617 - CvtHex + + + +#define SHA1HashSize 20 +#define SHA1HashHexSize 40 + +/* This structure will hold context information for the SHA-1 hashing operation */ +typedef struct SHA1Context +{ + DWORD Intermediate_Hash[SHA1HashSize/4];/* Message Digest */ + ULARGE_INTEGER Length; /* Message length in bits */ + BYTE Message_Block[64]; /* 512-bit message blocks */ + BOOL Computed; /* Is the digest computed? */ +} SHA1Context; + + +#ifdef UNICODE + #define SHA1HMACGetString SHA1HMACGetStringW + #define SHA1GetStringDigest SHA1GetStringDigestW + #define SHA1CvtString SHA1CvtStringW +#else + #define SHA1HMACGetString SHA1HMACGetStringA + #define SHA1GetStringDigest SHA1GetStringDigestA + #define SHA1CvtString SHA1CvtStringA +#endif + + +#ifndef SHA1_MAX_SPEED + #ifdef SecureZeroMemory + #define SHA1SecureZeroMemory SecureZeroMemory + #else + #define SHA1SecureZeroMemory bzero + #endif +#else + #define SHA1SecureZeroMemory +#endif + + +/* + * Description: + * This file implements the Secure Hashing Algorithm 1 as + * defined in FIPS PUB 180-1 published April 17, 1995. + * + * The SHA-1, produces a 160-bit message digest for a given + * data stream. It should take about 2**n steps to find a + * message with the same digest as a given message and + * 2**(n/2) to find any two messages with the same digest, + * when n is the digest size in bits. Therefore, this + * algorithm can serve as a means of providing a + * "fingerprint" for a message. + * + * Portability Issues: + * SHA-1 is defined in terms of 32-bit "words". This code + * uses (included via "sha1.h" to define 32 and 8 + * bit unsigned integer types. If your C compiler does not + * support 32 bit unsigned integers, this code is not + * appropriate. + * + * Caveats: + * SHA-1 is designed to work with messages less than 2^64 bits + * long. Although SHA-1 allows a message digest to be generated + * for messages of any number of bits less than 2^64, this + * implementation only works with messages with a length that is + * a multiple of the size of an 8-bit character. + * + */ + + + +/* Define the SHA1 circular left shift macro */ +#define SHA1CircularShift(bits,word) (((word) << (bits)) | ((word) >> (32-(bits)))) + +/* Local Function Prototyptes */ +//void SHA1PadMessage(SHA1Context *); +//void SHA1ProcessMessageBlock(SHA1Context *); + + +__inline DWORD BSWAP(DWORD dwIn) +{ +return((((dwIn<<8) & 0x00ff0000) | (dwIn<<24) | ((dwIn>>8) & 0x0000ff00) | (dwIn>>24))); +} + +__inline void CopyMemoryReverseDWORD(LPCVOID lpcDestination,LPCVOID lpcSource,size_t dwSize) +{ +#ifdef _WIN64 + BYTE *pDestination=(BYTE*)lpcDestination,*pSource=(BYTE*)lpcSource; + + //for(size_t i=0;iIntermediate_Hash[0],/* Word buffers */ + B=context->Intermediate_Hash[1], + C=context->Intermediate_Hash[2], + D=context->Intermediate_Hash[3], + E=context->Intermediate_Hash[4]; + + /* Initialize the first 16 words in the array W */ + CopyMemoryReverseDWORD(W,Message_Block,64); + + for(t=16;t<80;t++) + { + W[t]=SHA1CircularShift(1,W[t-3]^W[t-8]^W[t-14]^W[t-16]); + } + + for(t=0;t<20;t++) + { + temp=SHA1CircularShift(5,A) + ((B&C) | ((~B)&D)) + E + W[t] + K[0]; + E=D; + D=C; + C=SHA1CircularShift(30,B); + B=A; + A=temp; + } + + for(t=20;t<40;t++) + { + temp=SHA1CircularShift(5,A) + (B^C^D) + E + W[t] + K[1]; + E=D; + D=C; + C=SHA1CircularShift(30,B); + B=A; + A=temp; + } + + for(t=40;t<60;t++) + { + temp=SHA1CircularShift(5,A) + ((B&C) | (B&D) | (C&D)) + E + W[t] + K[2]; + E=D; + D=C; + C=SHA1CircularShift(30,B); + B=A; + A=temp; + } + + for(t=60;t<80;t++) + { + temp=SHA1CircularShift(5,A) + (B^C^D) + E + W[t] + K[3]; + E=D; + D=C; + C=SHA1CircularShift(30,B); + B=A; + A=temp; + } + + context->Intermediate_Hash[0]+=A; + context->Intermediate_Hash[1]+=B; + context->Intermediate_Hash[2]+=C; + context->Intermediate_Hash[3]+=D; + context->Intermediate_Hash[4]+=E; + + /* Zeroize sensitive information.*/ + SHA1SecureZeroMemory(W,sizeof(W)); +} + + +/* +* SHA1PadMessage +* +* Description: +* According to the standard, the message must be padded to an even +* 512 bits. The first padding bit must be a '1'. The last 64 +* bits represent the length of the original message. All bits in +* between should be 0. This function will pad the message +* according to those rules by filling the Message_Block array +* accordingly. It will also call the ProcessMessageBlock function +* provided appropriately. When it returns, it can be assumed that +* the message digest has been computed. +* +* Parameters: +* context: [in/out] +* The context to pad +* ProcessMessageBlock: [in] +* The appropriate SHA*ProcessMessageBlock function +* Returns: +* Nothing. +* +*/ +__inline void SHA1PadMessage(SHA1Context *context) +{ + /* + * Check to see if the current message block is too small to hold + * the initial padding bits and length. If so, we will pad the + * block, process it, and then continue padding into a second + * block. + */ + size_t Message_Block_Index=(size_t)((context->Length.LowPart>>3) & 0x3F); + context->Message_Block[Message_Block_Index++]=0x80; + if (Message_Block_Index>56) + { + memset(&context->Message_Block[Message_Block_Index], 0, (64-Message_Block_Index)); + SHA1ProcessMessageBlock(context,context->Message_Block); + memset(&context->Message_Block, 0, 56); + }else{ + memset(&context->Message_Block[Message_Block_Index], 0, (56-Message_Block_Index)); + } + + /* Store the message length as the last 8 octets */ + context->Message_Block[56]=(BYTE)(context->Length.HighPart>>24); + context->Message_Block[57]=(BYTE)(context->Length.HighPart>>16); + context->Message_Block[58]=(BYTE)(context->Length.HighPart>>8); + context->Message_Block[59]=(BYTE)(context->Length.HighPart); + context->Message_Block[60]=(BYTE)(context->Length.LowPart>>24); + context->Message_Block[61]=(BYTE)(context->Length.LowPart>>16); + context->Message_Block[62]=(BYTE)(context->Length.LowPart>>8); + context->Message_Block[63]=(BYTE)(context->Length.LowPart); + + SHA1ProcessMessageBlock(context,context->Message_Block); +} + + + +/* +* SHA1Reset +* +* Description: +* This function will initialize the SHA1Context in preparation +* for computing a new SHA1 message digest. +* +* Parameters: +* context: [in/out] +* The context to reset. +* +* Returns: +* sha Error Code. +* +*/ +__inline DWORD SHA1Reset(SHA1Context *context) +{ + context->Intermediate_Hash[0]=0x67452301; + context->Intermediate_Hash[1]=0xEFCDAB89; + context->Intermediate_Hash[2]=0x98BADCFE; + context->Intermediate_Hash[3]=0x10325476; + context->Intermediate_Hash[4]=0xC3D2E1F0; + context->Length.QuadPart=0; + context->Computed=FALSE; + +return(NO_ERROR); +} + +/* +* SHA1Result +* +* Description: +* This function will return the 160-bit message digest into the +* Message_Digest array provided by the caller. +* NOTE: The first octet of hash is stored in the 0th element, +* the last octet of hash in the 19th element. +* +* Parameters: +* context: [in/out] +* The context to use to calculate the SHA-1 hash. +* Message_Digest: [out] +* Where the digest is returned. +* +* Returns: +* sha Error Code. +* +*/ +__inline DWORD SHA1Result(SHA1Context *context,BYTE *Message_Digest) +{ + if (context->Computed==FALSE) + { + SHA1PadMessage(context); + SHA1SecureZeroMemory(context->Message_Block,64);/* message may be sensitive, clear it out */ + context->Length.QuadPart=0; /* and clear length */ + context->Computed=TRUE; + } + + CopyMemoryReverseDWORD(Message_Digest,context->Intermediate_Hash,SHA1HashSize); + +return(NO_ERROR); +} + +/* +* SHA1Input +* +* Description: +* This function accepts an array of octets as the next portion +* of the message. +* +* Parameters: +* context: [in/out] +* The SHA context to update +* message_array: [in] +* An array of characters representing the next portion of +* the message. +* length: [in] +* The length of the message in message_array +* +* Returns: +* sha Error Code. +* +*/ +__inline DWORD SHA1Input(SHA1Context *context,const BYTE *message_array,size_t length) +{ + if (context->Computed==TRUE) return(ERROR_INVALID_HANDLE_STATE); + + if ((context->Length.QuadPart+(length<<3))>=(length<<3)) + { + size_t i,Message_Block_Index,partLen; + /* Compute number of bytes mod 64 */ + Message_Block_Index=(size_t)((context->Length.LowPart>>3) & 0x3F); + /* Update number of bits */ + context->Length.QuadPart+=(((ULONGLONG)length)<<3); + partLen=(64-Message_Block_Index); + /* Transform as many times as possible.*/ + if (length>=partLen) + { + memmove(&context->Message_Block[Message_Block_Index],message_array,partLen); + SHA1ProcessMessageBlock(context,context->Message_Block); + for (i=partLen;(i+63)Message_Block[Message_Block_Index],&message_array[i],(length-i)); + }else{ + return(RPC_S_STRING_TOO_LONG);/* Message is too long */ + } +return(NO_ERROR); +} +//////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////// +//////////////////////////////RFC 2104////////////////////////////// +//////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////// +__inline void hmac_sha1(BYTE *text,size_t text_len,BYTE *key,size_t key_len,BYTE *digest) +{ +//BYTE* text; /* pointer to data stream */ +//int text_len; /* length of data stream */ +//BYTE* key; /* pointer to authentication key */ +//int key_len; /* length of authentication key */ +//HASH digest; /* caller digest to be filled in */ + SHA1Context context; + BYTE k_ipad[65]; /* inner padding - key XORd with ipad */ + BYTE k_opad[65]; /* outer padding - key XORd with opad */ + BYTE tk[SHA1HashSize]; + /* if key is longer than 64 bytes reset it to key=SHA1(key) */ + if (key_len>64) + { + SHA1Context tctx; + + SHA1Reset(&tctx); + SHA1Input(&tctx,key,key_len); + SHA1Result(&tctx,(BYTE*)&tk); + + key=tk; + key_len=SHA1HashSize; + } + + /* + * the HMAC_SHA1 transform looks like: + * + * SHA1(K XOR opad, SHA1(K XOR ipad, text)) + * + * where K is an n byte key + * ipad is the byte 0x36 repeated 64 times + * opad is the byte 0x5c repeated 64 times + * and text is the data being protected + */ + + /* start out by storing key in pads */ + memmove(&k_ipad,key,key_len); + memmove(&k_opad,key,key_len); + memset(&k_ipad[key_len], 0, (sizeof(k_ipad)-key_len)); + memset(&k_opad[key_len], 0 , (sizeof(k_opad)-key_len)); + + /* XOR key with ipad and opad values */ + for (size_t i=0;i<(64/sizeof(ULONGLONG));i++) + { + ((ULONGLONG*)k_ipad)[i]^=0x3636363636363636; + ((ULONGLONG*)k_opad)[i]^=0x5C5C5C5C5C5C5C5C; + } + /* perform inner SHA1 */ + SHA1Reset(&context); /* init context for 1st pass */ + SHA1Input(&context,k_ipad,64); /* start with inner pad */ + SHA1Input(&context,text,text_len); /* then text of datagram */ + SHA1Result(&context,digest); /* finish up 1st pass */ + /* perform outer SHA1 */ + SHA1Reset(&context); /* init context for 2nd pass */ + SHA1Input(&context,k_opad,64); /* start with outer pad */ + SHA1Input(&context,(BYTE*)digest,SHA1HashSize); /* then results of 1st hash */ + SHA1Result(&context,digest); /* finish up 2nd pass */ + + SHA1SecureZeroMemory(k_ipad,sizeof(k_ipad)); + SHA1SecureZeroMemory(k_opad,sizeof(k_opad)); + SHA1SecureZeroMemory(tk,sizeof(tk)); +} +//////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////// +//////////////////////////////RFC 2617////////////////////////////// +//////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////// +__inline void SHA1CvtHex(BYTE *Bin,BYTE *Hex) +{ + BYTE j; + + for (size_t i=0;i>4)&0xf; + if(j<=9) + { + Hex[(i*2)]=(j+'0'); + }else{ + Hex[(i*2)]=(j+'a'-10); + } + + j=Bin[i]&0xf; + if(j<=9) + { + Hex[(i*2+1)]=(j+'0'); + }else{ + Hex[(i*2+1)]=(j+'a'-10); + } + }; + Hex[SHA1HashHexSize]=0; +}; + +//////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////// +__inline void SHA1CvtStringA(BYTE *digest,LPSTR lpszDigest) +{ + SHA1CvtHex(digest,(BYTE*)lpszDigest); +}; + + +__inline void SHA1CvtStringW(BYTE *digest,LPWSTR lpszDigest) +{ + size_t i,p=0; + for (i=0;i + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + + + +#if !defined(AFX_SOCKET_FUNCTIONS__H__INCLUDED_) +#define AFX_SOCKET_FUNCTIONS__H__INCLUDED_ + +#if(_WIN32_WINNT >= 0x0501) +static LPFN_CONNECTEX ConnectEx=NULL; +static LPFN_DISCONNECTEX DisconnectEx=NULL; +static LPFN_TRANSMITPACKETS TransmitPackets=NULL; +#endif + + +#ifndef NTOHS + +__inline u_short USHORT_FLIP(u_short usIn) +{ +return(((usIn<<8) | (usIn>>8))); +} +#define NTOHS(in) USHORT_FLIP(in) +#define HTONS(in) USHORT_FLIP(in) + +#endif + + + +#ifndef NTOHL + +__inline u_long ULONG_FLIP(u_long ulIn) +{ +#if defined (_M_IA64) || defined (_M_AMD64) +return((((ulIn<<8) & 0x00ff0000) | (ulIn<<24) | ((ulIn>>8) & 0x0000ff00) | (ulIn>>24))); +#else + __asm + { + mov eax,ulIn + bswap eax + mov ulIn,eax + }; +return(ulIn); +#endif +} + +#define NTOHL(in) ULONG_FLIP(in) +#define HTONL(in) ULONG_FLIP(in) + +#endif + + + + + +#define CLOSE_SOCKET(skt) if (skt) {closesocket(skt);skt=INVALID_SOCKET;} + + + +__inline BOOL SocketGetACCEPTCONN(SOCKET skt) +{ + BOOL bRet; + int iSize=sizeof(BOOL); + if (getsockopt(skt,SOL_SOCKET,SO_ACCEPTCONN,(char*)&bRet,(int*)&iSize)!=NO_ERROR) bRet=FALSE; +return(bRet); +} + + +__inline BOOL SocketGetBROADCAST(SOCKET skt) +{ + BOOL bRet; + int iSize=sizeof(BOOL); + if (getsockopt(skt,SOL_SOCKET,SO_BROADCAST,(char*)&bRet,(int*)&iSize)!=NO_ERROR) bRet=FALSE; +return(bRet); +} + +__inline int SocketSetBROADCAST(SOCKET skt,BOOL bBroadcast) +{ +return(setsockopt(skt,SOL_SOCKET,SO_BROADCAST,(const char*)&bBroadcast,sizeof(BOOL))); +} + + + +__inline int SocketGetCONNECT_TIME(SOCKET skt) +{ + int iSeconds,iSize=sizeof(int); + if (getsockopt(skt,SOL_SOCKET,SO_CONNECT_TIME,(char*)&iSeconds,(int*)&iSize)!=NO_ERROR) iSeconds=-1; +return(iSeconds); +} + + +__inline BOOL SocketGetKEEPALIVE(SOCKET skt) +{ + BOOL bRet; + int iSize=sizeof(BOOL); + if (getsockopt(skt,SOL_SOCKET,SO_KEEPALIVE,(char*)&bRet,(int*)&iSize)!=NO_ERROR) bRet=FALSE; +return(bRet); +} + +__inline int SocketSetKEEPALIVE(SOCKET skt,BOOL bKeepAlive) +{ +return(setsockopt(skt,SOL_SOCKET,SO_KEEPALIVE,(const char*)&bKeepAlive,sizeof(BOOL))); +} + + + +__inline int SocketGetMAX_MSG_SIZE(SOCKET skt) +{ + int iMaxMsgSize,iSize=sizeof(int); + if (getsockopt(skt,SOL_SOCKET,SO_MAX_MSG_SIZE,(char*)&iMaxMsgSize,(int*)&iSize)!=NO_ERROR) iMaxMsgSize=-1; +return(iMaxMsgSize); +} + + +__inline int SocketSetEXCLUSIVEADDRUSE(SOCKET skt,BOOL bExclusiveAddrUse) +{ +return(setsockopt(skt,SOL_SOCKET,SO_EXCLUSIVEADDRUSE,(const char*)&bExclusiveAddrUse,sizeof(BOOL))); +} + + +__inline BOOL SocketGetREUSEADDR(SOCKET skt) +{ + BOOL bRet; + int iSize=sizeof(BOOL); + if (getsockopt(skt,SOL_SOCKET,SO_REUSEADDR,(char*)&bRet,(int*)&iSize)!=NO_ERROR) bRet=FALSE; +return(bRet); +} + +__inline int SocketSetREUSEADDR(SOCKET skt,BOOL bReuseAddr) +{ +return(setsockopt(skt,SOL_SOCKET,SO_REUSEADDR,(const char*)&bReuseAddr,sizeof(BOOL))); +} + + +__inline int SocketSetRCVBUF(SOCKET skt,unsigned int uiBuffSize) +{ +return(setsockopt(skt,SOL_SOCKET,SO_RCVBUF,(const char*)&uiBuffSize,sizeof(int))); +} + + +__inline int SocketSetSNDBUF(SOCKET skt,unsigned int uiBuffSize) +{ +return(setsockopt(skt,SOL_SOCKET,SO_SNDBUF,(const char*)&uiBuffSize,sizeof(int))); +} + + + +__inline int SocketSetUPDATE_ACCEPT_CONTEXT(SOCKET skt,SOCKET sktAccept) +{ +return(setsockopt(skt,SOL_SOCKET,SO_UPDATE_ACCEPT_CONTEXT,(char*)&sktAccept,sizeof(SOCKET))); +} + + +#if(_WIN32_WINNT >= 0x0501) +__inline int SocketSetUPDATE_CONNECT_CONTEXT(SOCKET skt) +{ +return(setsockopt(skt,SOL_SOCKET,SO_UPDATE_CONNECT_CONTEXT,NULL,0)); +} +#endif + + + + +__inline BOOL SocketGetHDRINCL(SOCKET skt) +{ + BOOL bRet; + int iSize=sizeof(BOOL); + if (getsockopt(skt,IPPROTO_IP,IP_HDRINCL,(char*)&bRet,(int*)&iSize)!=NO_ERROR) bRet=FALSE; +return(bRet); +} + +__inline int SocketSetHDRINCL(SOCKET skt,BOOL bProvideIPHdr) +{ +return(setsockopt(skt,IPPROTO_IP,IP_HDRINCL,(const char*)&bProvideIPHdr,sizeof(DWORD))); +} + + +#define TOS_DEFAULT 0 +#define TOS_MIN_MONETARY_COST 2 +#define TOS_MIN_RELIABILITY 4 +#define TOS_MAX_THROUGHPUT 8 +#define TOS_MIN_DELAY 16 +#define TOS_MAX_SECURITY 30 + +__inline int SocketSetTOS(SOCKET skt,DWORD dwTOS) +{ +return(setsockopt(skt,IPPROTO_IP,IP_TOS,(const char*)&dwTOS,sizeof(DWORD))); +} + + +__inline int SocketSetTTL(SOCKET skt,UINT iTTL) +{ +return(setsockopt(skt,IPPROTO_IP,IP_TTL,(const char*)&iTTL,sizeof(DWORD))); +} + + +__inline int SocketSetTCP_NODELAY(SOCKET skt,BOOL bTCPNoDelay) +{ +return(setsockopt(skt,IPPROTO_TCP,TCP_NODELAY,(const char*)&bTCPNoDelay,sizeof(DWORD))); +} + +/* +int // OUT: whatever setsockopt() returns +join_source_group(int sd, u_int32 grpaddr, + u_int32 srcaddr, u_int32 iaddr) +{ + struct ip_mreq_source imr; + + imr.imr_multiaddr.s_addr = grpaddr; + imr.imr_sourceaddr.s_addr = srcaddr; + imr.imr_interface.s_addr = iaddr; + return setsockopt(sd, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP, &imr, sizeof(imr)); +} + +int +leave_source_group(int sd, u_int32 grpaddr, + u_int32 srcaddr, u_int32 iaddr) +{ + struct ip_mreq_source imr; + + imr.imr_multiaddr.s_addr = grpaddr; + imr.imr_sourceaddr.s_addr = srcaddr; + imr.imr_interface.s_addr = iaddr; + return setsockopt(sd, IPPROTO_IP, IP_DROP_SOURCE_MEMBERSHIP, &imr, sizeof(imr)); +}*/ + + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +__inline BOOL WINAPI DisconnectExTF(SOCKET hSocket,LPOVERLAPPED lpOverlapped,DWORD dwFlags,DWORD reserved) +{ + reserved=0; + dwFlags&=TF_REUSE_SOCKET; + dwFlags|=TF_DISCONNECT; +return(TransmitFile(hSocket,NULL,0,0,lpOverlapped,NULL,dwFlags)); +} + + + +__inline DWORD SocketsInitialize() +{ + DWORD dwRetErrorCode; + WSADATA wsaData; + + if ((dwRetErrorCode=WSAStartup(MAKEWORD(1,1),&wsaData))==NO_ERROR) + {// version 1.1 OK + WSACleanup(); + + dwRetErrorCode=WSAStartup(wsaData.wHighVersion,&wsaData); + } +return(dwRetErrorCode); +} + + +#if(_WIN32_WINNT >= 0x0501) +__inline DWORD SocketsInitializeEx(DWORD dwFlags) +{ + DWORD dwRetErrorCode; + WSADATA wsaData; + + dwFlags=0; + if ((dwRetErrorCode=WSAStartup(MAKEWORD(1,1),&wsaData))==NO_ERROR) + {// version 1.1 OK + WSACleanup(); + if ((dwRetErrorCode=WSAStartup(wsaData.wHighVersion,&wsaData))==NO_ERROR) + {// max version initialized + SOCKET skt; + + if ((skt=WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,0,0,WSA_FLAG_OVERLAPPED))!=INVALID_SOCKET) + { + DWORD dwSize; + GUID ExtensionGuidCONNECTEX=WSAID_CONNECTEX; + GUID ExtensionGuidDISCONNECTEX=WSAID_DISCONNECTEX; + GUID ExtensionGuidTRANSMITPACKETS=WSAID_TRANSMITPACKETS; + + dwRetErrorCode=NO_ERROR; + + if (WSAIoctl(skt,SIO_GET_EXTENSION_FUNCTION_POINTER,&ExtensionGuidCONNECTEX,sizeof(GUID),&ConnectEx,sizeof(FARPROC),&dwSize,NULL,NULL)==0) + { + if (ConnectEx==NULL) dwRetErrorCode=WSAGetLastError(); + }else{ + dwRetErrorCode=WSAGetLastError(); + } + + + if (WSAIoctl(skt,SIO_GET_EXTENSION_FUNCTION_POINTER,&ExtensionGuidDISCONNECTEX,sizeof(GUID),&DisconnectEx,sizeof(FARPROC),&dwSize,NULL,NULL)==0) + { + if (DisconnectEx==NULL) + { + DisconnectEx=DisconnectExTF; + //dwRetErrorCode=WSAGetLastError(); + } + }else{ + dwRetErrorCode=WSAGetLastError(); + } + + if (WSAIoctl(skt,SIO_GET_EXTENSION_FUNCTION_POINTER,&ExtensionGuidTRANSMITPACKETS,sizeof(GUID),&TransmitPackets,sizeof(FARPROC),&dwSize,NULL,NULL)==0) + { + if (TransmitPackets==NULL) dwRetErrorCode=WSAGetLastError(); + }else{ + dwRetErrorCode=WSAGetLastError(); + } + + closesocket(skt); + }else{ + dwRetErrorCode=WSAGetLastError(); + } + } + } +return(dwRetErrorCode); +} +#endif + + + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +///////////////////////////SOCKADDR_STORAGE///////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +#if(_WIN32_WINNT >= 0x0501) + +__inline DWORD SockAddrInDataSet(LPCVOID lpcsasSockAddrStorage,DWORD dwPort,LPCVOID lpcAddress,size_t dwAddressSize) +{ + DWORD dwRetErrorCode=NO_ERROR; + + if (lpcsasSockAddrStorage && lpcAddress) + { + switch(dwAddressSize){ + case sizeof(in_addr): + ((sockaddr_in*)lpcsasSockAddrStorage)->sin_family=AF_INET; + ((sockaddr_in*)lpcsasSockAddrStorage)->sin_port=HTONS((WORD)dwPort); + (*((DWORD*)&(((sockaddr_in*)lpcsasSockAddrStorage)->sin_addr)))=(*((DWORD*)lpcAddress)); + break; + case sizeof(in6_addr): + ((sockaddr_in6*)lpcsasSockAddrStorage)->sin6_family=AF_INET6; + ((sockaddr_in6*)lpcsasSockAddrStorage)->sin6_port=HTONS((WORD)dwPort); + memmove(&(((sockaddr_in6*)lpcsasSockAddrStorage)->sin6_addr),lpcAddress,sizeof(in6_addr)); + break; + default: + dwRetErrorCode=ERROR_INVALID_PARAMETER; + break; + } + }else{ + dwRetErrorCode=ERROR_INVALID_HANDLE; + } +return(dwRetErrorCode); +} + + +__inline DWORD SockAddrInPortSet(LPCVOID lpcsasSockAddrStorage,DWORD dwPort) +{ + DWORD dwRetErrorCode=NO_ERROR; + + if (lpcsasSockAddrStorage) + { + switch(((SOCKADDR_STORAGE*)lpcsasSockAddrStorage)->ss_family){ + case AF_INET: + ((sockaddr_in*)lpcsasSockAddrStorage)->sin_port=HTONS((WORD)dwPort); + break; + case AF_INET6: + ((sockaddr_in6*)lpcsasSockAddrStorage)->sin6_port=HTONS((WORD)dwPort); + break; + default: + dwRetErrorCode=ERROR_INVALID_PARAMETER; + break; + } + }else{ + dwRetErrorCode=ERROR_INVALID_HANDLE; + } +return(dwRetErrorCode); +} + + +__inline DWORD SockAddrInAddressSet(LPCVOID lpcsasSockAddrStorage,LPCVOID lpcAddress,size_t dwAddressSize) +{ + DWORD dwRetErrorCode=NO_ERROR; + + if (lpcsasSockAddrStorage && lpcAddress) + { + switch(dwAddressSize){ + case sizeof(in_addr): + ((sockaddr_in*)lpcsasSockAddrStorage)->sin_family=AF_INET; + (*((DWORD*)&(((sockaddr_in*)lpcsasSockAddrStorage)->sin_addr)))=(*((DWORD*)lpcAddress)); + break; + case sizeof(in6_addr): + ((sockaddr_in6*)lpcsasSockAddrStorage)->sin6_family=AF_INET6; + memmove(&(((sockaddr_in6*)lpcsasSockAddrStorage)->sin6_addr),lpcAddress,sizeof(in6_addr)); + break; + default: + dwRetErrorCode=ERROR_INVALID_PARAMETER; + break; + } + }else{ + dwRetErrorCode=ERROR_INVALID_HANDLE; + } +return(dwRetErrorCode); +} + + +__inline DWORD SockAddrAddressSet(LPCVOID lpcsasSockAddrStorage,LPCVOID lpcAddress,size_t dwAddressSize) +{ + DWORD dwRetErrorCode=NO_ERROR; + + if (lpcsasSockAddrStorage && lpcAddress) + { + switch(dwAddressSize){ + case sizeof(in_addr): + ((sockaddr*)lpcsasSockAddrStorage)->sa_family=AF_INET; + (*((DWORD*)&(((sockaddr*)lpcsasSockAddrStorage)->sa_data)))=(*((DWORD*)lpcAddress)); + break; + case sizeof(in6_addr): + ((sockaddr*)lpcsasSockAddrStorage)->sa_family=AF_INET6; + memmove(&(((sockaddr*)lpcsasSockAddrStorage)->sa_data),lpcAddress,sizeof(in6_addr)); + break; + default: + dwRetErrorCode=ERROR_INVALID_PARAMETER; + break; + } + }else{ + dwRetErrorCode=ERROR_INVALID_HANDLE; + } +return(dwRetErrorCode); +} + + +__inline size_t SockAddrGetSize(LPCVOID lpcsasSockAddrStorage) +{ + size_t dwRet; + + if (lpcsasSockAddrStorage) + { + switch(((SOCKADDR_STORAGE*)lpcsasSockAddrStorage)->ss_family){ + case AF_INET: + dwRet=sizeof(sockaddr_in); + break; + case AF_INET6: + dwRet=sizeof(sockaddr_in6); + break; + default: + dwRet=sizeof(SOCKADDR_STORAGE); + break; + } + }else{ + dwRet=0; + } +return(dwRet); +} + + +#endif +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + + +#endif //AFX_SOCKET_FUNCTIONS__H__INCLUDED_ \ No newline at end of file diff --git a/protocols/MRA/src/Sdk/StrHexToNum.h b/protocols/MRA/src/Sdk/StrHexToNum.h new file mode 100644 index 0000000000..e4a5cc98fa --- /dev/null +++ b/protocols/MRA/src/Sdk/StrHexToNum.h @@ -0,0 +1,634 @@ +/* + * Copyright (c) 2005 Rozhuk Ivan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + + + +#if !defined(AFX_STRHEXTONUM__H__INCLUDED_) +#define AFX_STRHEXTONUM__H__INCLUDED_ + + + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + + + +__inline size_t StrHexToUNum(LPCSTR lpcszString,size_t dwStringLen) +{ + size_t dwNum=0; + BYTE bCurentFigure; + + while(dwStringLen) + { + bCurentFigure=(*lpcszString); + if ('0'<=bCurentFigure && bCurentFigure<='9') + { + bCurentFigure-='0'; + }else + if ('a'<=bCurentFigure && bCurentFigure<='f') + { + bCurentFigure-=('a'+10); + }else + if ('A'<=bCurentFigure && bCurentFigure<='F') + { + bCurentFigure-=('A'+10); + }else{ + bCurentFigure=255; + } + + if (bCurentFigure!=255) + { + dwNum*=16;// сдвигаем предыдущее число на один разряд чтоб добавить в младший разряд новую цифру + dwNum+=bCurentFigure;// добавляем цифру в младший разряд + } + lpcszString++;// перемещаем указатель на следующую позицию + dwStringLen--;// уменьшаем длинну + } + +return(dwNum); +} + +__inline DWORD StrHexToUNum32(LPCSTR lpcszString,size_t dwStringLen) +{ + DWORD dwNum=0; + BYTE bCurentFigure; + + + while(dwStringLen) + { + bCurentFigure=(*lpcszString); + if ('0'<=bCurentFigure && bCurentFigure<='9') + { + bCurentFigure-='0'; + }else + if ('a'<=bCurentFigure && bCurentFigure<='f') + { + bCurentFigure-=('a'+10); + }else + if ('A'<=bCurentFigure && bCurentFigure<='F') + { + bCurentFigure-=('A'+10); + }else{ + bCurentFigure=255; + } + + if (bCurentFigure!=255) + { + dwNum*=16;// сдвигаем предыдущее число на один разряд чтоб добавить в младший разряд новую цифру + dwNum+=bCurentFigure;// добавляем цифру в младший разряд + } + lpcszString++;// перемещаем указатель на следующую позицию + dwStringLen--;// уменьшаем длинну + } + +return(dwNum); +} + +__inline DWORDLONG StrHexToUNum64(LPCSTR lpcszString,size_t dwStringLen) +{ + DWORDLONG dwlNum=0; + BYTE bCurentFigure; + + + while(dwStringLen) + { + bCurentFigure=(*lpcszString); + if ('0'<=bCurentFigure && bCurentFigure<='9') + { + bCurentFigure-='0'; + }else + if ('a'<=bCurentFigure && bCurentFigure<='f') + { + bCurentFigure-=('a'+10); + }else + if ('A'<=bCurentFigure && bCurentFigure<='F') + { + bCurentFigure-=('A'+10); + }else{ + bCurentFigure=255; + } + + if (bCurentFigure!=255) + { + dwlNum*=16;// сдвигаем предыдущее число на один разряд чтоб добавить в младший разряд новую цифру + dwlNum+=bCurentFigure;// добавляем цифру в младший разряд + } + lpcszString++;// перемещаем указатель на следующую позицию + dwStringLen--;// уменьшаем длинну + } + +return(dwlNum); +} + + + +__inline DWORD StrHexToUNumEx(LPCSTR lpcszString,size_t dwStringLen,size_t *pdwNum) +{ + DWORD dwRetErrorCode; + size_t dwNum=0,dwProcessed=0; + BYTE bCurentFigure; + + + while(dwStringLen) + { + bCurentFigure=(*lpcszString); + if ('0'<=bCurentFigure && bCurentFigure<='9') + { + bCurentFigure-='0'; + }else + if ('a'<=bCurentFigure && bCurentFigure<='f') + { + bCurentFigure-=('a'+10); + }else + if ('A'<=bCurentFigure && bCurentFigure<='F') + { + bCurentFigure-=('A'+10); + }else{ + bCurentFigure=255; + } + + if (bCurentFigure!=255) + { + dwNum*=16;// сдвигаем предыдущее число на один разряд чтоб добавить в младший разряд новую цифру + dwNum+=bCurentFigure;// добавляем цифру в младший разряд + dwProcessed++;// увеличиваем счётчик обработанных цифр + } + lpcszString++;// перемещаем указатель на следующую позицию + dwStringLen--;// уменьшаем длинну + } + + if (dwProcessed) + {// как минимум одна цифра была обработана + if (pdwNum) (*pdwNum)=dwNum; + if (dwProcessed==dwStringLen) + {// в строке были только цифры, всё отработало как нужно //Операция успешно завершена. + dwRetErrorCode=NO_ERROR; + }else{// в строке были не только цифры //Имеются дополнительные данные. + dwRetErrorCode=ERROR_MORE_DATA; + } + }else{// строка вообще не содержала цифр //Недопустимые данные. + dwRetErrorCode=ERROR_INVALID_DATA; + } +return(dwRetErrorCode); +} + + +__inline DWORD StrHexToUNumEx32(LPCSTR lpcszString,size_t dwStringLen,DWORD *pdwNum) +{ + DWORD dwRetErrorCode; + DWORD dwNum=0,dwProcessed=0; + BYTE bCurentFigure; + + + while(dwStringLen) + { + bCurentFigure=(*lpcszString); + if ('0'<=bCurentFigure && bCurentFigure<='9') + { + bCurentFigure-='0'; + }else + if ('a'<=bCurentFigure && bCurentFigure<='f') + { + bCurentFigure-=('a'+10); + }else + if ('A'<=bCurentFigure && bCurentFigure<='F') + { + bCurentFigure-=('A'+10); + }else{ + bCurentFigure=255; + } + + if (bCurentFigure!=255) + { + dwNum*=16;// сдвигаем предыдущее число на один разряд чтоб добавить в младший разряд новую цифру + dwNum+=bCurentFigure;// добавляем цифру в младший разряд + dwProcessed++;// увеличиваем счётчик обработанных цифр + } + lpcszString++;// перемещаем указатель на следующую позицию + dwStringLen--;// уменьшаем длинну + } + + if (dwProcessed) + {// как минимум одна цифра была обработана + if (pdwNum) (*pdwNum)=dwNum; + if (dwProcessed==dwStringLen) + {// в строке были только цифры, всё отработало как нужно //Операция успешно завершена. + dwRetErrorCode=NO_ERROR; + }else{// в строке были не только цифры //Имеются дополнительные данные. + dwRetErrorCode=ERROR_MORE_DATA; + } + }else{// строка вообще не содержала цифр //Недопустимые данные. + dwRetErrorCode=ERROR_INVALID_DATA; + } +return(dwRetErrorCode); +} + + +__inline DWORD StrHexToUNumEx64(LPCSTR lpcszString,size_t dwStringLen,DWORDLONG *pdwlNum) +{ + DWORD dwRetErrorCode; + DWORDLONG dwlNum=0; + size_t dwProcessed=0; + BYTE bCurentFigure; + + + while(dwStringLen) + { + bCurentFigure=(*lpcszString); + if ('0'<=bCurentFigure && bCurentFigure<='9') + { + bCurentFigure-='0'; + }else + if ('a'<=bCurentFigure && bCurentFigure<='f') + { + bCurentFigure-=('a'+10); + }else + if ('A'<=bCurentFigure && bCurentFigure<='F') + { + bCurentFigure-=('A'+10); + }else{ + bCurentFigure=255; + } + + if (bCurentFigure!=255) + { + dwlNum*=16;// сдвигаем предыдущее число на один разряд чтоб добавить в младший разряд новую цифру + dwlNum+=bCurentFigure;// добавляем цифру в младший разряд + dwProcessed++;// увеличиваем счётчик обработанных цифр + } + lpcszString++;// перемещаем указатель на следующую позицию + dwStringLen--;// уменьшаем длинну + } + + if (dwProcessed) + {// как минимум одна цифра была обработана + if (pdwlNum) (*pdwlNum)=dwlNum; + if (dwProcessed==dwStringLen) + {// в строке были только цифры, всё отработало как нужно //Операция успешно завершена. + dwRetErrorCode=NO_ERROR; + }else{// в строке были не только цифры //Имеются дополнительные данные. + dwRetErrorCode=ERROR_MORE_DATA; + } + }else{// строка вообще не содержала цифр //Недопустимые данные. + dwRetErrorCode=ERROR_INVALID_DATA; + } +return(dwRetErrorCode); +} + + + + +__inline SSIZE_T StrHexToNum(LPCSTR lpcszString,size_t dwStringLen) +{ + SSIZE_T lNum=0,lSingn=1; + BYTE bCurentFigure; + + + while(dwStringLen && ((bCurentFigure=((*lpcszString)-48))>9)) + { + if (bCurentFigure=='-') lSingn=-1; + if (bCurentFigure=='+') lSingn=1; + + lpcszString++;// перемещаем указатель на следующую позицию + dwStringLen--;// уменьшаем длинну + } + + while(dwStringLen) + { + bCurentFigure=(*lpcszString); + if ('0'<=bCurentFigure && bCurentFigure<='9') + { + bCurentFigure-='0'; + }else + if ('a'<=bCurentFigure && bCurentFigure<='f') + { + bCurentFigure-=('a'+10); + }else + if ('A'<=bCurentFigure && bCurentFigure<='F') + { + bCurentFigure-=('A'+10); + }else{ + bCurentFigure=255; + } + + if (bCurentFigure!=255) + { + lNum*=16;// сдвигаем предыдущее число на один разряд чтоб добавить в младший разряд новую цифру + lNum+=bCurentFigure;// добавляем цифру в младший разряд + } + lpcszString++;// перемещаем указатель на следующую позицию + dwStringLen--;// уменьшаем длинну + } + lNum*=lSingn; + +return(lNum); +} + + +__inline LONG StrHexToNum32(LPCSTR lpcszString,size_t dwStringLen) +{ + LONG lNum=0,lSingn=1; + BYTE bCurentFigure; + + + while(dwStringLen && ((bCurentFigure=((*lpcszString)-48))>9)) + { + if (bCurentFigure=='-') lSingn=-1; + if (bCurentFigure=='+') lSingn=1; + + lpcszString++;// перемещаем указатель на следующую позицию + dwStringLen--;// уменьшаем длинну + } + + while(dwStringLen) + { + bCurentFigure=(*lpcszString); + if ('0'<=bCurentFigure && bCurentFigure<='9') + { + bCurentFigure-='0'; + }else + if ('a'<=bCurentFigure && bCurentFigure<='f') + { + bCurentFigure-=('a'+10); + }else + if ('A'<=bCurentFigure && bCurentFigure<='F') + { + bCurentFigure-=('A'+10); + }else{ + bCurentFigure=255; + } + + if (bCurentFigure!=255) + { + lNum*=16;// сдвигаем предыдущее число на один разряд чтоб добавить в младший разряд новую цифру + lNum+=bCurentFigure;// добавляем цифру в младший разряд + } + lpcszString++;// перемещаем указатель на следующую позицию + dwStringLen--;// уменьшаем длинну + } + lNum*=lSingn; + +return(lNum); +} + + +__inline LONGLONG StrHexToNum64(LPCSTR lpcszString,size_t dwStringLen) +{ + LONGLONG llNum=0,llSingn=1; + BYTE bCurentFigure; + + + while(dwStringLen && ((bCurentFigure=((*lpcszString)-48))>9)) + { + if (bCurentFigure=='-') llSingn=-1; + if (bCurentFigure=='+') llSingn=1; + + lpcszString++;// перемещаем указатель на следующую позицию + dwStringLen--;// уменьшаем длинну + } + + while(dwStringLen) + { + bCurentFigure=(*lpcszString); + if ('0'<=bCurentFigure && bCurentFigure<='9') + { + bCurentFigure-='0'; + }else + if ('a'<=bCurentFigure && bCurentFigure<='f') + { + bCurentFigure-=('a'+10); + }else + if ('A'<=bCurentFigure && bCurentFigure<='F') + { + bCurentFigure-=('A'+10); + }else{ + bCurentFigure=255; + } + + if (bCurentFigure!=255) + { + llNum*=16;// сдвигаем предыдущее число на один разряд чтоб добавить в младший разряд новую цифру + llNum+=bCurentFigure;// добавляем цифру в младший разряд + } + lpcszString++;// перемещаем указатель на следующую позицию + dwStringLen--;// уменьшаем длинну + } + llNum*=llSingn; + +return(llNum); +} + + + +__inline DWORD StrHexToNumEx(LPCSTR lpcszString,size_t dwStringLen,SSIZE_T *plNum) +{ + DWORD dwRetErrorCode; + size_t dwProcessed=0; + SSIZE_T lNum=0,lSingn=1; + BYTE bCurentFigure; + + + while(dwStringLen && ((bCurentFigure=((*lpcszString)-48))>9)) + { + if (bCurentFigure=='-') lSingn=-1; + if (bCurentFigure=='+') lSingn=1; + + lpcszString++;// перемещаем указатель на следующую позицию + dwStringLen--;// уменьшаем длинну + } + + while(dwStringLen) + { + bCurentFigure=(*lpcszString); + if ('0'<=bCurentFigure && bCurentFigure<='9') + { + bCurentFigure-='0'; + }else + if ('a'<=bCurentFigure && bCurentFigure<='f') + { + bCurentFigure-=('a'+10); + }else + if ('A'<=bCurentFigure && bCurentFigure<='F') + { + bCurentFigure-=('A'+10); + }else{ + bCurentFigure=255; + } + + if (bCurentFigure!=255) + { + lNum*=16;// сдвигаем предыдущее число на один разряд чтоб добавить в младший разряд новую цифру + lNum+=bCurentFigure;// добавляем цифру в младший разряд + dwProcessed++;// увеличиваем счётчик обработанных цифр + } + lpcszString++;// перемещаем указатель на следующую позицию + dwStringLen--;// уменьшаем длинну + } + + if (dwProcessed) + {// как минимум одна цифра была обработана + if (plNum) (*plNum)=(lNum*lSingn); + if (dwProcessed==dwStringLen) + {// в строке были только цифры, всё отработало как нужно //Операция успешно завершена. + dwRetErrorCode=NO_ERROR; + }else{// в строке были не только цифры //Имеются дополнительные данные. + dwRetErrorCode=ERROR_MORE_DATA; + } + }else{// строка вообще не содержала цифр //Недопустимые данные. + dwRetErrorCode=ERROR_INVALID_DATA; + } +return(dwRetErrorCode); +} + + +__inline DWORD StrHexToNumEx32(LPCSTR lpcszString,size_t dwStringLen,LONG *plNum) +{ + DWORD dwRetErrorCode; + size_t dwProcessed=0; + LONG lNum=0,lSingn=1; + BYTE bCurentFigure; + + + while(dwStringLen && ((bCurentFigure=((*lpcszString)-48))>9)) + { + if (bCurentFigure=='-') lSingn=-1; + if (bCurentFigure=='+') lSingn=1; + + lpcszString++;// перемещаем указатель на следующую позицию + dwStringLen--;// уменьшаем длинну + } + + while(dwStringLen) + { + bCurentFigure=(*lpcszString); + if ('0'<=bCurentFigure && bCurentFigure<='9') + { + bCurentFigure-='0'; + }else + if ('a'<=bCurentFigure && bCurentFigure<='f') + { + bCurentFigure-=('a'+10); + }else + if ('A'<=bCurentFigure && bCurentFigure<='F') + { + bCurentFigure-=('A'+10); + }else{ + bCurentFigure=255; + } + + if (bCurentFigure!=255) + { + lNum*=16;// сдвигаем предыдущее число на один разряд чтоб добавить в младший разряд новую цифру + lNum+=bCurentFigure;// добавляем цифру в младший разряд + dwProcessed++;// увеличиваем счётчик обработанных цифр + } + lpcszString++;// перемещаем указатель на следующую позицию + dwStringLen--;// уменьшаем длинну + } + + if (dwProcessed) + {// как минимум одна цифра была обработана + if (plNum) (*plNum)=(lNum*lSingn); + if (dwProcessed==dwStringLen) + {// в строке были только цифры, всё отработало как нужно //Операция успешно завершена. + dwRetErrorCode=NO_ERROR; + }else{// в строке были не только цифры //Имеются дополнительные данные. + dwRetErrorCode=ERROR_MORE_DATA; + } + }else{// строка вообще не содержала цифр //Недопустимые данные. + dwRetErrorCode=ERROR_INVALID_DATA; + } +return(dwRetErrorCode); +} + + +__inline DWORD StrHexToNumEx64(LPCSTR lpcszString,size_t dwStringLen,LONGLONG *pllNum) +{ + DWORD dwRetErrorCode; + size_t dwProcessed=0; + LONGLONG llNum=0,llSingn=1; + BYTE bCurentFigure; + + + while(dwStringLen && ((bCurentFigure=((*lpcszString)-48))>9)) + { + if (bCurentFigure=='-') llSingn=-1; + if (bCurentFigure=='+') llSingn=1; + + lpcszString++;// перемещаем указатель на следующую позицию + dwStringLen--;// уменьшаем длинну + } + + while(dwStringLen) + { + bCurentFigure=(*lpcszString); + if ('0'<=bCurentFigure && bCurentFigure<='9') + { + bCurentFigure-='0'; + }else + if ('a'<=bCurentFigure && bCurentFigure<='f') + { + bCurentFigure-=('a'+10); + }else + if ('A'<=bCurentFigure && bCurentFigure<='F') + { + bCurentFigure-=('A'+10); + }else{ + bCurentFigure=255; + } + + if (bCurentFigure!=255) + { + llNum*=16;// сдвигаем предыдущее число на один разряд чтоб добавить в младший разряд новую цифру + llNum+=bCurentFigure;// добавляем цифру в младший разряд + dwProcessed++;// увеличиваем счётчик обработанных цифр + } + lpcszString++;// перемещаем указатель на следующую позицию + dwStringLen--;// уменьшаем длинну + } + + if (dwProcessed) + {// как минимум одна цифра была обработана + if (pllNum) (*pllNum)=(llNum*llSingn); + if (dwProcessed==dwStringLen) + {// в строке были только цифры, всё отработало как нужно //Операция успешно завершена. + dwRetErrorCode=NO_ERROR; + }else{// в строке были не только цифры //Имеются дополнительные данные. + dwRetErrorCode=ERROR_MORE_DATA; + } + }else{// строка вообще не содержала цифр //Недопустимые данные. + dwRetErrorCode=ERROR_INVALID_DATA; + } +return(dwRetErrorCode); +} + + + + +#endif // !defined(AFX_STRHEXTONUM__H__INCLUDED_) \ No newline at end of file diff --git a/protocols/MRA/src/Sdk/StrToNum.h b/protocols/MRA/src/Sdk/StrToNum.h new file mode 100644 index 0000000000..6e67ac6be1 --- /dev/null +++ b/protocols/MRA/src/Sdk/StrToNum.h @@ -0,0 +1,447 @@ +/* + * Copyright (c) 2005 Rozhuk Ivan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + + + +#if !defined(AFX_STRTONUM__H__INCLUDED_) +#define AFX_STRTONUM__H__INCLUDED_ + + + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + + + + +__inline size_t StrToUNum(LPCSTR lpcszString,size_t dwStringLen) +{ + size_t dwNum=0; + BYTE bCurentFigure; + + + while(dwStringLen) + { + if ((bCurentFigure=((*lpcszString)-48))<10) + { + dwNum*=10;// сдвигаем предыдущее число на один разряд чтоб добавить в младший разряд новую цифру + dwNum+=bCurentFigure;// добавляем цифру в младший разряд + } + lpcszString++;// перемещаем указатель на следующую позицию + dwStringLen--;// уменьшаем длинну + } + +return(dwNum); +} + + +__inline DWORD StrToUNum32(LPCSTR lpcszString,size_t dwStringLen) +{ + DWORD dwNum=0; + BYTE bCurentFigure; + + + while(dwStringLen) + { + if ((bCurentFigure=((*lpcszString)-48))<10) + { + dwNum*=10;// сдвигаем предыдущее число на один разряд чтоб добавить в младший разряд новую цифру + dwNum+=bCurentFigure;// добавляем цифру в младший разряд + } + lpcszString++;// перемещаем указатель на следующую позицию + dwStringLen--;// уменьшаем длинну + } + +return(dwNum); +} + + +__inline DWORDLONG StrToUNum64(LPCSTR lpcszString,size_t dwStringLen) +{ + DWORDLONG dwlNum=0; + BYTE bCurentFigure; + + + while(dwStringLen) + { + if ((bCurentFigure=((*lpcszString)-48))<10) + { + dwlNum*=10;// сдвигаем предыдущее число на один разряд чтоб добавить в младший разряд новую цифру + dwlNum+=bCurentFigure;// добавляем цифру в младший разряд + } + lpcszString++;// перемещаем указатель на следующую позицию + dwStringLen--;// уменьшаем длинну + } + +return(dwlNum); +} + + + + +__inline DWORD StrToUNumEx(LPCSTR lpcszString,size_t dwStringLen,size_t *pdwNum) +{ + DWORD dwRetErrorCode; + size_t dwNum=0,dwProcessed=0; + BYTE bCurentFigure; + + + while(dwStringLen) + { + if ((bCurentFigure=((*lpcszString)-48))<10) + { + dwNum*=10;// сдвигаем предыдущее число на один разряд чтоб добавить в младший разряд новую цифру + dwNum+=bCurentFigure;// добавляем цифру в младший разряд + dwProcessed++;// увеличиваем счётчик обработанных цифр + } + lpcszString++;// перемещаем указатель на следующую позицию + dwStringLen--;// уменьшаем длинну + } + + if (dwProcessed) + {// как минимум одна цифра была обработана + if (pdwNum) (*pdwNum)=dwNum; + if (dwProcessed==dwStringLen) + {// в строке были только цифры, всё отработало как нужно //Операция успешно завершена. + dwRetErrorCode=NO_ERROR; + }else{// в строке были не только цифры //Имеются дополнительные данные. + dwRetErrorCode=ERROR_MORE_DATA; + } + }else{// строка вообще не содержала цифр //Недопустимые данные. + dwRetErrorCode=ERROR_INVALID_DATA; + } +return(dwRetErrorCode); +} + + +__inline DWORD StrToUNumEx32(LPCSTR lpcszString,size_t dwStringLen,DWORD *pdwNum) +{ + DWORD dwRetErrorCode; + DWORD dwNum=0,dwProcessed=0; + BYTE bCurentFigure; + + + while(dwStringLen) + { + if ((bCurentFigure=((*lpcszString)-48))<10) + { + dwNum*=10;// сдвигаем предыдущее число на один разряд чтоб добавить в младший разряд новую цифру + dwNum+=bCurentFigure;// добавляем цифру в младший разряд + dwProcessed++;// увеличиваем счётчик обработанных цифр + } + lpcszString++;// перемещаем указатель на следующую позицию + dwStringLen--;// уменьшаем длинну + } + + if (dwProcessed) + {// как минимум одна цифра была обработана + if (pdwNum) (*pdwNum)=dwNum; + if (dwProcessed==dwStringLen) + {// в строке были только цифры, всё отработало как нужно //Операция успешно завершена. + dwRetErrorCode=NO_ERROR; + }else{// в строке были не только цифры //Имеются дополнительные данные. + dwRetErrorCode=ERROR_MORE_DATA; + } + }else{// строка вообще не содержала цифр //Недопустимые данные. + dwRetErrorCode=ERROR_INVALID_DATA; + } +return(dwRetErrorCode); +} + + +__inline DWORD StrToUNumEx64(LPCSTR lpcszString,size_t dwStringLen,DWORDLONG *pdwlNum) +{ + DWORD dwRetErrorCode; + DWORDLONG dwlNum=0; + size_t dwProcessed=0; + BYTE bCurentFigure; + + + while(dwStringLen) + { + if ((bCurentFigure=((*lpcszString)-48))<10) + { + dwlNum*=10;// сдвигаем предыдущее число на один разряд чтоб добавить в младший разряд новую цифру + dwlNum+=bCurentFigure;// добавляем цифру в младший разряд + dwProcessed++;// увеличиваем счётчик обработанных цифр + } + lpcszString++;// перемещаем указатель на следующую позицию + dwStringLen--;// уменьшаем длинну + } + + if (dwProcessed) + {// как минимум одна цифра была обработана + if (pdwlNum) (*pdwlNum)=dwlNum; + if (dwProcessed==dwStringLen) + {// в строке были только цифры, всё отработало как нужно //Операция успешно завершена. + dwRetErrorCode=NO_ERROR; + }else{// в строке были не только цифры //Имеются дополнительные данные. + dwRetErrorCode=ERROR_MORE_DATA; + } + }else{// строка вообще не содержала цифр //Недопустимые данные. + dwRetErrorCode=ERROR_INVALID_DATA; + } +return(dwRetErrorCode); +} + + + + +__inline SSIZE_T StrToNum(LPCSTR lpcszString,size_t dwStringLen) +{ + SSIZE_T lNum=0,lSingn=1; + BYTE bCurentFigure; + + + while(dwStringLen && ((bCurentFigure=((*lpcszString)-48))>9)) + { + if (bCurentFigure=='-') lSingn=-1; + if (bCurentFigure=='+') lSingn=1; + + lpcszString++;// перемещаем указатель на следующую позицию + dwStringLen--;// уменьшаем длинну + } + + while(dwStringLen) + { + if ((bCurentFigure=((*lpcszString)-48))<10) + { + lNum*=10;// сдвигаем предыдущее число на один разряд чтоб добавить в младший разряд новую цифру + lNum+=bCurentFigure;// добавляем цифру в младший разряд + } + lpcszString++;// перемещаем указатель на следующую позицию + dwStringLen--;// уменьшаем длинну + } + lNum*=lSingn; + +return(lNum); +} + + +__inline LONG StrToNum32(LPCSTR lpcszString,size_t dwStringLen) +{ + LONG lNum=0,lSingn=1; + BYTE bCurentFigure; + + + while(dwStringLen && ((bCurentFigure=((*lpcszString)-48))>9)) + { + if (bCurentFigure=='-') lSingn=-1; + if (bCurentFigure=='+') lSingn=1; + + lpcszString++;// перемещаем указатель на следующую позицию + dwStringLen--;// уменьшаем длинну + } + + while(dwStringLen) + { + if ((bCurentFigure=((*lpcszString)-48))<10) + { + lNum*=10;// сдвигаем предыдущее число на один разряд чтоб добавить в младший разряд новую цифру + lNum+=bCurentFigure;// добавляем цифру в младший разряд + } + lpcszString++;// перемещаем указатель на следующую позицию + dwStringLen--;// уменьшаем длинну + } + lNum*=lSingn; + +return(lNum); +} + + +__inline LONGLONG StrToNum64(LPCSTR lpcszString,size_t dwStringLen) +{ + LONGLONG llNum=0,llSingn=1; + BYTE bCurentFigure; + + + while(dwStringLen && ((bCurentFigure=((*lpcszString)-48))>9)) + { + if (bCurentFigure=='-') llSingn=-1; + if (bCurentFigure=='+') llSingn=1; + + lpcszString++;// перемещаем указатель на следующую позицию + dwStringLen--;// уменьшаем длинну + } + + while(dwStringLen) + { + if ((bCurentFigure=((*lpcszString)-48))<10) + { + llNum*=10;// сдвигаем предыдущее число на один разряд чтоб добавить в младший разряд новую цифру + llNum+=bCurentFigure;// добавляем цифру в младший разряд + } + lpcszString++;// перемещаем указатель на следующую позицию + dwStringLen--;// уменьшаем длинну + } + llNum*=llSingn; + +return(llNum); +} + + + +__inline DWORD StrToNumEx(LPCSTR lpcszString,size_t dwStringLen,SSIZE_T *plNum) +{ + DWORD dwRetErrorCode; + size_t dwProcessed=0; + SSIZE_T lNum=0,lSingn=1; + BYTE bCurentFigure; + + + while(dwStringLen && ((bCurentFigure=((*lpcszString)-48))>9)) + { + if (bCurentFigure=='-') lSingn=-1; + if (bCurentFigure=='+') lSingn=1; + + lpcszString++;// перемещаем указатель на следующую позицию + dwStringLen--;// уменьшаем длинну + } + + while(dwStringLen) + { + if ((bCurentFigure=((*lpcszString)-48))<10) + { + lNum*=10;// сдвигаем предыдущее число на один разряд чтоб добавить в младший разряд новую цифру + lNum+=bCurentFigure;// добавляем цифру в младший разряд + dwProcessed++;// увеличиваем счётчик обработанных цифр + } + lpcszString++;// перемещаем указатель на следующую позицию + dwStringLen--;// уменьшаем длинну + } + + if (dwProcessed) + {// как минимум одна цифра была обработана + if (plNum) (*plNum)=(lNum*lSingn); + if (dwProcessed==dwStringLen) + {// в строке были только цифры, всё отработало как нужно //Операция успешно завершена. + dwRetErrorCode=NO_ERROR; + }else{// в строке были не только цифры //Имеются дополнительные данные. + dwRetErrorCode=ERROR_MORE_DATA; + } + }else{// строка вообще не содержала цифр //Недопустимые данные. + dwRetErrorCode=ERROR_INVALID_DATA; + } +return(dwRetErrorCode); +} + + +__inline DWORD StrToNumEx32(LPCSTR lpcszString,size_t dwStringLen,LONG *plNum) +{ + DWORD dwRetErrorCode; + size_t dwProcessed=0; + LONG lNum=0,lSingn=1; + BYTE bCurentFigure; + + + while(dwStringLen && ((bCurentFigure=((*lpcszString)-48))>9)) + { + if (bCurentFigure=='-') lSingn=-1; + if (bCurentFigure=='+') lSingn=1; + + lpcszString++;// перемещаем указатель на следующую позицию + dwStringLen--;// уменьшаем длинну + } + + while(dwStringLen) + { + if ((bCurentFigure=((*lpcszString)-48))<10) + { + lNum*=10;// сдвигаем предыдущее число на один разряд чтоб добавить в младший разряд новую цифру + lNum+=bCurentFigure;// добавляем цифру в младший разряд + dwProcessed++;// увеличиваем счётчик обработанных цифр + } + lpcszString++;// перемещаем указатель на следующую позицию + dwStringLen--;// уменьшаем длинну + } + + if (dwProcessed) + {// как минимум одна цифра была обработана + if (plNum) (*plNum)=(lNum*lSingn); + if (dwProcessed==dwStringLen) + {// в строке были только цифры, всё отработало как нужно //Операция успешно завершена. + dwRetErrorCode=NO_ERROR; + }else{// в строке были не только цифры //Имеются дополнительные данные. + dwRetErrorCode=ERROR_MORE_DATA; + } + }else{// строка вообще не содержала цифр //Недопустимые данные. + dwRetErrorCode=ERROR_INVALID_DATA; + } +return(dwRetErrorCode); +} + + +__inline DWORD StrToNumEx64(LPCSTR lpcszString,size_t dwStringLen,LONGLONG *pllNum) +{ + DWORD dwRetErrorCode; + size_t dwProcessed=0; + LONGLONG llNum=0,llSingn=1; + BYTE bCurentFigure; + + + while(dwStringLen && ((bCurentFigure=((*lpcszString)-48))>9)) + { + if (bCurentFigure=='-') llSingn=-1; + if (bCurentFigure=='+') llSingn=1; + + lpcszString++;// перемещаем указатель на следующую позицию + dwStringLen--;// уменьшаем длинну + } + + while(dwStringLen) + { + if ((bCurentFigure=((*lpcszString)-48))<10) + { + llNum*=10;// сдвигаем предыдущее число на один разряд чтоб добавить в младший разряд новую цифру + llNum+=bCurentFigure;// добавляем цифру в младший разряд + dwProcessed++;// увеличиваем счётчик обработанных цифр + } + lpcszString++;// перемещаем указатель на следующую позицию + dwStringLen--;// уменьшаем длинну + } + + if (dwProcessed) + {// как минимум одна цифра была обработана + if (pllNum) (*pllNum)=(llNum*llSingn); + if (dwProcessed==dwStringLen) + {// в строке были только цифры, всё отработало как нужно //Операция успешно завершена. + dwRetErrorCode=NO_ERROR; + }else{// в строке были не только цифры //Имеются дополнительные данные. + dwRetErrorCode=ERROR_MORE_DATA; + } + }else{// строка вообще не содержала цифр //Недопустимые данные. + dwRetErrorCode=ERROR_INVALID_DATA; + } +return(dwRetErrorCode); +} + + + + +#endif // !defined(AFX_STRTONUM__H__INCLUDED_) \ No newline at end of file diff --git a/protocols/MRA/src/Sdk/SystemHeaders.h b/protocols/MRA/src/Sdk/SystemHeaders.h new file mode 100644 index 0000000000..6779342812 --- /dev/null +++ b/protocols/MRA/src/Sdk/SystemHeaders.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2008 Rozhuk Ivan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + + + +#if !defined(AFX_SYSTEMHEADERS_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_) +#define AFX_SYSTEMHEADERS_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_ + + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + + + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define WINVER 0x0502 +#define _WIN32_WINNT 0x0502 +#include +#include +#include +#include +#include +#include +#include +#include +//#include + + +#pragma comment(lib,"Crypt32.lib") +#pragma comment(lib,"shlwapi.lib") +#pragma comment(lib,"ws2_32.lib") +#pragma comment(lib,"mswsock.lib") +// RunTmChk.lib Imagehlp.lib kernel32.lib Crypt32.lib shlwapi.lib ws2_32.lib mswsock.lib + + + + + +#endif // !defined(AFX_SYSTEMHEADERS_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_) diff --git a/protocols/MRA/src/Sdk/timefuncs.h b/protocols/MRA/src/Sdk/timefuncs.h new file mode 100644 index 0000000000..3b25b99787 --- /dev/null +++ b/protocols/MRA/src/Sdk/timefuncs.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2009 Rozhuk Ivan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + + + +#if !defined(AFX_TIME_FUNCS__H__INCLUDED_) +#define AFX_TIME_FUNCS__H__INCLUDED_ + + + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include +#include + + + +#define _MAX__TIME32_T 0x7fffd27f // number of seconds from + // 00:00:00, 01/01/1970 UTC to + // 23:59:59, 01/18/2038 UTC + +// Number of 100 nanosecond units from 1/1/1601 to 1/1/1970 +#define EPOCH_BIAS 116444736000000000i64 + +//nion to facilitate converting from FILETIME to unsigned __int64 +typedef union { + unsigned __int64 ft_scalar; + FILETIME ft_struct; + } FT; + + +static inline __time32_t __cdecl _time32(__time32_t *timeptr) +{ + __time64_t tim; + FT nt_time; + + GetSystemTimeAsFileTime(&(nt_time.ft_struct)); + tim=(__time64_t)((nt_time.ft_scalar-EPOCH_BIAS)/10000000i64); + if (tim > (__time64_t)(_MAX__TIME32_T)) tim=(__time64_t)(-1); + if (timeptr) *timeptr = (__time32_t)(tim);// store time if requested + +return(__time32_t)(tim); +} + + +inline __time32_t MakeTime32FromLocalSystemTime(CONST PSYSTEMTIME pcstSystemTime) +{ + __time64_t tim=0; + FT nt_time; + + if (SystemTimeToFileTime(pcstSystemTime,&(nt_time.ft_struct))) + { + if (LocalFileTimeToFileTime(&(nt_time.ft_struct),&(nt_time.ft_struct))) + { + tim=(__time64_t)((nt_time.ft_scalar-EPOCH_BIAS)/10000000i64); + if (tim > (__time64_t)(_MAX__TIME32_T)) tim=(__time64_t)(-1); + } + } +return(__time32_t)(tim); +} + + +inline BOOL MakeLocalSystemTimeFromTime32(__time32_t tim32,PSYSTEMTIME pstSystemTime) +{ + BOOL bRet=FALSE; + + if (pstSystemTime) + { + __time64_t tim=(__time64_t)tim32; + FT nt_time; + + //if (tim==(__time64_t)(-1)) tim=(__time64_t)(_MAX__TIME32_T); + nt_time.ft_scalar=(__time64_t)((tim*10000000i64)+EPOCH_BIAS); + if (FileTimeToLocalFileTime(&(nt_time.ft_struct),&(nt_time.ft_struct))) + { + bRet=FileTimeToSystemTime(&(nt_time.ft_struct),pstSystemTime); + } + } +return(bRet); +} + + + +static inline __time32_t __cdecl _mktime32(struct tm *ptmTime) +{ + SYSTEMTIME stTime; + + stTime.wMilliseconds=0; + stTime.wSecond=ptmTime->tm_sec; // seconds after the minute - [0,59] + stTime.wMinute=ptmTime->tm_min; // minutes after the hour - [0,59] + stTime.wHour=ptmTime->tm_hour; // hours since midnight - [0,23] + stTime.wDay=ptmTime->tm_mday; // day of the month - [1,31] + stTime.wMonth=(ptmTime->tm_mon+1); // months since January - [0,11] + stTime.wYear=(ptmTime->tm_year+1900); // years since 1900 + stTime.wDayOfWeek=0;//ptmTime->tm_wday; // days since Sunday - [0,6] + //ptmTime->tm_yday; // days since January 1 - [0,365] + //ptmTime->tm_isdst; // daylight savings time flag +return(MakeTime32FromLocalSystemTime(&stTime)); +} + + + + + +#endif // !defined(AFX_TIME_FUNCS__H__INCLUDED_) diff --git a/protocols/MRA/src/Sdk/zconf.h b/protocols/MRA/src/Sdk/zconf.h new file mode 100644 index 0000000000..02ce56c431 --- /dev/null +++ b/protocols/MRA/src/Sdk/zconf.h @@ -0,0 +1,428 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2010 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + * Even better than compiling with -DZ_PREFIX would be to use configure to set + * this permanently in zconf.h using "./configure --zprefix". + */ +#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ + +/* all linked symbols */ +# define _dist_code z__dist_code +# define _length_code z__length_code +# define _tr_align z__tr_align +# define _tr_flush_block z__tr_flush_block +# define _tr_init z__tr_init +# define _tr_stored_block z__tr_stored_block +# define _tr_tally z__tr_tally +# define adler32 z_adler32 +# define adler32_combine z_adler32_combine +# define adler32_combine64 z_adler32_combine64 +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define crc32 z_crc32 +# define crc32_combine z_crc32_combine +# define crc32_combine64 z_crc32_combine64 +# define deflate z_deflate +# define deflateBound z_deflateBound +# define deflateCopy z_deflateCopy +# define deflateEnd z_deflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateInit_ z_deflateInit_ +# define deflateParams z_deflateParams +# define deflatePrime z_deflatePrime +# define deflateReset z_deflateReset +# define deflateSetDictionary z_deflateSetDictionary +# define deflateSetHeader z_deflateSetHeader +# define deflateTune z_deflateTune +# define deflate_copyright z_deflate_copyright +# define get_crc_table z_get_crc_table +# define gz_error z_gz_error +# define gz_intmax z_gz_intmax +# define gz_strwinerror z_gz_strwinerror +# define gzbuffer z_gzbuffer +# define gzclearerr z_gzclearerr +# define gzclose z_gzclose +# define gzclose_r z_gzclose_r +# define gzclose_w z_gzclose_w +# define gzdirect z_gzdirect +# define gzdopen z_gzdopen +# define gzeof z_gzeof +# define gzerror z_gzerror +# define gzflush z_gzflush +# define gzgetc z_gzgetc +# define gzgets z_gzgets +# define gzoffset z_gzoffset +# define gzoffset64 z_gzoffset64 +# define gzopen z_gzopen +# define gzopen64 z_gzopen64 +# define gzprintf z_gzprintf +# define gzputc z_gzputc +# define gzputs z_gzputs +# define gzread z_gzread +# define gzrewind z_gzrewind +# define gzseek z_gzseek +# define gzseek64 z_gzseek64 +# define gzsetparams z_gzsetparams +# define gztell z_gztell +# define gztell64 z_gztell64 +# define gzungetc z_gzungetc +# define gzwrite z_gzwrite +# define inflate z_inflate +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define inflateBackInit_ z_inflateBackInit_ +# define inflateCopy z_inflateCopy +# define inflateEnd z_inflateEnd +# define inflateGetHeader z_inflateGetHeader +# define inflateInit2_ z_inflateInit2_ +# define inflateInit_ z_inflateInit_ +# define inflateMark z_inflateMark +# define inflatePrime z_inflatePrime +# define inflateReset z_inflateReset +# define inflateReset2 z_inflateReset2 +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateUndermine z_inflateUndermine +# define inflate_copyright z_inflate_copyright +# define inflate_fast z_inflate_fast +# define inflate_table z_inflate_table +# define uncompress z_uncompress +# define zError z_zError +# define zcalloc z_zcalloc +# define zcfree z_zcfree +# define zlibCompileFlags z_zlibCompileFlags +# define zlibVersion z_zlibVersion + +/* all zlib typedefs in zlib.h and zconf.h */ +# define Byte z_Byte +# define Bytef z_Bytef +# define alloc_func z_alloc_func +# define charf z_charf +# define free_func z_free_func +# define gzFile z_gzFile +# define gz_header z_gz_header +# define gz_headerp z_gz_headerp +# define in_func z_in_func +# define intf z_intf +# define out_func z_out_func +# define uInt z_uInt +# define uIntf z_uIntf +# define uLong z_uLong +# define uLongf z_uLongf +# define voidp z_voidp +# define voidpc z_voidpc +# define voidpf z_voidpf + +/* all zlib structs in zlib.h and zconf.h */ +# define gz_header_s z_gz_header_s +# define internal_state z_internal_state + +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_UNISTD_H +#endif + +#ifdef STDC +# include /* for off_t */ +#endif + +/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and + * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even + * though the former does not conform to the LFS document), but considering + * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as + * equivalently requesting no 64-bit operations + */ +#if -_LARGEFILE64_SOURCE - -1 == 1 +# undef _LARGEFILE64_SOURCE +#endif + +#if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# ifndef z_off_t +# define z_off_t off_t +# endif +#endif + +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 +# define z_off64_t off64_t +#else +# define z_off64_t z_off_t +#endif + +#if defined(__OS400__) +# define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) + #pragma map(deflateInit_,"DEIN") + #pragma map(deflateInit2_,"DEIN2") + #pragma map(deflateEnd,"DEEND") + #pragma map(deflateBound,"DEBND") + #pragma map(inflateInit_,"ININ") + #pragma map(inflateInit2_,"ININ2") + #pragma map(inflateEnd,"INEND") + #pragma map(inflateSync,"INSY") + #pragma map(inflateSetDictionary,"INSEDI") + #pragma map(compressBound,"CMBND") + #pragma map(inflate_table,"INTABL") + #pragma map(inflate_fast,"INFA") + #pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/protocols/MRA/src/Sdk/zlib.h b/protocols/MRA/src/Sdk/zlib.h new file mode 100644 index 0000000000..62d0e4675b --- /dev/null +++ b/protocols/MRA/src/Sdk/zlib.h @@ -0,0 +1,1357 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.3, July 18th, 2005 + + Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.3" +#define ZLIB_VERNUM 0x1230 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip streams in memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumualte before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + the value returned by deflateBound (see below). If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, + Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() stop + if and when it gets to the next deflate block boundary. When decoding the + zlib or gzip format, this will cause inflate() to return immediately after + the header and before the first block. When doing a raw inflate, inflate() + will go ahead and process the first block, and will return when it gets to + the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 + if inflate() is currently decoding the last block in the deflate stream, + plus 128 if inflate() returned immediately after decoding an end-of-block + code or decoding the complete header up to just before the first byte of the + deflate stream. The end-of-block will not be indicated until all of the + uncompressed data from that block has been written to strm->next_out. The + number of unused bits may in general be greater than seven, except when + bit 7 of data_type is set, in which case the number of unused bits will be + less than eight. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster approach + may be used for the single inflate() call. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the only effect of the flush parameter in this implementation + is on the return value of inflate(), as noted below, or when it returns early + because Z_BLOCK is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the adler32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the adler32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() will decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically. Any information + contained in the gzip header is not retained, so applications that need that + information should instead use raw inflate, see inflateInit2() below, or + inflateBack() and perform their own processing of the gzip header and + trailer. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may then + call inflateSync() to look for a good compression block if a partial recovery + of the data is desired. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), + no header crc, and the operating system will be set to 255 (unknown). If a + gzip stream is being written, strm->adler is a crc32 instead of an adler32. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as + Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy + parameter only affects the compression ratio but not the correctness of the + compressed output even if it is not set appropriately. Z_FIXED prevents the + use of dynamic Huffman codes, allowing for a simpler decoder for special + applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. In addition, the + current implementation of deflate will use at most the window size minus + 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() + or deflateInit2(). This would be used to allocate an output buffer + for deflation in a single pass, and so would be called before deflate(). +*/ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the + bits leftover from a previous deflate stream when appending to it. As such, + this function can only be used for raw deflate, and must be used before the + first deflate() call after a deflateInit2() or deflateReset(). bits must be + less than or equal to 16, and that many of the least significant bits of + value will be inserted in the output. + + deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is + a crc32 instead of an adler32. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg + is set to null if there is no error message. inflateInit2 does not perform + any decompression apart from reading the zlib header if present: this will + be done by inflate(). (So next_in and avail_in may be modified, but next_out + and avail_out are unchanged.) +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called + immediately after inflateInit2() or inflateReset() and before any call of + inflate() to set the dictionary. The application must insure that the + dictionary that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK can be used to + force inflate() to return immediately after header processing is complete + and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When + any of extra, name, or comment are not Z_NULL and the respective field is + not present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the paramaters are invalid, Z_MEM_ERROR if the internal state could not + be allocated, or Z_VERSION_ERROR if the version of the library does not + match the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is more efficient than inflate() for + file i/o applications in that it avoids copying between the output and the + sliding window by simply making the window itself the output buffer. This + function trusts the application to not change the output buffer passed by + the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free + the allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects + only the raw deflate stream to decompress. This is different from the + normal behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format + error in the deflate stream (in which case strm->msg is set to indicate the + nature of the error), or Z_STREAM_ERROR if the stream was not properly + initialized. In the case of Z_BUF_ERROR, an input or output error can be + distinguished using strm->next_in which will be Z_NULL only if in() returned + an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to + out() returning non-zero. (in() will always be called before out(), so + strm->next_in is assured to be defined if out() returns non-zero.) Note + that inflateBack() cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least the value returned + by compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before + a compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. +*/ + + +typedef voidp gzFile; + +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h", or 'R' for run-length encoding + as in "wb1R". (See the description of deflateInit2 for more information + about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). The number of + uncompressed bytes written is limited to 4095. The caller should assure that + this limit is not exceeded. If it is exceeded, then gzprintf() will return + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf() + because the secure snprintf() or vsnprintf() functions were not available. +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read again later. + Only one character of push-back is allowed. gzungetc() returns the + character pushed, or -1 on failure. gzungetc() will fail if a + character has been pushed but not read yet, or if c is -1. The pushed + character will be discarded if the stream is repositioned with gzseek() + or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns 1 if file is being read directly without decompression, otherwise + zero. +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); +/* + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. If buf is NULL, this function returns the required initial + value for the for the crc. Pre- and post-conditioning (one's complement) is + performed within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + +/* + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + + +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; /* hack for buggy compilers */ +#endif + +ZEXTERN const char * ZEXPORT zError OF((int)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/protocols/MRA/src/proto.h b/protocols/MRA/src/proto.h new file mode 100644 index 0000000000..bf0c28e03a --- /dev/null +++ b/protocols/MRA/src/proto.h @@ -0,0 +1,611 @@ +//*************************************************************************** +// $Id: proto.h, v 1.141 2005/10/24 15:32:33 shingrus Exp $ +//*************************************************************************** + +#ifndef MRIM_PROTO_H +#define MRIM_PROTO_H + +#include + +#include "version.h" + +typedef struct mrim_packet_header_t +{ + u_long magic; // Magic + u_long proto; // Версия протокола + u_long seq; // Sequence + u_long msg; // Тип пакета + u_long dlen; // Длина данных + u_char reserved[24]; // Зарезервировано +} +mrim_packet_header_t; + +#define CS_MAGIC 0xDEADBEEF // Клиентский Magic ( C <-> S ) + + +// UNICODE = (UTF-16LE) ( >= 1.17) + +/*************************************************************************** + + ПРОТОКОЛ СВЯЗИ КЛИЕНТ-СЕРВЕР + + ***************************************************************************/ + +#define MRIM_CS_HELLO 0x1001 // C -> S +// empty + +#define MRIM_CS_HELLO_ACK 0x1002 // S -> C +// mrim_connection_params_t + + +#define MRIM_CS_LOGIN_ACK 0x1004 // S -> C +// empty + +#define MRIM_CS_LOGIN_REJ 0x1005 // S -> C +// LPS reason ??? + +#define MRIM_CS_PING 0x1006 // C -> S +// empty + +#define MRIM_CS_MESSAGE 0x1008 // C -> S +// UL flags + #define MESSAGE_FLAG_OFFLINE 0x00000001 + #define MESSAGE_FLAG_NORECV 0x00000004 + #define MESSAGE_FLAG_AUTHORIZE 0x00000008 // X-MRIM-Flags: 00000008 + #define MESSAGE_FLAG_SYSTEM 0x00000040 + #define MESSAGE_FLAG_RTF 0x00000080 + #define MESSAGE_FLAG_CONTACT 0x00000200 + #define MESSAGE_FLAG_NOTIFY 0x00000400 + #define MESSAGE_FLAG_SMS 0x00000800 + #define MESSAGE_FLAG_MULTICAST 0x00001000 + #define MESSAGE_SMS_DELIVERY_REPORT 0x00002000 + #define MESSAGE_FLAG_ALARM 0x00004000 + #define MESSAGE_FLAG_FLASH 0x00008000 + #define MESSAGE_FLAG_SPAMF_SPAM 0x00020000 // чтобы пожаловатся на спам - вернуть назад с этим флагом ;клиенту игнорировать, ставится в момент обработки сообщения при передаче внутри кластера + #define MESSAGE_FLAG_MULTICHAT 0x00400000 // + #define MULTICHAT_MESSAGE 0 // received message (s->c) + #define MULTICHAT_GET_MEMBERS 1 // request members list from server (c->s) + #define MULTICHAT_MEMBERS 2 // members list from server (s->c) + #define MULTICHAT_ADD_MEMBERS 3 // + #define MULTICHAT_ATTACHED 4 // user joined to chat (s->c) + #define MULTICHAT_DETACHED 5 // user leave chat (s->c) + #define MULTICHAT_DESTROYED 6 // + #define MULTICHAT_INVITE 7 // + #define MESSAGE_FLAG_v1p16 0x00100000 // для перекодировки юникода + #define MESSAGE_FLAG_CP1251 0x00200000 +// LPS to e-mail ANSI +// LPS message ANSI/UNICODE (see flags) +// LPS rtf-formatted message ( >= 1.1) ??? +// LPS multichat_data ( >= 1.20) ??? + +#define MAX_MULTICAST_RECIPIENTS 50 + #define MESSAGE_USERFLAGS_MASK 0x000036A8 // Flags that user is allowed to set himself + + +#define MRIM_CS_MESSAGE_ACK 0x1009 // S -> C +// UL msg_id +// UL flags +// LPS from e-mail ANSI +// LPS message UNICODE +// LPS rtf-formatted message ( >= 1.1) - MESSAGE_FLAG_RTF +// //BASE64( - MESSAGE_FLAG_AUTHORIZE +// UL parts count = 2 +// LPS auth_sender_nick UNICODE +// LPS auth_request_text UNICODE +//[ LPS multichat_data ] ( >= 1.20) - MESSAGE_FLAG_MULTICHAT +// UL type +// LPS multichat_name +// switch (type) { +// MULTICHAT_MESSAGE { +// LPS sender ANSI +// } +// MULTICHAT_MEMBERS { +// CLPS members +// [ LPS owner ] +// } +// MULTICHAT_ADD_MEMBERS { +// LPS sender ANSI +// CLPS members +// } +// MULTICHAT_ATTACHED { +// LPS member ANSI +// } +// MULTICHAT_DETACHED { +// LPS member ANSI +// } +// MULTICHAT_INVITE { +// LPS sender ANSI +// } +// } +// ) + + + + + +#define MRIM_CS_MESSAGE_RECV 0x1011 // C -> S +// LPS from e-mail ANSI +// UL msg_id + +#define MRIM_CS_MESSAGE_STATUS 0x1012 // S -> C +// UL status + #define MESSAGE_DELIVERED 0x0000 // Message delivered directly to user + #define MESSAGE_REJECTED_NOUSER 0x8001 // Message rejected - no such user + #define MESSAGE_REJECTED_INTERR 0x8003 // Internal server error + #define MESSAGE_REJECTED_LIMIT_EXCEEDED 0x8004 // Offline messages limit exceeded + #define MESSAGE_REJECTED_TOO_LARGE 0x8005 // Message is too large + #define MESSAGE_REJECTED_DENY_OFFMSG 0x8006 // User does not accept offline messages + #define MESSAGE_REJECTED_DENY_OFFFLSH 0x8007 // User does not accept offline flash animation + //#define MESSAGE_REJECTED_DENY_OFFFLSH 0x8008 // User does not accept offline flash animation + //#define MESSAGE_REJECTED_DENY_OFFFLSH 0x8009 // User does not accept offline flash animation + +#define MRIM_CS_USER_STATUS 0x100F // S -> C +// UL status + #define STATUS_OFFLINE 0x00000000 + #define STATUS_ONLINE 0x00000001 + #define STATUS_AWAY 0x00000002 + #define STATUS_UNDETERMINATED 0x00000003 + #define STATUS_USER_DEFINED 0x00000004 + #define STATUS_FLAG_INVISIBLE 0x80000000 +// LPS spec_status_uri ANSI ( >= 1.14) + #define SPEC_STATUS_URI_MAX 256 +// LPS status_title UNICODE ( >= 1.14) + #define STATUS_TITLE_MAX 16 +// LPS status_desc UNICODE ( >= 1.14) + #define STATUS_DESC_MAX 64 +// LPS user e-mail ANSI +// UL com_support ( >= 1.14) + #define FEATURE_FLAG_RTF_MESSAGE 0x00000001 + #define FEATURE_FLAG_BASE_SMILES 0x00000002 + #define FEATURE_FLAG_ADVANCED_SMILES 0x00000004 + #define FEATURE_FLAG_CONTACTS_EXCH 0x00000008 + #define FEATURE_FLAG_WAKEUP 0x00000010 + #define FEATURE_FLAG_MULTS 0x00000020 + #define FEATURE_FLAG_FILE_TRANSFER 0x00000040 + #define FEATURE_FLAG_VOICE 0x00000080 + #define FEATURE_FLAG_VIDEO 0x00000100 + #define FEATURE_FLAG_GAMES 0x00000200 + #define FEATURE_FLAG_LAST 0x00000200 + #define FEATURE_UA_FLAG_MASK ((FEATURE_FLAG_LAST << 1) - 1) +// LPS user_agent ( >= 1.14) ANSI + #define USER_AGENT_MAX 255 + // Format: + // user_agent = param *(param ) + // param = pname "=" pvalue + // pname = token + // pvalue = token / quoted-string + // + // Params: + // "client" - magent/jagent/??? + // "name" - sys-name. + // "title" - display-name. + // "version" - product internal numeration. Examples: "1.2", "1.3 pre". + // "build" - product internal numeration (may be positive number or time). + // "protocol" - MMP protocol number by format ".". + + +#define MRIM_CS_LOGOUT 0x1013 // S -> C +// UL reason + #define LOGOUT_NO_RELOGIN_FLAG 0x0010 // Logout due to double login + +#define MRIM_CS_CONNECTION_PARAMS 0x1014 // S -> C (>1.16 depricated ?) +// mrim_connection_params_t + +#define MRIM_CS_USER_INFO 0x1015 // S -> C +// (LPS key, LPS value)* X ??? +// MESSAGES.TOTAL - num UNICODE +// MESSAGES.UNREAD - num UNICODE +// MRIM.NICKNAME - nick UNICODE +// client.endpoint - ip:port UNICODE + + +#define MRIM_CS_ADD_CONTACT 0x1019 // C -> S +// UL flags (group(2) or usual(0) + #define CONTACT_FLAG_REMOVED 0x00000001 + #define CONTACT_FLAG_GROUP 0x00000002 + #define CONTACT_FLAG_INVISIBLE 0x00000004 + #define CONTACT_FLAG_VISIBLE 0x00000008 + #define CONTACT_FLAG_IGNORE 0x00000010 + #define CONTACT_FLAG_SHADOW 0x00000020 + #define CONTACT_FLAG_AUTHORIZED 0x00000040 // ( >= 1.15) + #define CONTACT_FLAG_MULTICHAT 0x00000080 // ( >= 1.20) = 128 + #define CONTACT_FLAG_UNICODE_NAME 0x00000200 // = 512 + #define CONTACT_FLAG_PHONE 0x00100000 + +// UL group id (unused if contact is group) +// LPS contact e-mail ANSI +// LPS name UNICODE +// LPS custom phones ANSI +// LPS BASE64( +// UL parts count = 2 +// LPS auth_sender_nick ??? +// LPS auth_request_text ??? +// ) +// UL actions ( >= 1.15) +// [LPS multichat_data] +// CLPS members ( >= 1.20) +// [ LPS owner ] + #define ADD_CONTACT_FLAG_MYMAIL_INVITE 0x00000001 + #define ADD_CONTACT_FLAG_MULTICHAT_ATTACHE 0x00000002 + //used internal in win32 agent + #define CONTACT_AWAITING_AUTHORIZATION_USER 0x00000100 + #define CONTACT_FLAG_TEMPORARY 0x00010000 + + +#define MRIM_CS_ADD_CONTACT_ACK 0x101A // S -> C +// UL status + #define CONTACT_OPER_SUCCESS 0x0000 + #define CONTACT_OPER_ERROR 0x0001 + #define CONTACT_OPER_INTERR 0x0002 + #define CONTACT_OPER_NO_SUCH_USER 0x0003 + #define CONTACT_OPER_INVALID_INFO 0x0004 + #define CONTACT_OPER_USER_EXISTS 0x0005 + #define CONTACT_OPER_GROUP_LIMIT 0x6 +// UL contact_id or (u_long)-1 if status is not OK +// [LPS multichat_contact ( >= 1.20)] + + +#define MRIM_CS_MODIFY_CONTACT 0x101B // C -> S +// UL id +// UL flags - same as for MRIM_CS_ADD_CONTACT +// UL group id (unused if contact is group) +// LPS contact e-mail ANSI +// LPS name UNICODE +// LPS custom phones ANSI + +#define MRIM_CS_MODIFY_CONTACT_ACK 0x101C // S -> C +// UL status, same as for MRIM_CS_ADD_CONTACT_ACK + +#define MRIM_CS_OFFLINE_MESSAGE_ACK 0x101D // S -> C +// UIDL +// LPS offline message ??? + +#define MRIM_CS_DELETE_OFFLINE_MESSAGE 0x101E // C -> S +// UIDL + + +#define MRIM_CS_AUTHORIZE 0x1020 // C -> S +// LPS user e-mail ANSI + +#define MRIM_CS_AUTHORIZE_ACK 0x1021 // S -> C +// LPS user e-mail ANSI + +#define MRIM_CS_CHANGE_STATUS 0x1022 // C -> S +// UL new status +// LPS spec_status_uri ANSI ( >= 1.14) +// LPS status_title UNICODE ( >= 1.14) +// LPS status_desc UNICODE ( >= 1.14) +// UL com_support ( >= 1.14) (see MRIM_CS_USER_STATUS) + + +#define MRIM_CS_GET_MPOP_SESSION 0x1024 // C -> S + + +#define MRIM_CS_MPOP_SESSION 0x1025 // S -> C +// UL status + #define MRIM_GET_SESSION_FAIL 0 + #define MRIM_GET_SESSION_SUCCESS 1 +// LPS mpop session ??? + + +#define MRIM_CS_FILE_TRANSFER 0x1026 // C->S +// LPS TO/FROM e-mail ANSI +// DWORD id_request - uniq per connect +// DWORD FILESIZE +// LPS: // LPS Files (FileName;FileSize;FileName;FileSize;) ANSI + // LPS DESCRIPTION: + // UL ? + // Files (FileName;FileSize;FileName;FileSize;) UNICODE + // LPS Conn (IP:Port;IP:Port;) ANSI + +#define MRIM_CS_FILE_TRANSFER_ACK 0x1027 // S->C +// DWORD status + #define FILE_TRANSFER_STATUS_OK 1 + #define FILE_TRANSFER_STATUS_DECLINE 0 + #define FILE_TRANSFER_STATUS_ERROR 2 + #define FILE_TRANSFER_STATUS_INCOMPATIBLE_VERS 3 + #define FILE_TRANSFER_MIRROR 4 +// LPS TO/FROM e-mail ANSI +// DWORD id_request +// LPS DESCRIPTION [Conn (IP:Port;IP:Port;) ANSI] + + + +//white pages! +#define MRIM_CS_WP_REQUEST 0x1029 //C->S +// DWORD field +// LPS value ??? +#define PARAMS_NUMBER_LIMIT 50 +#define PARAM_VALUE_LENGTH_LIMIT 64 + +//if last symbol in value eq '*' it will be replaced by LIKE '%' +// params define +// must be in consecutive order (0..N) to quick check in check_anketa_info_request + enum { + MRIM_CS_WP_REQUEST_PARAM_USER = 0, // ANSI + MRIM_CS_WP_REQUEST_PARAM_DOMAIN, // ANSI + MRIM_CS_WP_REQUEST_PARAM_NICKNAME, // UNICODE + MRIM_CS_WP_REQUEST_PARAM_FIRSTNAME, // UNICODE + MRIM_CS_WP_REQUEST_PARAM_LASTNAME, // UNICODE + MRIM_CS_WP_REQUEST_PARAM_SEX , // ANSI + MRIM_CS_WP_REQUEST_PARAM_BIRTHDAY, // not used for search + MRIM_CS_WP_REQUEST_PARAM_DATE1 , // ANSI + MRIM_CS_WP_REQUEST_PARAM_DATE2 , // ANSI + //!!!!!!!!!!!!!!!!!!!online request param must be at end of request!!!!!!!!!!!!!!! + MRIM_CS_WP_REQUEST_PARAM_ONLINE , // ANSI + MRIM_CS_WP_REQUEST_PARAM_STATUS , // we do not used it, yet + MRIM_CS_WP_REQUEST_PARAM_CITY_ID, // ANSI + MRIM_CS_WP_REQUEST_PARAM_ZODIAC, // ANSI + MRIM_CS_WP_REQUEST_PARAM_BIRTHDAY_MONTH, // ANSI + MRIM_CS_WP_REQUEST_PARAM_BIRTHDAY_DAY, // ANSI + MRIM_CS_WP_REQUEST_PARAM_COUNTRY_ID, // ANSI + MRIM_CS_WP_REQUEST_PARAM_MAX + }; + +#define MRIM_CS_ANKETA_INFO 0x1028 //S->C +// DWORD status + #define MRIM_ANKETA_INFO_STATUS_OK 1 + #define MRIM_ANKETA_INFO_STATUS_NOUSER 0 + #define MRIM_ANKETA_INFO_STATUS_DBERR 2 + #define MRIM_ANKETA_INFO_STATUS_RATELIMERR 3 +// DWORD fields_num +// DWORD max_rows +// DWORD server_time sec since 1970 (unixtime) + // fields set //%fields_num == 0 + // values set //%fields_num == 0 +// LPS value (numbers too) ??? + + +#define MRIM_CS_MAILBOX_STATUS 0x1033 +// DWORD new messages in mailbox + + +#define MRIM_CS_GAME 0x1035 +// LPS to/from e-mail ANSI +// DWORD session unique per game +// DWORD msg internal game message + enum { + GAME_BASE, + GAME_CONNECTION_INVITE, + GAME_CONNECTION_ACCEPT, + GAME_DECLINE, + GAME_INC_VERSION, + GAME_NO_SUCH_GAME, + GAME_JOIN, + GAME_CLOSE, + GAME_SPEED, + GAME_SYNCHRONIZATION, + GAME_USER_NOT_FOUND, + GAME_ACCEPT_ACK, + GAME_PING, + GAME_RESULT, + GAME_MESSAGES_NUMBER + }; +// DWORD msg_id id for ack +// DWORD time_send time of client +// LPS data ??? + + + +#define MRIM_CS_CONTACT_LIST2 0x1037 //S->C +// UL status + #define GET_CONTACTS_OK 0x0000 + #define GET_CONTACTS_ERROR 0x0001 + #define GET_CONTACTS_INTERR 0x0002 +// DWORD status - if ...OK than this staff: +// DWORD groups number + // mask symbols table: + // 's' - lps + // 'u' - unsigned long + // 'z' - zero terminated string + // LPS groups fields mask ANSI + // LPS contacts fields mask ANSI + // group fields + // contacts fields + // groups mask 'us' == flags, name UNICODE + // contact mask 'uussuussssus' flags, group id, e-mail ANSI, nick UNICODE, server flags, status, custom phone numbers ANSI, spec_status_uri ANSI, status_title UNICODE, status_desc UNICODE, com_support (future flags), user_agent (formated string) ANSI, ul blog status id, ul blog status id, ul BlogStatusTime, blog status UNICODE, blog status music UNICODE, blog status sender, ????? + // uussuussssusuuusssss + #define CONTACT_INTFLAG_NOT_AUTHORIZED 0x0001 + + +//old packet cs_login with cs_statistic +#define MRIM_CS_LOGIN2 0x1038 // C -> S +// LPS login e-mail ANSI +// LPS password ANSI +// DWORD status +// LPS spec_status_uri ANSI ( >= 1.14) +// LPS status_title UNICODE ( >= 1.14) +// LPS status_desc UNICODE ( >= 1.14) +// UL com_support ( >= 1.14) (see MRIM_CS_USER_STATUS) +// LPS user_agent ANSI ( >= 1.14) (see MRIM_CS_USER_STATUS) + // + statistic packet data: +// LPS lang ( >= 1.16) +// LPS ua session ( >= 1.20) - шли пустой +// LPS replaced ua session ( >= 1.20) - шли пустой +// LPS client description ANSI + #define MAX_CLIENT_DESCRIPTION 256 +// unknown data +// LPS unknown id (len = 32) +/* SetUL(&lpbDataCurrent, 0);//00 00 00 00 + SetUL(&lpbDataCurrent, 0);//02 BA 0A 00 + SetUL(&lpbDataCurrent, 0);//00 00 00 03 + SetUL(&lpbDataCurrent, 0);//00 00 00 02 + + SetUL(&lpbDataCurrent, 0);//E2 FD 1E 22 + SetUL(&lpbDataCurrent, 0);//04 00 00 00 + SetUL(&lpbDataCurrent, 0);//02 FF FF FF + SetUL(&lpbDataCurrent, 0);//FF 05 00 00 + + SetUL(&lpbDataCurrent, 0);//00 02 FF FF + SetUL(&lpbDataCurrent, 0);//FF FF 06 00 + SetUL(&lpbDataCurrent, 0);//00 00 02 FF + SetUL(&lpbDataCurrent, 0);//FF FF FF 07 + + SetUL(&lpbDataCurrent, 0);//00 00 00 02 + SetUL(&lpbDataCurrent, 0);//FF FF FF FF + SetUL(&lpbDataCurrent, 0);//14 00 00 00 + SetUL(&lpbDataCurrent, 0);//02 00 00 00 + + SetUL(&lpbDataCurrent, 0);//00 16 00 00 + SetUL(&lpbDataCurrent, 0);//00 02 00 00 + SetUL(&lpbDataCurrent, 0);//00 00 17 00 + SetUL(&lpbDataCurrent, 0);//00 00 02 00 + + SetUL(&lpbDataCurrent, 0);//00 00 00 18 + SetUL(&lpbDataCurrent, 0);//00 00 00 02 + SetUL(&lpbDataCurrent, 0);//00 00 00 00 + SetUL(&lpbDataCurrent, 0);//19 00 00 00 + + SetUL(&lpbDataCurrent, 0);//02 00 00 00 + SetUL(&lpbDataCurrent, 0);//00 1A 00 00 + SetUL(&lpbDataCurrent, 0);//00 02 00 00 + SetUL(&lpbDataCurrent, 0);//00 00 1C 00 + + SetUL(&lpbDataCurrent, 0);//00 00 02 00 + SetUL(&lpbDataCurrent, 0);//00 00 00 1D + SetUL(&lpbDataCurrent, 0);//00 00 00 02 + SetUL(&lpbDataCurrent, 0);//00 00 00 00 + + SetUL(&lpbDataCurrent, 0);//23 00 00 00 + SetUL(&lpbDataCurrent, 0);//02 01 00 00 + SetUL(&lpbDataCurrent, 0);//00 24 00 00 + SetUL(&lpbDataCurrent, 0);//00 02 01 00 + + SetUL(&lpbDataCurrent, 0);//00 00 25 00 + SetUL(&lpbDataCurrent, 0);//00 00 02 01 + SetUL(&lpbDataCurrent, 0);//00 00 00 26 + SetUL(&lpbDataCurrent, 0);//00 00 00 02 + + SetUL(&lpbDataCurrent, 0);//00 00 00 00 + SetUL(&lpbDataCurrent, 0);//27 00 00 00 + SetUL(&lpbDataCurrent, 0);//02 00 00 00 + SetUL(&lpbDataCurrent, 0);//00 28 00 00 + + SetUL(&lpbDataCurrent, 0);//00 02 00 00 + SetUL(&lpbDataCurrent, 0);//00 00 29 00 + SetUL(&lpbDataCurrent, 0);//00 00 02 01 + SetUL(&lpbDataCurrent, 0);//00 00 00 2A + + SetUL(&lpbDataCurrent, 0);//00 00 00 02 + SetUL(&lpbDataCurrent, 0);//00 00 00 00 + SetUL(&lpbDataCurrent, 0);//2B 00 00 00 + SetUL(&lpbDataCurrent, 0);//02 00 00 00 + + SetUL(&lpbDataCurrent, 0);//00 2C 00 00 + SetUL(&lpbDataCurrent, 0);//00 01 + + SetLPS(&lpbDataCurrent, "d3a4a3d0c95e5ba24f160a499ec8b4ea", 32); +*/ + + +#define MRIM_CS_SMS 0x1039 // C -> S +// UL flags +// LPS to Phone ??? +// LPS message ??? + +#define MRIM_CS_SMS_ACK 0x1040 // S->C +// UL status + + + +#define MRIM_CS_PROXY 0x1044 +// LPS to e-mail ANSI +// DWORD id_request +// DWORD data_type + #define MRIM_PROXY_TYPE_VOICE 1 + #define MRIM_PROXY_TYPE_FILES 2 + #define MRIM_PROXY_TYPE_CALLOUT 3 +// LPS user_data ??? +// LPS lps_ip_port ??? +// DWORD session_id[4] + +#define MRIM_CS_PROXY_ACK 0x1045 +//DWORD status + #define PROXY_STATUS_OK 1 + #define PROXY_STATUS_DECLINE 0 + #define PROXY_STATUS_ERROR 2 + #define PROXY_STATUS_INCOMPATIBLE_VERS 3 + #define PROXY_STATUS_NOHARDWARE 4 + #define PROXY_STATUS_MIRROR 5 + #define PROXY_STATUS_CLOSED 6 +// LPS to e-mail ANSI +// DWORD id_request +// DWORD data_type +// LPS user_data ??? +// LPS: lps_ip_port ??? +// DWORD[4] Session_id + +#define MRIM_CS_PROXY_HELLO 0x1046 +// DWORD[4] Session_id + +#define MRIM_CS_PROXY_HELLO_ACK 0x1047 + + + +#define MRIM_CS_NEW_MAIL 0x1048 // S->C +// UL unread count +// LPS from e-mail ANSI +// LPS subject ??? +// UL date +// UL uidl + + + + +#define MRIM_CS_USER_BLOG_STATUS 0x1063 +// DWORD flags + #define MRIM_BLOG_STATUS_UPDATE 0x00000001 + #define MRIM_BLOG_STATUS_MUSIC 0x00000002 // add music to status + #define MRIM_BLOG_STATUS_REPLY 0x00000004 + #define MRIM_BLOG_STATUS_NOTIFY 0x00000010 // not set self status, alert only +// LPS user +// UINT64 id +// DWORD time +// LPS text (MRIM_BLOG_STATUS_MUSIC: track) +// LPS reply_user_nick + +#define MRIM_CS_CHANGE_USER_BLOG_STATUS 0x1064 +// DWORD flags +// LPS text (MRIM_BLOG_STATUS_MUSIC: track) + #define MICBLOG_STATUS_MAX 500 +// switch (flags) { +// MRIM_BLOG_STATUS_REPLY: +// UINT64 orig_id +// } + + +#define MRIM_CS_UNKNOWN 0x1073 +// DWORD ??? +// DWORD ??? + + +#define MRIM_CS_USER_GEO 0x1077 +// LPS user +// LPS: // DWORD flags? + // LPS: "geo-point": + // LPS dolgota + // LPS shirota + // LPS "MAPOBJECT" + // LPS some data? + // LPS/DWORD + // LPS/DWORD + // LPS some data? + // LPS some data? + + +#define MRIM_CS_SERVER_SETTINGS 0x1079 + + + + + +typedef struct mrim_connection_params_t +{ + unsigned long ping_period; +} +mrim_connection_params_t; + + + +#endif // MRIM_PROTO_H + diff --git a/protocols/MRA/src/resource.h b/protocols/MRA/src/resource.h new file mode 100644 index 0000000000..aa5469d599 --- /dev/null +++ b/protocols/MRA/src/resource.h @@ -0,0 +1,142 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by resource.rc +// +#define IDI_MRA 101 +#define IDD_OPT 102 +#define IDD_OPT_CONNECTIONS 102 +#define IDI_INBOX 103 +#define IDD_DIALOG_SELECT_EMAIL 103 +#define IDI_PROFILE 104 +#define IDI_AUTHRUGUEST 106 +#define IDI_AUTHGRANT 107 +#define IDD_MRAADVANCEDSEARCH 108 +#define IDD_OPTAVATRS 109 +#define IDD_OPT_AVATRS 109 +#define IDI_MAIL_NOTIFY 111 +#define IDI_MRA_WEB_SEARCH 112 +#define IDI_MRA_BLOGS 113 +#define IDI_MRA_POSTCARD 114 +#define IDI_MRA_ZHUKI 115 +#define IDI_MRA_PHOTO 117 +#define IDI_MRA_CHAT 120 +#define IDI_MRA_PHONE 122 +#define IDD_OPT_FILES 126 +#define IDD_OPT_ACCOUNT 127 +#define IDD_OPT_POPUPS 128 +#define IDD_MRAACCOUNT 129 +#define IDI_ICON1 130 +#define IDI_MRA_ALARM 130 +#define IDD_OPT_ANTISPAM 131 +#define IDI_MRA_VIDEO 132 +#define IDI_MRA_ANSWERS 133 +#define IDI_MRA_WORLD 134 +#define IDD_MINIBLOG 135 +#define IDI_BLOGSTATUS 137 +#define IDD_SETXSTATUS 256 +#define IDC_GROUPCONFIG 1000 +#define IDC_GROUPCONFIG2 1001 +#define IDC_GROUPMAIN 1002 +#define IDC_REGISTER 1002 +#define IDC_SLOWSEND 1003 +#define IDC_RETURN_ABC_PATH 1004 +#define IDC_FILE_SEND_HIDE_MY_ADDRESSES 1004 +#define IDC_HIDE_MENU_ITEMS_FOR_NON_MRA 1004 +#define IDC_RTF_SEND_ENABLE 1005 +#define IDC_RTF_BGCOLOUR 1006 +#define IDC_CVT_SMILES_ON_SEND_TEXT 1007 +#define IDC_CVT_SMILES_TO_TAGS 1007 +#define IDC_DELETE_AVT_ON_CONTACT_DELETE 1008 +#define IDC_FILE_SEND_ADD_EXTRA_ADDRESS 1008 +#define IDC_INCREMENTAL_NEW_MAIL_NOTIFY 1008 +#define IDC_ENABLE 1009 +#define IDC_AUTO_ADD_CONTACTS_TO_SERVER 1009 +#define IDC_FILE_SEND_NOOUTCONNECTIONONSEND 1010 +#define IDC_AUTO_AUTH_REQ_ON_LOGON 1010 +#define IDC_SHOWPOPUP 1010 +#define IDC_KEEPALIVE 1011 +#define IDC_FILE_SEND_NOOUTCONNECTIONONRECEIVE 1011 +#define IDC_LIST_EMAILS 1011 +#define IDC_TRAYICON_NEW_MAIL_NOTIFY 1011 +#define IDC_WRITETOSYSTEMHISTORY 1011 +#define IDC_FILE_SEND_IGNORYADDITIONALPORTS 1012 +#define IDC_RTF_RECEIVE_ENABLE 1012 +#define IDC_CHK_TEMP_CONTACTS 1012 +#define IDC_DELETE_SPAMBOT_CONTACT 1013 +#define IDC_RTF_SEND_SMART 1013 +#define IDC_COMBO_PHONE 1014 +#define IDC_TRAYICON_NEW_MAIL_NOTIFY_CLICK_TO_INBOX 1014 +#define IDC_FILE_SEND_ENABLE_DIRECT_CONN 1014 +#define IDC_SEND_SPAM_REPORT_TO_SERVER 1014 +#define IDC_EDIT_TEXT 1015 +#define IDC_FILE_SEND_ENABLE_MRIMPROXY_CONS 1015 +#define IDC_AUTO_AUTH_GRAND_IN_CLIST 1015 +#define IDC_CLN_NON_ALPHNUM 1015 +#define IDC_AUTO_AUTH_GRAND_NEW_USERS 1016 +#define IDC_OPTIONSTAB 1017 +#define IDC_AUTO_AUTH_GRAND_NEW_USERS_DISABLE_SPAM_CHECK 1017 +#define IDC_NEW_ACCOUNT_LINK 1018 +#define IDC_LOOKUPLINK 1019 +#define IDC_PASSWORD 1020 +#define IDC_BUTTON_DEFAULT 1020 +#define IDC_LOGIN 1022 +#define IDC_FILE_SEND_BLOCK_SIZE 1022 +#define IDC_COMBO_POPUP_TYPE 1023 +#define IDC_CHK_ENABLE 1024 +#define IDC_CHK_USE_WIN_COLORS 1025 +#define IDC_POPUP_BACKCOLOR 1026 +#define IDC_POPUP_TEXTCOLOR 1027 +#define IDC_POPUP_TIMEOUT 1028 +#define IDC_PREVIEW 1029 +#define IDC_USE_KEEPALIVE_CONN 1030 +#define IDC_BUTTON_FONT 1031 +#define IDC_BAD_WORDS_LIST 1032 +#define IDC_EDIT_BAD_WORD 1033 +#define IDC_BUTTON_ADD 1034 +#define IDC_BUTTONREMOVE 1035 +#define IDC_EMAIL_USER 1048 +#define IDC_EMAIL_DOMAIN 1049 +#define IDC_NICK 1053 +#define IDC_GENDER 1060 +#define IDC_STATE 1061 +#define IDC_ZODIAK 1062 +#define IDC_COUNTRY 1063 +#define IDC_CITY2 1064 +#define IDC_CITY 1064 +#define IDC_XTITLE 1065 +#define IDC_XMSG 1066 +#define IDC_MAX_LANG_CHANGES 1071 +#define IDC_USER_BLOG_STATUS_MSG 1072 +#define IDC_MSG_TO_SEND 1073 +#define IDC_CHK_NOTIFY 1074 +#define IDC_STATIC_WRITED_TIME 1075 +#define IDC_STATIC_CHARS_COUNTER 1076 +#define IDC_CHECK1 1077 +#define IDC_CHK_REMEMBER 1077 +#define IDC_SERVER 1171 +#define IDC_SERVERPORT 1174 +#define IDC_UPD_CHECK_INTERVAL 1175 +#define IDC_FILE_SEND_EXTRA_ADDRESS 1175 +#define IDC_FIRSTNAME 1224 +#define IDC_LASTNAME 1225 +#define IDC_AGERANGE_FROM 1410 +#define IDC_AGERANGE_TO 1411 +#define IDC_BIRTHDAY_DAY 1412 +#define IDC_BIRTHDAY_MONTH 1413 +#define IDC_BIRTHDAY_YEAR 1414 +#define IDC_ONLINEONLY 1430 +#define IDC_SUMMARYGROUP 1434 +#define IDC_LOCATIONGROUP 1436 +#define IDC_STATIC -1 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NO_MFC 1 +#define _APS_NEXT_RESOURCE_VALUE 138 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1078 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/protocols/MRA/src/version.h b/protocols/MRA/src/version.h new file mode 100644 index 0000000000..b7ce1137bf --- /dev/null +++ b/protocols/MRA/src/version.h @@ -0,0 +1,6 @@ +#define __FILEVERSION_STRING 2, 0, 0, 1 +#define __VERSION_STRING "2.0.0.1" +#define __VERSION_DWORD PLUGIN_MAKE_VERSION(2, 0, 0, 1) + +#define PROTO_VERSION_MAJOR 1 +#define PROTO_VERSION_MINOR 21 -- cgit v1.2.3