From 3b55a62fdcb1f8222de3c2c8fbed530792c419a0 Mon Sep 17 00:00:00 2001 From: Vadim Dashevskiy Date: Fri, 12 Oct 2012 14:53:57 +0000 Subject: GTalkExt, ICQ, IRC, Jabber: folders restructurization git-svn-id: http://svn.miranda-ng.org/main/trunk@1890 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- protocols/GTalkExt/src/inbox.cpp | 402 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 402 insertions(+) create mode 100644 protocols/GTalkExt/src/inbox.cpp (limited to 'protocols/GTalkExt/src/inbox.cpp') diff --git a/protocols/GTalkExt/src/inbox.cpp b/protocols/GTalkExt/src/inbox.cpp new file mode 100644 index 0000000000..53a4aa2fcb --- /dev/null +++ b/protocols/GTalkExt/src/inbox.cpp @@ -0,0 +1,402 @@ +//*************************************************************************************** +// +// Google Extension plugin for the Miranda IM's Jabber protocol +// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +//*************************************************************************************** + +#include "stdafx.h" +#include "inbox.h" +#include "notifications.h" +#include "db.h" +#include "options.h" + +static const LPTSTR COMMON_GMAIL_HOST1 = _T("gmail.com"); +static const LPTSTR COMMON_GMAIL_HOST2 = _T("googlemail.com"); + +static const LPSTR AUTH_REQUEST_URL = "https://www.google.com/accounts/ClientAuth"; +static const LPSTR AUTH_REQUEST_PARAMS = "Email=%s&Passwd=%s&" + "accountType=HOSTED_OR_GOOGLE&" + "skipvpage=true&" + "PersistentCookie=false"; + +static const LPSTR ISSUE_TOKEN_REQUEST_URL = "https://www.google.com/accounts/IssueAuthToken"; +static const LPSTR ISSUE_TOKEN_REQUEST_PARAMS = "SID=%s&LSID=%s&" + "Session=true&" + "skipvpage=true&" + "service=gaia"; + +static const LPSTR TOKEN_AUTH_URL = "https://www.google.com/accounts/TokenAuth?"\ + "auth=%s&" + "service=mail&" + "continue=%s&" + "source=googletalk"; + + +static const NETLIBHTTPHEADER HEADER_URL_ENCODED = {"Content-Type", "application/x-www-form-urlencoded"}; +static const int HTTP_OK = 200; + +static const LPSTR SID_KEY_NAME = "SID="; +static const LPSTR LSID_KEY_NAME = "LSID="; + +static const LPSTR LOGIN_PASS_SETTING_NAME = "LoginPassword"; + +static const LPTSTR INBOX_URL_FORMAT = _T("https://mail.google.com/%s%s/#inbox"); + +static const DWORD SIZE_OF_JABBER_OPTIONS = 243 * sizeof(DWORD); + +// 3 lines from netlib.h +#define GetNetlibHandleType(h) (h?*(int*)h:NLH_INVALID) +#define NLH_INVALID 0 +#define NLH_USER 'USER' + +char to_hex(char code) { + static char hex[] = "0123456789abcdef"; + return hex[code & 15]; +} + +char *url_encode(char *str) { + char *pstr = str, *buf = (char*)malloc(strlen(str) * 3 + 1), *pbuf = buf; + while (*pstr) { + if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == ',' || *pstr == '~') + *pbuf++ = *pstr; + else if (*pstr == ' ') + *pbuf++ = '+'; + else + *pbuf++ = '%', *pbuf++ = to_hex(*pstr >> 4), *pbuf++ = to_hex(*pstr & 15); + pstr++; + } + *pbuf = '\0'; + return buf; +} + +LPSTR HttpPost(HANDLE hUser, LPSTR reqUrl, LPSTR reqParams) +{ + NETLIBHTTPREQUEST nlhr = {0}; + nlhr.cbSize = sizeof(nlhr); + nlhr.requestType = REQUEST_POST; + nlhr.flags = NLHRF_GENERATEHOST | NLHRF_SMARTAUTHHEADER | NLHRF_HTTP11 | NLHRF_SSL | NLHRF_NODUMP | NLHRF_NODUMPHEADERS; + nlhr.szUrl = reqUrl; + nlhr.headers = (NETLIBHTTPHEADER*)&HEADER_URL_ENCODED; + nlhr.headersCount = 1; + nlhr.pData = reqParams; + nlhr.dataLength = lstrlenA(reqParams); + + NETLIBHTTPREQUEST *pResp = (NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)hUser, (LPARAM)&nlhr); + if (!pResp) return NULL; + __try { + if (HTTP_OK == pResp->resultCode) + return _strdup(pResp->pData); + else + return NULL; + } + __finally { + CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)pResp); + } +} + +LPSTR MakeRequest(HANDLE hUser, LPSTR reqUrl, LPSTR reqParamsFormat, LPSTR p1, LPSTR p2) +{ + LPSTR encodedP1 = url_encode(p1); + __try { + LPSTR encodedP2 = url_encode(p2); + __try { + LPSTR reqParams = (LPSTR)malloc(lstrlenA(reqParamsFormat) + 1 + lstrlenA(encodedP1) + lstrlenA(encodedP2)); + __try { + sprintf(reqParams, reqParamsFormat, encodedP1, encodedP2); + return HttpPost(hUser, reqUrl, reqParams); + } + __finally { + free(reqParams); + } + } + __finally { + free(encodedP2); + } + } + __finally { + free(encodedP1); + } +} + +LPSTR FindSid(LPSTR resp, LPSTR *LSID) +{ + LPSTR SID = strstr(resp, SID_KEY_NAME); + *LSID = strstr(resp, LSID_KEY_NAME); + if (!SID || !*LSID) return NULL; + + if (SID - 1 == *LSID) SID = strstr(SID + 1, SID_KEY_NAME); + if (!SID) return NULL; + + SID += lstrlenA(SID_KEY_NAME); + LPSTR term = strstr(SID, "\n"); + if (term) term[0] = 0; + + *LSID += lstrlenA(LSID_KEY_NAME); + term = strstr(*LSID, "\n"); + if (term) term[0] = 0; + + return SID; +} + +void DoOpenUrl(LPSTR tokenResp, LPSTR url) +{ + LPSTR encodedUrl = url_encode(url); + __try { + LPSTR encodedToken = url_encode(tokenResp); + __try { + LPSTR composedUrl = (LPSTR)malloc(lstrlenA(TOKEN_AUTH_URL) + 1 + lstrlenA(encodedToken) + lstrlenA(encodedUrl)); + __try { + sprintf(composedUrl, TOKEN_AUTH_URL, encodedToken, encodedUrl); + ShellExecuteA(0, NULL, composedUrl, NULL, NULL, SW_SHOW); + } + __finally { + free(composedUrl); + } + } + __finally { + free(encodedToken); + } + } + __finally { + free(encodedUrl); + } +} + +BOOL AuthAndOpen(HANDLE hUser, LPSTR url, LPSTR mailbox, LPSTR pwd) +{ + LPSTR authResp = MakeRequest(hUser, AUTH_REQUEST_URL, AUTH_REQUEST_PARAMS, mailbox, pwd); + if (!authResp) return FALSE; + + __try { + LPSTR LSID; + LPSTR SID = FindSid(authResp, &LSID); + LPSTR tokenResp = MakeRequest(hUser, ISSUE_TOKEN_REQUEST_URL, ISSUE_TOKEN_REQUEST_PARAMS, SID, LSID); + if (!tokenResp) return FALSE; + + __try { + DoOpenUrl(tokenResp, url); + return TRUE; + } + __finally { + free(tokenResp); + } + } + __finally { + free(authResp); + } +} + +struct OPEN_URL_HEADER { + LPSTR url; + LPSTR mailbox; + LPSTR pwd; + LPCSTR acc; +}; + +HANDLE FindNetUserHandle(LPCSTR acc) +{ + IJabberInterface *ji = getJabberApi(acc); + if (!ji) return NULL; + + PBYTE m_psProto = *(PBYTE*)((PBYTE)ji + sizeof(*ji)); // see CJabberInterface in jabber_proto.h + + PHANDLE pResult = (PHANDLE)(m_psProto + // see CJabberProto in jabber_proto.h + sizeof(PVOID) + // skip vtable ptr + sizeof(PVOID) + // skip m_ThreadInfo + SIZE_OF_JABBER_OPTIONS); // skip m_options + + for (int i=0; i < 100; i++) { + __try { + if (GetNetlibHandleType(*pResult) == NLH_USER) + break; + } + __except (EXCEPTION_EXECUTE_HANDLER){ + } + pResult++; + } + + assert(GetNetlibHandleType(*pResult) == NLH_USER); + return *pResult; +} + +unsigned __stdcall OpenUrlThread(OPEN_URL_HEADER* data) +{ + __try { + HANDLE hUser = FindNetUserHandle(data->acc); + if (!hUser || !AuthAndOpen(hUser, data->url, data->mailbox, data->pwd)) + ShellExecuteA(0, NULL, data->url, NULL, NULL, SW_SHOW); + } + __finally { + free(data); + } + return 0; +} + +void __forceinline DecryptString(LPSTR str, int len) +{ + for (--len; len >= 0; len--) + { + const char c = str[len] ^ 0xc3; + if (c) str[len] = c; + } +} + +int GetMailboxPwd(LPCSTR acc, LPCTSTR mailbox, LPSTR *pwd, int buffSize) +{ + char buff[256]; + + DBCONTACTGETSETTING cgs; + DBVARIANT dbv; + cgs.szModule = acc; + cgs.szSetting = LOGIN_PASS_SETTING_NAME; + cgs.pValue = &dbv; + dbv.type = DBVT_ASCIIZ; + dbv.pszVal = &buff[0]; + dbv.cchVal = sizeof(buff); + if (CallService(MS_DB_CONTACT_GETSETTINGSTATIC, 0, (LPARAM)&cgs)) + return 0; + + int result = dbv.cchVal; + + if (pwd) { + if (buffSize < result + 1) result = buffSize - 1; + memcpy(*pwd, &buff, result + 1); + DecryptString(*pwd, result); + } + + return result; +} + +BOOL OpenUrlWithAuth(LPCSTR acc, LPCTSTR mailbox, LPCTSTR url) +{ + int pwdLen = GetMailboxPwd(acc, mailbox, NULL, 0); + if (!pwdLen++) return FALSE; + + int urlLen = lstrlen(url) + 1; + int mailboxLen = lstrlen(mailbox) + 1; + + OPEN_URL_HEADER *data = (OPEN_URL_HEADER*)malloc(sizeof(OPEN_URL_HEADER) + urlLen + mailboxLen + pwdLen); + __try { + data->url = (LPSTR)data + sizeof(OPEN_URL_HEADER); + LPSTR ansi = WtoA(url); + __try { + memcpy(data->url, ansi, urlLen); + } + __finally { + free(ansi); + } + + data->mailbox = data->url + urlLen; + ansi = WtoA(mailbox); + __try { + memcpy(data->mailbox, ansi, mailboxLen); + } + __finally { + free(ansi); + } + + data->pwd = data->mailbox + mailboxLen; + if (!GetMailboxPwd(acc, mailbox, &data->pwd, pwdLen)) return FALSE; + + data->acc = acc; + + if (HANDLE h = mir_forkthreadex((pThreadFuncEx)OpenUrlThread, data, NULL)) { + CloseHandle(h); + data = NULL; + } + else return FALSE; + } + __finally { + free(data); + } + + return TRUE; +} + +unsigned __stdcall ShellExecuteThread(PVOID param) +{ + __try { + ShellExecute(0, NULL, (LPTSTR)param, NULL, NULL, SW_SHOW); + } + __finally { + free(param); + } + return 0; +} + +void StartShellExecuteThread(LPCTSTR url) +{ + LPTSTR urlCopy = _tcsdup(url); + __try { + if (HANDLE h = mir_forkthreadex(ShellExecuteThread, urlCopy, NULL)) { + CloseHandle(h); + urlCopy = NULL; + } + } + __finally { + free(urlCopy); + } +} + +void OpenUrl(LPCSTR acc, LPCTSTR mailbox, LPCTSTR url) +{ + extern DWORD itlsSettings; + if (!ReadCheckbox(0, IDC_AUTHONMAILBOX, (DWORD)TlsGetValue(itlsSettings)) || + !OpenUrlWithAuth(acc, mailbox, url)) + StartShellExecuteThread(url); +} + +LPTSTR CraftInboxUrl(LPTSTR jid) +{ + LPTSTR host = _tcsstr(jid, _T("@")) + 1; + + LPTSTR result = (LPTSTR)malloc((lstrlen(INBOX_URL_FORMAT) + 1 + lstrlen(jid)) * sizeof(TCHAR)); + __try { + if (lstrcmpi(host, COMMON_GMAIL_HOST1) && lstrcmpi(host, COMMON_GMAIL_HOST2)) + wsprintf(result, INBOX_URL_FORMAT, _T("a/"), host); // hosted + else + wsprintf(result, INBOX_URL_FORMAT, NULL, _T("mail")); // common + } + __except ( + free(result), + EXCEPTION_CONTINUE_SEARCH + ) {} + + return result; +} + +void OpenContactInbox(HANDLE hContact) +{ + LPSTR acc = (LPSTR)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + if (!acc) return; + + DBVARIANT dbv; + if (!DBGetContactSettingTString(0, acc, "jid", &dbv)) + __try { + LPTSTR url = CraftInboxUrl(dbv.ptszVal); + __try { + OpenUrl(acc, dbv.ptszVal, url); + } + __finally { + free(url); + } + } + __finally { + DBFreeVariant(&dbv); + } +} -- cgit v1.2.3