bool validateShortcut() { QString path = systemShortcutPath(); if (path.isEmpty() || cExeName().isEmpty()) return false; if (cAlphaVersion()) { path += qsl("TelegramAlpha.lnk"); if (validateShortcutAt(path)) return true; } else { if (validateShortcutAt(path + qsl("Telegram Desktop/Telegram.lnk"))) return true; if (validateShortcutAt(path + qsl("Telegram Win (Unofficial)/Telegram.lnk"))) return true; path += qsl("Telegram.lnk"); if (validateShortcutAt(path)) return true; } ComPtr<IShellLink> shellLink; HRESULT hr = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&shellLink)); if (!SUCCEEDED(hr)) return false; hr = shellLink->SetPath(QDir::toNativeSeparators(cExeDir() + cExeName()).toStdWString().c_str()); if (!SUCCEEDED(hr)) return false; hr = shellLink->SetArguments(L""); if (!SUCCEEDED(hr)) return false; hr = shellLink->SetWorkingDirectory(QDir::toNativeSeparators(QDir(cWorkingDir()).absolutePath()).toStdWString().c_str()); if (!SUCCEEDED(hr)) return false; ComPtr<IPropertyStore> propertyStore; hr = shellLink.As(&propertyStore); if (!SUCCEEDED(hr)) return false; PROPVARIANT appIdPropVar; hr = InitPropVariantFromString(getId(), &appIdPropVar); if (!SUCCEEDED(hr)) return false; hr = propertyStore->SetValue(getKey(), appIdPropVar); PropVariantClear(&appIdPropVar); if (!SUCCEEDED(hr)) return false; PROPVARIANT startPinPropVar; hr = InitPropVariantFromUInt32(APPUSERMODEL_STARTPINOPTION_NOPINONINSTALL, &startPinPropVar); if (!SUCCEEDED(hr)) return false; hr = propertyStore->SetValue(pkey_AppUserModel_StartPinOption, startPinPropVar); PropVariantClear(&startPinPropVar); if (!SUCCEEDED(hr)) return false; hr = propertyStore->Commit(); if (!SUCCEEDED(hr)) return false; ComPtr<IPersistFile> persistFile; hr = shellLink.As(&persistFile); if (!SUCCEEDED(hr)) return false; hr = persistFile->Save(QDir::toNativeSeparators(path).toStdWString().c_str(), TRUE); if (!SUCCEEDED(hr)) return false; return true; }
void cleanupShortcut() { static const int maxFileLen = MAX_PATH * 10; QString path = systemShortcutPath() + qsl("Telegram.lnk"); std::wstring p = QDir::toNativeSeparators(path).toStdWString(); DWORD attributes = GetFileAttributes(p.c_str()); if (attributes >= 0xFFFFFFF) return; // file does not exist ComPtr<IShellLink> shellLink; HRESULT hr = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&shellLink)); if (!SUCCEEDED(hr)) return; ComPtr<IPersistFile> persistFile; hr = shellLink.As(&persistFile); if (!SUCCEEDED(hr)) return; hr = persistFile->Load(p.c_str(), STGM_READWRITE); if (!SUCCEEDED(hr)) return; WCHAR szGotPath[MAX_PATH]; WIN32_FIND_DATA wfd; hr = shellLink->GetPath(szGotPath, MAX_PATH, (WIN32_FIND_DATA*)&wfd, SLGP_SHORTPATH); if (!SUCCEEDED(hr)) return; if (QDir::toNativeSeparators(cExeDir() + cExeName()).toStdWString() == szGotPath) { QFile().remove(path); } }
void Launcher::prepareSettings() { #ifdef Q_OS_MAC #ifndef OS_MAC_OLD if (QSysInfo::macVersion() >= QSysInfo::MV_10_11) { gIsElCapitan = true; } #else // OS_MAC_OLD if (QSysInfo::macVersion() < QSysInfo::MV_10_7) { gIsSnowLeopard = true; } #endif // OS_MAC_OLD #endif // Q_OS_MAC switch (cPlatform()) { case dbipWindows: #ifndef OS_WIN_STORE gPlatformString = qsl("Windows"); #else // OS_WIN_STORE gPlatformString = qsl("WinStore"); #endif // OS_WIN_STORE break; case dbipMac: #ifndef OS_MAC_STORE gPlatformString = qsl("MacOS"); #else // OS_MAC_STORE gPlatformString = qsl("MacAppStore"); #endif // OS_MAC_STORE break; case dbipMacOld: gPlatformString = qsl("MacOSold"); break; case dbipLinux64: gPlatformString = qsl("Linux64bit"); break; case dbipLinux32: gPlatformString = qsl("Linux32bit"); break; } auto path = Platform::CurrentExecutablePath(_argc, _argv); LOG(("Executable path before check: %1").arg(path)); if (!path.isEmpty()) { auto info = QFileInfo(path); if (info.isSymLink()) { info = info.symLinkTarget(); } if (info.exists()) { const auto dir = info.absoluteDir().absolutePath(); gExeDir = (dir.endsWith('/') ? dir : (dir + '/')); gExeName = info.fileName(); } } if (cExeName().isEmpty()) { LOG(("WARNING: Could not compute executable path, some features will be disabled.")); } processArguments(); }
QStringList atosstr(uint64 *addresses, int count, uint64 base) { QStringList result; if (!count) return result; result.reserve(count); QString cmdstr = "atos -o " + escapeShell(cExeDir() + cExeName()) + qsl("/Contents/MacOS/Telegram -l 0x%1").arg(base, 0, 16); for (int i = 0; i < count; ++i) { if (addresses[i]) { cmdstr += qsl(" 0x%1").arg(addresses[i], 0, 16); } } QByteArray cmd = cmdstr.toUtf8(); FILE *f = popen(cmd.constData(), "r"); QStringList atosResult; if (f) { char buffer[4096] = {0}; while (!feof(f)) { if (fgets(buffer, 4096, f) != NULL) { atosResult.push_back(QString::fromUtf8(buffer)); } } pclose(f); } for (int i = 0, j = 0; i < count; ++i) { if (addresses[i]) { if (j < atosResult.size() && !atosResult.at(j).isEmpty() && !atosResult.at(j).startsWith(qstr("0x"))) { result.push_back(atosResult.at(j).trimmed()); } else { result.push_back(QString()); } ++j; } else { result.push_back(QString()); } } return result; }
bool Launcher::launchUpdater(UpdaterLaunch action) { if (cExeName().isEmpty()) { return false; } const auto operation = (action == UpdaterLaunch::JustRelaunch) ? QString() : (cWriteProtected() ? qsl("runas") : QString()); const auto binaryPath = (action == UpdaterLaunch::JustRelaunch) ? (cExeDir() + cExeName()) : (cWriteProtected() ? (cWorkingDir() + qsl("tupdates/temp/Updater.exe")) : (cExeDir() + qsl("Updater.exe"))); auto argumentsList = QStringList(); const auto pushArgument = [&](const QString &argument) { argumentsList.push_back(argument.trimmed()); }; if (cLaunchMode() == LaunchModeAutoStart) { pushArgument(qsl("-autostart")); } if (Logs::DebugEnabled()) { pushArgument(qsl("-debug")); } if (cStartInTray()) { pushArgument(qsl("-startintray")); } if (cTestMode()) { pushArgument(qsl("-testmode")); } #ifndef TDESKTOP_DISABLE_AUTOUPDATE if (Core::UpdaterDisabled()) { pushArgument(qsl("-externalupdater")); } #endif // !TDESKTOP_DISABLE_AUTOUPDATE if (customWorkingDir()) { pushArgument(qsl("-workdir")); pushArgument('"' + cWorkingDir() + '"'); } if (cDataFile() != qsl("data")) { pushArgument(qsl("-key")); pushArgument('"' + cDataFile() + '"'); } if (action == UpdaterLaunch::JustRelaunch) { pushArgument(qsl("-noupdate")); if (cRestartingToSettings()) { pushArgument(qsl("-tosettings")); } } else { pushArgument(qsl("-update")); pushArgument(qsl("-exename")); pushArgument('"' + cExeName() + '"'); if (cWriteProtected()) { pushArgument(qsl("-writeprotected")); pushArgument('"' + cExeDir() + '"'); } } return launch(operation, binaryPath, argumentsList); }
bool psCheckReadyUpdate() { QString readyPath = cWorkingDir() + qsl("tupdates/ready"); if (!QDir(readyPath).exists()) { return false; } // check ready version QString versionPath = readyPath + qsl("/tdata/version"); { QFile fVersion(versionPath); if (!fVersion.open(QIODevice::ReadOnly)) { LOG(("Update Error: cant read version file '%1'").arg(versionPath)); PsUpdateDownloader::clearAll(); return false; } VerInt versionNum; if (fVersion.read((char*)&versionNum, sizeof(VerInt)) != sizeof(VerInt)) { LOG(("Update Error: cant read version from file '%1'").arg(versionPath)); PsUpdateDownloader::clearAll(); return false; } fVersion.close(); if (versionNum <= AppVersion) { LOG(("Update Error: cant install version %1 having version %2").arg(versionNum).arg(AppVersion)); PsUpdateDownloader::clearAll(); return false; } } #ifdef Q_OS_WIN QString curUpdater = (cExeDir() + qsl("Updater.exe")); QFileInfo updater(cWorkingDir() + qsl("tupdates/ready/Updater.exe")); #elif defined Q_OS_MAC QString curUpdater = (cExeDir() + cExeName() + qsl("/Contents/Frameworks/Updater")); QFileInfo updater(cWorkingDir() + qsl("tupdates/ready/Telegram.app/Contents/Frameworks/Updater")); #endif if (!updater.exists()) { QFileInfo current(curUpdater); if (!current.exists()) { PsUpdateDownloader::clearAll(); return false; } if (!QFile(current.absoluteFilePath()).copy(updater.absoluteFilePath())) { PsUpdateDownloader::clearAll(); return false; } } #ifdef Q_OS_WIN if (CopyFile(updater.absoluteFilePath().toStdWString().c_str(), curUpdater.toStdWString().c_str(), FALSE) == FALSE) { PsUpdateDownloader::clearAll(); return false; } if (DeleteFile(updater.absoluteFilePath().toStdWString().c_str()) == FALSE) { PsUpdateDownloader::clearAll(); return false; } #elif defined Q_OS_MAC QDir().mkpath(QFileInfo(curUpdater).absolutePath()); DEBUG_LOG(("Update Info: moving %1 to %2..").arg(updater.absoluteFilePath()).arg(curUpdater)); if (!objc_moveFile(updater.absoluteFilePath(), curUpdater)) { PsUpdateDownloader::clearAll(); return false; } #endif return true; }
void psRegisterCustomScheme() { QString home(_psHomeDir()); if (home.isEmpty()) return; DEBUG_LOG(("App Info: placing .desktop file")); if (QDir(home + qsl(".local/")).exists()) { QString apps = home + qsl(".local/share/applications/"); if (!QDir(apps).exists()) QDir().mkpath(apps); QString path = cWorkingDir() + qsl("tdata/"), file = path + qsl("telegramdesktop.desktop"); QDir().mkpath(path); QFile f(file); if (f.open(QIODevice::WriteOnly)) { QString icon = path + qsl("icon.png"); if (!QFile(icon).exists()) { if (QFile(qsl(":/gui/art/icon256.png")).copy(icon)) { DEBUG_LOG(("App Info: Icon copied to 'tdata'")); } } QTextStream s(&f); s.setCodec("UTF-8"); s << "[Desktop Entry]\n"; s << "Encoding=UTF-8\n"; s << "Version=1.0\n"; s << "Name=Telegram Desktop\n"; s << "Comment=Official desktop version of Telegram messaging app\n"; s << "Exec=" << escapeShell(cExeDir() + cExeName()) << " -- %u\n"; s << "Icon=" << icon << "\n"; s << "Terminal=false\n"; s << "Type=Application\n"; s << "Categories=Network;\n"; s << "MimeType=application/x-xdg-protocol-tg;x-scheme-handler/tg;\n"; f.close(); if (_psRunCommand(qsl("desktop-file-install --dir=%1 --delete-original %2").arg(escapeShell(home + qsl(".local/share/applications"))).arg(escapeShell(file)))) { DEBUG_LOG(("App Info: removing old .desktop file")); QFile(qsl("%1.local/share/applications/telegram.desktop").arg(home)).remove(); _psRunCommand(qsl("update-desktop-database %1").arg(escapeShell(home + qsl(".local/share/applications")))); _psRunCommand(qsl("xdg-mime default telegramdesktop.desktop x-scheme-handler/tg")); } } else { LOG(("App Error: Could not open '%1' for write").arg(file)); } } DEBUG_LOG(("App Info: registerting for Gnome")); if (_psRunCommand(qsl("gconftool-2 -t string -s /desktop/gnome/url-handlers/tg/command %1").arg(escapeShell(qsl("%1 -- %s").arg(escapeShell(cExeDir() + cExeName())))))) { _psRunCommand(qsl("gconftool-2 -t bool -s /desktop/gnome/url-handlers/tg/needs_terminal false")); _psRunCommand(qsl("gconftool-2 -t bool -s /desktop/gnome/url-handlers/tg/enabled true")); } DEBUG_LOG(("App Info: placing .protocol file")); QString services; if (QDir(home + qsl(".kde4/")).exists()) { services = home + qsl(".kde4/share/kde4/services/"); } else if (QDir(home + qsl(".kde/")).exists()) { services = home + qsl(".kde/share/kde4/services/"); } if (!services.isEmpty()) { if (!QDir(services).exists()) QDir().mkpath(services); QString path = services, file = path + qsl("tg.protocol"); QFile f(file); if (f.open(QIODevice::WriteOnly)) { QTextStream s(&f); s.setCodec("UTF-8"); s << "[Protocol]\n"; s << "exec=" << escapeShell(cExeDir() + cExeName()) << " -- %u\n"; s << "protocol=tg\n"; s << "input=none\n"; s << "output=none\n"; s << "helper=true\n"; s << "listing=false\n"; s << "reading=false\n"; s << "writing=false\n"; s << "makedir=false\n"; s << "deleting=false\n"; f.close(); } else { LOG(("App Error: Could not open '%1' for write").arg(file)); } } }