/* Miranda SmileyAdd Plugin Copyright (C) 2007 - 2011 Boris Krasnovskiy 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 "general.h" #include "m_smileyadd.h" #include "m_folders.h" extern HANDLE hEvent1; HANDLE hNetlibUser; static HANDLE hFolder, hFolderHook; struct QueueElem { bkstring url; bkstring fname; bool needext; QueueElem(bkstring& purl, bkstring& pfname, bool ne) : url(purl), fname(pfname), needext(ne) {} }; static HANDLE g_hDlMutex; static OBJLIST dlQueue(10); static TCHAR cachepath[MAX_PATH]; static bool threadRunning; bool InternetDownloadFile(const char *szUrl, char* szDest, HANDLE &hHttpDwnl) { int result = 0xBADBAD; char* szRedirUrl = NULL; NETLIBHTTPREQUEST nlhr = {0}; // initialize the netlib request nlhr.cbSize = sizeof(nlhr); nlhr.requestType = REQUEST_GET; nlhr.flags = NLHRF_NODUMP; nlhr.szUrl = (char*)szUrl; nlhr.nlc = hHttpDwnl; if (CallService(MS_SYSTEM_GETVERSION, 0, 0) >= PLUGIN_MAKE_VERSION(0,9,0,5)) nlhr.flags |= NLHRF_HTTP11 | NLHRF_PERSISTENT | NLHRF_REDIRECT; // change the header so the plugin is pretended to be IE 6 + WinXP nlhr.headersCount = 2; nlhr.headers=(NETLIBHTTPHEADER*)alloca(sizeof(NETLIBHTTPHEADER)*nlhr.headersCount); nlhr.headers[0].szName = "User-Agent"; nlhr.headers[0].szValue = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"; nlhr.headers[1].szName = "Connection"; nlhr.headers[1].szValue = "close"; while (result == 0xBADBAD) { // download the page NETLIBHTTPREQUEST *nlhrReply = (NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)hNetlibUser,(LPARAM)&nlhr); if (nlhrReply) { hHttpDwnl = nlhrReply->nlc; // if the recieved code is 200 OK if(nlhrReply->resultCode == 200) { char* delim = strrchr(szDest, '\\'); if (delim) *delim = '\0'; CallService(MS_UTILS_CREATEDIRTREE, 0, (LPARAM)szDest); if (delim) *delim = '\\'; int res = -1; int fh = _open(szDest, _O_BINARY | _O_WRONLY | _O_CREAT, _S_IREAD | _S_IWRITE); if (fh != -1) { res = _write(fh, nlhrReply->pData, nlhrReply->dataLength); _close(fh); } if (res < 0) remove(szDest); else result = 0; } // if the recieved code is 302 Moved, Found, etc // workaround for url forwarding else if(nlhrReply->resultCode == 302 || nlhrReply->resultCode == 301 || nlhrReply->resultCode == 307) // page moved { // get the url for the new location and save it to szInfo // look for the reply header "Location" for (int 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; } } } else result = 1; } else { hHttpDwnl = NULL; result = 1; } CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT,0,(LPARAM)nlhrReply); } mir_free(szRedirUrl); return result == 0; } void __cdecl SmileyDownloadThread(void*) { bool needext = false; HANDLE hHttpDwnl = NULL; WaitForSingleObject(g_hDlMutex, 3000); while (!Miranda_Terminated() && dlQueue.getCount()) { ReleaseMutex(g_hDlMutex); if (_taccess(dlQueue[0].fname.c_str(), 0) != 0) { InternetDownloadFile(T2A_SM(dlQueue[0].url.c_str()), T2A_SM(dlQueue[0].fname.c_str()), hHttpDwnl); WaitForSingleObject(g_hDlMutex, 3000); bkstring fname(dlQueue[0].fname); if (dlQueue[0].needext) { fname += GetImageExt(fname); needext = true; } _trename(dlQueue[0].fname.c_str(), fname.c_str()); } else WaitForSingleObject(g_hDlMutex, 3000); dlQueue.remove(0); } dlQueue.destroy(); if (hHttpDwnl) Netlib_CloseHandle(hHttpDwnl); threadRunning = false; ReleaseMutex(g_hDlMutex); if (!Miranda_Terminated()) { if (needext) CallServiceSync(MS_SMILEYADD_RELOAD, 0, 0); else NotifyEventHooks(hEvent1, 0, 0); } } bool GetSmileyFile(bkstring& url, const bkstring& packstr) { _TPattern * urlsplit = _TPattern::compile(_T(".*/(.*)")); _TMatcher * m0 = urlsplit->createTMatcher(url); m0->findFirstMatch(); bkstring filename; filename.appendfmt(_T("%s\\%s\\"), cachepath, packstr.c_str()); size_t pathpos = filename.size(); filename += m0->getGroup(1); delete m0; delete urlsplit; bool needext = filename.find('.') == filename.npos; if (needext) filename += _T(".*"); _tfinddata_t c_file; INT_PTR hFile = _tfindfirst((TCHAR*)filename.c_str(), &c_file); if (hFile > -1) { _findclose(hFile); filename.erase(pathpos); filename += c_file.name; url = filename; return false; } if (needext) filename.erase(filename.size()-1); WaitForSingleObject(g_hDlMutex, 3000); dlQueue.insert(new QueueElem(url, filename, needext)); ReleaseMutex(g_hDlMutex); if (!threadRunning) { threadRunning = true; mir_forkthread(SmileyDownloadThread, NULL); } url = filename; return false; } void GetDefaultSmileyCacheFolder(TCHAR* szPath, size_t cbLen) { TCHAR *tmpPath = Utils_ReplaceVarsT(_T("%miranda_userdata%\\SmileyCache")); if ((INT_PTR)tmpPath != CALLSERVICE_NOTFOUND) { mir_sntprintf(szPath, cbLen, _T("%s"), tmpPath); mir_free(tmpPath); } else { char dbPath[MAX_PATH]; CallService(MS_DB_GETPROFILEPATH, SIZEOF(dbPath), (LPARAM)dbPath); mir_sntprintf(szPath, cbLen, _T("%s\\SmileyCache"), A2T_SM(dbPath)); } } int FolderChanged(WPARAM, LPARAM) { FOLDERSGETDATA fgd = {0}; fgd.cbSize = sizeof(FOLDERSGETDATA); fgd.nMaxPathSize = SIZEOF(cachepath); fgd.szPathT = cachepath; if (CallService(MS_FOLDERS_GET_PATH, (WPARAM) hFolder, (LPARAM) &fgd)) { GetDefaultSmileyCacheFolder(cachepath, SIZEOF(cachepath)); } return 0; } void GetSmileyCacheFolder(void) { TCHAR defaultPath[MAX_PATH]; GetDefaultSmileyCacheFolder(defaultPath, SIZEOF(defaultPath)); FOLDERSDATA fd = {0}; fd.cbSize = sizeof(FOLDERSDATA); strcpy(fd.szSection, "SmileyAdd"); strcpy(fd.szName,"Smiley Cache"); fd.szFormatT = defaultPath; fd.flags = FF_TCHAR; hFolder = (HANDLE)CallService(MS_FOLDERS_REGISTER_PATH, 0, (LPARAM) &fd); FolderChanged(0, 0); hFolderHook = HookEvent(ME_FOLDERS_PATH_CHANGED, FolderChanged); } void DownloadInit(void) { NETLIBUSER nlu = {0}; nlu.cbSize = sizeof(nlu); nlu.flags = NUF_OUTGOING|NUF_HTTPCONNS|NUF_NOHTTPSOPTION; nlu.szSettingsModule = "SmileyAdd"; nlu.szDescriptiveName = Translate("SmileyAdd HTTP connections"); hNetlibUser = (HANDLE)CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu); GetSmileyCacheFolder(); g_hDlMutex = CreateMutex(NULL, FALSE, NULL); } void DownloadClose(void) { UnhookEvent(hFolderHook); CloseHandle(g_hDlMutex); Netlib_CloseHandle(hNetlibUser); }