diff options
Diffstat (limited to 'protocols/MRA/src')
61 files changed, 27546 insertions, 0 deletions
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<CMraProto> 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 <SystemHeaders.h>
+#include <Wincrypt.h>
+#include <Ntsecapi.h>
+#include <Commdlg.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <time.h>
+#include <DebugFunctions.h>
+#include <commctrl.h>
+#include <uxtheme.h>
+#include <SocketFunctions.h>
+
+#define bzero(pvDst, count) memset(pvDst, 0, count)
+#include <timefuncs.h>
+
+#include "../../plugins/zlib/zlib.h"
+
+#define MIRANDA_VER 0x0A00
+
+// http://miranda.svn.sourceforge.net/viewvc/miranda/trunk/miranda/include/?sortby = file
+#include <newpluginapi.h>
+#include <m_system.h>
+#include <m_system_cpp.h>
+#include <m_protocols.h>
+#include <m_clc.h>
+#include <m_clist.h>
+#include <m_cluiframes.h>
+#include <m_clui.h>
+#include <m_genmenu.h>
+#include <m_ignore.h>
+#include <m_message.h>
+#include <m_options.h>
+#include <m_protomod.h>
+#include <m_protosvc.h>
+#include <m_protoint.h>
+#include <m_skin.h>
+#include <m_userinfo.h>
+#include <m_utils.h>
+#include <m_database.h>
+#include <m_langpack.h>
+#include <m_netlib.h>
+#include <m_icolib.h>
+#include <win2k.h>
+#include <m_popup.h>
+#include <m_popup2.h>
+#include <m_nudge.h>
+#include <m_folders.h>
+#include <m_avatars.h>
+#include <m_chat.h>
+#include <m_extraicons.h>
+#include <m_music.h>
+#include <m_icq.h>
+#include <m_proto_listeningto.h>
+
+
+#include <MemoryFind.h>
+#include <MemoryFindByte.h>
+#include <MemoryCompare.h>
+#include <MemoryReplace.h>
+#include <BuffToLowerCase.h>
+#include <StrToNum.h>
+#include <StrToNum.h>
+#include <StrHexToNum.h>
+#include <Base64.h>
+#include <InternetTime.h>
+#include <ListMT.h>
+#include <FIFOMT.h>
+#include <RC4.h>
+#include <SHA1.h>
+
+
+// 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<CMraProto> 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<<bitpos)
+#define GetBit(bytes, bitpos) ((bytes&(1<<bitpos))? TRUE:FALSE)
+
+#define IsXStatusValid(XStatus) (((XStatus) && (XStatus)<MRA_XSTATUS_COUNT))
+
+#define SEND_DLG_ITEM_MESSAGEW(hDlg, nIDDlgItem, Msg, wParam, lParam) SendMessageW(GetDlgItem(hDlg, nIDDlgItem), Msg, wParam, lParam)
+#define SEND_DLG_ITEM_MESSAGEA(hDlg, nIDDlgItem, Msg, wParam, lParam) SendMessageA(GetDlgItem(hDlg, nIDDlgItem), Msg, wParam, lParam)
+#define SEND_DLG_ITEM_MESSAGE(hDlg, nIDDlgItem, Msg, wParam, lParam) SendMessage(GetDlgItem(hDlg, nIDDlgItem), Msg, wParam, lParam)
+
+#define IS_DLG_BUTTON_CHECKED(hDlg, nIDDlgItem) SEND_DLG_ITEM_MESSAGE(hDlg, nIDDlgItem, BM_GETCHECK, NULL, NULL)
+#define CHECK_DLG_BUTTON(hDlg, nIDDlgItem, uCheck) SEND_DLG_ITEM_MESSAGE(hDlg, nIDDlgItem, BM_SETCHECK, (WPARAM)uCheck, NULL)
+
+#define SET_DLG_ITEM_TEXTW(hDlg, nIDDlgItem, lpString) SEND_DLG_ITEM_MESSAGEW(hDlg, nIDDlgItem, WM_SETTEXT, 0, (LPARAM)lpString)
+#define SET_DLG_ITEM_TEXTA(hDlg, nIDDlgItem, lpString) SEND_DLG_ITEM_MESSAGEA(hDlg, nIDDlgItem, WM_SETTEXT, 0, (LPARAM)lpString)
+#define SET_DLG_ITEM_TEXT(hDlg, nIDDlgItem, lpString) SEND_DLG_ITEM_MESSAGE(hDlg, nIDDlgItem, WM_SETTEXT, 0, (LPARAM)lpString)
+
+#define GET_DLG_ITEM_TEXTW(hDlg, nIDDlgItem, lpString, nMaxCount) SEND_DLG_ITEM_MESSAGEW(hDlg, nIDDlgItem, WM_GETTEXT, (WPARAM)nMaxCount, (LPARAM)lpString)
+#define GET_DLG_ITEM_TEXTA(hDlg, nIDDlgItem, lpString, nMaxCount) SEND_DLG_ITEM_MESSAGEA(hDlg, nIDDlgItem, WM_GETTEXT, (WPARAM)nMaxCount, (LPARAM)lpString)
+#define GET_DLG_ITEM_TEXT(hDlg, nIDDlgItem, lpString, nMaxCount) SEND_DLG_ITEM_MESSAGE(hDlg, nIDDlgItem, WM_GETTEXT, (WPARAM)nMaxCount, (LPARAM)lpString)
+
+#define GET_DLG_ITEM_TEXT_LENGTH(hDlg, nIDDlgItem) SEND_DLG_ITEM_MESSAGE(hDlg, nIDDlgItem, WM_GETTEXTLENGTH, NULL, NULL)
+#define GET_WINDOW_TEXT_LENGTH(hDlg) SendMessage(hDlg, WM_GETTEXTLENGTH, NULL, NULL)
+
+#define GET_CURRENT_COMBO_DATA(hWndDlg, ControlID) SEND_DLG_ITEM_MESSAGE(hWndDlg, ControlID, CB_GETITEMDATA, SEND_DLG_ITEM_MESSAGE(hWndDlg, ControlID, CB_GETCURSEL, 0, 0), 0)
+
+
+#define IsFileExist(FileName) (GetFileAttributes(FileName) != INVALID_FILE_ATTRIBUTES)
+#define IsFileExistA(FileName) (GetFileAttributesA(FileName) != INVALID_FILE_ATTRIBUTES)
+#define IsFileExistW(FileName) (GetFileAttributesW(FileName) != INVALID_FILE_ATTRIBUTES)
+
+
+#define IsThreadAlive(hThread) (GetThreadPriority(hThread) != THREAD_PRIORITY_ERROR_RETURN)
+
+void MraAddrListFree(MRA_ADDR_LIST *pmalAddrList);
+DWORD MraAddrListGetFromBuff(LPSTR lpszAddreses, size_t dwAddresesSize, MRA_ADDR_LIST *pmalAddrList);
+DWORD MraAddrListGetToBuff(MRA_ADDR_LIST *pmalAddrList, LPSTR lpszBuff, size_t dwBuffSize, size_t *pdwBuffSizeRet);
+
+DWORD MraGetVersionStringFromFormatted (LPSTR dwUserAgentFormatted, size_t dwUserAgentFormattedSize, LPSTR lpszVersion, size_t dwVersionSize, size_t *pdwVersionSizeRet);
+BOOL IsUnicodeEnv ();
+BOOL IsHTTPSProxyUsed (HANDLE hNetlibUser);
+BOOL IsContactMraProto (HANDLE hContact);
+BOOL IsEMailMR (LPSTR lpszEMail, size_t dwEMailSize);
+BOOL GetEMailFromString (LPSTR lpszBuff, size_t dwBuffSize, LPSTR *plpszEMail, size_t *pdwEMailSize);
+
+DWORD CreateBlobFromContact (HANDLE hContact, LPWSTR lpwszRequestReason, size_t dwRequestReasonSize, LPBYTE lpbBuff, size_t dwBuffSize, size_t *pdwBuffSizeRet);
+int ExtraSetIcon (HANDLE hExtraIcon, HANDLE hContact, HANDLE hImage, int iColumnType);
+size_t CopyNumber (LPCVOID lpcOutBuff, LPCVOID lpcBuff, size_t dwLen);
+BOOL IsPhone (LPSTR lpszString, size_t dwStringSize);
+BOOL IsContactPhone (HANDLE hContact, LPSTR lpszPhone, size_t dwPhoneSize);
+HANDLE MraHContactFromPhone (LPSTR lpszPhone, size_t dwPhoneSize, BOOL bAddIfNeeded, BOOL bTemporary, BOOL *pbAdded);
+void EnableControlsArray (HWND hWndDlg, WORD *pwControlsList, size_t dwControlsListCount, BOOL bEnabled);
+BOOL MraRequestXStatusDetails (DWORD dwXStatus);
+BOOL MraSendReplyBlogStatus (HANDLE hContact);
+DWORD GetYears (CONST PSYSTEMTIME pcstSystemTime);
+DWORD FindFile (LPWSTR lpszFolder, DWORD dwFolderLen, LPWSTR lpszFileName, DWORD dwFileNameLen, LPWSTR lpszRetFilePathName, DWORD dwRetFilePathLen, DWORD *pdwRetFilePathLen);
+DWORD MemFillRandom (LPVOID lpBuff, size_t dwBuffSize);
+DWORD DecodeXML (LPTSTR lptszMessage, size_t dwMessageSize, LPTSTR lptszMessageConverted, size_t dwMessageConvertedBuffSize, size_t *pdwMessageConvertedSize);
+DWORD EncodeXML (LPTSTR lptszMessage, size_t dwMessageSize, LPTSTR lptszMessageConverted, size_t dwMessageConvertedBuffSize, size_t *pdwMessageConvertedSize);
+
+DWORD GetMraStatusFromMiradaStatus (DWORD dwMirandaStatus, DWORD dwXStatusMir, DWORD *pdwXStatusMra);
+DWORD GetMiradaStatusFromMraStatus (DWORD dwMraStatus, DWORD dwXStatusMra, DWORD *pdwXStatusMir);
+DWORD GetMraXStatusIDFromMraUriStatus (LPSTR lpszStatusUri, size_t dwStatusUriSize);
+
+INT_PTR CALLBACK DlgProcAccount(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
+
+#endif // !defined(AFX_MRA_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_)
diff --git a/protocols/MRA/src/MraAdvancedSearch.cpp b/protocols/MRA/src/MraAdvancedSearch.cpp new file mode 100644 index 0000000000..8ffe222cab --- /dev/null +++ b/protocols/MRA/src/MraAdvancedSearch.cpp @@ -0,0 +1,361 @@ +#include "Mra.h"
+#include "proto.h"
+#include "MraPlaces.h"
+
+
+
+struct FieldNames
+{
+ BYTE dwCode;
+ LPWSTR lpszText;
+};
+
+
+
+static const FieldNames GenderField[] =
+{
+ {1, L"Male"},
+ {2, L"Female"},
+ {-1, NULL}
+};
+
+static const FieldNames MonthField[] =
+{
+ {1, L"January"},
+ {2, L"February"},
+ {3, L"March"},
+ {4, L"April"},
+ {5, L"May"},
+ {6, L"June"},
+ {7, L"July"},
+ {8, L"August"},
+ {9, L"September"},
+ {10, L"October"},
+ {11, L"November"},
+ {12, L"December"},
+ {-1, NULL}
+};
+
+static const FieldNames ZodiakField[] =
+{
+ {1, L"Aries"},
+ {2, L"Taurus"},
+ {3, L"Gemini"},
+ {4, L"Cancer"},
+ {5, L"Leo"},
+ {6, L"Virgo"},
+ {7, L"Libra"},
+ {8, L"Scorpio"},
+ {9, L"Sagitarius"},
+ {10, L"Capricorn"},
+ {11, L"Aquarius"},
+ {12, L"Pisces"},
+ {-1, NULL}
+};
+
+
+
+
+
+
+void ResetComboBox(HWND hWndCombo)
+{
+ DWORD dwItem;
+
+ 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);
+}
+
+
+void InitComboBox(HWND hWndCombo, FieldNames *lpNames)
+{
+ DWORD dwItem;
+
+ ResetComboBox(hWndCombo);
+
+ for (size_t i = 0;lpNames[i].lpszText;i++)
+ {
+ dwItem = SendMessage(hWndCombo, CB_ADDSTRING, 0, (LPARAM)TranslateW(lpNames[i].lpszText));
+ SendMessage(hWndCombo, CB_SETITEMDATA, dwItem, lpNames[i].dwCode);
+ }
+}
+
+
+void InitComboBoxNumders(HWND hWndCombo, DWORD dwStart, DWORD dwEnd)
+{
+ DWORD dwItem;
+ WCHAR szBuff[MAX_PATH];
+
+ ResetComboBox(hWndCombo);
+
+ for (DWORD i = dwStart;i <= dwEnd;i++)
+ {
+ mir_sntprintf(szBuff, SIZEOF(szBuff), L"%lu", i);
+ dwItem = SendMessage(hWndCombo, CB_ADDSTRING, 0, (LPARAM)szBuff);
+ SendMessage(hWndCombo, CB_SETITEMDATA, dwItem, i);
+ }
+}
+
+
+INT_PTR CALLBACK AdvancedSearchDlgProc(HWND hWndDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ CMraProto *ppro = (CMraProto*)GetWindowLongPtr(hWndDlg, GWLP_USERDATA);
+
+ switch (message) {
+ case WM_INITDIALOG:
+ {
+ HWND hWndCombo;
+ DWORD dwItem;
+ WCHAR wszBuff[MAX_PATH];
+ SYSTEMTIME stTime;
+ GetLocalTime(&stTime);
+
+ SetWindowLongPtr(hWndDlg, GWLP_USERDATA, lParam);
+ ppro = (CMraProto*)lParam;
+ //InitComboBox(GetDlgItem(hWndDlg, IDC_EMAIL_DOMAIN), (FieldNames*)DomainField);
+ {
+ hWndCombo = GetDlgItem(hWndDlg, IDC_EMAIL_DOMAIN);
+ ResetComboBox(hWndCombo);
+ for (size_t i = 0;lpcszMailRuDomains[i];i++)
+ {
+ MultiByteToWideChar(MRA_CODE_PAGE, 0, lpcszMailRuDomains[i], -1, wszBuff, SIZEOF(wszBuff));
+ SendMessage(hWndCombo, CB_ADDSTRING, 0, (LPARAM)wszBuff);
+ }
+ }
+ InitComboBox(GetDlgItem(hWndDlg, IDC_GENDER), (FieldNames*)GenderField);
+ InitComboBoxNumders(GetDlgItem(hWndDlg, IDC_AGERANGE_FROM), 1, 100);
+ InitComboBoxNumders(GetDlgItem(hWndDlg, IDC_AGERANGE_TO), 1, 100);
+ InitComboBoxNumders(GetDlgItem(hWndDlg, IDC_BIRTHDAY_DAY), 1, 31);
+ InitComboBox(GetDlgItem(hWndDlg, IDC_BIRTHDAY_MONTH), (FieldNames*)MonthField);
+ InitComboBoxNumders(GetDlgItem(hWndDlg, IDC_BIRTHDAY_YEAR), 1900, (DWORD)stTime.wYear);
+ InitComboBox(GetDlgItem(hWndDlg, IDC_ZODIAK), (FieldNames*)ZodiakField);
+
+ hWndCombo = GetDlgItem(hWndDlg, IDC_COUNTRY);
+ ResetComboBox(hWndCombo);
+ for (size_t i = 0;mrapPlaces[i].lpszData;i++)
+ {
+ if (mrapPlaces[i].dwCityID == 0 && mrapPlaces[i].dwPlaceID == 0)
+ {
+ dwItem = SendMessage(hWndCombo, CB_ADDSTRING, 0, (LPARAM)mrapPlaces[i].lpszData);
+ SendMessage(hWndCombo, CB_SETITEMDATA, dwItem, mrapPlaces[i].dwCountryID);
+ }
+ }
+
+
+ ResetComboBox(GetDlgItem(hWndDlg, IDC_CITY));
+
+ if ( ppro->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<dwMessageSize;i++)
+ if (IsCharAlphaNumeric(lpwszMessage[i]))
+ *lpwszCurWritePos++ = lpwszMessage[i];
+
+ *lpwszCurWritePos = 0;
+ dwRet = lpwszCurWritePos - lpwszMessage;
+ }
+ return dwRet;
+}
+
+
+BOOL MraAntiSpamTestMessageForBadWordsW(LPWSTR lpwszMessage, size_t dwMessageSize)
+{
+ if (lpwszMessage && dwMessageSize)
+ for (size_t i = 0; i < dwBadWordsCount; i++)
+ if (MemoryFind(0, lpwszMessage, (dwMessageSize*sizeof(WCHAR)), pmabwBadWords[i].lpwszBadWord, (pmabwBadWords[i].dwBadWordLen*sizeof(WCHAR))))
+ return TRUE;
+
+ return FALSE;
+}
+
+BOOL CMraProto::MraAntiSpamHasMessageBadWordsW(LPWSTR lpwszMessage, size_t dwMessageSize)
+{
+ BOOL bRet = FALSE;
+
+ if (lpwszMessage && dwMessageSize) {
+ LPWSTR lpwszMessageConverted = (LPWSTR)mir_alloc((dwMessageSize+1)*sizeof(WCHAR));
+ if (lpwszMessageConverted) {
+ size_t dwtm;
+
+ // в нижний регистр всё сообщение
+ memmove(lpwszMessageConverted, lpwszMessage, (dwMessageSize*sizeof(WCHAR)));
+ CharLowerBuffW(lpwszMessageConverted, DWORD(dwMessageSize));
+
+ // 1 проход: считаем колличество переключений языка
+ dwtm = mraGetDword(NULL, "AntiSpamMaxLangChanges", MRA_ANTISPAM_DEFAULT_MAX_LNG_CHANGES);
+ if (dwtm)
+ if (dwtm <= MraAntiSpamCalcLangChanges(lpwszMessageConverted, dwMessageSize))
+ bRet = TRUE;
+
+ // 2 проход: ищем плохие слова
+ if (bRet == FALSE)
+ bRet = MraAntiSpamTestMessageForBadWordsW(lpwszMessageConverted, dwMessageSize);
+
+ // 3 проход: оставляем только буквы + цифры и снова ищем плохие слова
+ if (bRet == FALSE)
+ if (mraGetByte(NULL, "AntiSpamCleanNonAlphaNumeric", MRA_ANTISPAM_DEFAULT_ENABLE)) {
+ dwMessageSize = MraAntiSpamCleanNonAlphaNumeric(lpwszMessageConverted, dwMessageSize);
+ bRet = MraAntiSpamTestMessageForBadWordsW(lpwszMessageConverted, dwMessageSize);
+ }
+
+ mir_free(lpwszMessageConverted);
+ }
+ }
+ return bRet;
+}
+
+DWORD CMraProto::MraAntiSpamReceivedMessageW(LPSTR lpszEMail, size_t dwEMailSize, DWORD dwMessageFlags, LPWSTR lpwszMessage, size_t dwMessageSize)
+{
+ DWORD dwRet = MESSAGE_NOT_SPAM;;
+
+ if ((dwMessageFlags&(MESSAGE_FLAG_SYSTEM|MESSAGE_FLAG_CONTACT|MESSAGE_FLAG_NOTIFY|MESSAGE_FLAG_SMS|MESSAGE_SMS_DELIVERY_REPORT|MESSAGE_FLAG_ALARM|MESSAGE_FLAG_MULTICHAT)) == 0)
+ if (mraGetByte(NULL, "AntiSpamEnable", MRA_ANTISPAM_DEFAULT_ENABLE))
+ if (IsEMailChatAgent(lpszEMail, dwEMailSize) == FALSE) { // enabled, message must be checked
+ BOOL bCheckMessage = TRUE;
+ dwRet = MESSAGE_SPAM;
+ HANDLE hContact = MraHContactFromEmail(lpszEMail, dwEMailSize, FALSE, TRUE, NULL);
+ if (hContact) {
+ DWORD dwID, dwGroupID, dwContactFlag, dwContactSeverFlags;
+ GetContactBasicInfoW(hContact, &dwID, &dwGroupID, &dwContactFlag, &dwContactSeverFlags, NULL, NULL, 0, NULL, NULL, 0, NULL, NULL, 0, NULL);
+
+ // not temp contact, OK
+ if ((dwID != -1 && db_get_b(hContact, "CList", "NotOnList", 0) == 0) || dwGroupID == -2) {
+ bCheckMessage = FALSE;
+ dwRet = MESSAGE_NOT_SPAM;
+ }
+ else { // temp contact
+ if (mraGetByte(NULL, "AntiSpamCheckTempContacts", MRA_ANTISPAM_DEFAULT_CHK_TEMP_CONTACTS) == FALSE ||
+ (((dwMessageFlags&MESSAGE_FLAG_AUTHORIZE) && mraGetByte(NULL, "AutoAuthGrandNewUsers", MRA_DEFAULT_AUTO_AUTH_GRAND_NEW_USERS) && mraGetByte(NULL, "AutoAuthGrandNewUsersDisableSPAMCheck", MRA_DEFAULT_AUTO_AUTH_GRAND_NEW_USERS_DISABLE_SPAM_CHECK))))
+ {// проверка временного контакта
+ bCheckMessage = FALSE;
+ dwRet = MESSAGE_NOT_SPAM;
+ }
+ }
+ }
+
+ if (bCheckMessage)
+ if (MraAntiSpamHasMessageBadWordsW(lpwszMessage, dwMessageSize) == FALSE)
+ dwRet = MESSAGE_NOT_SPAM;
+
+ if (dwRet == MESSAGE_SPAM) {
+ BOOL bAntiSpamShowPopUp, bAntiSpamWriteToSystemHistory, bAntiSpamDeteleSpamBotContacts;
+
+ bAntiSpamShowPopUp = (BOOL)mraGetByte(NULL, "AntiSpamShowPopUp", MRA_ANTISPAM_DEFAULT_SHOWPOP);
+ bAntiSpamWriteToSystemHistory = (BOOL)mraGetByte(NULL, "AntiSpamWriteToSystemHistory", MRA_ANTISPAM_DEFAULT_WRITETOSYSTEMHISTORY);
+ bAntiSpamDeteleSpamBotContacts = (BOOL)mraGetByte(NULL, "AntiSpamDeteleSpamBotContacts", MRA_ANTISPAM_DEFAULT_DELETE_SPAMBOT_CONTACT);
+
+ if (bAntiSpamShowPopUp || bAntiSpamWriteToSystemHistory) {
+ char szEMail[MAX_EMAIL_LEN];
+ WCHAR wszBuff[MRA_MAXLENOFMESSAGE*2];
+ size_t dwDBMessageSize;
+
+ memmove(szEMail, lpszEMail, dwEMailSize);
+ (*((WORD*)(szEMail+dwEMailSize))) = 0;
+
+ dwDBMessageSize = mir_sntprintf(wszBuff, SIZEOF(wszBuff), L"%s: %S\r\n", TranslateW(L"Spam bot blocked"), szEMail);
+ if (dwMessageSize>(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.timeout<MRA_TIMEOUT_CONN_MIN) nloc.timeout = MRA_TIMEOUT_CONN_MIN;
+ if (nloc.timeout>MRA_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<TCHAR> 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;i<dat->dwFilesCount;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.timeout<MRA_TIMEOUT_CONN_MIN) nloc.timeout = MRA_TIMEOUT_CONN_MIN;
+ if (nloc.timeout>MRA_TIMEOUT_CONN_МАХ) nloc.timeout = MRA_TIMEOUT_CONN_МАХ;
+
+ // Set up the sockaddr structure
+ for (size_t i = 0;i<dat->malAddrList.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;i<dat->dwFilesCount;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)<SIZEOF(wszFileName))
+ {
+ memmove(wszFileName, dat->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;j<dat->dwFilesCount;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 <SystemHeaders.h>
+#include <MemoryFindByte.h>
+#include <MemoryCompare.h>
+#include <BuffToLowerCase.h>
+#include <ListMT.h>
+#include <StrToNum.h>
+#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;i<pmrafqFilesQueueItem->dwFilesCount;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;i<pmrafqFilesQueueItem->dwFilesCount;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;i<pmrafqFilesQueueItem->dwFilesCount;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;i<pmrafqFilesQueueItem->dwFilesCount;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;i<pmrafqFilesQueueItem->dwAddrCount;i++)
+ {// Set up the sockaddr structure
+ if (dwLocalPort==pmrafqFilesQueueItem->pmfqaAddreses[i].dwPort)
+ {
+ bFiltering=TRUE;
+ break;
+ }
+ }
+ }
+
+ for(i=0;i<pmrafqFilesQueueItem->dwAddrCount;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;i<pmrafqFilesQueueItem->dwFilesCount;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;i<pmrafqFilesQueueItem->dwFilesCount;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;i<pmrafqFilesQueueItem->dwFilesCount;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;j<pmrafqFilesQueueItem->dwFilesCount;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<dwCount;i++) {
+ mir_snprintf(szBuff, SIZEOF(szBuff), "MRA_%s", pgdiItems[i].lpszName);
+ sid.pszName = szBuff;
+ sid.pwszDescription = pgdiItems[i].lpwszDescr;
+ sid.iDefaultIndex = -pgdiItems[i].defIcon;
+ sid.hDefaultIcon = (HICON)LoadImage(masMraSettings.hInstance, MAKEINTRESOURCE(pgdiItems[i].defIcon), IMAGE_ICON, 0, 0, LR_SHARED);
+ if (sid.hDefaultIcon == NULL) sid.hDefaultIcon = (HICON)LoadImage(NULL, MAKEINTRESOURCE(pgdiItems[i].defIcon), IMAGE_ICON, 0, 0, LR_SHARED);
+ pgdiItems[i].hIconHandle = Skin_AddIcon(&sid);
+ }
+}
+
+HICON IconLibGetIcon(HANDLE hIcon)
+{
+ return IconLibGetIconEx(hIcon, LR_SHARED);
+}
+
+HICON IconLibGetIconEx(HANDLE hIcon, DWORD dwFlags)
+{
+ HICON hiIcon = NULL;
+ if (hIcon) {
+ hiIcon = Skin_GetIconByHandle(hIcon);
+ if ((dwFlags & LR_SHARED) == 0)
+ hiIcon = CopyIcon(hiIcon);
+ }
+ return hiIcon;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+
+void IconsLoad()
+{
+ AddIcoLibItems(L"MainMenu", gdiMenuItems, SIZEOF(gdiMenuItems));
+ AddIcoLibItems(L"ContactMenu", gdiContactMenuItems, SIZEOF(gdiContactMenuItems));
+
+ // Advanced Status Icons initialization
+ AddIcoLibItems(L"Extra status", gdiExtraStatusIconsItems, SIZEOF(gdiExtraStatusIconsItems));
+}
+
+void CMraProto::InitXStatusIcons()
+{
+ WCHAR wszSection[MAX_PATH], wszPath[MAX_FILEPATH];
+ mir_sntprintf(wszSection, SIZEOF(wszSection), L"Status Icons/%s/Custom Status", m_tszUserName);
+ if (masMraSettings.hDLLXStatusIcons)
+ GetModuleFileName(masMraSettings.hDLLXStatusIcons, wszPath, SIZEOF(wszPath));
+ else
+ bzero(wszPath, sizeof(wszPath));
+
+ SKINICONDESC sid = {0};
+ sid.cbSize = sizeof(sid);
+ sid.pwszSection = wszSection;
+ sid.pwszDefaultFile = wszPath;
+ sid.cx = sid.cy = 16;
+ sid.flags = SIDF_ALL_UNICODE;
+
+ hXStatusAdvancedStatusIcons[0] = NULL;
+ for (int i = 1; i < MRA_XSTATUS_COUNT+1; i++) {
+ char szBuff[MAX_PATH];
+ mir_snprintf(szBuff, SIZEOF(szBuff), "%s_xstatus%ld", m_szModuleName, i);
+ sid.pszName = szBuff;
+
+ int iCurIndex = i+IDI_XSTATUS1-1;
+ sid.pwszDescription = lpcszXStatusNameDef[i];
+ sid.iDefaultIndex = -iCurIndex;
+ if (masMraSettings.hDLLXStatusIcons)
+ sid.hDefaultIcon = (HICON)LoadImage(masMraSettings.hDLLXStatusIcons, MAKEINTRESOURCE(iCurIndex), IMAGE_ICON, 0, 0, LR_SHARED);
+ else
+ sid.hDefaultIcon = NULL;
+
+ hXStatusAdvancedStatusIcons[i] = Skin_AddIcon(&sid);
+ }
+}
+
+void CMraProto::DestroyXStatusIcons()
+{
+ char szBuff[MAX_PATH];
+
+ for (size_t i = 1; i < MRA_XSTATUS_COUNT+1; i++) {
+ mir_snprintf(szBuff, SIZEOF(szBuff), "xstatus%ld", i);
+ Skin_RemoveIcon(szBuff);
+ }
+
+ bzero(hXStatusAdvancedStatusIcons, sizeof(hXStatusAdvancedStatusIcons));
+ bzero(hXStatusAdvancedStatusItems, sizeof(hXStatusAdvancedStatusItems));
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CMraProto::InitMainMenu()
+{
+ HICON hMainIcon = (HICON)LoadImage(masMraSettings.hInstance, MAKEINTRESOURCE(IDI_MRA), IMAGE_ICON, 0, 0, LR_SHARED);
+ CListCreateMenu(200001, 500085000, hMainIcon, NULL, TRUE, gdiMenuItems, SIZEOF(gdiMenuItems), hMainMenuItems);
+}
+
+void CMraProto::InitContactMenu()
+{
+ CListCreateMenu(2000060000, -500050000, NULL, NULL, FALSE, gdiContactMenuItems, SIZEOF(gdiContactMenuItems), hContactMenuItems);
+}
+
+void CMraProto::CListCreateMenu(LONG lPosition, LONG lPopupPosition, HICON hMainIcon, LPSTR pszContactOwner, BOOL bIsMain, const GUI_DISPLAY_ITEM *pgdiItems, size_t dwCount, HANDLE *hResult)
+{
+ if (!pgdiItems || !dwCount || !hResult)
+ return;
+
+ char szServiceFunction[MAX_PATH], *pszServiceFunctionName;
+ strncpy(szServiceFunction, m_szModuleName, sizeof(szServiceFunction));
+ pszServiceFunctionName = szServiceFunction + strlen(m_szModuleName);
+
+ CLISTMENUITEM mi = {0};
+ mi.cbSize = sizeof(mi);
+ mi.position = -1999901008;
+
+ HGENMENU (*fnAddFunc)(CLISTMENUITEM*);
+ if (bIsMain) {
+ fnAddFunc = Menu_AddProtoMenuItem;
+
+ HGENMENU hRootMenu = MO_GetProtoRootMenu(m_szModuleName);
+ if (hRootMenu == NULL) {
+ mi.ptszName = m_tszUserName;
+ mi.hParentMenu = HGENMENU_ROOT;
+ mi.flags = CMIF_ROOTPOPUP | CMIF_TCHAR | CMIF_KEEPUNTRANSLATED;
+ mi.hIcon = hMainIcon;
+ hRootMenu = Menu_AddProtoMenuItem(&mi);
+ }
+ mi.hParentMenu = hRootMenu;
+ mi.flags = CMIF_UNICODE | CMIF_ICONFROMICOLIB | CMIF_CHILDPOPUP;
+ }
+ else {
+ fnAddFunc = Menu_AddContactMenuItem;
+ mi.ptszPopupName = m_tszUserName;
+ mi.flags = CMIF_UNICODE | CMIF_ICONFROMICOLIB;
+ }
+
+ mi.popupPosition = lPopupPosition;
+ mi.pszService = szServiceFunction;
+
+ for (size_t i = 0; i < dwCount; i++) {
+ memmove(pszServiceFunctionName, pgdiItems[i].lpszName, lstrlenA(pgdiItems[i].lpszName)+1);
+ if (pgdiItems[i].lpFunc)
+ CreateObjectSvc(pgdiItems[i].lpszName, pgdiItems[i].lpFunc);
+ mi.position = int(lPosition + i);
+ mi.icolibItem = pgdiItems[i].hIconHandle;
+ mi.ptszName = pgdiItems[i].lpwszDescr;
+ hResult[i] = fnAddFunc(&mi);
+ }
+}
diff --git a/protocols/MRA/src/MraIcons.h b/protocols/MRA/src/MraIcons.h new file mode 100644 index 0000000000..992914805b --- /dev/null +++ b/protocols/MRA/src/MraIcons.h @@ -0,0 +1,13 @@ +#if !defined(AFX_MRA_ICONS_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_)
+#define AFX_MRA_ICONS_H__F58D13FF_F6F2_476C_B8F0_7B9E9357CF48__INCLUDED_
+
+
+#if _MSC_VER > 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->dwMPOPKeySize<dwKeySize || dwKeySize == 0) {
+ mir_free(pmpsqMPopSessionQueue->lpszMPOPKey);
+ 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.timeout<MRA_TIMEOUT_CONN_MIN) nloc.timeout = MRA_TIMEOUT_CONN_MIN;
+ if (nloc.timeout>MRA_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<<dwType);
+ else
+ dwPopupsEventFilter &= ~(1<<dwType);
+
+ ppro->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"<SMILE>id = flas", 28);
+ if (lpwszFound)
+ if (MemoryFind(((lpwszFound-lpwszMessage)+32), lpwszMessage, dwMessageSize, L"'</SMILE>", 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<SYMBOLS_COUNT;i++)
+ if (lpszFounded[i] && (lpszFounded[i]<lpszFounded[dwFirstFoundIndex] || lpszFounded[dwFirstFoundIndex] == NULL))
+ dwFirstFoundIndex = i;
+
+ if (lpszFounded[dwFirstFoundIndex]) { // found
+ dwMemPartToCopy = (lpszFounded[dwFirstFoundIndex]-lpszMessageCurPrev);
+ if (lpszMessageConvertedMax > (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<SYMBOLS_COUNT;i++) { // looking for the next time
+ if (lpszFounded[i] && lpszFounded[i] < lpszMessageCurPrev) {
+ dwFoundCount--;// вычитаем тут, чтобы учесть схожие смайлы: "):-(" и ":-("
+ lpszFounded[i] = (LPSTR)MemoryFind((lpszMessageCurPrev-lpszMessage), lpszMessage, dwMessageSize, lpszSimbols[i], dwcSimbolsCount[i]);
+ if (lpszFounded[i]) dwFoundCount++;
+ }
+ }
+ }
+ else {
+ dwRetErrorCode = ERROR_BUFFER_OVERFLOW;
+ DebugBreak();
+ break;
+ }
+ }
+ }
+
+ lpszMessageCur = (lpszMessage+dwMessageSize);
+ MraTextToRTFData(lpszMessageCurPrev, (lpszMessageCur-lpszMessageCurPrev), lpszMessageConvertedCur, (lpszMessageConvertedMax-lpszMessageConvertedCur), &i);lpszMessageConvertedCur += i;
+ *((WORD*)lpszMessageConvertedCur) = 0;
+
+ if (pdwMessageConvertedSize)
+ *pdwMessageConvertedSize = lpszMessageConvertedCur - lpszMessageConverted;
+
+ return(dwRetErrorCode);
+}
+
+DWORD CMraProto::MraConvertToRTFW(LPCWSTR lpwszMessage, size_t dwMessageSize, LPSTR lpszMessageRTF, size_t dwMessageRTFBuffSize, size_t *pdwMessageRTFSize)
+{
+ if (!lpwszMessage || !lpszMessageRTF)
+ return ERROR_INVALID_HANDLE;
+
+ if ((dwMessageSize+1024) > dwMessageRTFBuffSize) {
+ if (pdwMessageRTFSize)
+ *pdwMessageRTFSize = dwMessageSize;
+ return ERROR_BUFFER_OVERFLOW;
+ }
+
+ mir_ptr<CHAR> 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<char> 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<char> 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 = ((dwDataSize<SIZEOF(szData))? dwDataSize:SIZEOF(szData));
+ BuffToLowerCase(szData, lpszData, dwDataSize);
+
+ lpszParamDataStart = (LPSTR)MemoryFind(0, szData, dwDataSize, lpszParamName, dwParamNameSize);
+ if (lpszParamDataStart)
+ if ((*((WORD*)(lpszParamDataStart+dwParamNameSize))) == (*((WORD*)"=\""))) {
+ lpszParamDataStart += dwParamNameSize+2;
+ lpszParamDataEnd = (LPSTR)MemoryFindByte((lpszParamDataStart-szData), szData, dwDataSize, '"');
+ if (lpszParamDataEnd) {
+ memmove(lpszParamValue, (lpszData+(lpszParamDataStart-szData)), (lpszParamDataEnd-lpszParamDataStart));
+ if (pParamValueSizeRet) (*pParamValueSizeRet) = (lpszParamDataEnd-lpszParamDataStart);
+ return NO_ERROR;
+ }
+ }
+ return ERROR_NOT_FOUND;
+}
+
+DWORD MraGetVersionStringFromFormatted(LPSTR dwUserAgentFormatted, size_t dwUserAgentFormattedSize, LPSTR lpszVersion, size_t dwVersionSize, size_t *pdwVersionSizeRet)
+{
+ if (!dwUserAgentFormatted || !dwUserAgentFormattedSize || !lpszVersion || !dwVersionSize)
+ return ERROR_INVALID_HANDLE;
+
+ char szBuff[4096];
+ size_t dwBuffSize, dwVersionSizeRet;
+
+ if ( !GetParamValue(dwUserAgentFormatted, dwUserAgentFormattedSize, "name", 4, szBuff, SIZEOF(szBuff), &dwBuffSize))
+ if ( !_strnicmp(szBuff, "Miranda IM", dwBuffSize) || !_strnicmp(szBuff, "Miranda NG", dwBuffSize)) {
+ GetParamValue(dwUserAgentFormatted, dwUserAgentFormattedSize, "title", 5, lpszVersion, dwVersionSize, pdwVersionSizeRet);
+ return 0;
+ }
+
+ dwVersionSizeRet = 0;
+ if ( !GetParamValue(dwUserAgentFormatted, dwUserAgentFormattedSize, "client", 6, lpszVersion, dwVersionSize, &dwBuffSize)) {
+ dwVersionSizeRet += dwBuffSize;
+ *((BYTE*)(lpszVersion+dwVersionSizeRet)) = ' ';
+ }
+
+ if ( !GetParamValue(dwUserAgentFormatted, dwUserAgentFormattedSize, "name", 4, lpszVersion, dwVersionSize, &dwBuffSize)) {
+ dwVersionSizeRet += dwBuffSize;
+ *((BYTE*)(lpszVersion+dwVersionSizeRet)) = ' ';
+ }
+
+ if ( !GetParamValue(dwUserAgentFormatted, dwUserAgentFormattedSize, "title", 5, lpszVersion, dwVersionSize, &dwBuffSize)) {
+ dwVersionSizeRet += dwBuffSize;
+ *((BYTE*)(lpszVersion+dwVersionSizeRet)) = ' ';
+ }
+
+ if ( !GetParamValue(dwUserAgentFormatted, dwUserAgentFormattedSize, "version", 7, (lpszVersion+dwVersionSizeRet+1), (dwVersionSize-dwVersionSizeRet), &dwBuffSize)) {
+ dwVersionSizeRet += (dwBuffSize+1);
+ *((BYTE*)(lpszVersion+dwVersionSizeRet)) = '.';
+ if ( !GetParamValue(dwUserAgentFormatted, dwUserAgentFormattedSize, "build", 5, (lpszVersion+dwVersionSizeRet+1), (dwVersionSize-dwVersionSizeRet), &dwBuffSize))
+ dwVersionSizeRet += (dwBuffSize+1);
+ }
+
+ // no data extracted, copy raw
+ if (dwVersionSizeRet == 0) {
+ dwVersionSizeRet = (dwUserAgentFormattedSize < dwVersionSize) ? dwUserAgentFormattedSize : dwVersionSize;
+ memmove(lpszVersion, dwUserAgentFormatted, dwVersionSizeRet);
+ }
+
+ if (pdwVersionSizeRet)
+ *pdwVersionSizeRet = dwVersionSizeRet;
+
+ return 0;
+}
+
+DWORD MraAddrListGetFromBuff(LPSTR lpszAddreses, size_t dwAddresesSize, MRA_ADDR_LIST *pmalAddrList)
+{
+ if (!lpszAddreses || !dwAddresesSize || !pmalAddrList)
+ return ERROR_INVALID_HANDLE;
+
+ LPSTR lpszCurrentItem, lpszDelimiter, lpszEndItem;
+ DWORD dwAllocatedCount;
+
+ dwAllocatedCount = ALLOCATED_COUNT;
+ pmalAddrList->dwAddrCount = 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;i<pmalAddrList->dwAddrCount;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)<dwEMailSize)
+ if (CompareStringA( MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), NORM_IGNORECASE, MAILRU_CHAT_CONF_DOMAIN, (sizeof(MAILRU_CHAT_CONF_DOMAIN)-1), (lpszEMail+(dwEMailSize-(sizeof(MAILRU_CHAT_CONF_DOMAIN)-1))), (sizeof(MAILRU_CHAT_CONF_DOMAIN)-1)) == CSTR_EQUAL)
+ {
+ if ( (*(BYTE*)(lpszEMail+((dwEMailSize-(sizeof(MAILRU_CHAT_CONF_DOMAIN)-1))-1))) == '@' )
+ {
+ bRet = TRUE;
+ }
+ }
+ }
+return(bRet);
+}
+
+
+BOOL CMraProto::IsContactChatAgent(HANDLE hContact)
+{
+ BOOL bRet = FALSE;
+
+ if (hContact)
+ {
+ CHAR szEMail[MAX_EMAIL_LEN];
+ size_t dwEMailSize;
+
+ if (mraGetStaticStringA(hContact, "e-mail", szEMail, SIZEOF(szEMail), &dwEMailSize))
+ {
+ bRet = IsEMailChatAgent(szEMail, dwEMailSize);
+ }
+ //bRet = ((GetContactFlags(hContact)&CONTACT_FLAG_MULTICHAT) != 0);
+ }
+return(bRet);
+}
+
+
+
+BOOL IsEMailMR(LPSTR lpszEMail, size_t dwEMailSize)
+{
+ BOOL bRet = FALSE;
+
+ if (lpszEMail)
+ {
+ size_t i, dwDomainLen;
+
+ if (dwEMailSize == 0) dwEMailSize = lstrlenA(lpszEMail);
+ for (i = 0;lpcszMailRuDomains[i];i++)
+ {
+ dwDomainLen = lstrlenA(lpcszMailRuDomains[i]);
+ if (dwDomainLen<dwEMailSize)
+ if (CompareStringA( MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), NORM_IGNORECASE, lpcszMailRuDomains[i], dwDomainLen, (lpszEMail+(dwEMailSize-dwDomainLen)), dwDomainLen) == CSTR_EQUAL)
+ {
+ if ( (*(BYTE*)(lpszEMail+((dwEMailSize-dwDomainLen)-1))) == '@' )
+ {
+ bRet = TRUE;
+ break;
+ }
+ }
+ }
+ }
+return(bRet);
+}
+
+
+BOOL GetEMailFromString(LPSTR lpszBuff, size_t dwBuffSize, LPSTR *plpszEMail, size_t *pdwEMailSize)
+{
+ BOOL bRet = FALSE;
+
+ if (lpszBuff && dwBuffSize)
+ {
+ LPSTR lpszEMailStart, lpszEMailEnd;
+
+ if ((lpszEMailStart = (LPSTR)MemoryFindByte(0, lpszBuff, dwBuffSize, '<')))
+ {
+ lpszEMailStart++;
+ if ((lpszEMailEnd = (LPSTR)MemoryFindByte((lpszEMailStart-lpszBuff), lpszBuff, dwBuffSize, '>')))
+ {
+ 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.wMonth<pcstSystemTime->wMonth)
+ dwRet--;
+ // др ещё будет в этом месяце или уже был...
+ else {
+ // др в этом месяце
+ if (stTime.wMonth == pcstSystemTime->wMonth)
+ // ещё только будет, не сегодня
+ if (stTime.wDay<pcstSystemTime->wDay)
+ 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<dwReplaceItemsCount;i++)
+ {
+ if (lstrlen((LPTSTR)plpInReplaceItems[i]) != (pdwInReplaceItemsCounts[i]/sizeof(TCHAR))) DebugBreak();
+ if (lstrlen((LPTSTR)plpOutReplaceItems[i]) != (pdwOutReplaceItemsCounts[i]/sizeof(TCHAR))) DebugBreak();
+ }
+ #endif
+
+ plpbtFounded = (LPBYTE*)mir_calloc((sizeof(LPBYTE)*dwReplaceItemsCount));
+ if (plpbtFounded) {
+ LPBYTE lpbtOutBuffCur, lpbtInBuffCur, lpbtInBuffCurPrev, lpbtOutBuffMax;
+ size_t i, dwFirstFoundIndex = 0, dwFoundCount = 0, dwMemPartToCopy;
+
+ lpbtInBuffCurPrev = (LPBYTE)lpInBuff;
+ lpbtOutBuffCur = (LPBYTE)lpOutBuff;
+ lpbtOutBuffMax = (((LPBYTE)lpOutBuff)+dwOutBuffSize);
+ for (i = 0; i < dwReplaceItemsCount; i++) {// looking for the first time
+ plpbtFounded[i] = (LPBYTE)MemoryFind((lpbtInBuffCurPrev-(LPBYTE)lpInBuff), lpInBuff, dwInBuffSize, plpInReplaceItems[i], pdwInReplaceItemsCounts[i]);
+ if (plpbtFounded[i])
+ dwFoundCount++;
+ }
+
+ while (dwFoundCount) {
+ for (i = 0; i < dwReplaceItemsCount; i++)
+ if (plpbtFounded[i] && (plpbtFounded[i] < plpbtFounded[dwFirstFoundIndex] || plpbtFounded[dwFirstFoundIndex] == NULL))
+ dwFirstFoundIndex = i;
+
+ if (plpbtFounded[dwFirstFoundIndex]) {// in found
+ dwMemPartToCopy = (plpbtFounded[dwFirstFoundIndex]-lpbtInBuffCurPrev);
+ if (lpbtOutBuffMax>(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<dwReplaceItemsCount;i++) {// looking for in next time
+ if (plpbtFounded[i] && plpbtFounded[i] < lpbtInBuffCurPrev) {
+ plpbtFounded[i] = (LPBYTE)MemoryFind((lpbtInBuffCurPrev-(LPBYTE)lpInBuff), lpInBuff, dwInBuffSize, plpInReplaceItems[i], pdwInReplaceItemsCounts[i]);
+ if (plpbtFounded[i] == NULL) dwFoundCount--;
+ }
+ }
+ }
+ else {
+ dwRetErrorCode = ERROR_BUFFER_OVERFLOW;
+ DebugBreak();
+ break;
+ }
+ }
+ else {// сюда по идее никогда не попадём, на всякий случай.
+ DebugBreak();
+ break;
+ }
+ }
+ lpbtInBuffCur = (((LPBYTE)lpInBuff)+dwInBuffSize);
+ memmove(lpbtOutBuffCur, lpbtInBuffCurPrev, (lpbtInBuffCur-lpbtInBuffCurPrev));lpbtOutBuffCur += (lpbtInBuffCur-lpbtInBuffCurPrev);
+ (*((WORD*)lpbtOutBuffCur)) = 0;
+
+ mir_free(plpbtFounded);
+
+ if (pdwOutBuffSize) (*pdwOutBuffSize) = (lpbtOutBuffCur-((LPBYTE)lpOutBuff));
+ }
+ else dwRetErrorCode = GetLastError();
+
+ return dwRetErrorCode;
+}
+
+static const LPTSTR lpszXMLTags[] = {TEXT("'"), TEXT("""), TEXT("&"), TEXT("<"), TEXT(">")};
+static const size_t dwXMLTagsCount[] = {(6*sizeof(TCHAR)), (6*sizeof(TCHAR)), (5*sizeof(TCHAR)), (4*sizeof(TCHAR)), (4*sizeof(TCHAR))};
+static const LPTSTR lpszXMLSymbols[] = {TEXT("\'"), TEXT("\""), TEXT("&"), TEXT("<"), TEXT(">")};
+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.timeout<MRA_TIMEOUT_CONN_MIN) nloc.timeout = MRA_TIMEOUT_CONN_MIN;
+ if (nloc.timeout>MRA_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;(i<MRA_MAX_MRIM_SERVER && m_iStatus != ID_STATUS_OFFLINE); i++) {
+ mir_snprintf(szHost, SIZEOF(szHost), "mrim%lu.mail.ru", i);
+
+ 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;
+ break;
+ }
+ }
+ }
+
+ if (bConnected && m_iStatus != ID_STATUS_OFFLINE)
+ MraNetworkDispatcher();
+ else {
+ if (bConnected == FALSE) {
+ ShowFormattedErrorMessage(L"Can't connect to MRIM server, error", GetLastError());
+ ProtoBroadcastAckAsync(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NONETWORK);
+ }
+ }
+
+ MraThreadClean();
+}
+
+void CMraProto::MraThreadClean()
+{
+ MraMPopSessionQueueFlush(hMPopSessionQueue);
+ Netlib_CloseHandle(hConnection);// called twice, if user set offline, its normal
+ hConnection = NULL;
+ dwCMDNum = 0;
+
+ SleepEx(100, FALSE);// to prevent high CPU load by some status plugins like allwaysonline
+
+ hThreadWorker = NULL;
+ InterlockedExchange((volatile LONG*)&dwThreadWorkerRunning, FALSE);
+ SetStatus(ID_STATUS_OFFLINE);
+}
+
+DWORD CMraProto::MraGetNLBData(LPSTR lpszHost, size_t dwHostBuffSize, WORD *pwPort)
+{
+ DWORD dwRetErrorCode;
+
+ BOOL bContinue = TRUE;
+ BYTE btBuff[MAX_PATH];
+ DWORD dwConnectReTryCount, dwCurConnectReTryCount;
+ LPSTR lpszPort;
+ size_t dwBytesReceived, dwRcvBuffSizeUsed = 0;
+ NETLIBSELECT nls = {0};
+ NETLIBOPENCONNECTION nloc = {0};
+
+ dwConnectReTryCount = mraGetDword(NULL, "ConnectReTryCountNLB", MRA_DEFAULT_CONN_RETRY_COUNT_NLB);
+
+ nloc.cbSize = sizeof(nloc);
+ nloc.flags = NLOCF_V2;
+ if (mraGetStaticStringA(NULL, "Server", (LPSTR)btBuff, SIZEOF(btBuff), NULL))
+ nloc.szHost = (LPSTR)btBuff;
+ else
+ nloc.szHost = MRA_DEFAULT_SERVER;
+
+ if ( IsHTTPSProxyUsed(hNetlibUser))
+ nloc.wPort = MRA_SERVER_PORT_HTTPS;
+ else
+ nloc.wPort = mraGetWord(NULL, "ServerPort", MRA_DEFAULT_SERVER_PORT);
+
+ nloc.timeout = mraGetDword(NULL, "TimeOutConnectNLB", MRA_DEFAULT_TIMEOUT_CONN_NLB);
+ if (nloc.timeout<MRA_TIMEOUT_CONN_MIN) nloc.timeout = MRA_TIMEOUT_CONN_MIN;
+ if (nloc.timeout>MRA_TIMEOUT_CONN_МАХ) 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<dwFeildsNum;i++)
+ GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &pmralpsValues[i]);
+
+ // write to DB and exit loop
+ if (dwAckType == ACKTYPE_GETINFO && hContact) {
+ mraSetDword(hContact, "InfoTS", (DWORD)_time32(NULL));
+ //MRA_LPS mralpsUsernameValue;
+ for (i = 0; i < dwFeildsNum; i++) {
+ if ( !_strnicmp(pmralpsFeilds[i].lpszData, "Username", 8))
+ ; //mralpsUsernameValue = pmralpsValues[i];
+ else if ( !_strnicmp(pmralpsFeilds[i].lpszData, "Domain", 6))
+ ;
+ else if ( !_strnicmp(pmralpsFeilds[i].lpszData, "Flags", 5))
+ ;
+ else if ( !_strnicmp(pmralpsFeilds[i].lpszData, "Nickname", 8))
+ mraSetLPSStringW(hContact, "Nick", &pmralpsValues[i]);
+ else if ( !_strnicmp(pmralpsFeilds[i].lpszData, "FirstName", 9))
+ mraSetLPSStringW(hContact, "FirstName", &pmralpsValues[i]);
+ else if ( !_strnicmp(pmralpsFeilds[i].lpszData, "LastName", 8))
+ mraSetLPSStringW(hContact, "LastName", &pmralpsValues[i]);
+ else if ( !_strnicmp(pmralpsFeilds[i].lpszData, "Sex", 3)) {
+ switch (StrToUNum32(pmralpsValues[i].lpszData, pmralpsValues[i].dwSize)) {
+ case 1:// мужской
+ mraSetByte(hContact, "Gender", 'M');
+ break;
+ case 2:// женский
+ mraSetByte(hContact, "Gender", 'F');
+ break;
+ default:// а фиг его знает
+ mraDelValue(hContact, "Gender");
+ break;
+ }
+ }
+ else if ( !_strnicmp(pmralpsFeilds[i].lpszData, "Birthday", 8)) {
+ if (pmralpsValues[i].dwSize > 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;i<dwFeildsNum;i++) {
+ if ( !_strnicmp(pmralpsFeilds[i].lpszData, "Username", 8))
+ mralpsUsernameValue = pmralpsValues[i];
+ else if ( !_strnicmp(pmralpsFeilds[i].lpszData, "Domain", 6)) { // имя было уже задано ранее
+ dwStringSize = MultiByteToWideChar(MRA_CODE_PAGE, 0, mralpsUsernameValue.lpszData, mralpsUsernameValue.dwSize, szEMail, SIZEOF(szEMail));
+
+ szEMail[dwStringSize] = (*((WCHAR*)L"@"));
+ dwStringSize++;
+
+ dwStringSize += MultiByteToWideChar(MRA_CODE_PAGE, 0, pmralpsValues[i].lpszData, pmralpsValues[i].dwSize, &szEMail[dwStringSize], (SIZEOF(szEMail)-(dwStringSize+1)));
+ szEMail[dwStringSize] = 0;
+ }
+ else if ( !_strnicmp(pmralpsFeilds[i].lpszData, "Nickname", 8)) {
+ dwStringSize = min((sizeof(szNick)-sizeof(WCHAR)), pmralpsValues[i].dwSize);
+ memmove(szNick, pmralpsValues[i].lpwszData, dwStringSize);
+ szNick[dwStringSize] = 0;
+ }
+ else if ( !_strnicmp(pmralpsFeilds[i].lpszData, "FirstName", 9)) {
+ dwStringSize = min((sizeof(szFirstName)-sizeof(WCHAR)), pmralpsValues[i].dwSize);
+ memmove(szFirstName, pmralpsValues[i].lpwszData, dwStringSize);
+ szFirstName[dwStringSize] = 0;
+ }
+ else if ( !_strnicmp(pmralpsFeilds[i].lpszData, "LastName", 8)) {
+ dwStringSize = min((sizeof(szLastName)-sizeof(WCHAR)), pmralpsValues[i].dwSize);
+ memmove(szLastName, pmralpsValues[i].lpwszData, dwStringSize);
+ szLastName[dwStringSize] = 0;
+ }
+ }// end for
+ ProtoBroadcastAck(m_szModuleName, hContact, dwAckType, ACKRESULT_DATA, (HANDLE)pmaHeader->seq, (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<dwTemp || dwTemp == 0)
+ MraUpdateEmailStatus(NULL, 0, NULL, 0, 0, 0);
+ break;
+
+ case MRIM_CS_GAME:
+ {
+ DWORD dwGameSessionID, dwGameMsg, dwGameMsgID;
+
+ GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsEMail);//LPS to/from
+ dwGameSessionID = GetUL(&lpbDataCurrent);//DWORD session unique per game
+ dwGameMsg = GetUL(&lpbDataCurrent);//DWORD msg internal game message
+ dwGameMsgID = GetUL(&lpbDataCurrent);//DWORD msg_id id for ack
+ dwTemp = GetUL(&lpbDataCurrent);//DWORD time_send time of client
+ GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsString);//LPS data
+
+ #ifdef _DEBUG
+ BYTE btBuff[1024] = {0};
+ memmove(btBuff, lpsString.lpszData, lpsString.dwSize);
+ #endif
+
+ switch (dwGameMsg) {
+ case GAME_CONNECTION_INVITE:
+ if (m_iStatus != ID_STATUS_INVISIBLE)
+ MraGame(lpsEMail.lpszData, lpsEMail.dwSize, dwGameSessionID, GAME_DECLINE, dwGameMsgID, lpsString.lpszData, lpsString.dwSize);
+ break;
+ case GAME_CONNECTION_ACCEPT:
+ break;
+ case GAME_DECLINE:
+ break;
+ case GAME_INC_VERSION:
+ break;
+ case GAME_NO_SUCH_GAME:// user invisible
+ if ((hContact = MraHContactFromEmail(lpsEMail.lpszData, lpsEMail.dwSize, FALSE, TRUE, NULL)))
+ if (MraGetContactStatus(hContact) == ID_STATUS_OFFLINE)
+ MraSetContactStatus(hContact, ID_STATUS_INVISIBLE);
+ break;
+ case GAME_JOIN:
+ break;
+ case GAME_CLOSE:
+ break;
+ case GAME_SPEED:
+ break;
+ case GAME_SYNCHRONIZATION:
+ break;
+ case GAME_USER_NOT_FOUND:
+ break;
+ case GAME_ACCEPT_ACK:
+ break;
+ case GAME_PING:
+ break;
+ case GAME_RESULT:
+ break;
+ case GAME_MESSAGES_NUMBER:
+ break;
+ default:
+ mir_sntprintf(szBuff, SIZEOF(szBuff), TranslateW(L"MRIM_CS_GAME: unknown internal game message code: %lu"), dwGameMsg);
+ MraPopupShowFromAgentW(MRA_POPUP_TYPE_DEBUG, 0, szBuff);
+ break;
+ }
+ }
+ break;
+ case MRIM_CS_CONTACT_LIST2:
+ dwTemp = GetUL(&lpbDataCurrent);
+ if (dwTemp == GET_CONTACTS_OK) { // received contact list
+ BOOL bAdded;
+ char szGroupMask[MAX_PATH], szContactMask[MAX_PATH];
+ DWORD dwID, dwGroupFlags, dwContactFlag, dwGroupID, dwContactSeverFlags, dwStatus, dwXStatus, dwFutureFlags, dwBlogStatusTime;
+ MRA_LPS mralpsGroupName, mralpsNick, mralpsCustomPhones, lpsSpecStatusUri, lpsStatusTitle, lpsStatusDesc, lpsUserAgentFormated, lpsBlogStatus, lpsBlogStatusMusic;
+ size_t i, j, dwGroupsCount, dwGroupMaskSize, dwContactMaskSize, dwControlParam;
+ ULARGE_INTEGER dwBlogStatusID;
+
+ dwGroupsCount = GetUL(&lpbDataCurrent);
+
+ GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsString);
+ dwGroupMaskSize = lpsString.dwSize;
+ memmove(szGroupMask, lpsString.lpszData, dwGroupMaskSize);(*(szGroupMask+dwGroupMaskSize)) = 0;
+
+ GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsString);
+ dwContactMaskSize = lpsString.dwSize;
+ memmove(szContactMask, lpsString.lpszData, dwContactMaskSize);(*(szContactMask+dwContactMaskSize)) = 0;
+
+ DebugPrintCRLFW(L"Groups:");
+ DebugPrintCRLFA(szGroupMask);
+ dwID = 0;
+ for (i = 0; i < dwGroupsCount; i++) { //groups handle
+ dwControlParam = 0;
+ for (j = 0; j < dwGroupMaskSize; j++) { //enumerating parameters
+ switch (szGroupMask[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 && szGroupMask[j] == 'u') {// GroupFlags
+ dwGroupFlags = dwTemp;
+ dwControlParam++;
+ }
+ else if (j == 1 && szGroupMask[j] == 's') {// GroupName
+ mralpsGroupName = lpsString;
+ dwControlParam++;
+ }
+ }
+
+ // add/modify group
+ if (dwControlParam > 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), "<sms_response><source>Mail.ru</source><deliverable>Yes</deliverable><network>Mail.ru, Russia</network><message_id>%s-1-1955988055-%s</message_id><destination>%s</destination><messages_left>0</messages_left></sms_response>\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 || dwAckType<dwTemp || dwTemp == 0)
+ MraUpdateEmailStatus(lpsEMail.lpszData, lpsEMail.dwSize, lpsString.lpszData, lpsString.dwSize, dwDate, dwUIDL);
+ }
+ break;
+
+ case MRIM_CS_USER_BLOG_STATUS:
+ {
+ DWORD dwTime, dwFlags;
+ MRA_LPS lpsText;
+ LPBYTE lpbBuff = NULL;
+ DWORDLONG dwBlogStatusID;
+
+ dwFlags = GetUL(&lpbDataCurrent);// UL flags
+ GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsEMail);// LPS user
+ dwBlogStatusID = GetUIDL(&lpbDataCurrent);// UINT64 id
+ dwTime = GetUL(&lpbDataCurrent);// UL time
+ GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsText);// LPS text (MRIM_BLOG_STATUS_MUSIC: track)
+ GetLPS(lpbData, dwDataSize, &lpbDataCurrent, &lpsString);// LPS reply_user_nick
+
+ if ((hContact = MraHContactFromEmail(lpsEMail.lpszData, lpsEMail.dwSize, FALSE, TRUE, NULL))) {
+ if (dwFlags & MRIM_BLOG_STATUS_MUSIC)
+ mraSetLPSStringW(hContact, DBSETTING_BLOGSTATUSMUSIC, &lpsText);
+ else {
+ mraSetDword(hContact, DBSETTING_BLOGSTATUSTIME, dwTime);
+ mraWriteContactSettingBlob(hContact, DBSETTING_BLOGSTATUSID, &dwBlogStatusID, sizeof(DWORDLONG));
+ mraSetLPSStringW(hContact, DBSETTING_BLOGSTATUS, &lpsText);
+ }
+ }
+ }
+ break;
+
+ case MRIM_CS_UNKNOWN:
+ case MRIM_CS_USER_GEO:
+ case MRIM_CS_SERVER_SETTINGS:
+ break;
+
+ default:
+ #ifdef _DEBUG
+ BYTE btBuff[8192] = {0};
+ memmove(btBuff, lpbData, dwDataSize);
+ DebugBreak();
+ #endif
+ break;
+ }
+ return 0;
+}
+
+DWORD CMraProto::MraRecvCommand_Message(DWORD dwTime, DWORD dwFlags, MRA_LPS *plpsFrom, MRA_LPS *plpsText, MRA_LPS *plpsRFTText, MRA_LPS *plpsMultiChatData)
+{// Сообщение
+ BOOL bAdded;
+ DWORD dwRetErrorCode = NO_ERROR, dwBackColour;
+ LPSTR lpszMessageExt = NULL;
+ LPWSTR lpwszMessage = NULL;
+ size_t dwMessageSize = 0, dwMessageExtSize = 0;
+ CCSDATA ccs = {0};
+ PROTORECVEVENT pre = {0};
+
+ //ccs.wParam = 0;
+ ccs.lParam = (LPARAM)⪯
+ pre.timestamp = dwTime;
+
+ // check flags and datas
+ if (dwFlags & MESSAGE_FLAG_RTF) {
+ if (plpsRFTText) {
+ if (plpsRFTText->lpszData == 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)), "<sms_delivery_receipt><message_id>%s-1-1955988055-%s</message_id><destination>%s</destination><delivered>No</delivered><submition_time>%s</submition_time><error_code>0</error_code><error><id>15</id><params><param>%s</param></params></error></sms_delivery_receipt>", 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)), "<sms_message><source>Mail.ru</source><destination_UIN>%s</destination_UIN><sender>%s</sender><senders_network>Mail.ru</senders_network><text>%s</text><time>%s</time></sms_message>", 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<WCHAR> 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 <rozhuk.im@gmail.com>
+ * 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<dwEncodedSize))
+ {// выходной буффер слишком мал
+ dwRetErrorCode=ERROR_INSUFFICIENT_BUFFER;
+ }else{// размер выходного буффера достаточен
+ dwEncodedSize=0;
+ if(lpcSource && lpcDestination && dwSourceSize)
+ {
+#ifdef _WIN64
+ LPBYTE lpbtSource=(LPBYTE)lpcSource,lpbtDestination=(LPBYTE)lpcDestination;
+ size_t i;
+
+ for (i=0;i<dwSourceSize;i+=3)
+ {
+ *(lpbtDestination++)=pbtCodingTableBASE64[(*lpbtSource)>>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 ((dwDestinationSize<dwDecodedSize))
+ {// выходной буффер слишком мал
+ dwRetErrorCode=ERROR_INSUFFICIENT_BUFFER;
+ }else{// размер выходного буффера достаточен
+ dwDecodedSize=0;
+ if(lpcSource && lpcDestination)
+ {// буффера в порядке
+ if (dwSourceSize>3)
+ {
+#ifdef _WIN64
+ LPBYTE lpbtSource=(LPBYTE)lpcSource,lpbtDestination=(LPBYTE)lpcDestination;
+
+ for(size_t i=0;i<dwSourceSize;i+=4)
+ {
+ *(lpbtDestination++)=(unsigned char) (btDeCodingTableBASE64[(*lpbtSource)] << 2 | btDeCodingTableBASE64[lpbtSource[1]] >> 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 <rozhuk.im@gmail.com>
+ * 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 <rozhuk.im@gmail.com>
+ * 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 <intrin.h>
+ #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 <rozhuk.im@gmail.com>
+ * 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 <ListMT.h>
+#include <InterlockedFunctions.h>
+
+
+
+
+
+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 <rozhuk.im@gmail.com>
+ * 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 <rozhuk.im@gmail.com>
+ * 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 <StrToNum.h>
+#include <MemoryFind.h>
+#include <MemoryFindByte.h>
+
+
+
+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: <US-ASCII HT, horizontal-tab (9)> || <US-ASCII SP, space (32)>
+ {
+ 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 && pSPEnd<pEnd) pSPEnd++;
+
+ // check SP on line start
+ if ((pSPStart-1)>lpszBuff)
+ {
+ 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 <rozhuk.im@gmail.com>
+ * 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 <InterlockedFunctions.h>
+
+#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 <rozhuk.im@gmail.com>
+ * 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<lpString2 >> 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<dwBuff2Size)
+ {
+ uiRet=CMEM_LESS_THAN;
+ }else{
+ uiRet=CMEM_GREATER_THAN;
+ }
+ }
+return(uiRet);
+}
+
+
+
+#endif // !defined(AFX_MEMORYCOMPARE__H__INCLUDED_)
diff --git a/protocols/MRA/src/Sdk/MemoryFind.h b/protocols/MRA/src/Sdk/MemoryFind.h new file mode 100644 index 0000000000..860c5ce20a --- /dev/null +++ b/protocols/MRA/src/Sdk/MemoryFind.h @@ -0,0 +1,80 @@ +/*
+ * Copyright (c) 2003 Rozhuk Ivan <rozhuk.im@gmail.com>
+ * 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 <rozhuk.im@gmail.com>
+ * 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 && dwFrom<dwBuffSize)
+ {
+ pRet=(void*)memchr((const void*)(((size_t)pBuff)+dwFrom),chWhatFind,(dwBuffSize-dwFrom));
+ }
+return(pRet);
+}
+
+
+#ifndef _WIN64
+__inline void *MemoryFindByteReverse(size_t dwFrom,const void *pBuff,size_t dwBuffSize,unsigned char chWhatFind)
+{
+ void *pRet=NULL;
+
+ __asm
+ {
+ push ebx // сохраняем регистр
+ push edi // сохраняем регистр
+ push esi // сохраняем регистр
+
+ mov ecx,dwBuffSize
+ test ecx,ecx //; проверка входного параметра, он !=0
+ je short end_func
+
+ mov edi,pBuff //; di = string
+ test edi,edi //; проверка входного параметра, он !=0
+ jz short end_func
+
+ mov eax,dwFrom
+
+/////////////////////////////////////////////
+ cmp eax,ecx //; проверка ecx(=len)=>dwFrom
+ 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 <rozhuk.im@gmail.com>
+ * 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<dwReplaceItemsCount;i++)
+ {// loking for in first time
+ ppFounded[i]=(unsigned char*)MemoryFind((pSrcBuffCurPrev-(unsigned char*)pSrcBuff),pSrcBuff,dwSrcBuffSize,ppInReplaceItems[i],pdwInReplaceItemsCounts[i]);
+ if (ppFounded[i]) dwFoundedCount++;
+ }
+
+ while(dwFoundedCount)
+ {
+ for(i=0;i<dwReplaceItemsCount;i++)
+ {// looking for first to replace
+ if (ppFounded[i] && (ppFounded[i]<ppFounded[dwFirstFoundedIndex] || ppFounded[dwFirstFoundedIndex]==NULL)) dwFirstFoundedIndex=i;
+ }
+
+ if (ppFounded[dwFirstFoundedIndex])
+ {// in founded
+ dwMemPartToCopy=(ppFounded[dwFirstFoundedIndex]-pSrcBuffCurPrev);
+ if (pDstBuffMax>(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<dwReplaceItemsCount;i++)
+ {// loking for in next time // update founded records
+ if (ppFounded[i] && ppFounded[i]<pSrcBuffCurPrev)
+ {
+ ppFounded[i]=(unsigned char*)MemoryFind((pSrcBuffCurPrev-(unsigned char*)pSrcBuff),pSrcBuff,dwSrcBuffSize,ppInReplaceItems[i],pdwInReplaceItemsCounts[i]);
+ if (ppFounded[i]==NULL) dwFoundedCount--;
+ }
+ }
+ }else{// ERROR_BUFFER_OVERFLOW
+ iRet=-2;
+ DebugBreak();
+ break;
+ }
+ }else{// сюда по идее никогда не попадём, на всякий случай.
+ DebugBreak();
+ break;
+ }
+ }
+ pSrcBuffCur=(((unsigned char*)pSrcBuff)+dwSrcBuffSize);
+ memmove(pDstBuffCur,pSrcBuffCurPrev,(pSrcBuffCur-pSrcBuffCurPrev));
+ pDstBuffCur+=(pSrcBuffCur-pSrcBuffCurPrev);
+ (*((unsigned short*)pDstBuffCur))=0;
+
+ MEMORY_REPLACE_MEMFREE(ppFounded);
+
+ if (pdwDstBuffSize) (*pdwDstBuffSize)=(pDstBuffCur-((unsigned char*)pDstBuff));
+ if (pdwReplacesCount) (*pdwReplacesCount)=dwReplacesCount;
+ iRet=0;
+ }else{
+ iRet=-3;
+ }
+ }
+ }
+return(iRet);
+}
+
+
+#endif // !defined(AFX_MEMORY_REPLACE__H__INCLUDED_)
diff --git a/protocols/MRA/src/Sdk/RC4.h b/protocols/MRA/src/Sdk/RC4.h new file mode 100644 index 0000000000..cb6331a183 --- /dev/null +++ b/protocols/MRA/src/Sdk/RC4.h @@ -0,0 +1,103 @@ +/*
+ * Copyright (c) 2007 Rozhuk Ivan <rozhuk.im@gmail.com>
+ * 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<dwBuffSize;x++)
+ {
+ //increment i
+ i=(i+1U)%256U;
+ //increment j
+ j=(j+(unsigned long)Sbox[i])%256U;
+
+ //Scramble SBox #1 further so encryption routine will
+ //will repeat itself at great interval
+ temp=Sbox[i];
+ Sbox[i]=Sbox[j];
+ Sbox[j]=temp;
+
+ //Get ready to create pseudo random byte for encryption lpKey
+ t=((unsigned long)Sbox[i]+(unsigned long)Sbox[j])%256U;
+
+ //get the random byte
+ //xor with the data and done
+ lpBuff[x]=(lpBuff[x]^Sbox[t]);
+ }
+}
+
+
+
+#endif // !defined(AFX_RC4__H__INCLUDED_)
+
+
diff --git a/protocols/MRA/src/Sdk/SHA1.h b/protocols/MRA/src/Sdk/SHA1.h new file mode 100644 index 0000000000..f7d4643d32 --- /dev/null +++ b/protocols/MRA/src/Sdk/SHA1.h @@ -0,0 +1,596 @@ +/*
+ * Copyright (c) 2003 Rozhuk Ivan <rozhuk.im@gmail.com>
+ * 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 <stdint.h> (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;i<dwSize;i++) pDestination[i]=pSource[(i&~0x00000003)+(3-(i&0x00000003))];
+ for(size_t i=0;i<dwSize;i+=4) (*((DWORD*)(pDestination+i)))=BSWAP((*((DWORD*)(pSource+i))));
+
+#else
+ __asm{
+ push edi // сохраняем регистр
+ push esi // сохраняем регистр
+
+ mov ecx,dwSize // ecx = длинна входного буффера
+ mov edi,lpcDestination // edi = адрес выходного буффера
+ mov esi,lpcSource // esi = указатель на входной буффер
+ cld
+
+ read_loop:
+ lodsd // читаем 4 байта
+ bswap eax
+ stosd
+ sub ecx,4
+ jg short read_loop // если длинна 3 и более байт, то продолжаем дальше
+
+ pop esi // восстанавливаем содержимое регистра
+ pop edi // восстанавливаем содержимое регистра
+ }
+#endif
+}
+
+
+
+/*
+* SHA1ProcessMessageBlock
+*
+* Description:
+* This function will process the next 512 bits of the message
+* stored in the Message_Block array.
+*
+* Parameters:
+* None.
+*
+* Returns:
+* Nothing.
+*
+* Comments:
+* Many of the variable names in this code, especially the
+* single character names, were used because those were the
+* names used in the publication.
+*
+*
+*/
+__inline void SHA1ProcessMessageBlock(SHA1Context *context,BYTE *Message_Block)
+{
+ /* Constants defined in SHA-1 */
+ const DWORD K[]={0x5A827999,0x6ED9EBA1,0x8F1BBCDC,0xCA62C1D6};
+ DWORD t; /* Loop counter */
+ DWORD temp; /* Temporary word value */
+ DWORD W[80]; /* Word sequence */
+ DWORD A=context->Intermediate_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)<length;i+=64) SHA1ProcessMessageBlock(context,(BYTE*)&message_array[i]);
+ Message_Block_Index=0;
+ }else{
+ i=0;
+ }
+ /* Buffer remaining input */
+ memmove(&context->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<SHA1HashSize;i++)
+ {
+ j=(Bin[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<SHA1HashSize;i++,p+=2)
+ {
+ wsprintfW((LPWSTR)(lpszDigest+p),L"%02x",digest[i]);
+ }
+ lpszDigest[SHA1HashHexSize]=0;
+};
+////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////
+__inline void SHA1HMACGetDigest(LPVOID lpBuff,size_t dwBuffSize,LPVOID lpKey,size_t dwKeySize,BYTE *digest)
+{
+ hmac_sha1((BYTE*)lpBuff,dwBuffSize,(BYTE*)lpKey,dwKeySize,digest);
+}
+
+
+__inline void SHA1HMACGetStringA(LPSTR lpszBuff,size_t dwBuffSize,LPSTR lpszKey,size_t dwKeySize,LPSTR lpszDigest)
+{
+ BYTE digest[SHA1HashSize];
+ hmac_sha1((BYTE*)lpszBuff,dwBuffSize,(BYTE*)lpszKey,dwKeySize,digest);
+ SHA1CvtHex(digest,(BYTE*)lpszDigest);
+}
+
+
+__inline void SHA1HMACGetStringW(LPWSTR lpszBuff,size_t dwBuffSize,LPWSTR lpszKey,size_t dwKeySize,LPWSTR lpszDigest)
+{
+ BYTE digest[SHA1HashSize];
+ hmac_sha1((BYTE*)lpszBuff,dwBuffSize,(BYTE*)lpszKey,dwKeySize,digest);
+ SHA1CvtStringW(digest,lpszDigest);
+}
+
+
+
+__inline void SHA1GetDigest(LPVOID lpBuff,size_t dwBuffSize,BYTE *digest)
+{
+ SHA1Context sha;
+
+ SHA1Reset(&sha);
+ SHA1Input(&sha,(BYTE*)lpBuff,dwBuffSize);
+ SHA1Result(&sha,digest);
+}
+
+
+__inline void SHA1GetStringDigestA(LPSTR lpszBuff,size_t dwBuffSize,LPSTR lpszDigest)
+{
+ SHA1Context sha;
+ BYTE digest[SHA1HashSize];
+
+ SHA1Reset(&sha);
+ SHA1Input(&sha,(BYTE*)lpszBuff,dwBuffSize);
+ SHA1Result(&sha,digest);
+
+ SHA1CvtHex(digest,(BYTE*)lpszDigest);
+}
+
+
+__inline void SHA1GetStringDigestW(LPWSTR lpszBuff,size_t dwBuffSize,LPWSTR lpszDigest)
+{
+ SHA1Context sha;
+ BYTE digest[SHA1HashSize];
+
+ SHA1Reset(&sha);
+ SHA1Input(&sha,(BYTE*)lpszBuff,dwBuffSize);
+ SHA1Result(&sha,digest);
+
+ SHA1CvtStringW(digest,lpszDigest);
+}
+
+
+
+
+#endif //AFX__SHA1_H__INCLUDED_
\ No newline at end of file diff --git a/protocols/MRA/src/Sdk/SocketFunctions.h b/protocols/MRA/src/Sdk/SocketFunctions.h new file mode 100644 index 0000000000..0d609d80f9 --- /dev/null +++ b/protocols/MRA/src/Sdk/SocketFunctions.h @@ -0,0 +1,485 @@ +/*
+ * Copyright (c) 2003 Rozhuk Ivan <rozhuk.im@gmail.com>
+ * 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 <rozhuk.im@gmail.com>
+ * 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 <rozhuk.im@gmail.com>
+ * 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 <rozhuk.im@gmail.com>
+ * 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 <windows.h>
+#include <wincrypt.h>
+#include <shlwapi.h>
+#include <winsock2.h>
+#include <mswsock.h>
+#include <WS2tcpip.h>
+#include <PrSht.h>
+#include <Commdlg.h>
+//#include <strsafe.h>
+
+
+#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 <rozhuk.im@gmail.com>
+ * 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 <windows.h>
+#include <time.h>
+
+
+
+#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 <windows.h> + /* 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 <sys/types.h> /* 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 <unistd.h> /* for SEEK_* and off_t */ +# ifdef VMS +# include <unixio.h> /* 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 <sys/types.h>
+
+#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 "<major>.<minor>".
+
+
+#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
|