diff --git a/.gitignore b/.gitignore index d06dd7e59f..cc845b1732 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ tools/repack-thes-dict.dSYM build*/ subprojects/boost*/ subprojects/cairo* +subprojects/curl-* subprojects/ffmpeg subprojects/ffms2* subprojects/fontconfig* diff --git a/meson.build b/meson.build index a0ec18d18f..3d1e01b7a4 100644 --- a/meson.build +++ b/meson.build @@ -69,6 +69,10 @@ if get_option('official_release') conf.set('AEGI_OFFICIAL_RELEASE', 1) endif conf.set('WITH_UPDATE_CHECKER', get_option('enable_update_checker')) +if get_option('enable_update_checker') + conf.set_quoted('UPDATE_CHECKER_SERVER', get_option('update_server')) + conf.set_quoted('UPDATE_CHECKER_BASE_URL', get_option('update_url')) +endif deps = [] deps_inc = [] @@ -277,6 +281,41 @@ endif conf_platform = configuration_data() conf_platform.set('DEFAULT_PLAYER_AUDIO', def_audio) +if get_option('enable_update_checker') + libcurl_dep = dependency('libcurl', required: false) + + if (not libcurl_dep.found()) + libcurl_opt = cmake.subproject_options() + options_dict = { + 'HTTP_ONLY': true, + 'BUILD_CURL_EXE': false, + 'CMAKE_BUILD_TYPE': get_option('buildtype') == 'release' ? 'Release' : 'Debug', + } + if host_machine.system() == 'windows' + options_dict += {'CURL_USE_SCHANNEL': true} + deps += cc.find_library('crypt32') + elif host_machine.system() == 'darwin' + options_dict += {'CURL_USE_SECTRANSP': true} + else + options_dict += {'CURL_USE_OPENSSL': true} + endif + if get_option('default_library') == 'static' and (host_machine.system() == 'windows' or host_machine.system() == 'darwin') + options_dict += {'BUILD_SHARED_LIBS': false} + add_project_arguments('-DCURL_STATICLIB', language: ['cpp']) + endif + libcurl_opt.add_cmake_defines(options_dict) + libcurl = cmake.subproject('curl', options: libcurl_opt) + + libcurl_dep = libcurl.dependency('libcurl') + + # Horrible meson hack to work around the cmake subproject creating broken include directories + libcurl_dep = libcurl_dep.partial_dependency(compile_args: true, link_args: true, links: true, sources: true) + libcurl_fixed_inc = declare_dependency(include_directories: subproject('curl_meson').get_variable('libcurl_fixed_inc')) + deps += [libcurl_fixed_inc] + endif + deps += [libcurl_dep] +endif + luajit = dependency('luajit', version: '>=2.0.0', required: get_option('system_luajit')) if luajit.found() and luajit.type_name() != 'internal' luajit_test = cc.run('''#include diff --git a/meson_options.txt b/meson_options.txt index a6f3e7d118..5509d90bda 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -21,8 +21,8 @@ option('wx_version', type: 'string', value: '3.0.0', description: 'The minimum w option('credit', type: 'string', value: '', description: 'Build credit shown in program title') option('official_release', type: 'boolean', value: false, description: 'Set on official builds') -option('enable_update_checker', type: 'boolean', value: false, description: 'Enable the update checker') -option('update_server', type: 'string', value: 'updates.aegisub.org', description: 'Server to use for the update checker') +option('enable_update_checker', type: 'boolean', value: true, description: 'Enable the update checker') +option('update_server', type: 'string', value: 'https://updates.aegisub.org', description: 'Server to use for the update checker') option('update_url', type: 'string', value: '/trunk', description: 'Base path to use for the update checker') option('build_osx_bundle', type: 'boolean', value: 'false', description: 'Package Aegisub.app on OSX') diff --git a/src/dialog_version_check.cpp b/src/dialog_version_check.cpp index 6dea7e3b6a..4d039f0461 100644 --- a/src/dialog_version_check.cpp +++ b/src/dialog_version_check.cpp @@ -29,10 +29,6 @@ #ifdef WITH_UPDATE_CHECKER -#ifdef _MSC_VER -#pragma warning(disable : 4250) // 'boost::asio::basic_socket_iostream' : inherits 'std::basic_ostream<_Elem,_Traits>::std::basic_ostream<_Elem,_Traits>::_Add_vtordisp2' via dominance -#endif - #include "compat.h" #include "format.h" #include "options.h" @@ -46,9 +42,10 @@ #include #include -#include +#include #include #include +#include #include #include #include @@ -280,44 +277,46 @@ static wxString GetAegisubLanguage() { return to_wx(OPT_GET("App/Language")->GetString()); } +size_t writeToStringCb(char *contents, size_t size, size_t nmemb, std::string *s) { + s->append(contents, size * nmemb); + return size * nmemb; +} + void DoCheck(bool interactive) { - boost::asio::ip::tcp::iostream stream; - stream.connect(UPDATE_CHECKER_SERVER, "http"); - if (!stream) - throw VersionCheckError(from_wx(_("Could not connect to updates server."))); - - agi::format(stream, - "GET %s?rev=%d&rel=%d&os=%s&lang=%s&aegilang=%s HTTP/1.0\r\n" - "User-Agent: Aegisub %s\r\n" - "Host: %s\r\n" - "Accept: */*\r\n" - "Connection: close\r\n\r\n" - , UPDATE_CHECKER_BASE_URL - , GetSVNRevision() - , (GetIsOfficialRelease() ? 1 : 0) - , GetOSShortName() - , GetSystemLanguage() - , GetAegisubLanguage() - , GetAegisubLongVersionString() - , UPDATE_CHECKER_SERVER); - - std::string http_version; - stream >> http_version; - int status_code; - stream >> status_code; - if (!stream || http_version.substr(0, 5) != "HTTP/") - throw VersionCheckError(from_wx(_("Could not download from updates server."))); - if (status_code != 200) - throw VersionCheckError(agi::format(_("HTTP request failed, got HTTP response %d."), status_code)); - - stream.ignore(std::numeric_limits::max(), '\n'); - - // Skip the headers since we don't care about them - for (auto const& header : agi::line_iterator(stream)) - if (header.empty()) break; + CURL *curl; + CURLcode res_code; + + curl = curl_easy_init(); + if (!curl) + throw VersionCheckError(from_wx(_("Curl could not be initialized."))); + + curl_easy_setopt(curl, CURLOPT_URL, + agi::format("%s%s?rev=%d&rel=%d&os=%s&lang=%s&aegilang=%s" + , UPDATE_CHECKER_SERVER + , UPDATE_CHECKER_BASE_URL + , GetSVNRevision() + , (GetIsOfficialRelease() ? 1 : 0) + , GetOSShortName() + , GetSystemLanguage() + , GetAegisubLanguage() + ).c_str()); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(curl, CURLOPT_USERAGENT, agi::format("Aegisub %s", GetAegisubLongVersionString()).c_str()); + + std::string result; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeToStringCb); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &result); + + res_code = curl_easy_perform(curl); + curl_easy_cleanup(curl); + if (res_code != CURLE_OK) { + std::string err_msg = agi::format(_("Checking for updates failed: %s."), curl_easy_strerror(res_code)); + throw VersionCheckError(err_msg); + } + std::stringstream ss(result); std::vector results; - for (auto const& line : agi::line_iterator(stream)) { + for (auto const& line : agi::line_iterator(ss)) { if (line.empty()) continue; std::vector parsed; diff --git a/subprojects/curl.wrap b/subprojects/curl.wrap new file mode 100644 index 0000000000..91a83b6aa6 --- /dev/null +++ b/subprojects/curl.wrap @@ -0,0 +1,9 @@ +[wrap-file] +directory = curl-7.82.0 +source_url = https://github.com/curl/curl/releases/download/curl-7_82_0/curl-7.82.0.tar.gz +source_filename = curl-7.82.0.tar.xz +source_hash = 910cc5fe279dc36e2cca534172c94364cf3fcf7d6494ba56e6c61a390881ddce +patch_directory = curl + +[provide] +dependency_names = libcurl diff --git a/subprojects/curl_meson.wrap b/subprojects/curl_meson.wrap new file mode 100644 index 0000000000..71e55be5e3 --- /dev/null +++ b/subprojects/curl_meson.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = curl-7.82.0 +source_url = https://github.com/curl/curl/releases/download/curl-7_82_0/curl-7.82.0.tar.gz +source_filename = curl-7.82.0.tar.xz +source_hash = 910cc5fe279dc36e2cca534172c94364cf3fcf7d6494ba56e6c61a390881ddce +patch_directory = curl diff --git a/subprojects/packagefiles/curl/meson.build b/subprojects/packagefiles/curl/meson.build new file mode 100644 index 0000000000..a0635751c3 --- /dev/null +++ b/subprojects/packagefiles/curl/meson.build @@ -0,0 +1,3 @@ +project('curl_meson', 'cpp') + +libcurl_fixed_inc = include_directories('include/')