/* Miranda Crash Dumper Plugin Copyright (C) 2008 - 2012 Boris Krasnovskiy All Rights Reserved 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 version 2 of the License. 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, see . */ #include "utils.h" HANDLE hNetlibUser; static void arrayToHex(BYTE* data, size_t datasz, char* res) { char* resptr = res; for (unsigned i=0; i> 4); *resptr++ = (char)((ch0 <= 9) ? ('0' + ch0) : (('a' - 10) + ch0)); const char ch1 = (char)(ch & 0xF); *resptr++ = (char)((ch1 <= 9) ? ('0' + ch1) : (('a' - 10) + ch1)); } *resptr = '\0'; } void GetLoginStr(char* user, size_t szuser, char* pass) { DBVARIANT dbv; if (db_get_s(NULL, PluginName, "Username", &dbv) == 0) { mir_snprintf(user, szuser, "%s", dbv.pszVal); db_free(&dbv); } else user[0] = 0; if (db_get_s(NULL, PluginName, "Password", &dbv) == 0) { CallService(MS_DB_CRYPT_DECODESTRING, strlen(dbv.pszVal)+1, (LPARAM)dbv.pszVal); BYTE hash[16]; mir_md5_state_t context; mir_md5_init(&context); mir_md5_append(&context, (BYTE*)dbv.pszVal, (int)strlen(dbv.pszVal)); mir_md5_finish(&context, hash); arrayToHex(hash, sizeof(hash), pass); db_free(&dbv); } else pass[0] = 0; } void OpenAuthUrl(const char* url) { char user[64], pass[40]; GetLoginStr(user, sizeof(user), pass); if (user[0] && pass[0]) { char str[256]; mir_snprintf(str, sizeof(str), url, user); mir_snprintf(str, sizeof(str), "http://www.miranda-vi.org/cdlogin?name=%s&pass=%s&redir=%s", user, pass, ptrA( mir_urlEncode(str))); CallService(MS_UTILS_OPENURL, OUF_NEWWINDOW, (LPARAM)str); } else CallService(MS_UTILS_OPENURL, OUF_NEWWINDOW, (LPARAM)"http://www.miranda-vi.org/"); } void CreateAuthString(char* auth) { char user[64], pass[40]; GetLoginStr(user, sizeof(user), pass); char str[110]; int len = mir_snprintf(str, sizeof(str), "%s:%s", user, pass); mir_snprintf(auth, 250, "Basic %s", ptrA( mir_base64_encode((PBYTE)str, len))); } bool InternetDownloadFile(const char *szUrl, VerTrnsfr* szReq) { int result = 0xBADBAD; char* szRedirUrl = NULL; NETLIBHTTPREQUEST nlhr = {0}; // initialize the netlib request nlhr.cbSize = sizeof(nlhr); nlhr.requestType = REQUEST_POST; nlhr.flags = NLHRF_HTTP11 | NLHRF_NODUMP; nlhr.szUrl = (char*)szUrl; nlhr.headersCount = 6; nlhr.headers=(NETLIBHTTPHEADER*)mir_alloc(sizeof(NETLIBHTTPHEADER)*nlhr.headersCount); nlhr.headers[0].szName = "Connection"; nlhr.headers[0].szValue = "close"; nlhr.headers[1].szName = "Cache-Control"; nlhr.headers[1].szValue = "no-cache"; nlhr.headers[2].szName = "Pragma"; nlhr.headers[2].szValue = "no-cache"; nlhr.headers[3].szName = "Content-Type"; nlhr.headers[3].szValue = "text/plain; charset=utf-8"; nlhr.headers[4].szName = "AutoUpload"; nlhr.headers[4].szValue = (char*)(szReq->autot ? "1" : "0"); nlhr.headers[5].szName = "Authorization"; char auth[256]; CreateAuthString(auth); nlhr.headers[5].szValue = auth; nlhr.pData = szReq->buf; nlhr.dataLength = (int)strlen(szReq->buf); while (result == 0xBADBAD) { // download the page NETLIBHTTPREQUEST *nlhrReply = (NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)hNetlibUser,(LPARAM)&nlhr); if (nlhrReply) { int i; // if the recieved code is 200 OK switch(nlhrReply->resultCode) { case 200: if (db_get_b(NULL, PluginName, "UploadChanged", 0)) ProcessVIHash(true); for (i=nlhrReply->headersCount; i--; ) { if (_stricmp(nlhrReply->headers[i].szName, "OldPlugins") == 0) { i = atoi(nlhrReply->headers[i].szValue); break; } } ShowMessage(1, TranslateT("VersionInfo upload successful,\n %d old plugins"), i); result = 0; break; case 401: ShowMessage(0, TranslateT("Cannot upload VersionInfo. Incorrect username or password")); result = 1; break; case 510: ShowMessage(0, TranslateT("Cannot upload VersionInfo. User is banned")); result = 1; break; case 511: ShowMessage(0, TranslateT("Cannot upload VersionInfo. Daily upload limit exceeded")); result = 1; break; case 301: case 302: case 307: // get the url for the new location and save it to szInfo // look for the reply header "Location" for (i=0; iheadersCount; i++) { if (!strcmp(nlhrReply->headers[i].szName, "Location")) { size_t rlen = 0; if (nlhrReply->headers[i].szValue[0] == '/') { const char* szPath; const char* szPref = strstr(szUrl, "://"); szPref = szPref ? szPref + 3 : szUrl; szPath = strchr(szPref, '/'); rlen = szPath != NULL ? szPath - szUrl : strlen(szUrl); } szRedirUrl = (char*)mir_realloc(szRedirUrl, rlen + strlen(nlhrReply->headers[i].szValue)*3 + 1); strncpy(szRedirUrl, szUrl, rlen); strcpy(szRedirUrl+rlen, nlhrReply->headers[i].szValue); nlhr.szUrl = szRedirUrl; break; } } break; default: result = 1; ShowMessage(0, TranslateT("Cannot upload VersionInfo. Unknown error")); } } else { result = 1; ShowMessage(0, TranslateT("Cannot upload VersionInfo. Host unreachable.")); } CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT,0,(LPARAM)nlhrReply); } mir_free(szRedirUrl); mir_free(nlhr.headers); return result == 0; } void __cdecl VersionInfoUploadThread(void* arg) { VerTrnsfr* trn = (VerTrnsfr*)arg; InternetDownloadFile("http://www.miranda-vi.org/uploadpost", trn); mir_free(trn->buf); mir_free(trn); } void UploadInit(void) { NETLIBUSER nlu = {0}; nlu.cbSize = sizeof(nlu); nlu.flags = NUF_OUTGOING | NUF_HTTPCONNS | NUF_NOHTTPSOPTION | NUF_TCHAR; nlu.szSettingsModule = (char*)PluginName; nlu.ptszDescriptiveName = TranslateT("Crash Dumper HTTP connections"); hNetlibUser = (HANDLE)CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu); } void UploadClose(void) { Netlib_CloseHandle(hNetlibUser); } bool ProcessVIHash(bool store) { bkstring buffer; buffer.reserve(0x1800); PrintVersionInfo(buffer, 0); BYTE hash[16]; mir_md5_state_t context; mir_md5_init(&context); mir_md5_append(&context, (PBYTE)buffer.c_str(), (int)buffer.sizebytes()); mir_md5_finish(&context, hash); char hashstr[40]; arrayToHex(hash, sizeof(hash), hashstr); bool result; if (store) { db_set_s(NULL, PluginName, "VIHash", hashstr); result = true; } else { DBVARIANT dbv; if (db_get_s(NULL, PluginName, "VIHash", &dbv) == 0) { result = strcmp(hashstr, dbv.pszVal) == 0; db_free(&dbv); } else result = false; } return result; }