Compare commits

...

77 Commits

Author SHA1 Message Date
John Preston
d2fa8ef0b0 Alpha version 1.2.18: Fix OS X old build. 2018-05-05 22:30:42 +03:00
John Preston
97b576f446 Alpha version 1.2.18.
- Improve working through proxy servers.
- Bug fixes and other minor improvements.
2018-05-05 22:07:05 +03:00
John Preston
257dfa6b3f Improve phone rules checking. 2018-05-05 21:55:39 +03:00
John Preston
678d2a58c5 Improve proxy row design. 2018-05-05 21:55:39 +03:00
John Preston
e0431d270b Allow cdn requests through mtproto proxy. 2018-05-05 21:55:39 +03:00
John Preston
7797e5a3b7 Improve proxies box design. 2018-05-05 21:55:39 +03:00
John Preston
d15b0cdb08 Improve infinite radial animation. 2018-05-05 21:55:39 +03:00
John Preston
1af2769209 Closed beta 1.2.17.4: Fix option lookup. 2018-05-05 21:55:39 +03:00
John Preston
e6906b84f3 Closed beta 1.2.17.3: Fix layout. 2018-05-05 21:55:39 +03:00
John Preston
ca0f6c7ded Closed beta 1.2.17.3. 2018-05-05 21:55:39 +03:00
John Preston
f9ff676e57 Improve proxies box design and progress animation. 2018-05-05 21:55:38 +03:00
John Preston
db7041f2dc Send different dns requests for simple config. 2018-05-05 21:55:38 +03:00
John Preston
ad1f089802 Read autoupdate prefix from config. 2018-05-05 21:55:38 +03:00
John Preston
62c812858e Improve config re-requesting. 2018-05-05 21:55:38 +03:00
John Preston
4bf66cb6e9 Better special config implementation. 2018-05-05 21:55:38 +03:00
John Preston
95fee543ec Try all available endpoints from config. 2018-05-05 21:55:38 +03:00
John Preston
df4daca15b Display connecting/online proxy state. 2018-05-05 21:55:38 +03:00
John Preston
f794d8dbd8 Check proxy availability in ProxiesBox. 2018-05-05 21:55:38 +03:00
John Preston
9935a36c3d Create and edit proxy box. 2018-05-05 21:55:38 +03:00
John Preston
a7c77682d7 Apply, delete and restore proxies in the box. 2018-05-05 21:55:38 +03:00
John Preston
8bbea976ea Display proxies list in a box. 2018-05-05 21:55:38 +03:00
John Preston
900d1ddb36 Support multiple proxies in local storage. 2018-05-05 21:55:38 +03:00
John Preston
8e99135f37 Support tg://proxy links. 2018-05-05 21:55:37 +03:00
John Preston
dc9483e07a Fix possible deadlock.
Some unknown code (like getSession) was called while holding
_requestsByDcLock mutex which could lead to a deadlock.

Now all access points to _requestsByDc are simple.
2018-05-05 21:55:37 +03:00
John Preston
48e913bf2c Use static version map for autoupdates. 2018-05-05 21:55:37 +03:00
John Preston
993cb987a6 Improve autoupdate code, move it from Application. 2018-05-05 21:55:37 +03:00
John Preston
65f968ec1b Update API scheme to layer 78. 2018-05-05 21:55:37 +03:00
John Preston
93f6d4b6e7 Support many config endpoints for one dc+params. 2018-05-05 21:55:37 +03:00
John Preston
7482025c10 Support work with different dcs on a single IP. 2018-05-05 21:55:37 +03:00
John Preston
909acb25fd Requesting config if can't connect. 2018-05-05 21:55:37 +03:00
John Preston
4a9db99082 Use application level proxy settings. 2018-05-05 21:55:37 +03:00
John Zimmermann
a2606c4fc4 fix libressl-2.7 compat (#4633) 2018-04-28 21:57:02 +03:00
Max Razumov
647c609bf8 Update supported version of Ubuntu (#4612) 2018-04-28 21:55:15 +03:00
John Preston
cf98025177 Use exact tagged version of OpenAL.
I hope if fixes #4531.
2018-04-18 22:10:21 +04:00
John Preston
e0f20e9f82 Version 1.2.17: Add changelog entry. 2018-04-08 21:34:33 +04:00
John Preston
597a5c9d75 Version 1.2.17: Fix undefined behaviour on exit.
Core::Launcher didn't have virtual destructor it required.
2018-04-08 21:32:48 +04:00
John Preston
d055908f4f Version 1.2.16: Improve release build scripts. 2018-04-08 18:23:12 +04:00
John Preston
f3eac6b259 Version 1.2.16: Fix text processing crash in OS X 10.6. 2018-04-08 18:21:40 +04:00
John Preston
87d6081408 Version 1.2.16: Fix build in Xcode 9.3. 2018-04-07 12:47:08 +04:00
John Preston
dd53bd1c55 Version 1.2.16.
- Bug fixes and other minor improvements.
2018-04-07 12:20:46 +04:00
Kirsan
3ff033cdf3 Fix for https://github.com/telegramdesktop/tdesktop/issues/4544
(cherry picked from commit d99c757d44d7c31fbb0eb290f273ad4d2d464255)
2018-04-07 12:13:52 +04:00
John Preston
c1c3b6a7e5 Disable emoji suggestions for :-D/:-P 2018-04-07 11:51:17 +04:00
John Preston
64d5a6acd5 Fix game scores display. 2018-04-07 11:41:48 +04:00
John Preston
e5b2e0a6b5 Fix memory clearing from photos/documents. 2018-04-07 11:01:32 +04:00
John Preston
9895b45293 Fix calls supported layer arguments. 2018-04-07 11:00:43 +04:00
John Preston
811fc43b63 Fix Qt text processing crash.
Fixes #4551.
2018-03-30 18:18:35 +04:00
John Preston
9dcfa3ad6e Version 1.2.15.
- Bug fixes and other minor improvements.
2018-03-26 02:02:58 +04:00
John Preston
67bda19458 Fix inline bot messages with previews. 2018-03-26 02:01:13 +04:00
John Preston
6c38919c3d Scroll history to down when sharing contact. 2018-03-26 01:47:05 +04:00
John Preston
ce9445287c Extend huge local cache map crash annotations. 2018-03-26 00:56:41 +04:00
John Preston
d4bd8862bd Fix switching between stickers pan and panel.
Fixes #4537.
2018-03-26 00:54:02 +04:00
John Preston
6904e023d3 Increment dropdown emoji selection in recent list.
Fixes #4539.
2018-03-26 00:28:23 +04:00
John Preston
91a7a77bb0 Fix case-insensitive emoji suggestions.
Fixes #4528, fixes #4511, fixes #4535.
2018-03-26 00:18:14 +04:00
John Preston
d9306e3e30 Fix parent link refresh for GIF webpage preview.
Fixes #4534.
2018-03-26 00:18:14 +04:00
John Preston
efdd3df129 Fix working with webpage preview GIFs.
Fixes #4533.
2018-03-26 00:18:14 +04:00
John Preston
63098d3c7d Work better with 'unlimited' config time limits. 2018-03-26 00:18:14 +04:00
Vasilii Babich
aa5781b550 Update some details in Xcode build instructions. 2018-03-25 19:29:38 +04:00
John Preston
d6e1862c08 Fix crash in AdminLog view with deleted delegates. 2018-03-22 02:27:14 +04:00
John Preston
9aa2831fef Version 1.2.14.
- Discover new stickers.
Type one emoji to see suggestions from popular sticker sets.
Suggestions from your installed sticker sets will come first.
- Search for Stickers. Click on the new search icon
to access your sticker sets or find new ones.
- Quick Reply. Double click near a message for a quick reply.
2018-03-21 18:05:45 +04:00
John Preston
70eb29c1a9 Alpha version 1.2.13.
- Bug fixes and other minor improvements.
2018-03-21 13:46:32 +04:00
John Preston
13e07b1623 Add some debug information. 2018-03-21 13:46:22 +04:00
John Preston
27ce1f8d44 Show something inside an 'empty' message. 2018-03-20 18:51:51 +04:00
John Preston
38c20fc3c2 Return one old way for requesting special config. 2018-03-20 18:21:36 +04:00
John Preston
4a32b00068 Setting for cloud stickers suggestions. 2018-03-20 01:09:03 +04:00
John Preston
3406f88fdc Single place for joining channels, in ApiWrap. 2018-03-20 01:09:03 +04:00
Marco Trevisan
c96cb37680 Travis flags update (#4506)
* travis: don't build alsoft tools, examples and tests

* travis: don't try to build with mir client support
2018-03-16 17:39:29 +03:00
John Preston
0d415837a0 Destroy old info button in top bar widget.
Fixes #4503.
2018-03-15 18:22:55 +03:00
John Preston
9dc48522d8 Fix multi-forward notification layout (long name). 2018-03-15 03:12:00 +03:00
John Preston
31b82a5d92 Show audio file performer-title in dialogs list. 2018-03-15 03:12:00 +03:00
John Preston
87ab4d9dd1 Improve local search in sticker sets.
- Don't index special sticker sets, like "Favorite stickers".
- Show "Not found." if no local results and waiting for server-side.
2018-03-15 03:11:59 +03:00
John Preston
b6e7625016 Improve case-insensitive emoji suggestions. 2018-03-15 03:11:59 +03:00
Sven-Hendrik Haase
c5e6bfce95 Fix wrong uname flag used
This is required because uname -p actually returns "unknown" for some hardware. The uname help documents this by stating that -p is non-portable. The -m flag is the one to use.
2018-03-14 15:01:26 +03:00
John Preston
7a849b2899 Fix crash on album parts being deleted. 2018-03-13 13:54:24 +03:00
John Preston
999fa39d7c Fix shared links layout for webpage previews.
Fixes #4489.
2018-03-13 13:29:56 +03:00
John Preston
7de15ce5cf Fix inline bots with photos. 2018-03-13 13:29:42 +03:00
John Preston
f792b0052f Refresh caption Text after media is being sent.
Fixes #4488.
2018-03-13 13:19:06 +03:00
John Preston
57d0b1d215 Show error when joining a full group. 2018-03-12 10:55:30 +03:00
164 changed files with 6430 additions and 3163 deletions

View File

@@ -486,6 +486,9 @@ buildOpenAL() {
-D CMAKE_INSTALL_PREFIX=$OPENAL_PATH \
-D CMAKE_BUILD_TYPE=Release \
-D LIBTYPE=STATIC \
-D ALSOFT_EXAMPLES=OFF \
-D ALSOFT_TESTS=OFF \
-D ALSOFT_UTILS=OFF \
..
make $MAKE_ARGS
sudo make install
@@ -608,7 +611,7 @@ buildCustomQt() {
./configure -prefix $QT_PATH -release -opensource -confirm-license -qt-zlib \
-qt-libpng -qt-libjpeg -qt-freetype -qt-harfbuzz -qt-pcre -qt-xcb \
-qt-xkbcommon-x11 -no-opengl -no-gtkstyle -static \
-nomake examples -nomake tests \
-nomake examples -nomake tests -no-mirclient \
-dbus-runtime -no-gstreamer -no-mtdev # <- Not sure about these
make $MAKE_ARGS
sudo make install

View File

@@ -15,7 +15,7 @@ The source code is published under GPLv3 with OpenSSL exception, the license is
* Windows XP - Windows 10 (**not** RT)
* 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 16.04
* Ubuntu 12.04 - Ubuntu 18.04
* Fedora 22 - Fedora 24
## Third-party

View File

@@ -1,5 +1,5 @@
diff --git a/configure b/configure
index cb8d78f..cadb3f0 100755
index cb8d78fd3c..cadb3f0a88 100755
--- a/configure
+++ b/configure
@@ -511,7 +511,8 @@ if [ "$BUILD_ON_MAC" = "yes" ]; then
@@ -13,7 +13,7 @@ index cb8d78f..cadb3f0 100755
echo " Xcode not set up properly. You may need to confirm the license" >&2
echo " agreement by running /usr/bin/xcodebuild without arguments." >&2
diff --git a/mkspecs/common/g++-macx.conf b/mkspecs/common/g++-macx.conf
index 086510d..c485967 100644
index 086510dd96..c485967863 100644
--- a/mkspecs/common/g++-macx.conf
+++ b/mkspecs/common/g++-macx.conf
@@ -14,7 +14,13 @@ QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += -gdwarf-2
@@ -32,7 +32,7 @@ index 086510d..c485967 100644
QMAKE_XCODE_GCC_VERSION = com.apple.compilers.llvmgcc42
diff --git a/mkspecs/features/mac/default_pre.prf b/mkspecs/features/mac/default_pre.prf
index 0cc8cd6..ca9725b 100644
index 0cc8cd6dfd..ca9725b779 100644
--- a/mkspecs/features/mac/default_pre.prf
+++ b/mkspecs/features/mac/default_pre.prf
@@ -12,7 +12,9 @@ isEmpty(QMAKE_XCODE_DEVELOPER_PATH) {
@@ -47,7 +47,7 @@ index 0cc8cd6..ca9725b 100644
}
diff --git a/src/gui/image/qbmphandler.cpp b/src/gui/image/qbmphandler.cpp
index bb79a13..5d595bc 100644
index bb79a139b3..5d595bc3b3 100644
--- a/src/gui/image/qbmphandler.cpp
+++ b/src/gui/image/qbmphandler.cpp
@@ -220,6 +220,10 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int
@@ -74,7 +74,7 @@ index bb79a13..5d595bc 100644
if (ncols > 0) { // read color table
uchar rgb[4];
diff --git a/src/gui/painting/qpaintengine_p.h b/src/gui/painting/qpaintengine_p.h
index ebff950..4300ca4 100644
index ebff9509ab..4300ca4c0f 100644
--- a/src/gui/painting/qpaintengine_p.h
+++ b/src/gui/painting/qpaintengine_p.h
@@ -87,8 +87,18 @@ public:
@@ -98,7 +98,7 @@ index ebff950..4300ca4 100644
// Make sure we're inside the viewport.
diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp
index 4879ae5..56cdcba 100644
index 4879ae51d7..56cdcbaf01 100644
--- a/src/gui/text/qtextlayout.cpp
+++ b/src/gui/text/qtextlayout.cpp
@@ -654,6 +654,9 @@ int QTextLayout::nextCursorPosition(int oldPos, CursorMode mode) const
@@ -175,7 +175,7 @@ index 4879ae5..56cdcba 100644
inline void resetRightBearing()
diff --git a/src/gui/text/qtextlayout.h b/src/gui/text/qtextlayout.h
index cbe42c3..b273db7 100644
index cbe42c3844..b273db7e78 100644
--- a/src/gui/text/qtextlayout.h
+++ b/src/gui/text/qtextlayout.h
@@ -194,6 +194,9 @@ private:
@@ -189,7 +189,7 @@ index cbe42c3..b273db7 100644
diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm
index ca7afb7..25ae500 100644
index ca7afb7d1b..25ae50008d 100644
--- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm
+++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm
@@ -256,6 +256,13 @@ static void getFontDescription(CTFontDescriptorRef font, FontDescription *fd)
@@ -207,7 +207,7 @@ index ca7afb7..25ae500 100644
fd->weight = QFont::Normal;
fd->style = QFont::StyleNormal;
diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
index 92358ec..694fee7 100644
index 92358ecc74..694fee7350 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
+++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
@@ -213,7 +213,8 @@ static void cleanupCocoaApplicationDelegate()
@@ -244,7 +244,7 @@ index 92358ec..694fee7 100644
- (void)appleEventQuit:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
diff --git a/src/plugins/platforms/cocoa/qcocoacursor.mm b/src/plugins/platforms/cocoa/qcocoacursor.mm
index b81b9a0..4e59e83 100644
index b81b9a0b1c..4e59e833b1 100644
--- a/src/plugins/platforms/cocoa/qcocoacursor.mm
+++ b/src/plugins/platforms/cocoa/qcocoacursor.mm
@@ -81,7 +81,7 @@ void QCocoaCursor::setPos(const QPoint &position)
@@ -256,8 +256,41 @@ index b81b9a0..4e59e83 100644
CGEventPost(kCGHIDEventTap, e);
CFRelease(e);
}
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm
index 9850f83dea..218ed7e81c 100644
--- a/src/plugins/platforms/cocoa/qcocoahelpers.mm
+++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm
@@ -649,9 +649,10 @@ OSStatus qt_mac_drawCGImage(CGContextRef inContext, const CGRect *inBounds, CGIm
// Verbatim copy if HIViewDrawCGImage (as shown on Carbon-Dev)
OSStatus err = noErr;
- require_action(inContext != NULL, InvalidContext, err = paramErr);
- require_action(inBounds != NULL, InvalidBounds, err = paramErr);
- require_action(inImage != NULL, InvalidImage, err = paramErr);
+ // Patch: Fix build on latest Xcode.
+ //require_action(inContext != NULL, InvalidContext, err = paramErr);
+ //require_action(inBounds != NULL, InvalidBounds, err = paramErr);
+ //require_action(inImage != NULL, InvalidImage, err = paramErr);
CGContextSaveGState( inContext );
CGContextTranslateCTM (inContext, 0, inBounds->origin.y + CGRectGetMaxY(*inBounds));
@@ -660,9 +661,11 @@ OSStatus qt_mac_drawCGImage(CGContextRef inContext, const CGRect *inBounds, CGIm
CGContextDrawImage(inContext, *inBounds, inImage);
CGContextRestoreGState(inContext);
-InvalidImage:
-InvalidBounds:
-InvalidContext:
+
+// Patch: Fix build on latest Xcode.
+//InvalidImage:
+//InvalidBounds:
+//InvalidContext:
return err;
}
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm
index 9fd05a6..dea6072 100644
index 9fd05a65ee..dea60720e7 100644
--- a/src/plugins/platforms/cocoa/qcocoaintegration.mm
+++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm
@@ -402,14 +402,24 @@ void QCocoaIntegration::updateScreens()
@@ -288,7 +321,7 @@ index 9fd05a6..dea6072 100644
QCocoaScreen *QCocoaIntegration::screenAtIndex(int index)
diff --git a/src/plugins/platforms/cocoa/qcocoakeymapper.mm b/src/plugins/platforms/cocoa/qcocoakeymapper.mm
index e46eaff..c62db53 100644
index e46eaff6be..c62db534a2 100644
--- a/src/plugins/platforms/cocoa/qcocoakeymapper.mm
+++ b/src/plugins/platforms/cocoa/qcocoakeymapper.mm
@@ -382,6 +382,12 @@ bool QCocoaKeyMapper::updateKeyboard()
@@ -315,7 +348,7 @@ index e46eaff..c62db53 100644
}
return ret;
diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
index 83c960d..03ae969 100755
index 83c960d931..03ae9696af 100755
--- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
+++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
@@ -102,7 +102,10 @@ QT_USE_NAMESPACE
@@ -483,7 +516,7 @@ index 83c960d..03ae969 100755
}
@end
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
index 4d0458a..3357a5e 100644
index 4d0458a4aa..3357a5ef81 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -167,7 +167,8 @@ static bool isMouseEvent(NSEvent *ev)
@@ -546,7 +579,7 @@ index 4d0458a..3357a5e 100644
[iconButton setImage:image];
[image release];
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm
index a18ee7f..1f91feb 100644
index a18ee7ff71..1f91feb0ae 100644
--- a/src/plugins/platforms/cocoa/qnsview.mm
+++ b/src/plugins/platforms/cocoa/qnsview.mm
@@ -393,7 +393,9 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
@@ -615,7 +648,7 @@ index a18ee7f..1f91feb 100644
}
return [super performKeyEquivalent:nsevent];
diff --git a/src/tools/qlalr/lalr.cpp b/src/tools/qlalr/lalr.cpp
index c680764..e2a7aaf 100644
index c68076477f..e2a7aafa58 100644
--- a/src/tools/qlalr/lalr.cpp
+++ b/src/tools/qlalr/lalr.cpp
@@ -246,11 +246,13 @@ void Grammar::buildExtendedGrammar ()
@@ -655,7 +688,7 @@ index c680764..e2a7aaf 100644
continue;
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp
index 7396808..7178aec 100644
index 7396808442..7178aecf80 100644
--- a/src/widgets/kernel/qwidget.cpp
+++ b/src/widgets/kernel/qwidget.cpp
@@ -4722,6 +4722,17 @@ void QWidget::render(QPainter *painter, const QPoint &targetOffset,
@@ -708,7 +741,7 @@ index 7396808..7178aec 100644
|| (k->key() == Qt::Key_Tab && (k->modifiers() & Qt::ShiftModifier)))
res = focusNextPrevChild(false);
diff --git a/src/widgets/styles/qmacstyle_mac.mm b/src/widgets/styles/qmacstyle_mac.mm
index 0845a5e..5735cb6 100644
index 0845a5eb02..5735cb6b39 100644
--- a/src/widgets/styles/qmacstyle_mac.mm
+++ b/src/widgets/styles/qmacstyle_mac.mm
@@ -3667,9 +3667,11 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
@@ -726,7 +759,7 @@ index 0845a5e..5735cb6 100644
}
diff --git a/src/widgets/util/qsystemtrayicon_qpa.cpp b/src/widgets/util/qsystemtrayicon_qpa.cpp
index f98aeaf..00c0734 100644
index f98aeaf678..00c0734129 100644
--- a/src/widgets/util/qsystemtrayicon_qpa.cpp
+++ b/src/widgets/util/qsystemtrayicon_qpa.cpp
@@ -99,13 +99,18 @@ void QSystemTrayIconPrivate::updateIcon_sys()
@@ -755,7 +788,7 @@ index f98aeaf..00c0734 100644
}
diff --git a/src/widgets/widgets/qwidgetlinecontrol.cpp b/src/widgets/widgets/qwidgetlinecontrol.cpp
index 75f3059..980f2be 100644
index 75f30599be..980f2be1e9 100644
--- a/src/widgets/widgets/qwidgetlinecontrol.cpp
+++ b/src/widgets/widgets/qwidgetlinecontrol.cpp
@@ -1867,7 +1867,8 @@ void QWidgetLineControl::processKeyEvent(QKeyEvent* event)
@@ -769,7 +802,7 @@ index 75f3059..980f2be 100644
#ifndef QT_NO_COMPLETER
complete(event->key());
diff --git a/src/widgets/widgets/qwidgettextcontrol.cpp b/src/widgets/widgets/qwidgettextcontrol.cpp
index 96438a0..b0b7206 100644
index 96438a0bdf..b0b7206405 100644
--- a/src/widgets/widgets/qwidgettextcontrol.cpp
+++ b/src/widgets/widgets/qwidgettextcontrol.cpp
@@ -1342,7 +1342,8 @@ void QWidgetTextControlPrivate::keyPressEvent(QKeyEvent *e)

Binary file not shown.

After

Width:  |  Height:  |  Size: 369 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 655 B

View File

@@ -296,6 +296,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_settings_section_chat_settings" = "Chat Settings";
"lng_settings_replace_emojis" = "Replace emoji";
"lng_settings_suggest_by_emoji" = "Suggest popular stickers by emoji";
"lng_settings_view_emojis" = "View list";
"lng_settings_send_enter" = "Send by Enter";
"lng_settings_send_ctrlenter" = "Send by Ctrl+Enter";
@@ -417,8 +418,28 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_connection_port_ph" = "Port";
"lng_connection_user_ph" = "Username";
"lng_connection_password_ph" = "Password";
"lng_connection_proxy_secret_ph" = "Secret";
"lng_connection_save" = "Save";
"lng_proxy_settings" = "Proxy settings";
"lng_proxy_use" = "Use proxy";
"lng_proxy_add" = "Add proxy";
"lng_proxy_share" = "Share";
"lng_proxy_online" = "online";
"lng_proxy_checking" = "checking";
"lng_proxy_connecting" = "connecting";
"lng_proxy_available" = "available (ping: {ping}ms)";
"lng_proxy_unavailable" = "not available";
"lng_proxy_edit" = "Edit proxy";
"lng_proxy_menu_edit" = "Edit";
"lng_proxy_menu_delete" = "Delete";
"lng_proxy_menu_restore" = "Restore";
"lng_proxy_edit_share" = "Share";
"lng_proxy_address_label" = "Socket address";
"lng_proxy_credentials_optional" = "Credentials (optional)";
"lng_proxy_credentials" = "Credentials";
"lng_proxy_description" = "Your saved proxy list will be here.";
"lng_settings_blocked_users" = "Blocked users";
"lng_settings_last_seen_privacy" = "Last seen privacy";
"lng_settings_calls_privacy" = "Phone calls privacy";
@@ -819,6 +840,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_channel_not_accessible" = "Sorry, this channel is not accessible.";
"lng_group_not_accessible" = "Sorry, this group is not accessible.";
"lng_group_full" = "Sorry, this group is full.";
"lng_channels_too_much_public_about" = "Sorry, you have reserved too many public usernames. You can revoke the link from one of your older groups or channels.";
"lng_channels_too_much_public_revoke_confirm_group" = "Are you sure you want to revoke the link {link}?\n\nThe group «{group}» will become private.";

View File

@@ -107,8 +107,13 @@ new_session_created#9ec20908 first_msg_id:long unique_id:long server_salt:long =
http_wait#9299359f max_delay:int wait_after:int max_wait:int = HttpWait;
ipPort ipv4:int port:int = IpPort;
help.configSimple#d997c3c5 date:int expires:int dc_id:int ip_port_list:Vector<ipPort> = help.ConfigSimple;
//ipPort ipv4:int port:int = IpPort;
//help.configSimple#d997c3c5 date:int expires:int dc_id:int ip_port_list:Vector<ipPort> = help.ConfigSimple;
ipPort#d433ad73 ipv4:int port:int = IpPort;
ipPortSecret#37982646 ipv4:int port:int secret:bytes = IpPort;
accessPointRule#4679b65f phone_prefix_rules:string dc_id:int ips:vector<IpPort> = AccessPointRule;
help.configSimple#5a592a6c date:int expires:int rules:vector<AccessPointRule> = help.ConfigSimple;
---functions---
@@ -220,7 +225,7 @@ userStatusLastMonth#77ebc742 = UserStatus;
chatEmpty#9ba2d800 id:int = Chat;
chat#d91cdd54 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true admins_enabled:flags.3?true admin:flags.4?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel = Chat;
chatForbidden#7328bdb id:int title:string = Chat;
channel#450b7115 flags:# creator:flags.0?true left:flags.2?true editor:flags.3?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true democracy:flags.10?true signatures:flags.11?true min:flags.12?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string admin_rights:flags.14?ChannelAdminRights banned_rights:flags.15?ChannelBannedRights participants_count:flags.17?int = Chat;
channel#c88974ac flags:# creator:flags.0?true left:flags.2?true editor:flags.3?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true democracy:flags.10?true signatures:flags.11?true min:flags.12?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string admin_rights:flags.14?ChannelAdminRights banned_rights:flags.15?ChannelBannedRights participants_count:flags.17?int = Chat;
channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat;
chatFull#2e02a614 id:int participants:ChatParticipants chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> = ChatFull;
@@ -306,7 +311,6 @@ inputPeerNotifySettings#38935eb2 flags:# show_previews:flags.0?true silent:flags
peerNotifyEventsEmpty#add53cb3 = PeerNotifyEvents;
peerNotifyEventsAll#6d1ded88 = PeerNotifyEvents;
peerNotifySettingsEmpty#70a68512 = PeerNotifySettings;
peerNotifySettings#9acda4c0 flags:# show_previews:flags.0?true silent:flags.1?true mute_until:int sound:string = PeerNotifySettings;
peerSettings#818426cd flags:# report_spam:flags.0?true = PeerSettings;
@@ -461,9 +465,9 @@ photos.photo#20212ca8 photo:Photo users:Vector<User> = photos.Photo;
upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File;
upload.fileCdnRedirect#f18cda44 dc_id:int file_token:bytes encryption_key:bytes encryption_iv:bytes file_hashes:Vector<FileHash> = upload.File;
dcOption#5d8c6cc 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 = DcOption;
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#86b5778e 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 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 suggested_lang_code:flags.2?string lang_pack_version:flags.2?int = Config;
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;
nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc;
@@ -1220,4 +1224,4 @@ langpack.getStrings#2e1ee318 lang_code:string keys:Vector<string> = Vector<LangP
langpack.getDifference#b2e4d7d from_version:int = LangPackDifference;
langpack.getLanguages#800fd57d = Vector<LangPackLanguage>;
// LAYER 76
// LAYER 78

View File

@@ -9,7 +9,7 @@
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
ProcessorArchitecture="ARCHITECTURE"
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
Version="1.2.12.0" />
Version="1.2.18.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,2,12,0
PRODUCTVERSION 1,2,12,0
FILEVERSION 1,2,18,0
PRODUCTVERSION 1,2,18,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.2.12.0"
VALUE "FileVersion", "1.2.18.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2018"
VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "1.2.12.0"
VALUE "ProductVersion", "1.2.18.0"
END
END
BLOCK "VarFileInfo"

View File

@@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,2,12,0
PRODUCTVERSION 1,2,12,0
FILEVERSION 1,2,18,0
PRODUCTVERSION 1,2,18,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.2.12.0"
VALUE "FileVersion", "1.2.18.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2018"
VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "1.2.12.0"
VALUE "ProductVersion", "1.2.18.0"
END
END
BLOCK "VarFileInfo"

View File

@@ -908,7 +908,7 @@ void ApiWrap::requestPeers(const QList<PeerData*> &peers) {
channels.push_back((*i)->asChannel()->inputChannel);
}
}
auto handleChats = [this](const MTPmessages_Chats &result) {
auto handleChats = [=](const MTPmessages_Chats &result) {
if (auto chats = Api::getChatsFromMessagesChats(result)) {
App::feedChats(*chats);
}
@@ -920,7 +920,7 @@ void ApiWrap::requestPeers(const QList<PeerData*> &peers) {
request(MTPchannels_GetChannels(MTP_vector<MTPInputChannel>(channels))).done(handleChats).send();
}
if (!users.isEmpty()) {
request(MTPusers_GetUsers(MTP_vector<MTPInputUser>(users))).done([this](const MTPVector<MTPUser> &result) {
request(MTPusers_GetUsers(MTP_vector<MTPInputUser>(users))).done([=](const MTPVector<MTPUser> &result) {
App::feedUsers(result);
}).send();
}
@@ -1509,16 +1509,28 @@ void ApiWrap::stickerSetDisenabled(mtpRequestId requestId) {
}
};
void ApiWrap::joinChannel(ChannelData *channel) {
void ApiWrap::joinChannel(not_null<ChannelData*> channel) {
if (channel->amIn()) {
Notify::peerUpdatedDelayed(channel, Notify::PeerUpdate::Flag::ChannelAmIn);
Notify::peerUpdatedDelayed(
channel,
Notify::PeerUpdate::Flag::ChannelAmIn);
} else if (!_channelAmInRequests.contains(channel)) {
auto requestId = request(MTPchannels_JoinChannel(channel->inputChannel)).done([this, channel](const MTPUpdates &result) {
auto requestId = request(MTPchannels_JoinChannel(
channel->inputChannel
)).done([=](const MTPUpdates &result) {
_channelAmInRequests.remove(channel);
applyUpdates(result);
}).fail([this, channel](const RPCError &error) {
if (error.type() == qstr("CHANNELS_TOO_MUCH")) {
}).fail([=](const RPCError &error) {
if (error.type() == qstr("CHANNEL_PRIVATE")
|| error.type() == qstr("CHANNEL_PUBLIC_GROUP_NA")
|| error.type() == qstr("USER_BANNED_IN_CHANNEL")) {
Ui::show(Box<InformBox>(lang(channel->isMegagroup()
? lng_group_not_accessible
: lng_channel_not_accessible)));
} else if (error.type() == qstr("CHANNELS_TOO_MUCH")) {
Ui::show(Box<InformBox>(lang(lng_join_channel_error)));
} else if (error.type() == qstr("USERS_TOO_MUCH")) {
Ui::show(Box<InformBox>(lang(lng_group_full)));
}
_channelAmInRequests.remove(channel);
}).send();
@@ -1527,14 +1539,18 @@ void ApiWrap::joinChannel(ChannelData *channel) {
}
}
void ApiWrap::leaveChannel(ChannelData *channel) {
void ApiWrap::leaveChannel(not_null<ChannelData*> channel) {
if (!channel->amIn()) {
Notify::peerUpdatedDelayed(channel, Notify::PeerUpdate::Flag::ChannelAmIn);
Notify::peerUpdatedDelayed(
channel,
Notify::PeerUpdate::Flag::ChannelAmIn);
} else if (!_channelAmInRequests.contains(channel)) {
auto requestId = request(MTPchannels_LeaveChannel(channel->inputChannel)).done([this, channel](const MTPUpdates &result) {
auto requestId = request(MTPchannels_LeaveChannel(
channel->inputChannel
)).done([=](const MTPUpdates &result) {
_channelAmInRequests.remove(channel);
applyUpdates(result);
}).fail([this, channel](const RPCError &error) {
}).fail([=](const RPCError &error) {
_channelAmInRequests.remove(channel);
}).send();
@@ -1607,7 +1623,10 @@ void ApiWrap::requestNotifySetting(PeerData *peer) {
notifySettingReceived(notifyPeer, result);
_notifySettingRequests.remove(peer);
}).fail([this, notifyPeer, peer](const RPCError &error) {
notifySettingReceived(notifyPeer, MTP_peerNotifySettingsEmpty());
notifySettingReceived(notifyPeer, MTP_peerNotifySettings(
MTP_flags(MTPDpeerNotifySettings::Flag::f_show_previews),
MTP_int(0),
MTP_string("default")));
_notifySettingRequests.remove(peer);
}).send();
@@ -1686,7 +1705,7 @@ void ApiWrap::handlePrivacyChange(mtpTypeId keyTypeId, const MTPVector<MTPPrivac
}
auto now = unixtime();
App::enumerateUsers([&userRules, contactsRule, everyoneRule, now](UserData *user) {
App::enumerateUsers([&](UserData *user) {
if (user->isSelf() || user->loadedStatus != PeerData::FullLoaded) {
return;
}
@@ -2017,7 +2036,7 @@ void ApiWrap::requestParticipantsCountDelayed(
not_null<ChannelData*> channel) {
_participantsCountRequestTimer.call(
kReloadChannelMembersTimeout,
[this, channel] { channel->updateFullForced(); });
[=] { channel->updateFullForced(); });
}
void ApiWrap::requestChannelRangeDifference(not_null<History*> history) {
@@ -2280,7 +2299,7 @@ void ApiWrap::requestStickers(TimeId now) {
};
_stickersUpdateRequest = request(MTPmessages_GetAllStickers(
MTP_int(Local::countStickersHash(true))
)).done(onDone).fail([this, onDone](const RPCError &error) {
)).done(onDone).fail([=](const RPCError &error) {
LOG(("App Fail: Failed to get stickers!"));
onDone(MTP_messages_allStickersNotModified());
}).send();
@@ -3568,6 +3587,12 @@ void ApiWrap::sendSharedContact(
MTP_string(firstName),
MTP_string(lastName));
sendMedia(item, media, peer->notifySilentPosts());
if (const auto main = App::main()) {
_session->data().sendHistoryChangeNotifications();
main->historyToDown(history);
main->dialogsToUp();
}
}
void ApiWrap::sendVoiceMessage(
@@ -3716,7 +3741,7 @@ void ApiWrap::uploadAlbumMedia(
const MessageGroupId &groupId,
const MTPInputMedia &media) {
const auto localId = item->fullId();
const auto failed = [this] {
const auto failed = [=] {
};
request(MTPmessages_UploadMedia(

View File

@@ -133,8 +133,8 @@ public:
std::vector<not_null<DocumentData*>> *stickersByEmoji(
not_null<EmojiPtr> emoji);
void joinChannel(ChannelData *channel);
void leaveChannel(ChannelData *channel);
void joinChannel(not_null<ChannelData*> channel);
void leaveChannel(not_null<ChannelData*> channel);
void blockUser(UserData *user);
void unblockUser(UserData *user);

View File

@@ -38,6 +38,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "observer_peer.h"
#include "auth_session.h"
#include "core/crash_reports.h"
#include "core/update_checker.h"
#include "storage/storage_facade.h"
#include "storage/storage_shared_media.h"
#include "window/themes/window_theme.h"
@@ -923,6 +924,7 @@ namespace {
: nullptr);
existing->setViewsCount(m.has_views() ? m.vviews.v : -1);
existing->indexAsNewItem();
Auth().data().requestItemTextRefresh(existing);
if (existing->mainView()) {
App::checkSavedGif(existing);
return true;
@@ -1627,6 +1629,7 @@ namespace {
int64 nowImageCacheSize = imageCacheSize();
if (nowImageCacheSize > serviceImageCacheSize + MemoryForImageCache) {
App::forgetMedia();
Auth().data().forgetMedia();
serviceImageCacheSize = imageCacheSize();
}
}
@@ -1665,7 +1668,7 @@ namespace {
void restart() {
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
bool updateReady = (Sandbox::updatingState() == Application::UpdatingReady);
bool updateReady = (Core::UpdateChecker().state() == Core::UpdateChecker::State::Ready);
#else // !TDESKTOP_DISABLE_AUTOUPDATE
bool updateReady = false;
#endif // else for !TDESKTOP_DISABLE_AUTOUPDATE
@@ -1780,38 +1783,6 @@ namespace {
if (changeInMin) App::main()->updateMutedIn(changeInMin);
}
void setProxySettings(QNetworkAccessManager &manager) {
#ifndef TDESKTOP_DISABLE_NETWORK_PROXY
manager.setProxy(getHttpProxySettings());
#endif // !TDESKTOP_DISABLE_NETWORK_PROXY
}
#ifndef TDESKTOP_DISABLE_NETWORK_PROXY
QNetworkProxy getHttpProxySettings() {
const ProxyData *proxy = nullptr;
if (Global::started()) {
proxy = (Global::ConnectionType() == dbictHttpProxy) ? (&Global::ConnectionProxy()) : nullptr;
} else {
proxy = Sandbox::PreLaunchProxy().host.isEmpty() ? nullptr : (&Sandbox::PreLaunchProxy());
}
if (proxy) {
return QNetworkProxy(QNetworkProxy::HttpProxy, proxy->host, proxy->port, proxy->user, proxy->password);
}
return QNetworkProxy(QNetworkProxy::DefaultProxy);
}
#endif // !TDESKTOP_DISABLE_NETWORK_PROXY
void setProxySettings(QTcpSocket &socket) {
#ifndef TDESKTOP_DISABLE_NETWORK_PROXY
if (Global::ConnectionType() == dbictTcpProxy) {
auto &p = Global::ConnectionProxy();
socket.setProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, p.host, p.port, p.user, p.password));
} else {
socket.setProxy(QNetworkProxy(QNetworkProxy::NoProxy));
}
#endif // !TDESKTOP_DISABLE_NETWORK_PROXY
}
void rectWithCorners(Painter &p, QRect rect, const style::color &bg, RoundCorners index, RectParts corners) {
auto parts = RectPart::Top
| RectPart::NoTopBottom

View File

@@ -225,12 +225,6 @@ namespace App {
void unregMuted(not_null<PeerData*> peer);
void updateMuted();
void setProxySettings(QNetworkAccessManager &manager);
#ifndef TDESKTOP_DISABLE_NETWORK_PROXY
QNetworkProxy getHttpProxySettings();
#endif // !TDESKTOP_DISABLE_NETWORK_PROXY
void setProxySettings(QTcpSocket &socket);
void complexOverlayRect(Painter &p, QRect rect, ImageRoundRadius radius, RectParts corners);
void complexLocationRect(Painter &p, QRect rect, ImageRoundRadius radius, RectParts corners);

View File

@@ -11,11 +11,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mainwidget.h"
#include "mainwindow.h"
#include "storage/localstorage.h"
#include "autoupdater.h"
#include "window/notifications_manager.h"
#include "core/crash_reports.h"
#include "messenger.h"
#include "base/timer.h"
#include "core/update_checker.h"
#include "core/crash_report_window.h"
namespace {
@@ -65,7 +65,11 @@ Application::Application(
int &argc,
char **argv)
: QApplication(argc, argv)
, _launcher(launcher) {
, _launcher(launcher)
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
, _updateChecker(std::make_unique<Core::UpdateChecker>())
#endif // TDESKTOP_DISABLE_AUTOUPDATE
{
const auto d = QFile::encodeName(QDir(cWorkingDir()).absolutePath());
char h[33] = { 0 };
hashMd5Hex(d.constData(), d.size(), h);
@@ -86,13 +90,6 @@ Application::Application(
QTimer::singleShot(0, this, SLOT(startApplication()));
connect(this, SIGNAL(aboutToQuit()), this, SLOT(closeApplication()));
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
_updateCheckTimer.create(this);
connect(_updateCheckTimer, SIGNAL(timeout()), this, SLOT(updateCheck()));
connect(this, SIGNAL(updateFailed()), this, SLOT(onUpdateFailed()));
connect(this, SIGNAL(updateReady()), this, SLOT(onUpdateReady()));
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
if (cManyInstance()) {
LOG(("Many instance allowed, starting..."));
singleInstanceChecked();
@@ -180,7 +177,7 @@ void Application::socketError(QLocalSocket::LocalSocketError e) {
#endif // !Q_OS_WINRT
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
if (!cNoStartUpdate() && checkReadyUpdate()) {
if (!cNoStartUpdate() && Core::checkReadyUpdate()) {
cSetRestartingUpdate(true);
DEBUG_LOG(("Application Info: installing update instead of starting app..."));
return App::quit();
@@ -196,6 +193,7 @@ void Application::singleInstanceChecked() {
}
Sandbox::start();
refreshGlobalProxy();
if (!Logs::started() || (!cManyInstance() && !Logs::instanceChecked())) {
new NotStartedWindow();
@@ -307,9 +305,29 @@ void Application::startApplication() {
void Application::createMessenger() {
Expects(!App::quitting());
_messengerInstance = std::make_unique<Messenger>(_launcher);
}
void Application::refreshGlobalProxy() {
#ifndef TDESKTOP_DISABLE_NETWORK_PROXY
const auto proxy = [&] {
if (Global::started()) {
return Global::UseProxy()
? Global::SelectedProxy()
: ProxyData();
}
return Sandbox::PreLaunchProxy();
}();
if (proxy.type == ProxyData::Type::Socks5
|| proxy.type == ProxyData::Type::Http) {
QNetworkProxy::setApplicationProxy(ToNetworkProxy(proxy));
} else {
QNetworkProxyFactory::setUseSystemConfiguration(true);
}
#endif // TDESKTOP_DISABLE_NETWORK_PROXY
}
void Application::closeApplication() {
if (App::launchState() == App::QuitProcessed) return;
App::setLaunchState(App::QuitProcessed);
@@ -328,169 +346,10 @@ void Application::closeApplication() {
_localSocket.close();
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
delete _updateReply;
_updateReply = 0;
if (_updateChecker) _updateChecker->deleteLater();
_updateChecker = 0;
if (_updateThread) {
_updateThread->quit();
}
_updateThread = 0;
_updateChecker = nullptr;
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
}
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
void Application::updateCheck() {
startUpdateCheck(false);
}
void Application::updateGotCurrent() {
if (!_updateReply || _updateThread) return;
cSetLastUpdateCheck(unixtime());
QRegularExpressionMatch m = QRegularExpression(qsl("^\\s*(\\d+)\\s*:\\s*([\\x21-\\x7f]+)\\s*$")).match(QString::fromLatin1(_updateReply->readAll()));
if (m.hasMatch()) {
uint64 currentVersion = m.captured(1).toULongLong();
QString url = m.captured(2);
bool betaVersion = false;
if (url.startsWith(qstr("beta_"))) {
betaVersion = true;
url = url.mid(5) + '_' + countBetaVersionSignature(currentVersion);
}
if ((!betaVersion || cBetaVersion()) && currentVersion > (betaVersion ? cBetaVersion() : uint64(AppVersion))) {
_updateThread = new QThread();
connect(_updateThread, SIGNAL(finished()), _updateThread, SLOT(deleteLater()));
_updateChecker = new UpdateChecker(_updateThread, url);
_updateThread->start();
}
}
if (_updateReply) _updateReply->deleteLater();
_updateReply = 0;
if (!_updateThread) {
QDir updates(cWorkingDir() + "tupdates");
if (updates.exists()) {
QFileInfoList list = updates.entryInfoList(QDir::Files);
for (QFileInfoList::iterator i = list.begin(), e = list.end(); i != e; ++i) {
if (QRegularExpression("^(tupdate|tmacupd|tmac32upd|tlinuxupd|tlinux32upd)\\d+(_[a-z\\d]+)?$", QRegularExpression::CaseInsensitiveOption).match(i->fileName()).hasMatch()) {
QFile(i->absoluteFilePath()).remove();
}
}
}
emit updateLatest();
}
startUpdateCheck(true);
Local::writeSettings();
}
void Application::updateFailedCurrent(QNetworkReply::NetworkError e) {
LOG(("App Error: could not get current version (update check): %1").arg(e));
if (_updateReply) _updateReply->deleteLater();
_updateReply = 0;
emit updateFailed();
startUpdateCheck(true);
}
void Application::onUpdateReady() {
if (_updateChecker) {
_updateChecker->deleteLater();
_updateChecker = nullptr;
}
_updateCheckTimer->stop();
cSetLastUpdateCheck(unixtime());
Local::writeSettings();
}
void Application::onUpdateFailed() {
if (_updateChecker) {
_updateChecker->deleteLater();
_updateChecker = 0;
if (_updateThread) _updateThread->quit();
_updateThread = 0;
}
cSetLastUpdateCheck(unixtime());
Local::writeSettings();
}
Application::UpdatingState Application::updatingState() {
if (!_updateThread) return Application::UpdatingNone;
if (!_updateChecker) return Application::UpdatingReady;
return Application::UpdatingDownload;
}
int32 Application::updatingSize() {
if (!_updateChecker) return 0;
return _updateChecker->size();
}
int32 Application::updatingReady() {
if (!_updateChecker) return 0;
return _updateChecker->ready();
}
void Application::stopUpdate() {
if (_updateReply) {
_updateReply->abort();
_updateReply->deleteLater();
_updateReply = 0;
}
if (_updateChecker) {
_updateChecker->deleteLater();
_updateChecker = 0;
if (_updateThread) _updateThread->quit();
_updateThread = 0;
}
}
void Application::startUpdateCheck(bool forceWait) {
if (!Sandbox::started()) return;
_updateCheckTimer->stop();
if (_updateThread || _updateReply || !cAutoUpdate() || cExeName().isEmpty()) return;
int32 constDelay = cBetaVersion() ? 600 : UpdateDelayConstPart, randDelay = cBetaVersion() ? 300 : UpdateDelayRandPart;
int32 updateInSecs = cLastUpdateCheck() + constDelay + int32(rand() % randDelay) - unixtime();
bool sendRequest = (updateInSecs <= 0 || updateInSecs > (constDelay + randDelay));
if (!sendRequest && !forceWait) {
QDir updates(cWorkingDir() + "tupdates");
if (updates.exists()) {
QFileInfoList list = updates.entryInfoList(QDir::Files);
for (QFileInfoList::iterator i = list.begin(), e = list.end(); i != e; ++i) {
if (QRegularExpression("^(tupdate|tmacupd|tmac32upd|tlinuxupd|tlinux32upd)\\d+(_[a-z\\d]+)?$", QRegularExpression::CaseInsensitiveOption).match(i->fileName()).hasMatch()) {
sendRequest = true;
}
}
}
}
if (cManyInstance() && !cDebug()) return; // only main instance is updating
if (sendRequest) {
QUrl url(cUpdateURL());
if (cBetaVersion()) {
url.setQuery(qsl("version=%1&beta=%2").arg(AppVersion).arg(cBetaVersion()));
} else if (cAlphaVersion()) {
url.setQuery(qsl("version=%1&alpha=1").arg(AppVersion));
} else {
url.setQuery(qsl("version=%1").arg(AppVersion));
}
QString u = url.toString();
QNetworkRequest checkVersion(url);
if (_updateReply) _updateReply->deleteLater();
App::setProxySettings(_updateManager);
_updateReply = _updateManager.get(checkVersion);
connect(_updateReply, SIGNAL(finished()), this, SLOT(updateGotCurrent()));
connect(_updateReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(updateFailedCurrent(QNetworkReply::NetworkError)));
emit updateChecking();
} else {
_updateCheckTimer->start((updateInSecs + 5) * 1000);
}
}
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
inline Application *application() {
return qobject_cast<Application*>(QApplication::instance());
}
@@ -542,73 +401,6 @@ void adjustSingleTimers() {
base::Timer::Adjust();
}
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
void startUpdateCheck() {
if (auto a = application()) {
return a->startUpdateCheck(false);
}
}
void stopUpdate() {
if (auto a = application()) {
return a->stopUpdate();
}
}
Application::UpdatingState updatingState() {
if (auto a = application()) {
return a->updatingState();
}
return Application::UpdatingNone;
}
int32 updatingSize() {
if (auto a = application()) {
return a->updatingSize();
}
return 0;
}
int32 updatingReady() {
if (auto a = application()) {
return a->updatingReady();
}
return 0;
}
void updateChecking() {
if (auto a = application()) {
emit a->updateChecking();
}
}
void updateLatest() {
if (auto a = application()) {
emit a->updateLatest();
}
}
void updateProgress(qint64 ready, qint64 total) {
if (auto a = application()) {
emit a->updateProgress(ready, total);
}
}
void updateFailed() {
if (auto a = application()) {
emit a->updateFailed();
}
}
void updateReady() {
if (auto a = application()) {
emit a->updateReady();
}
}
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
void connect(const char *signal, QObject *object, const char *method) {
if (auto a = application()) {
a->connect(a, signal, object, method);
@@ -648,4 +440,10 @@ void launch() {
application()->createMessenger();
}
void refreshGlobalProxy() {
if (const auto instance = application()) {
instance->refreshGlobalProxy();
}
}
} // namespace Sandbox

View File

@@ -7,10 +7,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
class UpdateChecker;
namespace Core {
class Launcher;
class UpdateChecker;
} // namespace Core
class Application : public QApplication {
@@ -22,6 +21,7 @@ public:
bool event(QEvent *e) override;
void createMessenger();
void refreshGlobalProxy();
~Application();
@@ -58,46 +58,11 @@ private:
void singleInstanceChecked();
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
// Autoupdating
public:
void startUpdateCheck(bool forceWait);
void stopUpdate();
enum UpdatingState {
UpdatingNone,
UpdatingDownload,
UpdatingReady,
};
UpdatingState updatingState();
int32 updatingSize();
int32 updatingReady();
signals:
void updateChecking();
void updateLatest();
void updateProgress(qint64 ready, qint64 total);
void updateReady();
void updateFailed();
public slots:
void updateCheck();
void updateGotCurrent();
void updateFailedCurrent(QNetworkReply::NetworkError e);
void onUpdateReady();
void onUpdateFailed();
private:
object_ptr<SingleTimer> _updateCheckTimer = { nullptr };
QNetworkReply *_updateReply = nullptr;
QNetworkAccessManager _updateManager;
QThread *_updateThread = nullptr;
UpdateChecker *_updateChecker = nullptr;
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
std::unique_ptr<Core::UpdateChecker> _updateChecker;
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
};
namespace Sandbox {
@@ -111,22 +76,7 @@ void execExternal(const QString &cmd);
void adjustSingleTimers();
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
void startUpdateCheck();
void stopUpdate();
Application::UpdatingState updatingState();
int32 updatingSize();
int32 updatingReady();
void updateChecking();
void updateLatest();
void updateProgress(qint64 ready, qint64 total);
void updateFailed();
void updateReady();
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
void refreshGlobalProxy();
void connect(const char *signal, QObject *object, const char *method);

View File

@@ -278,10 +278,10 @@ AuthSession::AuthSession(UserId userId)
, _changelogs(Core::Changelogs::Create(this)) {
Expects(_userId != 0);
_saveDataTimer.setCallback([this] {
_saveDataTimer.setCallback([=] {
Local::writeUserSettings();
});
subscribe(Messenger::Instance().passcodedChanged(), [this] {
subscribe(Messenger::Instance().passcodedChanged(), [=] {
_shouldLockAt = 0;
notifications().updateAll();
});

View File

@@ -1,614 +0,0 @@
/*
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 "autoupdater.h"
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#ifdef Q_OS_WIN // use Lzma SDK for win
#include <LzmaLib.h>
#else // Q_OS_WIN
#include <lzma.h>
#endif // else of Q_OS_WIN
#include "application.h"
#include "platform/platform_specific.h"
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
#ifdef Q_OS_WIN
typedef DWORD VerInt;
typedef WCHAR VerChar;
#else // Q_OS_WIN
typedef int VerInt;
typedef wchar_t VerChar;
#endif // Q_OS_WIN
UpdateChecker::UpdateChecker(QThread *thread, const QString &url) : reply(0), already(0), full(0) {
updateUrl = url;
moveToThread(thread);
manager.moveToThread(thread);
App::setProxySettings(manager);
connect(thread, SIGNAL(started()), this, SLOT(start()));
initOutput();
}
void UpdateChecker::initOutput() {
QString fileName;
QRegularExpressionMatch m = QRegularExpression(qsl("/([^/\\?]+)(\\?|$)")).match(updateUrl);
if (m.hasMatch()) {
fileName = m.captured(1).replace(QRegularExpression(qsl("[^a-zA-Z0-9_\\-]")), QString());
}
if (fileName.isEmpty()) {
fileName = qsl("tupdate-%1").arg(rand_value<uint32>() % 1000000);
}
QString dirStr = cWorkingDir() + qsl("tupdates/");
fileName = dirStr + fileName;
QFileInfo file(fileName);
QDir dir(dirStr);
if (dir.exists()) {
QFileInfoList all = dir.entryInfoList(QDir::Files);
for (QFileInfoList::iterator i = all.begin(), e = all.end(); i != e; ++i) {
if (i->absoluteFilePath() != file.absoluteFilePath()) {
QFile::remove(i->absoluteFilePath());
}
}
} else {
dir.mkdir(dir.absolutePath());
}
outputFile.setFileName(fileName);
if (file.exists()) {
uint64 fullSize = file.size();
if (fullSize < INT_MAX) {
int32 goodSize = (int32)fullSize;
if (goodSize % UpdateChunk) {
goodSize = goodSize - (goodSize % UpdateChunk);
if (goodSize) {
if (outputFile.open(QIODevice::ReadOnly)) {
QByteArray goodData = outputFile.readAll().mid(0, goodSize);
outputFile.close();
if (outputFile.open(QIODevice::WriteOnly)) {
outputFile.write(goodData);
outputFile.close();
QMutexLocker lock(&mutex);
already = goodSize;
}
}
}
} else {
QMutexLocker lock(&mutex);
already = goodSize;
}
}
if (!already) {
QFile::remove(fileName);
}
}
}
void UpdateChecker::start() {
sendRequest();
}
void UpdateChecker::sendRequest() {
QNetworkRequest req(updateUrl);
QByteArray rangeHeaderValue = "bytes=" + QByteArray::number(already) + "-";
req.setRawHeader("Range", rangeHeaderValue);
req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
if (reply) reply->deleteLater();
reply = manager.get(req);
connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(partFinished(qint64,qint64)));
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(partFailed(QNetworkReply::NetworkError)));
connect(reply, SIGNAL(metaDataChanged()), this, SLOT(partMetaGot()));
}
void UpdateChecker::partMetaGot() {
typedef QList<QNetworkReply::RawHeaderPair> Pairs;
Pairs pairs = reply->rawHeaderPairs();
for (Pairs::iterator i = pairs.begin(), e = pairs.end(); i != e; ++i) {
if (QString::fromUtf8(i->first).toLower() == "content-range") {
QRegularExpressionMatch m = QRegularExpression(qsl("/(\\d+)([^\\d]|$)")).match(QString::fromUtf8(i->second));
if (m.hasMatch()) {
{
QMutexLocker lock(&mutex);
full = m.captured(1).toInt();
}
Sandbox::updateProgress(already, full);
}
}
}
}
int32 UpdateChecker::ready() {
QMutexLocker lock(&mutex);
return already;
}
int32 UpdateChecker::size() {
QMutexLocker lock(&mutex);
return full;
}
void UpdateChecker::partFinished(qint64 got, qint64 total) {
if (!reply) return;
QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
if (statusCode.isValid()) {
int status = statusCode.toInt();
if (status != 200 && status != 206 && status != 416) {
LOG(("Update Error: Bad HTTP status received in partFinished(): %1").arg(status));
return fatalFail();
}
}
if (!already && !full) {
QMutexLocker lock(&mutex);
full = total;
}
DEBUG_LOG(("Update Info: part %1 of %2").arg(got).arg(total));
if (!outputFile.isOpen()) {
if (!outputFile.open(QIODevice::Append)) {
LOG(("Update Error: Could not open output file '%1' for appending").arg(outputFile.fileName()));
return fatalFail();
}
}
QByteArray r = reply->readAll();
if (!r.isEmpty()) {
outputFile.write(r);
QMutexLocker lock(&mutex);
already += r.size();
}
if (got >= total) {
reply->deleteLater();
reply = 0;
outputFile.close();
unpackUpdate();
} else {
Sandbox::updateProgress(already, full);
}
}
void UpdateChecker::partFailed(QNetworkReply::NetworkError e) {
if (!reply) return;
QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
reply->deleteLater();
reply = 0;
if (statusCode.isValid()) {
int status = statusCode.toInt();
if (status == 416) { // Requested range not satisfiable
outputFile.close();
unpackUpdate();
return;
}
}
LOG(("Update Error: failed to download part starting from %1, error %2").arg(already).arg(e));
Sandbox::updateFailed();
}
void UpdateChecker::fatalFail() {
clearAll();
Sandbox::updateFailed();
}
void UpdateChecker::clearAll() {
psDeleteDir(cWorkingDir() + qsl("tupdates"));
}
//QString winapiErrorWrap() {
// WCHAR errMsg[2048];
// DWORD errorCode = GetLastError();
// LPTSTR errorText = NULL, errorTextDefault = L"(Unknown error)";
// FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&errorText, 0, 0);
// if (!errorText) {
// errorText = errorTextDefault;
// }
// StringCbPrintf(errMsg, sizeof(errMsg), L"Error code: %d, error message: %s", errorCode, errorText);
// if (errorText != errorTextDefault) {
// LocalFree(errorText);
// }
// return QString::fromWCharArray(errMsg);
//}
void UpdateChecker::unpackUpdate() {
QByteArray packed;
if (!outputFile.open(QIODevice::ReadOnly)) {
LOG(("Update Error: cant read updates file!"));
return fatalFail();
}
#ifdef Q_OS_WIN // use Lzma SDK for win
const int32 hSigLen = 128, hShaLen = 20, hPropsLen = LZMA_PROPS_SIZE, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hPropsLen + hOriginalSizeLen; // header
#else // Q_OS_WIN
const int32 hSigLen = 128, hShaLen = 20, hPropsLen = 0, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hOriginalSizeLen; // header
#endif // Q_OS_WIN
QByteArray compressed = outputFile.readAll();
int32 compressedLen = compressed.size() - hSize;
if (compressedLen <= 0) {
LOG(("Update Error: bad compressed size: %1").arg(compressed.size()));
return fatalFail();
}
outputFile.close();
QString tempDirPath = cWorkingDir() + qsl("tupdates/temp"), readyFilePath = cWorkingDir() + qsl("tupdates/temp/ready");
psDeleteDir(tempDirPath);
QDir tempDir(tempDirPath);
if (tempDir.exists() || QFile(readyFilePath).exists()) {
LOG(("Update Error: cant clear tupdates/temp dir!"));
return fatalFail();
}
uchar sha1Buffer[20];
bool goodSha1 = !memcmp(compressed.constData() + hSigLen, hashSha1(compressed.constData() + hSigLen + hShaLen, compressedLen + hPropsLen + hOriginalSizeLen, sha1Buffer), hShaLen);
if (!goodSha1) {
LOG(("Update Error: bad SHA1 hash of update file!"));
return fatalFail();
}
RSA *pbKey = PEM_read_bio_RSAPublicKey(BIO_new_mem_buf(const_cast<char*>(AppAlphaVersion ? UpdatesPublicAlphaKey : UpdatesPublicKey), -1), 0, 0, 0);
if (!pbKey) {
LOG(("Update Error: cant read public rsa key!"));
return fatalFail();
}
if (RSA_verify(NID_sha1, (const uchar*)(compressed.constData() + hSigLen), hShaLen, (const uchar*)(compressed.constData()), hSigLen, pbKey) != 1) { // verify signature
RSA_free(pbKey);
if (cAlphaVersion() || cBetaVersion()) { // try other public key, if we are in alpha or beta version
pbKey = PEM_read_bio_RSAPublicKey(BIO_new_mem_buf(const_cast<char*>(AppAlphaVersion ? UpdatesPublicKey : UpdatesPublicAlphaKey), -1), 0, 0, 0);
if (!pbKey) {
LOG(("Update Error: cant read public rsa key!"));
return fatalFail();
}
if (RSA_verify(NID_sha1, (const uchar*)(compressed.constData() + hSigLen), hShaLen, (const uchar*)(compressed.constData()), hSigLen, pbKey) != 1) { // verify signature
RSA_free(pbKey);
LOG(("Update Error: bad RSA signature of update file!"));
return fatalFail();
}
} else {
LOG(("Update Error: bad RSA signature of update file!"));
return fatalFail();
}
}
RSA_free(pbKey);
QByteArray uncompressed;
int32 uncompressedLen;
memcpy(&uncompressedLen, compressed.constData() + hSigLen + hShaLen + hPropsLen, hOriginalSizeLen);
uncompressed.resize(uncompressedLen);
size_t resultLen = uncompressed.size();
#ifdef Q_OS_WIN // use Lzma SDK for win
SizeT srcLen = compressedLen;
int uncompressRes = LzmaUncompress((uchar*)uncompressed.data(), &resultLen, (const uchar*)(compressed.constData() + hSize), &srcLen, (const uchar*)(compressed.constData() + hSigLen + hShaLen), LZMA_PROPS_SIZE);
if (uncompressRes != SZ_OK) {
LOG(("Update Error: could not uncompress lzma, code: %1").arg(uncompressRes));
return fatalFail();
}
#else // Q_OS_WIN
lzma_stream stream = LZMA_STREAM_INIT;
lzma_ret ret = lzma_stream_decoder(&stream, UINT64_MAX, LZMA_CONCATENATED);
if (ret != LZMA_OK) {
const char *msg;
switch (ret) {
case LZMA_MEM_ERROR: msg = "Memory allocation failed"; break;
case LZMA_OPTIONS_ERROR: msg = "Specified preset is not supported"; break;
case LZMA_UNSUPPORTED_CHECK: msg = "Specified integrity check is not supported"; break;
default: msg = "Unknown error, possibly a bug"; break;
}
LOG(("Error initializing the decoder: %1 (error code %2)").arg(msg).arg(ret));
return fatalFail();
}
stream.avail_in = compressedLen;
stream.next_in = (uint8_t*)(compressed.constData() + hSize);
stream.avail_out = resultLen;
stream.next_out = (uint8_t*)uncompressed.data();
lzma_ret res = lzma_code(&stream, LZMA_FINISH);
if (stream.avail_in) {
LOG(("Error in decompression, %1 bytes left in _in of %2 whole.").arg(stream.avail_in).arg(compressedLen));
return fatalFail();
} else if (stream.avail_out) {
LOG(("Error in decompression, %1 bytes free left in _out of %2 whole.").arg(stream.avail_out).arg(resultLen));
return fatalFail();
}
lzma_end(&stream);
if (res != LZMA_OK && res != LZMA_STREAM_END) {
const char *msg;
switch (res) {
case LZMA_MEM_ERROR: msg = "Memory allocation failed"; break;
case LZMA_FORMAT_ERROR: msg = "The input data is not in the .xz format"; break;
case LZMA_OPTIONS_ERROR: msg = "Unsupported compression options"; break;
case LZMA_DATA_ERROR: msg = "Compressed file is corrupt"; break;
case LZMA_BUF_ERROR: msg = "Compressed data is truncated or otherwise corrupt"; break;
default: msg = "Unknown error, possibly a bug"; break;
}
LOG(("Error in decompression: %1 (error code %2)").arg(msg).arg(res));
return fatalFail();
}
#endif // Q_OS_WIN
tempDir.mkdir(tempDir.absolutePath());
quint32 version;
{
QDataStream stream(uncompressed);
stream.setVersion(QDataStream::Qt_5_1);
stream >> version;
if (stream.status() != QDataStream::Ok) {
LOG(("Update Error: cant read version from downloaded stream, status: %1").arg(stream.status()));
return fatalFail();
}
quint64 betaVersion = 0;
if (version == 0x7FFFFFFF) { // beta version
stream >> betaVersion;
if (stream.status() != QDataStream::Ok) {
LOG(("Update Error: cant read beta version from downloaded stream, status: %1").arg(stream.status()));
return fatalFail();
}
if (!cBetaVersion() || betaVersion <= cBetaVersion()) {
LOG(("Update Error: downloaded beta version %1 is not greater, than mine %2").arg(betaVersion).arg(cBetaVersion()));
return fatalFail();
}
} else if (int32(version) <= AppVersion) {
LOG(("Update Error: downloaded version %1 is not greater, than mine %2").arg(version).arg(AppVersion));
return fatalFail();
}
quint32 filesCount;
stream >> filesCount;
if (stream.status() != QDataStream::Ok) {
LOG(("Update Error: cant read files count from downloaded stream, status: %1").arg(stream.status()));
return fatalFail();
}
if (!filesCount) {
LOG(("Update Error: update is empty!"));
return fatalFail();
}
for (uint32 i = 0; i < filesCount; ++i) {
QString relativeName;
quint32 fileSize;
QByteArray fileInnerData;
bool executable = false;
stream >> relativeName >> fileSize >> fileInnerData;
#if defined Q_OS_MAC || defined Q_OS_LINUX
stream >> executable;
#endif // Q_OS_MAC || Q_OS_LINUX
if (stream.status() != QDataStream::Ok) {
LOG(("Update Error: cant read file from downloaded stream, status: %1").arg(stream.status()));
return fatalFail();
}
if (fileSize != quint32(fileInnerData.size())) {
LOG(("Update Error: bad file size %1 not matching data size %2").arg(fileSize).arg(fileInnerData.size()));
return fatalFail();
}
QFile f(tempDirPath + '/' + relativeName);
if (!QDir().mkpath(QFileInfo(f).absolutePath())) {
LOG(("Update Error: cant mkpath for file '%1'").arg(tempDirPath + '/' + relativeName));
return fatalFail();
}
if (!f.open(QIODevice::WriteOnly)) {
LOG(("Update Error: cant open file '%1' for writing").arg(tempDirPath + '/' + relativeName));
return fatalFail();
}
auto writtenBytes = f.write(fileInnerData);
if (writtenBytes != fileSize) {
f.close();
LOG(("Update Error: cant write file '%1', desiredSize: %2, write result: %3").arg(tempDirPath + '/' + relativeName).arg(fileSize).arg(writtenBytes));
return fatalFail();
}
f.close();
if (executable) {
QFileDevice::Permissions p = f.permissions();
p |= QFileDevice::ExeOwner | QFileDevice::ExeUser | QFileDevice::ExeGroup | QFileDevice::ExeOther;
f.setPermissions(p);
}
}
// create tdata/version file
tempDir.mkdir(QDir(tempDirPath + qsl("/tdata")).absolutePath());
std::wstring versionString = ((version % 1000) ? QString("%1.%2.%3").arg(int(version / 1000000)).arg(int((version % 1000000) / 1000)).arg(int(version % 1000)) : QString("%1.%2").arg(int(version / 1000000)).arg(int((version % 1000000) / 1000))).toStdWString();
VerInt versionNum = VerInt(version), versionLen = VerInt(versionString.size() * sizeof(VerChar));
VerChar versionStr[32];
memcpy(versionStr, versionString.c_str(), versionLen);
QFile fVersion(tempDirPath + qsl("/tdata/version"));
if (!fVersion.open(QIODevice::WriteOnly)) {
LOG(("Update Error: cant write version file '%1'").arg(tempDirPath + qsl("/version")));
return fatalFail();
}
fVersion.write((const char*)&versionNum, sizeof(VerInt));
if (versionNum == 0x7FFFFFFF) { // beta version
fVersion.write((const char*)&betaVersion, sizeof(quint64));
} else {
fVersion.write((const char*)&versionLen, sizeof(VerInt));
fVersion.write((const char*)&versionStr[0], versionLen);
}
fVersion.close();
}
QFile readyFile(readyFilePath);
if (readyFile.open(QIODevice::WriteOnly)) {
if (readyFile.write("1", 1)) {
readyFile.close();
} else {
LOG(("Update Error: cant write ready file '%1'").arg(readyFilePath));
return fatalFail();
}
} else {
LOG(("Update Error: cant create ready file '%1'").arg(readyFilePath));
return fatalFail();
}
outputFile.remove();
Sandbox::updateReady();
}
UpdateChecker::~UpdateChecker() {
delete reply;
reply = 0;
}
bool checkReadyUpdate() {
QString readyFilePath = cWorkingDir() + qsl("tupdates/temp/ready"), readyPath = cWorkingDir() + qsl("tupdates/temp");
if (!QFile(readyFilePath).exists() || cExeName().isEmpty()) {
if (QDir(cWorkingDir() + qsl("tupdates/ready")).exists() || QDir(cWorkingDir() + qsl("tupdates/temp")).exists()) {
UpdateChecker::clearAll();
}
return false;
}
// check ready version
QString versionPath = readyPath + qsl("/tdata/version");
{
QFile fVersion(versionPath);
if (!fVersion.open(QIODevice::ReadOnly)) {
LOG(("Update Error: cant read version file '%1'").arg(versionPath));
UpdateChecker::clearAll();
return false;
}
VerInt versionNum;
if (fVersion.read((char*)&versionNum, sizeof(VerInt)) != sizeof(VerInt)) {
LOG(("Update Error: cant read version from file '%1'").arg(versionPath));
UpdateChecker::clearAll();
return false;
}
if (versionNum == 0x7FFFFFFF) { // beta version
quint64 betaVersion = 0;
if (fVersion.read((char*)&betaVersion, sizeof(quint64)) != sizeof(quint64)) {
LOG(("Update Error: cant read beta version from file '%1'").arg(versionPath));
UpdateChecker::clearAll();
return false;
}
if (!cBetaVersion() || betaVersion <= cBetaVersion()) {
LOG(("Update Error: cant install beta version %1 having beta version %2").arg(betaVersion).arg(cBetaVersion()));
UpdateChecker::clearAll();
return false;
}
} else if (versionNum <= AppVersion) {
LOG(("Update Error: cant install version %1 having version %2").arg(versionNum).arg(AppVersion));
UpdateChecker::clearAll();
return false;
}
fVersion.close();
}
#ifdef Q_OS_WIN
QString curUpdater = (cExeDir() + qsl("Updater.exe"));
QFileInfo updater(cWorkingDir() + qsl("tupdates/temp/Updater.exe"));
#elif defined Q_OS_MAC // Q_OS_WIN
QString curUpdater = (cExeDir() + cExeName() + qsl("/Contents/Frameworks/Updater"));
QFileInfo updater(cWorkingDir() + qsl("tupdates/temp/Telegram.app/Contents/Frameworks/Updater"));
#elif defined Q_OS_LINUX // Q_OS_MAC
QString curUpdater = (cExeDir() + qsl("Updater"));
QFileInfo updater(cWorkingDir() + qsl("tupdates/temp/Updater"));
#endif // Q_OS_LINUX
if (!updater.exists()) {
QFileInfo current(curUpdater);
if (!current.exists()) {
UpdateChecker::clearAll();
return false;
}
if (!QFile(current.absoluteFilePath()).copy(updater.absoluteFilePath())) {
UpdateChecker::clearAll();
return false;
}
}
#ifdef Q_OS_WIN
if (CopyFile(updater.absoluteFilePath().toStdWString().c_str(), curUpdater.toStdWString().c_str(), FALSE) == FALSE) {
DWORD errorCode = GetLastError();
if (errorCode == ERROR_ACCESS_DENIED) { // we are in write-protected dir, like Program Files
cSetWriteProtected(true);
return true;
} else {
UpdateChecker::clearAll();
return false;
}
}
if (DeleteFile(updater.absoluteFilePath().toStdWString().c_str()) == FALSE) {
UpdateChecker::clearAll();
return false;
}
#elif defined Q_OS_MAC // Q_OS_WIN
QDir().mkpath(QFileInfo(curUpdater).absolutePath());
DEBUG_LOG(("Update Info: moving %1 to %2...").arg(updater.absoluteFilePath()).arg(curUpdater));
if (!objc_moveFile(updater.absoluteFilePath(), curUpdater)) {
UpdateChecker::clearAll();
return false;
}
#elif defined Q_OS_LINUX // Q_OS_MAC
if (!linuxMoveFile(QFile::encodeName(updater.absoluteFilePath()).constData(), QFile::encodeName(curUpdater).constData())) {
UpdateChecker::clearAll();
return false;
}
#endif // Q_OS_LINUX
return true;
}
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
QString countBetaVersionSignature(uint64 version) { // duplicated in packer.cpp
if (cBetaPrivateKey().isEmpty()) {
LOG(("Error: Trying to count beta version signature without beta private key!"));
return QString();
}
QByteArray signedData = (qstr("TelegramBeta_") + QString::number(version, 16).toLower()).toUtf8();
static const int32 shaSize = 20, keySize = 128;
uchar sha1Buffer[shaSize];
hashSha1(signedData.constData(), signedData.size(), sha1Buffer); // count sha1
uint32 siglen = 0;
RSA *prKey = PEM_read_bio_RSAPrivateKey(BIO_new_mem_buf(const_cast<char*>(cBetaPrivateKey().constData()), -1), 0, 0, 0);
if (!prKey) {
LOG(("Error: Could not read beta private key!"));
return QString();
}
if (RSA_size(prKey) != keySize) {
LOG(("Error: Bad beta private key size: %1").arg(RSA_size(prKey)));
RSA_free(prKey);
return QString();
}
QByteArray signature;
signature.resize(keySize);
if (RSA_sign(NID_sha1, (const uchar*)(sha1Buffer), shaSize, (uchar*)(signature.data()), &siglen, prKey) != 1) { // count signature
LOG(("Error: Counting beta version signature failed!"));
RSA_free(prKey);
return QString();
}
RSA_free(prKey);
if (siglen != keySize) {
LOG(("Error: Bad beta version signature length: %1").arg(siglen));
return QString();
}
signature = signature.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
signature = signature.replace('-', '8').replace('_', 'B');
return QString::fromUtf8(signature.mid(19, 32));
}

View File

@@ -1,63 +0,0 @@
/*
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
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
#include <QtNetwork/QLocalSocket>
#include <QtNetwork/QLocalServer>
#include <QtNetwork/QNetworkReply>
class UpdateChecker : public QObject {
Q_OBJECT
public:
UpdateChecker(QThread *thread, const QString &url);
void unpackUpdate();
int32 ready();
int32 size();
static void clearAll();
~UpdateChecker();
public slots:
void start();
void partMetaGot();
void partFinished(qint64 got, qint64 total);
void partFailed(QNetworkReply::NetworkError e);
void sendRequest();
private:
void initOutput();
void fatalFail();
QString updateUrl;
QNetworkAccessManager manager;
QNetworkReply *reply;
int32 already, full;
QFile outputFile;
QMutex mutex;
};
bool checkReadyUpdate();
#else // TDESKTOP_DISABLE_AUTOUPDATE
class UpdateChecker : public QObject {
Q_OBJECT
};
#endif // TDESKTOP_DISABLE_AUTOUPDATE
QString countBetaVersionSignature(uint64 version);

View File

@@ -0,0 +1,137 @@
/*
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 <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>;
template <
typename Container,
typename = std::enable_if_t<!std::is_const_v<Container>>>
inline span make_span(Container &container) {
return gsl::as_writeable_bytes(gsl::make_span(container));
}
template <typename Container>
inline const_span make_span(const Container &container) {
return gsl::as_bytes(gsl::make_span(container));
}
template <typename Type, std::ptrdiff_t Extent>
inline span make_span(gsl::span<Type, Extent> container) {
return gsl::as_writeable_bytes(container);
}
template <typename Type, std::ptrdiff_t Extent>
inline const_span make_span(gsl::span<const Type, Extent> container) {
return gsl::as_bytes(container);
}
template <typename Type>
inline span make_span(Type *value, std::size_t count) {
return gsl::as_writeable_bytes(gsl::make_span(value, count));
}
template <typename Type>
inline const_span make_span(const Type *value, std::size_t count) {
return gsl::as_bytes(gsl::make_span(value, count));
}
template <typename Container>
inline vector make_vector(const Container &container) {
const auto buffer = bytes::make_span(container);
return { buffer.begin(), buffer.end() };
}
inline void copy(span destination, const_span source) {
Expects(destination.size() >= source.size());
memcpy(destination.data(), source.data(), source.size());
}
inline void move(span destination, const_span source) {
Expects(destination.size() >= source.size());
memmove(destination.data(), source.data(), source.size());
}
inline void set_with_const(span destination, gsl::byte value) {
memset(
destination.data(),
gsl::to_integer<unsigned char>(value),
destination.size());
}
inline int compare(const_span a, const_span b) {
const auto aSize = a.size(), bSize = b.size();
return (aSize > bSize)
? 1
: (aSize < bSize)
? -1
: memcmp(a.data(), b.data(), aSize);
}
namespace details {
template <typename Arg>
std::size_t spansLength(Arg &&arg) {
return bytes::make_span(arg).size();
}
template <typename Arg, typename ...Args>
std::size_t spansLength(Arg &&arg, Args &&...args) {
return bytes::make_span(arg).size() + spansLength(args...);
}
template <typename Arg>
void spansAppend(span destination, Arg &&arg) {
bytes::copy(destination, bytes::make_span(arg));
}
template <typename Arg, typename ...Args>
void spansAppend(span destination, Arg &&arg, Args &&...args) {
const auto data = bytes::make_span(arg);
bytes::copy(destination, data);
spansAppend(destination.subspan(data.size()), args...);
}
} // namespace details
template <
typename ...Args,
typename = std::enable_if_t<(sizeof...(Args) > 1)>>
vector concatenate(Args &&...args) {
const auto size = details::spansLength(args...);
auto result = vector(size);
details::spansAppend(make_span(result), args...);
return result;
}
template <
typename SpanRange>
vector concatenate(SpanRange args) {
auto size = std::size_t(0);
for (const auto &arg : args) {
size += bytes::make_span(arg).size();
}
auto result = vector(size);
auto buffer = make_span(result);
for (const auto &arg : args) {
const auto part = bytes::make_span(arg);
bytes::copy(buffer, part);
buffer = buffer.subspan(part.size());
}
return result;
}
} // namespace bytes

View File

@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <openssl/bn.h>
#include <openssl/sha.h>
#include <openssl/rand.h>
#include "base/bytes.h"
namespace openssl {
@@ -223,3 +224,13 @@ inline int FillRandom(base::byte_span bytes) {
}
} // namespace openssl
namespace bytes {
inline void set_random(span destination) {
RAND_bytes(
reinterpret_cast<unsigned char*>(destination.data()),
destination.size());
}
} // namespace bytes

View File

@@ -38,4 +38,10 @@ QMap<QString, QString> url_parse_params(
return result;
}
bool is_ipv6(const QString &ip) {
//static const auto regexp = QRegularExpression("^[a-fA-F0-9:]+$");
//return regexp.match(ip).hasMatch();
return ip.indexOf(':') >= 0;
}
} // namespace qthelp

View File

@@ -24,4 +24,6 @@ enum class UrlParamNameTransform {
// Parses a string like "p1=v1&p2=v2&..&pn=vn" to a map.
QMap<QString, QString> url_parse_params(const QString &params, UrlParamNameTransform transform = UrlParamNameTransform::NoTransform);
bool is_ipv6(const QString &ip);
} // namespace qthelp

View File

@@ -17,12 +17,26 @@ QObject *TimersAdjuster() {
} // namespace
Timer::Timer(base::lambda<void()> callback) : QObject(nullptr)
Timer::Timer(
not_null<QThread*> thread,
base::lambda<void()> callback)
: Timer(std::move(callback)) {
moveToThread(thread);
}
Timer::Timer(base::lambda<void()> callback)
: QObject(nullptr)
, _callback(std::move(callback))
, _type(Qt::PreciseTimer)
, _adjusted(false) {
setRepeat(Repeat::Interval);
connect(TimersAdjuster(), &QObject::destroyed, this, [this] { adjust(); }, Qt::QueuedConnection);
connect(
TimersAdjuster(),
&QObject::destroyed,
this,
[this] { adjust(); },
Qt::QueuedConnection);
}
void Timer::start(TimeMs timeout, Qt::TimerType type, Repeat repeat) {
@@ -56,7 +70,11 @@ TimeMs Timer::remainingTime() const {
void Timer::Adjust() {
QObject emitter;
connect(&emitter, &QObject::destroyed, TimersAdjuster(), &QObject::destroyed);
connect(
&emitter,
&QObject::destroyed,
TimersAdjuster(),
&QObject::destroyed);
}
void Timer::adjust() {
@@ -70,6 +88,7 @@ void Timer::adjust() {
void Timer::setTimeout(TimeMs timeout) {
Expects(timeout >= 0 && timeout <= std::numeric_limits<int>::max());
_timeout = static_cast<unsigned int>(timeout);
}
@@ -93,8 +112,12 @@ void Timer::timerEvent(QTimerEvent *e) {
}
}
int DelayedCallTimer::call(TimeMs timeout, lambda_once<void()> callback, Qt::TimerType type) {
int DelayedCallTimer::call(
TimeMs timeout,
lambda_once<void()> callback,
Qt::TimerType type) {
Expects(timeout >= 0);
if (!callback) {
return 0;
}
@@ -108,7 +131,7 @@ int DelayedCallTimer::call(TimeMs timeout, lambda_once<void()> callback, Qt::Tim
void DelayedCallTimer::cancel(int callId) {
if (callId) {
killTimer(callId);
_callbacks.erase(callId);
_callbacks.remove(callId);
}
}

View File

@@ -14,7 +14,10 @@ namespace base {
class Timer final : private QObject {
public:
Timer(base::lambda<void()> callback = base::lambda<void()>());
explicit Timer(
not_null<QThread*> thread,
base::lambda<void()> callback = nullptr);
explicit Timer(base::lambda<void()> callback = nullptr);
static Qt::TimerType DefaultType(TimeMs timeout) {
constexpr auto kThreshold = TimeMs(1000);
@@ -85,17 +88,23 @@ private:
class DelayedCallTimer final : private QObject {
public:
int call(TimeMs timeout, lambda_once<void()> callback) {
return call(timeout, std::move(callback), Timer::DefaultType(timeout));
return call(
timeout,
std::move(callback),
Timer::DefaultType(timeout));
}
int call(TimeMs timeout, lambda_once<void()> callback, Qt::TimerType type);
int call(
TimeMs timeout,
lambda_once<void()> callback,
Qt::TimerType type);
void cancel(int callId);
protected:
void timerEvent(QTimerEvent *e) override;
private:
std::map<int, lambda_once<void()>> _callbacks; // Better to use flatmap.
base::flat_map<int, lambda_once<void()>> _callbacks;
};

View File

@@ -10,7 +10,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lang/lang_keys.h"
#include "mainwidget.h"
#include "mainwindow.h"
#include "autoupdater.h"
#include "boxes/confirm_box.h"
#include "application.h"
#include "ui/widgets/buttons.h"
@@ -18,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "styles/style_boxes.h"
#include "platform/platform_file_utilities.h"
#include "core/click_handler_types.h"
#include "core/update_checker.h"
AboutBox::AboutBox(QWidget *parent)
: _version(this, lng_about_version(lt_version, QString::fromLatin1(AppVersionStr.c_str()) + (cAlphaVersion() ? " alpha" : "") + (cBetaVersion() ? qsl(" beta %1").arg(cBetaVersion()) : QString())), st::aboutVersionLink)
@@ -68,7 +68,7 @@ void AboutBox::showVersionHistory() {
case dbipLinux32: url += qsl("linux32/%1.tar.xz"); break;
case dbipLinux64: url += qsl("linux/%1.tar.xz"); break;
}
url = url.arg(qsl("tbeta%1_%2").arg(cRealBetaVersion()).arg(countBetaVersionSignature(cRealBetaVersion())));
url = url.arg(qsl("tbeta%1_%2").arg(cRealBetaVersion()).arg(Core::countBetaVersionSignature(cRealBetaVersion())));
Application::clipboard()->setText(url);

View File

@@ -19,12 +19,22 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mainwidget.h"
#include "mainwindow.h"
QPointer<Ui::RoundButton> BoxContent::addButton(base::lambda<QString()> textFactory, base::lambda<void()> clickCallback) {
return addButton(std::move(textFactory), std::move(clickCallback), st::defaultBoxButton);
QPointer<Ui::RoundButton> BoxContent::addButton(
base::lambda<QString()> textFactory,
base::lambda<void()> clickCallback) {
return addButton(
std::move(textFactory),
std::move(clickCallback),
st::defaultBoxButton);
}
QPointer<Ui::RoundButton> BoxContent::addLeftButton(base::lambda<QString()> textFactory, base::lambda<void()> clickCallback) {
return getDelegate()->addLeftButton(std::move(textFactory), std::move(clickCallback), st::defaultBoxButton);
QPointer<Ui::RoundButton> BoxContent::addLeftButton(
base::lambda<QString()> textFactory,
base::lambda<void()> clickCallback) {
return getDelegate()->addLeftButton(
std::move(textFactory),
std::move(clickCallback),
st::defaultBoxButton);
}
void BoxContent::setInner(object_ptr<TWidget> inner) {
@@ -117,7 +127,7 @@ void BoxContent::updateShadowsVisibility() {
(top > 0 || _innerTopSkip > 0),
anim::type::normal);
_bottomShadow->toggle(
(top < _scroll->scrollTopMax()),
(top < _scroll->scrollTopMax() || _innerBottomSkip > 0),
anim::type::normal);
}
@@ -145,6 +155,16 @@ void BoxContent::setInnerTopSkip(int innerTopSkip, bool scrollBottomFixed) {
}
}
void BoxContent::setInnerBottomSkip(int innerBottomSkip) {
if (_innerBottomSkip != innerBottomSkip) {
auto delta = innerBottomSkip - _innerBottomSkip;
_innerBottomSkip = innerBottomSkip;
if (_scroll && width() > 0) {
updateScrollAreaGeometry();
}
}
}
void BoxContent::setInnerVisible(bool scrollAreaVisible) {
if (_scroll) {
_scroll->setVisible(scrollAreaVisible);
@@ -169,13 +189,15 @@ void BoxContent::resizeEvent(QResizeEvent *e) {
}
void BoxContent::updateScrollAreaGeometry() {
auto newScrollHeight = height() - _innerTopSkip;
auto newScrollHeight = height() - _innerTopSkip - _innerBottomSkip;
auto changed = (_scroll->height() != newScrollHeight);
_scroll->setGeometryToLeft(0, _innerTopSkip, width(), newScrollHeight);
_topShadow->entity()->resize(width(), st::lineWidth);
_topShadow->moveToLeft(0, _innerTopSkip);
_bottomShadow->entity()->resize(width(), st::lineWidth);
_bottomShadow->moveToLeft(0, height() - st::lineWidth);
_bottomShadow->moveToLeft(
0,
height() - _innerBottomSkip - st::lineWidth);
if (changed) {
updateInnerVisibleTopBottom();
@@ -184,7 +206,7 @@ void BoxContent::updateScrollAreaGeometry() {
(top > 0 || _innerTopSkip > 0),
anim::type::instant);
_bottomShadow->toggle(
(top < _scroll->scrollTopMax()),
(top < _scroll->scrollTopMax() || _innerBottomSkip > 0),
anim::type::instant);
}
}

View File

@@ -130,19 +130,29 @@ protected:
getDelegate()->setDimensions(newWidth, maxHeight);
}
void setInnerTopSkip(int topSkip, bool scrollBottomFixed = false);
void setInnerBottomSkip(int bottomSkip);
template <typename Widget>
QPointer<Widget> setInnerWidget(object_ptr<Widget> inner, const style::ScrollArea &st, int topSkip = 0) {
QPointer<Widget> setInnerWidget(
object_ptr<Widget> inner,
const style::ScrollArea &st,
int topSkip = 0,
int bottomSkip = 0) {
auto result = QPointer<Widget>(inner.data());
setInnerTopSkip(topSkip);
setInnerBottomSkip(bottomSkip);
setInner(std::move(inner), st);
return result;
}
template <typename Widget>
QPointer<Widget> setInnerWidget(object_ptr<Widget> inner, int topSkip = 0) {
QPointer<Widget> setInnerWidget(
object_ptr<Widget> inner,
int topSkip = 0,
int bottomSkip = 0) {
auto result = QPointer<Widget>(inner.data());
setInnerTopSkip(topSkip);
setInnerBottomSkip(bottomSkip);
setInner(std::move(inner));
return result;
}
@@ -183,6 +193,7 @@ private:
bool _preparing = false;
bool _noContentMargin = false;
int _innerTopSkip = 0;
int _innerBottomSkip = 0;
object_ptr<Ui::ScrollArea> _scroll = { nullptr };
object_ptr<Ui::FadeShadow> _topShadow = { nullptr };
object_ptr<Ui::FadeShadow> _bottomShadow = { nullptr };

View File

@@ -711,3 +711,66 @@ sendMediaFileThumbSize: 64px;
sendMediaFileThumbSkip: 10px;
sendMediaFileNameTop: 7px;
sendMediaFileStatusTop: 37px;
proxyUsePadding: margins(22px, 8px, 22px, 12px);
proxyTryIPv6Padding: margins(22px, 12px, 22px, 8px);
proxyRowPadding: margins(22px, 8px, 8px, 8px);
proxyRowIconSkip: 32px;
proxyRowSkip: 2px;
proxyRowRipple: RippleAnimation(defaultRippleAnimation) {
color: windowBgOver;
}
proxyRowSelectedIcon: icon {{ "passport_ready", windowActiveTextFg }};
proxyRowTitleFg: windowFg;
proxyRowTitlePalette: TextPalette(defaultTextPalette) {
linkFg: windowSubTextFg;
}
proxyRowTitleStyle: TextStyle(defaultTextStyle) {
font: semiboldFont;
linkFont: normalFont;
linkFontOver: normalFont;
}
proxyRowStatusFg: windowSubTextFg;
proxyRowStatusFgOnline: windowActiveTextFg;
proxyRowStatusFgOffline: boxTextFgError;
proxyRowStatusFgAvailable: boxTextFgGood;
proxyRowEdit: IconButton(defaultIconButton) {
width: 40px;
height: 40px;
icon: icon {{ "settings_edit_name", menuIconFg }};
iconOver: icon {{ "settings_edit_name", menuIconFgOver }};
iconPosition: point(12px, 13px);
rippleAreaSize: 40px;
rippleAreaPosition: point(0px, 0px);
ripple: RippleAnimation(defaultRippleAnimation) {
color: windowBgOver;
}
}
proxyEditTitle: FlatLabel(defaultFlatLabel) {
style: TextStyle(defaultTextStyle) {
font: autoDownloadTitleFont;
}
textFg: boxTitleFg;
}
proxyEditTitlePadding: margins(22px, 16px, 22px, 0px);
proxyEditTypePadding: margins(22px, 4px, 22px, 8px);
proxyEditInputPadding: margins(22px, 0px, 22px, 0px);
proxyEditSkip: 16px;
proxyEmptyListLabel: FlatLabel(defaultFlatLabel) {
align: align(top);
textFg: windowSubTextFg;
}
proxyEmptyListPadding: margins(22px, 48px, 22px, 0px);
proxyCheckingPosition: point(2px, 5px);
proxyCheckingSkip: 6px;
proxyCheckingAnimation: InfiniteRadialAnimation(defaultInfiniteRadialAnimation) {
color: windowSubTextFg;
thickness: 1px;
size: size(8px, 8px);
}
proxyDropdownDownPosition: point(-2px, 35px);
proxyDropdownUpPosition: point(-2px, 20px);

View File

@@ -641,7 +641,7 @@ ConfirmInviteBox::ConfirmInviteBox(QWidget*, const QString &title, bool isChanne
}
void ConfirmInviteBox::prepare() {
addButton(langFactory(lng_group_invite_join), [this] {
addButton(langFactory(lng_group_invite_join), [] {
if (auto main = App::main()) {
main->onInviteImport();
}

File diff suppressed because it is too large Load Diff

View File

@@ -8,6 +8,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once
#include "boxes/abstract_box.h"
#include "base/timer.h"
#include "mtproto/connection_abstract.h"
namespace Ui {
class InputField;
@@ -24,9 +26,13 @@ class ConnectionBox : public BoxContent {
Q_OBJECT
public:
using Type = ProxyData::Type;
ConnectionBox(QWidget *parent);
static void ShowApplyProxyConfirmation(const QMap<QString, QString> &fields);
static void ShowApplyProxyConfirmation(
Type type,
const QMap<QString, QString> &fields);
protected:
void prepare() override;
@@ -40,19 +46,20 @@ private slots:
void onSave();
private:
void typeChanged(DBIConnectionType type);
void typeChanged(Type type);
void updateControlsVisibility();
void updateControlsPosition();
bool badProxyValue() const;
bool proxyFieldsVisible() const;
object_ptr<Ui::InputField> _hostInput;
object_ptr<Ui::PortInput> _portInput;
object_ptr<Ui::InputField> _userInput;
object_ptr<Ui::PasswordInput> _passwordInput;
std::shared_ptr<Ui::RadioenumGroup<DBIConnectionType>> _typeGroup;
object_ptr<Ui::Radioenum<DBIConnectionType>> _autoRadio;
object_ptr<Ui::Radioenum<DBIConnectionType>> _httpProxyRadio;
object_ptr<Ui::Radioenum<DBIConnectionType>> _tcpProxyRadio;
std::shared_ptr<Ui::RadioenumGroup<Type>> _typeGroup;
object_ptr<Ui::Radioenum<Type>> _autoRadio;
object_ptr<Ui::Radioenum<Type>> _httpProxyRadio;
object_ptr<Ui::Radioenum<Type>> _tcpProxyRadio;
object_ptr<Ui::Checkbox> _tryIPv6;
};
@@ -84,3 +91,88 @@ private:
int _sectionHeight = 0;
};
class ProxiesBoxController : public base::Subscriber {
public:
using Type = ProxyData::Type;
ProxiesBoxController();
static object_ptr<BoxContent> CreateOwningBox();
object_ptr<BoxContent> create();
enum class ItemState {
Connecting,
Online,
Checking,
Available,
Unavailable
};
struct ItemView {
int id = 0;
QString type;
QString host;
uint32 port = 0;
int ping = 0;
bool selected = false;
bool deleted = false;
bool canShare = false;
ItemState state = ItemState::Checking;
};
void deleteItem(int id);
void restoreItem(int id);
void shareItem(int id);
void applyItem(int id);
object_ptr<BoxContent> editItemBox(int id);
object_ptr<BoxContent> addNewItemBox();
bool setProxyEnabled(bool enabled);
void setTryIPv6(bool enabled);
rpl::producer<bool> proxyEnabledValue() const;
rpl::producer<ItemView> views() const;
~ProxiesBoxController();
private:
using Checker = MTP::internal::ConnectionPointer;
struct Item {
int id = 0;
ProxyData data;
bool deleted = false;
Checker checker;
Checker checkerv6;
ItemState state = ItemState::Checking;
int ping = 0;
};
std::vector<Item>::iterator findById(int id);
std::vector<Item>::iterator findByProxy(const ProxyData &proxy);
void setDeleted(int id, bool deleted);
void updateView(const Item &item);
void share(const ProxyData &proxy);
void applyChanges();
void saveDelayed();
void refreshChecker(Item &item);
void setupChecker(int id, const Checker &checker);
void replaceItemWith(
std::vector<Item>::iterator which,
std::vector<Item>::iterator with);
void replaceItemValue(
std::vector<Item>::iterator which,
const ProxyData &proxy);
void addNewItem(const ProxyData &proxy);
int _idCounter = 0;
std::vector<Item> _list;
rpl::event_stream<ItemView> _views;
base::Timer _saveTimer;
rpl::event_stream<bool> _proxyEnabledChanges;
ProxyData _lastSelectedProxy;
bool _lastSelectedProxyUsed = false;
};

View File

@@ -469,7 +469,7 @@ void EditRestrictedBox::createUntilVariants() {
_untilVariants.back()->setDisabled(true);
}
};
auto addCustomVariant = [this, addVariant](TimeId until, TimeId from, TimeId to) {
auto addCustomVariant = [addVariant](TimeId until, TimeId from, TimeId to) {
if (!ChannelData::IsRestrictedForever(until) && until > from && until <= to) {
addVariant(
until,

View File

@@ -95,7 +95,7 @@ void EditPrivacyBox::prepare() {
int EditPrivacyBox::resizeGetHeight(int newWidth) {
auto top = 0;
auto layoutRow = [this, newWidth, &top](auto &widget, style::margins padding) {
auto layoutRow = [&](auto &widget, style::margins padding) {
if (!widget) return;
widget->resizeToNaturalWidth(newWidth - padding.left() - padding.right());
widget->moveToLeft(padding.left(), top + padding.top());
@@ -137,7 +137,7 @@ int EditPrivacyBox::countDefaultHeight(int newWidth) {
}
return st::editPrivacyOptionMargin.top() + st::defaultCheck.diameter + st::editPrivacyOptionMargin.bottom();
};
auto labelHeight = [this, newWidth](const QString &text, const style::FlatLabel &st, style::margins padding) {
auto labelHeight = [newWidth](const QString &text, const style::FlatLabel &st, style::margins padding) {
if (text.isEmpty()) {
return 0;
}

View File

@@ -731,7 +731,7 @@ void EditChatAdminsBoxController::Start(not_null<ChatData*> chat) {
}
void AddBotToGroupBoxController::Start(not_null<UserData*> bot) {
auto initBox = [bot](not_null<PeerListBox*> box) {
auto initBox = [=](not_null<PeerListBox*> box) {
box->addButton(langFactory(lng_cancel), [box] { box->closeBox(); });
};
Ui::show(Box<PeerListBox>(std::make_unique<AddBotToGroupBoxController>(bot), std::move(initBox)));

View File

@@ -124,7 +124,16 @@ void Call::startOutgoing() {
Expects(_type == Type::Outgoing);
Expects(_state == State::Requesting);
request(MTPphone_RequestCall(_user->inputUser, MTP_int(rand_value<int32>()), MTP_bytes(_gaHash), MTP_phoneCallProtocol(MTP_flags(MTPDphoneCallProtocol::Flag::f_udp_p2p | MTPDphoneCallProtocol::Flag::f_udp_reflector), MTP_int(kMinLayer), MTP_int(kMaxLayer)))).done([this](const MTPphone_PhoneCall &result) {
request(MTPphone_RequestCall(
_user->inputUser,
MTP_int(rand_value<int32>()),
MTP_bytes(_gaHash),
MTP_phoneCallProtocol(
MTP_flags(MTPDphoneCallProtocol::Flag::f_udp_p2p
| MTPDphoneCallProtocol::Flag::f_udp_reflector),
MTP_int(kMinLayer),
MTP_int(kMaxLayer))
)).done([this](const MTPphone_PhoneCall &result) {
Expects(result.type() == mtpc_phone_phoneCall);
setState(State::Waiting);
@@ -185,7 +194,15 @@ void Call::answer() {
} else {
_answerAfterDhConfigReceived = false;
}
request(MTPphone_AcceptCall(MTP_inputPhoneCall(MTP_long(_id), MTP_long(_accessHash)), MTP_bytes(_gb), _protocol)).done([this](const MTPphone_PhoneCall &result) {
request(MTPphone_AcceptCall(
MTP_inputPhoneCall(MTP_long(_id), MTP_long(_accessHash)),
MTP_bytes(_gb),
MTP_phoneCallProtocol(
MTP_flags(MTPDphoneCallProtocol::Flag::f_udp_p2p
| MTPDphoneCallProtocol::Flag::f_udp_reflector),
MTP_int(kMinLayer),
MTP_int(kMaxLayer))
)).done([this](const MTPphone_PhoneCall &result) {
Expects(result.type() == mtpc_phone_phoneCall);
auto &call = result.c_phone_phoneCall();
App::feedUsers(call.vusers);
@@ -294,7 +311,6 @@ bool Call::handleUpdate(const MTPPhoneCall &call) {
}
_id = data.vid.v;
_accessHash = data.vaccess_hash.v;
_protocol = data.vprotocol;
auto gaHashBytes = bytesFromMTP(data.vg_a_hash);
if (gaHashBytes.size() != _gaHash.size()) {
LOG(("Call Error: Wrong g_a_hash size %1, expected %2.").arg(gaHashBytes.size()).arg(_gaHash.size()));
@@ -393,7 +409,16 @@ void Call::confirmAcceptedCall(const MTPDphoneCallAccepted &call) {
_keyFingerprint = ComputeFingerprint(_authKey);
setState(State::ExchangingKeys);
request(MTPphone_ConfirmCall(MTP_inputPhoneCall(MTP_long(_id), MTP_long(_accessHash)), MTP_bytes(_ga), MTP_long(_keyFingerprint), MTP_phoneCallProtocol(MTP_flags(MTPDphoneCallProtocol::Flag::f_udp_p2p | MTPDphoneCallProtocol::Flag::f_udp_reflector), MTP_int(kMinLayer), MTP_int(kMaxLayer)))).done([this](const MTPphone_PhoneCall &result) {
request(MTPphone_ConfirmCall(
MTP_inputPhoneCall(MTP_long(_id), MTP_long(_accessHash)),
MTP_bytes(_ga),
MTP_long(_keyFingerprint),
MTP_phoneCallProtocol(
MTP_flags(MTPDphoneCallProtocol::Flag::f_udp_p2p
| MTPDphoneCallProtocol::Flag::f_udp_reflector),
MTP_int(kMinLayer),
MTP_int(kMaxLayer))
)).done([this](const MTPphone_PhoneCall &result) {
Expects(result.type() == mtpc_phone_phoneCall);
auto &call = result.c_phone_phoneCall();
App::feedUsers(call.vusers);

View File

@@ -401,7 +401,7 @@ QString SuggestionsController::getEmojiQuery() {
}
position -= from;
_queryStartPosition = from;
return fragment.text().toLower();
return fragment.text();
}
return QString();
};
@@ -411,10 +411,23 @@ QString SuggestionsController::getEmojiQuery() {
return QString();
}
auto isSuggestionChar = [](QChar ch) {
return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || (ch == '_') || (ch == '-') || (ch == '+');
const auto isUpperCaseLetter = [](QChar ch) {
return (ch >= 'A' && ch <= 'Z');
};
auto isGoodCharBeforeSuggestion = [isSuggestionChar](QChar ch) {
const auto isLetter = [](QChar ch) {
return (ch >= 'a' && ch <= 'z')
|| (ch >= 'A' && ch <= 'Z')
|| (ch >= '0' && ch <= '9');
};
const auto isSuggestionChar = [](QChar ch) {
return (ch >= 'a' && ch <= 'z')
|| (ch >= 'A' && ch <= 'Z')
|| (ch >= '0' && ch <= '9')
|| (ch == '_')
|| (ch == '-')
|| (ch == '+');
};
const auto isGoodCharBeforeSuggestion = [&](QChar ch) {
return !isSuggestionChar(ch) || (ch == 0);
};
Assert(position > 0 && position <= text.size());
@@ -427,7 +440,22 @@ QString SuggestionsController::getEmojiQuery() {
if (position > i + 1) {
// Skip colon and the first letter.
_queryStartPosition += i + 2;
return text.mid(i, position - i);
const auto length = position - i;
auto result = text.mid(i, length);
const auto upperCaseLetters = std::count_if(
result.begin(),
result.end(),
isUpperCaseLetter);
const auto letters = std::count_if(
result.begin(),
result.end(),
isLetter);
if (letters == upperCaseLetters && letters == 1) {
// No upper case single letter suggestions.
// We don't want to suggest emoji on :D and :-P
return QString();
}
return result.toLower();
}
}
return QString();
@@ -452,8 +480,7 @@ void SuggestionsController::replaceCurrent(const QString &replacement) {
cursor.insertText(replacement);
}
auto emojiText = GetSuggestionEmoji(QStringToUTF16(replacement));
if (auto emoji = Find(QStringFromUTF16(emojiText))) {
if (auto emoji = Find(replacement)) {
if (emoji->hasVariants()) {
auto it = cEmojiVariants().constFind(emoji->nonColoredId());
if (it != cEmojiVariants().cend()) {

View File

@@ -783,9 +783,9 @@ std::vector<not_null<DocumentData*>> GetListByEmoji(
addList(
Auth().data().stickerSetsOrder(),
MTPDstickerSet::Flag::f_archived);
addList(
Auth().data().featuredStickerSetsOrder(),
MTPDstickerSet::Flag::f_installed_date);
//addList(
// Auth().data().featuredStickerSetsOrder(),
// MTPDstickerSet::Flag::f_installed_date);
if (!setsToRequest.empty()) {
for (const auto [setId, accessHash] : setsToRequest) {
@@ -794,13 +794,15 @@ std::vector<not_null<DocumentData*>> GetListByEmoji(
Auth().api().requestStickerSets();
}
const auto others = Auth().api().stickersByEmoji(original);
if (!others) {
return {};
}
result.reserve(result.size() + others->size());
for (const auto document : *others) {
add(document, CreateOtherSortKey(document));
if (Global::SuggestStickersByEmoji()) {
const auto others = Auth().api().stickersByEmoji(original);
if (!others) {
return {};
}
result.reserve(result.size() + others->size());
for (const auto document : *others) {
add(document, CreateOtherSortKey(document));
}
}
ranges::action::sort(

View File

@@ -63,7 +63,9 @@ public:
Footer(not_null<StickersListWidget*> parent);
void preloadImages();
void validateSelectedIcon(uint64 setId, ValidateIconAnimations animations);
void validateSelectedIcon(
uint64 setId,
ValidateIconAnimations animations);
void refreshIcons(ValidateIconAnimations animations);
bool hasOnlyFeaturedSets() const;
@@ -99,6 +101,7 @@ private:
int newSelected,
ValidateIconAnimations animations);
void refreshIconsGeometry(ValidateIconAnimations animations);
void updateSelected();
void finishDragging();
void paintStickerSettingsIcon(Painter &p) const;
@@ -253,7 +256,7 @@ void StickersListWidget::Footer::enumerateVisibleIcons(Callback callback) {
}
void StickersListWidget::Footer::preloadImages() {
enumerateVisibleIcons([this](const StickerIcon &icon, int x) {
enumerateVisibleIcons([](const StickerIcon &icon, int x) {
if (auto sticker = icon.sticker) {
sticker->thumb->load();
}
@@ -389,6 +392,7 @@ void StickersListWidget::Footer::resizeEvent(QResizeEvent *e) {
if (_searchField) {
resizeSearchControls();
}
refreshIconsGeometry(ValidateIconAnimations::None);
}
void StickersListWidget::Footer::resizeSearchControls() {
@@ -543,10 +547,11 @@ void StickersListWidget::Footer::updateSelected() {
if (y >= _iconsTop
&& y < _iconsTop + st::emojiFooterHeight
&& x >= _iconsLeft
&& x < width() - _iconsRight
&& x < _icons.size() * st::stickerIconWidth) {
&& x < width() - _iconsRight) {
x += qRound(_iconsX.current()) - _iconsLeft;
newOver = qFloor(x / st::stickerIconWidth);
if (x < _icons.size() * st::stickerIconWidth) {
newOver = qFloor(x / st::stickerIconWidth);
}
}
}
if (newOver != _iconOver) {
@@ -561,8 +566,13 @@ void StickersListWidget::Footer::updateSelected() {
void StickersListWidget::Footer::refreshIcons(
ValidateIconAnimations animations) {
_iconOver = SpecialOver::None;
_pan->fillIcons(_icons);
refreshIconsGeometry(animations);
}
void StickersListWidget::Footer::refreshIconsGeometry(
ValidateIconAnimations animations) {
_iconOver = _iconDown = SpecialOver::None;
_iconsX.finish();
_iconSelX.finish();
_iconsStartAnim = 0;
@@ -919,7 +929,7 @@ void StickersListWidget::refreshSearchRows(
_searchSets.clear();
fillLocalSearchRows(_searchNextQuery);
if (!cloudSets && _searchSets.empty()) {
if (!cloudSets && _searchNextQuery.isEmpty()) {
showStickerSet(!_mySets.empty()
? _mySets[0].id
: Stickers::FeaturedSetId);
@@ -1711,7 +1721,11 @@ void StickersListWidget::refreshSearchSets() {
void StickersListWidget::refreshSearchIndex() {
_searchIndex.clear();
for (const auto &set : _mySets) {
const auto list = TextUtilities::PrepareSearchWords(set.title + ' ' + set.shortName);
if (set.flags & MTPDstickerSet_ClientFlag::f_special) {
continue;
}
const auto string = set.title + ' ' + set.shortName;
const auto list = TextUtilities::PrepareSearchWords(string);
_searchIndex.emplace_back(set.id, list);
}
}

View File

@@ -54,7 +54,16 @@ addChildParentFlags('MTPDchannelForbidden', 'MTPDchannel');
# each key flag of parentFlags should be a subset of the value flag here
parentFlagsCheck = {};
countedTypeIdExceptions = {};
countedTypeIdExceptions[77] = countedTypeIdExceptions[78] = {}
countedTypeIdExceptions[77]['channel'] = countedTypeIdExceptions[78]['channel'] = True
countedTypeIdExceptions['ipPortSecret'] = True
countedTypeIdExceptions['accessPointRule'] = True
countedTypeIdExceptions['help_configSimple'] = True
lines = [];
layer = '';
layerIndex = 0;
funcs = 0
types = 0;
consts = 0
@@ -83,7 +92,12 @@ with open(input_file) as f:
for line in f:
layerline = re.match(r'// LAYER (\d+)', line)
if (layerline):
layer = 'constexpr auto CurrentLayer = mtpPrime(' + layerline.group(1) + ');';
layerIndex = int(layerline.group(1));
layer = 'constexpr auto CurrentLayer = mtpPrime(' + str(layerIndex) + ');';
else:
lines.append(line);
for line in lines:
nocomment = re.match(r'^(.*?)//', line)
if (nocomment):
line = nocomment.group(1);
@@ -131,8 +145,10 @@ with open(input_file) as f:
if (typeid and len(typeid) > 0):
typeid = '0x' + typeid;
if (typeid != countTypeId):
print('Warning: counted ' + countTypeId + ' mismatch with provided ' + typeid + ' (' + cleanline + ')');
continue;
if (not layerIndex in countedTypeIdExceptions or not name in countedTypeIdExceptions[layerIndex]):
if (not name in countedTypeIdExceptions):
print('Warning: counted ' + countTypeId + ' mismatch with provided ' + typeid + ' (' + cleanline + ')');
continue;
else:
typeid = countTypeId;
@@ -507,7 +523,9 @@ def addTextSerialize(lst, dct, dataLetter):
if (not vtypeget):
result += '); vtypes.push_back(0';
else:
result += '0); vtypes.push_back(0';
if (not vtypeget):
result += '0';
result += '); vtypes.push_back(0';
result += '); stages.push_back(0); flags.push_back(0); ';
if (k in conditions):
result += '} else { to.add("[ SKIPPED BY BIT ' + conditions[k] + ' IN FIELD ' + hasFlags + ' ]"); } ';

View File

@@ -457,7 +457,7 @@ public:\n\
inline const color &get_transparent() const { return _colors[0]; }; // special color\n";
int indexInPalette = 1;
if (!module_.enumVariables([this, &indexInPalette](const Variable &variable) -> bool {
if (!module_.enumVariables([&](const Variable &variable) -> bool {
auto name = variable.name.back();
if (variable.value.type().tag != structure::TypeTag::Color) {
return false;
@@ -584,7 +584,7 @@ QList<row> data();\n\
}
bool Generator::writeStructsForwardDeclarations() {
bool hasNoExternalStructs = module_.enumVariables([this](const Variable &value) -> bool {
bool hasNoExternalStructs = module_.enumVariables([&](const Variable &value) -> bool {
if (value.value.type().tag == structure::TypeTag::Struct) {
if (!module_.findStructInModule(value.value.type().name, module_)) {
return false;
@@ -598,7 +598,7 @@ bool Generator::writeStructsForwardDeclarations() {
header_->newline();
std::set<QString> alreadyDeclaredTypes;
bool result = module_.enumVariables([this, &alreadyDeclaredTypes](const Variable &value) -> bool {
bool result = module_.enumVariables([&](const Variable &value) -> bool {
if (value.value.type().tag == structure::TypeTag::Struct) {
if (!module_.findStructInModule(value.value.type().name, module_)) {
if (alreadyDeclaredTypes.find(value.value.type().name.back()) == alreadyDeclaredTypes.end()) {
@@ -618,7 +618,7 @@ bool Generator::writeStructsDefinitions() {
return true;
}
bool result = module_.enumStructs([this](const Struct &value) -> bool {
bool result = module_.enumStructs([&](const Struct &value) -> bool {
header_->stream() << "\
struct " << value.name.back() << " {\n";
for (auto &field : value.fields) {
@@ -646,7 +646,7 @@ bool Generator::writeRefsDeclarations() {
if (isPalette_) {
header_->stream() << "extern const style::color &transparent; // special color\n";
}
bool result = module_.enumVariables([this](const Variable &value) -> bool {
bool result = module_.enumVariables([&](const Variable &value) -> bool {
auto name = value.name.back();
auto type = typeToString(value.value.type());
if (type.isEmpty()) {
@@ -668,7 +668,7 @@ bool Generator::writeIncludesInSource() {
}
auto includes = QStringList();
std::function<bool(const Module&)> collector = [this, &collector, &includes](const Module &module) {
std::function<bool(const Module&)> collector = [&](const Module &module) {
module.enumIncludes(collector);
auto base = moduleBaseName(module);
if (!includes.contains(base)) {
@@ -690,7 +690,7 @@ bool Generator::writeVariableDefinitions() {
}
source_->newline();
bool result = module_.enumVariables([this](const Variable &variable) -> bool {
bool result = module_.enumVariables([&](const Variable &variable) -> bool {
auto name = variable.name.back();
auto type = typeToString(variable.value.type());
if (type.isEmpty()) {
@@ -710,7 +710,7 @@ bool Generator::writeRefsDefinition() {
if (isPalette_) {
source_->stream() << "const style::color &transparent(_palette.get_transparent()); // special color\n";
}
bool result = module_.enumVariables([this](const Variable &variable) -> bool {
bool result = module_.enumVariables([&](const Variable &variable) -> bool {
auto name = variable.name.back();
auto type = typeToString(variable.value.type());
if (type.isEmpty()) {
@@ -752,7 +752,7 @@ void palette::finalize() {\n\
compute(0, -1, { 255, 255, 255, 0}); // special color\n";
QList<structure::FullName> names;
module_.enumVariables([this, &names](const Variable &variable) -> bool {
module_.enumVariables([&](const Variable &variable) -> bool {
names.push_back(variable.name);
return true;
});
@@ -761,7 +761,7 @@ void palette::finalize() {\n\
int indexInPalette = 1;
QByteArray checksumString;
checksumString.append("&transparent:{ 255, 255, 255, 0 }");
auto result = module_.enumVariables([this, &indexInPalette, &checksumString, &dataRows, &names](const Variable &variable) -> bool {
auto result = module_.enumVariables([&](const Variable &variable) -> bool {
auto name = variable.name.back();
auto index = indexInPalette++;
paletteIndices_.emplace(name, index);
@@ -826,7 +826,7 @@ int getPaletteIndex(QLatin1String name) {\n\
auto tabsUsed = 1;
// Returns true if at least one check was finished.
auto finishChecksTillKey = [this, &chars, &checkTypes, &checkLengthHistory, &tabsUsed, tabs](const QString &key) {
auto finishChecksTillKey = [&](const QString &key) {
auto result = false;
while (!chars.isEmpty() && key.midRef(0, chars.size()) != chars) {
result = true;
@@ -1069,7 +1069,7 @@ void init_" << baseName_ << "() {\n\
if (module_.hasIncludes()) {
bool writtenAtLeastOne = false;
bool result = module_.enumIncludes([this,&writtenAtLeastOne](const Module &module) -> bool {
bool result = module_.enumIncludes([&](const Module &module) -> bool {
if (module.hasVariables()) {
source_->stream() << "\tinit_" + moduleBaseName(module) + "();\n";
writtenAtLeastOne = true;
@@ -1096,7 +1096,7 @@ void init_" << baseName_ << "() {\n\
if (isPalette_) {
source_->stream() << "\t_palette.finalize();\n";
} else if (!module_.enumVariables([this](const Variable &variable) -> bool {
} else if (!module_.enumVariables([&](const Variable &variable) -> bool {
auto name = variable.name.back();
auto value = valueAssignmentCode(variable.value);
if (value.isEmpty()) {

View File

@@ -32,6 +32,7 @@ constexpr int kErrorAlreadyDefined = 805;
constexpr int kErrorBadString = 806;
constexpr int kErrorIconDuplicate = 807;
constexpr int kErrorBadIconModifier = 808;
constexpr int kErrorCyclicDependency = 809;
QString findInputFile(const Options &options) {
for (const auto &dir : options.includePaths) {
@@ -148,14 +149,21 @@ Modifier GetModifier(const QString &name) {
return modifiers.value(name);
}
ParsedFile::ParsedFile(const Options &options)
ParsedFile::ParsedFile(
const Options &options,
std::vector<QString> includeStack)
: filePath_(findInputFile(options))
, file_(filePath_)
, options_(options) {
, options_(options)
, includeStack_(includeStack) {
}
bool ParsedFile::read() {
if (!file_.read()) {
if (std::find(begin(includeStack_), end(includeStack_), filePath_)
!= end(includeStack_)) {
logError(kErrorCyclicDependency) << "include cycle detected.";
return false;
} else if (!file_.read()) {
return false;
}
@@ -205,7 +213,11 @@ common::LogStream ParsedFile::logErrorTypeMismatch() {
ParsedFile::ModulePtr ParsedFile::readIncluded() {
if (auto usingFile = assertNextToken(BasicType::String)) {
if (assertNextToken(BasicType::Semicolon)) {
ParsedFile included(includedOptions(tokenValue(usingFile)));
auto includeStack = includeStack_;
includeStack.push_back(filePath_);
ParsedFile included(
includedOptions(tokenValue(usingFile)),
includeStack);
if (included.read()) {
return included.getResult();
} else {

View File

@@ -24,7 +24,9 @@ Modifier GetModifier(const QString &name);
// Parses an input file to the internal struct.
class ParsedFile {
public:
explicit ParsedFile(const Options &options);
explicit ParsedFile(
const Options &options,
std::vector<QString> includeStack = {});
ParsedFile(const ParsedFile &other) = delete;
ParsedFile &operator=(const ParsedFile &other) = delete;
@@ -108,6 +110,8 @@ private:
bool failed_ = false;
ModulePtr module_;
std::vector<QString> includeStack_;
QMap<std::string, structure::Type> typeNames_ = {
{ "int" , { structure::TypeTag::Int } },
{ "double" , { structure::TypeTag::Double } },

View File

@@ -25,13 +25,6 @@ enum {
MTPAckSendWaiting = 10000, // how much time to wait for some more requests, when sending msg acks
MTPResendThreshold = 1, // how much ints should message contain for us not to resend, but to check it's state
MTPContainerLives = 600, // container lives 10 minutes in haveSent map
MTPMinReceiveDelay = 4000, // 4 seconds
MTPMaxReceiveDelay = 64000, // 64 seconds
MTPMinConnectDelay = 1000, // tcp connect should take less then 1 second
MTPMaxConnectDelay = 8000, // tcp connect should take 8 seconds max
MTPConnectionOldTimeout = 192000, // 192 seconds
MTPTcpConnectionWaitTimeout = 2000, // 2 seconds waiting for tcp, until we accept http
MTPIPv4ConnectionWaitTimeout = 1000, // 1 seconds waiting for ipv4, until we accept ipv6
MTPKillFileSessionTimeout = 5000, // how much time without upload / download causes additional session kill
@@ -39,10 +32,6 @@ enum {
MaxUsersPerInvite = 100, // max users in one super group invite request
MTPPingDelayDisconnect = 60, // 1 min
MTPPingSendAfterAuto = 30, // send new ping starting from 30 seconds (add to existing container)
MTPPingSendAfter = 45, // send new ping after 45 seconds without ping
MTPChannelGetDifferenceLimit = 100,
MaxSelectedItems = 100,
@@ -163,11 +152,11 @@ static const BuiltInDc _builtInDcs[] = {
};
static const BuiltInDc _builtInDcsIPv6[] = {
{ 1, "2001:b28:f23d:f001::a", 443 },
{ 2, "2001:67c:4e8:f002::a", 443 },
{ 3, "2001:b28:f23d:f003::a", 443 },
{ 4, "2001:67c:4e8:f004::a", 443 },
{ 5, "2001:b28:f23f:f005::a", 443 }
{ 1, "2001:0b28:f23d:f001:0000:0000:0000:000a", 443 },
{ 2, "2001:067c:04e8:f002:0000:0000:0000:000a", 443 },
{ 3, "2001:0b28:f23d:f003:0000:0000:0000:000a", 443 },
{ 4, "2001:067c:04e8:f004:0000:0000:0000:000a", 443 },
{ 5, "2001:0b28:f23f:f005:0000:0000:0000:000a", 443 }
};
static const BuiltInDc _builtInTestDcs[] = {
@@ -177,9 +166,9 @@ static const BuiltInDc _builtInTestDcs[] = {
};
static const BuiltInDc _builtInTestDcsIPv6[] = {
{ 1, "2001:b28:f23d:f001::e", 443 },
{ 2, "2001:67c:4e8:f002::e", 443 },
{ 3, "2001:b28:f23d:f003::e", 443 }
{ 1, "2001:0b28:f23d:f001:0000:0000:0000:000e", 443 },
{ 2, "2001:067c:04e8:f002:0000:0000:0000:000e", 443 },
{ 3, "2001:0b28:f23d:f003:0000:0000:0000:000e", 443 }
};
inline const BuiltInDc *builtInDcs() {

View File

@@ -50,6 +50,8 @@ QString tryConvertUrlToLocal(QString url) {
return url;
} else if (auto socksMatch = regex_match(qsl("socks/?\\?(.+)(#|$)"), query, matchOptions)) {
return qsl("tg://socks?") + socksMatch->captured(1);
} else if (auto proxyMatch = regex_match(qsl("proxy/?\\?(.+)(#|$)"), query, matchOptions)) {
return qsl("tg://proxy?") + proxyMatch->captured(1);
} else if (auto usernameMatch = regex_match(qsl("^([a-zA-Z0-9\\.\\_]+)(/?\\?|/?$|/(\\d+)/?(?:\\?|$))"), query, matchOptions)) {
auto params = query.mid(usernameMatch->captured(0).size()).toString();
auto postParam = QString();

View File

@@ -12,7 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "platform/platform_specific.h"
#include "application.h"
#include "base/zlib_help.h"
#include "autoupdater.h"
#include "core/update_checker.h"
PreLaunchWindow *PreLaunchWindowInstance = nullptr;
@@ -299,23 +299,36 @@ LastCrashedWindow::LastCrashedWindow()
_updatingSkip.setText(qsl("SKIP"));
connect(&_updatingSkip, SIGNAL(clicked()), this, SLOT(onUpdateSkip()));
Sandbox::connect(SIGNAL(updateChecking()), this, SLOT(onUpdateChecking()));
Sandbox::connect(SIGNAL(updateLatest()), this, SLOT(onUpdateLatest()));
Sandbox::connect(SIGNAL(updateProgress(qint64,qint64)), this, SLOT(onUpdateDownloading(qint64,qint64)));
Sandbox::connect(SIGNAL(updateFailed()), this, SLOT(onUpdateFailed()));
Sandbox::connect(SIGNAL(updateReady()), this, SLOT(onUpdateReady()));
Core::UpdateChecker checker;
using Progress = Core::UpdateChecker::Progress;
checker.checking(
) | rpl::start_with_next([=] { onUpdateChecking(); }, _lifetime);
checker.isLatest(
) | rpl::start_with_next([=] { onUpdateLatest(); }, _lifetime);
checker.progress(
) | rpl::start_with_next([=](const Progress &result) {
onUpdateDownloading(result.already, result.size);
}, _lifetime);
checker.failed(
) | rpl::start_with_next([=] { onUpdateFailed(); }, _lifetime);
checker.ready(
) | rpl::start_with_next([=] { onUpdateReady(); }, _lifetime);
switch (Sandbox::updatingState()) {
case Application::UpdatingDownload:
switch (checker.state()) {
case Core::UpdateChecker::State::Download:
setUpdatingState(UpdatingDownload, true);
setDownloadProgress(Sandbox::updatingReady(), Sandbox::updatingSize());
break;
case Application::UpdatingReady: setUpdatingState(UpdatingReady, true); break;
default: setUpdatingState(UpdatingCheck, true); break;
setDownloadProgress(checker.already(), checker.size());
break;
case Core::UpdateChecker::State::Ready:
setUpdatingState(UpdatingReady, true);
break;
default:
setUpdatingState(UpdatingCheck, true);
break;
}
cSetLastUpdateCheck(0);
Sandbox::startUpdateCheck();
checker.start();
#else // !TDESKTOP_DISABLE_AUTOUPDATE
_updating.setText(qsl("Please check if there is a new version available."));
if (_sendingState != SendingNoReport) {
@@ -434,7 +447,6 @@ void LastCrashedWindow::onSendReport() {
_sendReply->deleteLater();
_sendReply = nullptr;
}
App::setProxySettings(_sendManager);
QString apiid = getReportField(qstr("apiid"), qstr("ApiId:")), version = getReportField(qstr("version"), qstr("Version:"));
_checkReply = _sendManager.get(QNetworkRequest(qsl("https://tdesktop.com/crash.php?act=query_report&apiid=%1&version=%2&dmp=%3&platform=%4").arg(apiid).arg(version).arg(minidumpFileName().isEmpty() ? 0 : 1).arg(cPlatformString())));
@@ -756,22 +768,45 @@ void LastCrashedWindow::updateControls() {
}
void LastCrashedWindow::onNetworkSettings() {
auto &p = Sandbox::PreLaunchProxy();
NetworkSettingsWindow *box = new NetworkSettingsWindow(this, p.host, p.port ? p.port : 80, p.user, p.password);
connect(box, SIGNAL(saved(QString, quint32, QString, QString)), this, SLOT(onNetworkSettingsSaved(QString, quint32, QString, QString)));
const auto &proxy = Sandbox::PreLaunchProxy();
const auto box = new NetworkSettingsWindow(
this,
proxy.host,
proxy.port ? proxy.port : 80,
proxy.user,
proxy.password);
connect(
box,
SIGNAL(saved(QString,quint32,QString,QString)),
this,
SLOT(onNetworkSettingsSaved(QString,quint32,QString,QString)));
box->show();
}
void LastCrashedWindow::onNetworkSettingsSaved(QString host, quint32 port, QString username, QString password) {
Sandbox::RefPreLaunchProxy().host = host;
Sandbox::RefPreLaunchProxy().port = port ? port : 80;
Sandbox::RefPreLaunchProxy().user = username;
Sandbox::RefPreLaunchProxy().password = password;
void LastCrashedWindow::onNetworkSettingsSaved(
QString host,
quint32 port,
QString username,
QString password) {
Expects(host.isEmpty() || port != 0);
auto &proxy = Sandbox::RefPreLaunchProxy();
proxy.type = host.isEmpty()
? ProxyData::Type::None
: ProxyData::Type::Http;
proxy.host = host;
proxy.port = port;
proxy.user = username;
proxy.password = password;
Sandbox::refreshGlobalProxy();
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
if ((_updatingState == UpdatingFail && (_sendingState == SendingNoReport || _sendingState == SendingUpdateCheck)) || (_updatingState == UpdatingCheck)) {
Sandbox::stopUpdate();
Core::UpdateChecker checker;
checker.stop();
cSetLastUpdateCheck(0);
Sandbox::startUpdateCheck();
checker.start();
} else
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
if (_sendingState == SendingFail || _sendingState == SendingProgress) {
@@ -794,7 +829,7 @@ void LastCrashedWindow::setUpdatingState(UpdatingState state, bool force) {
}
break;
case UpdatingReady:
if (checkReadyUpdate()) {
if (Core::checkReadyUpdate()) {
cSetRestartingUpdate(true);
App::quit();
return;
@@ -828,7 +863,8 @@ void LastCrashedWindow::setDownloadProgress(qint64 ready, qint64 total) {
void LastCrashedWindow::onUpdateRetry() {
cSetLastUpdateCheck(0);
Sandbox::startUpdateCheck();
Core::UpdateChecker checker;
checker.start();
}
void LastCrashedWindow::onUpdateSkip() {
@@ -836,7 +872,8 @@ void LastCrashedWindow::onUpdateSkip() {
onContinue();
} else {
if (_updatingState == UpdatingCheck || _updatingState == UpdatingDownload) {
Sandbox::stopUpdate();
Core::UpdateChecker checker;
checker.stop();
setUpdatingState(UpdatingFail);
}
_sendingState = SendingNone;

View File

@@ -114,6 +114,11 @@ private:
QString minidumpFileName();
void updateControls();
void excludeReportUsername();
QString getReportField(const QLatin1String &name, const QLatin1String &prefix);
void addReportFieldPart(const QLatin1String &name, const QLatin1String &prefix, QHttpMultiPart *multipart);
QString _host, _username, _password;
quint32 _port;
@@ -128,8 +133,6 @@ private:
bool _reportShown, _reportSaved;
void excludeReportUsername();
enum SendingState {
SendingNoReport,
SendingUpdateCheck,
@@ -167,8 +170,7 @@ private:
void setDownloadProgress(qint64 ready, qint64 total);
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
QString getReportField(const QLatin1String &name, const QLatin1String &prefix);
void addReportFieldPart(const QLatin1String &name, const QLatin1String &prefix, QHttpMultiPart *multipart);
rpl::lifetime _lifetime;
};

View File

@@ -109,7 +109,6 @@ void Launcher::prepareSettings() {
switch (cPlatform()) {
case dbipWindows:
gUpdateURL = QUrl(qsl("http://tdesktop.com/win/tupdates/current"));
#ifndef OS_WIN_STORE
gPlatformString = qsl("Windows");
#else // OS_WIN_STORE
@@ -117,7 +116,6 @@ void Launcher::prepareSettings() {
#endif // OS_WIN_STORE
break;
case dbipMac:
gUpdateURL = QUrl(qsl("http://tdesktop.com/mac/tupdates/current"));
#ifndef OS_MAC_STORE
gPlatformString = qsl("MacOS");
#else // OS_MAC_STORE
@@ -125,15 +123,12 @@ void Launcher::prepareSettings() {
#endif // OS_MAC_STORE
break;
case dbipMacOld:
gUpdateURL = QUrl(qsl("http://tdesktop.com/mac32/tupdates/current"));
gPlatformString = qsl("MacOSold");
break;
case dbipLinux64:
gUpdateURL = QUrl(qsl("http://tdesktop.com/linux/tupdates/current"));
gPlatformString = qsl("Linux64bit");
break;
case dbipLinux32:
gUpdateURL = QUrl(qsl("http://tdesktop.com/linux32/tupdates/current"));
gPlatformString = qsl("Linux32bit");
break;
}

View File

@@ -22,6 +22,8 @@ public:
return _customWorkingDir;
}
virtual ~Launcher() = default;
protected:
enum class UpdaterLaunch {
PerformUpdate,

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,59 @@
/*
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
namespace Core {
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
class Updater;
class UpdateChecker {
public:
enum class State {
None,
Download,
Ready,
};
struct Progress {
int64 already;
int64 size;
};
UpdateChecker();
rpl::producer<> checking() const;
rpl::producer<> isLatest() const;
rpl::producer<Progress> progress() const;
rpl::producer<> failed() const;
rpl::producer<> ready() const;
void start(bool forceWait = false);
void stop();
void test();
State state() const;
int already() const;
int size() const;
private:
const std::shared_ptr<Updater> _updater;
};
bool checkReadyUpdate();
#else // TDESKTOP_DISABLE_AUTOUPDATE
class UpdateChecker {
};
#endif // TDESKTOP_DISABLE_AUTOUPDATE
QString countBetaVersionSignature(uint64 version);
} // namespace Core

View File

@@ -236,6 +236,53 @@ namespace {
_MsStarter _msStarter;
}
bool ProxyData::valid() const {
if (type == Type::None || host.isEmpty() || !port) {
return false;
} else if (type == Type::Mtproto && !ValidSecret(password)) {
return false;
}
return true;
}
ProxyData::operator bool() const {
return valid();
}
bool ProxyData::operator==(const ProxyData &other) const {
if (!valid()) {
return !other.valid();
}
return (type == other.type)
&& (host == other.host)
&& (port == other.port)
&& (user == other.user)
&& (password == other.password);
}
bool ProxyData::operator!=(const ProxyData &other) const {
return !(*this == other);
}
bool ProxyData::ValidSecret(const QString &secret) {
return QRegularExpression("^[a-fA-F0-9]{32}$").match(secret).hasMatch();
}
QNetworkProxy ToNetworkProxy(const ProxyData &proxy) {
if (proxy.type == ProxyData::Type::None
|| proxy.type == ProxyData::Type::Mtproto) {
return QNetworkProxy::NoProxy;
}
return QNetworkProxy(
(proxy.type == ProxyData::Type::Socks5
? QNetworkProxy::Socks5Proxy
: QNetworkProxy::HttpProxy),
proxy.host,
proxy.port,
proxy.user,
proxy.password);
}
namespace ThirdParty {
void start() {

View File

@@ -420,19 +420,30 @@ enum DBIWorkMode {
dbiwmWindowOnly = 2,
};
enum DBIConnectionType {
dbictAuto = 0,
dbictHttpAuto = 1, // not used
dbictHttpProxy = 2,
dbictTcpProxy = 3,
};
struct ProxyData {
enum class Type {
None,
Socks5,
Http,
Mtproto,
};
Type type = Type::None;
QString host;
uint32 port = 0;
QString user, password;
bool valid() const;
explicit operator bool() const;
bool operator==(const ProxyData &other) const;
bool operator!=(const ProxyData &other) const;
static bool ValidSecret(const QString &secret);
};
QNetworkProxy ToNetworkProxy(const ProxyData &proxy);
enum DBIScale {
dbisAuto = 0,
dbisOne = 1,

View File

@@ -11,7 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#define BETA_VERSION_MACRO (0ULL)
constexpr int AppVersion = 1002012;
constexpr str_const AppVersionStr = "1.2.12";
constexpr int AppVersion = 1002018;
constexpr str_const AppVersionStr = "1.2.18";
constexpr bool AppAlphaVersion = true;
constexpr uint64 AppBetaVersion = BETA_VERSION_MACRO;

View File

@@ -205,6 +205,10 @@ bool Media::consumeMessageText(const TextWithEntities &text) {
return false;
}
TextWithEntities Media::consumedMessageText() const {
return {};
}
std::unique_ptr<HistoryMedia> Media::createView(
not_null<HistoryView::Element*> message) {
return createView(message, message->data());
@@ -482,8 +486,9 @@ QString MediaFile::chatsListText() const {
return lang(lng_in_dlg_video);
} else if (_document->isVoiceMessage()) {
return lang(lng_in_dlg_audio);
} else if (!_document->filename().isEmpty()) {
return _document->filename();
} else if (const auto name = _document->composeNameString();
!name.isEmpty()) {
return name;
} else if (_document->isAudioFile()) {
return lang(lng_in_dlg_audio_file);
}
@@ -907,6 +912,14 @@ std::unique_ptr<Media> MediaWebPage::clone(not_null<HistoryItem*> parent) {
return std::make_unique<MediaWebPage>(parent, _page);
}
DocumentData *MediaWebPage::document() const {
return _page->document;
}
PhotoData *MediaWebPage::photo() const {
return _page->photo;
}
WebPageData *MediaWebPage::webpage() const {
return _page;
}
@@ -1032,6 +1045,10 @@ bool MediaGame::consumeMessageText(const TextWithEntities &text) {
return true;
}
TextWithEntities MediaGame::consumedMessageText() const {
return _consumedText;
}
bool MediaGame::updateInlineResultMedia(const MTPMessageMedia &media) {
return updateSentMedia(media);
}

View File

@@ -100,6 +100,7 @@ public:
[[nodiscard]] virtual bool consumeMessageText(
const TextWithEntities &text);
[[nodiscard]] virtual TextWithEntities consumedMessageText() const;
// After sending an inline result we may want to completely recreate
// the media (all media that was generated on client side, for example).
@@ -292,6 +293,8 @@ public:
std::unique_ptr<Media> clone(not_null<HistoryItem*> parent) override;
DocumentData *document() const override;
PhotoData *photo() const override;
WebPageData *webpage() const override;
bool hasReplyPreview() const override;
@@ -332,6 +335,7 @@ public:
not_null<ChannelData*> channel) const override;
bool consumeMessageText(const TextWithEntities &text) override;
TextWithEntities consumedMessageText() const override;
bool updateInlineResultMedia(const MTPMessageMedia &media) override;
bool updateSentMedia(const MTPMessageMedia &media) override;

View File

@@ -114,28 +114,15 @@ MTPinputPeerNotifySettings NotifySettingsValue::serialize() const {
}
bool NotifySettings::change(const MTPPeerNotifySettings &settings) {
switch (settings.type()) {
case mtpc_peerNotifySettingsEmpty: {
if (!_known || _value) {
_known = true;
_value = nullptr;
return true;
}
return false;
} break;
Expects(settings.type() == mtpc_peerNotifySettings);
case mtpc_peerNotifySettings: {
auto &data = settings.c_peerNotifySettings();
if (_value) {
return _value->change(data);
}
_known = true;
_value = std::make_unique<NotifySettingsValue>(data);
return true;
} break;
auto &data = settings.c_peerNotifySettings();
if (_value) {
return _value->change(data);
}
Unexpected("Type in NotifySettings::change()");
_known = true;
_value = std::make_unique<NotifySettingsValue>(data);
return true;
}
NotifySettings::NotifySettings() = default;
@@ -152,18 +139,6 @@ bool NotifySettings::change(
if (_value) {
return _value->change(mute, silent, muteForSeconds);
}
const auto asEmpty = [&] {
if (mute == MuteChange::Mute) {
return false;
}
if (silent == SilentPostsChange::Silent) {
return false;
}
return true;
}();
if (asEmpty) {
return change(MTP_peerNotifySettingsEmpty());
}
const auto flags = MTPDpeerNotifySettings::Flag::f_show_previews
| ((silent == SilentPostsChange::Silent)
? MTPDpeerNotifySettings::Flag::f_silent

View File

@@ -435,7 +435,11 @@ void UserData::setName(const QString &newFirstName, const QString &newLastName,
}
void UserData::setPhone(const QString &newPhone) {
_phone = newPhone;
if (_phone != newPhone) {
_phone = newPhone;
if (bareId() == Auth().userId()) {
}
}
}
void UserData::setBotInfoVersion(int version) {

View File

@@ -34,7 +34,7 @@ inline auto SingleFlagValue(
return FlagsValueWithMask(
std::move(value),
flag
) | rpl::map([flag](typename ChangeType::Type value) {
) | rpl::map([](typename ChangeType::Type value) {
return !!value;
});
}

View File

@@ -256,6 +256,16 @@ rpl::producer<not_null<HistoryItem*>> Session::itemViewRefreshRequest() const {
return _itemViewRefreshRequest.events();
}
void Session::requestItemTextRefresh(not_null<HistoryItem*> item) {
if (const auto i = _views.find(item); i != _views.end()) {
for (const auto view : i->second) {
if (const auto media = view->media()) {
media->parentTextUpdated();
}
}
}
}
void Session::requestAnimationPlayInline(not_null<HistoryItem*> item) {
_animationPlayInlineRequest.fire_copy(item);
}
@@ -1248,7 +1258,7 @@ void Session::gameApplyFields(
const QString &description,
PhotoData *photo,
DocumentData *document) {
if (game->accessHash || !accessHash) {
if (game->accessHash) {
return;
}
game->accessHash = accessHash;

View File

@@ -80,6 +80,7 @@ public:
[[nodiscard]] rpl::producer<not_null<ViewElement*>> viewResizeRequest() const;
void requestItemViewRefresh(not_null<HistoryItem*> item);
[[nodiscard]] rpl::producer<not_null<HistoryItem*>> itemViewRefreshRequest() const;
void requestItemTextRefresh(not_null<HistoryItem*> item);
void requestAnimationPlayInline(not_null<HistoryItem*> item);
[[nodiscard]] rpl::producer<not_null<HistoryItem*>> animationPlayInlineRequest() const;
void notifyHistoryUnloaded(not_null<const History*> history);
@@ -468,6 +469,7 @@ private:
rpl::event_stream<not_null<const HistoryItem*>> _itemResizeRequest;
rpl::event_stream<not_null<ViewElement*>> _viewResizeRequest;
rpl::event_stream<not_null<HistoryItem*>> _itemViewRefreshRequest;
rpl::event_stream<not_null<HistoryItem*>> _itemTextRefreshRequest;
rpl::event_stream<not_null<HistoryItem*>> _animationPlayInlineRequest;
rpl::event_stream<not_null<const HistoryItem*>> _itemRemoved;
rpl::event_stream<not_null<const ViewElement*>> _viewRemoved;

View File

@@ -95,7 +95,7 @@ DialogsInner::DialogsInner(QWidget *parent, not_null<Window::Controller*> contro
[this](auto item) { itemRemoved(item); },
lifetime());
Auth().data().itemRepaintRequest(
) | rpl::start_with_next([this](auto item) {
) | rpl::start_with_next([=](auto item) {
const auto history = item->history();
if (history->textCachedFor == item) {
history->updateChatListEntry();
@@ -114,7 +114,7 @@ DialogsInner::DialogsInner(QWidget *parent, not_null<Window::Controller*> contro
UpdateRowSection::Default | UpdateRowSection::Filtered);
});
subscribe(Window::Theme::Background(), [this](const Window::Theme::BackgroundUpdate &data) {
subscribe(Window::Theme::Background(), [=](const Window::Theme::BackgroundUpdate &data) {
if (data.paletteChanged()) {
Dialogs::Layout::clearUnreadBadgesCache();
}

View File

@@ -20,7 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "application.h"
#include "mainwindow.h"
#include "mainwidget.h"
#include "autoupdater.h"
#include "core/update_checker.h"
#include "auth_session.h"
#include "apiwrap.h"
#include "messenger.h"
@@ -119,10 +119,15 @@ DialogsWidget::DialogsWidget(QWidget *parent, not_null<Window::Controller*> cont
connect(_filter, SIGNAL(cursorPositionChanged(int,int)), this, SLOT(onFilterCursorMoved(int,int)));
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
Sandbox::connect(SIGNAL(updateLatest()), this, SLOT(onCheckUpdateStatus()));
Sandbox::connect(SIGNAL(updateFailed()), this, SLOT(onCheckUpdateStatus()));
Sandbox::connect(SIGNAL(updateReady()), this, SLOT(onCheckUpdateStatus()));
onCheckUpdateStatus();
Core::UpdateChecker checker;
rpl::merge(
rpl::single(rpl::empty_value()),
checker.isLatest(),
checker.failed(),
checker.ready()
) | rpl::start_with_next([=] {
checkUpdateStatus();
}, lifetime());
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
subscribe(Adaptive::Changed(), [this] { updateForwardBar(); });
@@ -168,13 +173,14 @@ DialogsWidget::DialogsWidget(QWidget *parent, not_null<Window::Controller*> cont
}
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
void DialogsWidget::onCheckUpdateStatus() {
if (Sandbox::updatingState() == Application::UpdatingReady) {
void DialogsWidget::checkUpdateStatus() {
using Checker = Core::UpdateChecker;
if (Checker().state() == Checker::State::Ready) {
if (_updateTelegram) return;
_updateTelegram.create(this);
_updateTelegram->show();
_updateTelegram->setClickedCallback([] {
checkReadyUpdate();
Core::checkReadyUpdate();
App::restart();
});
} else {

View File

@@ -120,10 +120,6 @@ public slots:
private slots:
void onDraggingScrollTimer();
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
void onCheckUpdateStatus();
#endif // TDESKTOP_DISABLE_AUTOUPDATE
protected:
void dragEnterEvent(QDragEnterEvent *e) override;
void dragMoveEvent(QDragMoveEvent *e) override;
@@ -167,6 +163,10 @@ private:
void updateControlsGeometry();
void updateForwardBar();
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
void checkUpdateStatus();
#endif // TDESKTOP_DISABLE_AUTOUPDATE
bool dialogsFailed(const RPCError &error, mtpRequestId req);
bool searchFailed(DialogsSearchRequestType type, const RPCError &error, mtpRequestId req);
bool peopleFailed(const RPCError &error, mtpRequestId req);

View File

@@ -396,8 +396,8 @@ bool CheckBetaVersionDir() {
quint64 v;
QByteArray k;
dataStream >> v >> k;
if (dataStream.status() == QDataStream::Ok) {
cSetBetaVersion(qMax(v, AppVersion * 1000ULL));
if (dataStream.status() == QDataStream::Ok && !k.isEmpty()) {
cSetBetaVersion(AppVersion * 1000ULL);
cSetBetaPrivateKey(k);
cSetRealBetaVersion(v);
} else {
@@ -528,6 +528,7 @@ struct Data {
int32 CallConnectTimeoutMs = 30000;
int32 CallPacketTimeoutMs = 10000;
bool PhoneCallsEnabled = true;
bool BlockedMode = false;
base::Observable<void> PhoneCallsEnabledChanged;
HiddenPinnedMessagesMap HiddenPinnedMessages;
@@ -552,6 +553,7 @@ struct Data {
QByteArray DownloadPathBookmark;
base::Observable<void> DownloadPathChanged;
bool SuggestStickersByEmoji = true;
bool SoundNotify = true;
bool DesktopNotify = true;
bool RestoreSoundNotifyFromTray = false;
@@ -562,10 +564,10 @@ struct Data {
Notify::ScreenCorner NotificationsCorner = Notify::ScreenCorner::BottomRight;
bool NotificationsDemoIsShown = false;
DBIConnectionType ConnectionType = dbictAuto;
DBIConnectionType LastProxyType = dbictAuto;
bool TryIPv6 = (cPlatform() == dbipWindows) ? false : true;
ProxyData ConnectionProxy;
std::vector<ProxyData> ProxiesList;
ProxyData SelectedProxy;
bool UseProxy = false;
base::Observable<void> ConnectionTypeChanged;
int AutoLock = 3600;
@@ -650,6 +652,7 @@ DefineVar(Global, int32, CallRingTimeoutMs);
DefineVar(Global, int32, CallConnectTimeoutMs);
DefineVar(Global, int32, CallPacketTimeoutMs);
DefineVar(Global, bool, PhoneCallsEnabled);
DefineVar(Global, bool, BlockedMode);
DefineRefVar(Global, base::Observable<void>, PhoneCallsEnabledChanged);
DefineVar(Global, HiddenPinnedMessagesMap, HiddenPinnedMessages);
@@ -674,6 +677,7 @@ DefineVar(Global, QString, DownloadPath);
DefineVar(Global, QByteArray, DownloadPathBookmark);
DefineRefVar(Global, base::Observable<void>, DownloadPathChanged);
DefineVar(Global, bool, SuggestStickersByEmoji);
DefineVar(Global, bool, SoundNotify);
DefineVar(Global, bool, DesktopNotify);
DefineVar(Global, bool, RestoreSoundNotifyFromTray);
@@ -684,10 +688,10 @@ DefineVar(Global, int, NotificationsCount);
DefineVar(Global, Notify::ScreenCorner, NotificationsCorner);
DefineVar(Global, bool, NotificationsDemoIsShown);
DefineVar(Global, DBIConnectionType, ConnectionType);
DefineVar(Global, DBIConnectionType, LastProxyType);
DefineVar(Global, bool, TryIPv6);
DefineVar(Global, ProxyData, ConnectionProxy);
DefineVar(Global, std::vector<ProxyData>, ProxiesList);
DefineVar(Global, ProxyData, SelectedProxy);
DefineVar(Global, bool, UseProxy);
DefineRefVar(Global, base::Observable<void>, ConnectionTypeChanged);
DefineVar(Global, int, AutoLock);

View File

@@ -345,6 +345,7 @@ DeclareVar(int32, CallRingTimeoutMs);
DeclareVar(int32, CallConnectTimeoutMs);
DeclareVar(int32, CallPacketTimeoutMs);
DeclareVar(bool, PhoneCallsEnabled);
DeclareVar(bool, BlockedMode);
DeclareRefVar(base::Observable<void>, PhoneCallsEnabledChanged);
typedef QMap<PeerId, MsgId> HiddenPinnedMessagesMap;
@@ -360,6 +361,7 @@ DeclareVar(QString, DownloadPath);
DeclareVar(QByteArray, DownloadPathBookmark);
DeclareRefVar(base::Observable<void>, DownloadPathChanged);
DeclareVar(bool, SuggestStickersByEmoji);
DeclareVar(bool, SoundNotify);
DeclareVar(bool, DesktopNotify);
DeclareVar(bool, RestoreSoundNotifyFromTray);
@@ -370,10 +372,10 @@ DeclareVar(int, NotificationsCount);
DeclareVar(Notify::ScreenCorner, NotificationsCorner);
DeclareVar(bool, NotificationsDemoIsShown);
DeclareVar(DBIConnectionType, ConnectionType);
DeclareVar(DBIConnectionType, LastProxyType);
DeclareVar(std::vector<ProxyData>, ProxiesList);
DeclareVar(ProxyData, SelectedProxy);
DeclareVar(bool, UseProxy);
DeclareVar(bool, TryIPv6);
DeclareVar(ProxyData, ConnectionProxy);
DeclareRefVar(base::Observable<void>, ConnectionTypeChanged);
DeclareVar(int, AutoLock);

View File

@@ -531,6 +531,9 @@ void InnerWidget::saveState(not_null<SectionMemento*> memento) {
void InnerWidget::restoreState(not_null<SectionMemento*> memento) {
_items = memento->takeItems();
for (auto &item : _items) {
item.refreshView(this);
}
_itemsByIds = memento->takeItemsByIds();
if (auto manager = memento->takeIdManager()) {
_idManager = std::move(manager);
@@ -1190,7 +1193,7 @@ void InnerWidget::suggestRestrictUser(not_null<UserData*> user) {
MTP_int(0));
editRestrictions(hasAdminRights, bannedRights);
}
}).fail([this, editRestrictions](const RPCError &error) {
}).fail([=](const RPCError &error) {
auto bannedRights = MTP_channelBannedRights(
MTP_flags(0),
MTP_int(0));

View File

@@ -195,9 +195,9 @@ auto GenerateBannedChangeText(const TextWithEntities &user, const MTPChannelBann
lt_date,
langDateTime(ParseDateTime(newUntil)));
auto result = lng_admin_log_restricted__generic(
lt_user,
user,
lt_until,
lt_user,
user,
lt_until,
TextWithEntities { untilText });
static auto phraseMap = std::map<Flags, LangKey> {
@@ -317,6 +317,11 @@ OwnedItem::~OwnedItem() {
}
}
void OwnedItem::refreshView(
not_null<HistoryView::ElementDelegate*> delegate) {
_view = _data->createView(delegate);
}
void GenerateItems(
not_null<HistoryView::ElementDelegate*> delegate,
not_null<History*> history,

View File

@@ -46,6 +46,8 @@ public:
return get();
}
void refreshView(not_null<HistoryView::ElementDelegate*> delegate);
private:
HistoryItem *_data = nullptr;
std::unique_ptr<HistoryView::Element> _view;

View File

@@ -261,7 +261,7 @@ Widget::Widget(QWidget *parent, not_null<Window::Controller*> controller, not_nu
connect(_scroll, &Ui::ScrollArea::scrolled, this, [this] { onScroll(); });
_whatIsThis->setClickedCallback([this] { Ui::show(Box<InformBox>(lang(lng_admin_log_about_text))); });
_whatIsThis->setClickedCallback([=] { Ui::show(Box<InformBox>(lang(lng_admin_log_about_text))); });
}
void Widget::showFilter() {

View File

@@ -1732,7 +1732,7 @@ void HistoryInner::savePhotoToFile(not_null<PhotoData*> photo) {
filedialogDefaultName(
qsl("photo"),
qsl(".jpg")),
base::lambda_guarded(this, [this, photo](const QString &result) {
base::lambda_guarded(this, [=](const QString &result) {
if (!result.isEmpty()) {
photo->full->pix().toImage().save(result, "JPG");
}

View File

@@ -372,8 +372,8 @@ bool HistoryItem::canDeleteForEveryone(TimeId now) const {
const auto messageTooOld = messageToMyself
? false
: peer->isUser()
? (now >= date() + Global::RevokePrivateTimeLimit())
: (now >= date() + Global::RevokeTimeLimit());
? (now - date() >= Global::RevokePrivateTimeLimit())
: (now - date() >= Global::RevokeTimeLimit());
if (id < 0 || messageToMyself || messageTooOld || isPost()) {
return false;
}

View File

@@ -48,12 +48,6 @@ void initLocationManager() {
}
}
void reinitLocationManager() {
if (locationManager) {
locationManager->reinit();
}
}
void deinitLocationManager() {
if (locationManager) {
locationManager->deinit();
@@ -65,7 +59,6 @@ void deinitLocationManager() {
void LocationManager::init() {
if (manager) delete manager;
manager = new QNetworkAccessManager();
App::setProxySettings(*manager);
connect(manager, SIGNAL(authenticationRequired(QNetworkReply*, QAuthenticator*)), this, SLOT(onFailed(QNetworkReply*)));
#ifndef OS_MAC_OLD
@@ -83,10 +76,6 @@ void LocationManager::init() {
notLoadedPlaceholder = new ImagePtr(App::pixmapFromImageInPlace(std::move(data)), "GIF");
}
void LocationManager::reinit() {
if (manager) App::setProxySettings(*manager);
}
void LocationManager::deinit() {
if (manager) {
delete manager;

View File

@@ -8,7 +8,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once
void initLocationManager();
void reinitLocationManager();
void deinitLocationManager();
class LocationCoords {

View File

@@ -222,6 +222,8 @@ public:
// Should be called only by Data::Session.
virtual void updateSharedContactUserId(UserId userId) {
}
virtual void parentTextUpdated() {
}
virtual ~HistoryMedia() = default;

View File

@@ -13,12 +13,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/view/history_view_element.h"
#include "history/view/history_view_cursor_state.h"
#include "data/data_media_types.h"
#include "data/data_session.h"
#include "storage/storage_shared_media.h"
#include "lang/lang_keys.h"
#include "ui/grouped_layout.h"
#include "ui/text_options.h"
#include "styles/style_history.h"
#include "auth_session.h"
#include "layout.h"
#include "styles/style_history.h"
namespace {
@@ -391,6 +393,10 @@ void HistoryGroupedMedia::updateNeedBubbleState() {
_needBubble = computeNeedBubble();
}
void HistoryGroupedMedia::parentTextUpdated() {
Auth().data().requestViewResize(_parent);
}
bool HistoryGroupedMedia::needsBubble() const {
return _needBubble;
}

View File

@@ -79,6 +79,8 @@ public:
return true;
}
void parentTextUpdated() override;
private:
struct Part {
Part(not_null<HistoryItem*> item);

View File

@@ -681,6 +681,13 @@ bool HistoryPhoto::needsBubble() const {
return false;
}
void HistoryPhoto::parentTextUpdated() {
_caption = (_parent->media() == this)
? createCaption(_parent->data())
: Text();
Auth().data().requestViewResize(_parent);
}
HistoryVideo::HistoryVideo(
not_null<Element*> parent,
not_null<HistoryItem*> realParent,
@@ -1112,6 +1119,13 @@ bool HistoryVideo::needsBubble() const {
return false;
}
void HistoryVideo::parentTextUpdated() {
_caption = (_parent->media() == this)
? createCaption(_parent->data())
: Text();
Auth().data().requestViewResize(_parent);
}
void HistoryVideo::updateStatusText() const {
auto showPause = false;
auto statusSize = 0;
@@ -1832,6 +1846,20 @@ void HistoryDocument::refreshParentId(not_null<HistoryItem*> realParent) {
}
}
void HistoryDocument::parentTextUpdated() {
auto caption = (_parent->media() == this)
? createCaption(_parent->data())
: Text();
if (!caption.isEmpty()) {
AddComponents(HistoryDocumentCaptioned::Bit());
auto captioned = Get<HistoryDocumentCaptioned>();
captioned->_caption = std::move(caption);
} else {
RemoveComponents(HistoryDocumentCaptioned::Bit());
}
Auth().data().requestViewResize(_parent);
}
TextWithEntities HistoryDocument::getCaption() const {
if (const auto captioned = Get<HistoryDocumentCaptioned>()) {
return captioned->_caption.originalTextWithEntities();
@@ -2535,6 +2563,15 @@ void HistoryGif::updateStatusText() const {
}
}
void HistoryGif::refreshParentId(not_null<HistoryItem*> realParent) {
HistoryFileMedia::refreshParentId(realParent);
const auto fullId = realParent->fullId();
if (_openInMediaviewLink) {
_openInMediaviewLink->setMessageId(fullId);
}
}
QString HistoryGif::additionalInfoString() const {
if (_data->isVideoMessage()) {
updateStatusText();
@@ -2543,6 +2580,13 @@ QString HistoryGif::additionalInfoString() const {
return QString();
}
void HistoryGif::parentTextUpdated() {
_caption = (_parent->media() == this)
? createCaption(_parent->data())
: Text();
Auth().data().requestViewResize(_parent);
}
int HistoryGif::additionalWidth(const HistoryMessageVia *via, const HistoryMessageReply *reply, const HistoryMessageForwarded *forwarded) const {
int result = 0;
if (forwarded) {
@@ -4177,6 +4221,21 @@ int HistoryGame::bottomInfoPadding() const {
return result;
}
void HistoryGame::parentTextUpdated() {
if (const auto media = _parent->data()->media()) {
const auto consumed = media->consumedMessageText();
if (!consumed.text.isEmpty()) {
_description.setMarkedText(
st::webPageDescriptionStyle,
consumed,
Ui::ItemTextOptions(_parent->data()));
} else {
_description = Text(st::msgMinWidth - st::webPageLeft);
}
Auth().data().requestViewResize(_parent);
}
}
HistoryGame::~HistoryGame() {
Auth().data().unregisterGameView(_data, _parent);
}

View File

@@ -190,6 +190,8 @@ public:
return _data->loaded();
}
void parentTextUpdated() override;
protected:
float64 dataProgress() const override;
bool dataFinished() const override;
@@ -278,6 +280,8 @@ public:
return isBubbleBottom() && _caption.isEmpty();
}
void parentTextUpdated() override;
protected:
float64 dataProgress() const override;
bool dataFinished() const override;
@@ -354,6 +358,7 @@ public:
void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override;
void refreshParentId(not_null<HistoryItem*> realParent) override;
void parentTextUpdated() override;
protected:
float64 dataProgress() const override;
@@ -384,6 +389,8 @@ public:
return MediaTypeGif;
}
void refreshParentId(not_null<HistoryItem*> realParent) override;
void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const override;
TextState textState(QPoint point, StateRequest request) const override;
@@ -427,6 +434,8 @@ public:
return _data->loaded();
}
void parentTextUpdated() override;
~HistoryGif();
protected:
@@ -459,7 +468,7 @@ private:
bool isSeparateRoundVideo() const;
not_null<DocumentData*> _data;
ClickHandlerPtr _openInMediaviewLink;
FileClickHandlerPtr _openInMediaviewLink;
int _thumbw = 1;
int _thumbh = 1;
Text _caption;
@@ -796,6 +805,8 @@ public:
return _attach.get();
}
void parentTextUpdated() override;
~HistoryGame();
private:

View File

@@ -590,7 +590,7 @@ bool HistoryMessage::allowsEdit(TimeId now) const {
}();
const auto messageTooOld = (messageToMyself || canPinInMegagroup)
? false
: (now >= date() + Global::EditTimeLimit());
: (now - date() >= Global::EditTimeLimit());
if (id < 0 || messageTooOld) {
return false;
}
@@ -890,10 +890,10 @@ void HistoryMessage::applyEdition(const MTPDmessage &message) {
if (message.has_entities()) {
textWithEntities.entities = TextUtilities::EntitiesFromMTP(message.ventities.v);
}
setText(textWithEntities);
setReplyMarkup(message.has_reply_markup() ? (&message.vreply_markup) : nullptr);
refreshMedia(message.has_media() ? (&message.vmedia) : nullptr);
setViewsCount(message.has_views() ? message.vviews.v : -1);
setText(textWithEntities);
finishEdition(keyboardTop);
}
@@ -905,9 +905,9 @@ void HistoryMessage::applyEdition(const MTPDmessageService &message) {
}
void HistoryMessage::applyEditionToEmpty() {
setEmptyText();
refreshMedia(nullptr);
setReplyMarkup(nullptr);
refreshMedia(nullptr);
setEmptyText();
setViewsCount(-1);
finishEditionToEmpty();
@@ -957,7 +957,9 @@ Storage::SharedMediaTypesMask HistoryMessage::sharedMediaTypes() const {
void HistoryMessage::setText(const TextWithEntities &textWithEntities) {
for_const (auto &entity, textWithEntities.entities) {
auto type = entity.type();
if (type == EntityInTextUrl || type == EntityInTextCustomUrl || type == EntityInTextEmail) {
if (type == EntityInTextUrl
|| type == EntityInTextCustomUrl
|| type == EntityInTextEmail) {
_flags |= MTPDmessage_ClientFlag::f_has_text_links;
break;
}
@@ -970,6 +972,14 @@ void HistoryMessage::setText(const TextWithEntities &textWithEntities) {
st::messageTextStyle,
textWithEntities,
Ui::ItemTextOptions(this));
if (!textWithEntities.text.isEmpty() && _text.isEmpty()) {
// If server has allowed some text that we've trim-ed entirely,
// just replace it with something so that UI won't look buggy.
_text.setMarkedText(
st::messageTextStyle,
{ QString::fromUtf8("\xF0\x9F\x98\x94"), EntitiesInText() },
Ui::ItemTextOptions(this));
}
_textWidth = -1;
_textHeight = 0;
}

View File

@@ -573,8 +573,16 @@ HistoryWidget::HistoryWidget(
updateHistoryGeometry();
}
}, lifetime());
Auth().data().animationPlayInlineRequest(
Auth().data().itemViewRefreshRequest(
) | rpl::start_with_next([this](auto item) {
// While HistoryInner doesn't own item views we must refresh them
// even if the list is not yet created / was destroyed.
if (!_list) {
item->refreshMainView();
}
}, lifetime());
Auth().data().animationPlayInlineRequest(
) | rpl::start_with_next([=](auto item) {
if (const auto view = item->mainView()) {
if (const auto media = view->media()) {
media->playAnimation();
@@ -1770,6 +1778,7 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re
if (_peer) {
App::forgetMedia();
Auth().data().forgetMedia();
_serviceImageCacheSize = imageCacheSize();
Auth().downloader().clearPriorities();
@@ -2972,32 +2981,11 @@ void HistoryWidget::onBotStart() {
}
void HistoryWidget::onJoinChannel() {
if (_unblockRequest) return;
if (!_peer || !_peer->isChannel() || !isJoinChannel()) {
updateControlsVisibility();
return;
}
_unblockRequest = MTP::send(MTPchannels_JoinChannel(_peer->asChannel()->inputChannel), rpcDone(&HistoryWidget::joinDone), rpcFail(&HistoryWidget::joinFail));
}
void HistoryWidget::joinDone(const MTPUpdates &result, mtpRequestId req) {
if (_unblockRequest == req) _unblockRequest = 0;
if (App::main()) App::main()->sentUpdatesReceived(result);
}
bool HistoryWidget::joinFail(const RPCError &error, mtpRequestId req) {
if (MTP::isDefaultHandledError(error)) return false;
if (_unblockRequest == req) _unblockRequest = 0;
if (error.type() == qstr("CHANNEL_PRIVATE") || error.type() == qstr("CHANNEL_PUBLIC_GROUP_NA") || error.type() == qstr("USER_BANNED_IN_CHANNEL")) {
Ui::show(Box<InformBox>(lang((_peer && _peer->isMegagroup()) ? lng_group_not_accessible : lng_channel_not_accessible)));
return true;
} else if (error.type() == qstr("CHANNELS_TOO_MUCH")) {
Ui::show(Box<InformBox>(lang(lng_join_channel_error)));
}
return false;
Auth().api().joinChannel(_peer->asChannel());
}
void HistoryWidget::onMuteUnmute() {

View File

@@ -683,9 +683,6 @@ private:
bool unblockFail(const RPCError &error, mtpRequestId req);
void blockDone(PeerData *peer, const MTPBool &result);
void joinDone(const MTPUpdates &result, mtpRequestId req);
bool joinFail(const RPCError &error, mtpRequestId req);
void countHistoryShowFrom();
enum class TextUpdateEvent {

View File

@@ -386,8 +386,10 @@ void TopBarWidget::refreshInfoButton() {
Ui::UserpicButton::Role::Custom,
st::topBarInfoButton);
info->showSavedMessagesOnSelf(true);
_info.destroy();
_info = std::move(info);
} else if (const auto feed = _activeChat.feed()) {
_info.destroy();
_info = object_ptr<Ui::FeedUserpicButton>(
this,
_controller,

View File

@@ -107,7 +107,8 @@ std::unique_ptr<Result> Result::create(uint64 queryId, const MTPBotInlineResult
message = &r.vsend_message;
} break;
}
bool badAttachment = (result->_photo && !result->_photo->access) || (result->_document && !result->_document->isValid());
auto badAttachment = (result->_photo && result->_photo->full->isNull())
|| (result->_document && !result->_document->isValid());
if (!message) {
return nullptr;

View File

@@ -443,7 +443,7 @@ int Inner::refreshInlineRows(PeerData *queryPeer, UserData *bot, const CacheEntr
_inlineBot = bot;
_inlineQueryPeer = queryPeer;
refreshSwitchPmButton(entry);
auto clearResults = [this, entry]() {
auto clearResults = [&] {
if (!entry) {
return true;
}

View File

@@ -148,6 +148,7 @@ void PhoneWidget::submit() {
_checkRequest->start(1000);
_sentPhone = fullNumber();
Messenger::Instance().mtp()->setUserPhone(_sentPhone);
_sentRequest = MTP::send(MTPauth_CheckPhone(MTP_string(_sentPhone)), rpcDone(&PhoneWidget::phoneCheckDone), rpcFail(&PhoneWidget::phoneSubmitFail));
}

View File

@@ -26,7 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/labels.h"
#include "ui/wrap/fade_wrap.h"
#include "ui/effects/slide_animation.h"
#include "autoupdater.h"
#include "core/update_checker.h"
#include "window/window_slide_animation.h"
#include "styles/style_boxes.h"
#include "styles/style_intro.h"
@@ -42,7 +42,7 @@ constexpr str_const kDefaultCountry = "US";
} // namespace
Widget::Widget(QWidget *parent) : TWidget(parent)
Widget::Widget(QWidget *parent) : RpWidget(parent)
, _back(this, object_ptr<Ui::IconButton>(this, st::introBackButton))
, _settings(
this,
@@ -82,10 +82,17 @@ Widget::Widget(QWidget *parent) : TWidget(parent)
cSetPasswordRecovered(false);
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
Sandbox::connect(SIGNAL(updateLatest()), this, SLOT(onCheckUpdateStatus()));
Sandbox::connect(SIGNAL(updateFailed()), this, SLOT(onCheckUpdateStatus()));
Sandbox::connect(SIGNAL(updateReady()), this, SLOT(onCheckUpdateStatus()));
Sandbox::startUpdateCheck();
Core::UpdateChecker checker;
checker.isLatest() | rpl::start_with_next([=] {
onCheckUpdateStatus();
}, lifetime());
checker.failed() | rpl::start_with_next([=] {
onCheckUpdateStatus();
}, lifetime());
checker.ready() | rpl::start_with_next([=] {
onCheckUpdateStatus();
}, lifetime());
checker.start();
onCheckUpdateStatus();
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
}
@@ -104,7 +111,7 @@ void Widget::createLanguageLink() {
this,
object_ptr<Ui::LinkButton>(this, text));
_changeLanguage->hide(anim::type::instant);
_changeLanguage->entity()->setClickedCallback([this, languageId] {
_changeLanguage->entity()->setClickedCallback([=] {
Lang::CurrentCloudManager().switchToLanguage(languageId);
});
_changeLanguage->toggle(!_resetAccount, anim::type::normal);
@@ -117,7 +124,10 @@ void Widget::createLanguageLink() {
if (!currentId.isEmpty() && currentId != defaultId) {
createLink(Lang::GetOriginalValue(lng_switch_to_this), defaultId);
} else if (!suggestedId.isEmpty() && suggestedId != currentId) {
request(MTPlangpack_GetStrings(MTP_string(suggestedId), MTP_vector<MTPstring>(1, MTP_string("lng_switch_to_this")))).done([this, suggestedId, createLink](const MTPVector<MTPLangPackString> &result) {
request(MTPlangpack_GetStrings(
MTP_string(suggestedId),
MTP_vector<MTPstring>(1, MTP_string("lng_switch_to_this"))
)).done([=](const MTPVector<MTPLangPackString> &result) {
auto strings = Lang::Instance::ParseStrings(result);
auto it = strings.find(lng_switch_to_this);
if (it != strings.end()) {
@@ -129,7 +139,7 @@ void Widget::createLanguageLink() {
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
void Widget::onCheckUpdateStatus() {
if (Sandbox::updatingState() == Application::UpdatingReady) {
if (Core::UpdateChecker().state() == Core::UpdateChecker::State::Ready) {
if (_update) return;
_update.create(
this,
@@ -141,7 +151,7 @@ void Widget::onCheckUpdateStatus() {
_update->setVisible(true);
}
_update->entity()->setClickedCallback([] {
checkReadyUpdate();
Core::checkReadyUpdate();
App::restart();
});
} else {

View File

@@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once
#include "mtproto/sender.h"
#include "ui/rp_widget.h"
namespace Ui {
class IconButton;
@@ -22,7 +23,7 @@ class FadeWrap;
namespace Intro {
class Widget : public TWidget, private MTP::Sender, private base::Subscriber {
class Widget : public Ui::RpWidget, private MTP::Sender, private base::Subscriber {
Q_OBJECT
public:

View File

@@ -74,6 +74,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "window/themes/window_theme.h"
#include "mtproto/dc_options.h"
#include "core/file_utilities.h"
#include "core/update_checker.h"
#include "calls/calls_instance.h"
#include "calls/calls_top_bar.h"
#include "auth_session.h"
@@ -323,7 +324,8 @@ MainWidget::MainWidget(
orderWidgets();
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
Sandbox::startUpdateCheck();
Core::UpdateChecker checker;
checker.start();
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
}
@@ -704,7 +706,7 @@ void MainWidget::finishForwarding(not_null<History*> history) {
}
void MainWidget::updateMutedIn(TimeMs delay) {
accumulate_max(delay, 24 * 3600 * 1000LL);
accumulate_min(delay, 24 * 3600 * 1000LL);
if (!_updateMutedTimer.isActive()
|| _updateMutedTimer.remainingTime() > delay) {
_updateMutedTimer.start(delay);
@@ -911,7 +913,7 @@ void MainWidget::cancelUploadLayer(not_null<HistoryItem*> item) {
void MainWidget::deletePhotoLayer(PhotoData *photo) {
if (!photo) return;
Ui::show(Box<ConfirmBox>(lang(lng_delete_photo_sure), lang(lng_box_delete), base::lambda_guarded(this, [this, photo] {
Ui::show(Box<ConfirmBox>(lang(lng_delete_photo_sure), lang(lng_box_delete), base::lambda_guarded(this, [=] {
Ui::hideLayer();
auto me = App::self();
@@ -1665,12 +1667,12 @@ void MainWidget::documentLoadFailed(FileLoader *loader, bool started) {
auto document = Auth().data().document(documentId);
if (started) {
auto failedFileName = loader->fileName();
Ui::show(Box<ConfirmBox>(lang(lng_download_finish_failed), base::lambda_guarded(this, [this, document, failedFileName] {
Ui::show(Box<ConfirmBox>(lang(lng_download_finish_failed), base::lambda_guarded(this, [=] {
Ui::hideLayer();
if (document) document->save(failedFileName);
})));
} else {
Ui::show(Box<ConfirmBox>(lang(lng_download_path_failed), lang(lng_download_path_settings), base::lambda_guarded(this, [this] {
Ui::show(Box<ConfirmBox>(lang(lng_download_path_failed), lang(lng_download_path_settings), base::lambda_guarded(this, [=] {
Global::SetDownloadPath(QString());
Global::SetDownloadPathBookmark(QByteArray());
Ui::show(Box<DownloadPathBox>());

View File

@@ -99,9 +99,9 @@ void ConnectingWidget::paintEvent(QPaintEvent *e) {
}
void ConnectingWidget::onReconnect() {
auto throughProxy = (Global::ConnectionType() != dbictAuto);
if (throughProxy) {
Ui::show(Box<ConnectionBox>());
if (Global::UseProxy()) {
//Ui::show(Box<ConnectionBox>());
Ui::show(ProxiesBoxController::CreateOwningBox());
} else {
MTP::restart();
}
@@ -408,8 +408,8 @@ void MainWindow::mtpStateChanged(int32 dc, int32 state) {
}
void MainWindow::updateConnectingStatus() {
auto state = MTP::dcstate();
auto throughProxy = (Global::ConnectionType() != dbictAuto);
const auto state = MTP::dcstate();
const auto throughProxy = Global::UseProxy();
if (state == MTP::ConnectingState || state == MTP::DisconnectedState || (state < 0 && state > -600)) {
if (_main || getms() > 5000 || _connecting) {
showConnecting(lang(throughProxy ? lng_connecting_to_proxy : lng_connecting), throughProxy ? lang(lng_connecting_settings) : QString());

View File

@@ -76,47 +76,47 @@ CoverWidget::CoverWidget(QWidget *parent) : RpWidget(parent)
_timeLabel->setAttribute(Qt::WA_TransparentForMouseEvents);
setMouseTracking(true);
_playback->setInLoadingStateChangedCallback([this](bool loading) {
_playback->setInLoadingStateChangedCallback([=](bool loading) {
_playbackSlider->setDisabled(loading);
});
_playback->setValueChangedCallback([this](float64 value) {
_playback->setValueChangedCallback([=](float64 value) {
_playbackSlider->setValue(value);
});
_playbackSlider->setChangeProgressCallback([this](float64 value) {
_playbackSlider->setChangeProgressCallback([=](float64 value) {
_playback->setValue(value, false);
handleSeekProgress(value);
});
_playbackSlider->setChangeFinishedCallback([this](float64 value) {
_playbackSlider->setChangeFinishedCallback([=](float64 value) {
_playback->setValue(value, false);
handleSeekFinished(value);
});
_playPause->setClickedCallback([this] {
_playPause->setClickedCallback([=] {
instance()->playPauseCancelClicked(AudioMsgId::Type::Song);
});
updateRepeatTrackIcon();
_repeatTrack->setClickedCallback([this] {
_repeatTrack->setClickedCallback([=] {
instance()->toggleRepeat(AudioMsgId::Type::Song);
});
updateVolumeToggleIcon();
_volumeToggle->setClickedCallback([this]() {
_volumeToggle->setClickedCallback([=]() {
Global::SetSongVolume((Global::SongVolume() > 0) ? 0. : Global::RememberedSongVolume());
mixer()->setSongVolume(Global::SongVolume());
Global::RefSongVolumeChanged().notify();
});
subscribe(Global::RefSongVolumeChanged(), [this] { updateVolumeToggleIcon(); });
subscribe(instance()->repeatChangedNotifier(), [this](AudioMsgId::Type type) {
subscribe(Global::RefSongVolumeChanged(), [=] { updateVolumeToggleIcon(); });
subscribe(instance()->repeatChangedNotifier(), [=](AudioMsgId::Type type) {
if (type == AudioMsgId::Type::Song) {
updateRepeatTrackIcon();
}
});
subscribe(instance()->updatedNotifier(), [this](const TrackState &state) {
subscribe(instance()->updatedNotifier(), [=](const TrackState &state) {
if (state.id.type() == AudioMsgId::Type::Song) {
handleSongUpdate(state);
}
});
subscribe(instance()->trackChangedNotifier(), [this](AudioMsgId::Type type) {
subscribe(instance()->trackChangedNotifier(), [=](AudioMsgId::Type type) {
if (type == AudioMsgId::Type::Song) {
handleSongChange();
}
@@ -353,12 +353,12 @@ void CoverWidget::createPrevNextButtons() {
if (!_previousTrack) {
_previousTrack.create(this, st::mediaPlayerPanelPreviousButton);
_previousTrack->show();
_previousTrack->setClickedCallback([this]() {
_previousTrack->setClickedCallback([=]() {
instance()->previous();
});
_nextTrack.create(this, st::mediaPlayerPanelNextButton);
_nextTrack->show();
_nextTrack->setClickedCallback([this]() {
_nextTrack->setClickedCallback([=]() {
instance()->next();
});
updatePlayPrevNextPositions();

View File

@@ -116,7 +116,7 @@ Widget::Widget(QWidget *parent) : RpWidget(parent)
});
updateVolumeToggleIcon();
_volumeToggle->setClickedCallback([this] {
_volumeToggle->setClickedCallback([=] {
Global::SetSongVolume((Global::SongVolume() > 0) ? 0. : Global::RememberedSongVolume());
mixer()->setSongVolume(Global::SongVolume());
Global::RefSongVolumeChanged().notify();
@@ -124,7 +124,7 @@ Widget::Widget(QWidget *parent) : RpWidget(parent)
subscribe(Global::RefSongVolumeChanged(), [this] { updateVolumeToggleIcon(); });
updateRepeatTrackIcon();
_repeatTrack->setClickedCallback([this] {
_repeatTrack->setClickedCallback([=] {
instance()->toggleRepeat(AudioMsgId::Type::Song);
});
@@ -538,12 +538,12 @@ void Widget::createPrevNextButtons() {
if (!_previousTrack) {
_previousTrack.create(this, st::mediaPlayerPreviousButton);
_previousTrack->show();
_previousTrack->setClickedCallback([this]() {
_previousTrack->setClickedCallback([=]() {
instance()->previous();
});
_nextTrack.create(this, st::mediaPlayerNextButton);
_nextTrack->show();
_nextTrack->setClickedCallback([this]() {
_nextTrack->setClickedCallback([=]() {
instance()->next();
});
updatePlayPrevNextPositions();

View File

@@ -152,7 +152,7 @@ void MediaView::refreshLang() {
}
void MediaView::moveToScreen() {
auto widgetScreen = [this](auto &&widget) -> QScreen* {
auto widgetScreen = [&](auto &&widget) -> QScreen* {
if (auto handle = widget ? widget->windowHandle() : nullptr) {
return handle->screen();
}
@@ -2280,7 +2280,7 @@ void MediaView::paintThemePreview(Painter &p, QRect clip) {
}
}
auto fillOverlay = [this, &p, clip](QRect fill) {
auto fillOverlay = [&](QRect fill) {
auto clipped = fill.intersected(clip);
if (!clipped.isEmpty()) {
p.setOpacity(st::themePreviewOverlayOpacity);

View File

@@ -77,12 +77,14 @@ Messenger::Messenger(not_null<Core::Launcher*> launcher)
Expects(!_logo.isNull());
Expects(!_logoNoMargin.isNull());
Expects(SingleInstance == nullptr);
SingleInstance = this;
Fonts::Start();
ThirdParty::start();
Global::start();
Sandbox::refreshGlobalProxy(); // Depends on Global::started().
startLocalStorage();
@@ -167,10 +169,6 @@ Messenger::Messenger(not_null<Core::Launcher*> launcher)
_window->showSettings();
}
#ifndef TDESKTOP_DISABLE_NETWORK_PROXY
QNetworkProxyFactory::setUseSystemConfiguration(true);
#endif // !TDESKTOP_DISABLE_NETWORK_PROXY
_window->updateIsActive(Global::OnlineFocusTimeout());
if (!Shortcuts::errors().isEmpty()) {
@@ -391,7 +389,12 @@ void Messenger::setMtpAuthorization(const QByteArray &serialized) {
void Messenger::startMtp() {
Expects(!_mtproto);
_mtproto = std::make_unique<MTP::Instance>(_dcOptions.get(), MTP::Instance::Mode::Normal, base::take(_private->mtpConfig));
_mtproto = std::make_unique<MTP::Instance>(
_dcOptions.get(),
MTP::Instance::Mode::Normal,
base::take(_private->mtpConfig));
_mtproto->setUserPhone(cLoggedPhoneNumber());
_private->mtpConfig.mainDcId = _mtproto->mainDcId();
_mtproto->setStateChangedHandler([](MTP::ShiftedDcId shiftedDcId, int32 state) {
@@ -490,6 +493,20 @@ void Messenger::startLocalStorage() {
}
});
});
subscribe(Global::RefSelfChanged(), [=] {
InvokeQueued(this, [=] {
const auto phone = App::self()
? App::self()->phone()
: QString();
if (cLoggedPhoneNumber() != phone) {
cSetLoggedPhoneNumber(phone);
if (_mtproto) {
_mtproto->setUserPhone(phone);
}
Local::writeSettings();
}
});
});
}
void Messenger::regPhotoUpdate(const PeerId &peer, const FullMsgId &msgId) {
@@ -839,7 +856,11 @@ bool Messenger::openLocalUrl(const QString &url) {
}
} else if (auto socksMatch = regex_match(qsl("^socks/?\\?(.+)(#|$)"), command, matchOptions)) {
auto params = url_parse_params(socksMatch->captured(1), UrlParamNameTransform::ToLower);
ConnectionBox::ShowApplyProxyConfirmation(params);
ConnectionBox::ShowApplyProxyConfirmation(ProxyData::Type::Socks5, params);
return true;
} else if (auto proxyMatch = regex_match(qsl("^proxy/?\\?(.+)(#|$)"), command, matchOptions)) {
auto params = url_parse_params(proxyMatch->captured(1), UrlParamNameTransform::ToLower);
ConnectionBox::ShowApplyProxyConfirmation(ProxyData::Type::Mtproto, params);
return true;
}
return false;

View File

@@ -22,9 +22,11 @@ constexpr auto kSpecialRequestTimeoutMs = 6000; // 4 seconds timeout for it to w
ConfigLoader::ConfigLoader(
not_null<Instance*> instance,
const QString &phone,
RPCDoneHandlerPtr onDone,
RPCFailHandlerPtr onFail)
: _instance(instance)
, _phone(phone)
, _doneHandler(onDone)
, _failHandler(onFail) {
_enumDCTimer.setCallback([this] { enumerate(); });
@@ -52,7 +54,7 @@ mtpRequestId ConfigLoader::sendRequest(ShiftedDcId shiftedDcId) {
}
DcId ConfigLoader::specialToRealDcId(DcId specialDcId) {
return Instance::Config::kTemporaryMainDc + specialDcId;
return getTemporaryIdFromRealDcId(specialDcId);
}
void ConfigLoader::terminateRequest() {
@@ -96,24 +98,51 @@ void ConfigLoader::enumerate() {
_enumDCTimer.callOnce(kEnumerateDcTimeout);
createSpecialLoader();
refreshSpecialLoader();
}
void ConfigLoader::createSpecialLoader() {
if (Global::ConnectionType() != dbictAuto) {
void ConfigLoader::refreshSpecialLoader() {
if (Global::UseProxy()) {
_specialLoader.reset();
return;
}
if (!_specialLoader || (!_specialEnumRequest && _specialEndpoints.empty())) {
_specialLoader = std::make_unique<SpecialConfigRequest>([this](DcId dcId, const std::string &ip, int port) {
addSpecialEndpoint(dcId, ip, port);
});
_triedSpecialEndpoints.clear();
if (!_specialLoader
|| (!_specialEnumRequest && _specialEndpoints.empty())) {
createSpecialLoader();
}
}
void ConfigLoader::addSpecialEndpoint(DcId dcId, const std::string &ip, int port) {
auto endpoint = SpecialEndpoint { dcId, ip, port };
void ConfigLoader::setPhone(const QString &phone) {
if (_phone != phone) {
_phone = phone;
if (_specialLoader) {
createSpecialLoader();
}
}
}
void ConfigLoader::createSpecialLoader() {
_triedSpecialEndpoints.clear();
_specialLoader = std::make_unique<SpecialConfigRequest>([=](
DcId dcId,
const std::string &ip,
int port,
bytes::const_span secret) {
addSpecialEndpoint(dcId, ip, port, secret);
}, _phone);
}
void ConfigLoader::addSpecialEndpoint(
DcId dcId,
const std::string &ip,
int port,
bytes::const_span secret) {
auto endpoint = SpecialEndpoint {
dcId,
ip,
port,
bytes::make_vector(secret)
};
if (base::contains(_specialEndpoints, endpoint)
|| base::contains(_triedSpecialEndpoints, endpoint)) {
return;
@@ -128,12 +157,12 @@ void ConfigLoader::addSpecialEndpoint(DcId dcId, const std::string &ip, int port
void ConfigLoader::sendSpecialRequest() {
terminateSpecialRequest();
if (Global::ConnectionType() != dbictAuto) {
if (Global::UseProxy()) {
_specialLoader.reset();
return;
}
if (_specialEndpoints.empty()) {
createSpecialLoader();
refreshSpecialLoader();
return;
}
@@ -141,11 +170,16 @@ void ConfigLoader::sendSpecialRequest() {
const auto index = rand_value<uint32>() % _specialEndpoints.size();
const auto endpoint = _specialEndpoints.begin() + index;
_specialEnumCurrent = specialToRealDcId(endpoint->dcId);
using Flag = MTPDdcOption::Flag;
const auto flags = Flag::f_tcpo_only
| (endpoint->secret.empty() ? Flag(0) : Flag::f_secret);
_instance->dcOptions()->constructAddOne(
_specialEnumCurrent,
MTPDdcOption::Flag::f_tcpo_only,
flags,
endpoint->ip,
endpoint->port);
endpoint->port,
endpoint->secret);
_specialEnumRequest = _instance->send(
MTPhelp_GetConfig(),
rpcDone([weak](const MTPConfig &result) {

View File

@@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/timer.h"
#include "base/weak_ptr.h"
#include "base/bytes.h"
#include "mtproto/rpc_sender.h"
namespace MTP {
@@ -20,16 +21,26 @@ namespace internal {
class ConfigLoader : public base::has_weak_ptr {
public:
ConfigLoader(not_null<Instance*> instance, RPCDoneHandlerPtr onDone, RPCFailHandlerPtr onFail);
ConfigLoader(
not_null<Instance*> instance,
const QString &phone,
RPCDoneHandlerPtr onDone,
RPCFailHandlerPtr onFail);
~ConfigLoader();
void load();
void setPhone(const QString &phone);
private:
mtpRequestId sendRequest(ShiftedDcId shiftedDcId);
void addSpecialEndpoint(DcId dcId, const std::string &ip, int port);
void addSpecialEndpoint(
DcId dcId,
const std::string &ip,
int port,
bytes::const_span secret);
void sendSpecialRequest();
void enumerate();
void refreshSpecialLoader();
void createSpecialLoader();
DcId specialToRealDcId(DcId specialDcId);
void specialConfigLoaded(const MTPConfig &result);
@@ -45,6 +56,7 @@ private:
DcId dcId;
std::string ip;
int port;
bytes::vector secret;
};
friend bool operator==(const SpecialEndpoint &a, const SpecialEndpoint &b);
std::unique_ptr<SpecialConfigRequest> _specialLoader;
@@ -53,6 +65,7 @@ private:
base::Timer _specialEnumTimer;
DcId _specialEnumCurrent = 0;
mtpRequestId _specialEnumRequest = 0;
QString _phone;
RPCDoneHandlerPtr _doneHandler;
RPCFailHandlerPtr _failHandler;

File diff suppressed because it is too large Load Diff

View File

@@ -9,7 +9,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mtproto/auth_key.h"
#include "mtproto/dc_options.h"
#include "core/single_timer.h"
#include "mtproto/connection_abstract.h"
#include "base/timer.h"
namespace MTP {
@@ -25,12 +26,15 @@ struct ModExpFirst {
ModExpFirst CreateModExp(int g, base::const_byte_span primeBytes, base::const_byte_span randomSeed);
std::vector<gsl::byte> CreateAuthKey(base::const_byte_span firstBytes, base::const_byte_span randomBytes, base::const_byte_span primeBytes);
bytes::vector ProtocolSecretFromPassword(const QString &password);
namespace internal {
class AbstractConnection;
class ConnectionPrivate;
class SessionData;
class RSAPublicKey;
struct ConnectionOptions;
class Thread : public QThread {
Q_OBJECT
@@ -56,7 +60,7 @@ public:
HttpConnection
};
Connection(Instance *instance);
Connection(not_null<Instance*> instance);
void start(SessionData *data, ShiftedDcId shiftedDcId);
@@ -70,9 +74,9 @@ public:
QString transport() const;
private:
Instance *_instance = nullptr;
std::unique_ptr<QThread> thread;
ConnectionPrivate *data = nullptr;
not_null<Instance*> _instance;
std::unique_ptr<QThread> _thread;
ConnectionPrivate *_private = nullptr;
};
@@ -80,7 +84,12 @@ class ConnectionPrivate : public QObject {
Q_OBJECT
public:
ConnectionPrivate(Instance *instance, QThread *thread, Connection *owner, SessionData *data, ShiftedDcId shiftedDcId);
ConnectionPrivate(
not_null<Instance*> instance,
not_null<QThread*> thread,
not_null<Connection*> owner,
not_null<SessionData*> data,
ShiftedDcId shiftedDcId);
~ConnectionPrivate();
void stop();
@@ -108,29 +117,15 @@ signals:
void finished(internal::Connection *connection);
public slots:
void retryByTimer();
void restartNow();
void onPingSender();
void onPingSendForce();
void onWaitConnectedFailed();
void onWaitReceivedFailed();
void onWaitIPv4Failed();
void onOldConnection();
void onSentSome(uint64 size);
void onReceivedSome();
void onReadyData();
void onConnected4();
void onConnected6();
void onDisconnected4();
void onDisconnected6();
void onError4(qint32 errorCode);
void onError6(qint32 errorCode);
// Auth key creation packet receive slots
void pqAnswered();
void dhParamsAnswered();
@@ -148,15 +143,32 @@ public slots:
void onCDNConfigLoaded();
private:
struct TestConnection {
ConnectionPointer data;
int priority = 0;
};
void connectToServer(bool afterConfig = false);
void doDisconnect();
void restart();
void finishAndDestroy();
void requestCDNConfig();
void handleError(int errorCode);
void onError(
not_null<AbstractConnection*> connection,
qint32 errorCode);
void onConnected(not_null<AbstractConnection*> connection);
void onDisconnected(not_null<AbstractConnection*> connection);
void createConn(bool createIPv4, bool createIPv6);
void destroyConn(AbstractConnection **conn = 0); // 0 - destory all
void retryByTimer();
void waitConnectedFailed();
void waitReceivedFailed();
void waitBetterFailed();
void markConnectionOld();
void sendPingByTimer();
void destroyAllConnections();
void confirmBestConnection();
void removeTestConnection(not_null<AbstractConnection*> connection);
mtpMsgId placeToContainer(mtpRequest &toSendRequest, mtpMsgId &bigMsgId, mtpMsgId *&haveSentArr, mtpRequest &req);
mtpMsgId prepareToSend(mtpRequest &request, mtpMsgId currentLastId);
@@ -181,6 +193,26 @@ private:
base::byte_vector encryptPQInnerRSA(const MTPP_Q_inner_data &data, const MTP::internal::RSAPublicKey &key);
std::string encryptClientDHInner(const MTPClient_DH_Inner_Data &data);
void appendTestConnection(
DcOptions::Variants::Protocol protocol,
const QString &ip,
int port,
const bytes::vector &protocolSecret);
// if badTime received - search for ids in sessionData->haveSent and sessionData->wereAcked and sync time/salt, return true if found
bool requestsFixTimeSalt(const QVector<MTPlong> &ids, int32 serverTime, uint64 serverSalt);
// remove msgs with such ids from sessionData->haveSent, add to sessionData->wereAcked
void requestsAcked(const QVector<MTPlong> &ids, bool byResponse = false);
void resend(quint64 msgId, qint64 msCanWait = 0, bool forceContainer = false, bool sendMsgStateInfo = false);
void resendMany(QVector<quint64> msgIds, qint64 msCanWait = 0, bool forceContainer = false, bool sendMsgStateInfo = false);
template <typename TRequest>
void sendRequestNotSecure(const TRequest &request);
template <typename TResponse>
bool readResponseNotSecure(TResponse &response);
Instance *_instance = nullptr;
DcType _dcType = DcType::Regular;
@@ -192,44 +224,32 @@ private:
void resetSession();
ShiftedDcId _shiftedDcId = 0;
Connection *_owner = nullptr;
AbstractConnection *_conn = nullptr;
AbstractConnection *_conn4 = nullptr;
AbstractConnection *_conn6 = nullptr;;
not_null<Connection*> _owner;
ConnectionPointer _connection;
std::vector<TestConnection> _testConnections;
TimeMs _startedConnectingAt = 0;
SingleTimer retryTimer; // exp retry timer
int retryTimeout = 1;
qint64 retryWillFinish;
base::Timer _retryTimer; // exp retry timer
int _retryTimeout = 1;
qint64 _retryWillFinish = 0;
SingleTimer oldConnectionTimer;
bool oldConnection = true;
base::Timer _oldConnectionTimer;
bool _oldConnection = true;
SingleTimer _waitForConnectedTimer, _waitForReceivedTimer, _waitForIPv4Timer;
uint32 _waitForReceived, _waitForConnected;
base::Timer _waitForConnectedTimer;
base::Timer _waitForReceivedTimer;
base::Timer _waitForBetterTimer;
uint32 _waitForReceived = 0;
uint32 _waitForConnected = 0;
TimeMs firstSentAt = -1;
QVector<MTPlong> ackRequestData, resendRequestData;
// if badTime received - search for ids in sessionData->haveSent and sessionData->wereAcked and sync time/salt, return true if found
bool requestsFixTimeSalt(const QVector<MTPlong> &ids, int32 serverTime, uint64 serverSalt);
// remove msgs with such ids from sessionData->haveSent, add to sessionData->wereAcked
void requestsAcked(const QVector<MTPlong> &ids, bool byResponse = false);
mtpPingId _pingId = 0;
mtpPingId _pingIdToSend = 0;
TimeMs _pingSendAt = 0;
mtpMsgId _pingMsgId = 0;
SingleTimer _pingSender;
void resend(quint64 msgId, qint64 msCanWait = 0, bool forceContainer = false, bool sendMsgStateInfo = false);
void resendMany(QVector<quint64> msgIds, qint64 msCanWait = 0, bool forceContainer = false, bool sendMsgStateInfo = false);
template <typename TRequest>
void sendRequestNotSecure(const TRequest &request);
template <typename TResponse>
bool readResponseNotSecure(TResponse &response);
base::Timer _pingSender;
bool restarted = false;
bool _finished = false;
@@ -237,6 +257,7 @@ private:
uint64 keyId = 0;
QReadWriteLock sessionDataMutex;
SessionData *sessionData = nullptr;
std::unique_ptr<ConnectionOptions> _connectionOptions;
bool myKeyLock = false;
void lockKey();

View File

@@ -9,11 +9,71 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mtproto/connection_tcp.h"
#include "mtproto/connection_http.h"
#include "mtproto/connection_auto.h"
#include "mtproto/session.h"
namespace MTP {
namespace internal {
ConnectionPointer::ConnectionPointer() = default;
ConnectionPointer::ConnectionPointer(std::nullptr_t) {
}
ConnectionPointer::ConnectionPointer(AbstractConnection *value)
: _value(value) {
}
ConnectionPointer::ConnectionPointer(ConnectionPointer &&other)
: _value(base::take(other._value)) {
}
ConnectionPointer &ConnectionPointer::operator=(ConnectionPointer &&other) {
reset(base::take(other._value));
return *this;
}
AbstractConnection *ConnectionPointer::get() const {
return _value;
}
void ConnectionPointer::reset(AbstractConnection *value) {
if (_value == value) {
return;
} else if (const auto old = base::take(_value)) {
const auto disconnect = [&](auto signal) {
old->disconnect(old, signal, nullptr, nullptr);
};
disconnect(&AbstractConnection::receivedData);
disconnect(&AbstractConnection::receivedSome);
disconnect(&AbstractConnection::error);
disconnect(&AbstractConnection::connected);
disconnect(&AbstractConnection::disconnected);
old->disconnectFromServer();
old->deleteLater();
}
_value = value;
}
ConnectionPointer::operator AbstractConnection*() const {
return get();
}
AbstractConnection *ConnectionPointer::operator->() const {
return get();
}
AbstractConnection &ConnectionPointer::operator*() const {
return *get();
}
ConnectionPointer::operator bool() const {
return get() != nullptr;
}
ConnectionPointer::~ConnectionPointer() {
reset();
}
AbstractConnection::~AbstractConnection() {
}
@@ -62,13 +122,18 @@ MTPResPQ AbstractConnection::readPQFakeReply(const mtpBuffer &buffer) {
return response;
}
AbstractConnection *AbstractConnection::create(DcType type, QThread *thread) {
if ((type == DcType::Temporary) || (Global::ConnectionType() == dbictTcpProxy)) {
return new TCPConnection(thread);
} else if (Global::ConnectionType() == dbictHttpProxy) {
return new HTTPConnection(thread);
AbstractConnection::AbstractConnection(QThread *thread) {
moveToThread(thread);
}
ConnectionPointer AbstractConnection::create(
DcOptions::Variants::Protocol protocol,
QThread *thread) {
if (protocol == DcOptions::Variants::Tcp) {
return ConnectionPointer(new TCPConnection(thread));
} else {
return ConnectionPointer(new HTTPConnection(thread));
}
return new AutoConnection(thread);
}
} // namespace internal

View File

@@ -8,32 +8,64 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once
#include "mtproto/dc_options.h"
#include "base/bytes.h"
namespace MTP {
namespace internal {
struct ConnectionOptions;
class AbstractConnection;
class ConnectionPointer {
public:
ConnectionPointer();
ConnectionPointer(std::nullptr_t);
explicit ConnectionPointer(AbstractConnection *value);
ConnectionPointer(ConnectionPointer &&other);
ConnectionPointer &operator=(ConnectionPointer &&other);
AbstractConnection *get() const;
void reset(AbstractConnection *value = nullptr);
operator AbstractConnection*() const;
AbstractConnection *operator->() const;
AbstractConnection &operator*() const;
explicit operator bool() const;
~ConnectionPointer();
private:
AbstractConnection *_value = nullptr;
};
class AbstractConnection : public QObject {
Q_OBJECT
public:
AbstractConnection(QThread *thread) : _sentEncrypted(false) {
moveToThread(thread);
}
AbstractConnection(QThread *thread);
AbstractConnection(const AbstractConnection &other) = delete;
AbstractConnection &operator=(const AbstractConnection &other) = delete;
virtual ~AbstractConnection() = 0;
// virtual constructor
static AbstractConnection *create(DcType type, QThread *thread);
static ConnectionPointer create(
DcOptions::Variants::Protocol protocol,
QThread *thread);
void setSentEncrypted() {
_sentEncrypted = true;
}
virtual void setProxyOverride(const ProxyData &proxy) = 0;
virtual TimeMs pingTime() const = 0;
virtual void sendData(mtpBuffer &buffer) = 0; // has size + 3, buffer[0] = len, buffer[1] = packetnum, buffer[last] = crc32
virtual void disconnectFromServer() = 0;
virtual void connectTcp(const DcOptions::Endpoint &endpoint) = 0;
virtual void connectHttp(const DcOptions::Endpoint &endpoint) = 0;
virtual void connectToServer(
const QString &ip,
int port,
const bytes::vector &protocolSecret,
int16 protocolDcId) = 0;
virtual bool isConnected() const = 0;
virtual bool usingHttpWait() {
return false;
@@ -45,6 +77,7 @@ public:
virtual int32 debugState() const = 0;
virtual QString transport() const = 0;
virtual QString tag() const = 0;
using BuffersQueue = std::deque<mtpBuffer>;
BuffersQueue &received() {
@@ -65,7 +98,8 @@ signals:
protected:
BuffersQueue _receivedQueue; // list of received packets, not processed yet
bool _sentEncrypted;
bool _sentEncrypted = false;
int _pingTime = 0;
// first we always send fake MTPReq_pq to see if connection works at all
// we send them simultaneously through TCP/HTTP/IPv4/IPv6 to choose the working one

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