QString currentVersionText() { auto result = QString::fromLatin1(AppVersionStr.c_str()); if (cAlphaVersion()) { result += " alpha"; } if (cBetaVersion()) { result += qsl(" beta %1").arg(cBetaVersion() % 1000); } return result; }
AboutBox::AboutBox(QWidget *parent) : _version(this, lng_about_version(lt_version, QString::fromLatin1(AppVersionStr.c_str()) + (cAlphaVersion() ? " alpha" : "") + (cBetaVersion() ? qsl(" beta %1").arg(cBetaVersion()) : QString())), st::aboutVersionLink) , _text1(this, lang(lng_about_text_1), Ui::FlatLabel::InitType::Rich, st::aboutLabel) , _text2(this, lang(lng_about_text_2), Ui::FlatLabel::InitType::Rich, st::aboutLabel) , _text3(this, st::aboutLabel) { }
void UpdateChecker::unpackUpdate() { QByteArray packed; if (!outputFile.open(QIODevice::ReadOnly)) { LOG(("Update Error: cant read updates file!")); return fatalFail(); } #ifdef Q_OS_WIN // use Lzma SDK for win const int32 hSigLen = 128, hShaLen = 20, hPropsLen = LZMA_PROPS_SIZE, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hPropsLen + hOriginalSizeLen; // header #else // Q_OS_WIN const int32 hSigLen = 128, hShaLen = 20, hPropsLen = 0, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hOriginalSizeLen; // header #endif // Q_OS_WIN QByteArray compressed = outputFile.readAll(); int32 compressedLen = compressed.size() - hSize; if (compressedLen <= 0) { LOG(("Update Error: bad compressed size: %1").arg(compressed.size())); return fatalFail(); } outputFile.close(); QString tempDirPath = cWorkingDir() + qsl("tupdates/temp"), readyFilePath = cWorkingDir() + qsl("tupdates/temp/ready"); psDeleteDir(tempDirPath); QDir tempDir(tempDirPath); if (tempDir.exists() || QFile(readyFilePath).exists()) { LOG(("Update Error: cant clear tupdates/temp dir!")); return fatalFail(); } uchar sha1Buffer[20]; bool goodSha1 = !memcmp(compressed.constData() + hSigLen, hashSha1(compressed.constData() + hSigLen + hShaLen, compressedLen + hPropsLen + hOriginalSizeLen, sha1Buffer), hShaLen); if (!goodSha1) { LOG(("Update Error: bad SHA1 hash of update file!")); return fatalFail(); } RSA *pbKey = PEM_read_bio_RSAPublicKey(BIO_new_mem_buf(const_cast<char*>(AppAlphaVersion ? UpdatesPublicAlphaKey : UpdatesPublicKey), -1), 0, 0, 0); if (!pbKey) { LOG(("Update Error: cant read public rsa key!")); return fatalFail(); } if (RSA_verify(NID_sha1, (const uchar*)(compressed.constData() + hSigLen), hShaLen, (const uchar*)(compressed.constData()), hSigLen, pbKey) != 1) { // verify signature RSA_free(pbKey); if (cAlphaVersion() || cBetaVersion()) { // try other public key, if we are in alpha or beta version pbKey = PEM_read_bio_RSAPublicKey(BIO_new_mem_buf(const_cast<char*>(AppAlphaVersion ? UpdatesPublicKey : UpdatesPublicAlphaKey), -1), 0, 0, 0); if (!pbKey) { LOG(("Update Error: cant read public rsa key!")); return fatalFail(); } if (RSA_verify(NID_sha1, (const uchar*)(compressed.constData() + hSigLen), hShaLen, (const uchar*)(compressed.constData()), hSigLen, pbKey) != 1) { // verify signature RSA_free(pbKey); LOG(("Update Error: bad RSA signature of update file!")); return fatalFail(); } } else { LOG(("Update Error: bad RSA signature of update file!")); return fatalFail(); } } RSA_free(pbKey); QByteArray uncompressed; int32 uncompressedLen; memcpy(&uncompressedLen, compressed.constData() + hSigLen + hShaLen + hPropsLen, hOriginalSizeLen); uncompressed.resize(uncompressedLen); size_t resultLen = uncompressed.size(); #ifdef Q_OS_WIN // use Lzma SDK for win SizeT srcLen = compressedLen; int uncompressRes = LzmaUncompress((uchar*)uncompressed.data(), &resultLen, (const uchar*)(compressed.constData() + hSize), &srcLen, (const uchar*)(compressed.constData() + hSigLen + hShaLen), LZMA_PROPS_SIZE); if (uncompressRes != SZ_OK) { LOG(("Update Error: could not uncompress lzma, code: %1").arg(uncompressRes)); return fatalFail(); } #else // Q_OS_WIN lzma_stream stream = LZMA_STREAM_INIT; lzma_ret ret = lzma_stream_decoder(&stream, UINT64_MAX, LZMA_CONCATENATED); if (ret != LZMA_OK) { const char *msg; switch (ret) { case LZMA_MEM_ERROR: msg = "Memory allocation failed"; break; case LZMA_OPTIONS_ERROR: msg = "Specified preset is not supported"; break; case LZMA_UNSUPPORTED_CHECK: msg = "Specified integrity check is not supported"; break; default: msg = "Unknown error, possibly a bug"; break; } LOG(("Error initializing the decoder: %1 (error code %2)").arg(msg).arg(ret)); return fatalFail(); } stream.avail_in = compressedLen; stream.next_in = (uint8_t*)(compressed.constData() + hSize); stream.avail_out = resultLen; stream.next_out = (uint8_t*)uncompressed.data(); lzma_ret res = lzma_code(&stream, LZMA_FINISH); if (stream.avail_in) { LOG(("Error in decompression, %1 bytes left in _in of %2 whole.").arg(stream.avail_in).arg(compressedLen)); return fatalFail(); } else if (stream.avail_out) { LOG(("Error in decompression, %1 bytes free left in _out of %2 whole.").arg(stream.avail_out).arg(resultLen)); return fatalFail(); } lzma_end(&stream); if (res != LZMA_OK && res != LZMA_STREAM_END) { const char *msg; switch (res) { case LZMA_MEM_ERROR: msg = "Memory allocation failed"; break; case LZMA_FORMAT_ERROR: msg = "The input data is not in the .xz format"; break; case LZMA_OPTIONS_ERROR: msg = "Unsupported compression options"; break; case LZMA_DATA_ERROR: msg = "Compressed file is corrupt"; break; case LZMA_BUF_ERROR: msg = "Compressed data is truncated or otherwise corrupt"; break; default: msg = "Unknown error, possibly a bug"; break; } LOG(("Error in decompression: %1 (error code %2)").arg(msg).arg(res)); return fatalFail(); } #endif // Q_OS_WIN tempDir.mkdir(tempDir.absolutePath()); quint32 version; { QBuffer buffer(&uncompressed); buffer.open(QIODevice::ReadOnly); QDataStream stream(&buffer); stream.setVersion(QDataStream::Qt_5_1); stream >> version; if (stream.status() != QDataStream::Ok) { LOG(("Update Error: cant read version from downloaded stream, status: %1").arg(stream.status())); return fatalFail(); } quint64 betaVersion = 0; if (version == 0x7FFFFFFF) { // beta version stream >> betaVersion; if (stream.status() != QDataStream::Ok) { LOG(("Update Error: cant read beta version from downloaded stream, status: %1").arg(stream.status())); return fatalFail(); } if (!cBetaVersion() || betaVersion <= cBetaVersion()) { LOG(("Update Error: downloaded beta version %1 is not greater, than mine %2").arg(betaVersion).arg(cBetaVersion())); return fatalFail(); } } else if (int32(version) <= AppVersion) {
AboutBox::AboutBox() : AbstractBox(st::aboutWidth) , _version(this, lng_about_version(lt_version, QString::fromLatin1(AppVersionStr.c_str()) + (cAlphaVersion() ? " alpha" : "") + (cBetaVersion() ? qsl(" beta %1").arg(cBetaVersion()) : QString())), st::aboutVersionLink) , _text1(this, lang(lng_about_text_1), FlatLabel::InitType::Rich, st::aboutLabel, st::aboutTextStyle) , _text2(this, lang(lng_about_text_2), FlatLabel::InitType::Rich, st::aboutLabel, st::aboutTextStyle) , _text3(this,st::aboutLabel, st::aboutTextStyle) , _done(this, lang(lng_close), st::defaultBoxButton) { _text3.setRichText(lng_about_text_3(lt_faq_open, qsl("[a href=\"%1\"]").arg(telegramFaqLink()), lt_faq_close, qsl("[/a]"))); setMaxHeight(st::boxTitleHeight + st::aboutTextTop + _text1.height() + st::aboutSkip + _text2.height() + st::aboutSkip + _text3.height() + st::boxButtonPadding.top() + _done.height() + st::boxButtonPadding.bottom()); connect(&_version, SIGNAL(clicked()), this, SLOT(onVersion())); connect(&_done, SIGNAL(clicked()), this, SLOT(onClose())); prepare(); setAcceptDrops(true); }
int main(int argc, char *argv[]) { #ifdef Q_OS_WIN _oldWndExceptionFilter = SetUnhandledExceptionFilter(_exceptionFilter); // CAPIHook apiHook("kernel32.dll", "SetUnhandledExceptionFilter", (PROC)RedirectedSetUnhandledExceptionFilter); #endif settingsParseArgs(argc, argv); for (int32 i = 0; i < argc; ++i) { if (string("-fixprevious") == argv[i]) { return psFixPrevious(); } else if (string("-cleanup") == argv[i]) { return psCleanup(); } } if (!logsInit()) { return 0; } installSignalHandlers(); Global::Initializer _init; Local::readSettings(); if (Local::oldSettingsVersion() < AppVersion) { psNewVersion(); } if (cFromAutoStart() && !cAutoStart()) { psAutoStart(false, true); Local::stop(); return 0; } DEBUG_LOG(("Application Info: Telegram started, test mode: %1, exe dir: %2").arg(logBool(cTestMode())).arg(cExeDir())); if (cDebug()) { LOG(("Application Info: Telegram started in debug mode")); for (int32 i = 0; i < argc; ++i) { LOG(("Argument: %1").arg(fromUtf8Safe(argv[i]))); } QStringList logs = psInitLogs(); for (int32 i = 0, l = logs.size(); i < l; ++i) { LOG(("Init Log: %1").arg(logs.at(i))); } } psClearInitLogs(); DEBUG_LOG(("Application Info: ideal thread count: %1, using %2 connections per session").arg(QThread::idealThreadCount()).arg(cConnectionsInSession())); psStart(); int result = 0; { QByteArray args[] = { "-style=0" }; // prepare fake args static const int a_cnt = sizeof(args) / sizeof(args[0]); int a_argc = a_cnt + 1; char *a_argv[a_cnt + 1] = { argv[0], args[0].data() }; Application app(a_argc, a_argv); if (!App::quiting()) { result = app.exec(); } } psFinish(); Local::stop(); DEBUG_LOG(("Application Info: Telegram done, result: %1").arg(result)); #ifndef TDESKTOP_DISABLE_AUTOUPDATE if (cRestartingUpdate()) { if (!cBetaVersion() && DevVersion) { LOG(("Writing 'devversion' file before launching the Updater!")); QFile f(cWorkingDir() + qsl("tdata/devversion")); if (!f.exists() && f.open(QIODevice::WriteOnly)) { f.write("1"); f.close(); } } DEBUG_LOG(("Application Info: executing updater to install update..")); psExecUpdater(); } else #endif if (cRestarting()) { DEBUG_LOG(("Application Info: executing Telegram, because of restart..")); psExecTelegram(); } logsClose(); return result; }