2014-05-30 12:53:19 +04:00
/*
This file is part of Telegram Desktop ,
2014-12-01 13:47:38 +03:00
the official desktop version of Telegram messaging app , see https : //telegram.org
2014-05-30 12:53:19 +04:00
Telegram Desktop is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
It is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
2015-10-03 16:16:42 +03:00
In addition , as a special exception , the copyright holders give permission
to link the code of portions of this program with the OpenSSL library .
2014-05-30 12:53:19 +04:00
Full license : https : //github.com/telegramdesktop/tdesktop/blob/master/LICENSE
2017-01-11 22:31:31 +04:00
Copyright ( c ) 2014 - 2017 John Preston , https : //desktop.telegram.org
2014-05-30 12:53:19 +04:00
*/
# include "stdafx.h"
# include "application.h"
2016-02-27 22:39:51 +03:00
# include "shortcuts.h"
2014-05-30 12:53:19 +04:00
# include "pspecific.h"
# include "fileuploader.h"
# include "mainwidget.h"
# include "lang.h"
# include "boxes/confirmbox.h"
2016-05-25 20:59:21 +03:00
# include "ui/filedialog.h"
2016-10-26 19:43:13 +03:00
# include "ui/widgets/tooltip.h"
2014-05-30 12:53:19 +04:00
# include "langloaderplain.h"
2014-11-22 12:45:04 +03:00
# include "localstorage.h"
2015-06-03 21:13:01 +03:00
# include "autoupdater.h"
2016-05-25 15:09:05 +03:00
# include "core/observer.h"
2016-05-25 20:59:21 +03:00
# include "observer_peer.h"
2016-10-28 15:44:28 +03:00
# include "window/window_theme.h"
2016-09-23 19:04:26 +03:00
# include "media/player/media_player_instance.h"
2016-10-02 16:54:27 +03:00
# include "window/notifications_manager.h"
2016-09-27 16:37:18 +03:00
# include "history/history_location_manager.h"
2016-12-23 16:21:01 +03:00
# include "core/task_queue.h"
2015-06-03 21:13:01 +03:00
2014-05-30 12:53:19 +04:00
namespace {
2016-12-20 16:03:51 +03:00
void mtpStateChanged ( int32 dc , int32 state ) {
if ( App : : wnd ( ) ) {
App : : wnd ( ) - > mtpStateChanged ( dc , state ) ;
2014-08-01 22:49:43 +04:00
}
2016-12-20 16:03:51 +03:00
}
2014-08-01 22:49:43 +04:00
2016-12-20 16:03:51 +03:00
void mtpSessionReset ( int32 dc ) {
if ( App : : main ( ) & & dc = = MTP : : maindc ( ) ) {
App : : main ( ) - > getDifference ( ) ;
2016-01-11 23:43:29 +08:00
}
2016-12-20 16:03:51 +03:00
}
2016-01-11 23:43:29 +08:00
2016-12-20 16:03:51 +03:00
QChar _toHex ( ushort v ) {
v = v & 0x000F ;
return QChar : : fromLatin1 ( ( v > = 10 ) ? ( ' a ' + ( v - 10 ) ) : ( ' 0 ' + v ) ) ;
}
ushort _fromHex ( QChar c ) {
return ( ( c . unicode ( ) > = uchar ( ' a ' ) ) ? ( c . unicode ( ) - uchar ( ' a ' ) + 10 ) : ( c . unicode ( ) - uchar ( ' 0 ' ) ) ) & 0x000F ;
}
QString _escapeTo7bit ( const QString & str ) {
QString result ;
result . reserve ( str . size ( ) * 2 ) ;
for ( int i = 0 , l = str . size ( ) ; i ! = l ; + + i ) {
QChar ch ( str . at ( i ) ) ;
ushort uch ( ch . unicode ( ) ) ;
if ( uch < 32 | | uch > 127 | | uch = = ushort ( uchar ( ' % ' ) ) ) {
result . append ( ' % ' ) . append ( _toHex ( uch > > 12 ) ) . append ( _toHex ( uch > > 8 ) ) . append ( _toHex ( uch > > 4 ) ) . append ( _toHex ( uch ) ) ;
} else {
result . append ( ch ) ;
2016-01-11 23:43:29 +08:00
}
}
2016-12-20 16:03:51 +03:00
return result ;
}
2016-01-11 23:43:29 +08:00
2016-12-20 16:03:51 +03:00
QString _escapeFrom7bit ( const QString & str ) {
QString result ;
result . reserve ( str . size ( ) ) ;
for ( int i = 0 , l = str . size ( ) ; i ! = l ; + + i ) {
QChar ch ( str . at ( i ) ) ;
if ( ch = = QChar : : fromLatin1 ( ' % ' ) & & i + 4 < l ) {
result . append ( QChar ( ushort ( ( _fromHex ( str . at ( i + 1 ) ) < < 12 ) | ( _fromHex ( str . at ( i + 2 ) ) < < 8 ) | ( _fromHex ( str . at ( i + 3 ) ) < < 4 ) | _fromHex ( str . at ( i + 4 ) ) ) ) ) ;
i + = 4 ;
} else {
result . append ( ch ) ;
2016-01-11 23:43:29 +08:00
}
}
2016-12-20 16:03:51 +03:00
return result ;
2014-05-30 12:53:19 +04:00
}
2016-12-20 16:03:51 +03:00
} // namespace
AppClass * AppObject = nullptr ;
2014-07-18 14:37:34 +04:00
2016-04-14 22:24:42 +03:00
Application : : Application ( int & argc , char * * argv ) : QApplication ( argc , argv ) {
2016-02-09 17:42:36 +03:00
QByteArray d ( QFile : : encodeName ( QDir ( cWorkingDir ( ) ) . absolutePath ( ) ) ) ;
2014-07-18 14:37:34 +04:00
char h [ 33 ] = { 0 } ;
hashMd5Hex ( d . constData ( ) , d . size ( ) , h ) ;
2016-08-31 11:58:46 -06:00
# ifndef OS_MAC_STORE
2016-01-11 23:43:29 +08:00
_localServerName = psServerPrefix ( ) + h + ' - ' + cGUIDStr ( ) ;
2016-08-31 11:58:46 -06:00
# else // OS_MAC_STORE
h [ 4 ] = 0 ; // use only first 4 chars
_localServerName = psServerPrefix ( ) + h ;
# endif // OS_MAC_STORE
2016-01-11 23:43:29 +08:00
connect ( & _localSocket , SIGNAL ( connected ( ) ) , this , SLOT ( socketConnected ( ) ) ) ;
connect ( & _localSocket , SIGNAL ( disconnected ( ) ) , this , SLOT ( socketDisconnected ( ) ) ) ;
connect ( & _localSocket , SIGNAL ( error ( QLocalSocket : : LocalSocketError ) ) , this , SLOT ( socketError ( QLocalSocket : : LocalSocketError ) ) ) ;
connect ( & _localSocket , SIGNAL ( bytesWritten ( qint64 ) ) , this , SLOT ( socketWritten ( qint64 ) ) ) ;
connect ( & _localSocket , SIGNAL ( readyRead ( ) ) , this , SLOT ( socketReading ( ) ) ) ;
2016-01-17 13:03:57 +08:00
connect ( & _localServer , SIGNAL ( newConnection ( ) ) , this , SLOT ( newInstanceConnected ( ) ) ) ;
2016-01-11 23:43:29 +08:00
2016-02-29 19:53:26 +03:00
QTimer : : singleShot ( 0 , this , SLOT ( startApplication ( ) ) ) ;
2016-01-30 21:24:18 +03:00
connect ( this , SIGNAL ( aboutToQuit ( ) ) , this , SLOT ( closeApplication ( ) ) ) ;
2016-01-11 23:43:29 +08:00
# ifndef TDESKTOP_DISABLE_AUTOUPDATE
connect ( & _updateCheckTimer , SIGNAL ( timeout ( ) ) , this , SLOT ( updateCheck ( ) ) ) ;
connect ( this , SIGNAL ( updateFailed ( ) ) , this , SLOT ( onUpdateFailed ( ) ) ) ;
connect ( this , SIGNAL ( updateReady ( ) ) , this , SLOT ( onUpdateReady ( ) ) ) ;
2016-10-18 10:56:38 +03:00
# endif // !TDESKTOP_DISABLE_AUTOUPDATE
2014-07-18 14:37:34 +04:00
2016-01-11 23:43:29 +08:00
if ( cManyInstance ( ) ) {
2016-03-24 18:07:13 +03:00
LOG ( ( " Many instance allowed, starting... " ) ) ;
2016-01-11 23:43:29 +08:00
singleInstanceChecked ( ) ;
} else {
2016-03-24 18:07:13 +03:00
LOG ( ( " Connecting local socket to %1... " ) . arg ( _localServerName ) ) ;
2016-01-11 23:43:29 +08:00
_localSocket . connectToServer ( _localServerName ) ;
2014-05-30 12:53:19 +04:00
}
2016-01-11 23:43:29 +08:00
}
2014-05-30 12:53:19 +04:00
2016-09-15 13:50:43 +03:00
bool Application : : event ( QEvent * e ) {
if ( e - > type ( ) = = QEvent : : Close ) {
App : : quit ( ) ;
}
return QApplication : : event ( e ) ;
}
2016-01-11 23:43:29 +08:00
void Application : : socketConnected ( ) {
2016-03-24 18:07:13 +03:00
LOG ( ( " Socket connected, this is not the first application instance, sending show command... " ) ) ;
2016-01-11 23:43:29 +08:00
_secondInstance = true ;
QString commands ;
const QStringList & lst ( cSendPaths ( ) ) ;
for ( QStringList : : const_iterator i = lst . cbegin ( ) , e = lst . cend ( ) ; i ! = e ; + + i ) {
commands + = qsl ( " SEND: " ) + _escapeTo7bit ( * i ) + ' ; ' ;
}
if ( ! cStartUrl ( ) . isEmpty ( ) ) {
commands + = qsl ( " OPEN: " ) + _escapeTo7bit ( cStartUrl ( ) ) + ' ; ' ;
2014-05-30 12:53:19 +04:00
}
2016-01-11 23:43:29 +08:00
commands + = qsl ( " CMD:show; " ) ;
2014-05-30 12:53:19 +04:00
2016-01-11 23:43:29 +08:00
DEBUG_LOG ( ( " Application Info: writing commands %1 " ) . arg ( commands ) ) ;
_localSocket . write ( commands . toLatin1 ( ) ) ;
}
2014-06-15 16:31:03 +04:00
2016-01-11 23:43:29 +08:00
void Application : : socketWritten ( qint64 /* bytes*/ ) {
if ( _localSocket . state ( ) ! = QLocalSocket : : ConnectedState ) {
2016-01-17 13:01:14 +08:00
LOG ( ( " Socket is not connected %1 " ) . arg ( _localSocket . state ( ) ) ) ;
2016-01-11 23:43:29 +08:00
return ;
2014-12-20 00:20:30 +03:00
}
2016-01-11 23:43:29 +08:00
if ( _localSocket . bytesToWrite ( ) ) {
return ;
2014-05-30 12:53:19 +04:00
}
2016-03-24 18:07:13 +03:00
LOG ( ( " Show command written, waiting response... " ) ) ;
2016-01-11 23:43:29 +08:00
}
2014-05-30 12:53:19 +04:00
2016-01-11 23:43:29 +08:00
void Application : : socketReading ( ) {
if ( _localSocket . state ( ) ! = QLocalSocket : : ConnectedState ) {
2016-01-17 13:01:14 +08:00
LOG ( ( " Socket is not connected %1 " ) . arg ( _localSocket . state ( ) ) ) ;
2016-01-11 23:43:29 +08:00
return ;
}
_localSocketReadData . append ( _localSocket . readAll ( ) ) ;
if ( QRegularExpression ( " RES:( \\ d+); " ) . match ( _localSocketReadData ) . hasMatch ( ) ) {
uint64 pid = _localSocketReadData . mid ( 4 , _localSocketReadData . length ( ) - 5 ) . toULongLong ( ) ;
psActivateProcess ( pid ) ;
2016-03-24 18:07:13 +03:00
LOG ( ( " Show command response received, pid = %1, activating and quitting... " ) . arg ( pid ) ) ;
2016-01-11 23:43:29 +08:00
return App : : quit ( ) ;
}
}
2015-01-05 23:19:05 +03:00
2016-01-11 23:43:29 +08:00
void Application : : socketError ( QLocalSocket : : LocalSocketError e ) {
2016-03-02 20:34:42 +02:00
if ( App : : quitting ( ) ) return ;
2016-01-21 14:58:58 +08:00
2016-01-11 23:43:29 +08:00
if ( _secondInstance ) {
2016-03-24 18:07:13 +03:00
LOG ( ( " Could not write show command, error %1, quitting... " ) . arg ( e ) ) ;
2016-01-11 23:43:29 +08:00
return App : : quit ( ) ;
}
2014-05-30 12:53:19 +04:00
2016-01-11 23:43:29 +08:00
if ( e = = QLocalSocket : : ServerNotFoundError ) {
2016-03-24 18:07:13 +03:00
LOG ( ( " This is the only instance of Telegram, starting server and app... " ) ) ;
2016-01-11 23:43:29 +08:00
} else {
2016-03-24 18:07:13 +03:00
LOG ( ( " Socket connect error %1, starting server and app... " ) . arg ( e ) ) ;
2016-01-11 23:43:29 +08:00
}
_localSocket . close ( ) ;
2014-11-26 19:45:52 +03:00
2016-04-26 16:00:23 +03:00
// Local server does not work in WinRT build.
# ifndef Q_OS_WINRT
2016-01-11 23:43:29 +08:00
psCheckLocalSocket ( _localServerName ) ;
2014-05-30 12:53:19 +04:00
2016-01-11 23:43:29 +08:00
if ( ! _localServer . listen ( _localServerName ) ) {
2016-01-17 13:01:14 +08:00
LOG ( ( " Failed to start listening to %1 server, error %2 " ) . arg ( _localServerName ) . arg ( int ( _localServer . serverError ( ) ) ) ) ;
2016-01-11 23:43:29 +08:00
return App : : quit ( ) ;
}
2016-04-26 16:00:23 +03:00
# endif // !Q_OS_WINRT
2014-05-30 12:53:19 +04:00
2016-01-11 23:43:29 +08:00
# ifndef TDESKTOP_DISABLE_AUTOUPDATE
if ( ! cNoStartUpdate ( ) & & checkReadyUpdate ( ) ) {
cSetRestartingUpdate ( true ) ;
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " Application Info: installing update instead of starting app... " ) ) ;
2016-01-11 23:43:29 +08:00
return App : : quit ( ) ;
}
2016-10-18 10:56:38 +03:00
# endif // !TDESKTOP_DISABLE_AUTOUPDATE
2015-10-15 13:51:10 +02:00
2016-01-11 23:43:29 +08:00
singleInstanceChecked ( ) ;
}
2014-05-30 12:53:19 +04:00
2016-01-11 23:43:29 +08:00
void Application : : singleInstanceChecked ( ) {
2016-01-17 13:01:14 +08:00
if ( cManyInstance ( ) ) {
Logs : : multipleInstances ( ) ;
}
2016-02-08 17:54:55 +03:00
Sandbox : : start ( ) ;
2014-10-30 19:23:44 +03:00
2016-01-21 14:58:58 +08:00
if ( ! Logs : : started ( ) | | ( ! cManyInstance ( ) & & ! Logs : : instanceChecked ( ) ) ) {
2016-01-25 13:22:58 +03:00
new NotStartedWindow ( ) ;
2016-01-21 14:58:58 +08:00
} else {
SignalHandlers : : Status status = SignalHandlers : : start ( ) ;
if ( status = = SignalHandlers : : CantOpen ) {
2016-01-25 13:22:58 +03:00
new NotStartedWindow ( ) ;
} else if ( status = = SignalHandlers : : LastCrashed ) {
2016-02-08 17:54:55 +03:00
if ( Sandbox : : LastCrashDump ( ) . isEmpty ( ) ) { // don't handle bad closing for now
2016-02-07 18:38:49 +03:00
if ( SignalHandlers : : restart ( ) = = SignalHandlers : : CantOpen ) {
new NotStartedWindow ( ) ;
} else {
2016-02-08 17:54:55 +03:00
Sandbox : : launch ( ) ;
2016-02-07 18:38:49 +03:00
}
} else {
new LastCrashedWindow ( ) ;
}
2016-01-21 14:58:58 +08:00
} else {
2016-02-08 17:54:55 +03:00
Sandbox : : launch ( ) ;
2016-01-21 14:58:58 +08:00
}
}
2016-01-11 23:43:29 +08:00
}
void Application : : socketDisconnected ( ) {
if ( _secondInstance ) {
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " Application Error: socket disconnected before command response received, quitting... " ) ) ;
2016-01-11 23:43:29 +08:00
return App : : quit ( ) ;
}
}
void Application : : newInstanceConnected ( ) {
DEBUG_LOG ( ( " Application Info: new local socket connected " ) ) ;
for ( QLocalSocket * client = _localServer . nextPendingConnection ( ) ; client ; client = _localServer . nextPendingConnection ( ) ) {
_localClients . push_back ( LocalClient ( client , QByteArray ( ) ) ) ;
connect ( client , SIGNAL ( readyRead ( ) ) , this , SLOT ( readClients ( ) ) ) ;
connect ( client , SIGNAL ( disconnected ( ) ) , this , SLOT ( removeClients ( ) ) ) ;
}
}
void Application : : readClients ( ) {
QString startUrl ;
QStringList toSend ;
for ( LocalClients : : iterator i = _localClients . begin ( ) , e = _localClients . end ( ) ; i ! = e ; + + i ) {
i - > second . append ( i - > first - > readAll ( ) ) ;
if ( i - > second . size ( ) ) {
QString cmds ( QString : : fromLatin1 ( i - > second ) ) ;
int32 from = 0 , l = cmds . length ( ) ;
for ( int32 to = cmds . indexOf ( QChar ( ' ; ' ) , from ) ; to > = from ; to = ( from < l ) ? cmds . indexOf ( QChar ( ' ; ' ) , from ) : - 1 ) {
QStringRef cmd ( & cmds , from , to - from ) ;
if ( cmd . startsWith ( qsl ( " CMD: " ) ) ) {
2016-02-08 17:54:55 +03:00
Sandbox : : execExternal ( cmds . mid ( from + 4 , to - from - 4 ) ) ;
2016-01-11 23:43:29 +08:00
QByteArray response ( qsl ( " RES:%1; " ) . arg ( QCoreApplication : : applicationPid ( ) ) . toLatin1 ( ) ) ;
i - > first - > write ( response . data ( ) , response . size ( ) ) ;
} else if ( cmd . startsWith ( qsl ( " SEND: " ) ) ) {
if ( cSendPaths ( ) . isEmpty ( ) ) {
toSend . append ( _escapeFrom7bit ( cmds . mid ( from + 5 , to - from - 5 ) ) ) ;
}
} else if ( cmd . startsWith ( qsl ( " OPEN: " ) ) ) {
if ( cStartUrl ( ) . isEmpty ( ) ) {
2016-07-28 20:01:08 +03:00
startUrl = _escapeFrom7bit ( cmds . mid ( from + 5 , to - from - 5 ) ) . mid ( 0 , 8192 ) ;
2016-01-11 23:43:29 +08:00
}
} else {
LOG ( ( " Application Error: unknown command %1 passed in local socket " ) . arg ( QString ( cmd . constData ( ) , cmd . length ( ) ) ) ) ;
}
from = to + 1 ;
}
if ( from > 0 ) {
i - > second = i - > second . mid ( from ) ;
}
}
}
if ( ! toSend . isEmpty ( ) ) {
QStringList paths ( cSendPaths ( ) ) ;
paths . append ( toSend ) ;
cSetSendPaths ( paths ) ;
}
if ( ! cSendPaths ( ) . isEmpty ( ) ) {
if ( App : : wnd ( ) ) {
App : : wnd ( ) - > sendPaths ( ) ;
}
}
if ( ! startUrl . isEmpty ( ) ) {
cSetStartUrl ( startUrl ) ;
}
2016-10-03 11:20:02 +03:00
if ( auto main = App : : main ( ) ) {
main - > checkStartUrl ( ) ;
2016-01-11 23:43:29 +08:00
}
}
void Application : : removeClients ( ) {
DEBUG_LOG ( ( " Application Info: remove clients slot called, clients %1 " ) . arg ( _localClients . size ( ) ) ) ;
for ( LocalClients : : iterator i = _localClients . begin ( ) , e = _localClients . end ( ) ; i ! = e ; ) {
if ( i - > first - > state ( ) ! = QLocalSocket : : ConnectedState ) {
DEBUG_LOG ( ( " Application Info: removing client " ) ) ;
i = _localClients . erase ( i ) ;
e = _localClients . end ( ) ;
} else {
+ + i ;
}
}
}
2016-02-29 19:53:26 +03:00
void Application : : startApplication ( ) {
2016-03-02 20:34:42 +02:00
if ( App : : quitting ( ) ) {
2016-02-29 19:53:26 +03:00
quit ( ) ;
}
}
2016-01-11 23:43:29 +08:00
void Application : : closeApplication ( ) {
2016-03-03 20:37:15 +02:00
if ( App : : launchState ( ) = = App : : QuitProcessed ) return ;
2016-03-02 20:34:42 +02:00
App : : setLaunchState ( App : : QuitProcessed ) ;
2016-03-02 22:50:58 +02:00
2016-10-02 16:54:27 +03:00
if ( auto manager = Window : : Notifications : : manager ( ) ) {
manager - > clearAllFast ( ) ;
}
2016-10-07 19:45:45 +03:00
delete base : : take ( AppObject ) ;
2016-02-29 19:53:26 +03:00
Sandbox : : finish ( ) ;
2016-01-11 23:43:29 +08:00
_localServer . close ( ) ;
for ( LocalClients : : iterator i = _localClients . begin ( ) , e = _localClients . end ( ) ; i ! = e ; + + i ) {
disconnect ( i - > first , SIGNAL ( disconnected ( ) ) , this , SLOT ( removeClients ( ) ) ) ;
i - > first - > close ( ) ;
2014-05-30 12:53:19 +04:00
}
2016-01-11 23:43:29 +08:00
_localClients . clear ( ) ;
2016-02-29 19:53:26 +03:00
_localSocket . close ( ) ;
# ifndef TDESKTOP_DISABLE_AUTOUPDATE
delete _updateReply ;
_updateReply = 0 ;
if ( _updateChecker ) _updateChecker - > deleteLater ( ) ;
_updateChecker = 0 ;
2016-08-28 13:16:23 -06:00
if ( _updateThread ) {
_updateThread - > quit ( ) ;
}
2016-02-29 19:53:26 +03:00
_updateThread = 0 ;
2016-10-18 10:56:38 +03:00
# endif // !TDESKTOP_DISABLE_AUTOUPDATE
2014-05-30 12:53:19 +04:00
}
2016-12-23 16:21:01 +03:00
void Application : : onMainThreadTask ( ) {
base : : TaskQueue : : ProcessMainTasks ( ) ;
}
2015-08-20 00:00:37 +02:00
# ifndef TDESKTOP_DISABLE_AUTOUPDATE
2016-01-11 23:43:29 +08:00
void Application : : updateCheck ( ) {
startUpdateCheck ( false ) ;
}
2014-05-30 12:53:19 +04:00
void Application : : updateGotCurrent ( ) {
2016-01-11 23:43:29 +08:00
if ( ! _updateReply | | _updateThread ) return ;
2014-05-30 12:53:19 +04:00
cSetLastUpdateCheck ( unixtime ( ) ) ;
2016-01-11 23:43:29 +08:00
QRegularExpressionMatch m = QRegularExpression ( qsl ( " ^ \\ s*( \\ d+) \\ s*: \\ s*([ \\ x21- \\ x7f]+) \\ s*$ " ) ) . match ( QString : : fromLatin1 ( _updateReply - > readAll ( ) ) ) ;
2014-05-30 12:53:19 +04:00
if ( m . hasMatch ( ) ) {
2015-12-04 17:29:57 +03:00
uint64 currentVersion = m . captured ( 1 ) . toULongLong ( ) ;
2015-12-03 21:16:34 +03:00
QString url = m . captured ( 2 ) ;
bool betaVersion = false ;
if ( url . startsWith ( qstr ( " beta_ " ) ) ) {
betaVersion = true ;
url = url . mid ( 5 ) + ' _ ' + countBetaVersionSignature ( currentVersion ) ;
}
2015-12-04 17:29:57 +03:00
if ( ( ! betaVersion | | cBetaVersion ( ) ) & & currentVersion > ( betaVersion ? cBetaVersion ( ) : uint64 ( AppVersion ) ) ) {
2016-01-11 23:43:29 +08:00
_updateThread = new QThread ( ) ;
connect ( _updateThread , SIGNAL ( finished ( ) ) , _updateThread , SLOT ( deleteLater ( ) ) ) ;
_updateChecker = new UpdateChecker ( _updateThread , url ) ;
_updateThread - > start ( ) ;
2014-05-30 12:53:19 +04:00
}
}
2016-01-11 23:43:29 +08:00
if ( _updateReply ) _updateReply - > deleteLater ( ) ;
_updateReply = 0 ;
if ( ! _updateThread ) {
2014-05-30 12:53:19 +04:00
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 ) {
2015-12-03 21:16:34 +03:00
if ( QRegularExpression ( " ^(tupdate|tmacupd|tmac32upd|tlinuxupd|tlinux32upd) \\ d+(_[a-z \\ d]+)?$ " , QRegularExpression : : CaseInsensitiveOption ) . match ( i - > fileName ( ) ) . hasMatch ( ) ) {
2014-05-30 12:53:19 +04:00
QFile ( i - > absoluteFilePath ( ) ) . remove ( ) ;
}
}
}
emit updateLatest ( ) ;
}
startUpdateCheck ( true ) ;
2015-03-02 15:34:16 +03:00
Local : : writeSettings ( ) ;
2014-05-30 12:53:19 +04:00
}
void Application : : updateFailedCurrent ( QNetworkReply : : NetworkError e ) {
LOG ( ( " App Error: could not get current version (update check): %1 " ) . arg ( e ) ) ;
2016-01-11 23:43:29 +08:00
if ( _updateReply ) _updateReply - > deleteLater ( ) ;
_updateReply = 0 ;
2014-05-30 12:53:19 +04:00
emit updateFailed ( ) ;
startUpdateCheck ( true ) ;
}
void Application : : onUpdateReady ( ) {
2016-01-11 23:43:29 +08:00
if ( _updateChecker ) {
_updateChecker - > deleteLater ( ) ;
_updateChecker = 0 ;
2014-05-30 12:53:19 +04:00
}
2016-01-11 23:43:29 +08:00
_updateCheckTimer . stop ( ) ;
2014-05-30 12:53:19 +04:00
cSetLastUpdateCheck ( unixtime ( ) ) ;
2015-03-02 15:34:16 +03:00
Local : : writeSettings ( ) ;
2014-05-30 12:53:19 +04:00
}
void Application : : onUpdateFailed ( ) {
2016-01-11 23:43:29 +08:00
if ( _updateChecker ) {
_updateChecker - > deleteLater ( ) ;
_updateChecker = 0 ;
if ( _updateThread ) _updateThread - > quit ( ) ;
_updateThread = 0 ;
2014-05-30 12:53:19 +04:00
}
cSetLastUpdateCheck ( unixtime ( ) ) ;
2015-03-02 15:34:16 +03:00
Local : : writeSettings ( ) ;
2014-05-30 12:53:19 +04:00
}
2016-01-11 23:43:29 +08:00
Application : : UpdatingState Application : : updatingState ( ) {
if ( ! _updateThread ) return Application : : UpdatingNone ;
if ( ! _updateChecker ) return Application : : UpdatingReady ;
return Application : : UpdatingDownload ;
2014-05-30 12:53:19 +04:00
}
2016-01-11 23:43:29 +08:00
int32 Application : : updatingSize ( ) {
if ( ! _updateChecker ) return 0 ;
return _updateChecker - > size ( ) ;
2014-05-30 12:53:19 +04:00
}
2016-01-11 23:43:29 +08:00
int32 Application : : updatingReady ( ) {
if ( ! _updateChecker ) return 0 ;
return _updateChecker - > ready ( ) ;
2014-05-30 12:53:19 +04:00
}
2016-01-11 23:43:29 +08:00
void Application : : stopUpdate ( ) {
if ( _updateReply ) {
_updateReply - > abort ( ) ;
_updateReply - > deleteLater ( ) ;
_updateReply = 0 ;
}
if ( _updateChecker ) {
_updateChecker - > deleteLater ( ) ;
_updateChecker = 0 ;
if ( _updateThread ) _updateThread - > quit ( ) ;
_updateThread = 0 ;
2014-05-30 12:53:19 +04:00
}
}
2016-01-11 23:43:29 +08:00
void Application : : startUpdateCheck ( bool forceWait ) {
2016-12-20 16:03:51 +03:00
if ( ! Sandbox : : started ( ) ) return ;
2016-01-11 23:43:29 +08:00
_updateCheckTimer . stop ( ) ;
if ( _updateThread | | _updateReply | | ! cAutoUpdate ( ) ) return ;
2015-10-15 13:51:10 +02:00
2016-01-11 23:43:29 +08:00
int32 constDelay = cBetaVersion ( ) ? 600 : UpdateDelayConstPart , randDelay = cBetaVersion ( ) ? 300 : UpdateDelayRandPart ;
2016-01-30 19:31:10 +03:00
int32 updateInSecs = cLastUpdateCheck ( ) + constDelay + int32 ( rand ( ) % randDelay ) - unixtime ( ) ;
2016-01-11 23:43:29 +08:00
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 ( ) ) ) ;
2016-04-27 15:02:17 +03:00
} else if ( cAlphaVersion ( ) ) {
url . setQuery ( qsl ( " version=%1&alpha=1 " ) . arg ( AppVersion ) ) ;
2016-01-11 23:43:29 +08:00
} 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 ) ;
}
}
2016-10-18 10:56:38 +03:00
# endif // !TDESKTOP_DISABLE_AUTOUPDATE
2016-01-11 23:43:29 +08:00
inline Application * application ( ) {
return qobject_cast < Application * > ( QApplication : : instance ( ) ) ;
}
2016-02-08 17:54:55 +03:00
namespace Sandbox {
2016-01-11 23:43:29 +08:00
QRect availableGeometry ( ) {
if ( Application * a = application ( ) ) {
return a - > desktop ( ) - > availableGeometry ( ) ;
}
return QDesktopWidget ( ) . availableGeometry ( ) ;
}
QRect screenGeometry ( const QPoint & p ) {
if ( Application * a = application ( ) ) {
return a - > desktop ( ) - > screenGeometry ( p ) ;
}
return QDesktopWidget ( ) . screenGeometry ( p ) ;
}
void setActiveWindow ( QWidget * window ) {
if ( Application * a = application ( ) ) {
a - > setActiveWindow ( window ) ;
}
}
bool isSavingSession ( ) {
if ( Application * a = application ( ) ) {
return a - > isSavingSession ( ) ;
}
return false ;
}
2016-02-07 18:38:49 +03:00
void installEventFilter ( QObject * filter ) {
if ( Application * a = application ( ) ) {
a - > installEventFilter ( filter ) ;
}
}
2016-07-11 21:05:46 +03:00
void removeEventFilter ( QObject * filter ) {
if ( Application * a = application ( ) ) {
a - > removeEventFilter ( filter ) ;
}
}
2016-01-30 19:31:10 +03:00
void execExternal ( const QString & cmd ) {
DEBUG_LOG ( ( " Application Info: executing external command '%1' " ) . arg ( cmd ) ) ;
if ( cmd = = " show " ) {
if ( App : : wnd ( ) ) {
App : : wnd ( ) - > activate ( ) ;
} else if ( PreLaunchWindow : : instance ( ) ) {
PreLaunchWindow : : instance ( ) - > activate ( ) ;
}
}
}
2016-01-11 23:43:29 +08:00
# ifndef TDESKTOP_DISABLE_AUTOUPDATE
void startUpdateCheck ( ) {
if ( Application * a = application ( ) ) {
return a - > startUpdateCheck ( false ) ;
}
}
void stopUpdate ( ) {
if ( Application * a = application ( ) ) {
return a - > stopUpdate ( ) ;
}
}
Application : : UpdatingState updatingState ( ) {
if ( Application * a = application ( ) ) {
return a - > updatingState ( ) ;
}
return Application : : UpdatingNone ;
}
int32 updatingSize ( ) {
if ( Application * a = application ( ) ) {
return a - > updatingSize ( ) ;
}
return 0 ;
}
int32 updatingReady ( ) {
if ( Application * a = application ( ) ) {
return a - > updatingReady ( ) ;
}
return 0 ;
}
void updateChecking ( ) {
if ( Application * a = application ( ) ) {
emit a - > updateChecking ( ) ;
}
}
void updateLatest ( ) {
if ( Application * a = application ( ) ) {
emit a - > updateLatest ( ) ;
}
}
void updateProgress ( qint64 ready , qint64 total ) {
if ( Application * a = application ( ) ) {
emit a - > updateProgress ( ready , total ) ;
}
}
void updateFailed ( ) {
if ( Application * a = application ( ) ) {
emit a - > updateFailed ( ) ;
}
}
void updateReady ( ) {
if ( Application * a = application ( ) ) {
emit a - > updateReady ( ) ;
}
}
2016-10-18 10:56:38 +03:00
# endif // !TDESKTOP_DISABLE_AUTOUPDATE
2016-02-05 22:53:01 +03:00
2016-01-11 23:43:29 +08:00
void connect ( const char * signal , QObject * object , const char * method ) {
if ( Application * a = application ( ) ) {
a - > connect ( a , signal , object , method ) ;
}
}
2016-02-08 17:54:55 +03:00
void launch ( ) {
2016-02-05 22:53:01 +03:00
t_assert ( application ( ) ! = 0 ) ;
float64 dpi = Application : : primaryScreen ( ) - > logicalDotsPerInch ( ) ;
if ( dpi < = 108 ) { // 0-96-108
cSetScreenScale ( dbisOne ) ;
} else if ( dpi < = 132 ) { // 108-120-132
cSetScreenScale ( dbisOneAndQuarter ) ;
} else if ( dpi < = 168 ) { // 132-144-168
cSetScreenScale ( dbisOneAndHalf ) ;
} else { // 168-192-inf
cSetScreenScale ( dbisTwo ) ;
}
2016-09-28 19:23:25 +03:00
auto devicePixelRatio = application ( ) - > devicePixelRatio ( ) ;
if ( devicePixelRatio > 1. ) {
if ( ( cPlatform ( ) ! = dbipMac & & cPlatform ( ) ! = dbipMacOld ) | | ( devicePixelRatio ! = 2. ) ) {
LOG ( ( " Found non-trivial Device Pixel Ratio: %1 " ) . arg ( devicePixelRatio ) ) ;
LOG ( ( " Environmental variables: QT_DEVICE_PIXEL_RATIO='%1' " ) . arg ( QString : : fromLatin1 ( qgetenv ( " QT_DEVICE_PIXEL_RATIO " ) ) ) ) ;
LOG ( ( " Environmental variables: QT_SCALE_FACTOR='%1' " ) . arg ( QString : : fromLatin1 ( qgetenv ( " QT_SCALE_FACTOR " ) ) ) ) ;
LOG ( ( " Environmental variables: QT_AUTO_SCREEN_SCALE_FACTOR='%1' " ) . arg ( QString : : fromLatin1 ( qgetenv ( " QT_AUTO_SCREEN_SCALE_FACTOR " ) ) ) ) ;
LOG ( ( " Environmental variables: QT_SCREEN_SCALE_FACTORS='%1' " ) . arg ( QString : : fromLatin1 ( qgetenv ( " QT_SCREEN_SCALE_FACTORS " ) ) ) ) ;
}
2016-02-05 22:53:01 +03:00
cSetRetina ( true ) ;
2016-09-28 19:23:25 +03:00
cSetRetinaFactor ( devicePixelRatio ) ;
2016-02-05 22:53:01 +03:00
cSetIntRetinaFactor ( int32 ( cRetinaFactor ( ) ) ) ;
cSetConfigScale ( dbisOne ) ;
cSetRealScale ( dbisOne ) ;
}
new AppClass ( ) ;
}
2016-01-11 23:43:29 +08:00
}
2016-10-28 15:44:28 +03:00
AppClass : : AppClass ( ) : QObject ( ) {
2016-01-11 23:43:29 +08:00
AppObject = this ;
2016-01-30 19:31:10 +03:00
Fonts : : start ( ) ;
2016-01-11 23:43:29 +08:00
ThirdParty : : start ( ) ;
2016-02-08 17:54:55 +03:00
Global : : start ( ) ;
2016-01-11 23:43:29 +08:00
Local : : start ( ) ;
if ( Local : : oldSettingsVersion ( ) < AppVersion ) {
psNewVersion ( ) ;
}
if ( cLaunchMode ( ) = = LaunchModeAutoStart & & ! cAutoStart ( ) ) {
psAutoStart ( false , true ) ;
application ( ) - > quit ( ) ;
return ;
}
2016-02-05 22:53:01 +03:00
if ( cRetina ( ) ) {
2016-01-11 23:43:29 +08:00
cSetConfigScale ( dbisOne ) ;
cSetRealScale ( dbisOne ) ;
}
2016-10-28 15:44:28 +03:00
loadLanguage ( ) ;
2016-01-11 23:43:29 +08:00
style : : startManager ( ) ;
anim : : startManager ( ) ;
historyInit ( ) ;
2016-09-23 19:04:26 +03:00
Media : : Player : : start ( ) ;
2016-10-02 12:30:28 +03:00
Window : : Notifications : : start ( ) ;
2016-01-11 23:43:29 +08:00
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " Application Info: inited... " ) ) ;
2016-01-11 23:43:29 +08:00
application ( ) - > installNativeEventFilter ( psNativeEventFilter ( ) ) ;
2016-02-14 18:58:39 +03:00
cChangeTimeFormat ( QLocale : : system ( ) . timeFormat ( QLocale : : ShortFormat ) ) ;
2016-01-11 23:43:29 +08:00
connect ( & killDownloadSessionsTimer , SIGNAL ( timeout ( ) ) , this , SLOT ( killDownloadSessions ( ) ) ) ;
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " Application Info: starting app... " ) ) ;
2016-01-11 23:43:29 +08:00
2016-10-02 12:30:28 +03:00
// Create mime database, so it won't be slow later.
QMimeDatabase ( ) . mimeTypeForName ( qsl ( " text/plain " ) ) ;
2016-01-11 23:43:29 +08:00
2016-04-13 00:31:28 +03:00
_window = new MainWindow ( ) ;
2016-02-14 18:58:39 +03:00
_window - > createWinId ( ) ;
_window - > init ( ) ;
Sandbox : : connect ( SIGNAL ( applicationStateChanged ( Qt : : ApplicationState ) ) , this , SLOT ( onAppStateChanged ( Qt : : ApplicationState ) ) ) ;
2016-01-11 23:43:29 +08:00
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " Application Info: window created... " ) ) ;
2016-01-11 23:43:29 +08:00
2016-02-27 22:39:51 +03:00
Shortcuts : : start ( ) ;
2016-09-27 16:37:18 +03:00
initLocationManager ( ) ;
2016-01-11 23:43:29 +08:00
App : : initMedia ( ) ;
Local : : ReadMapState state = Local : : readMap ( QByteArray ( ) ) ;
if ( state = = Local : : ReadMapPassNeeded ) {
2016-08-28 13:16:23 -06:00
Global : : SetLocalPasscode ( true ) ;
Global : : RefLocalPasscodeChanged ( ) . notify ( ) ;
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " Application Info: passcode needed... " ) ) ;
2016-01-11 23:43:29 +08:00
} else {
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " Application Info: local map read... " ) ) ;
2016-01-11 23:43:29 +08:00
MTP : : start ( ) ;
}
MTP : : setStateChangedHandler ( mtpStateChanged ) ;
MTP : : setSessionResetHandler ( mtpSessionReset ) ;
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " Application Info: MTP started... " ) ) ;
2016-01-11 23:43:29 +08:00
DEBUG_LOG ( ( " Application Info: showing. " ) ) ;
if ( state = = Local : : ReadMapPassNeeded ) {
2016-11-04 22:50:35 +03:00
_window - > setupPasscode ( ) ;
2016-01-11 23:43:29 +08:00
} else {
if ( MTP : : authedId ( ) ) {
2016-11-04 22:50:35 +03:00
_window - > setupMain ( ) ;
2016-01-11 23:43:29 +08:00
} else {
2016-11-04 22:50:35 +03:00
_window - > setupIntro ( ) ;
2016-01-11 23:43:29 +08:00
}
}
2016-02-14 18:58:39 +03:00
_window - > firstShow ( ) ;
2016-01-11 23:43:29 +08:00
if ( cStartToSettings ( ) ) {
2016-02-14 18:58:39 +03:00
_window - > showSettings ( ) ;
2016-01-11 23:43:29 +08:00
}
2016-03-20 11:16:35 +03:00
# ifndef TDESKTOP_DISABLE_NETWORK_PROXY
2016-01-11 23:43:29 +08:00
QNetworkProxyFactory : : setUseSystemConfiguration ( true ) ;
2016-10-18 10:56:38 +03:00
# endif // !TDESKTOP_DISABLE_NETWORK_PROXY
2016-01-11 23:43:29 +08:00
if ( state ! = Local : : ReadMapPassNeeded ) {
checkMapVersion ( ) ;
}
2016-02-18 19:36:33 +03:00
_window - > updateIsActive ( Global : : OnlineFocusTimeout ( ) ) ;
2016-02-27 22:39:51 +03:00
if ( ! Shortcuts : : errors ( ) . isEmpty ( ) ) {
const QStringList & errors ( Shortcuts : : errors ( ) ) ;
for ( QStringList : : const_iterator i = errors . cbegin ( ) , e = errors . cend ( ) ; i ! = e ; + + i ) {
LOG ( ( " Shortcuts Error: %1 " ) . arg ( * i ) ) ;
}
}
2016-01-11 23:43:29 +08:00
}
2016-10-28 15:44:28 +03:00
void AppClass : : loadLanguage ( ) {
if ( cLang ( ) < languageTest ) {
cSetLang ( Sandbox : : LangSystem ( ) ) ;
}
if ( cLang ( ) = = languageTest ) {
if ( QFileInfo ( cLangFile ( ) ) . exists ( ) ) {
LangLoaderPlain loader ( cLangFile ( ) ) ;
cSetLangErrors ( loader . errors ( ) ) ;
if ( ! cLangErrors ( ) . isEmpty ( ) ) {
LOG ( ( " Lang load errors: %1 " ) . arg ( cLangErrors ( ) ) ) ;
} else if ( ! loader . warnings ( ) . isEmpty ( ) ) {
LOG ( ( " Lang load warnings: %1 " ) . arg ( loader . warnings ( ) ) ) ;
}
} else {
cSetLang ( languageDefault ) ;
}
} else if ( cLang ( ) > languageDefault & & cLang ( ) < languageCount ) {
LangLoaderPlain loader ( qsl ( " :/langs/lang_ " ) + LanguageCodes [ cLang ( ) ] . c_str ( ) + qsl ( " .strings " ) ) ;
if ( ! loader . errors ( ) . isEmpty ( ) ) {
LOG ( ( " Lang load errors: %1 " ) . arg ( loader . errors ( ) ) ) ;
} else if ( ! loader . warnings ( ) . isEmpty ( ) ) {
LOG ( ( " Lang load warnings: %1 " ) . arg ( loader . warnings ( ) ) ) ;
}
}
application ( ) - > installTranslator ( _translator = new Translator ( ) ) ;
}
2016-01-11 23:43:29 +08:00
void AppClass : : regPhotoUpdate ( const PeerId & peer , const FullMsgId & msgId ) {
photoUpdates . insert ( msgId , peer ) ;
}
bool AppClass : : isPhotoUpdating ( const PeerId & peer ) {
for ( QMap < FullMsgId , PeerId > : : iterator i = photoUpdates . begin ( ) , e = photoUpdates . end ( ) ; i ! = e ; + + i ) {
if ( i . value ( ) = = peer ) {
return true ;
}
}
return false ;
}
void AppClass : : cancelPhotoUpdate ( const PeerId & peer ) {
for ( QMap < FullMsgId , PeerId > : : iterator i = photoUpdates . begin ( ) , e = photoUpdates . end ( ) ; i ! = e ; ) {
if ( i . value ( ) = = peer ) {
i = photoUpdates . erase ( i ) ;
} else {
+ + i ;
}
}
}
void AppClass : : selfPhotoCleared ( const MTPUserProfilePhoto & result ) {
2014-05-30 12:53:19 +04:00
if ( ! App : : self ( ) ) return ;
App : : self ( ) - > setPhoto ( result ) ;
emit peerPhotoDone ( App : : self ( ) - > id ) ;
}
2016-01-11 23:43:29 +08:00
void AppClass : : chatPhotoCleared ( PeerId peer , const MTPUpdates & updates ) {
2014-05-30 12:53:19 +04:00
if ( App : : main ( ) ) {
2015-04-02 13:33:19 +03:00
App : : main ( ) - > sentUpdatesReceived ( updates ) ;
2014-05-30 12:53:19 +04:00
}
cancelPhotoUpdate ( peer ) ;
emit peerPhotoDone ( peer ) ;
}
2016-01-11 23:43:29 +08:00
void AppClass : : selfPhotoDone ( const MTPphotos_Photo & result ) {
2014-05-30 12:53:19 +04:00
if ( ! App : : self ( ) ) return ;
2016-04-08 14:44:35 +04:00
const auto & photo ( result . c_photos_photo ( ) ) ;
2014-05-30 12:53:19 +04:00
App : : feedPhoto ( photo . vphoto ) ;
App : : feedUsers ( photo . vusers ) ;
cancelPhotoUpdate ( App : : self ( ) - > id ) ;
emit peerPhotoDone ( App : : self ( ) - > id ) ;
}
2016-01-11 23:43:29 +08:00
void AppClass : : chatPhotoDone ( PeerId peer , const MTPUpdates & updates ) {
2014-05-30 12:53:19 +04:00
if ( App : : main ( ) ) {
2015-04-02 13:33:19 +03:00
App : : main ( ) - > sentUpdatesReceived ( updates ) ;
2014-05-30 12:53:19 +04:00
}
cancelPhotoUpdate ( peer ) ;
emit peerPhotoDone ( peer ) ;
}
2016-01-11 23:43:29 +08:00
bool AppClass : : peerPhotoFail ( PeerId peer , const RPCError & error ) {
2016-04-08 14:44:35 +04:00
if ( MTP : : isDefaultHandledError ( error ) ) return false ;
2015-04-04 23:01:34 +03:00
LOG ( ( " Application Error: update photo failed %1: %2 " ) . arg ( error . type ( ) ) . arg ( error . description ( ) ) ) ;
2014-05-30 12:53:19 +04:00
cancelPhotoUpdate ( peer ) ;
emit peerPhotoFail ( peer ) ;
return true ;
}
2016-01-11 23:43:29 +08:00
void AppClass : : peerClearPhoto ( PeerId id ) {
2015-09-03 13:48:40 +03:00
if ( MTP : : authedId ( ) & & peerToUser ( id ) = = MTP : : authedId ( ) ) {
2016-09-13 13:03:21 +03:00
MTP : : send ( MTPphotos_UpdateProfilePhoto ( MTP_inputPhotoEmpty ( ) ) , rpcDone ( & AppClass : : selfPhotoCleared ) , rpcFail ( & AppClass : : peerPhotoFail , id ) ) ;
2015-09-03 13:48:40 +03:00
} else if ( peerIsChat ( id ) ) {
2016-01-11 23:43:29 +08:00
MTP : : send ( MTPmessages_EditChatPhoto ( peerToBareMTPInt ( id ) , MTP_inputChatPhotoEmpty ( ) ) , rpcDone ( & AppClass : : chatPhotoCleared , id ) , rpcFail ( & AppClass : : peerPhotoFail , id ) ) ;
2015-09-03 13:48:40 +03:00
} else if ( peerIsChannel ( id ) ) {
if ( ChannelData * channel = App : : channelLoaded ( id ) ) {
2016-01-11 23:43:29 +08:00
MTP : : send ( MTPchannels_EditPhoto ( channel - > inputChannel , MTP_inputChatPhotoEmpty ( ) ) , rpcDone ( & AppClass : : chatPhotoCleared , id ) , rpcFail ( & AppClass : : peerPhotoFail , id ) ) ;
2015-09-03 13:48:40 +03:00
}
2014-05-30 12:53:19 +04:00
}
}
2016-01-11 23:43:29 +08:00
void AppClass : : killDownloadSessionsStart ( int32 dc ) {
2014-10-30 19:23:44 +03:00
if ( killDownloadSessionTimes . constFind ( dc ) = = killDownloadSessionTimes . cend ( ) ) {
2014-11-05 20:43:32 +03:00
killDownloadSessionTimes . insert ( dc , getms ( ) + MTPAckSendWaiting + MTPKillFileSessionTimeout ) ;
2014-10-30 19:23:44 +03:00
}
if ( ! killDownloadSessionsTimer . isActive ( ) ) {
2014-11-05 20:43:32 +03:00
killDownloadSessionsTimer . start ( MTPAckSendWaiting + MTPKillFileSessionTimeout + 5 ) ;
2014-10-30 19:23:44 +03:00
}
}
2016-01-11 23:43:29 +08:00
void AppClass : : killDownloadSessionsStop ( int32 dc ) {
2014-10-30 19:23:44 +03:00
killDownloadSessionTimes . remove ( dc ) ;
if ( killDownloadSessionTimes . isEmpty ( ) & & killDownloadSessionsTimer . isActive ( ) ) {
killDownloadSessionsTimer . stop ( ) ;
}
}
2016-01-11 23:43:29 +08:00
void AppClass : : checkLocalTime ( ) {
2014-11-12 23:30:26 +03:00
if ( App : : main ( ) ) App : : main ( ) - > checkLastUpdate ( checkms ( ) ) ;
}
2016-01-11 23:43:29 +08:00
void AppClass : : onAppStateChanged ( Qt : : ApplicationState state ) {
2014-11-12 23:30:26 +03:00
checkLocalTime ( ) ;
2016-02-17 19:37:21 +03:00
if ( _window ) {
2016-02-18 19:36:33 +03:00
_window - > updateIsActive ( ( state = = Qt : : ApplicationActive ) ? Global : : OnlineFocusTimeout ( ) : Global : : OfflineBlurTimeout ( ) ) ;
2016-02-17 19:37:21 +03:00
}
2016-02-15 14:46:01 +03:00
if ( state ! = Qt : : ApplicationActive ) {
2016-10-26 19:43:13 +03:00
Ui : : Tooltip : : Hide ( ) ;
2016-02-15 14:46:01 +03:00
}
2014-11-12 23:30:26 +03:00
}
2016-03-19 19:55:15 +03:00
void AppClass : : call_handleHistoryUpdate ( ) {
Notify : : handlePendingHistoryUpdate ( ) ;
}
2016-04-14 22:24:42 +03:00
void AppClass : : call_handleUnreadCounterUpdate ( ) {
2016-11-06 20:23:13 +03:00
Global : : RefUnreadCounterUpdate ( ) . notify ( true ) ;
2016-04-14 22:24:42 +03:00
}
2016-05-25 20:59:21 +03:00
void AppClass : : call_handleFileDialogQueue ( ) {
while ( true ) {
if ( ! FileDialog : : processQuery ( ) ) {
return ;
}
}
}
2016-06-02 16:02:55 +03:00
void AppClass : : call_handleDelayedPeerUpdates ( ) {
Notify : : peerUpdatedSendDelayed ( ) ;
}
2016-08-18 21:27:43 +02:00
void AppClass : : call_handleObservables ( ) {
base : : HandleObservables ( ) ;
}
2016-01-11 23:43:29 +08:00
void AppClass : : killDownloadSessions ( ) {
2016-12-01 22:20:33 +03:00
auto ms = getms ( ) , left = static_cast < TimeMs > ( MTPAckSendWaiting ) + MTPKillFileSessionTimeout ;
for ( auto i = killDownloadSessionTimes . begin ( ) ; i ! = killDownloadSessionTimes . end ( ) ; ) {
2014-10-30 19:23:44 +03:00
if ( i . value ( ) < = ms ) {
2014-12-05 16:44:27 +03:00
for ( int j = 0 ; j < MTPDownloadSessionsCount ; + + j ) {
2016-03-24 11:57:11 +03:00
MTP : : stopSession ( MTP : : dldDcId ( i . key ( ) , j ) ) ;
2014-10-30 19:23:44 +03:00
}
i = killDownloadSessionTimes . erase ( i ) ;
} else {
if ( i . value ( ) - ms < left ) {
left = i . value ( ) - ms ;
}
+ + i ;
}
}
if ( ! killDownloadSessionTimes . isEmpty ( ) ) {
killDownloadSessionsTimer . start ( left ) ;
}
}
2016-02-26 12:29:07 +03:00
void AppClass : : photoUpdated ( const FullMsgId & msgId , bool silent , const MTPInputFile & file ) {
2014-05-30 12:53:19 +04:00
if ( ! App : : self ( ) ) return ;
2016-09-09 18:52:46 +03:00
auto i = photoUpdates . find ( msgId ) ;
2014-05-30 12:53:19 +04:00
if ( i ! = photoUpdates . end ( ) ) {
2016-09-09 18:52:46 +03:00
auto id = i . value ( ) ;
2015-09-03 13:48:40 +03:00
if ( MTP : : authedId ( ) & & peerToUser ( id ) = = MTP : : authedId ( ) ) {
2016-09-13 13:03:21 +03:00
MTP : : send ( MTPphotos_UploadProfilePhoto ( file ) , rpcDone ( & AppClass : : selfPhotoDone ) , rpcFail ( & AppClass : : peerPhotoFail , id ) ) ;
2015-09-17 00:15:13 +03:00
} else if ( peerIsChat ( id ) ) {
2016-09-09 18:52:46 +03:00
auto history = App : : history ( id ) ;
2016-09-13 13:03:21 +03:00
history - > sendRequestId = MTP : : send ( MTPmessages_EditChatPhoto ( history - > peer - > asChat ( ) - > inputChat , MTP_inputChatUploadedPhoto ( file ) ) , rpcDone ( & AppClass : : chatPhotoDone , id ) , rpcFail ( & AppClass : : peerPhotoFail , id ) , 0 , 0 , history - > sendRequestId ) ;
2015-09-17 00:15:13 +03:00
} else if ( peerIsChannel ( id ) ) {
2016-09-09 18:52:46 +03:00
auto history = App : : history ( id ) ;
2016-09-13 13:03:21 +03:00
history - > sendRequestId = MTP : : send ( MTPchannels_EditPhoto ( history - > peer - > asChannel ( ) - > inputChannel , MTP_inputChatUploadedPhoto ( file ) ) , rpcDone ( & AppClass : : chatPhotoDone , id ) , rpcFail ( & AppClass : : peerPhotoFail , id ) , 0 , 0 , history - > sendRequestId ) ;
2014-05-30 12:53:19 +04:00
}
}
}
2016-01-11 23:43:29 +08:00
void AppClass : : onSwitchDebugMode ( ) {
2015-04-02 13:33:19 +03:00
if ( cDebug ( ) ) {
QFile ( cWorkingDir ( ) + qsl ( " tdata/withdebug " ) ) . remove ( ) ;
cSetDebug ( false ) ;
2016-10-28 15:44:28 +03:00
App : : restart ( ) ;
2015-04-02 13:33:19 +03:00
} else {
2014-05-30 12:53:19 +04:00
cSetDebug ( true ) ;
2016-01-11 23:43:29 +08:00
DEBUG_LOG ( ( " Debug logs started. " ) ) ;
2014-09-30 07:11:09 -07:00
QFile f ( cWorkingDir ( ) + qsl ( " tdata/withdebug " ) ) ;
if ( f . open ( QIODevice : : WriteOnly ) ) {
f . write ( " 1 " ) ;
f . close ( ) ;
}
2015-12-07 21:09:05 +03:00
Ui : : hideLayer ( ) ;
2015-04-02 13:33:19 +03:00
}
}
2016-04-11 14:59:01 +04:00
void AppClass : : onSwitchWorkMode ( ) {
Global : : SetDialogsModeEnabled ( ! Global : : DialogsModeEnabled ( ) ) ;
Global : : SetDialogsMode ( Dialogs : : Mode : : All ) ;
Local : : writeUserSettings ( ) ;
2016-10-28 15:44:28 +03:00
App : : restart ( ) ;
2016-04-11 14:59:01 +04:00
}
2016-01-11 23:43:29 +08:00
void AppClass : : onSwitchTestMode ( ) {
2015-04-02 13:33:19 +03:00
if ( cTestMode ( ) ) {
QFile ( cWorkingDir ( ) + qsl ( " tdata/withtestmode " ) ) . remove ( ) ;
cSetTestMode ( false ) ;
} else {
QFile f ( cWorkingDir ( ) + qsl ( " tdata/withtestmode " ) ) ;
if ( f . open ( QIODevice : : WriteOnly ) ) {
f . write ( " 1 " ) ;
f . close ( ) ;
}
cSetTestMode ( true ) ;
2014-05-30 12:53:19 +04:00
}
2016-10-28 15:44:28 +03:00
App : : restart ( ) ;
2014-05-30 12:53:19 +04:00
}
2016-01-11 23:43:29 +08:00
FileUploader * AppClass : : uploader ( ) {
2016-03-02 20:34:42 +02:00
if ( ! _uploader & & ! App : : quitting ( ) ) _uploader = new FileUploader ( ) ;
2016-01-11 23:43:29 +08:00
return _uploader ;
2014-05-30 12:53:19 +04:00
}
2016-01-11 23:43:29 +08:00
void AppClass : : uploadProfilePhoto ( const QImage & tosend , const PeerId & peerId ) {
2014-05-30 12:53:19 +04:00
PreparedPhotoThumbs photoThumbs ;
QVector < MTPPhotoSize > photoSizes ;
2016-11-15 14:56:49 +03:00
auto thumb = App : : pixmapFromImageInPlace ( tosend . scaled ( 160 , 160 , Qt : : KeepAspectRatio , Qt : : SmoothTransformation ) ) ;
2014-05-30 12:53:19 +04:00
photoThumbs . insert ( ' a ' , thumb ) ;
photoSizes . push_back ( MTP_photoSize ( MTP_string ( " a " ) , MTP_fileLocationUnavailable ( MTP_long ( 0 ) , MTP_int ( 0 ) , MTP_long ( 0 ) ) , MTP_int ( thumb . width ( ) ) , MTP_int ( thumb . height ( ) ) , MTP_int ( 0 ) ) ) ;
2016-11-15 14:56:49 +03:00
auto medium = App : : pixmapFromImageInPlace ( tosend . scaled ( 320 , 320 , Qt : : KeepAspectRatio , Qt : : SmoothTransformation ) ) ;
2014-08-15 15:19:32 +04:00
photoThumbs . insert ( ' b ' , medium ) ;
photoSizes . push_back ( MTP_photoSize ( MTP_string ( " b " ) , MTP_fileLocationUnavailable ( MTP_long ( 0 ) , MTP_int ( 0 ) , MTP_long ( 0 ) ) , MTP_int ( medium . width ( ) ) , MTP_int ( medium . height ( ) ) , MTP_int ( 0 ) ) ) ;
2016-11-15 14:56:49 +03:00
auto full = QPixmap : : fromImage ( tosend , Qt : : ColorOnly ) ;
2014-05-30 12:53:19 +04:00
photoThumbs . insert ( ' c ' , full ) ;
photoSizes . push_back ( MTP_photoSize ( MTP_string ( " c " ) , MTP_fileLocationUnavailable ( MTP_long ( 0 ) , MTP_int ( 0 ) , MTP_long ( 0 ) ) , MTP_int ( full . width ( ) ) , MTP_int ( full . height ( ) ) , MTP_int ( 0 ) ) ) ;
QByteArray jpeg ;
QBuffer jpegBuffer ( & jpeg ) ;
full . save ( & jpegBuffer , " JPG " , 87 ) ;
2016-03-24 13:12:18 +03:00
PhotoId id = rand_value < PhotoId > ( ) ;
2014-05-30 12:53:19 +04:00
2016-09-13 13:03:21 +03:00
MTPDphoto : : Flags photoFlags = 0 ;
auto photo = MTP_photo ( MTP_flags ( photoFlags ) , MTP_long ( id ) , MTP_long ( 0 ) , MTP_int ( unixtime ( ) ) , MTP_vector < MTPPhotoSize > ( photoSizes ) ) ;
2014-05-30 12:53:19 +04:00
QString file , filename ;
int32 filesize = 0 ;
QByteArray data ;
2016-11-28 18:45:07 +03:00
SendMediaReady ready ( SendMediaType : : Photo , file , filename , filesize , data , id , id , qsl ( " jpg " ) , peerId , photo , photoThumbs , MTP_documentEmpty ( MTP_long ( 0 ) ) , jpeg , 0 ) ;
2014-05-30 12:53:19 +04:00
2016-02-26 12:29:07 +03:00
connect ( App : : uploader ( ) , SIGNAL ( photoReady ( const FullMsgId & , bool , const MTPInputFile & ) ) , App : : app ( ) , SLOT ( photoUpdated ( const FullMsgId & , bool , const MTPInputFile & ) ) , Qt : : UniqueConnection ) ;
2014-05-30 12:53:19 +04:00
2015-09-03 13:48:40 +03:00
FullMsgId newId ( peerToChannel ( peerId ) , clientMsgId ( ) ) ;
2014-05-30 12:53:19 +04:00
App : : app ( ) - > regPhotoUpdate ( peerId , newId ) ;
App : : uploader ( ) - > uploadMedia ( newId , ready ) ;
}
2016-01-11 23:43:29 +08:00
void AppClass : : checkMapVersion ( ) {
2015-06-02 15:29:02 +03:00
if ( Local : : oldMapVersion ( ) < AppVersion ) {
2015-03-02 15:34:16 +03:00
if ( Local : : oldMapVersion ( ) ) {
QString versionFeatures ;
2017-01-27 10:08:59 +03:00
if ( ( cAlphaVersion ( ) | | cBetaVersion ( ) ) & & Local : : oldMapVersion ( ) < 1000003 ) {
versionFeatures = QString : : fromUtf8 ( " \xe2 \x80 \x94 Audio device is opened only when some sound is played. \n \xe2 \x80 \x94 On Windows Vista and later audio device should switch after the system default changes. " ) ;
2017-01-19 11:41:19 +03:00
} else if ( ! ( cAlphaVersion ( ) | | cBetaVersion ( ) ) & & Local : : oldMapVersion ( ) < 1000002 ) {
2016-04-05 11:45:53 +04:00
versionFeatures = langNewVersionText ( ) ;
2015-09-10 16:20:22 +03:00
} else {
versionFeatures = lang ( lng_new_version_minor ) . trimmed ( ) ;
2015-03-02 15:34:16 +03:00
}
if ( ! versionFeatures . isEmpty ( ) ) {
2017-01-11 22:31:31 +04:00
versionFeatures = lng_new_version_wrap ( lt_version , QString : : fromLatin1 ( AppVersionStr . c_str ( ) ) , lt_changes , versionFeatures , lt_link , qsl ( " https://desktop.telegram.org/changelog " ) ) ;
2016-12-13 10:59:57 +03:00
_window - > serviceNotificationLocal ( versionFeatures ) ;
2015-03-02 15:34:16 +03:00
}
}
}
}
2016-01-11 23:43:29 +08:00
AppClass : : ~ AppClass ( ) {
2016-02-27 22:39:51 +03:00
Shortcuts : : finish ( ) ;
2016-10-07 19:45:45 +03:00
delete base : : take ( _window ) ;
2016-12-03 15:10:35 +03:00
App : : clearHistories ( ) ;
2016-09-03 17:27:22 -04:00
2016-10-02 12:30:28 +03:00
Window : : Notifications : : finish ( ) ;
2016-09-03 17:27:22 -04:00
2014-05-30 12:53:19 +04:00
anim : : stopManager ( ) ;
2015-12-31 03:09:20 +08:00
stopWebLoadManager ( ) ;
2014-05-30 12:53:19 +04:00
App : : deinitMedia ( ) ;
2016-09-27 16:37:18 +03:00
deinitLocationManager ( ) ;
2015-12-28 20:23:27 +03:00
2016-03-01 21:41:06 +02:00
MTP : : finish ( ) ;
2016-02-18 19:36:33 +03:00
2016-09-03 17:27:22 -04:00
AppObject = nullptr ;
2016-10-07 19:45:45 +03:00
delete base : : take ( _uploader ) ;
delete base : : take ( _translator ) ;
2014-05-30 12:53:19 +04:00
2016-10-28 15:44:28 +03:00
Window : : Theme : : Unload ( ) ;
2015-02-03 18:02:46 +03:00
2016-09-23 19:04:26 +03:00
Media : : Player : : finish ( ) ;
2014-05-30 12:53:19 +04:00
style : : stopManager ( ) ;
2016-01-01 17:58:05 +08:00
2016-01-11 23:43:29 +08:00
Local : : finish ( ) ;
2016-02-08 17:54:55 +03:00
Global : : finish ( ) ;
2016-01-11 23:43:29 +08:00
ThirdParty : : finish ( ) ;
2014-05-30 12:53:19 +04:00
}
2016-01-11 23:43:29 +08:00
AppClass * AppClass : : app ( ) {
return AppObject ;
2014-05-30 12:53:19 +04:00
}
2016-04-13 00:31:28 +03:00
MainWindow * AppClass : : wnd ( ) {
2016-10-02 12:30:28 +03:00
return AppObject ? AppObject - > _window : nullptr ;
2014-12-20 00:20:30 +03:00
}
2016-01-11 23:43:29 +08:00
MainWidget * AppClass : : main ( ) {
2016-10-02 12:30:28 +03:00
return ( AppObject & & AppObject - > _window ) ? AppObject - > _window - > mainWidget ( ) : nullptr ;
2014-05-30 12:53:19 +04:00
}