diff options
Diffstat (limited to 'plugins/Updater/socket.cpp')
-rw-r--r-- | plugins/Updater/socket.cpp | 355 |
1 files changed, 355 insertions, 0 deletions
diff --git a/plugins/Updater/socket.cpp b/plugins/Updater/socket.cpp new file mode 100644 index 0000000000..52a82bd6b1 --- /dev/null +++ b/plugins/Updater/socket.cpp @@ -0,0 +1,355 @@ +#include "common.h"
+#include "socket.h"
+
+void unzip_mem(char* buf, int len, TCHAR* dest);
+
+bool GetFile(char *url, TCHAR *temp_folder, char *plugin_name, char *version, bool dlls_only, int recurse_count /*=0*/) {
+ if(recurse_count > MAX_REDIRECT_RECURSE) {
+ NLog("GetFile: error, too many redirects");
+ return false;
+ }
+
+ TCHAR save_file[MAX_PATH];
+
+ if(url == 0 || temp_folder == 0 || plugin_name == 0)
+ return false;
+
+ // ensure temp_folder exists
+ if(!CreatePath(options.temp_folder)) {
+ NLogF("GetFile: error creating temp folder, code %u", GetLastError());
+ return false;
+ }
+
+ // ensure zip_folder exists, if necessary
+ if(options.save_zips && !CreatePath(options.zip_folder)) {
+ NLogF("GetFile: error creating zip folder, code %u", GetLastError());
+ return false;
+ }
+
+ TCHAR *temp_str = GetTString(plugin_name);
+ mir_sntprintf(save_file, SIZEOF(save_file), _T("%s\\%s"), temp_folder, temp_str);
+ mir_free(temp_str);
+ if (version)
+ {
+ temp_str = GetTString(version);
+ _tcscat(save_file, _T("_"));
+ _tcscat(save_file, temp_str);
+ mir_free(temp_str);
+ }
+ // copt extension from url
+ char *ext = strrchr(url, '.');
+ if(ext && *ext && strcmp(ext, ".dll") == 0) {
+ _tcscat(save_file, _T(".dll"));
+ } else { // default to zip extension (e.g. miranda fl)
+ _tcscat(save_file, _T(".zip"));
+ ext = ".zip";
+ }
+
+ // replace version text in URL
+ char tmp_url[1024];
+ if (version != NULL) {
+ char *p;
+ size_t pos = 0;
+ size_t version_len = strlen(version);
+ while ((p = strstr(url, "%VERSION%")) != NULL && (p - url + version_len < sizeof(tmp_url) - 1)) {
+ strncpy(&tmp_url[pos], url, p - url);
+ pos += p - url;
+ strcpy(&tmp_url[pos], version);
+ pos += version_len;
+ url += p - url + 9; // 9 == strlen("%VERSION%")
+ }
+ if (strlen(url) < sizeof(tmp_url) - 1) {
+ strcpy(&tmp_url[pos], url);
+ pos += strlen(url);
+ }
+ tmp_url[pos] = 0;
+ url = tmp_url;
+ }
+
+
+ NETLIBHTTPREQUEST req = {0};
+
+ req.cbSize = sizeof(req);
+ req.requestType = REQUEST_GET;
+ req.szUrl = url;
+ req.flags = NLHRF_NODUMP | NLHRF_HTTP11;
+ req.nlc = hNetlibHttp;
+
+ if (CallService(MS_SYSTEM_GETVERSION, 0, 0) >= PLUGIN_MAKE_VERSION(0,9,0,5))
+ req.flags |= NLHRF_PERSISTENT | NLHRF_REDIRECT;
+
+ NETLIBHTTPREQUEST *resp = (NETLIBHTTPREQUEST *)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)hNetlibUser, (LPARAM)&req);
+
+ if (resp)
+ {
+ hNetlibHttp = resp->nlc;
+ if (resp->resultCode == 200)
+ {
+ if (ext && *ext && _stricmp(ext, ".zip") == 0)
+ {
+ if (!options.no_unzip)
+ unzip_mem(resp->pData, resp->dataLength, temp_folder);
+
+ if (options.save_zips)
+ {
+ TCHAR save_archive[MAX_PATH];
+ mir_sntprintf(save_archive, SIZEOF(save_archive), _T("%s%s"), options.zip_folder, _tcsrchr(save_file, '\\'));
+
+ HANDLE hSaveFile = CreateFile(save_archive, GENERIC_WRITE, FILE_SHARE_WRITE, 0,
+ CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
+ if (hSaveFile != INVALID_HANDLE_VALUE)
+ {
+ unsigned long bytes_written;
+ WriteFile(hSaveFile, resp->pData, resp->dataLength, &bytes_written, NULL);
+ CloseHandle(hSaveFile);
+ }
+ else
+ NLogF("GetFile: error creating file, code %u", GetLastError());
+ }
+
+ if(dlls_only)
+ {
+ NLog("Deleting non-dlls");
+ DeleteNonDlls(temp_folder);
+ }
+
+ }
+ else
+ {
+ HANDLE hSaveFile = CreateFile(save_file, GENERIC_WRITE, FILE_SHARE_WRITE, 0,
+ CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
+ if (hSaveFile != INVALID_HANDLE_VALUE)
+ {
+ unsigned long bytes_written;
+ WriteFile(hSaveFile, resp->pData, resp->dataLength, &bytes_written, NULL);
+ CloseHandle(hSaveFile);
+ }
+ else
+ NLogF("GetFile: error creating file, code %u", GetLastError());
+ }
+
+ CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)resp);
+ return true;
+ }
+ else if (resp->resultCode >= 300 && resp->resultCode < 400)
+ {
+ // get new location
+ bool ret = false;
+ for (int i = 0; i < resp->headersCount; i++)
+ {
+ if (_stricmp(resp->headers[i].szName, "Location") == 0)
+ {
+ ret = GetFile(resp->headers[i].szValue, temp_folder, plugin_name, version, dlls_only, recurse_count + 1);
+ break;
+ }
+ }
+ CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)resp);
+ return ret;
+ }
+ else
+ {
+ TCHAR buff[1024], *tmp;
+ mir_sntprintf(buff, SIZEOF(buff), TranslateT("Failed to download \"%s\" - Invalid response, code %d"), (tmp = mir_a2t(plugin_name)), resp->resultCode);
+ ShowError(buff);
+ mir_free(tmp);
+ }
+ CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)resp);
+ }
+ else
+ {
+ hNetlibHttp = NULL;
+ int err = GetLastError();
+ if (err && !Miranda_Terminated())
+ {
+ TCHAR buff[1024], *tmp;
+ int len = mir_sntprintf(buff, SIZEOF(buff), TranslateT("Failed to download \"%s\": "), (tmp = mir_a2t(plugin_name)));
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, err, 0, buff + len, 512 - len, 0);
+ ShowError(buff);
+ mir_free(tmp);
+ }
+ }
+
+ return false;
+}
+
+char *CheckVersionURL(char *url, BYTE *pbPrefixBytes, int cpbPrefixBytes, BYTE *pbVersionBytes, int cpbVersionBytes)
+{
+ if (url == 0 || pbPrefixBytes == 0 || cpbPrefixBytes == 0 || pbVersionBytes == 0 || cpbVersionBytes == 0)
+ return 0;
+
+ char *ret = NULL;
+ NETLIBHTTPREQUEST req = {0};
+
+ req.cbSize = sizeof(req);
+ req.requestType = REQUEST_GET;
+ req.szUrl = url;
+ req.flags = NLHRF_DUMPASTEXT | NLHRF_HTTP11;
+ req.nlc = hNetlibHttp;
+
+ if (CallService(MS_SYSTEM_GETVERSION, 0, 0) >= PLUGIN_MAKE_VERSION(0,9,0,5))
+ req.flags |= NLHRF_PERSISTENT | NLHRF_REDIRECT;
+
+ NETLIBHTTPREQUEST *resp = (NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION,
+ (WPARAM)hNetlibUser, (LPARAM)&req);
+
+ if (resp)
+ {
+ hNetlibHttp = resp->nlc;
+ if (resp->resultCode == 200)
+ {
+ // find the location of the prefix
+ char* ver = (char*)memmem(resp->pData, resp->dataLength, pbPrefixBytes, cpbPrefixBytes);
+ if (ver)
+ {
+ int len = resp->dataLength - ((ver += cpbPrefixBytes) - resp->pData);
+ if (cpbVersionBytes <= len && memcmp(ver, pbVersionBytes, cpbVersionBytes) == 0)
+ {
+ // same version as current
+ CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)resp);
+ return 0;
+ }
+ else
+ {
+ DWORD ver_current, ver_potential;
+ char *buff = (char *)alloca(cpbVersionBytes + 1);
+ memcpy(buff, (char *)pbVersionBytes, cpbVersionBytes);
+ buff[cpbVersionBytes] = 0;
+
+ // this is safe because pData finishes with a zero always (according to m_netlib.h docs)
+ if (VersionFromString(buff, &ver_current) && VersionFromString(ver, &ver_potential))
+ {
+ switch(options.ver_req)
+ {
+ case VR_MAJOR:
+ ver_current &= 0xFF000000;
+ ver_potential &= 0xFF000000;
+ break;
+ case VR_MINOR:
+ ver_current &= 0xFFFF0000;
+ ver_potential &= 0xFFFF0000;
+ break;
+ case VR_RELEASE:
+ ver_current &= 0xFFFFFF00;
+ ver_potential &= 0xFFFFFF00;
+ break;
+ case VR_BUILD:
+ break;
+ }
+
+ // we can covert the versions to DWORDS, so compare...
+ if (ver_current < ver_potential)
+ {
+ char buff2[16];
+ CreateVersionString(ver_potential, buff2);
+ ret = _strdup(buff2);
+ }
+ }
+ else // invalid version(s), but different from current - assume it's an update
+ ret = _strdup(Translate("Yes"));
+ }
+ }
+ }
+ else if (resp->resultCode == 302) // redirect
+ {
+ // get new location
+ for (int i = 0; i < resp->headersCount; i++)
+ {
+ if(_stricmp(resp->headers[i].szName, "Location") == 0)
+ {
+ ret = CheckVersionURL(resp->headers[i].szValue, pbPrefixBytes, cpbPrefixBytes, pbVersionBytes, cpbVersionBytes);
+ break;
+ }
+ }
+ }
+ else
+ NLogF("CheckVersionURL: error, http result code %d", resp->resultCode);
+
+ CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)resp);
+ }
+ else
+ {
+ hNetlibHttp = NULL;
+ int err = GetLastError();
+ if (err)
+ NLogF("CheckVersionURL: error code %d", err);
+ }
+
+ return ret;
+}
+
+char *UpdateRequired(UpdateInternal &update_internal, bool *beta)
+{
+ // determine whether update is required
+
+ char *ret = NULL, *ret_beta = NULL;
+
+ if (options.use_xml_backend && update_internal.file_id != -1)
+ {
+ const char * res;
+ if (update_internal.cat == MC_UNKNOWN)
+ {
+ if (XMLDataAvailable(MC_PLUGINS) &&
+ (res = FindVersion(update_internal.file_id, update_internal.update.pbVersion, update_internal.update.cpbVersion, MC_PLUGINS)))
+ {
+ update_internal.cat = MC_PLUGINS;
+ if (strcmp(res, "same")) ret = _strdup(res);
+ }
+ else if (XMLDataAvailable(MC_LOCALIZATION) &&
+ (res = FindVersion(update_internal.file_id, update_internal.update.pbVersion, update_internal.update.cpbVersion, MC_LOCALIZATION)))
+ {
+ update_internal.cat = MC_LOCALIZATION;
+ if (strcmp(res, "same")) ret = _strdup(res);
+ }
+ }
+ else
+ {
+ res = FindVersion(update_internal.file_id, update_internal.update.pbVersion, update_internal.update.cpbVersion, update_internal.cat);
+ if (res && strcmp(res, "same")) ret = _strdup(res);
+ }
+ }
+ else
+ {
+ ret = CheckVersionURL(update_internal.update.szVersionURL, update_internal.update.pbVersionPrefix,
+ update_internal.update.cpbVersionPrefix, update_internal.update.pbVersion, update_internal.update.cpbVersion);
+ }
+
+ if (update_internal.update_options.use_beta)
+ {
+ ret_beta = CheckVersionURL(update_internal.update.szBetaVersionURL, update_internal.update.pbBetaVersionPrefix,
+ update_internal.update.cpbBetaVersionPrefix, update_internal.update.pbVersion, update_internal.update.cpbVersion);
+ }
+
+ if (ret && !ret_beta)
+ {
+ if(beta) *beta = false;
+ return ret;
+ }
+ else if (!ret && ret_beta)
+ {
+ if (beta) *beta = true;
+ return ret_beta;
+ }
+ else if (ret && ret_beta)
+ {
+ // find highest version of ret and ret_beta
+
+ DWORD vRet, vRetBeta;
+ VersionFromString(ret, &vRet);
+ VersionFromString(ret_beta, &vRetBeta);
+
+ if (vRetBeta > vRet)
+ {
+ free(ret);
+ if (beta) *beta = true;
+ return ret_beta;
+ }
+ else
+ {
+ free(ret_beta);
+ if (beta) *beta = false;
+ return ret;
+ }
+ }
+
+ return 0;
+}
|