Compare commits

...

287 Commits

Author SHA1 Message Date
John Preston
eacc6b7b6e Alpha version 1.3.16.
- Update libtgvoip, fix crash in calls.
- Fix crash in local cache database.
- Clear old local cache asynchronously.
2018-09-04 22:37:22 +03:00
John Preston
4b87363a20 Check value size before putting to cache db. 2018-09-04 22:37:22 +03:00
John Preston
9ba331693f Async clear of legacy local storage.
Sync call to QDir::entryList is a bad idea for the user data folder.
Some users reported hanging on startup with 1.25M legacy cache files.
Now we enumerate up to 10000 files at once asynchronously and clear.
2018-09-04 22:37:22 +03:00
John Preston
12be795de7 Update libtgvoip. 2018-09-02 16:49:08 +03:00
John Preston
49f56a38fb Fix changelog entry. 2018-09-01 21:44:46 +03:00
John Preston
4e80d54be1 Alpha version 1.3.15.
- Improved local caching for images and GIF animations.
- Control how much disk space is used by the cache
and for how long the cached files are stored.
2018-09-01 18:56:09 +03:00
John Preston
2096007ed9 Fix clearing leaked files with a passcode. 2018-09-01 18:56:09 +03:00
John Preston
47ce695142 Remove some unused lang keys. 2018-09-01 18:56:08 +03:00
John Preston
80cd74edc8 Closed beta version 1.3.14.2: Fix fallthrough. 2018-09-01 18:56:08 +03:00
John Preston
55583c2237 Closed beta version 1.3.14.2. 2018-09-01 18:56:08 +03:00
John Preston
069232ec1b Allow changing limits for cache in Settings. 2018-09-01 18:56:08 +03:00
John Preston
5733f4079f Allow updating some database settings. 2018-09-01 18:56:08 +03:00
John Preston
55fe977d54 Add some tests for Database. 2018-09-01 18:56:08 +03:00
John Preston
736789a9ed Closed beta version 1.3.14.1: Fix for OS X old. 2018-09-01 18:56:08 +03:00
John Preston
7150811aef Closed beta version 1.3.14.1. 2018-09-01 18:56:08 +03:00
John Preston
63103ede81 Update libtgvoip. 2018-09-01 18:56:08 +03:00
John Preston
c86252777b Remove leaked (unknown) files in user data folder. 2018-09-01 18:56:08 +03:00
John Preston
2bcdf27b03 Workaround GCC bug. 2018-09-01 18:56:08 +03:00
John Preston
2001d3c617 Allow cleaner to work after database is closed. 2018-09-01 18:56:08 +03:00
John Preston
8210a51fdc Fix build for Xcode.
Also guard database compactor so that it won't work after closing.
2018-09-01 18:56:08 +03:00
John Preston
08ff324b1b Work with Cache::Database in LocalStorageBox. 2018-09-01 18:56:08 +03:00
John Preston
55f60866cb Set correct cache tags for different file types. 2018-09-01 18:56:08 +03:00
John Preston
e2f08d4161 Write uint8 tags to Database and count stats.
Also pass rvalues to Database where copies are required anyway.
2018-09-01 18:56:08 +03:00
John Preston
2e7f4c2f21 Use Storage::Cache::Database for file caching. 2018-09-01 18:56:08 +03:00
John Preston
a58c082cfa Fix base::binary_guard. 2018-09-01 18:56:08 +03:00
John Preston
5824afa941 Add copy() and move() to Cache::Database. 2018-09-01 18:56:08 +03:00
John Preston
adcc11c474 Ignore database actions after IO error. 2018-09-01 18:56:08 +03:00
John Preston
4769a1a49f Added 100k test for storage cache. 2018-09-01 18:56:08 +03:00
John Preston
f6a6a39d3b Fix compactor and add simple tests for it. 2018-09-01 18:56:08 +03:00
John Preston
2940023cb0 Simplify db tests. 2018-09-01 18:56:08 +03:00
John Preston
d426f7242a Implement Storage::Cache::Compactor for database. 2018-09-01 18:56:08 +03:00
John Preston
2f9d65b4eb Add a generic BinlogReader. 2018-09-01 18:56:08 +03:00
John Preston
a4c1d5fe9d Move cache database to a separate module.
Also start compactor code.
2018-09-01 18:56:08 +03:00
John Preston
13c7c99965 Ignore put queries that don't change anything. 2018-09-01 18:56:08 +03:00
John Preston
fbfa7e7be3 Write date/time inside Store cache record. 2018-09-01 18:56:08 +03:00
John Preston
e5dda6dd49 Write removes/touches in bundles. Apply limits. 2018-09-01 18:56:08 +03:00
John Preston
b9af3c7f34 Add base::ConcurrentTimer.
Write removes from cache database once an hour.
2018-09-01 18:56:08 +03:00
John Preston
64b8adb3d0 Isolate lib_base library. Use crl::time in getms. 2018-09-01 18:56:08 +03:00
John Preston
cb371f09ac Clear old versions of Storage::Cache::Database. 2018-09-01 18:56:08 +03:00
John Preston
9147c12687 Add basic implementation of Storage::Cache DB. 2018-09-01 18:56:08 +03:00
John Preston
b5c870d677 Add xxHash library for checksums. 2018-09-01 18:56:08 +03:00
John Preston
62a396b661 Fix Storage::File lock with killing and add tests. 2018-09-01 18:56:08 +03:00
John Preston
81731139e9 Add tests for storage encrypted file.
Also fix some bugs found by the tests.
2018-09-01 18:56:08 +03:00
John Preston
8a371b9c1b New storage encrypted file. 2018-09-01 18:56:08 +03:00
John Preston
51092fb6a9 Fix file references for faved stickers. 2018-09-01 18:56:08 +03:00
John Preston
018abd6aad Merge remote-tracking branch 'origin/dev' 2018-09-01 18:55:29 +03:00
Henning Schild
5292d75617 Linux: disable RegisterCustomScheme when internal updater is disabled
Closes: https://github.com/telegramdesktop/tdesktop/issues/5118
Signed-off-by: Henning Schild <henning@hennsch.de>
2018-09-01 10:12:09 +03:00
Nicholas Guriev
401e1166f9 Workaround internal compiler error in GCC
Closes: #5111
2018-09-01 10:10:14 +03:00
John Preston
45c1427f91 Version 1.3.14.
- Fix a crash in calls.
2018-08-27 19:07:59 +03:00
John Preston
73be099d7f Update libtgvoip. 2018-08-27 18:18:08 +03:00
John Preston
735faa2d11 Force dump_syms existence in official build script. 2018-08-27 18:08:16 +03:00
John Preston
46946c7323 Use correct SHA1_ functions.
Fixes #5103.
2018-08-27 14:36:26 +03:00
John Preston
d98bbca353 Version 1.3.13.
- Export data from individual chats using the '...' menu.
- Added a new night theme.
- You can now assign custom themes as night and day themes
to quickly switch between them.
- Support for Telegram Passport 1.1 and improved password hashing
algorithm to better protect Telegram Passport data.
2018-08-25 13:50:51 +03:00
John Preston
83fcb8e8ed Fix native names handling in passport. 2018-08-22 17:02:06 +03:00
John Preston
ec61aa0080 Edit last non-service message on KeyUp. 2018-08-22 09:50:36 +03:00
John Preston
4211501acf Improve media viewer window decorations. 2018-08-22 09:50:35 +03:00
John Preston
ae6afad885 Closed beta version 1.3.13.4. 2018-08-20 17:34:26 +03:00
John Preston
3b8cee64b8 Closed beta version 1.3.13.3. 2018-08-20 17:26:28 +03:00
John Preston
a8da0c18ee Closed beta version: 1.3.13.2: Fix broken beta. 2018-08-20 17:26:28 +03:00
John Preston
dac0471157 Closed beta version 1.3.13.2. 2018-08-20 17:26:28 +03:00
John Preston
07007ee5a5 Closed beta version 1.3.13.1. 2018-08-20 17:26:28 +03:00
John Preston
b78c08a30a Bump version to 1.3.13. 2018-08-20 17:26:28 +03:00
John Preston
5a487bc30c Refresh file references in saveGif/faveSticker. 2018-08-20 17:26:28 +03:00
John Preston
c913c77fef Refresh file references when sending stickers. 2018-08-20 17:26:28 +03:00
John Preston
557d363d02 Refresh file references when downloading files. 2018-08-20 17:26:28 +03:00
John Preston
839885910c Pass FileOrigin in all file downloads. 2018-08-20 17:26:28 +03:00
John Preston
ee16070abe Update API scheme to layer 86. 2018-08-20 17:26:27 +03:00
John Preston
b8b5ab6378 Improve native name phrases in passport.
Also auto-save *_name to *_name_latin for english countries.
2018-08-20 17:25:33 +03:00
John Preston
5b88f4d3d2 Update API scheme. 2018-08-20 17:25:06 +03:00
John Preston
34eb834d94 Update libtgvoip to 2.2.2. 2018-08-17 19:32:30 +03:00
John Preston
82a3cd9bdb Use most-filled document from OneOf list. 2018-08-17 19:31:24 +03:00
John Preston
e25ecce887 Ask native names after all other fields are done. 2018-08-17 16:42:07 +03:00
John Preston
9f6d683415 Improve passport rows phrasing.
Also fix translations validation on value save.
2018-08-17 15:07:41 +03:00
John Preston
dc114d62c5 Handle APP_VERSION_OUTDATED in saving/accepting. 2018-08-17 14:11:09 +03:00
John Preston
6bf3006eb9 Rename payload->nonce in new passport scopes. 2018-08-17 14:01:23 +03:00
John Preston
fddc3d6ad9 Workaround MSVC 15.8 regressions. 2018-08-17 14:01:16 +03:00
John Preston
f76a2bc224 Add translations support to passport. 2018-08-14 20:48:23 +03:00
John Preston
6558a32794 Add [first|middle|last]_name_native support. 2018-08-14 15:51:12 +03:00
John Preston
b935d54fe7 Support common error for the whole value.
It is removed (considered fixed) if anything changes in the data.
2018-08-14 14:37:03 +03:00
John Preston
cb827406ca Don't open passport links from inside the app.
They contain secret payload that should not be known to Telegram.
2018-08-14 09:49:14 +03:00
John Preston
36fcf2c60e Add middle_name support to passport.
Also allow editing document without its details.
2018-08-14 09:42:06 +03:00
John Preston
7c173bd63f Ignore errors for not asked fields. 2018-08-14 08:43:40 +03:00
John Preston
3c43f621ce Start improved passport support. 2018-08-14 08:43:04 +03:00
John Preston
bdab477040 Update API scheme to layer 84. 2018-08-11 22:03:34 +03:00
John Preston
550c159ca8 Update API scheme to layer 83. 2018-08-04 23:11:04 +03:00
John Preston
aeec5d1542 Alpha version 1.3.12.
- Bug fixes and other minor improvements.
2018-08-04 21:53:40 +03:00
John Preston
b4aa213c64 Make MediaView modal with MainWindow transient parent on Linux.
There is hope :) that it will force MediaView to be floating in tiling WMs.

Possibly fixes #5048.
2018-08-04 21:12:34 +03:00
John Preston
a241e10208 Bypass window manager for toast notifications.
Regression was introduced in be043a4437.

Fixes #5052.
2018-08-04 21:12:34 +03:00
John Preston
90f6642d33 Use always the same sizes for group layout.
For the floating point precision to matter less in the album layout
decisions use always full image sizes for layout
when sending an album and when displaying it.

Fixes #5049.
2018-08-04 16:48:15 +03:00
John Preston
7bd289ed0f Update the new night theme.
Fixes #5054.
2018-08-04 15:17:48 +03:00
John Preston
c8aa35d23c Don't show PopupMenu for inactive window on macOS.
This is a fixup for 06bf67c146.
2018-08-04 15:17:23 +03:00
John Preston
4e0e472f97 Remove request for debug logs in issue template.
They contain sensitive data and should not be shared publicly.
2018-08-03 14:34:12 +03:00
John Preston
a76658ba46 Alpha version 1.3.11.
- Added a new night theme.
- You can now assign custom themes
as night and day themes to quickly switch between them.
2018-08-02 17:46:50 +03:00
John Preston
6796204126 Fix build for Xcode. 2018-08-02 17:46:50 +03:00
John Preston
1c5e91c9a8 Refresh EditCaptionBox thumbnail when loaded. 2018-08-02 17:46:49 +03:00
John Preston
7f16675d2f Fix via @bot display in Saved Messages.
Fixes #5034.
2018-08-02 17:46:49 +03:00
John Preston
6c7c442ad2 Remove excess RGB -> HSV -> RGB transformation.
Fixes #5043.
2018-08-02 17:46:49 +03:00
John Preston
82fb2151a0 Update libtgvoip submodule to 2.2. 2018-08-02 17:46:49 +03:00
John Preston
36b7c1c720 Fix default night mode applying. 2018-08-02 17:46:49 +03:00
John Preston
06bf67c146 Don't show PopupMenu for inactive window on macOS.
On macOS context menu (right click) doesn't activate the window that was clicked.
- You can't  activate it yourself if some other application is active.
- It's hard to make menu work while window still is inactive (like macOS menus).
Because when you left-click anything after right click Qt makes the window
something-like-focused (it shows on top and receives input), but not really
(it still displays as inactive, cursor not blinking and all). Looks like Qt bug.
2018-08-01 20:14:55 +03:00
John Preston
8cc0fbc687 Fix unmute-by-finished timers.
Fixes #5039.
2018-08-01 19:58:50 +03:00
John Preston
c846a14118 Fix suggest export box layout. 2018-08-01 16:15:51 +03:00
John Preston
097424c535 Fix request pending webpage. 2018-07-31 22:56:05 +03:00
John Preston
c7ed36d558 Check for composition in WM_NCACTIVATE. 2018-07-31 22:56:04 +03:00
John Preston
95eab45108 Fix export messages pagination.
Also fix reply highlight.
Also fix channel service messages.
Also improve single chat export progress display.
2018-07-31 22:56:04 +03:00
John Preston
f852813734 Improved night mode switching. 2018-07-31 22:56:04 +03:00
John Preston
ca6a331a26 Don't close send files box by outside click. 2018-07-31 22:56:04 +03:00
John Preston
bfae205fbe Fix animation in single column layout. 2018-07-31 22:56:04 +03:00
John Preston
aaa1245430 Add some javascript handlers to HTML export. 2018-07-31 22:56:03 +03:00
John Preston
a99ae76ad4 Allow single chat history export. 2018-07-31 22:56:03 +03:00
John Preston
6429e8b532 Improve theme applying. 2018-07-31 22:56:03 +03:00
John Preston
cb338e330f Allow independently change default / night themes. 2018-07-31 22:56:03 +03:00
John Preston
d12bd0824d Upgrade night theme. 2018-07-31 22:56:03 +03:00
John Preston
4c0551ebb1 Fix crash in tcp connection implementation. 2018-07-31 22:56:02 +03:00
John Preston
06fc23fc59 Fix possible premature export bar destruction. 2018-07-31 22:56:02 +03:00
John Preston
41977bf515 Fix build for Xcode. 2018-07-31 22:56:02 +03:00
John Preston
ffd2817d18 Destroy InputField::Inner before InputField.
Inner has a pointer to parent and uses it assuming it is InputField.
If Inner lives longer than InputField (till ~QWidget) then in some
cases it accesses InputField as a (not completely) destroyed object.
2018-07-31 22:56:02 +03:00
John Preston
c48937a2f5 Display export progress starting with 1 / N. 2018-07-31 22:56:02 +03:00
John Preston
091d1157da Fix clearing callbacks for timeout-ed requests. 2018-07-31 22:56:02 +03:00
John Preston
be043a4437 Remove BypassWindowManagerHint in MediaView / Passport.
It makes all kinds of usages buggy, including choose file dialog.

Fixes #4936.
I hope fixes #4950, I hope fixes #4955, I hope fixes #3553.
2018-07-31 22:55:30 +03:00
John Preston
fae0bccc9c Don't use registry quiet hours entry any more.
In the latest Windows 10 those settings aren't stored in registry.
2018-07-31 22:53:37 +03:00
John Preston
b44cf4a094 Remove error box on download start failure. 2018-07-31 22:53:37 +03:00
John Preston
90f4187ca9 Don't accept tg:// links in passport callbacks.
Fixes #5021.
2018-07-31 22:51:06 +03:00
John Preston
ae272074b9 Add a confirmation for internal passport links.
Fixes #5020.
2018-07-31 20:56:54 +03:00
John Preston
9972f7b90e Use server time in dialogs list sorting.
This way it won't mess up when you change your local time.
2018-07-31 17:34:14 +03:00
Marco Trevisan
f68cefbdc1 Snap packaging support (#4505)
* qtbuilder: inherit from make plugin instead of autotools

* qtbuilder: update to properly support snapcraft 2.23

We don't use the default 'source' property as it will recursively download
all the submodules and we don't want that.

Implement newer get_pull_properties.

* gyp-cmake: only strip in Release mode and if we've a binary

* telegram-snap: add first basic snapcraft.yaml to build tdesktop from src

We need to build upstream versions of libva, ffmpeg (with opus support),
openal, portaudio with custom flags and patched versions of gyp, and Qt.

This requires some custom plugins for patching sources, mix repos and
new build plugins for qt and gyp+cmake.

* plugins: properly support snapcraft 2.23

Implementing get_pull_properties class methods

* patches: add qt patch for saving tray icon in .cache

TMPDIR overriding isn't needed anymore

* snapcraft: add xdg-open support to open URIs

* snapcraft: move external libraries to desktop-integration part

* snapcraft: set QTCOMPOSE pointing to proper x11-data

* desktop-integration: add libpulse0 to enable voice/video recording / playing

* qtbuilder: add support for local patches that overrides remote ones

* qtbuilder: make qt-version optional

This allows to build upstream git version

* gyp-cmake: inherit from CMakePlugin reusing artifacts + organize

* patched-python: add support for patching using local files

* snapcraft.yaml: use distro's portaudio instead of building ours

* telegram: disable desktop file generation and custuom scheme registration

* snapcraft.yaml: update version to 0.10.20

* .travis.yaml: add support for building using travis

* qtbuilder: add g++ as build packages

* snapcraft: use distro opus version

* snapcraft: lzma for qt and ffmpeg

* snapcraft: add libdbusmenu for qt

* openal: add oss4-dev as build dependency

* travis: test some hacks to speed things up

* Move plugins to new dir

* QtBuilder: add qt-extra-plugins support

To include plugins that are out of the main qt repo

* QtBuilder: generate branch based on qtversion

* GypCMake: allow to define custom environment variables

* snapcraft: set name to 'telegram-desktop'

* snapcraft: add 'network-status' interface to Telegram app

To automatically reconnect

* snapcraft: use prime instead of snap for flitering files

* snacpraft: update dependencies and versions to build against git

* snapcraft: build with GCC-7

hackish solution

* QtBuilder: add environment support

* QtBuilder: add qt-extra-plugins to get_pull_properties

* snapcraft: set name of the app to telegram-desktop too

* snapcraft: build opus from git (v1.2.1)

So it does upstream, let's follow them

* telegram: apply patch to get proper home path from $HOME

* snapcraft: add version-script to generate proper version from upstream

* telegram: simplify the start command

* snapcraft: get rid of snapd-xdg-open

* snapcraft: use gtk3 and unity integration

* qt5: build using gcc7 too

* telegram-desktop: update desktop file

* telegram: add support unity launcher when snapped

We should actually fix this inside libunity

* gcc7: remove toolchain source.list after install

* desktop-integration: add pulse-audio as dependency again

* telegram-desktop: define XCURSOR_PATH to get system cursors

* gui: move files to snap folder

* libtgvoip: don't enable SSE2 in unsupported archs

* snapcraft: add -alpha sufix on versions and do not include git for tags

* telegram: add patch for building in ARM chips

* desktop-integration: include libunity

* telegram-desktop: no need to define XCURSOR_PATH anymore, desktop helper will do

* snapcraft: compile libunity from upstream to get proper launcher integration

Drop custom patch, it's just better to do it here. This means we
go back to upstream telegramdesktop desktop-id too.

* telegram: get desktop file and icon from telegram part source

* snapcraft: improve snap description

* gcc7: not needed to add devscripts or equivs

Unless we try to build gcc7 here, which well... A bit time consuming.

* libunity: use upstream branch (my changes just merged)

* ci: remove travis integration, it takes to long b.s.io does it already

* telegram: don't do unneeded checks in armhf

* telegram: more signed/unsigned char fixes for ARM, ignore errors for now

* telegram: add getclock definitions for ARM

* telegram: arm support, always use signed chars

* telegram: don't need to use signed chars in ARM anymmore

As we've fixed all the issues

* telegram: replace .desktop file icon with snap one, add keywords

* snapcraft: use diversity check on alpha value

* telegram: detect Ubuntu desktop adding support for badges and indicators

* telegram: unset WAYLAND_DISPLAY to get it running properly

* Add a README

* telegram: just add network-observe plug

* snapcraft: add beta detection

* snapcraft: only add network-manager plug, users might connect it

We should actually have a connection-observe plug.

* patches: add patch to use a customizable working dir in debug

* snapcraft: define again QT_IM_MODULE and QTCOMPOSE fix compose key

Setting compose to proper paths will allow to get composition key
working again in snapped QT apps.

* desktop-integration: add indicator-gtk3 and chinese fonts

* desktop-integration: don't snap fonts, use desktop interface

Fonts are now bind-mounted from host by the desktop interface

* patches: apply patches using 3way merge if they fail

* patches: update telegram-arm-support to apply cleanly

* snapcraft: disable wayland using desktop script env

* snapcraft: libunity has been SRU'ed, we can go back to archive version

* patches: update arm support patch

* breakpad: use upstream versions

* telegram, patches: remove upstreamed patches

* patches: disable Werror

It causes failures in some archs, and we don't care much at this
level (for now).

* patches: remove libtgvoip msse2 patch

* Revert "patches: remove libtgvoip msse2 patch"

Not yet in the submodule used by telegram desktop

This reverts commit 2e6f4cc619.

* snapcraft: show bash debugging on version script

* desktop-gtk3: update mime database and icon-cache during install

This saves some startup time

* telegram: add gsettings plug

* telegram-launch: use user-common as home and migrate if needed

* Import snap folder from telegram-snap repo

* patches, qtbase: use indicator icon in unity or ubuntu

Patch already applied upstream, remove from snap only

* .gitignore: add snap related files

* telegram-launch: merge downloaded files folder if found

* snap: remove patches not needed for upstream

* snap, patch, libtgvoip: sync with upstream

* telegram-launch: remove default dir after moving download files

* snap: remove libtgvoip patches, we can just update the submodule

The actual module update should be managed in a different
commit though.

* snapcraft: explain why gcc7 part is needed

* snapcraft: update summary text

* qt: no need to build gstreamer, and reorder configflags

* plugins: add copyright informations

* telegram: add common-id and parse-info with AppData

Use the appstream integration that snapcraft now supports.

* openal: use v1.18 branch as upstream does now

* qtbuilder: support tags in versions better

* qtbuilder: use shutil.rmtree to remove files

* telegram: set QT_IM_MODULE only if not set

* telegram: add removable-media plug

* telegram-launch: ignore ibus as input method

And add support for getting it from $TELEGRAM_QT_IM_MODULE env var

* snapcraft: use git describe to get revision

* snapcraft: use override-* stanzas for scriptlets

* snap: exit scriptlets on first error

* snap: remove summary, inherit from AppData

* lib_export: use includes paths as defined per platform
2018-07-21 17:35:37 +03:00
Omkar Nath Singh
08841ed895 Update Fedora version
Working fine on Fedora 28.
2018-07-17 00:42:34 +03:00
John Preston
a919737f6e Version 1.3.10.
- Bug fixes and other minor improvements.
2018-07-13 14:19:25 +03:00
John Preston
8f3510b3c4 Use reverse chronological order in export. 2018-07-13 14:17:50 +03:00
John Preston
6c588a8f2f Closed beta 1.3.9.3. 2018-07-12 22:27:24 +03:00
John Preston
4c9ef606f3 Display unread/mention mark in small left column.
Fixes #4939.
2018-07-12 22:25:10 +03:00
John Preston
0b7bb806b7 Improve export HTML layout. 2018-07-12 21:15:36 +03:00
John Preston
78558e513c Closed beta 1.3.9.2. 2018-07-12 18:35:59 +03:00
John Preston
52e7ddf079 Add '-externalupdater' command-line argument.
Now no-autoupdater mode can be switched on in runtime.
Also TDESKTOP_DISABLE_AUTOUPDATE build is disabled in CI (trivial).

Fixes #4895.
2018-07-12 18:35:59 +03:00
John Preston
e2bc6990c7 Fix crash in taskbar icon refresher.
Regression was introduced in 3b956c598.
2018-07-11 23:20:21 +03:00
John Preston
06c3082fdf Fix popular sticker suggestions.
Regression was introduced in ddb4527159.

Fixes #4966.
2018-07-11 23:15:55 +03:00
John Preston
54cd55523b Fix crash in markdown preprocessing. 2018-07-11 17:56:09 +03:00
John Preston
556f75ef6c Rewrite TCP socket reading using bytes::vector.
I hope this fixes a strange assertion violation.
2018-07-11 17:56:09 +03:00
John Preston
951634a717 Closed beta 1.3.9.1. 2018-07-11 17:56:09 +03:00
John Preston
51d7e177a6 Fix error layout in passport email/phone. 2018-07-11 17:56:09 +03:00
John Preston
81e074115d Fix build for Xcode.
Regression was introduced in a8d35b67aa.
2018-07-11 17:56:09 +03:00
John Preston
9eb34e496f Update langs. 2018-07-11 17:56:08 +03:00
John Preston
da60739893 Allow uploading many scans at once in passport. 2018-07-11 17:56:08 +03:00
John Preston
7be1f16313 Don't display errors list in passport. 2018-07-11 17:56:08 +03:00
John Preston
39b0d9e46f Handle the outdated app error in passport. 2018-07-11 17:56:08 +03:00
John Preston
7be9e0fb94 Warn on passport save before upload is finished. 2018-07-11 17:56:07 +03:00
John Preston
e3e8d083ea Remember passport credentials for 30 minutes. 2018-07-11 17:56:07 +03:00
John Preston
9929bfb281 If only selfie is missing use special phrases. 2018-07-11 17:56:07 +03:00
John Preston
effa277a3b Update libtgvoip to 2.1.1. 2018-07-11 17:56:07 +03:00
John Preston
2661f81fd1 Fix field bar cancel button visibility.
Fixes #4913.
2018-07-11 17:56:07 +03:00
John Preston
661de0c326 Improve phrases in passport. 2018-07-11 17:56:06 +03:00
John Preston
e1fd43b2a4 Fix crash in text post processing.
Fixes #4948.
2018-07-11 17:56:06 +03:00
John Preston
b697824540 When following a post link push reply-return.
Fixes #4856.
2018-07-11 17:56:06 +03:00
John Preston
eb3eef4b80 Fix notify settings saving (mute vs silent).
Fixes #4855.
2018-07-10 12:18:41 +03:00
John Preston
c3736c6fa3 Improve photo/video/sticker/GIF export layout. 2018-07-10 12:18:41 +03:00
John Preston
0ef7503917 Improve export history pagination. 2018-07-10 12:18:41 +03:00
John Preston
cef50e5f52 Export file thumbs, use in video messages. 2018-07-10 12:18:41 +03:00
John Preston
cb8ff398a5 Improved html message layout. 2018-07-10 12:18:41 +03:00
John Preston
eeb1a6b769 Add service messages HTML layout. 2018-07-10 12:18:41 +03:00
John Preston
66822f7333 Add some HTML design to export, except messages.
NB Testing the layout, the app is not in a working condition.
2018-07-10 12:18:41 +03:00
John Preston
e466dc9fc7 Fix default build.
Regression was introduced in a8d35b67aa.
2018-07-10 12:14:53 +03:00
Sven-Hendrik Haase
947204bb9d Add missing include to <gsl/gsl> (#4886) 2018-07-03 20:23:14 +03:00
Sven-Hendrik Haase
f37f097dec Add include to <memory> (#4887) 2018-07-03 20:22:52 +03:00
Marco Trevisan
a8d35b67aa lib_export: use includes paths as defined per platform (#4935) 2018-07-03 12:56:51 +03:00
John Preston
4e0d94f347 Version 1.3.9: Fix build for Xcode. 2018-06-28 20:26:31 +01:00
John Preston
c7e773dd9a Version 1.3.9.
- Mark chats in the chat list as Read or Unread.
- Improved censorship circumvention.
2018-06-28 20:12:07 +01:00
John Preston
e64d102efd Better display of first_name + last_name. 2018-06-28 20:01:26 +01:00
John Preston
49ea9434f2 Better nested key-value html serialization. 2018-06-28 18:52:57 +01:00
John Preston
e21c354428 Improve suggest export logic. 2018-06-28 18:44:07 +01:00
John Preston
d0614efd65 Prevent displaying two export suggest boxes. 2018-06-28 18:29:52 +01:00
John Preston
b0baf75fdd Fix forwarded names in saved messages export. 2018-06-28 18:25:23 +01:00
John Preston
efb3e92525 Show "Saved messages" chat name in export UI. 2018-06-28 18:12:13 +01:00
John Preston
5cdc563c9e Add saving of shared contacts vcards in export. 2018-06-28 18:03:44 +01:00
John Preston
a43dfc567c Allow injecting fail handlers in export.
Handle CHANNEL_PRIVATE while exporting all channel messages.
2018-06-28 17:25:50 +01:00
John Preston
ea6e4c6006 Display correct info in pinned message. 2018-06-28 16:28:45 +01:00
John Preston
98930792c3 Fix fast reply and right action in sent messages.
Fixes #4903.
2018-06-28 16:24:39 +01:00
John Preston
165d1aacae Fix tilde formatting in InputField.
Regression was introduced somewhen while uniting input field classes.

Fixes #4829.
2018-06-28 16:07:53 +01:00
John Preston
831f1b6aee Fix crash in file inline bot results.
Fixes #4904.
2018-06-28 16:01:32 +01:00
John Preston
2f5fb3688a Fix crash for invalid inline bot stickers. 2018-06-28 15:15:47 +01:00
John Preston
d8897a0cc8 Make export done button adaptive to text. 2018-06-28 04:39:23 +01:00
John Preston
3b956c598b Fix data export window theme changing.
Fixes #4902.
2018-06-28 04:39:10 +01:00
John Preston
1ee71bbd5c Update GSL to v1.0.0 2018-06-27 22:58:33 +01:00
John Preston
b7ab4fd086 Improve triple-backtick replacement. 2018-06-27 22:58:33 +01:00
John Preston
44c6050bf2 Fix field autocomplete in empty chat. 2018-06-27 22:58:33 +01:00
John Preston
35c759c6bc Mark [un]read from chats list. 2018-06-27 22:58:32 +01:00
John Preston
372cf275e0 Skip draft updates while sending with clear_draft.
I hope fixes #4845, fixes #4852, fixes #4861.
2018-06-27 22:58:32 +01:00
John Preston
33095966af Move sendMessage and sendInlineResult to ApiWrap. 2018-06-27 22:58:32 +01:00
John Preston
ff53404d5b Update API scheme to layer 82. 2018-06-27 22:58:32 +01:00
John Preston
941288b58e Handle new paddings in improved TCP protocol. 2018-06-27 22:58:31 +01:00
John Preston
22441ef80c Handle improved protocol secrets. 2018-06-25 20:22:03 +01:00
John Preston
8c2f11de7d Send correct paddings in improved TCP protocol. 2018-06-25 19:55:52 +01:00
John Preston
c7a4d67cfb Version 1.3.8.
- Testing new data export.
- Bug fixes and other minor improvements.
2018-06-24 16:17:46 +01:00
John Preston
688275ea81 Fix update request timeout. 2018-06-24 16:17:46 +01:00
John Preston
266102df2f Some phrases fixed, some logs added. 2018-06-24 16:17:46 +01:00
John Preston
f7aadc352b Handle LOCATION_INVALID error. 2018-06-24 15:44:53 +01:00
John Preston
1ae3af0e80 Split messages.html by 1000 messages. 2018-06-24 15:44:53 +01:00
John Preston
97d27fe869 Closed beta 1.3.7.4. 2018-06-24 15:44:53 +01:00
John Preston
fcd2e28abb Add some logs. 2018-06-24 15:44:53 +01:00
John Preston
2522e66969 Move export descriptions to lang. 2018-06-24 15:44:53 +01:00
John Preston
b9250edb33 Some more export data improvements. 2018-06-24 15:44:53 +01:00
John Preston
54cab2c5a5 Add other additional data export. 2018-06-24 15:44:53 +01:00
John Preston
6231db1411 Closed beta 1.3.7.3. 2018-06-24 15:44:53 +01:00
John Preston
ef5a395c60 Improve export folder structure. 2018-06-24 15:44:53 +01:00
John Preston
a200771868 Don't suggest export if one is running. 2018-06-24 15:44:53 +01:00
John Preston
914e043abe Improve export phrases. 2018-06-24 15:44:53 +01:00
John Preston
9d66f9cc03 Add basic HTML export. 2018-06-24 15:44:53 +01:00
John Preston
e708065446 Closed beta 1.3.7.2: Fix build for Windows. 2018-06-23 01:02:20 +01:00
John Preston
9c64cdb9c4 Closed beta 1.3.7.2. 2018-06-23 00:57:12 +01:00
John Preston
9f8d61ab2f Add information about saved data. 2018-06-23 00:56:53 +01:00
John Preston
0143fd28af Suggest start export when time comes. 2018-06-23 00:56:53 +01:00
John Preston
844d030332 Save export settings to local storage. 2018-06-23 00:56:53 +01:00
John Preston
ae18ece549 Ask export path with other export options. 2018-06-23 00:56:53 +01:00
John Preston
10a0c6a086 Update phrases. 2018-06-23 00:56:53 +01:00
John Preston
51189fd244 Fix empty chats assertion violation. 2018-06-23 00:56:53 +01:00
John Preston
1e10529f20 Fix Linux build. Use -flto for static libraries.
Some unbelievable crashes happen in MTP codegen-ed serialization
if the binary is using -flto with MTP in non-flto static library.

To build and link static libraries with -flto additional GYP patch
is required, so that ar/ranlib/nm use gcc- wrappers.
2018-06-23 00:28:44 +01:00
John Preston
8d701ebb4f Fix rpl::variable assignment. 2018-06-22 17:45:05 +01:00
John Preston
269bb94138 Closed beta 1.3.7.1: Fix build with GCC. 2018-06-22 01:44:28 +01:00
John Preston
9b98ff52ea Closed beta 1.3.7.1: Fix build for Xcode. 2018-06-22 01:25:54 +01:00
John Preston
52f2f96f36 Closed beta 1.3.7.1: Fix Release build. 2018-06-22 01:01:45 +01:00
John Preston
b53e40f1bf Closed beta 1.3.7.1. 2018-06-22 00:48:32 +01:00
John Preston
4e0d11f517 Add export format selection (text / json). 2018-06-22 00:48:18 +01:00
John Preston
1a24ba857c Parse message entities, export in JSON. 2018-06-22 00:48:18 +01:00
John Preston
1e254b958e Update crl submodule. 2018-06-22 00:48:18 +01:00
John Preston
23140b3d6a Fix build for old OS X. 2018-06-21 23:35:28 +01:00
John Preston
8c901d8f71 Fix build for Xcode. 2018-06-21 22:25:14 +01:00
John Preston
856356ce75 Add web authorizations export. 2018-06-21 22:15:27 +01:00
John Preston
b5a65a4519 Add export to JSON. 2018-06-21 21:42:50 +01:00
John Preston
d056c00c67 Use split ranges to export all messages. 2018-06-21 19:58:54 +01:00
John Preston
36fb6dac89 Call finish takeout. Handle errors. 2018-06-21 14:50:56 +01:00
John Preston
fcda883878 Show messages count in an exported chat. 2018-06-20 22:22:10 +01:00
John Preston
40c0286942 Export userpics in a separate file. 2018-06-20 21:53:31 +01:00
John Preston
59df447fed Request frequent contacts calls category. 2018-06-20 21:39:04 +01:00
John Preston
a253d34c00 Name files by index, not by media date. 2018-06-20 21:32:52 +01:00
John Preston
0a5eac50be Unite Dialogs and LeftChannels in Export. 2018-06-20 19:21:36 +01:00
John Preston
156c3d288c Allow selecting export folder. 2018-06-20 19:12:47 +01:00
John Preston
154e5660de Confirm export stop on quit and logout. 2018-06-20 18:30:57 +01:00
John Preston
13e6b91ac7 Remove old done widget in Export. 2018-06-20 17:45:52 +01:00
John Preston
a89ad5d0fb Add export my data button in Settings. 2018-06-20 17:41:59 +01:00
John Preston
e11c27048b Add export statistics for the final screen. 2018-06-20 17:10:38 +01:00
John Preston
e8dd277a00 Improve export progress / finished design. 2018-06-20 16:59:27 +01:00
John Preston
329db0d8e9 Export panel minimizes to a top bar, like a Call. 2018-06-20 01:02:36 +01:00
John Preston
eaf3ea9289 Fix dialogs list in export. 2018-06-20 01:01:41 +01:00
John Preston
4156beaa3c Export top peers as frequent contacts. 2018-06-19 21:40:16 +01:00
John Preston
4115d3d13d Display export progress. 2018-06-19 19:31:30 +01:00
John Preston
5f01751660 Display errors in export UI.
All errors are now fatal errors :(
2018-06-19 13:35:21 +01:00
John Preston
7d4e23448e Better steps division in export. 2018-06-18 22:52:13 +01:00
John Preston
c7aa5ed544 _DEBUG-test ConcurrentSender generic handlers. 2018-06-17 21:29:50 +01:00
John Preston
1bfe409c93 Export my messages from left channels. 2018-06-17 21:15:40 +01:00
John Preston
e8d619c740 Some export bugs fixed. 2018-06-17 18:18:34 +01:00
John Preston
2dc3ec955a Add downloaded files cache in export.
Also write downloaded photo paths.
2018-06-17 13:47:47 +01:00
John Preston
07ff7c6cb0 Request only my messages by settings bits. 2018-06-17 13:47:07 +01:00
John Preston
8d52ca6be6 Apply file type/size restrictions in export. 2018-06-17 09:54:38 +01:00
John Preston
df91b2bfeb Export settings layout ready. 2018-06-16 20:48:38 +01:00
John Preston
9d02e539c8 Update scheme for special export methods.
Export all saved contacts.
2018-06-16 20:48:38 +01:00
John Preston
241fee80a7 Export full messages information.
Also add some more .match() calls to MTP codegen-ed classes.
2018-06-14 21:34:53 +03:00
John Preston
83786ddeaf Export chat messages photos and documents.
Also rename .visit() with .match() in MTP types.
Also add base::match_method() and base::match() for base::variant.
Also add base::match() and .match() for base::optional_variant.
2018-06-14 01:09:48 +03:00
John Preston
0e9793b845 Move MimeType from utils to core/mime_type.
Also move to Core namespace.
2018-06-14 01:08:47 +03:00
John Preston
2b36dd660b Export chat messages text. 2018-06-13 16:12:36 +03:00
John Preston
35ffc03988 Use .visit() in export data parsing. 2018-06-12 22:59:58 +03:00
John Preston
5a9d1a3fce Add .visit(many, callbacks) method to MTP types. 2018-06-12 22:59:58 +03:00
John Preston
6776d88688 Add chats list export. 2018-06-12 21:09:21 +03:00
John Preston
affe9defb5 Fix authorization import in FILE_MIGRATE case.
Regression was introduced in dd933cf61c.
2018-06-12 16:30:00 +03:00
John Preston
d3fdf433cd Export sessions list. 2018-06-12 01:02:05 +03:00
John Preston
cec8114b99 Add simple files and contacts export.
Also move all API calls in export to Export::ApiWrap.
2018-06-12 01:02:05 +03:00
John Preston
0a1a5ed70e Use abstract export writer for different formats. 2018-06-12 01:02:05 +03:00
John Preston
c587c011d2 Start data export in lib_export. 2018-06-12 01:02:04 +03:00
John Preston
c2fa149ffd Replace InvokeQueued with on_main for has_weak_ptr. 2018-06-12 01:02:04 +03:00
John Preston
c63c75018d Update crl submodule. 2018-06-12 01:02:04 +03:00
John Preston
b0077d98f0 Version 1.3.7: Fix file dialog parent widget.
Regression was introduced in 67ea175fc6.

Fixes #4817.
2018-06-11 23:40:30 +03:00
John Preston
b5bc7a22af Version 1.3.7: Possible bug fix.
Attempt to fix strange crash in SPMediaKeyTap.
2018-06-11 22:31:44 +03:00
John Preston
e60311811b Version 1.3.7.
- Push fixes to stable version.
2018-06-11 22:28:34 +03:00
John Preston
8700c1b08f Alpha version 1.3.6: Make it another alpha. 2018-06-11 10:42:20 +03:00
John Preston
d8b51670e7 Version 1.3.6.
- Bug fixes and other minor improvements.
2018-06-11 10:39:59 +03:00
John Preston
68c2f563c6 Write logs without QTextStream. 2018-06-11 10:37:29 +03:00
John Preston
bf775cb4ca Fix history items cleanup. 2018-06-09 11:52:37 +03:00
John Preston
5c4b81434e Alpha version 1.3.5.
- Bug fixes and other minor improvements.
2018-06-08 23:12:00 +03:00
John Preston
cd1c7c56d3 Skip old and currently-sending draft updates. 2018-06-08 23:06:26 +03:00
John Preston
427ceb9a9a Submit MuteSettingsBox by Enter. 2018-06-08 22:26:23 +03:00
John Preston
2a110f0d3e Improve passport styles. 2018-06-08 22:26:08 +03:00
John Preston
d0ed75f3b5 Update langs. 2018-06-08 21:32:20 +03:00
John Preston
be2abd594f Alpha version 1.3.4.
- Bug fixes and other minor improvements.
2018-06-07 22:29:27 +03:00
John Preston
75a40b83ae Notify settings unknown => draw chats as muted.
Also request common notify settings at the app launch.
2018-06-07 22:28:09 +03:00
John Preston
472a677bca Fix crash in special scan upload. 2018-06-07 22:11:55 +03:00
John Preston
dca6e10beb Fix markdown apply to text with emoji. 2018-06-07 22:00:46 +03:00
John Preston
122ab94f3d Fix text color glitch after palette update.
Once again fixes #4774.
2018-06-07 21:25:10 +03:00
John Preston
2ab40de8b9 Alpha version 1.3.3.
- Bug fixes and other minor improvements.
2018-06-07 10:50:34 +03:00
John Preston
35659536c5 Fix first passcode unlock.
Fixes #4811.
2018-06-07 10:44:38 +03:00
474 changed files with 36594 additions and 7268 deletions

View File

@@ -56,10 +56,6 @@ GOTO:EOF
call:logInfo "Build version: %BUILD_VERSION%"
set TDESKTOP_BUILD_DEFINES=
echo %BUILD_VERSION% | findstr /C:"disable_autoupdate">nul && (
set TDESKTOP_BUILD_DEFINES=%TDESKTOP_BUILD_DEFINES%,TDESKTOP_DISABLE_AUTOUPDATE
)
echo %BUILD_VERSION% | findstr /C:"disable_register_custom_scheme">nul && (
set TDESKTOP_BUILD_DEFINES=%TDESKTOP_BUILD_DEFINES%,TDESKTOP_DISABLE_REGISTER_CUSTOM_SCHEME
)

View File

@@ -22,8 +22,5 @@ Tell us what happens instead
**Used theme**:
<details><summary><b>Logs</b>:</summary>
Insert logs here (if necessary)
<!-- You can type `debugmode` in settings and then see ~/.TelegramDesktop/DebugLogs/log_...txt for log files.
Type `debugmode` in settings again to disable logs. -->
Insert log.txt here (if necessary)
</details>

9
.gitignore vendored
View File

@@ -50,6 +50,15 @@ ipch/
project.xcworkspace
xcuserdata
parts
prime
stage
*.snap
.snapcraft
/snap/gui/*.png
/snap/gui/*.desktop
/snap/plugins/__pycache__
/Telegram/*.user.*
*.pro.user
/Linux/

3
.gitmodules vendored
View File

@@ -13,3 +13,6 @@
[submodule "Telegram/ThirdParty/crl"]
path = Telegram/ThirdParty/crl
url = https://github.com/telegramdesktop/crl.git
[submodule "Telegram/ThirdParty/xxHash"]
path = Telegram/ThirdParty/xxHash
url = https://github.com/Cyan4973/xxHash.git

View File

@@ -10,7 +10,6 @@ cache:
env:
matrix:
- BUILD_VERSION=""
- BUILD_VERSION="disable_autoupdate"
- BUILD_VERSION="disable_register_custom_scheme"
- BUILD_VERSION="disable_crash_reports"
- BUILD_VERSION="disable_network_proxy"

View File

@@ -100,10 +100,6 @@ build() {
fi
# Configure the build
if [[ $BUILD_VERSION == *"disable_autoupdate"* ]]; then
GYP_DEFINES+=",TDESKTOP_DISABLE_AUTOUPDATE"
fi
if [[ $BUILD_VERSION == *"disable_register_custom_scheme"* ]]; then
GYP_DEFINES+=",TDESKTOP_DISABLE_REGISTER_CUSTOM_SCHEME"
fi

View File

@@ -16,7 +16,7 @@ The source code is published under GPLv3 with OpenSSL exception, the license is
* Mac OS X 10.8 - Mac OS X 10.11
* Mac OS X 10.6 - Mac OS X 10.7 (separate build)
* Ubuntu 12.04 - Ubuntu 18.04
* Fedora 22 - Fedora 24
* Fedora 22 - Fedora 28
## Third-party
@@ -39,6 +39,7 @@ The source code is published under GPLv3 with OpenSSL exception, the license is
* Open Sans font ([Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0.html))
* Emoji alpha codes ([MIT License](https://github.com/emojione/emojione/blob/master/extras/alpha-codes/LICENSE.md))
* Catch test framework ([Boost License](https://github.com/philsquared/Catch/blob/master/LICENSE.txt))
* xxHash ([BSD License](https://github.com/Cyan4973/xxHash/blob/dev/LICENSE))
## Build instructions

View File

@@ -1,5 +1,5 @@
diff --git a/pylib/gyp/generator/cmake.py b/pylib/gyp/generator/cmake.py
index a2b9629..68d7020 100644
index a2b9629..ac59461 100644
--- a/pylib/gyp/generator/cmake.py
+++ b/pylib/gyp/generator/cmake.py
@@ -1070,6 +1070,23 @@ def WriteTarget(namer, qualified_target, target_dicts, build_dir, config_to_use,
@@ -26,6 +26,43 @@ index a2b9629..68d7020 100644
UnsetVariable(output, 'TOOLSET')
UnsetVariable(output, 'TARGET')
@@ -1112,6 +1129,8 @@ def GenerateOutputForConfig(target_list, target_dicts, data,
SetVariable(output, 'configuration', config_to_use)
ar = None
+ ranlib = None
+ nm = None
cc = None
cxx = None
@@ -1121,17 +1140,27 @@ def GenerateOutputForConfig(target_list, target_dicts, data,
for key, value in make_global_settings:
if key == 'AR':
ar = os.path.join(build_to_top, value)
+ if key == 'RANLIB':
+ ranlib = os.path.join(build_to_top, value)
+ if key == 'NM':
+ nm = os.path.join(build_to_top, value)
if key == 'CC':
cc = os.path.join(build_to_top, value)
if key == 'CXX':
cxx = os.path.join(build_to_top, value)
ar = gyp.common.GetEnvironFallback(['AR_target', 'AR'], ar)
+ ranlib = gyp.common.GetEnvironFallback(['RANLIB_target', 'RANLIB'], ranlib)
+ nm = gyp.common.GetEnvironFallback(['NM_target', 'NM'], nm)
cc = gyp.common.GetEnvironFallback(['CC_target', 'CC'], cc)
cxx = gyp.common.GetEnvironFallback(['CXX_target', 'CXX'], cxx)
if ar:
SetVariable(output, 'CMAKE_AR', ar)
+ if ranlib:
+ SetVariable(output, 'CMAKE_RANLIB', ranlib)
+ if nm:
+ SetVariable(output, 'CMAKE_NM', nm)
if cc:
SetVariable(output, 'CMAKE_C_COMPILER', cc)
if cxx:
diff --git a/pylib/gyp/generator/xcode.py b/pylib/gyp/generator/xcode.py
index db99d6a..8d56baf 100644
--- a/pylib/gyp/generator/xcode.py

View File

@@ -252,6 +252,43 @@ index 41834b21ae..8cdf4ab145 100644
if (value == WSAEADDRNOTAVAIL) {
setError(QAbstractSocket::NetworkError, AddressNotAvailableErrorString);
socketState = QAbstractSocket::UnconnectedState;
diff --git a/src/platformsupport/dbustray/qdbustrayicon.cpp b/src/platformsupport/dbustray/qdbustrayicon.cpp
index 4d6e707..9bdb0be 100644
--- a/src/platformsupport/dbustray/qdbustrayicon.cpp
+++ b/src/platformsupport/dbustray/qdbustrayicon.cpp
@@ -58,9 +58,18 @@ QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(qLcTray, "qt.qpa.tray")
+static QString cachePath()
+{
+ QString xdgCache = QString::fromUtf8(getenv("XDG_CACHE_HOME"));
+ if (xdgCache.isEmpty()) {
+ xdgCache = QDir::cleanPath(QDir::homePath() + QStringLiteral("/.cache"));
+ }
+ return xdgCache;
+}
+
static const QString KDEItemFormat = QStringLiteral("org.kde.StatusNotifierItem-%1-%2");
static const QString KDEWatcherService = QStringLiteral("org.kde.StatusNotifierWatcher");
-static const QString TempFileTemplate = QDir::tempPath() + QStringLiteral("/qt-trayicon-XXXXXX.png");
+static const QString TempFileTemplate = cachePath() + QStringLiteral("/qt-trayicon-XXXXXX.png");
static const QString XdgNotificationService = QStringLiteral("org.freedesktop.Notifications");
static const QString XdgNotificationPath = QStringLiteral("/org/freedesktop/Notifications");
static const QString DefaultAction = QStringLiteral("default");
@@ -151,6 +160,12 @@ QTemporaryFile *QDBusTrayIcon::tempIcon(const QIcon &icon)
uint pid = session.interface()->servicePid(KDEWatcherService).value();
QString processName = QLockFilePrivate::processNameByPid(pid);
necessary = processName.endsWith(QStringLiteral("indicator-application-service"));
+ if (!necessary) {
+ QString xdgDesktop = QString::fromUtf8(getenv("XDG_CURRENT_DESKTOP"));
+ QStringList desktops = xdgDesktop.toLower().split(QLatin1Char(':'));
+ necessary = desktops.contains(QStringLiteral("unity")) ||
+ desktops.contains(QStringLiteral("ubuntu"));
+ }
necessity_checked = true;
}
if (!necessary)
diff --git a/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp b/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp
index 728b166b71..1dc64593e1 100644
--- a/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp

View File

@@ -0,0 +1,530 @@
body {
margin: 0;
font: 12px/18px 'Open Sans',"Lucida Grande","Lucida Sans Unicode",Arial,Helvetica,Verdana,sans-serif;
}
strong {
font-weight: 700;
}
code, kbd, pre, samp {
font-family: Menlo,Monaco,Consolas,"Courier New",monospace;
}
code {
padding: 2px 4px;
font-size: 90%;
color: #c7254e;
background-color: #f9f2f4;
border-radius: 4px;
}
pre {
display: block;
margin: 0;
line-height: 1.42857143;
word-break: break-all;
word-wrap: break-word;
color: #333;
background-color: #f5f5f5;
border-radius: 4px;
overflow: auto;
padding: 3px;
border: 1px solid #eee;
max-height: none;
font-size: inherit;
}
.clearfix:after {
content: " ";
visibility: hidden;
display: block;
height: 0;
clear: both;
}
.pull_left {
float: left;
}
.pull_right {
float: right;
}
.page_wrap {
background-color: #ffffff;
color: #000000;
}
.page_wrap a {
color: #168acd;
text-decoration: none;
}
.page_wrap a:hover {
text-decoration: underline;
}
.page_header {
position: fixed;
z-index: 10;
background-color: #ffffff;
width: 100%;
border-bottom: 1px solid #e3e6e8;
}
.page_header .content {
width: 480px;
margin: 0 auto;
border-radius: 0 !important;
}
.page_header a.content {
background-repeat: no-repeat;
background-position: 24px 21px;
background-size: 24px 24px;
}
.bold {
color: #212121;
font-weight: 700;
}
.details {
color: #70777b;
}
.page_header .content .text {
padding: 24px 24px 22px 24px;
font-size: 22px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.page_header a.content .text {
padding: 24px 24px 22px 82px;
}
.page_body {
padding-top: 64px;
width: 480px;
margin: 0 auto;
}
.page_about {
padding: 24px 24px;
}
.with_divider {
border-top: 1px solid #e3e6e8;
}
.userpic_link {
display: block;
text-decoration: none;
}
.userpic_link:hover {
text-decoration: none;
}
.userpic {
display: block;
border-radius: 50%;
overflow: hidden;
}
.userpic .initials {
display: block;
color: #fff;
text-align: center;
text-transform: uppercase;
user-select: none;
}
.color_red,
.userpic1,
.media_call .fill,
.media_file .fill,
.media_live_location .fill {
background-color: #ff5555;
}
.color_green,
.userpic2,
.media_call.success .fill,
.media_photo .fill {
background-color: #64bf47;
}
.color_yellow,
.userpic3,
.media_venue .fill {
background-color: #ffab00;
}
.color_blue,
.userpic4,
.media_audio_file .fill,
.media_voice_message .fill {
background-color: #4f9cd9;
}
.color_purple,
.userpic5,
.media_game .fill {
background-color: #9884e8;
}
.color_pink,
.userpic6,
.media_invoice .fill {
background-color: #e671a5;
}
.color_sea,
.userpic7,
.media_location .fill,
.media_video .fill {
background-color: #47bcd1;
}
.color_orange,
.userpic8,
.media_contact .fill {
background-color: #ff8c44;
}
.personal_info {
padding: 24px;
}
.personal_info .userpic .initials {
font-size: 30px;
}
.personal_info .rows {
float: left;
padding-right: 24px;
}
.personal_info .names {
width: 164px;
}
.personal_info .info {
width: 124px;
}
.personal_info .bio {
width: 400px;
}
.personal_info .row {
padding-bottom: 16px;
}
a.block_link {
display: block;
text-decoration: none !important;
border-radius: 4px;
}
a.block_link:hover {
text-decoration: none !important;
background-color: #f5f7f8;
}
.sections {
padding: 11px 0;
}
.section {
height: 48px;
background-position: 24px 12px;
background-repeat: no-repeat;
background-size: 24px 24px;
}
.section .counter {
float: right;
padding: 14px 24px 0;
font-size: 15px;
}
.section .label {
padding: 15px 0 0 82px;
font-size: 15px;
}
.list_page .page_about {
padding: 16px 24px 0;
font-size: 11px;
}
.list_page .entry_list {
padding: 16px 0;
}
.list_page .entry {
padding: 10px 16px;
}
.list_page .entry .userpic .initials {
font-size: 18px;
}
.list_page .entry .body {
margin-left: 66px;
}
.list_page .entry .name {
padding: 4px 0 2px;
font-size: 14px;
}
.list_page .entry .subname {
padding-top: 4px;
}
.list_page .entry .details_entry {
padding-top: 4px;
}
.list_page .entry .info {
font-size: 11px;
padding-top: 5px;
}
.history {
padding: 16px 0;
}
.message {
margin: 0 -10px;
transition: background-color 2.0s ease;
}
div.selected {
background-color: rgba(242,246,250,255);
transition: background-color 0.5s ease;
}
.service {
padding: 10px 24px;
}
.service .body {
text-align: center;
}
.service .userpic_wrap {
padding-top: 10px;
}
.service .userpic {
margin: 0 auto;
}
.service .userpic .initials {
font-size: 24px;
}
.message .userpic .initials {
font-size: 16px;
}
.default {
padding: 10px;
}
.default.joined {
margin-top: -10px;
}
.default .from_name {
color: #3892db;
font-weight: 700;
padding-bottom: 5px;
}
.default .from_name .details {
font-weight: normal;
}
.default .body {
margin-left: 60px;
}
.default .text {
word-wrap: break-word;
line-height: 150%;
}
.default .reply_to,
.default .media_wrap {
padding-bottom: 5px;
}
.default .media {
margin: 0 -10px;
padding: 5px 10px;
}
.default .media .fill,
.default .media .thumb {
width: 48px;
height: 48px;
border-radius: 50%;
}
.default .media .fill {
background-repeat: no-repeat;
background-position: 12px 12px;
background-size: 24px 24px;
}
.default .media .title {
padding-top: 4px;
font-size: 14px;
}
.default .media .description {
color: #000000;
padding-top: 4px;
font-size: 13px;
}
.default .media .status {
padding-top: 4px;
font-size: 13px;
}
.default .video_file_wrap,
.default .animated_wrap {
position: relative;
}
.default .video_file,
.default .animated,
.default .photo,
.default .sticker {
display: block;
}
.video_duration {
background: rgba(0, 0, 0, .4);
padding: 0px 5px;
position: absolute;
z-index: 2;
border-radius: 2px;
right: 3px;
bottom: 3px;
color: #ffffff;
font-size: 11px;
}
.video_play_bg {
background: rgba(0, 0, 0, .4);
width: 40px;
height: 40px;
line-height: 0;
position: absolute;
z-index: 2;
border-radius: 50%;
overflow: hidden;
margin: -20px auto 0 -20px;
top: 50%;
left: 50%;
pointer-events: none;
}
.video_play {
position: absolute;
display: inline-block;
top: 50%;
left: 50%;
margin-left: -5px;
margin-top: -9px;
z-index: 1;
width: 0;
height: 0;
border-style: solid;
border-width: 9px 0 9px 14px;
border-color: transparent transparent transparent #fff;
}
.gif_play {
font-weight: 700;
color: #FFF;
display: block;
line-height: 40px;
font-size: 13px;
text-align: center;
}
.pagination {
text-align: center;
padding: 20px;
font-size: 16px;
}
.toast_container {
position: fixed;
left: 50%;
top: 50%;
opacity: 0;
transition: opacity 3.0s ease;
}
.toast_body {
margin: 0 -50%;
float: left;
border-radius: 15px;
padding: 10px 20px;
background: rgba(0, 0, 0, 0.7);
color: #ffffff;
}
div.toast_shown {
opacity: 1;
transition: opacity 0.4s ease;
}
.section.calls {
background-image: url(../images/section_calls.png);
}
.section.chats {
background-image: url(../images/section_chats.png);
}
.section.contacts {
background-image: url(../images/section_contacts.png);
}
.section.frequent {
background-image: url(../images/section_frequent.png);
}
.section.photos {
background-image: url(../images/section_photos.png);
}
.section.sessions {
background-image: url(../images/section_sessions.png);
}
.section.web {
background-image: url(../images/section_web.png);
}
.section.other {
background-image: url(../images/section_other.png)
}
.page_header a.content {
background-image: url(../images/back.png);
}
.media_call .fill {
background-image: url(../images/media_call.png)
}
.media_contact .fill {
background-image: url(../images/media_contact.png)
}
.media_file .fill {
background-image: url(../images/media_file.png)
}
.media_game .fill {
background-image: url(../images/media_game.png)
}
.media_live_location .fill,
.media_location .fill,
.media_venue .fill {
background-image: url(../images/media_location.png)
}
.media_audio_file .fill {
background-image: url(../images/media_music.png)
}
.media_invoice .fill {
background-image: url(../images/media_shop.png)
}
.media_voice_message .fill {
background-image: url(../images/media_voice.png)
}
.media_photo .fill {
background-image: url(../images/media_photo.png)
}
.media_video .fill {
background-image: url(../images/media_video.png)
}
@media only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min-device-pixel-ratio: 2) {
.section.calls {
background-image: url(../images/section_calls@2x.png);
}
.section.chats {
background-image: url(../images/section_chats@2x.png);
}
.section.contacts {
background-image: url(../images/section_contacts@2x.png);
}
.section.frequent {
background-image: url(../images/section_frequent@2x.png);
}
.section.photos {
background-image: url(../images/section_photos@2x.png);
}
.section.sessions {
background-image: url(../images/section_sessions@2x.png);
}
.section.web {
background-image: url(../images/section_web@2x.png);
}
.section.other {
background-image: url(../images/section_other@2x.png);
}
.page_header a.content {
background-image: url(../images/back@2x.png);
}
.media_call .fill {
background-image: url(../images/media_call@2x.png)
}
.media_contact .fill {
background-image: url(../images/media_contact@2x.png)
}
.media_file .fill {
background-image: url(../images/media_file@2x.png)
}
.media_game .fill {
background-image: url(../images/media_game@2x.png)
}
.media_live_location .fill,
.media_location .fill,
.media_venue .fill {
background-image: url(../images/media_location@2x.png)
}
.media_audio_file .fill {
background-image: url(../images/media_music@2x.png)
}
.media_invoice .fill {
background-image: url(../images/media_shop@2x.png)
}
.media_voice_message .fill {
background-image: url(../images/media_voice@2x.png)
}
.media_photo .fill {
background-image: url(../images/media_photo@2x.png)
}
.media_video .fill {
background-image: url(../images/media_video@2x.png)
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 518 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 417 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 815 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 600 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 408 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 510 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 480 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 991 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 275 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 464 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 458 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 377 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 790 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 411 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 660 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 656 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 454 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 508 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1023 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 771 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 402 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 619 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 269 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 415 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 750 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 447 B

View File

@@ -0,0 +1,189 @@
"use strict";
window.AllowBackFromHistory = false;
function CheckLocation() {
var start = "#go_to_message";
var hash = location.hash;
if (hash.substr(0, start.length) == start) {
var messageId = parseInt(hash.substr(start.length));
if (messageId) {
GoToMessage(messageId);
}
} else if (hash == "#allow_back") {
window.AllowBackFromHistory = true;
}
}
function ShowToast(text) {
var container = document.createElement("div");
container.className = "toast_container";
var inner = container.appendChild(document.createElement("div"));
inner.className = "toast_body";
inner.appendChild(document.createTextNode(text));
var appended = document.body.appendChild(container);
setTimeout(function () {
AddClass(appended, "toast_shown");
setTimeout(function () {
RemoveClass(appended, "toast_shown");
setTimeout(function () {
document.body.removeChild(appended);
}, 3000);
}, 3000);
}, 0);
}
function ShowHashtag(tag) {
ShowToast("This is a hashtag '#" + tag + "' link.");
return false;
}
function ShowCashtag(tag) {
ShowToast("This is a cashtag '$" + tag + "' link.");
return false;
}
function ShowBotCommand(command) {
ShowToast("This is a bot command '/" + command + "' link.");
return false;
}
function ShowMentionName() {
ShowToast("This is a link to a user mentioned by name.");
return false;
}
function AddClass(element, name) {
var current = element.className;
var expression = new RegExp('(^|\\s)' + name + '(\\s|$)', 'g');
if (expression.test(current)) {
return;
}
element.className = current + ' ' + name;
}
function RemoveClass(element, name) {
var current = element.className;
var expression = new RegExp('(^|\\s)' + name + '(\\s|$)', '');
var match = expression.exec(current);
while ((match = expression.exec(current)) != null) {
if (match[1].length > 0 && match[2].length > 0) {
current = current.substr(0, match.index + match[1].length)
+ current.substr(match.index + match[0].length);
} else {
current = current.substr(0, match.index)
+ current.substr(match.index + match[0].length);
}
}
element.className = current;
}
function EaseOutQuad(t) {
return t * t;
}
function EaseInOutQuad(t) {
return (t < 0.5) ? (2 * t * t) : ((4 - 2 * t) * t - 1);
}
function ScrollHeight() {
if ("innerHeight" in window) {
return window.innerHeight;
} else if (document.documentElement) {
return document.documentElement.clientHeight;
}
return document.body.clientHeight;
}
function ScrollTo(top, callback) {
var html = document.documentElement;
var current = html.scrollTop;
var delta = top - current;
var finish = function () {
html.scrollTop = top;
if (callback) {
callback();
}
};
if (!window.performance.now || delta == 0) {
finish();
return;
}
var transition = EaseOutQuad;
var max = 300;
if (delta < -max) {
current = top + max;
delta = -max;
} else if (delta > max) {
current = top - max;
delta = max;
} else {
transition = EaseInOutQuad;
}
var duration = 150;
var interval = 7;
var time = window.performance.now();
var animate = function () {
var now = window.performance.now();
if (now >= time + duration) {
finish();
return;
}
var dt = (now - time) / duration;
html.scrollTop = Math.round(current + delta * transition(dt));
setTimeout(animate, interval);
};
setTimeout(animate, interval);
}
function ScrollToElement(element, callback) {
var header = document.getElementsByClassName("page_header")[0];
var headerHeight = header.offsetHeight;
var html = document.documentElement;
var scrollHeight = ScrollHeight();
var available = scrollHeight - headerHeight;
var padding = 10;
var top = element.offsetTop;
var height = element.offsetHeight;
var desired = top
- Math.max((available - height) / 2, padding)
- headerHeight;
var scrollTopMax = html.offsetHeight - scrollHeight;
ScrollTo(Math.min(desired, scrollTopMax), callback);
}
function GoToMessage(messageId) {
var element = document.getElementById("message" + messageId);
if (element) {
var hash = "#go_to_message" + messageId;
if (location.hash != hash) {
location.hash = hash;
}
ScrollToElement(element, function () {
AddClass(element, "selected");
setTimeout(function () {
RemoveClass(element, "selected");
}, 1000);
});
} else {
ShowToast("This message was not exported. Maybe it was deleted.");
}
return false;
}
function GoBack(anchor) {
if (!window.AllowBackFromHistory) {
return true;
}
history.back();
if (!anchor || !anchor.getAttribute) {
return true;
}
var destination = anchor.getAttribute("href");
if (!destination) {
return true;
}
setTimeout(function () {
location.href = destination;
}, 100);
return false;
}

View File

@@ -0,0 +1,55 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
"cloud_lng_passport_in_ar" = "Arabic";
"cloud_lng_passport_in_az" = "Azerbaijani";
"cloud_lng_passport_in_bg" = "Bulgarian";
"cloud_lng_passport_in_bn" = "Bangla";
"cloud_lng_passport_in_cs" = "Czech";
"cloud_lng_passport_in_da" = "Danish";
"cloud_lng_passport_in_de" = "German";
"cloud_lng_passport_in_dv" = "Divehi";
"cloud_lng_passport_in_dz" = "Dzongkha";
"cloud_lng_passport_in_el" = "Greek";
"cloud_lng_passport_in_en" = "English";
"cloud_lng_passport_in_es" = "Spanish";
"cloud_lng_passport_in_et" = "Estonian";
"cloud_lng_passport_in_fa" = "Persian";
"cloud_lng_passport_in_fr" = "French";
"cloud_lng_passport_in_he" = "Hebrew";
"cloud_lng_passport_in_hr" = "Croatian";
"cloud_lng_passport_in_hu" = "Hungarian";
"cloud_lng_passport_in_hy" = "Armenian";
"cloud_lng_passport_in_id" = "Indonesian";
"cloud_lng_passport_in_is" = "Icelandic";
"cloud_lng_passport_in_it" = "Italian";
"cloud_lng_passport_in_ja" = "Japanese";
"cloud_lng_passport_in_ka" = "Georgian";
"cloud_lng_passport_in_km" = "Khmer";
"cloud_lng_passport_in_ko" = "Korean";
"cloud_lng_passport_in_lo" = "Lao";
"cloud_lng_passport_in_lt" = "Lithuanian";
"cloud_lng_passport_in_lv" = "Latvian";
"cloud_lng_passport_in_mk" = "Macedonian";
"cloud_lng_passport_in_mn" = "Mongolian";
"cloud_lng_passport_in_ms" = "Malay";
"cloud_lng_passport_in_my" = "Burmese";
"cloud_lng_passport_in_ne" = "Nepali";
"cloud_lng_passport_in_nl" = "Dutch";
"cloud_lng_passport_in_pl" = "Polish";
"cloud_lng_passport_in_pt" = "Portuguese";
"cloud_lng_passport_in_ro" = "Romanian";
"cloud_lng_passport_in_ru" = "Russian";
"cloud_lng_passport_in_sk" = "Slovak";
"cloud_lng_passport_in_sl" = "Slovenian";
"cloud_lng_passport_in_th" = "Thai";
"cloud_lng_passport_in_tk" = "Turkmen";
"cloud_lng_passport_in_tr" = "Turkish";
"cloud_lng_passport_in_uk" = "Ukrainian";
"cloud_lng_passport_in_uz" = "Uzbek";
"cloud_lng_passport_in_vi" = "Vietnamese";

View File

@@ -355,14 +355,28 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_settings_section_privacy" = "Privacy and Security";
"lng_local_storage_title" = "Local storage";
"lng_settings_no_data_cached" = "No cached data found!";
"lng_settings_images_cached#one" = "{count} image, {size}";
"lng_settings_images_cached#other" = "{count} images, {size}";
"lng_settings_audios_cached#one" = "{count} voice message, {size}";
"lng_settings_audios_cached#other" = "{count} voice messages, {size}";
"lng_local_storage_empty" = "No cached files";
"lng_local_storage_image#one" = "{count} image";
"lng_local_storage_image#other" = "{count} images";
"lng_local_storage_sticker#one" = "{count} sticker";
"lng_local_storage_sticker#other" = "{count} stickers";
"lng_local_storage_voice#one" = "{count} voice message";
"lng_local_storage_voice#other" = "{count} voice messages";
"lng_local_storage_round#one" = "{count} video message";
"lng_local_storage_round#other" = "{count} video messages";
"lng_local_storage_animation#one" = "{count} animation";
"lng_local_storage_animation#other" = "{count} animations";
"lng_local_storage_size_limit" = "Total size limit: {size}";
"lng_local_storage_time_limit" = "Clear files older than: {limit}";
"lng_local_storage_limit_weeks#one" = "{count} week";
"lng_local_storage_limit_weeks#other" = "{count} weeks";
"lng_local_storage_limit_months#one" = "{count} month";
"lng_local_storage_limit_months#other" = "{count} months";
"lng_local_storage_limit_never" = "Never";
"lng_local_storage_summary" = "Summary";
"lng_local_storage_clear_some" = "Clear";
"lng_local_storage_clear" = "Clear all";
"lng_local_storage_clearing" = "Clearing...";
"lng_local_storage_cleared" = "Cleared!";
"lng_settings_section_advanced_settings" = "Advanced Settings";
"lng_settings_enable_night_theme" = "Enable night mode";
@@ -469,6 +483,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_settings_calls_privacy" = "Phone calls privacy";
"lng_settings_groups_invite_privacy" = "Group invite settings";
"lng_settings_show_sessions" = "Show all sessions";
"lng_settings_export_data" = "Export Telegram data";
"lng_settings_self_destruct" = "Account self-destruct settings";
"lng_settings_change_phone" = "Change phone number";
@@ -671,6 +686,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_profile_delete_conversation" = "Delete conversation";
"lng_profile_block_user" = "Block user";
"lng_profile_unblock_user" = "Unblock user";
"lng_profile_export_chat" = "Export chat history";
"lng_profile_export_channel" = "Export channel history";
"lng_media_selected_photo#one" = "{count} Photo";
"lng_media_selected_photo#other" = "{count} Photos";
"lng_media_selected_video#one" = "{count} Video";
@@ -1105,6 +1122,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_context_view_feed_info" = "View feed info";
"lng_context_pin_to_top" = "Pin to top";
"lng_context_unpin_from_top" = "Unpin from top";
"lng_context_mark_unread" = "Mark as unread";
"lng_context_mark_read" = "Mark as read";
"lng_context_promote_admin" = "Promote to admin";
"lng_context_edit_permissions" = "Edit permissions";
@@ -1548,7 +1567,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_passport_password_wrong" = "The password you entered is not valid.";
"lng_passport_header" = "Requested information";
"lng_passport_identity_title" = "Identity document";
"lng_passport_identity_description" = "Upload a scan of your passport or another ID";
"lng_passport_identity_description" = "Upload proof of your identity";
"lng_passport_identity_passport" = "Passport";
"lng_passport_identity_passport_upload" = "Upload a scan of your passport";
"lng_passport_identity_card" = "Identity card";
@@ -1567,16 +1586,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_passport_address_agreement" = "Tenancy agreement";
"lng_passport_address_agreement_upload" = "Upload a scan of your tenancy agreement";
"lng_passport_address_registration" = "Passport registration";
"lng_passport_address_registration_upload" = "Upload a scan of your passport registration";
"lng_passport_address_registration_upload" = "Upload a scan of your passport registration page";
"lng_passport_address_temporary" = "Temporary registration";
"lng_passport_address_temporary_upload" = "Upload a scan of your temporary registration";
"lng_passport_address_about" = "To confirm your address, please upload a scan or photo of the selected document (all pages).";
"lng_passport_or_title" = "{document} or {second_document}";
"lng_passport_document_type" = "Please choose the type of your document:";
"lng_passport_upload_document" = "Upload document";
"lng_passport_phone_title" = "Phone number";
"lng_passport_phone_description" = "Enter your phone number";
"lng_passport_email_title" = "Email";
"lng_passport_email_description" = "Enter your email address";
"lng_passport_identity_selfie" = "Take a selfie with your document";
"lng_passport_translation_needed" = "Upload a translation of your document";
"lng_passport_accept_allow" = "You accept the {policy} and allow their {bot} to send you messages.";
"lng_passport_allow" = "You allow {bot} to send you messages.";
"lng_passport_policy" = "{bot} privacy policy";
@@ -1589,24 +1611,30 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_passport_upload_scans" = "Upload scans";
"lng_passport_upload_more" = "Upload additional scans";
"lng_passport_selfie_title" = "Selfie";
"lng_passport_selfie_name" = "Photo";
"lng_passport_selfie_description" = "Upload a photo of yourself holding your document. Make sure the ID and your face are clearly visible.";
"lng_passport_upload_selfie" = "Upload selfie";
"lng_passport_reupload_selfie" = "Reupload selfie";
"lng_passport_front_side_title" = "Front side";
"lng_passport_front_side_name" = "Scan";
"lng_passport_front_side_description" = "Upload front side of your document.";
"lng_passport_upload_front_side" = "Upload front side scan";
"lng_passport_front_side_description" = "Upload the front side of your document.";
"lng_passport_upload_front_side" = "Upload a scan of the front side";
"lng_passport_reupload_front_side" = "Reupload a scan of the front side";
"lng_passport_reverse_side_title" = "Reverse side";
"lng_passport_reverse_side_name" = "Scan";
"lng_passport_reverse_side_description" = "Upload reverse side of your document.";
"lng_passport_upload_reverse_side" = "Upload reverse side scan";
"lng_passport_reverse_side_description" = "Upload the reverse side of your document.";
"lng_passport_upload_reverse_side" = "Upload a scan of the reverse side";
"lng_passport_reupload_reverse_side" = "Reupload a scan of the reverse side";
"lng_passport_main_page_title" = "Main page";
"lng_passport_main_page_description" = "Upload the main page of your document.";
"lng_passport_upload_main_page" = "Upload a scan of the main page";
"lng_passport_reupload_main_page" = "Reupload a scan of the main page";
"lng_passport_personal_details" = "Personal details";
"lng_passport_personal_details_enter" = "Enter your personal details";
"lng_passport_personal_details_enter" = "Fill in your personal details";
"lng_passport_document_details" = "Document details";
"lng_passport_choose_image" = "Choose scan image";
"lng_passport_delete_scan_undo" = "Undo";
"lng_passport_scan_uploaded" = "Uploaded on {date}";
"lng_passport_first_name" = "Name";
"lng_passport_last_name" = "Surname";
"lng_passport_first_name" = "First name";
"lng_passport_middle_name" = "Middle name";
"lng_passport_last_name" = "Last name";
"lng_passport_birth_date" = "Date of birth";
"lng_passport_gender" = "Gender";
"lng_passport_gender_male" = "Male";
@@ -1614,14 +1642,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_passport_country" = "Country";
"lng_passport_residence_country" = "Residence";
"lng_passport_country_choose" = "Choose country";
"lng_passport_document_number" = "Card Number";
"lng_passport_document_number" = "Document Number";
"lng_passport_expiry_date" = "Expiry date";
"lng_passport_native_name_title" = "Name in document language";
"lng_passport_native_name_about" = "Your name in the language of the country ({country}) that issued the document.";
"lng_passport_native_name_language" = "Your name in {language}";
"lng_passport_native_name_language_about" = "Your name in the language of the country that issued the document.";
"lng_passport_address" = "Address";
"lng_passport_address_enter" = "Enter your address";
"lng_passport_address_enter" = "Please provide your address";
"lng_passport_street" = "Street";
"lng_passport_city" = "City";
"lng_passport_state" = "State";
"lng_passport_postcode" = "Postcode";
"lng_passport_translation" = "Translation";
"lng_passport_use_existing" = "USE {existing}";
"lng_passport_use_existing_phone" = "Use the same phone number as on Telegram.";
"lng_passport_new_phone" = "Or enter a new phone number";
@@ -1643,15 +1676,80 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_passport_delete_email_sure" = "Are you sure you want to delete your email address?";
"lng_passport_delete_phone" = "Delete phone number";
"lng_passport_delete_phone_sure" = "Are you sure you want to delete your phone number?";
"lng_passport_success" = "Authorization successfull!";
"lng_passport_success" = "Authorization successful!";
"lng_passport_stop_sure" = "Are you sure you want to stop this authorization?";
"lng_passport_stop" = "Stop";
"lng_passport_restart_sure" = "An unexpected error has occurred. Perhaps some changes were made from a different Telegram application. Would you like to restart this authorization?";
"lng_passport_restart" = "Restart";
"lng_passport_error_too_large" = "This file is too large.";
"lng_passport_error_bad_size" = "This image has bad dimensions.";
"lng_passport_error_too_large" = "Sorry, this file is too large.";
"lng_passport_error_bad_size" = "Sorry, this image has wrong dimensions.";
"lng_passport_error_cant_read" = "Can't read this file. Please choose an image.";
"lng_passport_bad_name" = "Use latin characters only.";
"lng_passport_bad_name" = "Please use latin characters only.";
"lng_passport_wait_upload" = "Please wait while upload is finished.";
"lng_passport_app_out_of_date" = "Sorry, your Telegram app is out of date and can't handle this request. Please update Telegram.";
"lng_export_title" = "Export Personal Data";
"lng_export_progress_title" = "Exporting personal data";
"lng_export_option_info" = "Account information";
"lng_export_option_info_about" = "Your chosen screen name, username, phone number and profile pictures.";
"lng_export_option_contacts" = "Contacts list";
"lng_export_option_contacts_about" = "If you allow access, contacts are continuously synced with Telegram. You can adjust this in Settings > Privacy & Security on mobile devices.";
"lng_export_option_sessions" = "Active sessions";
"lng_export_option_sessions_about" = "We store this to display your connected devices in Settings > Privacy & Security > Active Sessions.";
"lng_export_header_other" = "Other";
"lng_export_option_other" = "Miscellaneous data";
"lng_export_option_other_about" = "Other types of data not mentioned above (beta).";
"lng_export_header_chats" = "Chat export settings";
"lng_export_option_personal_chats" = "Personal chats";
"lng_export_option_bot_chats" = "Bot chats";
"lng_export_option_private_groups" = "Private groups";
"lng_export_option_private_channels" = "Private channels";
"lng_export_option_public_groups" = "Public groups";
"lng_export_option_public_channels" = "Public channels";
"lng_export_option_only_my" = "Only my messages";
"lng_export_header_media" = "Media export settings";
"lng_export_option_photos" = "Photos";
"lng_export_option_video_files" = "Video files";
"lng_export_option_voice_messages" = "Voice messages";
"lng_export_option_video_messages" = "Round video messages";
"lng_export_option_stickers" = "Stickers";
"lng_export_option_gifs" = "Animated GIFs";
"lng_export_option_files" = "Files";
"lng_export_option_size_limit" = "Size limit: {size}";
"lng_export_header_format" = "Location and format";
"lng_export_option_location" = "Download path: {path}";
"lng_export_option_html" = "Human-readable HTML";
"lng_export_option_json" = "Machine-readable JSON";
"lng_export_start" = "Export";
"lng_export_state_initializing" = "Initializing...";
"lng_export_state_userpics" = "Profile pictures";
"lng_export_state_chats_list" = "Processing chats...";
"lng_export_state_chats" = "Chats";
"lng_export_state_progress" = "{count} / {total}";
"lng_export_progress" = "You can close this window now. Please don't quit Telegram until the data export is completed.";
"lng_export_stop" = "Stop";
"lng_export_sure_stop" = "Are you sure you want to stop exporting your data?\n\nIf you do, you'll need to start over.";
"lng_export_about_done" = "Your data was successfully exported.";
"lng_export_done" = "Show my data";
"lng_export_finished" = "Data export completed.";
"lng_export_total_files" = "Total files: {count}.";
"lng_export_total_size" = "Total size: {size}.";
"lng_export_folder" = "Choose export folder";
"lng_export_invalid" = "Sorry, you have started a new data export, so this data export is now cancelled.";
"lng_export_delay" = "Sorry, for security reasons, you will be able to begin downloading your data in {hours}. We have notified all your devices about the export request to make sure it's authorized and to give you time to react if it's not.\n\nPlease come back on {date} and repeat the request using the same device.";
"lng_export_delay_less_than_hour" = "less than an hour";
"lng_export_delay_hours#one" = "{count} hour";
"lng_export_delay_hours#other" = "{count} hours";
"lng_export_suggest_title" = "Data export ready";
"lng_export_suggest_text" = "You can now download the data you requested. Start exporting data?";
"lng_export_suggest_cancel" = "Not now";
"lng_export_about_telegram" = "Here is all the data you requested. Remember: we dont use your data for ad targeting, we dont sell it to others, and were not part of any “family of companies.”\n\nTelegram only keeps the information it needs to function as a feature-rich cloud service for example, your cloud chats so that you can access them from any devices without using third-party backups, or your contacts so that you can rely on your existing social graph when messaging people on Telegram.\n\nCheck out Settings > Privacy & Security on Telegram's mobile apps for relevant settings.";
"lng_export_about_contacts" = "If you allow access, your contacts are continuously synced with Telegram. Thanks to this, you can easily switch to Telegram without losing your existing social graph and connect with friends across all your devices. We use data about your contacts to let you know when they join Telegram. We also use it to make sure that you see the names you have in your phone book instead of the screen names people choose for themselves.\n\nYou can disable contact syncing or delete your stored contacts in Settings > Privacy & Security on Telegram's mobile apps.";
"lng_export_about_frequent" = "This rating shows which people you are likelier to message frequently. Telegram uses this data to populate the 'People' box at the top of the Search section. This rating is also calculated for inline bots so that the app can suggest the bots you are most likely to use in the attachment menu (or when you start a new message with \"@\").\n\nTo delete this data, go to Settings > Privacy & Security and disable 'Suggest Frequent Contacts' (requires Telegram for iOS v.4.8.3 or Telegram for Android v.4.8.10 or higher).";
"lng_export_about_sessions" = "We store session info to display your connected devices in Settings > Privacy & Security > Active Sessions.";
"lng_export_about_web_sessions" = "We store this to display the websites where you logged in using authentication via Telegram. This information is shown in Settings > Privacy & Security > Active Sessions.";
"lng_export_about_chats" = "This page lists all chats from this export and where to look for their data.";
"lng_export_about_left_chats" = "Below are the supergroups and channels from this export that you've left or where you were banned.\n\nNote that when you leave a channel or supergroup you've created, you have the option to either delete it, or simply leave (in case you want to rejoin later, or keep the community alive despite not being a member).";
// Wnd specific

View File

@@ -1,4 +1,46 @@
<RCC>
<qresource prefix="/export">
<file alias="css/style.css">../export_html/css/style.css</file>
<file alias="images/back.png">../export_html/images/back.png</file>
<file alias="images/back@2x.png">../export_html/images/back@2x.png</file>
<file alias="images/media_call.png">../export_html/images/media_call.png</file>
<file alias="images/media_call@2x.png">../export_html/images/media_call@2x.png</file>
<file alias="images/media_contact.png">../export_html/images/media_contact.png</file>
<file alias="images/media_contact@2x.png">../export_html/images/media_contact@2x.png</file>
<file alias="images/media_file.png">../export_html/images/media_file.png</file>
<file alias="images/media_file@2x.png">../export_html/images/media_file@2x.png</file>
<file alias="images/media_game.png">../export_html/images/media_game.png</file>
<file alias="images/media_game@2x.png">../export_html/images/media_game@2x.png</file>
<file alias="images/media_location.png">../export_html/images/media_location.png</file>
<file alias="images/media_location@2x.png">../export_html/images/media_location@2x.png</file>
<file alias="images/media_music.png">../export_html/images/media_music.png</file>
<file alias="images/media_music@2x.png">../export_html/images/media_music@2x.png</file>
<file alias="images/media_photo.png">../export_html/images/media_photo.png</file>
<file alias="images/media_photo@2x.png">../export_html/images/media_photo@2x.png</file>
<file alias="images/media_shop.png">../export_html/images/media_shop.png</file>
<file alias="images/media_shop@2x.png">../export_html/images/media_shop@2x.png</file>
<file alias="images/media_video.png">../export_html/images/media_video.png</file>
<file alias="images/media_video@2x.png">../export_html/images/media_video@2x.png</file>
<file alias="images/media_voice.png">../export_html/images/media_voice.png</file>
<file alias="images/media_voice@2x.png">../export_html/images/media_voice@2x.png</file>
<file alias="images/section_calls.png">../export_html/images/section_calls.png</file>
<file alias="images/section_calls@2x.png">../export_html/images/section_calls@2x.png</file>
<file alias="images/section_chats.png">../export_html/images/section_chats.png</file>
<file alias="images/section_chats@2x.png">../export_html/images/section_chats@2x.png</file>
<file alias="images/section_contacts.png">../export_html/images/section_contacts.png</file>
<file alias="images/section_contacts@2x.png">../export_html/images/section_contacts@2x.png</file>
<file alias="images/section_frequent.png">../export_html/images/section_frequent.png</file>
<file alias="images/section_frequent@2x.png">../export_html/images/section_frequent@2x.png</file>
<file alias="images/section_other.png">../export_html/images/section_other.png</file>
<file alias="images/section_other@2x.png">../export_html/images/section_other@2x.png</file>
<file alias="images/section_photos.png">../export_html/images/section_photos.png</file>
<file alias="images/section_photos@2x.png">../export_html/images/section_photos@2x.png</file>
<file alias="images/section_sessions.png">../export_html/images/section_sessions.png</file>
<file alias="images/section_sessions@2x.png">../export_html/images/section_sessions@2x.png</file>
<file alias="images/section_web.png">../export_html/images/section_web.png</file>
<file alias="images/section_web@2x.png">../export_html/images/section_web@2x.png</file>
<file alias="js/script.js">../export_html/js/script.js</file>
</qresource>
<qresource prefix="/gui">
<file alias="fonts/OpenSans-Regular.ttf">../fonts/OpenSans-Regular.ttf</file>
<file alias="fonts/OpenSans-Bold.ttf">../fonts/OpenSans-Bold.ttf</file>

View File

@@ -167,7 +167,7 @@ inputMediaEmpty#9664f57f = InputMedia;
inputMediaUploadedPhoto#1e287d04 flags:# file:InputFile stickers:flags.0?Vector<InputDocument> ttl_seconds:flags.1?int = InputMedia;
inputMediaPhoto#b3ba0635 flags:# id:InputPhoto ttl_seconds:flags.0?int = InputMedia;
inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia;
inputMediaContact#a6e45987 phone_number:string first_name:string last_name:string = InputMedia;
inputMediaContact#f8ab7dfb phone_number:string first_name:string last_name:string vcard:string = InputMedia;
inputMediaUploadedDocument#5b38c6c1 flags:# nosound_video:flags.3?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector<DocumentAttribute> stickers:flags.0?Vector<InputDocument> ttl_seconds:flags.1?int = InputMedia;
inputMediaDocument#23ab23d2 flags:# id:InputDocument ttl_seconds:flags.0?int = InputMedia;
inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string = InputMedia;
@@ -186,12 +186,13 @@ inputGeoPointEmpty#e4c123d6 = InputGeoPoint;
inputGeoPoint#f3b7acc9 lat:double long:double = InputGeoPoint;
inputPhotoEmpty#1cd7bf0d = InputPhoto;
inputPhoto#fb95c6c4 id:long access_hash:long = InputPhoto;
inputPhoto#3bb3b94a id:long access_hash:long file_reference:bytes = InputPhoto;
inputFileLocation#14637196 volume_id:long local_id:int secret:long = InputFileLocation;
inputFileLocation#dfdaabe1 volume_id:long local_id:int secret:long file_reference:bytes = InputFileLocation;
inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation;
inputDocumentFileLocation#430f0724 id:long access_hash:long version:int = InputFileLocation;
inputDocumentFileLocation#196683d9 id:long access_hash:long file_reference:bytes = InputFileLocation;
inputSecureFileLocation#cbc7ee28 id:long access_hash:long = InputFileLocation;
inputTakeoutFileLocation#29be5899 = InputFileLocation;
inputAppEvent#770656a8 time:double type:string peer:long data:string = InputAppEvent;
@@ -211,7 +212,7 @@ storage.fileMp4#b3cea0e4 = storage.FileType;
storage.fileWebp#1081464c = storage.FileType;
fileLocationUnavailable#7c596b46 volume_id:long local_id:int secret:long = FileLocation;
fileLocation#53d69076 dc_id:int volume_id:long local_id:int secret:long = FileLocation;
fileLocation#91d11eb dc_id:int volume_id:long local_id:int secret:long file_reference:bytes = FileLocation;
userEmpty#200250ba id:int = User;
user#2e13f4c3 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?string bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User;
@@ -252,7 +253,7 @@ messageService#9e19a1f6 flags:# out:flags.1?true mentioned:flags.4?true media_un
messageMediaEmpty#3ded6320 = MessageMedia;
messageMediaPhoto#695150d7 flags:# photo:flags.0?Photo ttl_seconds:flags.2?int = MessageMedia;
messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia;
messageMediaContact#5e7d2f39 phone_number:string first_name:string last_name:string user_id:int = MessageMedia;
messageMediaContact#cbf24940 phone_number:string first_name:string last_name:string vcard:string user_id:int = MessageMedia;
messageMediaUnsupported#9f84f49e = MessageMedia;
messageMediaDocument#9cb070d7 flags:# document:flags.0?Document ttl_seconds:flags.2?int = MessageMedia;
messageMediaWebPage#a32dd600 webpage:WebPage = MessageMedia;
@@ -284,17 +285,17 @@ messageActionBotAllowed#abe9affe domain:string = MessageAction;
messageActionSecureValuesSentMe#1b287353 values:Vector<SecureValue> credentials:SecureCredentialsEncrypted = MessageAction;
messageActionSecureValuesSent#d95c6154 types:Vector<SecureValueType> = MessageAction;
dialog#e4def5db flags:# pinned:flags.2?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage = Dialog;
dialog#e4def5db flags:# pinned:flags.2?true unread_mark:flags.3?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage = Dialog;
photoEmpty#2331b22d id:long = Photo;
photo#9288dd29 flags:# has_stickers:flags.0?true id:long access_hash:long date:int sizes:Vector<PhotoSize> = Photo;
photo#9c477dd8 flags:# has_stickers:flags.0?true id:long access_hash:long file_reference:bytes date:int sizes:Vector<PhotoSize> = Photo;
photoSizeEmpty#e17e23c type:string = PhotoSize;
photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize;
photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize;
geoPointEmpty#1117dd5f = GeoPoint;
geoPoint#2049d70c long:double lat:double = GeoPoint;
geoPoint#296f104 long:double lat:double access_hash:long = GeoPoint;
auth.checkedPhone#811ea28e phone_registered:Bool = auth.CheckedPhone;
@@ -321,6 +322,7 @@ inputReportReasonSpam#58dbcab8 = ReportReason;
inputReportReasonViolence#1e22c78d = ReportReason;
inputReportReasonPornography#2e59d922 = ReportReason;
inputReportReasonOther#e1746d0a text:string = ReportReason;
inputReportReasonCopyright#9b89f93a = ReportReason;
userFull#f220f3f flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true user:User about:flags.1?string link:contacts.Link profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo common_chats_count:int = UserFull;
@@ -344,6 +346,7 @@ contacts.blockedSlice#900802a1 count:int blocked:Vector<ContactBlocked> users:Ve
messages.dialogs#15ba6c40 dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Dialogs;
messages.dialogsSlice#71e094f3 count:int dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Dialogs;
messages.dialogsNotModified#f0e3e596 count:int = messages.Dialogs;
messages.messages#8c718e87 messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages;
messages.messagesSlice#b446ae3 count:int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages;
@@ -440,6 +443,7 @@ updateFavedStickers#e511996d = Update;
updateChannelReadMessagesContents#89893b45 channel_id:int messages:Vector<int> = Update;
updateContactsReset#7084a7be = Update;
updateChannelAvailableMessages#70db6837 channel_id:int available_min_id:int = Update;
updateDialogUnreadMark#e16459c3 flags:# unread:flags.0?true peer:DialogPeer = Update;
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
@@ -466,11 +470,11 @@ upload.fileCdnRedirect#f18cda44 dc_id:int file_token:bytes encryption_key:bytes
dcOption#18b7a10d flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true id:int ip_address:string port:int secret:flags.10?bytes = DcOption;
config#eb7bb160 flags:# phonecalls_enabled:flags.1?true default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true ignore_phone_entities:flags.5?true revoke_pm_inbox:flags.6?true blocked_mode:flags.8?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector<DcOption> chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int channels_read_media_period:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string autoupdate_url_prefix:flags.7?string suggested_lang_code:flags.2?string lang_pack_version:flags.2?int = Config;
config#3213dbba flags:# phonecalls_enabled:flags.1?true default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true ignore_phone_entities:flags.5?true revoke_pm_inbox:flags.6?true blocked_mode:flags.8?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector<DcOption> dc_txt_domain_name:string chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int channels_read_media_period:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string autoupdate_url_prefix:flags.7?string gif_search_username:flags.9?string venue_search_username:flags.10?string img_search_username:flags.11?string static_maps_provider:flags.12?string caption_length_max:int message_length_max:int webfile_dc_id:int suggested_lang_code:flags.2?string lang_pack_version:flags.2?int = Config;
nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc;
help.appUpdate#8987f311 id:int critical:Bool url:string text:string = help.AppUpdate;
help.appUpdate#1da7158f flags:# popup:flags.0?true id:int version:string text:string entities:Vector<MessageEntity> document:flags.1?Document url:flags.2?string = help.AppUpdate;
help.noAppUpdate#c45a6536 = help.AppUpdate;
help.inviteText#18cb9f78 message:string = help.InviteText;
@@ -501,10 +505,10 @@ messages.sentEncryptedMessage#560f8935 date:int = messages.SentEncryptedMessage;
messages.sentEncryptedFile#9493ff32 date:int file:EncryptedFile = messages.SentEncryptedMessage;
inputDocumentEmpty#72f0eaae = InputDocument;
inputDocument#18798952 id:long access_hash:long = InputDocument;
inputDocument#1abfb575 id:long access_hash:long file_reference:bytes = InputDocument;
documentEmpty#36f8c871 id:long = Document;
document#87232bc7 id:long access_hash:long date:int mime_type:string size:int thumb:PhotoSize dc_id:int version:int attributes:Vector<DocumentAttribute> = Document;
document#59534e4c id:long access_hash:long file_reference:bytes date:int mime_type:string size:int thumb:PhotoSize dc_id:int attributes:Vector<DocumentAttribute> = Document;
help.support#17c6b5f6 phone_number:string user:User = help.Support;
@@ -586,12 +590,11 @@ authorization#7bf2e6f6 hash:long flags:int device_model:string platform:string s
account.authorizations#1250abde authorizations:Vector<Authorization> = account.Authorizations;
account.noPassword#5ea182f6 new_salt:bytes new_secure_salt:bytes secure_random:bytes email_unconfirmed_pattern:string = account.Password;
account.password#ca39b447 flags:# has_recovery:flags.0?true has_secure_values:flags.1?true current_salt:bytes new_salt:bytes new_secure_salt:bytes secure_random:bytes hint:string email_unconfirmed_pattern:string = account.Password;
account.password#ad2641f8 flags:# has_recovery:flags.0?true has_secure_values:flags.1?true has_password:flags.2?true current_algo:flags.2?PasswordKdfAlgo srp_B:flags.2?bytes srp_id:flags.2?long hint:flags.3?string email_unconfirmed_pattern:flags.4?string new_algo:PasswordKdfAlgo new_secure_algo:SecurePasswordKdfAlgo secure_random:bytes = account.Password;
account.passwordSettings#7bd9c3f1 email:string secure_salt:bytes secure_secret:bytes secure_secret_id:long = account.PasswordSettings;
account.passwordSettings#9a5c33e5 flags:# email:flags.0?string secure_settings:flags.1?SecureSecretSettings = account.PasswordSettings;
account.passwordInputSettings#21ffa60d flags:# new_salt:flags.0?bytes new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string new_secure_salt:flags.2?bytes new_secure_secret:flags.2?bytes new_secure_secret_id:flags.2?long = account.PasswordInputSettings;
account.passwordInputSettings#c23727c9 flags:# new_algo:flags.0?PasswordKdfAlgo new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string new_secure_settings:flags.2?SecureSecretSettings = account.PasswordInputSettings;
auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery;
@@ -693,7 +696,7 @@ inputBotInlineMessageMediaAuto#3380c786 flags:# message:string entities:flags.1?
inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
inputBotInlineMessageMediaGeo#c1b15d65 flags:# geo_point:InputGeoPoint period:int reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
inputBotInlineMessageMediaVenue#417bbf11 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
inputBotInlineMessageMediaContact#2daf01a7 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
inputBotInlineMessageMediaContact#a6edbffd flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
inputBotInlineResult#88bf9319 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?InputWebDocument content:flags.5?InputWebDocument send_message:InputBotInlineMessage = InputBotInlineResult;
@@ -705,7 +708,7 @@ botInlineMessageMediaAuto#764cf810 flags:# message:string entities:flags.1?Vecto
botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
botInlineMessageMediaGeo#b722de65 flags:# geo:GeoPoint period:int reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
botInlineMessageMediaVenue#8a86659c flags:# geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
botInlineMessageMediaContact#35edb4d4 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
botInlineMessageMediaContact#18d1cdc2 flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
botInlineResult#11965f3a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?WebDocument content:flags.5?WebDocument send_message:BotInlineMessage = BotInlineResult;
botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult;
@@ -748,8 +751,9 @@ topPeerCategoryPeers#fb834291 category:TopPeerCategory count:int peers:Vector<To
contacts.topPeersNotModified#de266ef5 = contacts.TopPeers;
contacts.topPeers#70b772a8 categories:Vector<TopPeerCategoryPeers> chats:Vector<Chat> users:Vector<User> = contacts.TopPeers;
contacts.topPeersDisabled#b52c939d = contacts.TopPeers;
draftMessageEmpty#ba4baec5 = DraftMessage;
draftMessageEmpty#1b0c841a flags:# date:flags.0?int = DraftMessage;
draftMessage#fd8e711f flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int message:string entities:flags.3?Vector<MessageEntity> date:int = DraftMessage;
messages.featuredStickersNotModified#4ede3cf = messages.FeaturedStickers;
@@ -837,14 +841,13 @@ paymentRequestedInfo#909c3f94 flags:# name:flags.0?string phone:flags.1?string e
paymentSavedCredentialsCard#cdc27a1f id:string title:string = PaymentSavedCredentials;
webDocument#c61acbd8 url:string access_hash:long size:int mime_type:string attributes:Vector<DocumentAttribute> dc_id:int = WebDocument;
webDocument#1c570ed1 url:string access_hash:long size:int mime_type:string attributes:Vector<DocumentAttribute> = WebDocument;
webDocumentNoProxy#f9c8bcc6 url:string size:int mime_type:string attributes:Vector<DocumentAttribute> = WebDocument;
inputWebDocument#9bed434d url:string size:int mime_type:string attributes:Vector<DocumentAttribute> = InputWebDocument;
inputWebFileLocation#c239d686 url:string access_hash:long = InputWebFileLocation;
inputWebFileGeoPointLocation#66275a62 geo_point:InputGeoPoint w:int h:int zoom:int scale:int = InputWebFileLocation;
inputWebFileGeoMessageLocation#553f32eb peer:InputPeer msg_id:int w:int h:int zoom:int scale:int = InputWebFileLocation;
inputWebFileGeoPointLocation#9f2221c9 geo_point:InputGeoPoint access_hash:long w:int h:int zoom:int scale:int = InputWebFileLocation;
upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile;
@@ -992,9 +995,9 @@ secureValueTypeTemporaryRegistration#ea02ec33 = SecureValueType;
secureValueTypePhone#b320aadb = SecureValueType;
secureValueTypeEmail#8e3ca7ee = SecureValueType;
secureValue#b4b4b699 flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?SecureFile reverse_side:flags.2?SecureFile selfie:flags.3?SecureFile files:flags.4?Vector<SecureFile> plain_data:flags.5?SecurePlainData hash:bytes = SecureValue;
secureValue#187fa0ca flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?SecureFile reverse_side:flags.2?SecureFile selfie:flags.3?SecureFile translation:flags.6?Vector<SecureFile> files:flags.4?Vector<SecureFile> plain_data:flags.5?SecurePlainData hash:bytes = SecureValue;
inputSecureValue#67872e8 flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?InputSecureFile reverse_side:flags.2?InputSecureFile selfie:flags.3?InputSecureFile files:flags.4?Vector<InputSecureFile> plain_data:flags.5?SecurePlainData = InputSecureValue;
inputSecureValue#db21d0a7 flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?InputSecureFile reverse_side:flags.2?InputSecureFile selfie:flags.3?InputSecureFile translation:flags.6?Vector<InputSecureFile> files:flags.4?Vector<InputSecureFile> plain_data:flags.5?SecurePlainData = InputSecureValue;
secureValueHash#ed1ecdb0 type:SecureValueType hash:bytes = SecureValueHash;
@@ -1004,16 +1007,41 @@ secureValueErrorReverseSide#868a2aa5 type:SecureValueType file_hash:bytes text:s
secureValueErrorSelfie#e537ced6 type:SecureValueType file_hash:bytes text:string = SecureValueError;
secureValueErrorFile#7a700873 type:SecureValueType file_hash:bytes text:string = SecureValueError;
secureValueErrorFiles#666220e9 type:SecureValueType file_hash:Vector<bytes> text:string = SecureValueError;
secureValueError#869d758f type:SecureValueType hash:bytes text:string = SecureValueError;
secureValueErrorTranslationFile#a1144770 type:SecureValueType file_hash:bytes text:string = SecureValueError;
secureValueErrorTranslationFiles#34636dd8 type:SecureValueType file_hash:Vector<bytes> text:string = SecureValueError;
secureCredentialsEncrypted#33f0ea47 data:bytes hash:bytes secret:bytes = SecureCredentialsEncrypted;
account.authorizationForm#cb976d53 flags:# selfie_required:flags.1?true required_types:Vector<SecureValueType> values:Vector<SecureValue> errors:Vector<SecureValueError> users:Vector<User> privacy_policy_url:flags.0?string = account.AuthorizationForm;
account.authorizationForm#ad2e1cd8 flags:# required_types:Vector<SecureRequiredType> values:Vector<SecureValue> errors:Vector<SecureValueError> users:Vector<User> privacy_policy_url:flags.0?string = account.AuthorizationForm;
account.sentEmailCode#811f854f email_pattern:string length:int = account.SentEmailCode;
help.deepLinkInfoEmpty#66afa166 = help.DeepLinkInfo;
help.deepLinkInfo#6a4ee832 flags:# update_app:flags.0?true message:string entities:flags.1?Vector<MessageEntity> = help.DeepLinkInfo;
savedPhoneContact#1142bd56 phone:string first_name:string last_name:string date:int = SavedContact;
account.takeout#4dba4501 id:long = account.Takeout;
passwordKdfAlgoUnknown#d45ab096 = PasswordKdfAlgo;
passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow#3a912d4a salt1:bytes salt2:bytes g:int p:bytes = PasswordKdfAlgo;
securePasswordKdfAlgoUnknown#4a8537 = SecurePasswordKdfAlgo;
securePasswordKdfAlgoPBKDF2HMACSHA512iter100000#bbf2dda0 salt:bytes = SecurePasswordKdfAlgo;
securePasswordKdfAlgoSHA512#86471d92 salt:bytes = SecurePasswordKdfAlgo;
secureSecretSettings#1527bcac secure_algo:SecurePasswordKdfAlgo secure_secret:bytes secure_secret_id:long = SecureSecretSettings;
inputCheckPasswordEmpty#9880f658 = InputCheckPasswordSRP;
inputCheckPasswordSRP#d27ff082 srp_id:long A:bytes M1:bytes = InputCheckPasswordSRP;
secureRequiredType#829d99da flags:# native_names:flags.0?true selfie_required:flags.1?true translation_required:flags.2?true type:SecureValueType = SecureRequiredType;
secureRequiredTypeOneOf#27477b4 types:Vector<SecureRequiredType> = SecureRequiredType;
help.passportConfigNotModified#bfb9f457 = help.PassportConfig;
help.passportConfig#a098d6af hash:int countries_langs:DataJSON = help.PassportConfig;
---functions---
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
@@ -1021,18 +1049,19 @@ invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector<long> query:!X = X;
initConnection#785188b8 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy query:!X = X;
invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X;
invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X;
invokeWithMessagesRange#365275f2 {X:Type} range:MessageRange query:!X = X;
invokeWithTakeout#aca9fd2e {X:Type} takeout_id:long query:!X = X;
auth.sendCode#86aef0ec flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool api_id:int api_hash:string = auth.SentCode;
auth.signUp#1b067634 phone_number:string phone_code_hash:string phone_code:string first_name:string last_name:string = auth.Authorization;
auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization;
auth.logOut#5717da40 = Bool;
auth.resetAuthorizations#9fab0d1a = Bool;
auth.sendInvites#771c1d97 phone_numbers:Vector<string> message:string = Bool;
auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization;
auth.importAuthorization#e3ef9613 id:int bytes:bytes = auth.Authorization;
auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool;
auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization;
auth.checkPassword#a63011e password_hash:bytes = auth.Authorization;
auth.checkPassword#d18b4d16 password:InputCheckPasswordSRP = auth.Authorization;
auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery;
auth.recoverPassword#4ea56e92 code:string = auth.Authorization;
auth.resendCode#3ef1a9bf phone_number:string phone_code_hash:string = auth.SentCode;
@@ -1061,11 +1090,11 @@ account.updateDeviceLocked#38df3532 period:int = Bool;
account.getAuthorizations#e320c158 = account.Authorizations;
account.resetAuthorization#df77f3bc hash:long = Bool;
account.getPassword#548a30f5 = account.Password;
account.getPasswordSettings#bc8d11bb current_password_hash:bytes = account.PasswordSettings;
account.updatePasswordSettings#fa7c4b86 current_password_hash:bytes new_settings:account.PasswordInputSettings = Bool;
account.getPasswordSettings#9cd4eaf9 password:InputCheckPasswordSRP = account.PasswordSettings;
account.updatePasswordSettings#a59b102f password:InputCheckPasswordSRP new_settings:account.PasswordInputSettings = Bool;
account.sendConfirmPhoneCode#1516d7bd flags:# allow_flashcall:flags.0?true hash:string current_number:flags.0?Bool = auth.SentCode;
account.confirmPhone#5f2178c3 phone_code_hash:string phone_code:string = Bool;
account.getTmpPassword#4a82327e password_hash:bytes period:int = account.TmpPassword;
account.getTmpPassword#449e0b51 password:InputCheckPasswordSRP period:int = account.TmpPassword;
account.getWebAuthorizations#182e6d6f = account.WebAuthorizations;
account.resetWebAuthorization#2d01b9ef hash:long = Bool;
account.resetWebAuthorizations#682d2594 = Bool;
@@ -1079,6 +1108,8 @@ account.sendVerifyPhoneCode#823380b4 flags:# allow_flashcall:flags.0?true phone_
account.verifyPhone#4dd3a7f6 phone_number:string phone_code_hash:string phone_code:string = Bool;
account.sendVerifyEmailCode#7011509f email:string = account.SentEmailCode;
account.verifyEmail#ecba39db email:string code:string = Bool;
account.initTakeoutSession#f05b4804 flags:# contacts:flags.0?true message_users:flags.1?true message_chats:flags.2?true message_megagroups:flags.3?true message_channels:flags.4?true files:flags.5?true file_max_size:flags.5?int = account.Takeout;
account.finishTakeoutSession#1d2652ee flags:# success:flags.0?true = Bool;
users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
users.getFullUser#ca30a5b1 id:InputUser = UserFull;
@@ -1099,9 +1130,11 @@ contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer;
contacts.getTopPeers#d4982db5 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true groups:flags.10?true channels:flags.15?true offset:int limit:int hash:int = contacts.TopPeers;
contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool;
contacts.resetSaved#879537f1 = Bool;
contacts.getSaved#82f1e39f = Vector<SavedContact>;
contacts.toggleTopPeers#8514bdda enabled:Bool = Bool;
messages.getMessages#63c66506 id:Vector<InputMessage> = messages.Messages;
messages.getDialogs#191ba9c5 flags:# exclude_pinned:flags.0?true offset_date:int offset_id:int offset_peer:InputPeer limit:int = messages.Dialogs;
messages.getDialogs#b098aee6 flags:# exclude_pinned:flags.0?true offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:int = messages.Dialogs;
messages.getHistory#dcbb8260 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages;
messages.search#8614ef68 flags:# peer:InputPeer q:string from_id:flags.0?InputUser filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages;
messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages;
@@ -1196,6 +1229,10 @@ messages.getRecentLocations#bbc45b09 peer:InputPeer limit:int hash:int = message
messages.sendMultiMedia#2095512f flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int multi_media:Vector<InputSingleMedia> = Updates;
messages.uploadEncryptedFile#5057c497 peer:InputEncryptedChat file:InputEncryptedFile = EncryptedFile;
messages.searchStickerSets#c2b7d08b flags:# exclude_featured:flags.0?true q:string hash:int = messages.FoundStickerSets;
messages.getSplitRanges#1cff7e08 = Vector<MessageRange>;
messages.markDialogUnread#c286d98f flags:# unread:flags.0?true peer:InputDialogPeer = Bool;
messages.getDialogUnreadMarks#22e24e22 = Vector<DialogPeer>;
messages.clearAllDrafts#7e58ee9c = Bool;
updates.getState#edd4882a = updates.State;
updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference;
@@ -1217,7 +1254,7 @@ upload.getFileHashes#c7025931 location:InputFileLocation offset:int = Vector<Fil
help.getConfig#c4f9186b = Config;
help.getNearestDc#1fb33026 = NearestDc;
help.getAppUpdate#ae2de196 = help.AppUpdate;
help.getAppUpdate#522d5a7d source:string = help.AppUpdate;
help.saveAppLog#6f02f748 events:Vector<InputAppEvent> = Bool;
help.getInviteText#4d392343 = help.InviteText;
help.getSupport#9cdf08cd = help.Support;
@@ -1229,6 +1266,7 @@ help.getProxyData#3d7758e1 = help.ProxyData;
help.getTermsOfServiceUpdate#2ca51fd1 = help.TermsOfServiceUpdate;
help.acceptTermsOfService#ee72f79a id:DataJSON = Bool;
help.getDeepLinkInfo#3fedc75f path:string = help.DeepLinkInfo;
help.getPassportConfig#c661ad08 hash:int = help.PassportConfig;
channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool;
channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector<int> = messages.AffectedMessages;
@@ -1262,6 +1300,7 @@ channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet =
channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector<int> = Bool;
channels.deleteHistory#af369d42 channel:InputChannel max_id:int = Bool;
channels.togglePreHistoryHidden#eabbb94c channel:InputChannel enabled:Bool = Updates;
channels.getLeftChannels#8341ecc0 offset:int = messages.Chats;
bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON;
bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool;
@@ -1287,9 +1326,9 @@ phone.discardCall#78d413a6 peer:InputPhoneCall duration:int reason:PhoneCallDisc
phone.setCallRating#1c536a34 peer:InputPhoneCall rating:int comment:string = Updates;
phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool;
langpack.getLangPack#9ab5c58e lang_code:string = LangPackDifference;
langpack.getStrings#2e1ee318 lang_code:string keys:Vector<string> = Vector<LangPackString>;
langpack.getLangPack#f2f2330a lang_pack:string lang_code:string = LangPackDifference;
langpack.getStrings#efea3803 lang_pack:string lang_code:string keys:Vector<string> = Vector<LangPackString>;
langpack.getDifference#b2e4d7d from_version:int = LangPackDifference;
langpack.getLanguages#800fd57d = Vector<LangPackLanguage>;
langpack.getLanguages#42c6978f lang_pack:string = Vector<LangPackLanguage>;
// LAYER 81
// LAYER 86

View File

@@ -9,7 +9,7 @@
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
ProcessorArchitecture="ARCHITECTURE"
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
Version="1.3.2.0" />
Version="1.3.16.0" />
<Properties>
<DisplayName>Telegram Desktop</DisplayName>
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>

View File

@@ -34,8 +34,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,3,2,0
PRODUCTVERSION 1,3,2,0
FILEVERSION 1,3,16,0
PRODUCTVERSION 1,3,16,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -52,10 +52,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Telegram Messenger LLP"
VALUE "FileDescription", "Telegram Desktop"
VALUE "FileVersion", "1.3.2.0"
VALUE "FileVersion", "1.3.16.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2018"
VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "1.3.2.0"
VALUE "ProductVersion", "1.3.16.0"
END
END
BLOCK "VarFileInfo"

View File

@@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,3,2,0
PRODUCTVERSION 1,3,2,0
FILEVERSION 1,3,16,0
PRODUCTVERSION 1,3,16,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -43,10 +43,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Telegram Messenger LLP"
VALUE "FileDescription", "Telegram Desktop Updater"
VALUE "FileVersion", "1.3.2.0"
VALUE "FileVersion", "1.3.16.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2018"
VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "1.3.2.0"
VALUE "ProductVersion", "1.3.16.0"
END
END
BLOCK "VarFileInfo"

View File

@@ -339,7 +339,7 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPWSTR cmdPara
LPWSTR *args;
int argsCount;
bool needupdate = false, autostart = false, debug = false, writeprotected = false, startintray = false, testmode = false;
bool needupdate = false, autostart = false, debug = false, writeprotected = false, startintray = false, testmode = false, externalupdater = false;
args = CommandLineToArgvW(GetCommandLine(), &argsCount);
if (args) {
for (int i = 1; i < argsCount; ++i) {
@@ -355,6 +355,8 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPWSTR cmdPara
startintray = true;
} else if (equal(args[i], L"-testmode")) {
testmode = true;
} else if (equal(args[i], L"-externalupdater")) {
externalupdater = true;
} else if (equal(args[i], L"-writeprotected") && ++i < argsCount) {
writeLog(std::wstring(L"Argument: ") + args[i]);
writeprotected = true;
@@ -425,6 +427,7 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPWSTR cmdPara
if (debug) targs += L" -debug";
if (startintray) targs += L" -startintray";
if (testmode) targs += L" -testmode";
if (externalupdater) targs += L" -externalupdater";
if (!customWorkingDir.empty()) {
targs += L" -workdir \"" + customWorkingDir + L"\"";
}

View File

@@ -337,6 +337,7 @@ int main(int argc, char *argv[]) {
bool tosettings = false;
bool startintray = false;
bool testmode = false;
bool externalupdater = false;
bool customWorkingDir = false;
char *key = 0;
@@ -352,6 +353,8 @@ int main(int argc, char *argv[]) {
startintray = true;
} else if (equal(argv[i], "-testmode")) {
testmode = true;
} else if (equal(argv[i], "-externalupdater")) {
externalupdater = true;
} else if (equal(argv[i], "-tosettings")) {
tosettings = true;
} else if (equal(argv[i], "-workdir_custom")) {
@@ -450,6 +453,7 @@ int main(int argc, char *argv[]) {
char p_key[] = "-key";
char p_startintray[] = "-startintray";
char p_testmode[] = "-testmode";
char p_externalupdater[] = "-externalupdater";
char p_workdir[] = "-workdir";
int argIndex = 0;
args[argIndex++] = path;
@@ -458,6 +462,7 @@ int main(int argc, char *argv[]) {
if (debug) args[argIndex++] = p_debug;
if (startintray) args[argIndex++] = p_startintray;
if (testmode) args[argIndex++] = p_testmode;
if (externalupdater) args[argIndex++] = p_externalupdater;
if (tosettings) args[argIndex++] = p_tosettings;
if (key) {
args[argIndex++] = p_key;

View File

@@ -75,7 +75,7 @@ int main(int argc, const char * argv[]) {
openLog();
pid_t procId = 0;
BOOL update = YES, toSettings = NO, autoStart = NO, startInTray = NO, testMode = NO;
BOOL update = YES, toSettings = NO, autoStart = NO, startInTray = NO, testMode = NO, externalUpdater = NO;
BOOL customWorkingDir = NO;
NSString *key = nil;
for (int i = 0; i < argc; ++i) {
@@ -101,6 +101,8 @@ int main(int argc, const char * argv[]) {
startInTray = YES;
} else if ([@"-testmode" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) {
testMode = YES;
} else if ([@"-externalupdater" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) {
externalUpdater = YES;
} else if ([@"-workdir_custom" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) {
customWorkingDir = YES;
} else if ([@"-key" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) {
@@ -235,6 +237,7 @@ int main(int argc, const char * argv[]) {
if (_debug) [args addObject:@"-debug"];
if (startInTray) [args addObject:@"-startintray"];
if (testMode) [args addObject:@"-testmode"];
if (externalUpdater) [args addObject:@"-externalupdater"];
if (autoStart) [args addObject:@"-autostart"];
if (key) {
[args addObject:@"-key"];

View File

@@ -37,9 +37,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "window/notifications_manager.h"
#include "window/window_lock_widgets.h"
#include "window/window_controller.h"
#include "inline_bots/inline_bot_result.h"
#include "chat_helpers/message_field.h"
#include "chat_helpers/stickers.h"
#include "ui/text_options.h"
#include "storage/localimageloader.h"
#include "storage/file_download.h"
#include "storage/storage_facade.h"
#include "storage/storage_shared_media.h"
#include "storage/storage_user_photos.h"
@@ -65,6 +68,11 @@ constexpr auto kFeedReadTimeout = TimeMs(1000);
constexpr auto kStickersByEmojiInvalidateTimeout = TimeMs(60 * 60 * 1000);
constexpr auto kNotifySettingSaveTimeout = TimeMs(1000);
using SimpleFileLocationId = Data::SimpleFileLocationId;
using DocumentFileLocationId = Data::DocumentFileLocationId;
using FileLocationId = Data::FileLocationId;
using UpdatedFileReferences = Data::UpdatedFileReferences;
bool IsSilentPost(not_null<HistoryItem*> item, bool silent) {
const auto history = item->history();
return silent
@@ -126,15 +134,15 @@ MTPVector<MTPDocumentAttribute> ComposeSendingDocumentAttributes(
return MTP_vector<MTPDocumentAttribute>(attributes);
}
FileLoadTo FileLoadTaskOptions(const ApiWrap::SendOptions &options) {
const auto peer = options.history->peer;
return FileLoadTo(
peer->id,
Auth().data().notifySilentPosts(peer),
options.replyTo);
} // namespace
ApiWrap::SendOptions::SendOptions(not_null<History*> history)
: history(history) {
}
} // namespace
ApiWrap::MessageToSend::MessageToSend(not_null<History*> history)
: history(history) {
}
ApiWrap::ApiWrap(not_null<AuthSession*> session)
: _session(session)
@@ -230,7 +238,7 @@ void ApiWrap::proxyPromotionDone(const MTPhelp_ProxyData &proxy) {
const auto peer = App::peer(peerId);
_session->data().setProxyPromoted(peer);
if (const auto history = App::historyLoaded(peer)) {
_session->api().requestDialogEntry(history);
requestDialogEntry(history);
}
}
@@ -270,8 +278,9 @@ void ApiWrap::requestTermsUpdate() {
_termsUpdateRequestId = 0;
const auto requestNext = [&](auto &&data) {
const auto timeout = (data.vexpires.v - unixtime());
_termsUpdateSendAt = getms(true) + snap(
TimeMs(data.vexpires.v - unixtime()),
timeout * TimeMs(1000),
kTermsUpdateTimeoutMin,
kTermsUpdateTimeoutMax);
requestTermsUpdate();
@@ -565,13 +574,15 @@ void ApiWrap::requestDialogEntry(not_null<Data::Feed*> feed) {
// }
// _dialogFeedRequests.emplace(feed);
//
// const auto hash = 0;
// request(MTPmessages_GetDialogs(
// MTP_flags(MTPmessages_GetDialogs::Flag::f_feed_id),
// MTP_int(feed->id()),
// MTP_int(0), // offset_date
// MTP_int(0), // offset_id
// MTP_inputPeerEmpty(), // offset_peer
// MTP_int(Data::Feed::kChannelsLimit)
// MTP_int(Data::Feed::kChannelsLimit),
// MTP_int(hash)
// )).done([=](const MTPmessages_Dialogs &result) {
// applyFeedDialogs(feed, result);
// _dialogFeedRequests.remove(feed);
@@ -631,7 +642,7 @@ void ApiWrap::historyDialogEntryApplied(not_null<History*> history) {
if (!chat->haveLeft()) {
Local::addSavedPeer(
history->peer,
history->chatsListDate());
ParseDateTime(history->chatsListTimeId()));
}
} else if (const auto channel = history->peer->asChannel()) {
const auto inviter = channel->inviter;
@@ -648,12 +659,11 @@ void ApiWrap::historyDialogEntryApplied(not_null<History*> history) {
return;
}
if (!history->chatsListDate().isNull()
&& history->loadedAtBottom()) {
if (history->chatsListTimeId() != 0 && history->loadedAtBottom()) {
if (const auto channel = history->peer->asChannel()) {
const auto inviter = channel->inviter;
if (inviter != 0
&& history->chatsListDate() <= ParseDateTime(channel->inviteDate)
&& history->chatsListTimeId() <= channel->inviteDate
&& channel->amIn()) {
if (const auto from = App::userLoaded(inviter)) {
history->insertJoinedMessage(true);
@@ -714,6 +724,18 @@ void ApiWrap::applyFeedDialogs(
_session->data().sendHistoryChangeNotifications();
}
void ApiWrap::changeDialogUnreadMark(
not_null<History*> history,
bool unread) {
history->setUnreadMark(unread);
using Flag = MTPmessages_MarkDialogUnread::Flag;
request(MTPmessages_MarkDialogUnread(
MTP_flags(unread ? Flag::f_unread : Flag(0)),
MTP_inputDialogPeer(history->peer->input)
)).send();
}
void ApiWrap::requestFullPeer(PeerData *peer) {
if (!peer || _fullPeerRequests.contains(peer)) return;
@@ -2055,10 +2077,22 @@ void ApiWrap::saveDraftsToCloud() {
if (!textWithTags.tags.isEmpty()) {
flags |= MTPmessages_SaveDraft::Flag::f_entities;
}
auto entities = TextUtilities::EntitiesToMTP(ConvertTextTagsToEntities(textWithTags.tags), TextUtilities::ConvertOption::SkipLocal);
auto entities = TextUtilities::EntitiesToMTP(
ConvertTextTagsToEntities(textWithTags.tags),
TextUtilities::ConvertOption::SkipLocal);
cloudDraft->saveRequestId = request(MTPmessages_SaveDraft(MTP_flags(flags), MTP_int(cloudDraft->msgId), history->peer->input, MTP_string(textWithTags.text), entities)).done([this, history](const MTPBool &result, mtpRequestId requestId) {
if (auto cloudDraft = history->cloudDraft()) {
const auto draftText = textWithTags.text;
history->setSentDraftText(draftText);
cloudDraft->saveRequestId = request(MTPmessages_SaveDraft(
MTP_flags(flags),
MTP_int(cloudDraft->msgId),
history->peer->input,
MTP_string(textWithTags.text),
entities
)).done([=](const MTPBool &result, mtpRequestId requestId) {
history->clearSentDraftText(draftText);
if (const auto cloudDraft = history->cloudDraft()) {
if (cloudDraft->saveRequestId == requestId) {
cloudDraft->saveRequestId = 0;
history->draftSavedToCloud();
@@ -2069,8 +2103,10 @@ void ApiWrap::saveDraftsToCloud() {
_draftsSaveRequestIds.erase(history);
checkQuitPreventFinished();
}
}).fail([this, history](const RPCError &error, mtpRequestId requestId) {
if (auto cloudDraft = history->cloudDraft()) {
}).fail([=](const RPCError &error, mtpRequestId requestId) {
history->clearSentDraftText(draftText);
if (const auto cloudDraft = history->cloudDraft()) {
if (cloudDraft->saveRequestId == requestId) {
history->clearCloudDraft();
}
@@ -2338,6 +2374,159 @@ void ApiWrap::channelRangeDifferenceDone(
}
}
template <typename Request>
void ApiWrap::requestFileReference(
Data::FileOrigin origin,
FileReferencesHandler &&handler,
Request &&data) {
const auto i = _fileReferenceHandlers.find(origin);
if (i != end(_fileReferenceHandlers)) {
i->second.push_back(std::move(handler));
return;
}
auto handlers = std::vector<FileReferencesHandler>();
handlers.push_back(std::move(handler));
_fileReferenceHandlers.emplace(origin, std::move(handlers));
request(std::move(data)).done([=](const auto &result) {
const auto parsed = Data::GetFileReferences(result);
for (const auto &p : parsed) {
// Unpack here the parsed pair by hand to workaround a GCC bug.
// See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87122
const auto &origin = p.first;
const auto &reference = p.second;
const auto documentId = base::get_if<DocumentFileLocationId>(
&origin);
if (documentId) {
_session->data().document(
*documentId
)->refreshFileReference(reference);
}
}
const auto i = _fileReferenceHandlers.find(origin);
Assert(i != end(_fileReferenceHandlers));
auto handlers = std::move(i->second);
_fileReferenceHandlers.erase(i);
for (auto &handler : handlers) {
handler(parsed);
}
}).fail([=](const RPCError &error) {
const auto i = _fileReferenceHandlers.find(origin);
Assert(i != end(_fileReferenceHandlers));
auto handlers = std::move(i->second);
_fileReferenceHandlers.erase(i);
for (auto &handler : handlers) {
handler(Data::UpdatedFileReferences());
}
}).send();
}
void ApiWrap::refreshFileReference(
Data::FileOrigin origin,
not_null<mtpFileLoader*> loader,
int requestId,
const QByteArray &current) {
return refreshFileReference(origin, crl::guard(loader, [=](
const Data::UpdatedFileReferences &data) {
loader->refreshFileReferenceFrom(data, requestId, current);
}));
}
void ApiWrap::refreshFileReference(
Data::FileOrigin origin,
FileReferencesHandler &&handler) {
const auto request = [&](
auto &&data,
Fn<void()> &&additional = nullptr) {
requestFileReference(
origin,
std::move(handler),
std::move(data));
if (additional) {
const auto i = _fileReferenceHandlers.find(origin);
Assert(i != end(_fileReferenceHandlers));
i->second.push_back([=](auto&&) {
additional();
});
}
};
const auto fail = [&] {
handler(Data::UpdatedFileReferences());
};
origin.match([&](Data::FileOriginMessage data) {
if (const auto item = App::histItemById(data)) {
if (const auto channel = item->history()->peer->asChannel()) {
request(MTPchannels_GetMessages(
channel->inputChannel,
MTP_vector<MTPInputMessage>(
1,
MTP_inputMessageID(MTP_int(item->id)))));
} else {
request(MTPmessages_GetMessages(
MTP_vector<MTPInputMessage>(
1,
MTP_inputMessageID(MTP_int(item->id)))));
}
} else {
fail();
}
}, [&](Data::FileOriginUserPhoto data) {
if (const auto user = App::user(data.userId)) {
request(MTPphotos_GetUserPhotos(
user->inputUser,
MTP_int(-1),
MTP_long(data.photoId),
MTP_int(1)));
} else {
fail();
}
}, [&](Data::FileOriginPeerPhoto data) {
if (const auto peer = App::peer(data.peerId)) {
if (const auto user = peer->asUser()) {
request(MTPusers_GetUsers(
MTP_vector<MTPInputUser>(1, user->inputUser)));
} else if (const auto chat = peer->asChat()) {
request(MTPmessages_GetChats(
MTP_vector<MTPint>(1, chat->inputChat)));
} else if (const auto channel = peer->asChannel()) {
request(MTPchannels_GetChannels(
MTP_vector<MTPInputChannel>(1, channel->inputChannel)));
} else {
fail();
}
} else {
fail();
}
}, [&](Data::FileOriginStickerSet data) {
if (data.setId == Stickers::CloudRecentSetId
|| data.setId == Stickers::RecentSetId) {
request(MTPmessages_GetRecentStickers(
MTP_flags(0),
MTP_int(0)),
[] { crl::on_main([] { Local::writeRecentStickers(); }); });
} else if (data.setId == Stickers::FavedSetId) {
request(MTPmessages_GetFavedStickers(MTP_int(0)),
[] { crl::on_main([] { Local::writeFavedStickers(); }); });
} else {
request(MTPmessages_GetStickerSet(
MTP_inputStickerSetID(
MTP_long(data.setId),
MTP_long(data.accessHash))),
[] { crl::on_main([] {
Local::writeInstalledStickers();
Local::writeRecentStickers();
Local::writeFavedStickers();
}); });
}
}, [&](Data::FileOriginSavedGifs data) {
request(
MTPmessages_GetSavedGifs(MTP_int(0)),
[] { crl::on_main([] { Local::writeSavedGifs(); }); });
}, [&](base::none_type) {
fail();
});
}
void ApiWrap::gotWebPages(ChannelData *channel, const MTPmessages_Messages &msgs, mtpRequestId req) {
const QVector<MTPMessage> *v = 0;
switch (msgs.type()) {
@@ -2470,6 +2659,12 @@ std::vector<not_null<DocumentData*>> *ApiWrap::stickersByEmoji(
auto &entry = _stickersByEmoji[emoji];
entry.list.clear();
entry.list.reserve(data.vstickers.v.size());
for (const auto &sticker : data.vstickers.v) {
const auto document = _session->data().document(sticker);
if (document->sticker()) {
entry.list.push_back(document);
}
}
entry.hash = data.vhash.v;
entry.received = getms(true);
_session->data().notifyStickersUpdated();
@@ -2483,6 +2678,80 @@ std::vector<not_null<DocumentData*>> *ApiWrap::stickersByEmoji(
return nullptr;
}
void ApiWrap::toggleFavedSticker(
not_null<DocumentData*> document,
Data::FileOrigin origin,
bool faved) {
if (faved && !document->sticker()) {
return;
}
auto failHandler = std::make_shared<Fn<void(const RPCError&)>>();
auto performRequest = [=] {
request(MTPmessages_FaveSticker(
document->mtpInput(),
MTP_bool(!faved)
)).done([=](const MTPBool &result) {
if (mtpIsTrue(result)) {
Stickers::SetFaved(document, faved);
}
}).fail(
base::duplicate(*failHandler)
).send();
};
*failHandler = [=](const RPCError &error) {
if (error.code() == 400
&& error.type().startsWith(qstr("FILE_REFERENCE_"))) {
const auto current = document->fileReference();
auto refreshed = [=](const Data::UpdatedFileReferences &data) {
if (document->fileReference() != current) {
performRequest();
}
};
refreshFileReference(origin, std::move(refreshed));
}
};
performRequest();
}
void ApiWrap::toggleSavedGif(
not_null<DocumentData*> document,
Data::FileOrigin origin,
bool saved) {
if (saved && !document->isGifv()) {
return;
}
auto failHandler = std::make_shared<Fn<void(const RPCError&)>>();
auto performRequest = [=] {
request(MTPmessages_SaveGif(
document->mtpInput(),
MTP_bool(!saved)
)).done([=](const MTPBool &result) {
if (mtpIsTrue(result)) {
if (saved) {
App::addSavedGif(document);
}
}
}).fail(
base::duplicate(*failHandler)
).send();
};
*failHandler = [=](const RPCError &error) {
if (error.code() == 400
&& error.type().startsWith(qstr("FILE_REFERENCE_"))) {
const auto current = document->fileReference();
auto refreshed = [=](const Data::UpdatedFileReferences &data) {
if (document->fileReference() != current) {
performRequest();
}
};
refreshFileReference(origin, std::move(refreshed));
}
};
performRequest();
}
void ApiWrap::requestStickers(TimeId now) {
if (!_session->data().stickersUpdateNeeded(now)
|| _stickersUpdateRequest) {
@@ -3763,6 +4032,8 @@ void ApiWrap::sendSharedContact(
const auto messagePostAuthor = channelPost
? (_session->user()->firstName + ' ' + _session->user()->lastName)
: QString();
const auto vcard = QString();
const auto views = 1;
const auto item = history->addNewMessage(
MTP_message(
MTP_flags(flags),
@@ -3778,10 +4049,11 @@ void ApiWrap::sendSharedContact(
MTP_string(phone),
MTP_string(firstName),
MTP_string(lastName),
MTP_string(vcard),
MTP_int(userId)),
MTPnullMarkup,
MTPnullEntities,
MTP_int(1),
MTP_int(views),
MTPint(),
MTP_string(messagePostAuthor),
MTPlong()),
@@ -3790,7 +4062,8 @@ void ApiWrap::sendSharedContact(
const auto media = MTP_inputMediaContact(
MTP_string(phone),
MTP_string(firstName),
MTP_string(lastName));
MTP_string(lastName),
MTP_string(vcard));
sendMedia(item, media, _session->data().notifySilentPosts(peer));
if (const auto main = App::main()) {
@@ -3806,7 +4079,7 @@ void ApiWrap::sendVoiceMessage(
int duration,
const SendOptions &options) {
const auto caption = TextWithTags();
const auto to = FileLoadTaskOptions(options);
const auto to = fileLoadTaskOptions(options);
_fileLoader->addTask(std::make_unique<FileLoadTask>(
result,
duration,
@@ -3822,15 +4095,15 @@ void ApiWrap::sendFiles(
std::shared_ptr<SendingAlbum> album,
const SendOptions &options) {
if (list.files.size() > 1 && !caption.text.isEmpty()) {
auto message = MainWidget::MessageToSend(options.history);
auto message = MessageToSend(options.history);
message.textWithTags = std::move(caption);
message.replyTo = options.replyTo;
message.clearDraft = false;
App::main()->sendMessage(message);
sendMessage(std::move(message));
caption = TextWithTags();
}
const auto to = FileLoadTaskOptions(options);
const auto to = fileLoadTaskOptions(options);
if (album) {
album->silent = to.silent;
}
@@ -3871,7 +4144,7 @@ void ApiWrap::sendFile(
const QByteArray &fileContent,
SendMediaType type,
const SendOptions &options) {
auto to = FileLoadTaskOptions(options);
const auto to = fileLoadTaskOptions(options);
auto caption = TextWithTags();
_fileLoader->addTask(std::make_unique<FileLoadTask>(
QString(),
@@ -3941,6 +4214,319 @@ void ApiWrap::cancelLocalItem(not_null<HistoryItem*> item) {
}
}
void ApiWrap::sendMessage(MessageToSend &&message) {
const auto history = message.history;
const auto peer = history->peer;
auto &textWithTags = message.textWithTags;
auto options = ApiWrap::SendOptions(history);
options.clearDraft = message.clearDraft;
options.replyTo = message.replyTo;
options.generateLocal = true;
options.webPageId = message.webPageId;
sendAction(options);
if (!peer->canWrite()) {
return;
}
Local::saveRecentSentHashtags(textWithTags.text);
auto sending = TextWithEntities();
auto left = TextWithEntities {
textWithTags.text,
ConvertTextTagsToEntities(textWithTags.tags)
};
auto prepareFlags = Ui::ItemTextOptions(
history,
_session->user()).flags;
TextUtilities::PrepareForSending(left, prepareFlags);
HistoryItem *lastMessage = nullptr;
while (TextUtilities::CutPart(sending, left, MaxMessageSize)) {
auto newId = FullMsgId(peerToChannel(peer->id), clientMsgId());
auto randomId = rand_value<uint64>();
TextUtilities::Trim(sending);
App::historyRegRandom(randomId, newId);
App::historyRegSentData(randomId, peer->id, sending.text);
MTPstring msgText(MTP_string(sending.text));
auto flags = NewMessageFlags(peer) | MTPDmessage::Flag::f_entities;
auto sendFlags = MTPmessages_SendMessage::Flags(0);
if (message.replyTo) {
flags |= MTPDmessage::Flag::f_reply_to_msg_id;
sendFlags |= MTPmessages_SendMessage::Flag::f_reply_to_msg_id;
}
MTPMessageMedia media = MTP_messageMediaEmpty();
if (message.webPageId == CancelledWebPageId) {
sendFlags |= MTPmessages_SendMessage::Flag::f_no_webpage;
} else if (message.webPageId) {
auto page = _session->data().webpage(message.webPageId);
media = MTP_messageMediaWebPage(
MTP_webPagePending(
MTP_long(page->id),
MTP_int(page->pendingTill)));
flags |= MTPDmessage::Flag::f_media;
}
bool channelPost = peer->isChannel() && !peer->isMegagroup();
bool silentPost = channelPost
&& _session->data().notifySilentPosts(peer);
if (channelPost) {
flags |= MTPDmessage::Flag::f_views;
flags |= MTPDmessage::Flag::f_post;
}
if (!channelPost) {
flags |= MTPDmessage::Flag::f_from_id;
} else if (peer->asChannel()->addsSignature()) {
flags |= MTPDmessage::Flag::f_post_author;
}
if (silentPost) {
sendFlags |= MTPmessages_SendMessage::Flag::f_silent;
}
auto localEntities = TextUtilities::EntitiesToMTP(sending.entities);
auto sentEntities = TextUtilities::EntitiesToMTP(sending.entities, TextUtilities::ConvertOption::SkipLocal);
if (!sentEntities.v.isEmpty()) {
sendFlags |= MTPmessages_SendMessage::Flag::f_entities;
}
if (message.clearDraft) {
sendFlags |= MTPmessages_SendMessage::Flag::f_clear_draft;
history->clearCloudDraft();
history->setSentDraftText(QString());
}
auto messageFromId = channelPost ? 0 : _session->userId();
auto messagePostAuthor = channelPost
? App::peerName(_session->user())
: QString();
lastMessage = history->addNewMessage(
MTP_message(
MTP_flags(flags),
MTP_int(newId.msg),
MTP_int(messageFromId),
peerToMTP(peer->id),
MTPnullFwdHeader,
MTPint(),
MTP_int(message.replyTo),
MTP_int(unixtime()),
msgText,
media,
MTPnullMarkup,
localEntities,
MTP_int(1),
MTPint(),
MTP_string(messagePostAuthor),
MTPlong()),
NewMessageUnread);
history->sendRequestId = request(MTPmessages_SendMessage(
MTP_flags(sendFlags),
peer->input,
MTP_int(message.replyTo),
msgText,
MTP_long(randomId),
MTPnullMarkup,
sentEntities
)).done([=](const MTPUpdates &result) {
applyUpdates(result, randomId);
history->clearSentDraftText(QString());
}).fail([=](const RPCError &error) {
sendMessageFail(error);
history->clearSentDraftText(QString());
}).afterRequest(history->sendRequestId
).send();
}
if (const auto main = App::main()) {
main->finishForwarding(history);
}
}
void ApiWrap::sendInlineResult(
not_null<UserData*> bot,
not_null<InlineBots::Result*> data,
const SendOptions &options) {
Auth().api().sendAction(options);
const auto history = options.history;
const auto peer = history->peer;
const auto newId = FullMsgId(peerToChannel(peer->id), clientMsgId());
const auto randomId = rand_value<uint64>();
auto flags = NewMessageFlags(peer) | MTPDmessage::Flag::f_media;
auto sendFlags = MTPmessages_SendInlineBotResult::Flag::f_clear_draft | 0;
if (options.replyTo) {
flags |= MTPDmessage::Flag::f_reply_to_msg_id;
sendFlags |= MTPmessages_SendInlineBotResult::Flag::f_reply_to_msg_id;
}
bool channelPost = peer->isChannel() && !peer->isMegagroup();
bool silentPost = channelPost && _session->data().notifySilentPosts(peer);
if (channelPost) {
flags |= MTPDmessage::Flag::f_views;
flags |= MTPDmessage::Flag::f_post;
}
if (!channelPost) {
flags |= MTPDmessage::Flag::f_from_id;
} else if (peer->asChannel()->addsSignature()) {
flags |= MTPDmessage::Flag::f_post_author;
}
if (silentPost) {
sendFlags |= MTPmessages_SendInlineBotResult::Flag::f_silent;
}
if (bot) {
flags |= MTPDmessage::Flag::f_via_bot_id;
}
auto messageFromId = channelPost ? 0 : Auth().userId();
auto messagePostAuthor = channelPost
? App::peerName(Auth().user())
: QString();
MTPint messageDate = MTP_int(unixtime());
UserId messageViaBotId = bot ? peerToUser(bot->id) : 0;
MsgId messageId = newId.msg;
App::historyRegRandom(randomId, newId);
data->addToHistory(
history,
flags,
messageId,
messageFromId,
messageDate,
messageViaBotId,
options.replyTo,
messagePostAuthor);
history->clearCloudDraft();
history->setSentDraftText(QString());
history->sendRequestId = request(MTPmessages_SendInlineBotResult(
MTP_flags(sendFlags),
peer->input,
MTP_int(options.replyTo),
MTP_long(randomId),
MTP_long(data->getQueryId()),
MTP_string(data->getId())
)).done([=](const MTPUpdates &result) {
applyUpdates(result, randomId);
history->clearSentDraftText(QString());
}).fail([=](const RPCError &error) {
sendMessageFail(error);
history->clearSentDraftText(QString());
}).afterRequest(history->sendRequestId
).send();
if (const auto main = App::main()) {
main->finishForwarding(history);
}
}
void ApiWrap::sendExistingDocument(
not_null<DocumentData*> document,
Data::FileOrigin origin,
TextWithEntities caption,
const SendOptions &options) {
Auth().api().sendAction(options);
const auto history = options.history;
const auto peer = history->peer;
const auto newId = FullMsgId(peerToChannel(peer->id), clientMsgId());
const auto randomId = rand_value<uint64>();
auto flags = NewMessageFlags(peer) | MTPDmessage::Flag::f_media;
auto sendFlags = MTPmessages_SendMedia::Flags(0);
if (options.replyTo) {
flags |= MTPDmessage::Flag::f_reply_to_msg_id;
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id;
}
bool channelPost = peer->isChannel() && !peer->isMegagroup();
bool silentPost = channelPost && Auth().data().notifySilentPosts(peer);
if (channelPost) {
flags |= MTPDmessage::Flag::f_views;
flags |= MTPDmessage::Flag::f_post;
}
if (!channelPost) {
flags |= MTPDmessage::Flag::f_from_id;
} else if (peer->asChannel()->addsSignature()) {
flags |= MTPDmessage::Flag::f_post_author;
}
if (silentPost) {
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
}
auto messageFromId = channelPost ? 0 : Auth().userId();
auto messagePostAuthor = channelPost
? App::peerName(Auth().user()) : QString();
TextUtilities::Trim(caption);
auto sentEntities = TextUtilities::EntitiesToMTP(
caption.entities,
TextUtilities::ConvertOption::SkipLocal);
if (!sentEntities.v.isEmpty()) {
sendFlags |= MTPmessages_SendMedia::Flag::f_entities;
}
const auto replyTo = options.replyTo;
const auto captionText = caption.text;
App::historyRegRandom(randomId, newId);
history->addNewDocument(
newId.msg,
flags,
0,
replyTo,
unixtime(),
messageFromId,
messagePostAuthor,
document,
caption,
MTPnullMarkup);
auto failHandler = std::make_shared<Fn<void(const RPCError&)>>();
auto performRequest = [=] {
history->sendRequestId = request(MTPmessages_SendMedia(
MTP_flags(sendFlags),
peer->input,
MTP_int(replyTo),
MTP_inputMediaDocument(
MTP_flags(0),
document->mtpInput(),
MTPint()),
MTP_string(captionText),
MTP_long(randomId),
MTPnullMarkup,
sentEntities
)).done([=](const MTPUpdates &result) {
applyUpdates(result, randomId);
}).fail(
base::duplicate(*failHandler)
).afterRequest(history->sendRequestId
).send();
};
*failHandler = [=](const RPCError &error) {
if (error.code() == 400
&& error.type().startsWith(qstr("FILE_REFERENCE_"))) {
const auto current = document->fileReference();
auto refreshed = [=](const Data::UpdatedFileReferences &data) {
if (document->fileReference() != current) {
performRequest();
} else {
sendMessageFail(error);
}
};
refreshFileReference(origin, std::move(refreshed));
} else {
sendMessageFail(error);
}
};
performRequest();
if (const auto main = App::main()) {
main->finishForwarding(history);
if (document->sticker()) {
main->incrementSticker(document);
}
}
}
void ApiWrap::uploadAlbumMedia(
not_null<HistoryItem*> item,
const MessageGroupId &groupId,
@@ -3980,7 +4566,10 @@ void ApiWrap::uploadAlbumMedia(
: MTPDinputMediaPhoto::Flag(0));
const auto media = MTP_inputMediaPhoto(
MTP_flags(flags),
MTP_inputPhoto(photo.vid, photo.vaccess_hash),
MTP_inputPhoto(
photo.vid,
photo.vaccess_hash,
photo.vfile_reference),
data.has_ttl_seconds() ? data.vttl_seconds : MTPint());
sendAlbumWithUploaded(item, groupId, media);
} break;
@@ -3998,7 +4587,10 @@ void ApiWrap::uploadAlbumMedia(
: MTPDinputMediaDocument::Flag(0));
const auto media = MTP_inputMediaDocument(
MTP_flags(flags),
MTP_inputDocument(document.vid, document.vaccess_hash),
MTP_inputDocument(
document.vid,
document.vaccess_hash,
document.vfile_reference),
data.has_ttl_seconds() ? data.vttl_seconds : MTPint());
sendAlbumWithUploaded(item, groupId, media);
} break;
@@ -4176,10 +4768,21 @@ void ApiWrap::sendAlbumIfReady(not_null<SendingAlbum*> album) {
).send();
}
FileLoadTo ApiWrap::fileLoadTaskOptions(const SendOptions &options) const {
const auto peer = options.history->peer;
return FileLoadTo(
peer->id,
_session->data().notifySilentPosts(peer),
options.replyTo);
}
void ApiWrap::readServerHistory(not_null<History*> history) {
if (history->unreadCount()) {
readServerHistoryForce(history);
}
if (history->unreadMark()) {
changeDialogUnreadMark(history, false);
}
}
void ApiWrap::readServerHistoryForce(not_null<History*> history) {

View File

@@ -21,6 +21,12 @@ class AuthSession;
struct MessageGroupId;
struct SendingAlbum;
enum class SendMediaType;
struct FileLoadTo;
class mtpFileLoader;
namespace InlineBots {
class Result;
} // namespace InlineBots
namespace Storage {
enum class SharedMediaType : signed char;
@@ -50,7 +56,6 @@ inline int32 CountHash(IntRange &&range) {
return int32(acc & 0x7FFFFFFF);
}
} // namespace Api
class ApiWrap : private MTP::Sender, private base::Subscriber {
@@ -80,6 +85,8 @@ public:
//void setFeedChannels(
// not_null<Data::Feed*> feed,
// const std::vector<not_null<ChannelData*>> &channels);
void changeDialogUnreadMark(not_null<History*> history, bool unread);
//void changeDialogUnreadMark(not_null<Data::Feed*> feed, bool unread); // #feed
void requestFullPeer(PeerData *peer);
void requestPeer(PeerData *peer);
@@ -90,6 +97,17 @@ public:
void requestParticipantsCountDelayed(not_null<ChannelData*> channel);
void requestChannelRangeDifference(not_null<History*> history);
using UpdatedFileReferences = Data::UpdatedFileReferences;
using FileReferencesHandler = FnMut<void(const UpdatedFileReferences&)>;
void refreshFileReference(
Data::FileOrigin origin,
FileReferencesHandler &&handler);
void refreshFileReference(
Data::FileOrigin origin,
not_null<mtpFileLoader*> loader,
int requestId,
const QByteArray &current);
void requestChangelog(
const QString &sinceVersion,
Fn<void(const MTPUpdates &result)> callback);
@@ -138,6 +156,14 @@ public:
const MTPInputStickerSet &set);
std::vector<not_null<DocumentData*>> *stickersByEmoji(
not_null<EmojiPtr> emoji);
void toggleFavedSticker(
not_null<DocumentData*> document,
Data::FileOrigin origin,
bool faved);
void toggleSavedGif(
not_null<DocumentData*> document,
Data::FileOrigin origin,
bool saved);
void joinChannel(not_null<ChannelData*> channel);
void leaveChannel(not_null<ChannelData*> channel);
@@ -221,8 +247,7 @@ public:
Fn<void()> callbackNotModified = nullptr);
struct SendOptions {
SendOptions(not_null<History*> history) : history(history) {
}
SendOptions(not_null<History*> history);
not_null<History*> history;
MsgId replyTo = 0;
@@ -277,6 +302,26 @@ public:
bool silent);
void cancelLocalItem(not_null<HistoryItem*> item);
struct MessageToSend {
MessageToSend(not_null<History*> history);
not_null<History*> history;
TextWithTags textWithTags;
MsgId replyTo = 0;
WebPageId webPageId = 0;
bool clearDraft = true;
};
void sendMessage(MessageToSend &&message);
void sendInlineResult(
not_null<UserData*> bot,
not_null<InlineBots::Result*> data,
const SendOptions &options);
void sendExistingDocument(
not_null<DocumentData*> document,
Data::FileOrigin origin,
TextWithEntities caption,
const SendOptions &options);
~ApiWrap();
private:
@@ -294,6 +339,10 @@ private:
TimeMs received = 0;
};
using SimpleFileLocationId = Data::SimpleFileLocationId;
using DocumentFileLocationId = Data::DocumentFileLocationId;
using FileLocationId = Data::FileLocationId;
void updatesReceived(const MTPUpdates &updates);
void checkQuitPreventFinished();
@@ -439,6 +488,7 @@ private:
const MTPInputMedia &media,
bool silent,
uint64 randomId);
FileLoadTo fileLoadTaskOptions(const SendOptions &options) const;
void readFeeds();
@@ -447,6 +497,12 @@ private:
void sendNotifySettingsUpdates();
template <typename Request>
void requestFileReference(
Data::FileOrigin origin,
FileReferencesHandler &&handler,
Request &&data);
not_null<AuthSession*> _session;
MessageDataRequests _messageDataRequests;
@@ -583,6 +639,10 @@ private:
base::flat_set<not_null<const PeerData*>> _updateNotifySettingsPeers;
base::Timer _updateNotifySettingsTimer;
std::map<
Data::FileOrigin,
std::vector<FileReferencesHandler>> _fileReferenceHandlers;
mtpRequestId _deepLinkInfoRequestId = 0;
TimeMs _termsUpdateSendAt = 0;

View File

@@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "styles/style_history.h"
#include "styles/style_boxes.h"
#include "lang/lang_keys.h"
#include "boxes/confirm_box.h"
#include "data/data_abstract_structure.h"
#include "data/data_media_types.h"
#include "data/data_session.h"
@@ -50,8 +51,7 @@ namespace {
UserData *self = nullptr;
using PeersData = QHash<PeerId, PeerData*>;
PeersData peersData;
std::unordered_map<PeerId, std::unique_ptr<PeerData>> peersData;
using LocationsData = QHash<LocationCoords, LocationData*>;
LocationsData locationsData;
@@ -747,7 +747,7 @@ namespace App {
} else if (chat->version <= d.vversion.v && chat->count > 0) {
chat->version = d.vversion.v;
auto canEdit = chat->canEdit();
UserData *user = App::userLoaded(d.vuser_id.v);
const auto user = App::userLoaded(d.vuser_id.v);
if (user) {
if (chat->participants.empty()) {
if (chat->count > 0) {
@@ -960,7 +960,16 @@ namespace App {
auto &d = size.c_photoSize();
if (d.vlocation.type() == mtpc_fileLocation) {
auto &l = d.vlocation.c_fileLocation();
return ImagePtr(StorageImageLocation(d.vw.v, d.vh.v, l.vdc_id.v, l.vvolume_id.v, l.vlocal_id.v, l.vsecret.v), d.vsize.v);
return ImagePtr(
StorageImageLocation(
d.vw.v,
d.vh.v,
l.vdc_id.v,
l.vvolume_id.v,
l.vlocal_id.v,
l.vsecret.v,
l.vfile_reference.v),
d.vsize.v);
}
} break;
case mtpc_photoCachedSize: {
@@ -968,10 +977,28 @@ namespace App {
if (d.vlocation.type() == mtpc_fileLocation) {
auto &l = d.vlocation.c_fileLocation();
auto bytes = qba(d.vbytes);
return ImagePtr(StorageImageLocation(d.vw.v, d.vh.v, l.vdc_id.v, l.vvolume_id.v, l.vlocal_id.v, l.vsecret.v), bytes);
return ImagePtr(
StorageImageLocation(
d.vw.v,
d.vh.v,
l.vdc_id.v,
l.vvolume_id.v,
l.vlocal_id.v,
l.vsecret.v,
l.vfile_reference.v),
bytes);
} else if (d.vlocation.type() == mtpc_fileLocationUnavailable) {
auto bytes = qba(d.vbytes);
return ImagePtr(StorageImageLocation(d.vw.v, d.vh.v, 0, 0, 0, 0), bytes);
return ImagePtr(
StorageImageLocation(
d.vw.v,
d.vh.v,
0,
0,
0,
0,
{}),
bytes);
}
} break;
}
@@ -1074,40 +1101,43 @@ namespace App {
}
PeerData *peer(const PeerId &id, PeerData::LoadedStatus restriction) {
if (!id) return nullptr;
if (!id) {
return nullptr;
}
auto i = peersData.constFind(id);
auto i = peersData.find(id);
if (i == peersData.cend()) {
PeerData *newData = nullptr;
if (peerIsUser(id)) {
newData = new UserData(id);
} else if (peerIsChat(id)) {
newData = new ChatData(id);
} else if (peerIsChannel(id)) {
newData = new ChannelData(id);
}
Assert(newData != nullptr);
auto newData = [&]() -> std::unique_ptr<PeerData> {
if (peerIsUser(id)) {
return std::make_unique<UserData>(id);
} else if (peerIsChat(id)) {
return std::make_unique<ChatData>(id);
} else if (peerIsChannel(id)) {
return std::make_unique<ChannelData>(id);
}
Unexpected("Peer id type.");
}();
newData->input = MTPinputPeer(MTP_inputPeerEmpty());
i = peersData.insert(id, newData);
i = peersData.emplace(id, std::move(newData)).first;
}
switch (restriction) {
case PeerData::MinimalLoaded: {
if (i.value()->loadedStatus == PeerData::NotLoaded) {
if (i->second->loadedStatus == PeerData::NotLoaded) {
return nullptr;
}
} break;
case PeerData::FullLoaded: {
if (i.value()->loadedStatus != PeerData::FullLoaded) {
if (i->second->loadedStatus != PeerData::FullLoaded) {
return nullptr;
}
} break;
}
return i.value();
return i->second.get();
}
void enumerateUsers(Fn<void(not_null<UserData*>)> action) {
for_const (const auto peer, peersData) {
for (const auto &[peerId, peer] : peersData) {
if (const auto user = peer->asUser()) {
action(user);
}
@@ -1116,9 +1146,9 @@ namespace App {
void enumerateChatsChannels(
Fn<void(not_null<PeerData*>)> action) {
for_const (const auto peer, peersData) {
for (const auto &[peerId, peer] : peersData) {
if (!peer->isUser()) {
action(peer);
action(peer.get());
}
}
}
@@ -1128,10 +1158,10 @@ namespace App {
}
PeerData *peerByName(const QString &username) {
QString uname(username.trimmed());
for_const (PeerData *peer, peersData) {
const auto uname = username.trimmed();
for (const auto &[peerId, peer] : peersData) {
if (!peer->userName().compare(uname, Qt::CaseInsensitive)) {
return peer;
return peer.get();
}
}
return nullptr;
@@ -1151,19 +1181,6 @@ namespace App {
}
}
MTPPhoto photoFromUserPhoto(MTPint userId, MTPint date, const MTPUserProfilePhoto &photo) {
if (photo.type() == mtpc_userProfilePhoto) {
const auto &uphoto(photo.c_userProfilePhoto());
QVector<MTPPhotoSize> photoSizes;
photoSizes.push_back(MTP_photoSize(MTP_string("a"), uphoto.vphoto_small, MTP_int(160), MTP_int(160), MTP_int(0)));
photoSizes.push_back(MTP_photoSize(MTP_string("c"), uphoto.vphoto_big, MTP_int(640), MTP_int(640), MTP_int(0)));
return MTP_photo(MTP_flags(0), uphoto.vphoto_id, MTP_long(0), date, MTP_vector<MTPPhotoSize>(photoSizes));
}
return MTP_photoEmpty(MTP_long(0));
}
QString peerName(const PeerData *peer, bool forDialogs) {
return peer ? ((forDialogs && peer->isUser() && !peer->asUser()->nameOrPhone.isEmpty()) ? peer->asUser()->nameOrPhone : peer->name) : lang(lng_deleted);
}
@@ -1246,24 +1263,16 @@ namespace App {
void historyClearMsgs() {
::dependentItems.clear();
QVector<HistoryItem*> toDelete;
for_const (auto item, msgsData) {
if (!item->mainView()) {
toDelete.push_back(item);
}
}
for_const (auto &chMsgsData, channelMsgsData) {
for_const (auto item, chMsgsData) {
if (!item->mainView()) {
toDelete.push_back(item);
}
}
}
msgsData.clear();
channelMsgsData.clear();
for_const (auto item, toDelete) {
const auto oldData = base::take(msgsData);
const auto oldChannelData = base::take(channelMsgsData);
for (const auto item : oldData) {
delete item;
}
for (const auto &data : oldChannelData) {
for (const auto item : data) {
delete item;
}
}
clearMousedItems();
}
@@ -1275,10 +1284,7 @@ namespace App {
cSetSavedPeersByTime(SavedPeersByTime());
cSetRecentInlineBots(RecentInlineBots());
for_const (auto peer, ::peersData) {
delete peer;
}
::peersData.clear();
peersData.clear();
if (AuthSession::Exists()) {
Auth().api().clearWebPageRequests();
@@ -1598,7 +1604,13 @@ namespace App {
}
void quit() {
if (quitting()) return;
if (quitting()) {
return;
} else if (AuthSession::Exists()
&& Auth().data().exportInProgress()) {
Auth().data().stopExportWithConfirmation([] { App::quit(); });
return;
}
setLaunchState(QuitRequested);
if (auto window = wnd()) {
@@ -1625,11 +1637,9 @@ namespace App {
}
void restart() {
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
bool updateReady = (Core::UpdateChecker().state() == Core::UpdateChecker::State::Ready);
#else // !TDESKTOP_DISABLE_AUTOUPDATE
bool updateReady = false;
#endif // else for !TDESKTOP_DISABLE_AUTOUPDATE
using namespace Core;
const auto updateReady = !UpdaterDisabled()
&& (UpdateChecker().state() == UpdateChecker::State::Ready);
if (updateReady) {
cSetRestartingUpdate(true);
} else {

View File

@@ -7,7 +7,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "core/basic_types.h"
#include "data/data_types.h"
#include "data/data_peer.h"
@@ -143,8 +142,6 @@ namespace App {
LocationData *location(const LocationCoords &coords);
void forgetMedia();
MTPPhoto photoFromUserPhoto(MTPint userId, MTPint date, const MTPUserProfilePhoto &photo);
Histories &histories();
not_null<History*> history(const PeerId &peer);
History *historyLoaded(const PeerId &peer);

View File

@@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/crash_reports.h"
#include "messenger.h"
#include "base/timer.h"
#include "base/concurrent_timer.h"
#include "base/qthelp_url.h"
#include "base/qthelp_regex.h"
#include "core/update_checker.h"
@@ -64,11 +65,10 @@ QString _escapeFrom7bit(const QString &str) {
} // namespace
bool StartUrlRequiresActivate(const QString &url) {
bool InternalPassportLink(const QString &url) {
const auto urlTrimmed = url.trimmed();
if (!urlTrimmed.startsWith(qstr("tg://"), Qt::CaseInsensitive)
|| Messenger::Instance().locked()) {
return true;
if (!urlTrimmed.startsWith(qstr("tg://"), Qt::CaseInsensitive)) {
return false;
}
const auto command = urlTrimmed.midRef(qstr("tg://").size());
@@ -78,11 +78,23 @@ bool StartUrlRequiresActivate(const QString &url) {
qsl("^passport/?\\?(.+)(#|$)"),
command,
matchOptions);
const auto authLegacyMatch = regex_match(
qsl("^resolve/?\\?domain=telegrampassport&(.+)(#|$)"),
const auto usernameMatch = regex_match(
qsl("^resolve/?\\?(.+)(#|$)"),
command,
matchOptions);
return !authMatch->hasMatch() && !authLegacyMatch->hasMatch();
const auto usernameValue = usernameMatch->hasMatch()
? url_parse_params(
usernameMatch->captured(1),
UrlParamNameTransform::ToLower).value(qsl("domain"))
: QString();
const auto authLegacy = (usernameValue == qstr("telegrampassport"));
return authMatch->hasMatch() || authLegacy;
}
bool StartUrlRequiresActivate(const QString &url) {
return Messenger::Instance().locked()
? true
: !InternalPassportLink(url);
}
Application::Application(
@@ -91,10 +103,9 @@ Application::Application(
char **argv)
: QApplication(argc, argv)
, _launcher(launcher)
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
, _updateChecker(std::make_unique<Core::UpdateChecker>())
#endif // TDESKTOP_DISABLE_AUTOUPDATE
{
, _updateChecker(Core::UpdaterDisabled()
? nullptr
: std::make_unique<Core::UpdateChecker>()) {
const auto d = QFile::encodeName(QDir(cWorkingDir()).absolutePath());
char h[33] = { 0 };
hashMd5Hex(d.constData(), d.size(), h);
@@ -204,13 +215,13 @@ void Application::socketError(QLocalSocket::LocalSocketError e) {
}
#endif // !Q_OS_WINRT
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
if (!cNoStartUpdate() && Core::checkReadyUpdate()) {
if (!Core::UpdaterDisabled()
&& !cNoStartUpdate()
&& Core::checkReadyUpdate()) {
cSetRestartingUpdate(true);
DEBUG_LOG(("Application Info: installing update instead of starting app..."));
return App::quit();
}
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
singleInstanceChecked();
}
@@ -384,9 +395,7 @@ void Application::closeApplication() {
_localSocket.close();
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
_updateChecker = nullptr;
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
}
inline Application *application() {
@@ -438,6 +447,7 @@ void adjustSingleTimers() {
a->adjustSingleTimers();
}
base::Timer::Adjust();
base::ConcurrentTimerEnvironment::Adjust();
}
void connect(const char *signal, QObject *object, const char *method) {

View File

@@ -12,6 +12,7 @@ class Launcher;
class UpdateChecker;
} // namespace Core
bool InternalPassportLink(const QString &url);
bool StartUrlRequiresActivate(const QString &url);
class Application : public QApplication {
@@ -61,9 +62,7 @@ private:
void singleInstanceChecked();
private:
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
std::unique_ptr<Core::UpdateChecker> _updateChecker;
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
};

View File

@@ -25,3 +25,14 @@ inline constexpr size_t array_size(const Type(&)[Size]) {
}
} // namespace base
template <typename T>
inline void accumulate_max(T &a, const T &b) { if (a < b) a = b; }
template <typename T>
inline void accumulate_min(T &a, const T &b) { if (a > b) a = b; }
template <size_t Size>
QLatin1String qstr(const char(&string)[Size]) {
return QLatin1String(string, Size - 1);
}

View File

@@ -0,0 +1,9 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "base/base_pch.h"

View File

@@ -0,0 +1,36 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include <QtCore/QByteArray>
#include <QtCore/QString>
#include <QtCore/QUrl>
#include <QtCore/QMutex>
#include <QtCore/QRegularExpression>
#include <QtCore/QThread>
#include <QtCore/QCoreApplication>
#if QT_VERSION < QT_VERSION_CHECK(5, 5, 0)
#define OS_MAC_OLD
#endif // QT_VERSION < 5.5.0
#include <crl/crl.h>
#include <rpl/rpl.h>
#include <vector>
#include <unordered_map>
#include <set>
#include <range/v3/all.hpp>
#ifdef Q_OS_WIN
#include "platform/win/windows_range_v3_helpers.h"
#endif // Q_OS_WIN
#include "base/flat_map.h"
#include "base/flat_set.h"
#include "base/optional.h"
#include "base/openssl_help.h"

View File

@@ -7,21 +7,25 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include <string>
#include <exception>
#include <memory>
#include <ctime>
#include <functional>
#include <crl/crl.h>
#include "base/build_config.h"
#include "base/ordered_set.h"
#include "base/unique_function.h"
#include "base/functors.h"
#include <QtGlobal>
#include <string>
#include <exception>
#include <memory>
#include <ctime>
#include <functional>
#include <gsl/gsl>
namespace func = base::functors;
using gsl::not_null;
using index_type = gsl::index;
using size_type = gsl::index;
template <typename Signature>
using Fn = std::function<Signature>;
@@ -30,6 +34,8 @@ template <typename Signature>
using FnMut = base::unique_function<Signature>;
//using uchar = unsigned char; // Qt has uchar
using int8 = qint8;
using uint8 = quint8;
using int16 = qint16;
using uint16 = quint16;
using int32 = qint32;
@@ -39,5 +45,23 @@ using uint64 = quint64;
using float32 = float;
using float64 = double;
#define qsl(s) QStringLiteral(s)
#define qstr(s) QLatin1String((s), sizeof(s) - 1)
using TimeMs = int64;
using TimeId = int32;
// Define specializations for QByteArray for Qt 5.3.2, because
// QByteArray in Qt 5.3.2 doesn't declare "pointer" subtype.
#ifdef OS_MAC_OLD
namespace gsl {
template <>
inline span<char> make_span<QByteArray>(QByteArray &cont) {
return span<char>(cont.data(), cont.size());
}
template <>
inline span<const char> make_span(const QByteArray &cont) {
return span<const char>(cont.constData(), cont.size());
}
} // namespace gsl
#endif // OS_MAC_OLD

View File

@@ -0,0 +1,76 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "base/algorithm.h"
#include <atomic>
namespace base {
class binary_guard {
public:
binary_guard() = default;
binary_guard(binary_guard &&other);
binary_guard &operator=(binary_guard &&other);
~binary_guard();
bool alive() const;
void kill();
private:
void destroy();
std::atomic<bool> *_bothAlive = nullptr;
friend std::pair<binary_guard, binary_guard> make_binary_guard();
};
inline binary_guard::binary_guard(binary_guard &&other)
: _bothAlive(base::take(other._bothAlive)) {
}
inline binary_guard &binary_guard::operator=(binary_guard &&other) {
if (this != &other) {
destroy();
_bothAlive = base::take(other._bothAlive);
}
return *this;
}
inline binary_guard::~binary_guard() {
destroy();
}
inline bool binary_guard::alive() const {
return _bothAlive && _bothAlive->load();
}
inline void binary_guard::kill() {
destroy();
}
inline void binary_guard::destroy() {
if (const auto both = base::take(_bothAlive)) {
auto old = true;
if (!both->compare_exchange_strong(old, false)) {
delete both;
}
}
}
inline std::pair<binary_guard, binary_guard> make_binary_guard() {
auto result = std::pair<binary_guard, binary_guard>();
result.first._bothAlive
= result.second._bothAlive
= new std::atomic<bool>(true);
return result;
}
} // namespace base

View File

@@ -56,11 +56,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#endif
#if defined(__GNUC__)
#define FORCE_INLINE inline __attribute__((always_inline))
#define TG_FORCE_INLINE inline __attribute__((always_inline))
#elif defined(_MSC_VER)
#define FORCE_INLINE __forceinline
#define TG_FORCE_INLINE __forceinline
#else
#define FORCE_INLINE inline
#define TG_FORCE_INLINE inline
#endif
#include <climits>

View File

@@ -7,13 +7,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include <gsl/gsl>
#include <gsl/gsl_byte>
namespace bytes {
using span = gsl::span<gsl::byte>;
using const_span = gsl::span<const gsl::byte>;
using vector = std::vector<gsl::byte>;
using type = gsl::byte;
using span = gsl::span<type>;
using const_span = gsl::span<const type>;
using vector = std::vector<type>;
template <gsl::index Size>
using array = std::array<type, Size>;
template <
typename Container,
@@ -47,6 +52,16 @@ inline const_span make_span(const Type *value, std::size_t count) {
return gsl::as_bytes(gsl::make_span(value, count));
}
template <typename Type>
inline span object_as_span(Type *value) {
return bytes::make_span(value, 1);
}
template <typename Type>
inline const_span object_as_span(const Type *value) {
return bytes::make_span(value, 1);
}
template <typename Container>
inline vector make_vector(const Container &container) {
const auto buffer = bytes::make_span(container);
@@ -65,7 +80,7 @@ inline void move(span destination, const_span source) {
memmove(destination.data(), source.data(), source.size());
}
inline void set_with_const(span destination, gsl::byte value) {
inline void set_with_const(span destination, type value) {
memset(
destination.data(),
gsl::to_integer<unsigned char>(value),
@@ -134,4 +149,7 @@ vector concatenate(SpanRange args) {
return result;
}
// Implemented in base/openssl_help.h
void set_random(span destination);
} // namespace bytes

View File

@@ -0,0 +1,367 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "base/concurrent_timer.h"
#include <QtCore/QThread>
#include <QtCore/QCoreApplication>
using namespace base::details;
namespace base {
namespace details {
namespace {
constexpr auto kCallDelayedEvent = QEvent::Type(QEvent::User + 1);
constexpr auto kCancelTimerEvent = QEvent::Type(QEvent::User + 2);
static_assert(kCancelTimerEvent < QEvent::MaxUser);
ConcurrentTimerEnvironment *Environment/* = nullptr*/;
QMutex EnvironmentMutex;
class CallDelayedEvent : public QEvent {
public:
CallDelayedEvent(
crl::time_type timeout,
Qt::TimerType type,
FnMut<void()> method);
crl::time_type timeout() const;
Qt::TimerType type() const;
FnMut<void()> takeMethod();
private:
crl::time_type _timeout = 0;
Qt::TimerType _type = Qt::PreciseTimer;
FnMut<void()> _method;
};
class CancelTimerEvent : public QEvent {
public:
CancelTimerEvent();
};
CallDelayedEvent::CallDelayedEvent(
crl::time_type timeout,
Qt::TimerType type,
FnMut<void()> method)
: QEvent(kCallDelayedEvent)
, _timeout(timeout)
, _type(type)
, _method(std::move(method)) {
Expects(_timeout >= 0 && _timeout < std::numeric_limits<int>::max());
}
crl::time_type CallDelayedEvent::timeout() const {
return _timeout;
}
Qt::TimerType CallDelayedEvent::type() const {
return _type;
}
FnMut<void()> CallDelayedEvent::takeMethod() {
return base::take(_method);
}
CancelTimerEvent::CancelTimerEvent() : QEvent(kCancelTimerEvent) {
}
} // namespace
class TimerObject : public QObject {
public:
TimerObject(
not_null<QThread*> thread,
not_null<QObject*> adjuster,
Fn<void()> adjust);
protected:
bool event(QEvent *e) override;
private:
void callDelayed(not_null<CallDelayedEvent*> e);
void callNow();
void cancel();
void adjust();
FnMut<void()> _next;
Fn<void()> _adjust;
int _timerId = 0;
};
TimerObject::TimerObject(
not_null<QThread*> thread,
not_null<QObject*> adjuster,
Fn<void()> adjust)
: _adjust(std::move(adjust)) {
moveToThread(thread);
connect(
adjuster,
&QObject::destroyed,
this,
&TimerObject::adjust,
Qt::DirectConnection);
}
bool TimerObject::event(QEvent *e) {
const auto type = e->type();
switch (type) {
case kCallDelayedEvent:
callDelayed(static_cast<CallDelayedEvent*>(e));
return true;
case kCancelTimerEvent:
cancel();
return true;
case QEvent::Timer:
callNow();
return true;
}
return QObject::event(e);
}
void TimerObject::callDelayed(not_null<CallDelayedEvent*> e) {
cancel();
const auto timeout = e->timeout();
const auto type = e->type();
_next = e->takeMethod();
if (timeout > 0) {
_timerId = startTimer(timeout, type);
} else {
base::take(_next)();
}
}
void TimerObject::cancel() {
if (const auto id = base::take(_timerId)) {
killTimer(id);
}
_next = nullptr;
}
void TimerObject::callNow() {
auto next = base::take(_next);
cancel();
next();
}
void TimerObject::adjust() {
if (_adjust) {
_adjust();
}
}
TimerObjectWrap::TimerObjectWrap(Fn<void()> adjust) {
QMutexLocker lock(&EnvironmentMutex);
if (Environment) {
_value = Environment->createTimer(std::move(adjust));
}
}
TimerObjectWrap::~TimerObjectWrap() {
if (_value) {
QMutexLocker lock(&EnvironmentMutex);
if (Environment) {
_value.release()->deleteLater();
}
}
}
void TimerObjectWrap::call(
crl::time_type timeout,
Qt::TimerType type,
FnMut<void()> method) {
sendEvent(std::make_unique<CallDelayedEvent>(
timeout,
type,
std::move(method)));
}
void TimerObjectWrap::cancel() {
sendEvent(std::make_unique<CancelTimerEvent>());
}
void TimerObjectWrap::sendEvent(std::unique_ptr<QEvent> event) {
if (!_value) {
return;
}
QCoreApplication::postEvent(
_value.get(),
event.release(),
Qt::HighEventPriority);
}
} // namespace details
ConcurrentTimerEnvironment::ConcurrentTimerEnvironment() {
_thread.start();
_adjuster.moveToThread(&_thread);
acquire();
}
ConcurrentTimerEnvironment::~ConcurrentTimerEnvironment() {
_thread.quit();
release();
_thread.wait();
QObject::disconnect(&_adjuster, &QObject::destroyed, nullptr, nullptr);
}
std::unique_ptr<TimerObject> ConcurrentTimerEnvironment::createTimer(
Fn<void()> adjust) {
return std::make_unique<TimerObject>(
&_thread,
&_adjuster,
std::move(adjust));
}
void ConcurrentTimerEnvironment::Adjust() {
QMutexLocker lock(&EnvironmentMutex);
if (Environment) {
Environment->adjustTimers();
}
}
void ConcurrentTimerEnvironment::adjustTimers() {
QObject emitter;
QObject::connect(
&emitter,
&QObject::destroyed,
&_adjuster,
&QObject::destroyed,
Qt::QueuedConnection);
}
void ConcurrentTimerEnvironment::acquire() {
Expects(Environment == nullptr);
QMutexLocker lock(&EnvironmentMutex);
Environment = this;
}
void ConcurrentTimerEnvironment::release() {
Expects(Environment == this);
QMutexLocker lock(&EnvironmentMutex);
Environment = nullptr;
}
ConcurrentTimer::ConcurrentTimer(
Fn<void(FnMut<void()>)> runner,
Fn<void()> callback)
: _runner(std::move(runner))
, _object(createAdjuster())
, _callback(std::move(callback))
, _type(Qt::PreciseTimer)
, _adjusted(false) {
setRepeat(Repeat::Interval);
}
Fn<void()> ConcurrentTimer::createAdjuster() {
auto guards = base::make_binary_guard();
_guard = std::make_shared<bool>(true);
return [=, runner = _runner, guard = std::weak_ptr<bool>(_guard)] {
runner([=] {
if (!guard.lock()) {
return;
}
adjust();
});
};
}
void ConcurrentTimer::start(
TimeMs timeout,
Qt::TimerType type,
Repeat repeat) {
_type = type;
setRepeat(repeat);
_adjusted = false;
setTimeout(timeout);
cancelAndSchedule(_timeout);
_next = crl::time() + _timeout;
}
void ConcurrentTimer::cancelAndSchedule(int timeout) {
auto guards = base::make_binary_guard();
_running = std::move(guards.first);
auto method = [
=,
runner = _runner,
guard = std::move(guards.second)
]() mutable {
if (!guard.alive()) {
return;
}
runner([=, guard = std::move(guard)] {
if (!guard.alive()) {
return;
}
timerEvent();
});
};
_object.call(timeout, _type, std::move(method));
}
void ConcurrentTimer::timerEvent() {
if (repeat() == Repeat::Interval) {
if (_adjusted) {
start(_timeout, _type, repeat());
} else {
_next = crl::time() + _timeout;
}
} else {
cancel();
}
if (_callback) {
_callback();
}
}
void ConcurrentTimer::cancel() {
_running = {};
if (isActive()) {
_running = base::binary_guard();
_object.cancel();
}
}
TimeMs ConcurrentTimer::remainingTime() const {
if (!isActive()) {
return -1;
}
const auto now = crl::time();
return (_next > now) ? (_next - now) : TimeMs(0);
}
void ConcurrentTimer::adjust() {
auto remaining = remainingTime();
if (remaining >= 0) {
cancelAndSchedule(remaining);
_adjusted = true;
}
}
void ConcurrentTimer::setTimeout(TimeMs timeout) {
Expects(timeout >= 0 && timeout <= std::numeric_limits<int>::max());
_timeout = static_cast<unsigned int>(timeout);
}
int ConcurrentTimer::timeout() const {
return _timeout;
}
} // namespace base

View File

@@ -0,0 +1,146 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "base/binary_guard.h"
#include <crl/crl_time.h>
#include <crl/crl_object_on_queue.h>
#include <QtCore/QThread>
namespace base {
namespace details {
class TimerObject;
class TimerObjectWrap {
public:
explicit TimerObjectWrap(Fn<void()> adjust);
~TimerObjectWrap();
void call(
crl::time_type timeout,
Qt::TimerType type,
FnMut<void()> method);
void cancel();
private:
void sendEvent(std::unique_ptr<QEvent> event);
std::unique_ptr<TimerObject> _value;
};
} // namespace details
class ConcurrentTimerEnvironment {
public:
ConcurrentTimerEnvironment();
~ConcurrentTimerEnvironment();
std::unique_ptr<details::TimerObject> createTimer(Fn<void()> adjust);
static void Adjust();
private:
void acquire();
void release();
void adjustTimers();
QThread _thread;
QObject _adjuster;
};
class ConcurrentTimer {
public:
explicit ConcurrentTimer(
Fn<void(FnMut<void()>)> runner,
Fn<void()> callback = nullptr);
template <typename Object>
explicit ConcurrentTimer(
crl::weak_on_queue<Object> weak,
Fn<void()> callback = nullptr);
static Qt::TimerType DefaultType(TimeMs timeout) {
constexpr auto kThreshold = TimeMs(1000);
return (timeout > kThreshold) ? Qt::CoarseTimer : Qt::PreciseTimer;
}
void setCallback(Fn<void()> callback) {
_callback = std::move(callback);
}
void callOnce(TimeMs timeout) {
callOnce(timeout, DefaultType(timeout));
}
void callEach(TimeMs timeout) {
callEach(timeout, DefaultType(timeout));
}
void callOnce(TimeMs timeout, Qt::TimerType type) {
start(timeout, type, Repeat::SingleShot);
}
void callEach(TimeMs timeout, Qt::TimerType type) {
start(timeout, type, Repeat::Interval);
}
bool isActive() const {
return _running.alive();
}
void cancel();
TimeMs remainingTime() const;
private:
enum class Repeat : unsigned {
Interval = 0,
SingleShot = 1,
};
Fn<void()> createAdjuster();
void start(TimeMs timeout, Qt::TimerType type, Repeat repeat);
void adjust();
void cancelAndSchedule(int timeout);
void setTimeout(TimeMs timeout);
int timeout() const;
void timerEvent();
void setRepeat(Repeat repeat) {
_repeat = static_cast<unsigned>(repeat);
}
Repeat repeat() const {
return static_cast<Repeat>(_repeat);
}
Fn<void(FnMut<void()>)> _runner;
std::shared_ptr<bool> _guard; // Must be before _object.
details::TimerObjectWrap _object;
Fn<void()> _callback;
base::binary_guard _running;
TimeMs _next = 0;
int _timeout = 0;
Qt::TimerType _type : 2;
bool _adjusted : 1;
unsigned _repeat : 1;
};
template <typename Object>
ConcurrentTimer::ConcurrentTimer(
crl::weak_on_queue<Object> weak,
Fn<void()> callback)
: ConcurrentTimer(weak.runner(), std::move(callback)) {
}
} // namespace base

View File

@@ -307,6 +307,15 @@ public:
};
flat_multi_map() = default;
flat_multi_map(const flat_multi_map &other) = default;
flat_multi_map(flat_multi_map &&other) = default;
flat_multi_map &operator=(const flat_multi_map &other) {
auto copy = other;
return (*this = std::move(copy));
}
flat_multi_map &operator=(flat_multi_map &&other) = default;
size_type size() const {
return impl().size();
}
@@ -417,8 +426,9 @@ public:
if (range.first == range.second) {
return 0;
}
const auto result = (range.second - range.first);
impl().erase(range.first, range.second);
return (range.second - range.first);
return result;
}
iterator erase(const_iterator where) {

View File

@@ -46,6 +46,27 @@ TEST_CASE("flat_maps should keep items sorted by key", "[flat_map]") {
}
}
TEST_CASE("simple flat_maps tests", "[flat_map]") {
SECTION("copy constructor") {
base::flat_map<int, string> v;
v.emplace(0, "a");
v.emplace(2, "b");
auto u = v;
REQUIRE(u.size() == 2);
REQUIRE(u.find(0) == u.begin());
REQUIRE(u.find(2) == u.end() - 1);
}
SECTION("assignment") {
base::flat_map<int, string> v, u;
v.emplace(0, "a");
v.emplace(2, "b");
u = v;
REQUIRE(u.size() == 2);
REQUIRE(u.find(0) == u.begin());
REQUIRE(u.find(2) == u.end() - 1);
}
}
TEST_CASE("flat_maps custom comparator", "[flat_map]") {
base::flat_map<int_wrap, string, int_wrap_comparator> v;
v.emplace({ 0 }, "a");

View File

@@ -297,8 +297,9 @@ public:
if (range.first == range.second) {
return 0;
}
const auto result = (range.second - range.first);
impl().erase(range.first, range.second);
return (range.second - range.first);
return result;
}
iterator erase(const_iterator where) {

View File

@@ -0,0 +1,52 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include <rpl/details/callable.h>
namespace base {
template <typename Data, typename Method, typename ...Methods>
inline decltype(auto) match_method(
Data &&data,
Method &&method,
Methods &&...methods) {
using namespace rpl::details;
if constexpr (is_callable_plain_v<Method, Data&&>) {
return std::forward<Method>(method)(std::forward<Data>(data));
} else {
return match_method(
std::forward<Data>(data),
std::forward<Methods>(methods)...);
}
}
template <
typename Data1,
typename Data2,
typename Method,
typename ...Methods>
inline decltype(auto) match_method2(
Data1 &&data1,
Data2 &&data2,
Method &&method,
Methods &&...methods) {
using namespace rpl::details;
if constexpr (is_callable_plain_v<Method, Data1&&, Data2&&>) {
return std::forward<Method>(method)(
std::forward<Data1>(data1),
std::forward<Data2>(data2));
} else {
return match_method2(
std::forward<Data1>(data1),
std::forward<Data2>(data2),
std::forward<Methods>(methods)...);
}
}
} // namespace base

View File

@@ -12,6 +12,7 @@ namespace internal {
namespace {
bool CantUseObservables = false;
void (*HandleDelayedMethod)() = nullptr;
struct ObservableListWrap {
~ObservableListWrap() {
@@ -35,7 +36,9 @@ ObservableListWrap &ActiveObservables() {
void RegisterPendingObservable(ObservableCallHandlers *handlers) {
if (CantUseObservables) return;
PendingObservables().list.insert(handlers);
Global::RefHandleObservables().call();
if (HandleDelayedMethod) {
HandleDelayedMethod();
}
}
void UnregisterActiveObservable(ObservableCallHandlers *handlers) {
@@ -51,6 +54,10 @@ void UnregisterObservable(ObservableCallHandlers *handlers) {
} // namespace internal
void InitObservables(void(*HandleDelayed)()) {
internal::HandleDelayedMethod = HandleDelayed;
}
void HandleObservables() {
if (internal::CantUseObservables) return;
auto &active = internal::ActiveObservables().list;

View File

@@ -452,6 +452,7 @@ private:
};
void InitObservables(void(*HandleDelayed)());
void HandleObservables();
template <

View File

@@ -8,13 +8,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once
#include "base/bytes.h"
#include "base/algorithm.h"
#include "base/basic_types.h"
extern "C" {
#include <openssl/bn.h>
#include <openssl/sha.h>
#include <openssl/rand.h>
#include <openssl/aes.h>
#include <openssl/modes.h>
#include <openssl/crypto.h>
#include <openssl/evp.h>
} // extern "C"
namespace openssl {
@@ -83,18 +87,11 @@ public:
_failed = true;
}
}
void setModExp(
const BigNum &a,
const BigNum &p,
const BigNum &m,
const Context &context = Context()) {
if (a.failed() || p.failed() || m.failed()) {
void setAdd(const BigNum &a, const BigNum &b) {
if (a.failed() || b.failed()) {
_failed = true;
} else if (a.isNegative() || p.isNegative() || m.isNegative()) {
_failed = true;
} else if (!BN_mod_exp(raw(), a.raw(), p.raw(), m.raw(), context.raw())) {
_failed = true;
} else if (isNegative()) {
} else if (!BN_add(raw(), a.raw(), b.raw())) {
_failed = true;
}
}
@@ -112,6 +109,16 @@ public:
_failed = true;
}
}
void setMul(
const BigNum &a,
const BigNum &b,
const Context &context = Context()) {
if (a.failed() || b.failed()) {
_failed = true;
} else if (!BN_mul(raw(), a.raw(), b.raw(), context.raw())) {
_failed = true;
}
}
BN_ULONG setDivWord(BN_ULONG word) {
Expects(word != 0);
if (failed()) {
@@ -124,6 +131,51 @@ public:
}
return result;
}
void setModSub(
const BigNum &a,
const BigNum &b,
const BigNum &m,
const Context &context = Context()) {
if (a.failed() || b.failed() || m.failed()) {
_failed = true;
} else if (a.isNegative() || b.isNegative() || m.isNegative()) {
_failed = true;
} else if (!BN_mod_sub(raw(), a.raw(), b.raw(), m.raw(), context.raw())) {
_failed = true;
} else if (isNegative()) {
_failed = true;
}
}
void setModMul(
const BigNum &a,
const BigNum &b,
const BigNum &m,
const Context &context = Context()) {
if (a.failed() || b.failed() || m.failed()) {
_failed = true;
} else if (a.isNegative() || b.isNegative() || m.isNegative()) {
_failed = true;
} else if (!BN_mod_mul(raw(), a.raw(), b.raw(), m.raw(), context.raw())) {
_failed = true;
} else if (isNegative()) {
_failed = true;
}
}
void setModExp(
const BigNum &base,
const BigNum &power,
const BigNum &m,
const Context &context = Context()) {
if (base.failed() || power.failed() || m.failed()) {
_failed = true;
} else if (base.isNegative() || power.isNegative() || m.isNegative()) {
_failed = true;
} else if (!BN_mod_exp(raw(), base.raw(), power.raw(), m.raw(), context.raw())) {
_failed = true;
} else if (isNegative()) {
_failed = true;
}
}
bool isNegative() const {
return failed() ? false : BN_is_negative(raw());
@@ -194,9 +246,54 @@ public:
return _failed;
}
static BigNum ModExp(const BigNum &base, const BigNum &power, const openssl::BigNum &mod) {
static BigNum Add(const BigNum &a, const BigNum &b) {
BigNum result;
result.setModExp(base, power, mod);
result.setAdd(a, b);
return result;
}
static BigNum Sub(const BigNum &a, const BigNum &b) {
BigNum result;
result.setSub(a, b);
return result;
}
static BigNum Mul(
const BigNum &a,
const BigNum &b,
const Context &context = Context()) {
BigNum result;
result.setMul(a, b, context);
return result;
}
static BigNum ModSub(
const BigNum &a,
const BigNum &b,
const BigNum &mod,
const Context &context = Context()) {
BigNum result;
result.setModSub(a, b, mod, context);
return result;
}
static BigNum ModMul(
const BigNum &a,
const BigNum &b,
const BigNum &mod,
const Context &context = Context()) {
BigNum result;
result.setModMul(a, b, mod, context);
return result;
}
static BigNum ModExp(
const BigNum &base,
const BigNum &power,
const BigNum &mod,
const Context &context = Context()) {
BigNum result;
result.setModExp(base, power, mod, context);
return result;
}
static BigNum Failed() {
BigNum result;
result._failed = true;
return result;
}
@@ -206,43 +303,144 @@ private:
};
inline BigNum operator-(const BigNum &a, const BigNum &b) {
BigNum result;
result.setSub(a, b);
return result;
namespace details {
template <typename Context, typename Method, typename Arg>
inline void ShaUpdate(Context context, Method method, Arg &&arg) {
const auto span = bytes::make_span(arg);
method(context, span.data(), span.size());
}
inline bytes::vector Sha512(bytes::const_span data) {
auto result = bytes::vector(SHA512_DIGEST_LENGTH);
SHA512(
template <typename Context, typename Method, typename Arg, typename ...Args>
inline void ShaUpdate(Context context, Method method, Arg &&arg, Args &&...args) {
const auto span = bytes::make_span(arg);
method(context, span.data(), span.size());
ShaUpdate(context, method, args...);
}
template <size_type Size, typename Method>
inline bytes::vector Sha(Method method, bytes::const_span data) {
auto result = bytes::vector(Size);
method(
reinterpret_cast<const unsigned char*>(data.data()),
data.size(),
reinterpret_cast<unsigned char*>(result.data()));
return result;
}
template <
size_type Size,
typename Context,
typename Init,
typename Update,
typename Finalize,
typename ...Args,
typename = std::enable_if_t<(sizeof...(Args) > 1)>>
bytes::vector Sha(
Context context,
Init init,
Update update,
Finalize finalize,
Args &&...args) {
auto result = bytes::vector(Size);
init(&context);
ShaUpdate(&context, update, args...);
finalize(reinterpret_cast<unsigned char*>(result.data()), &context);
return result;
}
template <
size_type Size,
typename Evp>
bytes::vector Pbkdf2(
bytes::const_span password,
bytes::const_span salt,
int iterations,
Evp evp) {
auto result = bytes::vector(Size);
PKCS5_PBKDF2_HMAC(
reinterpret_cast<const char*>(password.data()),
password.size(),
reinterpret_cast<const unsigned char*>(salt.data()),
salt.size(),
iterations,
evp,
result.size(),
reinterpret_cast<unsigned char*>(result.data()));
return result;
}
} // namespace details
constexpr auto kSha1Size = size_type(SHA_DIGEST_LENGTH);
constexpr auto kSha256Size = size_type(SHA256_DIGEST_LENGTH);
constexpr auto kSha512Size = size_type(SHA512_DIGEST_LENGTH);
inline bytes::vector Sha1(bytes::const_span data) {
return details::Sha<kSha1Size>(SHA1, data);
}
template <
typename ...Args,
typename = std::enable_if_t<(sizeof...(Args) > 1)>>
inline bytes::vector Sha1(Args &&...args) {
return details::Sha<kSha1Size>(
SHA_CTX(),
SHA1_Init,
SHA1_Update,
SHA1_Final,
args...);
}
inline bytes::vector Sha256(bytes::const_span data) {
auto result = bytes::vector(SHA256_DIGEST_LENGTH);
SHA256(
reinterpret_cast<const unsigned char*>(data.data()),
data.size(),
reinterpret_cast<unsigned char*>(result.data()));
return result;
return details::Sha<kSha256Size>(SHA256, data);
}
inline bytes::vector Sha1(bytes::const_span data) {
auto result = bytes::vector(SHA_DIGEST_LENGTH);
SHA1(
reinterpret_cast<const unsigned char*>(data.data()),
data.size(),
reinterpret_cast<unsigned char*>(result.data()));
return result;
template <
typename ...Args,
typename = std::enable_if_t<(sizeof...(Args) > 1)>>
inline bytes::vector Sha256(Args &&...args) {
return details::Sha<kSha256Size>(
SHA256_CTX(),
SHA256_Init,
SHA256_Update,
SHA256_Final,
args...);
}
inline bytes::vector Sha512(bytes::const_span data) {
return details::Sha<kSha512Size>(SHA512, data);
}
template <
typename ...Args,
typename = std::enable_if_t<(sizeof...(Args) > 1)>>
inline bytes::vector Sha512(Args &&...args) {
return details::Sha<kSha512Size>(
SHA512_CTX(),
SHA512_Init,
SHA512_Update,
SHA512_Final,
args...);
}
inline void AddRandomSeed(bytes::const_span data) {
RAND_seed(data.data(), data.size());
}
inline bytes::vector Pbkdf2Sha512(
bytes::const_span password,
bytes::const_span salt,
int iterations) {
return details::Pbkdf2<kSha512Size>(
password,
salt,
iterations,
EVP_sha512());
}
} // namespace openssl
namespace bytes {

View File

@@ -109,6 +109,15 @@ public:
return _impl.template get_unchecked<T>();
}
template <typename ...Methods>
decltype(auto) match(Methods &&...methods) {
return base::match(_impl, std::forward<Methods>(methods)...);
}
template <typename ...Methods>
decltype(auto) match(Methods &&...methods) const {
return base::match(_impl, std::forward<Methods>(methods)...);
}
private:
variant<none_type, Types...> _impl;
@@ -124,6 +133,20 @@ inline const T *get_if(const optional_variant<Types...> *v) {
return (v && v->template is<T>()) ? &v->template get_unchecked<T>() : nullptr;
}
template <typename ...Types, typename ...Methods>
inline decltype(auto) match(
optional_variant<Types...> &value,
Methods &&...methods) {
return value.match(std::forward<Methods>(methods)...);
}
template <typename ...Types, typename ...Methods>
inline decltype(auto) match(
const optional_variant<Types...> &value,
Methods &&...methods) {
return value.match(std::forward<Methods>(methods)...);
}
template <typename Type>
class optional;
@@ -160,12 +183,17 @@ class optional : public optional_variant<Type> {
public:
using parent::parent;
Type &operator*() {
Type &operator*() & {
Expects(parent::template is<Type>());
return parent::template get_unchecked<Type>();
}
const Type &operator*() const {
Type &&operator*() && {
Expects(parent::template is<Type>());
return std::move(parent::template get_unchecked<Type>());
}
const Type &operator*() const & {
Expects(parent::template is<Type>());
return parent::template get_unchecked<Type>();

View File

@@ -8,6 +8,53 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/qthelp_url.h"
namespace qthelp {
namespace {
QRegularExpression CreateRegExp(const QString &expression) {
auto result = QRegularExpression(
expression,
QRegularExpression::UseUnicodePropertiesOption);
#ifndef OS_MAC_OLD
result.optimize();
#endif // OS_MAC_OLD
return result;
}
QString ExpressionDomain() {
// Matches any domain name, containing at least one '.', including "file.txt".
return QString::fromUtf8("(?<![\\w\\$\\-\\_%=\\.])(?:([a-zA-Z]+)://)?((?:[A-Za-z" "\xD0\x90-\xD0\xAF\xD0\x81" "\xD0\xB0-\xD1\x8F\xD1\x91" "0-9\\-\\_]+\\.){1,10}([A-Za-z" "\xD1\x80\xD1\x84" "\\-\\d]{2,22})(\\:\\d+)?)");
}
QString ExpressionDomainExplicit() {
// Matches any domain name, containing a protocol, including "test://localhost".
return QString::fromUtf8("(?<![\\w\\$\\-\\_%=\\.])(?:([a-zA-Z]+)://)((?:[A-Za-z" "\xD0\x90-\xD0\xAF\xD0\x81" "\xD0\xB0-\xD1\x8F\xD1\x91" "0-9\\-\\_]+\\.){0,10}([A-Za-z" "\xD1\x80\xD1\x84" "\\-\\d]{2,22})(\\:\\d+)?)");
}
bool IsGoodProtocol(const QString &protocol) {
const auto equals = [&](QLatin1String string) {
return protocol.compare(string, Qt::CaseInsensitive) == 0;
};
return equals(qstr("http"))
|| equals(qstr("https"))
|| equals(qstr("tg"));
}
} // namespace
const QRegularExpression &RegExpDomain() {
static const auto result = CreateRegExp(ExpressionDomain());
return result;
}
const QRegularExpression &RegExpDomainExplicit() {
static const auto result = CreateRegExp(ExpressionDomainExplicit());
return result;
}
QRegularExpression RegExpProtocol() {
static const auto result = CreateRegExp("^([a-zA-Z]+)://");
return result;
}
QMap<QString, QString> url_parse_params(
const QString &params,
@@ -55,4 +102,24 @@ QString url_append_query_or_hash(const QString &url, const QString &add) {
+ add;
}
QString validate_url(const QString &value) {
const auto trimmed = value.trimmed();
if (trimmed.isEmpty()) {
return QString();
}
const auto match = RegExpDomainExplicit().match(trimmed);
if (!match.hasMatch()) {
const auto domain = RegExpDomain().match(trimmed);
if (!domain.hasMatch() || domain.capturedStart() != 0) {
return QString();
}
return qstr("http://") + trimmed;
} else if (match.capturedStart() != 0) {
return QString();
}
const auto protocolMatch = RegExpProtocol().match(trimmed);
Assert(protocolMatch.hasMatch());
return IsGoodProtocol(protocolMatch.captured(1)) ? trimmed : QString();
}
} // namespace qthelp

View File

@@ -9,6 +9,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace qthelp {
const QRegularExpression &RegExpDomain();
const QRegularExpression &RegExpDomainExplicit();
QRegularExpression RegExpProtocol();
inline QString url_encode(const QString &part) {
return QString::fromLatin1(QUrl::toPercentEncoding(part));
}
@@ -30,4 +34,6 @@ QString url_append_query_or_hash(const QString &url, const QString &add);
bool is_ipv6(const QString &ip);
QString validate_url(const QString &value);
} // namespace qthelp

View File

@@ -8,27 +8,21 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/runtime_composer.h"
struct RuntimeComposerMetadatasMap {
QMap<uint64, RuntimeComposerMetadata*> data;
~RuntimeComposerMetadatasMap() {
for_const (const RuntimeComposerMetadata *p, data) {
delete p;
}
}
std::map<uint64, std::unique_ptr<RuntimeComposerMetadata>> data;
QMutex mutex;
};
const RuntimeComposerMetadata *GetRuntimeComposerMetadata(uint64 mask) {
static RuntimeComposerMetadatasMap RuntimeComposerMetadatas;
static QMutex RuntimeComposerMetadatasMutex;
QMutexLocker lock(&RuntimeComposerMetadatasMutex);
auto i = RuntimeComposerMetadatas.data.constFind(mask);
if (i == RuntimeComposerMetadatas.data.cend()) {
RuntimeComposerMetadata *meta = new RuntimeComposerMetadata(mask);
Assert(meta != nullptr);
i = RuntimeComposerMetadatas.data.insert(mask, meta);
QMutexLocker lock(&RuntimeComposerMetadatas.mutex);
auto i = RuntimeComposerMetadatas.data.find(mask);
if (i == end(RuntimeComposerMetadatas.data)) {
i = RuntimeComposerMetadatas.data.emplace(
mask,
std::make_unique<RuntimeComposerMetadata>(mask)).first;
}
return i.value();
return i->second.get();
}
const RuntimeComposerMetadata *RuntimeComposerBase::ZeroRuntimeComposerMetadata = GetRuntimeComposerMetadata(0);

View File

@@ -10,6 +10,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "reporters/catch_reporter_compact.hpp"
#include <QFile>
int (*TestForkedMethod)()/* = nullptr*/;
namespace base {
namespace assertion {
@@ -84,6 +86,8 @@ int main(int argc, const char *argv[]) {
for (auto i = 0; i != argc; ++i) {
if (argv[i] == QString("--touch") && i + 1 != argc) {
touchFile = QFile::decodeName(argv[++i]);
} else if (argv[i] == QString("--forked") && TestForkedMethod) {
return TestForkedMethod();
}
}
const char *catch_argv[] = {

View File

@@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "base/timer.h"
#include <QtCore/QTimerEvent>
namespace base {
namespace {
@@ -24,7 +26,6 @@ Timer::Timer(
moveToThread(thread);
}
Timer::Timer(Fn<void()> callback)
: QObject(nullptr)
, _callback(std::move(callback))
@@ -48,7 +49,7 @@ void Timer::start(TimeMs timeout, Qt::TimerType type, Repeat repeat) {
setTimeout(timeout);
_timerId = startTimer(_timeout, _type);
if (_timerId) {
_next = getms(true) + _timeout;
_next = crl::time() + _timeout;
} else {
_next = 0;
}
@@ -64,7 +65,7 @@ TimeMs Timer::remainingTime() const {
if (!isActive()) {
return -1;
}
auto now = getms(true);
auto now = crl::time();
return (_next > now) ? (_next - now) : TimeMs(0);
}
@@ -101,7 +102,7 @@ void Timer::timerEvent(QTimerEvent *e) {
if (_adjusted) {
start(_timeout, _type, repeat());
} else {
_next = getms(true) + _timeout;
_next = crl::time() + _timeout;
}
} else {
cancel();

View File

@@ -7,7 +7,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include <QtCore/QObject>
#include <QtCore/QThread>
#include "base/observer.h"
#include "base/flat_map.h"
namespace base {

View File

@@ -69,11 +69,11 @@ public:
unique_any(const unique_any &other) = delete;
unique_any &operator=(const unique_any &other) = delete;
unique_any(unique_any &&other) noexcept
: _impl(std::move(other._impl)) {
}
unique_any &operator=(unique_any &&other) noexcept {
_impl = std::move(other._impl);
return *this;
@@ -88,7 +88,7 @@ public:
std::forward<Value>(other),
std::is_copy_constructible<std::decay_t<Value>>()) {
}
template <
typename Value,
typename = std::enable_if_t<
@@ -106,7 +106,7 @@ public:
}
return *this;
}
template <
typename Value,
typename ...Args,
@@ -143,7 +143,7 @@ private:
unique_any(Value &&other, std::true_type)
: _impl(std::forward<Value>(other)) {
}
template <
typename Value,
typename = std::enable_if_t<
@@ -177,7 +177,7 @@ inline void swap(unique_any &a, unique_any &b) noexcept {
template <
typename Value,
typename ...Args>
inline auto make_any(Args &&...args)
inline auto make_any(Args &&...args)
-> std::enable_if_t<
std::is_copy_constructible_v<std::decay_t<Value>>,
unique_any> {
@@ -187,7 +187,7 @@ inline auto make_any(Args &&...args)
template <
typename Value,
typename ...Args>
inline auto make_any(Args &&...args)
inline auto make_any(Args &&...args)
-> std::enable_if_t<
!std::is_copy_constructible_v<std::decay_t<Value>>
&& std::is_move_constructible_v<std::decay_t<Value>>,

View File

@@ -124,9 +124,8 @@ public:
_impl.swap(other._impl);
}
template <typename ...OtherArgs>
Return operator()(OtherArgs &&...args) {
return _impl(std::forward<OtherArgs>(args)...);
Return operator()(Args ...args) {
return _impl(std::forward<Args>(args)...);
}
explicit operator bool() const {

View File

@@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include <utility>
namespace base {
namespace details {

View File

@@ -8,6 +8,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once
#include <mapbox/variant.hpp>
#include <rpl/details/type_list.h>
#include "base/match_method.h"
#include "base/assertion.h"
// We use base::variant<> alias and base::get_if() helper while we don't have std::variant<>.
namespace base {
@@ -25,20 +28,79 @@ inline const T *get_if(const variant<Types...> *v) {
return (v && v->template is<T>()) ? &v->template get_unchecked<T>() : nullptr;
}
// Simplified visit
template <typename Method, typename... Types>
inline auto visit(Method &&method, const variant<Types...> &value) {
return value.match(std::forward<Method>(method));
namespace type_list = rpl::details::type_list;
template <typename ...Types>
struct normalized_variant {
using list = type_list::list<Types...>;
using distinct = type_list::distinct_t<list>;
using type = std::conditional_t<
type_list::size_v<distinct> == 1,
type_list::get_t<0, distinct>,
type_list::extract_to_t<distinct, base::variant>>;
};
template <typename ...Types>
using normalized_variant_t
= typename normalized_variant<Types...>::type;
template <typename TypeList, typename Variant, typename ...Methods>
struct match_helper;
template <
typename Type,
typename ...Types,
typename Variant,
typename ...Methods>
struct match_helper<type_list::list<Type, Types...>, Variant, Methods...> {
static decltype(auto) call(Variant &value, Methods &&...methods) {
if (const auto v = get_if<Type>(&value)) {
return match_method(
*v,
std::forward<Methods>(methods)...);
}
return match_helper<
type_list::list<Types...>,
Variant,
Methods...>::call(
value,
std::forward<Methods>(methods)...);
}
};
template <
typename Type,
typename Variant,
typename ...Methods>
struct match_helper<type_list::list<Type>, Variant, Methods...> {
static decltype(auto) call(Variant &value, Methods &&...methods) {
if (const auto v = get_if<Type>(&value)) {
return match_method(
*v,
std::forward<Methods>(methods)...);
}
Unexpected("Valueless variant in base::match().");
}
};
template <typename ...Types, typename ...Methods>
inline decltype(auto) match(
variant<Types...> &value,
Methods &&...methods) {
return match_helper<
type_list::list<Types...>,
variant<Types...>,
Methods...>::call(value, std::forward<Methods>(methods)...);
}
template <typename Method, typename... Types>
inline auto visit(Method &&method, variant<Types...> &value) {
return value.match(std::forward<Method>(method));
}
template <typename Method, typename... Types>
inline auto visit(Method &&method, variant<Types...> &&value) {
return value.match(std::forward<Method>(method));
template <typename ...Types, typename ...Methods>
inline decltype(auto) match(
const variant<Types...> &value,
Methods &&...methods) {
return match_helper<
type_list::list<Types...>,
const variant<Types...>,
Methods...>::call(value, std::forward<Methods>(methods)...);
}
} // namespace base

View File

@@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once
#include <atomic>
#include <memory>
namespace base {
namespace details {
@@ -315,24 +316,3 @@ struct guard_traits<
};
} // namespace crl
#ifdef QT_VERSION
template <typename Lambda>
inline void InvokeQueued(const base::has_weak_ptr *context, Lambda &&lambda) {
auto callback = [
guard = base::make_weak(context),
lambda = std::forward<Lambda>(lambda)
] {
if (guard) {
lambda();
}
};
QObject proxy;
QObject::connect(
&proxy,
&QObject::destroyed,
QCoreApplication::instance(),
std::move(callback),
Qt::QueuedConnection);
}
#endif // QT_VERSION

View File

@@ -31,18 +31,18 @@ void AboutBox::prepare() {
addButton(langFactory(lng_close), [this] { closeBox(); });
const auto linkHook = [](const ClickHandlerPtr &link, auto button) {
const auto linkFilter = [](const ClickHandlerPtr &link, auto button) {
if (const auto url = dynamic_cast<UrlClickHandler*>(link.get())) {
url->UrlClickHandler::onClick(button);
url->UrlClickHandler::onClick({ button });
return false;
}
return true;
};
_text3->setRichText(lng_about_text_3(lt_faq_open, qsl("[a href=\"%1\"]").arg(telegramFaqLink()), lt_faq_close, qsl("[/a]")));
_text1->setClickHandlerHook(linkHook);
_text2->setClickHandlerHook(linkHook);
_text3->setClickHandlerHook(linkHook);
_text1->setClickHandlerFilter(linkFilter);
_text2->setClickHandlerFilter(linkFilter);
_text3->setClickHandlerFilter(linkFilter);
_version->setClickedCallback([this] { showVersionHistory(); });

View File

@@ -157,7 +157,7 @@ void BackgroundBox::Inner::updateWallpapers() {
for (int i = 0; i < BackgroundsInRow * 3; ++i) {
if (i >= _bgCount) break;
App::cServerBackgrounds().at(i).thumb->load();
App::cServerBackgrounds()[i].thumb->load(Data::FileOrigin());
}
}
@@ -172,13 +172,16 @@ void BackgroundBox::Inner::paintEvent(QPaintEvent *e) {
int index = i * BackgroundsInRow + j;
if (index >= _bgCount) break;
const App::WallPaper &paper(App::cServerBackgrounds().at(index));
paper.thumb->load();
const auto &paper = App::cServerBackgrounds()[index];
paper.thumb->load(Data::FileOrigin());
int x = st::backgroundPadding + j * (st::backgroundSize.width() + st::backgroundPadding);
int y = st::backgroundPadding + i * (st::backgroundSize.height() + st::backgroundPadding);
const QPixmap &pix(paper.thumb->pix(st::backgroundSize.width(), st::backgroundSize.height()));
const auto &pix = paper.thumb->pix(
Data::FileOrigin(),
st::backgroundSize.width(),
st::backgroundSize.height());
p.drawPixmap(x, y, pix);
if (paper.id == Window::Theme::Background()->id()) {

View File

@@ -113,7 +113,7 @@ boxMediumSkip: 20px;
boxButtonPadding: margins(8px, 12px, 13px, 12px);
boxLayerButtonPadding: margins(8px, 8px, 8px, 8px);
boxLabel: FlatLabel(defaultFlatLabel) {
minWidth: 285px;
minWidth: 274px;
align: align(topleft);
style: boxLabelStyle;
}
@@ -354,7 +354,35 @@ peerListBox: PeerList(defaultPeerList) {
}
}
localStorageBoxSkip: 10px;
localStorageRowHeight: 50px;
localStorageRowPadding: margins(23px, 5px, 20px, 5px);
localStorageRowTitle: FlatLabel(defaultFlatLabel) {
textFg: windowBoldFg;
maxHeight: 20px;
style: TextStyle(defaultTextStyle) {
font: font(14px semibold);
linkFont: font(14px semibold);
linkFontOver: font(14px semibold);
}
}
localStorageRowSize: FlatLabel(defaultFlatLabel) {
textFg: contactsStatusFg;
maxHeight: 20px;
style: TextStyle(defaultTextStyle) {
font: font(14px);
linkFont: font(14px);
linkFontOver: font(14px);
}
}
localStorageClear: defaultBoxButton;
localStorageLimitLabel: LabelSimple(defaultLabelSimple) {
font: boxTextFont;
}
localStorageLimitLabelMargin: margins(23px, 10px, 20px, 5px);
localStorageLimitSlider: MediaSlider(defaultContinuousSlider) {
seekSize: size(15px, 15px);
}
localStorageLimitMargin: margins(23px, 5px, 20px, 10px);
shareRowsTop: 12px;
shareRowHeight: 108px;

View File

@@ -648,7 +648,13 @@ void DeleteMessagesBox::deleteAndClear() {
Auth().data().sendHistoryChangeNotifications();
}
ConfirmInviteBox::ConfirmInviteBox(QWidget*, const QString &title, bool isChannel, const MTPChatPhoto &photo, int count, const QVector<UserData*> &participants)
ConfirmInviteBox::ConfirmInviteBox(
QWidget*,
const QString &title,
bool isChannel,
const MTPChatPhoto &photo,
int count,
const QVector<UserData*> &participants)
: _title(this, st::confirmInviteTitle)
, _status(this, st::confirmInviteStatus)
, _participants(participants) {
@@ -675,7 +681,7 @@ ConfirmInviteBox::ConfirmInviteBox(QWidget*, const QString &title, bool isChanne
_photo = ImagePtr(location);
if (!_photo->loaded()) {
subscribe(Auth().downloaderTaskFinished(), [this] { update(); });
_photo->load();
_photo->load(Data::FileOrigin());
}
}
}
@@ -730,15 +736,31 @@ void ConfirmInviteBox::paintEvent(QPaintEvent *e) {
Painter p(this);
if (_photo) {
p.drawPixmap((width() - st::confirmInvitePhotoSize) / 2, st::confirmInvitePhotoTop, _photo->pixCircled(st::confirmInvitePhotoSize, st::confirmInvitePhotoSize));
p.drawPixmap(
(width() - st::confirmInvitePhotoSize) / 2,
st::confirmInvitePhotoTop,
_photo->pixCircled(
Data::FileOrigin(),
st::confirmInvitePhotoSize,
st::confirmInvitePhotoSize));
} else {
_photoEmpty->paint(p, (width() - st::confirmInvitePhotoSize) / 2, st::confirmInvitePhotoTop, width(), st::confirmInvitePhotoSize);
_photoEmpty->paint(
p,
(width() - st::confirmInvitePhotoSize) / 2,
st::confirmInvitePhotoTop,
width(),
st::confirmInvitePhotoSize);
}
int sumWidth = _participants.size() * _userWidth;
int left = (width() - sumWidth) / 2;
for_const (auto user, _participants) {
user->paintUserpicLeft(p, left + (_userWidth - st::confirmInviteUserPhotoSize) / 2, st::confirmInviteUserPhotoTop, width(), st::confirmInviteUserPhotoSize);
user->paintUserpicLeft(
p,
left + (_userWidth - st::confirmInviteUserPhotoSize) / 2,
st::confirmInviteUserPhotoTop,
width(),
st::confirmInviteUserPhotoSize);
left += _userWidth;
}
}

Some files were not shown because too many files have changed in this diff Show More