diff options
author | Kirill Volinsky <mataes2007@gmail.com> | 2012-10-13 08:54:34 +0000 |
---|---|---|
committer | Kirill Volinsky <mataes2007@gmail.com> | 2012-10-13 08:54:34 +0000 |
commit | de6eb3e4bc30eff928dc932c03812ede3077926a (patch) | |
tree | 966a57948af890b1c47699e5ec0db23a26a7add9 /protocols/MRA/src/MraAvatars.cpp | |
parent | 870d3d99c22c77a94a352ad292ed67e8eb81edf0 (diff) |
MRA: folders restructurization
git-svn-id: http://svn.miranda-ng.org/main/trunk@1900 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'protocols/MRA/src/MraAvatars.cpp')
-rw-r--r-- | protocols/MRA/src/MraAvatars.cpp | 755 |
1 files changed, 755 insertions, 0 deletions
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;
+}
|