Reimplement file open confirmations.

This commit is contained in:
John Preston
2024-04-15 11:18:57 +04:00
parent f4a09a9ca0
commit 6a28cd1a35
17 changed files with 375 additions and 158 deletions
@@ -28,6 +28,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/chat/chat_theme.h"
#include "ui/text/text_utilities.h"
#include "ui/widgets/checkbox.h"
#include "ui/wrap/slide_wrap.h"
#include "window/window_session_controller.h"
#include "styles/style_layers.h"
@@ -46,11 +47,12 @@ base::options::toggle OptionExternalVideoPlayer({
void ConfirmDontWarnBox(
not_null<Ui::GenericBox*> box,
rpl::producer<TextWithEntities> &&text,
rpl::producer<QString> &&check,
rpl::producer<QString> &&confirm,
Fn<void(bool)> callback) {
auto checkbox = object_ptr<Ui::Checkbox>(
box.get(),
tr::lng_launch_exe_dont_ask(),
std::move(check),
false,
st::defaultBoxCheckbox);
const auto weak = Ui::MakeWeak(checkbox.data());
@@ -67,29 +69,43 @@ void ConfirmDontWarnBox(
auto padding = st::boxPadding;
padding.setTop(padding.bottom());
box->addRow(std::move(checkbox), std::move(padding));
box->addRow(object_ptr<Ui::SlideWrap<Ui::FlatLabel>>(
box,
object_ptr<Ui::FlatLabel>(
box,
tr::lng_launch_dont_ask_settings(),
st::boxLabel)
))->toggleOn(weak->checkedValue());
}
void LaunchWithWarning(
// not_null<Window::Controller*> controller,
const QString &name,
HistoryItem *item) {
const auto isExecutable = Data::IsExecutableName(name);
const auto isIpReveal = Data::IsIpRevealingName(name);
const auto nameType = Core::DetectNameType(name);
const auto isIpReveal = (nameType != Core::NameType::Executable)
&& Core::IsIpRevealingPath(name);
const auto extension = Core::FileExtension(name).toLower();
auto &app = Core::App();
auto &settings = app.settings();
const auto warn = [&] {
if (item && item->history()->peer->isVerified()) {
return false;
}
return (isExecutable && app.settings().exeLaunchWarning())
|| (isIpReveal && app.settings().ipRevealWarning());
return (isIpReveal && settings.ipRevealWarning())
|| ((nameType == Core::NameType::Executable
|| nameType == Core::NameType::Unknown)
&& !settings.noWarningExtensions().contains(extension));
}();
const auto extension = '.' + Data::FileExtension(name);
if (Platform::IsWindows() && extension == u"."_q) {
if (extension.isEmpty()) {
// If you launch a file without extension, like "test", in case
// there is an executable file with the same name in this folder,
// like "test.bat", the executable file will be launched.
//
// Now we always force an Open With dialog box for such files.
//
// Let's force it for all platforms for files without extension.
crl::on_main([=] {
Platform::File::UnsafeShowOpenWith(name);
});
@@ -98,27 +114,38 @@ void LaunchWithWarning(
File::Launch(name);
return;
}
const auto callback = [=, &app](bool checked) {
const auto callback = [=, &app, &settings](bool checked) {
if (checked) {
if (isExecutable) {
app.settings().setExeLaunchWarning(false);
} else if (isIpReveal) {
app.settings().setIpRevealWarning(false);
if (isIpReveal) {
settings.setIpRevealWarning(false);
} else {
auto copy = settings.noWarningExtensions();
copy.emplace(extension);
settings.setNoWarningExtensions(std::move(copy));
}
app.saveSettingsDelayed();
}
File::Launch(name);
};
auto text = isExecutable
? tr::lng_launch_exe_warning(
lt_extension,
rpl::single(Ui::Text::Bold(extension)),
Ui::Text::WithEntities)
: tr::lng_launch_svg_warning(Ui::Text::WithEntities);
auto text = isIpReveal
? tr::lng_launch_svg_warning(Ui::Text::WithEntities)
: ((nameType == Core::NameType::Executable)
? tr::lng_launch_exe_warning
: tr::lng_launch_other_warning)(
lt_extension,
rpl::single(Ui::Text::Bold('.' + extension)),
Ui::Text::WithEntities);
auto check = (isIpReveal
? tr::lng_launch_exe_dont_ask
: tr::lng_launch_dont_ask)();
auto confirm = ((nameType == Core::NameType::Executable)
? tr::lng_launch_exe_sure
: tr::lng_launch_other_sure)();
Ui::show(Box(
ConfirmDontWarnBox,
std::move(text),
(isExecutable ? tr::lng_launch_exe_sure : tr::lng_continue)(),
std::move(check),
std::move(confirm),
callback));
}
@@ -126,91 +153,6 @@ void LaunchWithWarning(
const char kOptionExternalVideoPlayer[] = "external-video-player";
QString FileExtension(const QString &filepath) {
const auto reversed = ranges::views::reverse(filepath);
const auto last = ranges::find_first_of(reversed, ".\\/");
if (last == reversed.end() || *last != '.') {
return QString();
}
return QString(last.base(), last - reversed.begin());
}
#if 0
bool IsValidMediaFile(const QString &filepath) {
static const auto kExtensions = [] {
const auto list = qsl("\
16svx 2sf 3g2 3gp 8svx aac aaf aif aifc aiff amr amv ape asf ast au aup \
avchd avi brstm bwf cam cdda cust dat divx drc dsh dsf dts dtshd dtsma \
dvr-ms dwd evo f4a f4b f4p f4v fla flac flr flv gif gifv gsf gsm gym iff \
ifo it jam la ly m1v m2p m2ts m2v m4a m4p m4v mcf mid mk3d mka mks mkv mng \
mov mp1 mp2 mp3 mp4 minipsf mod mpc mpe mpeg mpg mpv mscz mt2 mus mxf mxl \
niff nsf nsv off ofr ofs ogg ogv opus ots pac ps psf psf2 psflib ptb qsf \
qt ra raw rka rm rmj rmvb roq s3m shn sib sid smi smp sol spc spx ssf svi \
swa swf tak ts tta txm usf vgm vob voc vox vqf wav webm wma wmv wrap wtv \
wv xm xml ym yuv").split(' ');
return base::flat_set<QString>(list.begin(), list.end());
}();
return ranges::binary_search(
kExtensions,
FileExtension(filepath).toLower());
}
#endif
bool IsExecutableName(const QString &filepath) {
static const auto kExtensions = [] {
const auto joined =
#ifdef Q_OS_WIN
u"\
ad ade adp app application appref-ms asp asx bas bat bin cab cdxml cer cfg \
chi chm cmd cnt com cpl crt csh der diagcab dll drv eml exe fon fxp gadget \
grp hlp hpj hta htt inf ini ins inx isp isu its jar jnlp job js jse key ksh \
lexe lnk local lua mad maf mag mam manifest maq mar mas mat mau mav maw mcf \
mda mdb mde mdt mdw mdz mht mhtml mjs mmc mof msc msg msh msh1 msh2 msh1xml \
msh2xml mshxml msi msp mst ops osd paf pcd phar php php3 php4 php5 php7 phps \
php-s pht phtml pif pl plg pm pod prf prg ps1 ps2 ps1xml ps2xml psc1 psc2 \
psd1 psm1 pssc pst py py3 pyc pyd pyi pyo pyw pyzw pyz rb reg rgs scf scr \
sct search-ms settingcontent-ms sh shb shs slk sys t tmp u3p url vb vbe vbp \
vbs vbscript vdx vsmacros vsd vsdm vsdx vss vssm vssx vst vstm vstx vsw vsx \
vtx website wlua ws wsc wsf wsh xbap xll xnk xs"_q;
#elif defined Q_OS_MAC // Q_OS_MAC
u"\
applescript action app bin command csh osx workflow terminal url caction \
mpkg pkg scpt scptd xhtm webarchive"_q;
#else // Q_OS_WIN || Q_OS_MAC
u"bin csh deb desktop ksh out pet pkg pup rpm run sh shar \
slp zsh"_q;
#endif // !Q_OS_WIN && !Q_OS_MAC
const auto list = joined.split(' ');
return base::flat_set<QString>(list.begin(), list.end());
}();
return ranges::binary_search(
kExtensions,
FileExtension(filepath).toLower());
}
bool IsIpRevealingName(const QString &filepath) {
static const auto kExtensions = [] {
const auto joined = u"htm html svg m4v m3u8"_q;
const auto list = joined.split(' ');
return base::flat_set<QString>(list.begin(), list.end());
}();
static const auto kMimeTypes = [] {
const auto joined = u"text/html image/svg+xml"_q;
const auto list = joined.split(' ');
return base::flat_set<QString>(list.begin(), list.end());
}();
return ranges::binary_search(
kExtensions,
FileExtension(filepath).toLower()
) || ranges::binary_search(
kMimeTypes,
QMimeDatabase().mimeTypeForFile(QFileInfo(filepath)).name()
);
}
base::binary_guard ReadBackgroundImageAsync(
not_null<Data::DocumentMedia*> media,
FnMut<QImage(QImage)> postprocess,