mirror of https://github.com/procxx/kepka.git
version 0.6.9 - some network and protocol improvements, checkboxes in photos overview, other fixes
This commit is contained in:
parent
c89f13bb53
commit
868b9843b0
|
@ -1,5 +1,5 @@
|
|||
AppVersionStr=0.6.8
|
||||
AppVersion=6008
|
||||
AppVersionStr=0.6.9
|
||||
AppVersion=6009
|
||||
|
||||
if [ ! -f "./../Linux/Release/deploy/$AppVersionStr/tlinuxupd$AppVersion" ]; then
|
||||
echo "tlinuxupd$AppVersion not found!";
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
AppVersionStr=0.6.8
|
||||
AppVersion=6008
|
||||
AppVersionStr=0.6.9
|
||||
AppVersion=6009
|
||||
|
||||
if [ ! -f "./../Linux/Release/deploy/$AppVersionStr/tlinux32upd$AppVersion" ]; then
|
||||
echo "tlinux32upd$AppVersion not found!"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
AppVersionStr=0.6.8
|
||||
AppVersion=6008
|
||||
AppVersionStr=0.6.9
|
||||
AppVersion=6009
|
||||
|
||||
if [ ! -f "./../Mac/Release/deploy/$AppVersionStr/tmacupd$AppVersion" ]; then
|
||||
echo "tmacupd$AppVersion not found!"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
AppVersionStr=0.6.8
|
||||
AppVersion=6008
|
||||
AppVersionStr=0.6.9
|
||||
AppVersion=6009
|
||||
|
||||
if [ ! -f "./../Win32/Deploy/deploy/$AppVersionStr/tupdate$AppVersion" ]; then
|
||||
echo "tupdate$AppVersion not found!"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
AppVersionStr=0.6.8
|
||||
AppVersion=6008
|
||||
AppVersionStr=0.6.9
|
||||
AppVersion=6009
|
||||
|
||||
if [ -d "./../Linux/Release/deploy/$AppVersionStr" ]; then
|
||||
echo "Deploy folder for version $AppVersionStr already exists!"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
AppVersionStr=0.6.8
|
||||
AppVersion=6008
|
||||
AppVersionStr=0.6.9
|
||||
AppVersion=6009
|
||||
|
||||
if [ -d "./../Linux/Release/deploy/$AppVersionStr" ]; then
|
||||
echo "Deploy folder for version $AppVersionStr already exists!"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
AppVersionStr=0.6.8
|
||||
AppVersion=6008
|
||||
AppVersionStr=0.6.9
|
||||
AppVersion=6009
|
||||
|
||||
echo ""
|
||||
echo "Preparing version $AppVersionStr.."
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
@echo OFF
|
||||
|
||||
set "AppVersionStr=0.6.8"
|
||||
set "AppVersionStr=0.6.9"
|
||||
echo.
|
||||
echo Preparing version %AppVersionStr%..
|
||||
echo.
|
||||
|
|
|
@ -61,7 +61,10 @@ lng_connecting: "Connecting..";
|
|||
lng_reconnecting: "Reconnect in %1 s..";
|
||||
lng_reconnecting_try_now: "Try now";
|
||||
|
||||
lng_status_offline: "offline";
|
||||
lng_status_offline: "last seen a long time ago";
|
||||
lng_status_recently: "last seen recently";
|
||||
lng_status_last_week: "last seen within a week";
|
||||
lng_status_last_month: "last seen within a month";
|
||||
lng_status_invisible: "invisible";
|
||||
lng_status_lastseen: "last seen {when}";
|
||||
lng_status_lastseen_now: "just now";
|
||||
|
|
|
@ -1572,6 +1572,9 @@ medviewPhotoSpritePos: point(14px, 14px);
|
|||
|
||||
overviewPhotoSkip: 10px;
|
||||
overviewPhotoMinSize: 100px;
|
||||
overviewPhotoCheck: sprite(245px, 308px, 32px, 32px);
|
||||
overviewPhotoChecked: sprite(278px, 308px, 32px, 32px);
|
||||
overviewPhotoSelectOverlay: #0a7bb03f;
|
||||
|
||||
// Mac specific
|
||||
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
|
||||
#define MyAppShortName "Telegram"
|
||||
#define MyAppName "Telegram Desktop"
|
||||
#define MyAppVersion "0.6.8"
|
||||
#define MyAppVersionZero "0.6.8"
|
||||
#define MyAppFullVersion "0.6.8.0"
|
||||
#define MyAppVersion "0.6.9"
|
||||
#define MyAppVersionZero "0.6.9"
|
||||
#define MyAppFullVersion "0.6.9.0"
|
||||
#define MyAppPublisher "Telegram Messenger LLP"
|
||||
#define MyAppURL "https://tdesktop.com"
|
||||
#define MyAppExeName "Telegram.exe"
|
||||
|
|
|
@ -183,8 +183,15 @@ namespace App {
|
|||
}
|
||||
|
||||
QString onlineText(int32 online, int32 now, bool precise) {
|
||||
if (!online) return lang(lng_status_offline);
|
||||
if (online < 0) return lang(lng_status_invisible);
|
||||
if (online <= 0) {
|
||||
switch (online) {
|
||||
case 0: return lang(lng_status_offline);
|
||||
case -2: return lang(lng_status_recently);
|
||||
case -3: return lang(lng_status_last_week);
|
||||
case -4: return lang(lng_status_last_month);
|
||||
}
|
||||
return lang(lng_status_invisible);
|
||||
}
|
||||
if (online > now) {
|
||||
return lang(lng_status_online);
|
||||
}
|
||||
|
@ -329,6 +336,10 @@ namespace App {
|
|||
|
||||
data->loaded = true;
|
||||
if (status) switch (status->type()) {
|
||||
case mtpc_userStatusEmpty: data->onlineTill = 0; break;
|
||||
case mtpc_userStatusRecently: data->onlineTill = -2; break;
|
||||
case mtpc_userStatusLastWeek: data->onlineTill = -3; break;
|
||||
case mtpc_userStatusLastMonth: data->onlineTill = -4; break;
|
||||
case mtpc_userStatusOffline: data->onlineTill = status->c_userStatusOffline().vwas_online.v; break;
|
||||
case mtpc_userStatusOnline: data->onlineTill = status->c_userStatusOnline().vexpires.v; break;
|
||||
}
|
||||
|
@ -408,7 +419,7 @@ namespace App {
|
|||
if (!data) continue;
|
||||
|
||||
data->loaded = true;
|
||||
data->updateName(title.trimmed(), QString());
|
||||
data->updateName(title.trimmed(), QString(), QString());
|
||||
|
||||
if (App::main()) App::main()->peerUpdated(data);
|
||||
}
|
||||
|
|
|
@ -633,7 +633,6 @@ void Application::startApp() {
|
|||
|
||||
readSupportTemplates();
|
||||
|
||||
MTP::setLayer(mtpLayerMax);
|
||||
MTP::start();
|
||||
|
||||
MTP::setStateChangedHandler(mtpStateChanged);
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 56 KiB |
Binary file not shown.
Before Width: | Height: | Size: 96 KiB After Width: | Height: | Size: 97 KiB |
|
@ -281,7 +281,7 @@ bool AddContactBox::onSaveFail(const RPCError &error) {
|
|||
QString err(error.type());
|
||||
QString firstName = _firstInput.text().trimmed(), lastName = _lastInput.text().trimmed();
|
||||
if (err == "CHAT_TITLE_NOT_MODIFIED") {
|
||||
_peer->updateName(firstName, QString());
|
||||
_peer->updateName(firstName, QString(), QString());
|
||||
emit closed();
|
||||
return true;
|
||||
} else if (err == "NO_CHAT_TITLE") {
|
||||
|
|
|
@ -231,6 +231,7 @@ void AddParticipantInner::mousePressEvent(QMouseEvent *e) {
|
|||
}
|
||||
|
||||
void AddParticipantInner::chooseParticipant() {
|
||||
_time = unixtime();
|
||||
int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2, from;
|
||||
if (_filter.isEmpty()) {
|
||||
if (!_sel || contactData(_sel)->inchat) return;
|
||||
|
@ -293,6 +294,7 @@ void AddParticipantInner::updateSel() {
|
|||
}
|
||||
|
||||
void AddParticipantInner::updateFilter(QString filter) {
|
||||
_time = unixtime();
|
||||
QStringList f;
|
||||
if (!filter.isEmpty()) {
|
||||
QStringList filterList = filter.split(cWordSplit(), QString::SkipEmptyParts);
|
||||
|
@ -405,6 +407,7 @@ AddParticipantInner::~AddParticipantInner() {
|
|||
}
|
||||
|
||||
void AddParticipantInner::selectSkip(int32 dir) {
|
||||
_time = unixtime();
|
||||
_mouseSel = false;
|
||||
int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2, origDir = dir;
|
||||
if (_filter.isEmpty()) {
|
||||
|
|
|
@ -17,8 +17,8 @@ Copyright (c) 2014 John Preston, https://tdesktop.com
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
static const int32 AppVersion = 6008;
|
||||
static const wchar_t *AppVersionStr = L"0.6.8";
|
||||
static const int32 AppVersion = 6009;
|
||||
static const wchar_t *AppVersionStr = L"0.6.9";
|
||||
|
||||
static const wchar_t *AppNameOld = L"Telegram Win (Unofficial)";
|
||||
static const wchar_t *AppName = L"Telegram Desktop";
|
||||
|
|
|
@ -3975,7 +3975,7 @@ QString textAccentFold(const QString &text) {
|
|||
continue;
|
||||
}
|
||||
if (ch->isHighSurrogate() && ch + 1 < e && (ch + 1)->isLowSurrogate()) {
|
||||
QChar noAccent = QChar::surrogateToUcs4(*ch, *(ch + 1));
|
||||
QChar noAccent = chNoAccent(QChar::surrogateToUcs4(*ch, *(ch + 1)));
|
||||
if (noAccent.unicode() > 0) {
|
||||
copying = true;
|
||||
result[i] = noAccent;
|
||||
|
|
|
@ -296,12 +296,13 @@ const ChatData *PeerData::asChat() const {
|
|||
return chat ? static_cast<const ChatData *>(this) : App::chat(id | 0x100000000L);
|
||||
}
|
||||
|
||||
void PeerData::updateName(const QString &newName, const QString &newNameOrPhone) {
|
||||
if (name == newName && nameOrPhone == newNameOrPhone) return;
|
||||
void PeerData::updateName(const QString &newName, const QString &newNameOrPhone, const QString &newUsername) {
|
||||
if (name == newName && nameOrPhone == newNameOrPhone && (chat || asUser()->username == newUsername)) return;
|
||||
|
||||
++nameVersion;
|
||||
name = newName;
|
||||
nameOrPhone = newNameOrPhone;
|
||||
if (!chat) asUser()->username = newUsername;
|
||||
Names oldNames = names;
|
||||
NameFirstChars oldChars = chars;
|
||||
fillNames();
|
||||
|
@ -352,24 +353,23 @@ void PeerData::fillNames() {
|
|||
|
||||
|
||||
void UserData::setName(const QString &first, const QString &last, const QString &phoneName, const QString &usern) {
|
||||
bool updName = !first.isEmpty() || !last.isEmpty();
|
||||
|
||||
if (username != usern) {
|
||||
username = usern;
|
||||
if (App::main()) {
|
||||
App::main()->peerUsernameChanged(this);
|
||||
}
|
||||
}
|
||||
bool updName = !first.isEmpty() || !last.isEmpty(), updUsername = (username != usern);
|
||||
|
||||
if (updName && first.trimmed().isEmpty()) {
|
||||
firstName = last;
|
||||
lastName = QString();
|
||||
updateName(firstName, phoneName);
|
||||
updateName(firstName, phoneName, usern);
|
||||
} else {
|
||||
if (updName) {
|
||||
firstName = first;
|
||||
lastName = last;
|
||||
}
|
||||
updateName(firstName + ' ' + lastName, phoneName);
|
||||
updateName(firstName + ' ' + lastName, phoneName, usern);
|
||||
}
|
||||
if (updUsername) {
|
||||
if (App::main()) {
|
||||
App::main()->peerUsernameChanged(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1168,7 +1168,7 @@ HistoryItem *History::createItem(HistoryBlock *block, const MTPmessage &msg, boo
|
|||
case mtpc_messageActionChatEditTitle: {
|
||||
const MTPDmessageActionChatEditTitle &d(action.c_messageActionChatEditTitle());
|
||||
ChatData *chat = peer->asChat();
|
||||
if (chat) chat->updateName(qs(d.vtitle), QString());
|
||||
if (chat) chat->updateName(qs(d.vtitle), QString(), QString());
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
@ -3074,7 +3074,7 @@ void ImageLinkManager::init() {
|
|||
App::setProxySettings(*manager);
|
||||
|
||||
connect(manager, SIGNAL(authenticationRequired(QNetworkReply*, QAuthenticator*)), this, SLOT(onFailed(QNetworkReply*)));
|
||||
connect(manager, SIGNAL(sslErrors(QNetworkReply*, const QList<QSslError>&errors)), this, SLOT(onFailed(QNetworkReply*)));
|
||||
connect(manager, SIGNAL(sslErrors(QNetworkReply*, const QList<QSslError>&)), this, SLOT(onFailed(QNetworkReply*)));
|
||||
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(onFinished(QNetworkReply*)));
|
||||
|
||||
if (black) delete black;
|
||||
|
|
|
@ -82,7 +82,7 @@ struct PeerData {
|
|||
ChatData *asChat();
|
||||
const ChatData *asChat() const;
|
||||
|
||||
void updateName(const QString &newName, const QString &newNameOrPhone);
|
||||
void updateName(const QString &newName, const QString &newNameOrPhone, const QString &newUsername);
|
||||
|
||||
void fillNames();
|
||||
|
||||
|
|
|
@ -1548,7 +1548,7 @@ HistoryWidget::HistoryWidget(QWidget *parent) : QWidget(parent)
|
|||
connect(&_attachDocument, SIGNAL(clicked()), this, SLOT(onDocumentSelect()));
|
||||
connect(&_attachPhoto, SIGNAL(clicked()), this, SLOT(onPhotoSelect()));
|
||||
connect(&_field, SIGNAL(submitted(bool)), this, SLOT(onSend(bool)));
|
||||
connect(&_field, SIGNAL(cancelled()), this, SIGNAL(cancelled()));
|
||||
connect(&_field, SIGNAL(cancelled()), this, SLOT(onCancel()));
|
||||
connect(&_field, SIGNAL(tabbed()), this, SLOT(onFieldTabbed()));
|
||||
connect(&_field, SIGNAL(resized()), this, SLOT(onFieldResize()));
|
||||
connect(&_field, SIGNAL(focused()), this, SLOT(onFieldFocused()));
|
||||
|
@ -3161,6 +3161,11 @@ void HistoryWidget::setFieldText(const QString &text) {
|
|||
noTypingUpdate = false;
|
||||
}
|
||||
|
||||
void HistoryWidget::onCancel() {
|
||||
showPeer(0);
|
||||
emit cancelled();
|
||||
}
|
||||
|
||||
void HistoryWidget::peerUpdated(PeerData *data) {
|
||||
if (data && data == histPeer) {
|
||||
updateListSize();
|
||||
|
|
|
@ -343,6 +343,8 @@ signals:
|
|||
|
||||
public slots:
|
||||
|
||||
void onCancel();
|
||||
|
||||
void peerUpdated(PeerData *data);
|
||||
|
||||
void cancelTyping();
|
||||
|
|
|
@ -2252,6 +2252,9 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
|
|||
if (user) {
|
||||
switch (d.vstatus.type()) {
|
||||
case mtpc_userStatusEmpty: user->onlineTill = 0; break;
|
||||
case mtpc_userStatusRecently: user->onlineTill = -2; break;
|
||||
case mtpc_userStatusLastWeek: user->onlineTill = -3; break;
|
||||
case mtpc_userStatusLastMonth: user->onlineTill = -4; break;
|
||||
case mtpc_userStatusOffline: user->onlineTill = d.vstatus.c_userStatusOffline().vwas_online.v; break;
|
||||
case mtpc_userStatusOnline: user->onlineTill = d.vstatus.c_userStatusOnline().vexpires.v; break;
|
||||
}
|
||||
|
@ -2263,8 +2266,12 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
|
|||
case mtpc_updateUserName: {
|
||||
const MTPDupdateUserName &d(update.c_updateUserName());
|
||||
UserData *user = App::userLoaded(d.vuser_id.v);
|
||||
if (user && user->contact <= 0) {
|
||||
user->setName(textOneLine(qs(d.vfirst_name)), textOneLine(qs(d.vlast_name)), user->nameOrPhone, textOneLine(qs(d.vusername)));
|
||||
if (user) {
|
||||
if (user->contact <= 0) {
|
||||
user->setName(textOneLine(qs(d.vfirst_name)), textOneLine(qs(d.vlast_name)), user->nameOrPhone, textOneLine(qs(d.vusername)));
|
||||
} else {
|
||||
user->setName(textOneLine(user->firstName), textOneLine(user->lastName), user->nameOrPhone, textOneLine(qs(d.vusername)));
|
||||
}
|
||||
if (App::main()) App::main()->peerUpdated(user);
|
||||
}
|
||||
} break;
|
||||
|
|
|
@ -177,11 +177,11 @@ with open('scheme.tl') as f:
|
|||
funcsText += '\tMTP' + name + '(' + ', '.join(prmsStr) + ') : ' + ', '.join(prmsInit) + ' {\n\t}\n';
|
||||
funcsText += '\n';
|
||||
|
||||
funcsText += '\tuint32 size() const {\n'; # count size
|
||||
funcsText += '\tuint32 innerLength() const {\n'; # count size
|
||||
size = [];
|
||||
for k in prmsList:
|
||||
v = prms[k];
|
||||
size.append('v' + k + '.size()');
|
||||
size.append('v' + k + '.innerLength()');
|
||||
if (not len(size)):
|
||||
size.append('0');
|
||||
funcsText += '\t\treturn ' + ' + '.join(size) + ';\n';
|
||||
|
@ -402,7 +402,7 @@ for restype in typesList:
|
|||
writeText += '\t\t';
|
||||
readText += '\tv.v' + paramName + '.read(from, end);\n';
|
||||
writeText += '\tv.v' + paramName + '.write(to);\n';
|
||||
sizeList.append('v.v' + paramName + '.size()');
|
||||
sizeList.append('v.v' + paramName + '.innerLength()');
|
||||
|
||||
forwards += 'class MTPD' + name + ';\n'; # data class forward declaration
|
||||
|
||||
|
@ -505,8 +505,8 @@ for restype in typesList:
|
|||
if (withData):
|
||||
typesText += getters;
|
||||
|
||||
typesText += '\n\tuint32 size() const;\n'; # size method
|
||||
inlineMethods += '\ninline uint32 MTP' + restype + '::size() const {\n';
|
||||
typesText += '\n\tuint32 innerLength() const;\n'; # size method
|
||||
inlineMethods += '\ninline uint32 MTP' + restype + '::innerLength() const {\n';
|
||||
if (withType and sizeCases):
|
||||
inlineMethods += '\tswitch (_type) {\n';
|
||||
inlineMethods += sizeCases;
|
||||
|
|
|
@ -350,10 +350,6 @@ namespace _mtp_internal {
|
|||
requestsByDC.remove(requestId);
|
||||
}
|
||||
|
||||
uint32 getLayer() {
|
||||
return layer;
|
||||
}
|
||||
|
||||
mtpRequestId storeRequest(mtpRequest &request, const RPCResponseHandler &parser) {
|
||||
mtpRequestId res = reqid();
|
||||
request->requestId = res;
|
||||
|
@ -379,20 +375,25 @@ namespace _mtp_internal {
|
|||
return req;
|
||||
}
|
||||
|
||||
void wrapInvokeAfter(mtpRequest &to, const mtpRequest &from, const mtpRequestMap &haveSent) {
|
||||
void wrapInvokeAfter(mtpRequest &to, const mtpRequest &from, const mtpRequestMap &haveSent, int32 skipBeforeRequest) {
|
||||
mtpMsgId afterId(*(mtpMsgId*)(from->after->data() + 4));
|
||||
mtpRequestMap::const_iterator i = afterId ? haveSent.constFind(afterId) : haveSent.cend();
|
||||
int32 size = to->size(), len = (*from)[7] >> 2, headlen = 4, fulllen = headlen + len;
|
||||
int32 size = to->size(), lenInInts = (from.innerLength() >> 2), headlen = 4, fulllen = headlen + lenInInts;
|
||||
if (i == haveSent.constEnd()) { // no invoke after or such msg was not sent or was completed recently
|
||||
to->resize(size + fulllen);
|
||||
memcpy(to->data() + size, from->constData() + 4, fulllen * sizeof(mtpPrime));
|
||||
to->resize(size + fulllen + skipBeforeRequest);
|
||||
if (skipBeforeRequest) {
|
||||
memcpy(to->data() + size, from->constData() + 4, headlen * sizeof(mtpPrime));
|
||||
memcpy(to->data() + size + headlen + skipBeforeRequest, from->constData() + 4 + headlen, lenInInts * sizeof(mtpPrime));
|
||||
} else {
|
||||
memcpy(to->data() + size, from->constData() + 4, fulllen * sizeof(mtpPrime));
|
||||
}
|
||||
} else {
|
||||
to->resize(size + fulllen + 3);
|
||||
to->resize(size + fulllen + skipBeforeRequest + 3);
|
||||
memcpy(to->data() + size, from->constData() + 4, headlen * sizeof(mtpPrime));
|
||||
(*to)[size + 3] += 3 * sizeof(mtpPrime);
|
||||
*((mtpTypeId*)&((*to)[size + headlen])) = mtpc_invokeAfterMsg;
|
||||
memcpy(to->data() + size + headlen + 1, &afterId, 2 * sizeof(mtpPrime));
|
||||
memcpy(to->data() + size + headlen + 3, from->constData() + 4 + headlen, len * sizeof(mtpPrime));
|
||||
*((mtpTypeId*)&((*to)[size + headlen + skipBeforeRequest])) = mtpc_invokeAfterMsg;
|
||||
memcpy(to->data() + size + headlen + skipBeforeRequest + 1, &afterId, 2 * sizeof(mtpPrime));
|
||||
memcpy(to->data() + size + headlen + skipBeforeRequest + 3, from->constData() + 4 + headlen, lenInInts * sizeof(mtpPrime));
|
||||
if (size + 3 != 7) (*to)[7] += 3 * sizeof(mtpPrime);
|
||||
}
|
||||
}
|
||||
|
@ -624,15 +625,6 @@ namespace MTP {
|
|||
}
|
||||
}
|
||||
|
||||
void setLayer(uint32 l) {
|
||||
if (l > mtpLayerMax) {
|
||||
l = mtpLayerMax;
|
||||
} else if (!l) {
|
||||
l = 1;
|
||||
}
|
||||
layer = l - 1;
|
||||
}
|
||||
|
||||
void setdc(int32 dc, bool fromZeroOnly) {
|
||||
if (!started) return;
|
||||
|
||||
|
|
|
@ -26,13 +26,11 @@ namespace _mtp_internal {
|
|||
void registerRequest(mtpRequestId requestId, int32 dc);
|
||||
void unregisterRequest(mtpRequestId requestId);
|
||||
|
||||
uint32 getLayer();
|
||||
|
||||
static const uint32 dcShift = 10000;
|
||||
|
||||
mtpRequestId storeRequest(mtpRequest &request, const RPCResponseHandler &parser);
|
||||
mtpRequest getRequest(mtpRequestId req);
|
||||
void wrapInvokeAfter(mtpRequest &to, const mtpRequest &from, const mtpRequestMap &haveSent);
|
||||
void wrapInvokeAfter(mtpRequest &to, const mtpRequest &from, const mtpRequestMap &haveSent, int32 skipBeforeRequest = 0);
|
||||
void clearCallbacks(mtpRequestId requestId, int32 errorCode = RPCError::NoError); // 0 - do not toggle onError callback
|
||||
void clearCallbacksDelayed(const RPCCallbackClears &requestIds);
|
||||
void performDelayedClear();
|
||||
|
@ -86,8 +84,6 @@ namespace MTP {
|
|||
void restart();
|
||||
void restart(int32 dcMask);
|
||||
|
||||
void setLayer(uint32 layer);
|
||||
|
||||
void setdc(int32 dc, bool fromZeroOnly = false);
|
||||
int32 maindc();
|
||||
int32 dcstate(int32 dc = 0);
|
||||
|
@ -98,7 +94,7 @@ namespace MTP {
|
|||
MTProtoSessionPtr session = _mtp_internal::getSession(dc);
|
||||
if (!session) return 0;
|
||||
|
||||
return session->send(request, callbacks, msCanWait, _mtp_internal::getLayer(), !dc, after);
|
||||
return session->send(request, callbacks, msCanWait, true, !dc, after);
|
||||
}
|
||||
template <typename TRequest>
|
||||
inline mtpRequestId send(const TRequest &request, RPCDoneHandlerPtr onDone, RPCFailHandlerPtr onFail = RPCFailHandlerPtr(), int32 dc = 0, uint64 msCanWait = 0, mtpRequestId after = 0) {
|
||||
|
|
|
@ -473,7 +473,7 @@ namespace {
|
|||
mtpBuffer _preparePQFake(const MTPint128 &nonce) {
|
||||
MTPReq_pq req_pq(nonce);
|
||||
mtpBuffer buffer;
|
||||
uint32 requestSize = req_pq.size() >> 2;
|
||||
uint32 requestSize = req_pq.innerLength() >> 2;
|
||||
|
||||
buffer.resize(0);
|
||||
buffer.reserve(8 + requestSize);
|
||||
|
@ -604,7 +604,7 @@ void MTPabstractTcpConnection::socketRead() {
|
|||
}
|
||||
|
||||
MTPautoConnection::MTPautoConnection(QThread *thread) : status(WaitingBoth),
|
||||
tcpNonce(MTP::nonce<MTPint128>()), httpNonce(MTP::nonce<MTPint128>()) {
|
||||
tcpNonce(MTP::nonce<MTPint128>()), httpNonce(MTP::nonce<MTPint128>()), _tcpTimeout(1) {
|
||||
moveToThread(thread);
|
||||
|
||||
manager.moveToThread(thread);
|
||||
|
@ -613,6 +613,9 @@ tcpNonce(MTP::nonce<MTPint128>()), httpNonce(MTP::nonce<MTPint128>()) {
|
|||
httpStartTimer.moveToThread(thread);
|
||||
httpStartTimer.setSingleShot(true);
|
||||
connect(&httpStartTimer, SIGNAL(timeout()), this, SLOT(onHttpStart()));
|
||||
tcpTimeoutTimer.moveToThread(thread);
|
||||
tcpTimeoutTimer.setSingleShot(true);
|
||||
connect(&tcpTimeoutTimer, SIGNAL(timeout()), this, SLOT(onTcpTimeoutTimer()));
|
||||
|
||||
sock.moveToThread(thread);
|
||||
sock.setProxy(QNetworkProxy(QNetworkProxy::NoProxy));
|
||||
|
@ -627,7 +630,7 @@ void MTPautoConnection::onHttpStart() {
|
|||
if (status == HttpReady) {
|
||||
DEBUG_LOG(("Connection Info: Http-transport chosen by timer"));
|
||||
status = UsingHttp;
|
||||
sock.disconnect();
|
||||
sock.disconnectFromHost();
|
||||
emit connected();
|
||||
}
|
||||
}
|
||||
|
@ -638,13 +641,37 @@ void MTPautoConnection::onSocketConnected() {
|
|||
|
||||
DEBUG_LOG(("Connection Info: sending fake req_pq through tcp transport"));
|
||||
|
||||
if (_tcpTimeout < 0) _tcpTimeout = -_tcpTimeout;
|
||||
tcpTimeoutTimer.start(_tcpTimeout * 1000);
|
||||
|
||||
tcpSend(buffer);
|
||||
} else if (status == WaitingHttp || status == UsingHttp) {
|
||||
sock.disconnect();
|
||||
sock.disconnectFromHost();
|
||||
}
|
||||
}
|
||||
|
||||
void MTPautoConnection::onTcpTimeoutTimer() {
|
||||
if (status == HttpReady || status == WaitingBoth || status == WaitingTcp) {
|
||||
if (_tcpTimeout < 64) _tcpTimeout *= 2;
|
||||
_tcpTimeout = -_tcpTimeout;
|
||||
|
||||
QAbstractSocket::SocketState state = sock.state();
|
||||
if (state == QAbstractSocket::ConnectedState || state == QAbstractSocket::ConnectingState || state == QAbstractSocket::HostLookupState) {
|
||||
sock.disconnectFromHost();
|
||||
} else if (state != QAbstractSocket::ClosingState) {
|
||||
sock.connectToHost(QHostAddress(_addr), _port);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MTPautoConnection::onSocketDisconnected() {
|
||||
if (_tcpTimeout < 0) {
|
||||
_tcpTimeout = -_tcpTimeout;
|
||||
if (status == HttpReady || status == WaitingBoth || status == WaitingTcp) {
|
||||
sock.connectToHost(QHostAddress(_addr), _port);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (status == WaitingBoth) {
|
||||
status = WaitingHttp;
|
||||
} else if (status == WaitingTcp || status == UsingTcp) {
|
||||
|
@ -725,14 +752,17 @@ void MTPautoConnection::connectToServer(const QString &addr, int32 port) {
|
|||
address = QUrl(qsl("http://%1:%2/api").arg(addr).arg(80));//not port - always 80 port for http transport
|
||||
connect(&manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestFinished(QNetworkReply*)));
|
||||
|
||||
_addr = addr;
|
||||
_port = port;
|
||||
|
||||
connect(&sock, SIGNAL(readyRead()), this, SLOT(socketRead()));
|
||||
sock.connectToHost(QHostAddress(_addr), _port);
|
||||
|
||||
mtpBuffer buffer(_preparePQFake(httpNonce));
|
||||
|
||||
DEBUG_LOG(("Connection Info: sending fake req_pq through http transport"));
|
||||
|
||||
httpSend(buffer);
|
||||
|
||||
sock.connectToHost(QHostAddress(addr), port);
|
||||
connect(&sock, SIGNAL(readyRead()), this, SLOT(socketRead()));
|
||||
}
|
||||
|
||||
bool MTPautoConnection::isConnected() {
|
||||
|
@ -766,7 +796,7 @@ void MTPautoConnection::requestFinished(QNetworkReply *reply) {
|
|||
} else {
|
||||
DEBUG_LOG(("Connection Info: Http-transport chosen by pq-response, awaited"));
|
||||
status = UsingHttp;
|
||||
sock.disconnect();
|
||||
sock.disconnectFromHost();
|
||||
emit connected();
|
||||
}
|
||||
}
|
||||
|
@ -786,7 +816,7 @@ void MTPautoConnection::requestFinished(QNetworkReply *reply) {
|
|||
return;
|
||||
}
|
||||
|
||||
bool mayBeBadKey = _handleHttpError(reply);
|
||||
bool mayBeBadKey = _handleHttpError(reply) && _sentEncrypted;
|
||||
if (status == WaitingBoth) {
|
||||
status = WaitingTcp;
|
||||
} else if (status == WaitingHttp || status == UsingHttp) {
|
||||
|
@ -802,14 +832,15 @@ void MTPautoConnection::socketPacket(mtpPrime *packet, uint32 size) {
|
|||
if (data.size() == 1) {
|
||||
if (status == WaitingBoth) {
|
||||
status = WaitingHttp;
|
||||
sock.disconnect();
|
||||
sock.disconnectFromHost();
|
||||
} else if (status == HttpReady) {
|
||||
DEBUG_LOG(("Connection Info: Http-transport chosen by bad tcp response, ready"));
|
||||
status = UsingHttp;
|
||||
sock.disconnect();
|
||||
sock.disconnectFromHost();
|
||||
emit connected();
|
||||
} else if (status == WaitingTcp || status == UsingTcp) {
|
||||
emit error(data[0] == -404);
|
||||
bool mayBeBadKey = (data[0] == -404) && _sentEncrypted;
|
||||
emit error(mayBeBadKey);
|
||||
} else {
|
||||
LOG(("Strange Tcp Error; status %1").arg(status));
|
||||
}
|
||||
|
@ -817,6 +848,7 @@ void MTPautoConnection::socketPacket(mtpPrime *packet, uint32 size) {
|
|||
receivedQueue.push_back(data);
|
||||
emit receivedData();
|
||||
} else if (status == WaitingBoth || status == WaitingTcp || status == HttpReady) {
|
||||
tcpTimeoutTimer.stop();
|
||||
try {
|
||||
MTPResPQ res_pq = _readPQFakeReply(data);
|
||||
const MTPDresPQ &res_pq_data(res_pq.c_resPQ());
|
||||
|
@ -828,11 +860,11 @@ void MTPautoConnection::socketPacket(mtpPrime *packet, uint32 size) {
|
|||
} catch (Exception &e) {
|
||||
if (status == WaitingBoth) {
|
||||
status = WaitingHttp;
|
||||
sock.disconnect();
|
||||
sock.disconnectFromHost();
|
||||
} else if (status == HttpReady) {
|
||||
DEBUG_LOG(("Connection Info: Http-transport chosen by bad tcp response, awaited"));
|
||||
status = UsingHttp;
|
||||
sock.disconnect();
|
||||
sock.disconnectFromHost();
|
||||
emit connected();
|
||||
} else {
|
||||
emit error();
|
||||
|
@ -907,14 +939,15 @@ void MTPtcpConnection::disconnectFromServer() {
|
|||
}
|
||||
|
||||
void MTPtcpConnection::connectToServer(const QString &addr, int32 port) {
|
||||
sock.connectToHost(QHostAddress(addr), port);
|
||||
connect(&sock, SIGNAL(readyRead()), this, SLOT(socketRead()));
|
||||
sock.connectToHost(QHostAddress(addr), port);
|
||||
}
|
||||
|
||||
void MTPtcpConnection::socketPacket(mtpPrime *packet, uint32 size) {
|
||||
mtpBuffer data = _handleTcpResponse(packet, size);
|
||||
if (data.size() == 1) {
|
||||
emit error(data[0] == -404);
|
||||
bool mayBeBadKey = (data[0] == -404) && _sentEncrypted;
|
||||
emit error(mayBeBadKey);
|
||||
}
|
||||
|
||||
receivedQueue.push_back(data);
|
||||
|
@ -1002,7 +1035,7 @@ void MTPhttpConnection::requestFinished(QNetworkReply *reply) {
|
|||
return;
|
||||
}
|
||||
|
||||
bool mayBeBadKey = _handleHttpError(reply);
|
||||
bool mayBeBadKey = _handleHttpError(reply) && _sentEncrypted;
|
||||
|
||||
emit error(mayBeBadKey);
|
||||
}
|
||||
|
@ -1362,6 +1395,7 @@ void MTProtoConnectionPrivate::tryToSend() {
|
|||
return;
|
||||
}
|
||||
|
||||
bool needsLayer = !sessionData->layerWasInited();
|
||||
bool prependOnly = false;
|
||||
mtpRequest pingRequest;
|
||||
if (toSendPingId) {
|
||||
|
@ -1370,7 +1404,7 @@ void MTProtoConnectionPrivate::tryToSend() {
|
|||
prependOnly = (getState() != MTProtoConnection::Connected);
|
||||
DEBUG_LOG(("MTP Info: sending ping, ping_id: %1, prepend_only: %2").arg(ping.vping_id.v).arg(prependOnly ? "[TRUE]" : "[FALSE]"));
|
||||
|
||||
uint32 pingSize = ping.size() >> 2; // copy from MTProtoSession::send
|
||||
uint32 pingSize = ping.innerLength() >> 2; // copy from MTProtoSession::send
|
||||
pingRequest = mtpRequestData::prepare(pingSize);
|
||||
ping.write(*pingRequest);
|
||||
|
||||
|
@ -1391,7 +1425,7 @@ void MTProtoConnectionPrivate::tryToSend() {
|
|||
if (!prependOnly && !ackRequestData.isEmpty()) {
|
||||
MTPMsgsAck ack(MTP_msgs_ack(MTP_vector<MTPlong>(ackRequestData)));
|
||||
|
||||
ackRequest = mtpRequestData::prepare(ack.size() >> 2);
|
||||
ackRequest = mtpRequestData::prepare(ack.innerLength() >> 2);
|
||||
ack.write(*ackRequest);
|
||||
|
||||
ackRequest->msDate = getms(true); // > 0 - can send without container
|
||||
|
@ -1402,7 +1436,7 @@ void MTProtoConnectionPrivate::tryToSend() {
|
|||
if (!prependOnly && !resendRequestData.isEmpty()) {
|
||||
MTPMsgResendReq resend(MTP_msg_resend_req(MTP_vector<MTPlong>(resendRequestData)));
|
||||
|
||||
resendRequest = mtpRequestData::prepare(resend.size() >> 2);
|
||||
resendRequest = mtpRequestData::prepare(resend.innerLength() >> 2);
|
||||
resend.write(*resendRequest);
|
||||
|
||||
resendRequest->msDate = getms(true); // > 0 - can send without container
|
||||
|
@ -1426,7 +1460,7 @@ void MTProtoConnectionPrivate::tryToSend() {
|
|||
if (!stateReq.isEmpty()) {
|
||||
MTPMsgsStateReq req(MTP_msgs_state_req(MTP_vector<MTPlong>(stateReq)));
|
||||
|
||||
stateRequest = mtpRequestData::prepare(req.size() >> 2);
|
||||
stateRequest = mtpRequestData::prepare(req.innerLength() >> 2);
|
||||
req.write(*stateRequest);
|
||||
|
||||
stateRequest->msDate = getms(true); // > 0 - can send without container
|
||||
|
@ -1434,6 +1468,14 @@ void MTProtoConnectionPrivate::tryToSend() {
|
|||
}
|
||||
}
|
||||
|
||||
MTPInitConnection<mtpRequest> initWrapperImpl, *initWrapper = &initWrapperImpl;
|
||||
int32 initSize = 0, initSizeInInts = 0;
|
||||
if (needsLayer) {
|
||||
initWrapperImpl = MTPInitConnection<mtpRequest>(MTP_int(ApiId), MTP_string(cApiDeviceModel()), MTP_string(cApiSystemVersion()), MTP_string(cApiAppVersion()), MTP_string(ApiLang), mtpRequest());
|
||||
initSizeInInts = (initWrapper->innerLength() >> 2) + 2;
|
||||
initSize = initSizeInInts * sizeof(mtpPrime);
|
||||
}
|
||||
|
||||
bool needAnyResponse = false;
|
||||
mtpRequest toSendRequest;
|
||||
{
|
||||
|
@ -1473,14 +1515,27 @@ void MTProtoConnectionPrivate::tryToSend() {
|
|||
QWriteLocker locker2(sessionData->haveSentMutex());
|
||||
mtpRequestMap &haveSent(sessionData->haveSentMap());
|
||||
haveSent.insert(msgId, toSendRequest);
|
||||
|
||||
if (needsLayer && !toSendRequest->needsLayer) needsLayer = false;
|
||||
if (toSendRequest->after) {
|
||||
int32 toSendSize = toSendRequest->at(7) >> 2;
|
||||
int32 toSendSize = toSendRequest.innerLength() >> 2;
|
||||
mtpRequest wrappedRequest(mtpRequestData::prepare(toSendSize, toSendSize + 3)); // cons + msg_id
|
||||
wrappedRequest->resize(4);
|
||||
memcpy(wrappedRequest->data(), toSendRequest->constData(), 4 * sizeof(mtpPrime));
|
||||
_mtp_internal::wrapInvokeAfter(wrappedRequest, toSendRequest, haveSent);
|
||||
toSendRequest = wrappedRequest;
|
||||
}
|
||||
if (needsLayer) {
|
||||
int32 noWrapSize = (toSendRequest.innerLength() >> 2), toSendSize = noWrapSize + initSizeInInts;
|
||||
mtpRequest wrappedRequest(mtpRequestData::prepare(toSendSize));
|
||||
memcpy(wrappedRequest->data(), toSendRequest->constData(), 7 * sizeof(mtpPrime)); // all except length
|
||||
wrappedRequest->push_back(mtpc_invokeWithLayer);
|
||||
wrappedRequest->push_back(mtpCurrentLayer);
|
||||
initWrapper->write(*wrappedRequest);
|
||||
wrappedRequest->resize(wrappedRequest->size() + noWrapSize);
|
||||
memcpy(wrappedRequest->data() + wrappedRequest->size() - noWrapSize, toSendRequest->constData() + 8, noWrapSize * sizeof(mtpPrime));
|
||||
toSendRequest = wrappedRequest;
|
||||
}
|
||||
|
||||
needAnyResponse = true;
|
||||
} else {
|
||||
|
@ -1489,6 +1544,7 @@ void MTProtoConnectionPrivate::tryToSend() {
|
|||
}
|
||||
}
|
||||
} else { // send in container
|
||||
bool willNeedInit = false;
|
||||
uint32 containerSize = 1 + 1, idsWrapSize = (toSendCount << 1); // cons + vector size, idsWrapSize - size of "request-like" wrap for msgId vector
|
||||
if (pingRequest) containerSize += mtpRequestData::messageSize(pingRequest);
|
||||
if (ackRequest) containerSize += mtpRequestData::messageSize(ackRequest);
|
||||
|
@ -1496,6 +1552,17 @@ void MTProtoConnectionPrivate::tryToSend() {
|
|||
if (stateRequest) containerSize += mtpRequestData::messageSize(stateRequest);
|
||||
for (mtpPreRequestMap::iterator i = toSend.begin(), e = toSend.end(); i != e; ++i) {
|
||||
containerSize += mtpRequestData::messageSize(i.value());
|
||||
if (needsLayer && i.value()->needsLayer) {
|
||||
containerSize += initSizeInInts;
|
||||
willNeedInit = true;
|
||||
}
|
||||
}
|
||||
mtpBuffer initSerialized;
|
||||
if (willNeedInit) {
|
||||
initSerialized.reserve(initSizeInInts);
|
||||
initSerialized.push_back(mtpc_invokeWithLayer);
|
||||
initSerialized.push_back(mtpCurrentLayer);
|
||||
initWrapper->write(initSerialized);
|
||||
}
|
||||
toSendRequest = mtpRequestData::prepare(containerSize, containerSize + 3 * toSend.size()); // prepare container + each in invoke after
|
||||
toSendRequest->push_back(mtpc_msg_container);
|
||||
|
@ -1530,8 +1597,20 @@ void MTProtoConnectionPrivate::tryToSend() {
|
|||
if (req->requestId) {
|
||||
if (mtpRequestData::needAck(req)) {
|
||||
req->msDate = mtpRequestData::isStateRequest(req) ? 0 : getms(true);
|
||||
int32 reqNeedsLayer = (needsLayer && req->needsLayer) ? toSendRequest->size() : 0;
|
||||
if (req->after) {
|
||||
_mtp_internal::wrapInvokeAfter(toSendRequest, req, haveSent);
|
||||
_mtp_internal::wrapInvokeAfter(toSendRequest, req, haveSent, reqNeedsLayer ? initSizeInInts : 0);
|
||||
if (reqNeedsLayer) {
|
||||
memcpy(toSendRequest->data() + reqNeedsLayer + 4, initSerialized.constData(), initSize);
|
||||
*(toSendRequest->data() + reqNeedsLayer + 3) += initSize;
|
||||
}
|
||||
added = true;
|
||||
} else if (reqNeedsLayer) {
|
||||
toSendRequest->resize(reqNeedsLayer + initSizeInInts + mtpRequestData::messageSize(req));
|
||||
memcpy(toSendRequest->data() + reqNeedsLayer, req->constData() + 4, 4 * sizeof(mtpPrime));
|
||||
memcpy(toSendRequest->data() + reqNeedsLayer + 4, initSerialized.constData(), initSize);
|
||||
memcpy(toSendRequest->data() + reqNeedsLayer + 4 + initSizeInInts, req->constData() + 8, req.innerLength());
|
||||
*(toSendRequest->data() + reqNeedsLayer + 3) += initSize;
|
||||
added = true;
|
||||
}
|
||||
haveSent.insert(msgId, req);
|
||||
|
@ -2329,6 +2408,10 @@ int32 MTProtoConnectionPrivate::handleOneReceived(const mtpPrime *from, const mt
|
|||
response.resize(end - from);
|
||||
memcpy(response.data(), from, (end - from) * sizeof(mtpPrime));
|
||||
}
|
||||
if (!sessionData->layerWasInited()) {
|
||||
sessionData->setLayerWasInited(true);
|
||||
sessionData->owner()->notifyLayerInited(true);
|
||||
}
|
||||
|
||||
mtpRequestId requestId = wasSent(reqMsgId.v);
|
||||
if (requestId && requestId != mtpRequestId(0xFFFFFFFF)) {
|
||||
|
@ -2787,7 +2870,7 @@ void MTProtoConnectionPrivate::pqAnswered() {
|
|||
|
||||
string &dhEncString(req_DH_params.vencrypted_data._string().v);
|
||||
|
||||
uint32 p_q_inner_size = p_q_inner.size(), encSize = (p_q_inner_size >> 2) + 6;
|
||||
uint32 p_q_inner_size = p_q_inner.innerLength(), encSize = (p_q_inner_size >> 2) + 6;
|
||||
if (encSize >= 65) {
|
||||
mtpBuffer tmp;
|
||||
tmp.reserve(encSize);
|
||||
|
@ -2854,7 +2937,7 @@ void MTProtoConnectionPrivate::dhParamsAnswered() {
|
|||
return restart();
|
||||
}
|
||||
|
||||
uint32 nlen = authKeyData->new_nonce.size(), slen = authKeyData->server_nonce.size();
|
||||
uint32 nlen = authKeyData->new_nonce.innerLength(), slen = authKeyData->server_nonce.innerLength();
|
||||
uchar tmp_aes[1024], sha1ns[20], sha1sn[20], sha1nn[20];
|
||||
memcpy(tmp_aes, &authKeyData->new_nonce, nlen);
|
||||
memcpy(tmp_aes + nlen, &authKeyData->server_nonce, slen);
|
||||
|
@ -2979,7 +3062,7 @@ void MTProtoConnectionPrivate::dhClientParamsSend() {
|
|||
|
||||
string &sdhEncString(req_client_DH_params.vencrypted_data._string().v);
|
||||
|
||||
uint32 client_dh_inner_size = client_dh_inner.size(), encSize = (client_dh_inner_size >> 2) + 5, encFullSize = encSize;
|
||||
uint32 client_dh_inner_size = client_dh_inner.innerLength(), encSize = (client_dh_inner_size >> 2) + 5, encFullSize = encSize;
|
||||
if (encSize & 0x03) {
|
||||
encFullSize += 4 - (encSize & 0x03);
|
||||
}
|
||||
|
@ -3047,7 +3130,7 @@ void MTProtoConnectionPrivate::dhClientParamsAnswered() {
|
|||
|
||||
DEBUG_LOG(("AuthKey Info: auth key gen succeed, id: %1, server salt: %2, auth key: %3").arg(authKey->keyId()).arg(serverSalt).arg(mb(authKeyData->auth_key, 256).str()));
|
||||
|
||||
sessionData->owner()->keyCreated(authKey); // slot will call authKeyCreated()
|
||||
sessionData->owner()->notifyKeyCreated(authKey); // slot will call authKeyCreated()
|
||||
sessionData->clear();
|
||||
unlockKey();
|
||||
} return;
|
||||
|
@ -3146,7 +3229,7 @@ void MTProtoConnectionPrivate::sendPing() {
|
|||
}
|
||||
|
||||
void MTProtoConnectionPrivate::onError(bool mayBeBadKey) {
|
||||
MTP_LOG(dc, ("Restarting after error.."));
|
||||
MTP_LOG(dc, ("Restarting after error, maybe bad key: %1..").arg(logBool(mayBeBadKey)));
|
||||
return restart(mayBeBadKey);
|
||||
}
|
||||
|
||||
|
@ -3157,7 +3240,7 @@ template <typename TRequest>
|
|||
void MTProtoConnectionPrivate::sendRequestNotSecure(const TRequest &request) {
|
||||
try {
|
||||
mtpBuffer buffer;
|
||||
uint32 requestSize = request.size() >> 2;
|
||||
uint32 requestSize = request.innerLength() >> 2;
|
||||
|
||||
buffer.resize(0);
|
||||
buffer.reserve(8 + requestSize);
|
||||
|
@ -3264,6 +3347,7 @@ bool MTProtoConnectionPrivate::sendRequest(mtpRequest &request, bool needAnyResp
|
|||
|
||||
DEBUG_LOG(("MTP Info: sending request, size: %1, num: %2, time: %3").arg(fullSize + 6).arg((*request)[4]).arg((*request)[5]));
|
||||
|
||||
conn->setSentEncrypted();
|
||||
conn->sendData(result);
|
||||
|
||||
if (needAnyResponse) {
|
||||
|
|
|
@ -106,6 +106,13 @@ class MTPabstractConnection : public QObject {
|
|||
|
||||
public:
|
||||
|
||||
MTPabstractConnection() : _sentEncrypted(false) {
|
||||
}
|
||||
|
||||
void setSentEncrypted() {
|
||||
_sentEncrypted = true;
|
||||
}
|
||||
|
||||
virtual void sendData(mtpBuffer &buffer) = 0; // has size + 3, buffer[0] = len, buffer[1] = packetnum, buffer[last] = crc32
|
||||
virtual void disconnectFromServer() = 0;
|
||||
virtual void connectToServer(const QString &addr, int32 port) = 0;
|
||||
|
@ -135,6 +142,7 @@ signals:
|
|||
protected:
|
||||
|
||||
BuffersQueue receivedQueue; // list of received packets, not processed yet
|
||||
bool _sentEncrypted;
|
||||
|
||||
};
|
||||
|
||||
|
@ -189,6 +197,8 @@ public slots:
|
|||
void onSocketDisconnected();
|
||||
void onHttpStart();
|
||||
|
||||
void onTcpTimeoutTimer();
|
||||
|
||||
protected:
|
||||
|
||||
void socketPacket(mtpPrime *packet, uint32 packetSize);
|
||||
|
@ -215,6 +225,10 @@ private:
|
|||
typedef QSet<QNetworkReply*> Requests;
|
||||
Requests requests;
|
||||
|
||||
QString _addr;
|
||||
int32 _port, _tcpTimeout;
|
||||
QTimer tcpTimeoutTimer;
|
||||
|
||||
};
|
||||
|
||||
class MTPtcpConnection : public MTPabstractTcpConnection {
|
||||
|
|
|
@ -172,12 +172,20 @@ void mtpTextSerializeCore(MTPStringLogger &to, const mtpPrime *&from, const mtpP
|
|||
} break;
|
||||
|
||||
default: {
|
||||
for (uint32 i = 1; i < mtpLayerMax; ++i) {
|
||||
for (uint32 i = 1; i < mtpLayerMaxSingle; ++i) {
|
||||
if (cons == mtpLayers[i]) {
|
||||
to.add("[LAYER").add(mtpWrapNumber(i + 1)).add("] "); mtpTextSerializeType(to, from, end, 0, level);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (cons == mtpc_invokeWithLayer) {
|
||||
if (from >= end) {
|
||||
throw Exception("from >= end in invokeWithLayer");
|
||||
}
|
||||
int32 layer = *(from++);
|
||||
to.add("[LAYER").add(mtpWrapNumber(layer)).add("] "); mtpTextSerializeType(to, from, end, 0, level);
|
||||
return;
|
||||
}
|
||||
throw Exception(QString("unknown cons 0x%1").arg(cons, 0, 16));
|
||||
} break;
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ public:
|
|||
explicit mtpRequest(mtpRequestData *ptr) : QSharedPointer<mtpRequestData>(ptr) {
|
||||
}
|
||||
|
||||
uint32 size() const;
|
||||
uint32 innerLength() const;
|
||||
void write(mtpBuffer &to) const;
|
||||
|
||||
typedef void ResponseType; // don't know real response type =(
|
||||
|
@ -74,10 +74,12 @@ public:
|
|||
// in toSend: = 0 - must send in container, > 0 - can send without container
|
||||
// in haveSent: = 0 - container with msgIds, > 0 - when was sent
|
||||
uint64 msDate;
|
||||
|
||||
mtpRequestId requestId;
|
||||
mtpRequest after;
|
||||
bool needsLayer;
|
||||
|
||||
mtpRequestData(bool/* sure*/) : msDate(0), requestId(0) {
|
||||
mtpRequestData(bool/* sure*/) : msDate(0), requestId(0), needsLayer(false) {
|
||||
}
|
||||
|
||||
static mtpRequest prepare(uint32 requestSize, uint32 maxSize = 0) {
|
||||
|
@ -92,7 +94,7 @@ public:
|
|||
static void padding(mtpRequest &request) {
|
||||
if (request->size() < 9) return;
|
||||
|
||||
uint32 requestSize = ((*request)[7] >> 2), padding = _padding(requestSize), fullSize = 8 + requestSize + padding; // 2: salt, 2: session_id, 2: msg_id, 1: seq_no, 1: message_length
|
||||
uint32 requestSize = (request.innerLength() >> 2), padding = _padding(requestSize), fullSize = 8 + requestSize + padding; // 2: salt, 2: session_id, 2: msg_id, 1: seq_no, 1: message_length
|
||||
if (uint32(request->size()) != fullSize) {
|
||||
request->resize(fullSize);
|
||||
if (padding) {
|
||||
|
@ -103,7 +105,7 @@ public:
|
|||
|
||||
static uint32 messageSize(const mtpRequest &request) {
|
||||
if (request->size() < 9) return 0;
|
||||
return 4 + ((*request)[7] >> 2); // 2: msg_id, 1: seq_no, q: message_length
|
||||
return 4 + (request.innerLength() >> 2); // 2: msg_id, 1: seq_no, q: message_length
|
||||
}
|
||||
|
||||
static bool isSentContainer(const mtpRequest &request); // "request-like" wrap for msgIds vector
|
||||
|
@ -119,7 +121,7 @@ private:
|
|||
|
||||
};
|
||||
|
||||
inline uint32 mtpRequest::size() const { // for template MTP requests and MTPBoxed instanciation
|
||||
inline uint32 mtpRequest::innerLength() const { // for template MTP requests and MTPBoxed instanciation
|
||||
mtpRequestData *value = data();
|
||||
if (!value || value->size() < 9) return 0;
|
||||
return value->at(7);
|
||||
|
@ -128,7 +130,7 @@ inline uint32 mtpRequest::size() const { // for template MTP requests and MTPBox
|
|||
inline void mtpRequest::write(mtpBuffer &to) const {
|
||||
mtpRequestData *value = data();
|
||||
if (!value || value->size() < 9) return;
|
||||
uint32 was = to.size(), s = size() / sizeof(mtpPrime);
|
||||
uint32 was = to.size(), s = innerLength() / sizeof(mtpPrime);
|
||||
to.resize(was + s);
|
||||
memcpy(to.data() + was, value->constData() + 8, s * sizeof(mtpPrime));
|
||||
}
|
||||
|
@ -335,6 +337,8 @@ enum {
|
|||
mtpc_invokeWithLayer17 = 0x50858a19,
|
||||
mtpc_invokeWithLayer18 = 0x1c900537,
|
||||
|
||||
mtpc_invokeWithLayer = 0xda9b0d0d, // after 18 layer
|
||||
|
||||
// manually parsed
|
||||
mtpc_rpc_result = 0xf35c6d01,
|
||||
mtpc_msg_container = 0x73f1f8dc,
|
||||
|
@ -362,7 +366,8 @@ static const mtpTypeId mtpLayers[] = {
|
|||
mtpc_invokeWithLayer16,
|
||||
mtpc_invokeWithLayer17,
|
||||
mtpc_invokeWithLayer18,
|
||||
}, mtpLayerMax = sizeof(mtpLayers) / sizeof(mtpLayers[0]);
|
||||
}, mtpLayerMaxSingle = sizeof(mtpLayers) / sizeof(mtpLayers[0]);
|
||||
static const mtpPrime mtpCurrentLayer = 19;
|
||||
|
||||
template <typename bareT>
|
||||
class MTPBoxed : public bareT {
|
||||
|
@ -386,8 +391,8 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
uint32 size() const {
|
||||
return sizeof(mtpTypeId) + bareT::size();
|
||||
uint32 innerLength() const {
|
||||
return sizeof(mtpTypeId) + bareT::innerLength();
|
||||
}
|
||||
void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) {
|
||||
if (from + 1 > end) throw mtpErrorInsufficient();
|
||||
|
@ -414,7 +419,7 @@ public:
|
|||
read(from, end, cons);
|
||||
}
|
||||
|
||||
uint32 size() const {
|
||||
uint32 innerLength() const {
|
||||
return sizeof(int32);
|
||||
}
|
||||
mtpTypeId type() const {
|
||||
|
@ -457,7 +462,7 @@ public:
|
|||
read(from, end, cons);
|
||||
}
|
||||
|
||||
uint32 size() const {
|
||||
uint32 innerLength() const {
|
||||
return sizeof(uint64);
|
||||
}
|
||||
mtpTypeId type() const {
|
||||
|
@ -503,7 +508,7 @@ public:
|
|||
read(from, end, cons);
|
||||
}
|
||||
|
||||
uint32 size() const {
|
||||
uint32 innerLength() const {
|
||||
return sizeof(uint64) + sizeof(uint64);
|
||||
}
|
||||
mtpTypeId type() const {
|
||||
|
@ -552,8 +557,8 @@ public:
|
|||
read(from, end, cons);
|
||||
}
|
||||
|
||||
uint32 size() const {
|
||||
return l.size() + h.size();
|
||||
uint32 innerLength() const {
|
||||
return l.innerLength() + h.innerLength();
|
||||
}
|
||||
mtpTypeId type() const {
|
||||
return mtpc_int256;
|
||||
|
@ -596,7 +601,7 @@ public:
|
|||
read(from, end, cons);
|
||||
}
|
||||
|
||||
uint32 size() const {
|
||||
uint32 innerLength() const {
|
||||
return sizeof(float64);
|
||||
}
|
||||
mtpTypeId type() const {
|
||||
|
@ -666,7 +671,7 @@ public:
|
|||
return *(const MTPDstring*)data;
|
||||
}
|
||||
|
||||
uint32 size() const {
|
||||
uint32 innerLength() const {
|
||||
uint32 l = c_string().v.length();
|
||||
if (l < 254) {
|
||||
l += 1;
|
||||
|
@ -770,7 +775,7 @@ public:
|
|||
read(from, end, cons);
|
||||
}
|
||||
|
||||
uint32 size() const {
|
||||
uint32 innerLength() const {
|
||||
return 0;
|
||||
}
|
||||
mtpTypeId type() const {
|
||||
|
@ -858,10 +863,10 @@ public:
|
|||
return *(const MTPDvector<T>*)data;
|
||||
}
|
||||
|
||||
uint32 size() const {
|
||||
uint32 innerLength() const {
|
||||
uint32 result(sizeof(uint32));
|
||||
for (typename VType::const_iterator i = c_vector().v.cbegin(), e = c_vector().v.cend(); i != e; ++i) {
|
||||
result += i->size();
|
||||
result += i->innerLength();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -961,8 +966,8 @@ public:
|
|||
return *(const MTPDerror*)data;
|
||||
}
|
||||
|
||||
uint32 size() const {
|
||||
return c_error().vcode.size() + c_error().vtext.size();
|
||||
uint32 innerLength() const {
|
||||
return c_error().vcode.innerLength() + c_error().vtext.innerLength();
|
||||
}
|
||||
mtpTypeId type() const {
|
||||
return mtpc_error;
|
||||
|
@ -999,7 +1004,7 @@ public:
|
|||
read(from, end, cons);
|
||||
}
|
||||
|
||||
uint32 size() const {
|
||||
uint32 innerLength() const {
|
||||
return 0;
|
||||
}
|
||||
mtpTypeId type() const {
|
||||
|
|
|
@ -350,7 +350,7 @@ void mtpSetDC(int32 dc) {
|
|||
}
|
||||
}
|
||||
|
||||
MTProtoDC::MTProtoDC(int32 id, const mtpAuthKeyPtr &key) : _id(id), _key(key), _connectionInited(false), _connectionInitSent(false) {
|
||||
MTProtoDC::MTProtoDC(int32 id, const mtpAuthKeyPtr &key) : _id(id), _key(key), _connectionInited(false) {
|
||||
connect(this, SIGNAL(authKeyCreated()), this, SLOT(authKeyWrite()), Qt::QueuedConnection);
|
||||
|
||||
QMutexLocker lock(&_keysMapForWriteMutex);
|
||||
|
@ -371,6 +371,7 @@ void MTProtoDC::authKeyWrite() {
|
|||
void MTProtoDC::setKey(const mtpAuthKeyPtr &key) {
|
||||
DEBUG_LOG(("AuthKey Info: MTProtoDC::setKey(%1), emitting authKeyCreated, dc %2").arg(key ? key->keyId() : 0).arg(_id));
|
||||
_key = key;
|
||||
_connectionInited = false;
|
||||
emit authKeyCreated();
|
||||
|
||||
QMutexLocker lock(&_keysMapForWriteMutex);
|
||||
|
|
|
@ -29,13 +29,6 @@ public:
|
|||
void setKey(const mtpAuthKeyPtr &key);
|
||||
void destroyKey();
|
||||
|
||||
bool needConnectionInit() {
|
||||
QMutexLocker lock(&initLock);
|
||||
if (_connectionInited || _connectionInitSent) return false;
|
||||
_connectionInitSent = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool connectionInited() const {
|
||||
QMutexLocker lock(&initLock);
|
||||
bool res = _connectionInited;
|
||||
|
@ -49,6 +42,7 @@ public:
|
|||
signals:
|
||||
|
||||
void authKeyCreated();
|
||||
void layerWasInited(bool was);
|
||||
|
||||
private slots:
|
||||
|
||||
|
@ -61,7 +55,6 @@ private:
|
|||
int32 _id;
|
||||
mtpAuthKeyPtr _key;
|
||||
bool _connectionInited;
|
||||
bool _connectionInitSent;
|
||||
};
|
||||
|
||||
typedef QSharedPointer<MTProtoDC> MTProtoDCPtr;
|
||||
|
|
|
@ -174,8 +174,7 @@ bool mtpFileLoader::loadPart() {
|
|||
App::app()->killDownloadSessionsStop(dc);
|
||||
}
|
||||
|
||||
MTPupload_GetFile request(MTPupload_getFile(loc, MTP_int(offset), MTP_int(limit)));
|
||||
mtpRequestId reqId = MTP::send(request, rpcDone(&mtpFileLoader::partLoaded, offset), rpcFail(&mtpFileLoader::partFailed), MTP::dld[dcIndex] + dc, 50);
|
||||
mtpRequestId reqId = MTP::send(MTPupload_GetFile(MTPupload_getFile(loc, MTP_int(offset), MTP_int(limit))), rpcDone(&mtpFileLoader::partLoaded, offset), rpcFail(&mtpFileLoader::partFailed), MTP::dld[dcIndex] + dc, 50);
|
||||
|
||||
++queue->queries;
|
||||
dr.v[dcIndex] += limit;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -113,8 +113,11 @@ void MTProtoSession::start(int32 dcenter, uint32 connects) {
|
|||
|
||||
ReadLockerAttempt lock(keyMutex());
|
||||
data.setKey(lock ? dc->getKey() : mtpAuthKeyPtr(0));
|
||||
|
||||
if (lock && dc->connectionInited()) {
|
||||
data.setLayerWasInited(true);
|
||||
}
|
||||
connect(dc.data(), SIGNAL(authKeyCreated()), this, SLOT(authKeyCreatedForDC()));
|
||||
connect(dc.data(), SIGNAL(layerWasInited(bool)), this, SLOT(layerWasInitedForDC(bool)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -376,21 +379,9 @@ void MTProtoSession::sendPrepared(const mtpRequest &request, uint64 msCanWait, b
|
|||
sendAnything(msCanWait);
|
||||
}
|
||||
|
||||
void MTProtoSession::sendPreparedWithInit(const mtpRequest &request, uint64 msCanWait) { // returns true, if emit of needToSend() is needed
|
||||
if (request->size() > 8 && request->at(8) == mtpc_initConnection) {
|
||||
sendPrepared(request, msCanWait, false);
|
||||
return;
|
||||
}
|
||||
{
|
||||
MTPInitConnection<mtpRequest> requestWrap(MTPinitConnection<mtpRequest>(MTP_int(ApiId), MTP_string(cApiDeviceModel()), MTP_string(cApiSystemVersion()), MTP_string(cApiAppVersion()), MTP_string(ApiLang), request));
|
||||
uint32 requestSize = requestWrap.size() >> 2;
|
||||
mtpRequest reqSerialized(mtpRequestData::prepare(requestSize));
|
||||
requestWrap.write(*reqSerialized);
|
||||
request->resize(reqSerialized->size());
|
||||
memcpy(request->data(), reqSerialized->constData(), reqSerialized->size());
|
||||
}
|
||||
request->msDate = getms(true); // > 0 - can send without container
|
||||
sendPrepared(request, msCanWait);
|
||||
void MTProtoSession::sendPreparedWithInit(const mtpRequest &request, uint64 msCanWait) {
|
||||
request->needsLayer = true;
|
||||
sendPrepared(request, msCanWait, false);
|
||||
}
|
||||
|
||||
QReadWriteLock *MTProtoSession::keyMutex() const {
|
||||
|
@ -403,11 +394,22 @@ void MTProtoSession::authKeyCreatedForDC() {
|
|||
emit authKeyCreated();
|
||||
}
|
||||
|
||||
void MTProtoSession::keyCreated(const mtpAuthKeyPtr &key) {
|
||||
void MTProtoSession::notifyKeyCreated(const mtpAuthKeyPtr &key) {
|
||||
DEBUG_LOG(("AuthKey Info: MTProtoSession::keyCreated(), setting, dc %1").arg(dcId));
|
||||
dc->setKey(key);
|
||||
}
|
||||
|
||||
void MTProtoSession::layerWasInitedForDC(bool wasInited) {
|
||||
DEBUG_LOG(("MTP Info: MTProtoSession::layerWasInitedForDC slot, dc %1").arg(dcId));
|
||||
data.setLayerWasInited(wasInited);
|
||||
}
|
||||
|
||||
void MTProtoSession::notifyLayerInited(bool wasInited) {
|
||||
DEBUG_LOG(("MTP Info: emitting MTProtoDC::layerWasInited(%1), dc %2").arg(logBool(wasInited)).arg(dcId));
|
||||
dc->setConnectionInited(wasInited);
|
||||
emit dc->layerWasInited(wasInited);
|
||||
}
|
||||
|
||||
void MTProtoSession::destroyKey() {
|
||||
if (!dc) return;
|
||||
|
||||
|
|
|
@ -28,8 +28,8 @@ public:
|
|||
|
||||
MTPSessionData(MTProtoSession *creator)
|
||||
: _session(0), _salt(0)
|
||||
, _messagesSent(0), fakeRequestId(-2000000000)
|
||||
, _owner(creator), keyChecked(false) {
|
||||
, _messagesSent(0), _fakeRequestId(-2000000000)
|
||||
, _owner(creator), _keyChecked(false), _layerInited(false) {
|
||||
}
|
||||
|
||||
void setSession(uint64 session) {
|
||||
|
@ -45,6 +45,14 @@ public:
|
|||
QReadLocker locker(&lock);
|
||||
return _session;
|
||||
}
|
||||
bool layerWasInited() const {
|
||||
QReadLocker locker(&lock);
|
||||
return _layerInited;
|
||||
}
|
||||
void setLayerWasInited(bool was) {
|
||||
QWriteLocker locker(&lock);
|
||||
_layerInited = was;
|
||||
}
|
||||
|
||||
void setSalt(uint64 salt) {
|
||||
QWriteLocker locker(&lock);
|
||||
|
@ -56,26 +64,31 @@ public:
|
|||
}
|
||||
|
||||
const mtpAuthKeyPtr &getKey() const {
|
||||
return authKey;
|
||||
return _authKey;
|
||||
}
|
||||
void setKey(const mtpAuthKeyPtr &key) {
|
||||
if (authKey != key) {
|
||||
if (_authKey != key) {
|
||||
uint64 session;
|
||||
memsetrnd(session);
|
||||
authKey = key;
|
||||
_authKey = key;
|
||||
|
||||
DEBUG_LOG(("MTP Info: new auth key set in SessionData, id %1, setting random server_session %2").arg(key ? key->keyId() : 0).arg(session));
|
||||
setSession(session);
|
||||
QWriteLocker locker(&lock);
|
||||
if (_session != session) {
|
||||
_session = session;
|
||||
_messagesSent = 0;
|
||||
}
|
||||
_layerInited = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool isCheckedKey() const {
|
||||
QReadLocker locker(&lock);
|
||||
return keyChecked;
|
||||
return _keyChecked;
|
||||
}
|
||||
void setCheckedKey(bool checked) {
|
||||
QWriteLocker locker(&lock);
|
||||
keyChecked = checked;
|
||||
_keyChecked = checked;
|
||||
}
|
||||
|
||||
QReadWriteLock *keyMutex() const;
|
||||
|
@ -147,11 +160,11 @@ public:
|
|||
|
||||
mtpRequestId nextFakeRequestId() { // must be locked by haveReceivedMutex()
|
||||
if (haveReceived.isEmpty() || haveReceived.cbegin().key() > 0) {
|
||||
fakeRequestId = -2000000000;
|
||||
_fakeRequestId = -2000000000;
|
||||
} else {
|
||||
++fakeRequestId;
|
||||
++_fakeRequestId;
|
||||
}
|
||||
return fakeRequestId;
|
||||
return _fakeRequestId;
|
||||
}
|
||||
|
||||
MTProtoSession *owner() {
|
||||
|
@ -174,12 +187,12 @@ private:
|
|||
uint64 _session, _salt;
|
||||
|
||||
uint32 _messagesSent;
|
||||
mtpRequestId fakeRequestId;
|
||||
mtpRequestId _fakeRequestId;
|
||||
|
||||
MTProtoSession *_owner;
|
||||
|
||||
mtpAuthKeyPtr authKey;
|
||||
bool keyChecked;
|
||||
mtpAuthKeyPtr _authKey;
|
||||
bool _keyChecked, _layerInited;
|
||||
|
||||
mtpPreRequestMap toSend; // map of request_id -> request, that is waiting to be sent
|
||||
mtpRequestMap haveSent; // map of msg_id -> request, that was sent, msDate = 0 for msgs_state_req (no resend / state req), msDate = 0, seqNo = 0 for containers
|
||||
|
@ -216,11 +229,12 @@ public:
|
|||
~MTProtoSession();
|
||||
|
||||
QReadWriteLock *keyMutex() const;
|
||||
void keyCreated(const mtpAuthKeyPtr &key);
|
||||
void notifyKeyCreated(const mtpAuthKeyPtr &key);
|
||||
void destroyKey();
|
||||
void notifyLayerInited(bool wasInited);
|
||||
|
||||
template <typename TRequest>
|
||||
mtpRequestId send(const TRequest &request, RPCResponseHandler callbacks = RPCResponseHandler(), uint64 msCanWait = 0, uint32 layer = 0, bool toMainDC = false, mtpRequestId after = 0); // send mtp request
|
||||
mtpRequestId send(const TRequest &request, RPCResponseHandler callbacks = RPCResponseHandler(), uint64 msCanWait = 0, bool needsLayer = false, bool toMainDC = false, mtpRequestId after = 0); // send mtp request
|
||||
void sendAnything(uint64 msCanWait);
|
||||
|
||||
void cancel(mtpRequestId requestId, mtpMsgId msgId);
|
||||
|
@ -247,6 +261,7 @@ signals:
|
|||
public slots:
|
||||
|
||||
void authKeyCreatedForDC();
|
||||
void layerWasInitedForDC(bool wasInited);
|
||||
|
||||
void tryToReceive();
|
||||
void checkRequestsByTimer();
|
||||
|
@ -255,9 +270,6 @@ public slots:
|
|||
|
||||
private:
|
||||
|
||||
template <typename TRequest>
|
||||
mtpRequestId sendFirst(const MTPInitConnection<TRequest> &request, RPCResponseHandler callbacks = RPCResponseHandler(), uint64 msCanWait = 0, uint32 layer = 0, bool toMainDC = false, mtpRequestId after = 0); // send first mtp request
|
||||
|
||||
typedef QList<MTProtoConnection*> MTProtoConnections;
|
||||
MTProtoConnections connections;
|
||||
|
||||
|
|
|
@ -18,22 +18,17 @@ Copyright (c) 2014 John Preston, https://tdesktop.com
|
|||
#pragma once
|
||||
|
||||
template <typename TRequest>
|
||||
mtpRequestId MTProtoSession::send(const TRequest &request, RPCResponseHandler callbacks, uint64 msCanWait, uint32 layer, bool toMainDC, mtpRequestId after) {
|
||||
mtpRequestId MTProtoSession::send(const TRequest &request, RPCResponseHandler callbacks, uint64 msCanWait, bool needsLayer, bool toMainDC, mtpRequestId after) {
|
||||
mtpRequestId requestId = 0;
|
||||
if (layer && dc->needConnectionInit()) {
|
||||
MTPInitConnection<TRequest> requestWrap(MTPinitConnection<TRequest>(MTP_int(ApiId), MTP_string(cApiDeviceModel()), MTP_string(cApiSystemVersion()), MTP_string(cApiAppVersion()), MTP_string(ApiLang), request));
|
||||
return sendFirst(requestWrap, callbacks, msCanWait, layer, toMainDC, after);
|
||||
}
|
||||
try {
|
||||
uint32 requestSize = request.size() >> 2;
|
||||
if (dc->connectionInited()) layer = 0;
|
||||
mtpRequest reqSerialized(mtpRequestData::prepare(requestSize + (layer ? 1 : 0)));
|
||||
if (layer) reqSerialized->push_back(mtpLayers[layer]);
|
||||
uint32 requestSize = request.innerLength() >> 2;
|
||||
mtpRequest reqSerialized(mtpRequestData::prepare(requestSize));
|
||||
request.write(*reqSerialized);
|
||||
|
||||
DEBUG_LOG(("MTP Info: adding request to toSendMap, msCanWait %1").arg(msCanWait));
|
||||
|
||||
reqSerialized->msDate = getms(true); // > 0 - can send without container
|
||||
reqSerialized->needsLayer = needsLayer;
|
||||
if (after) reqSerialized->after = _mtp_internal::getRequest(after);
|
||||
requestId = _mtp_internal::storeRequest(reqSerialized, callbacks);
|
||||
|
||||
|
@ -45,44 +40,3 @@ mtpRequestId MTProtoSession::send(const TRequest &request, RPCResponseHandler ca
|
|||
if (requestId) _mtp_internal::registerRequest(requestId, toMainDC ? -getDC() : getDC());
|
||||
return requestId;
|
||||
}
|
||||
|
||||
class RPCWrappedDcDoneHandler : public RPCAbstractDoneHandler {
|
||||
public:
|
||||
RPCWrappedDcDoneHandler(const MTProtoDCPtr &dc, const RPCDoneHandlerPtr &ondone) : _dc(dc), _ondone(ondone) {
|
||||
}
|
||||
|
||||
void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const {
|
||||
_dc->setConnectionInited();
|
||||
if (_ondone) (*_ondone)(requestId, from, end);
|
||||
}
|
||||
|
||||
private:
|
||||
MTProtoDCPtr _dc;
|
||||
RPCDoneHandlerPtr _ondone;
|
||||
};
|
||||
|
||||
template <typename TRequest>
|
||||
mtpRequestId MTProtoSession::sendFirst(const MTPInitConnection<TRequest> &request, RPCResponseHandler callbacks, uint64 msCanWait, uint32 layer, bool toMainDC, mtpRequestId after) {
|
||||
mtpRequestId requestId = 0;
|
||||
try {
|
||||
uint32 requestSize = request.size() >> 2;
|
||||
mtpRequest reqSerialized(mtpRequestData::prepare(requestSize + (layer ? 1 : 0)));
|
||||
if (layer) reqSerialized->push_back(mtpLayers[layer]);
|
||||
request.write(*reqSerialized);
|
||||
|
||||
DEBUG_LOG(("MTP Info: adding wrapped to init connection request to toSendMap, msCanWait %1").arg(msCanWait));
|
||||
callbacks.onDone = RPCDoneHandlerPtr(new RPCWrappedDcDoneHandler(dc, callbacks.onDone));
|
||||
reqSerialized->msDate = getms(true); // > 0 - can send without container
|
||||
if (after) reqSerialized->after = _mtp_internal::getRequest(after);
|
||||
requestId = _mtp_internal::storeRequest(reqSerialized, callbacks);
|
||||
|
||||
sendPrepared(reqSerialized, msCanWait);
|
||||
} catch (Exception &e) {
|
||||
requestId = 0;
|
||||
_mtp_internal::rpcErrorOccured(requestId, callbacks, rpcClientError("NO_REQUEST_ID", QString("sendFirst() failed to queue request, exception: %1").arg(e.what())));
|
||||
}
|
||||
if (requestId) {
|
||||
_mtp_internal::registerRequest(requestId, toMainDC ? -getDC() : getDC());
|
||||
}
|
||||
return requestId;
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
/////////////////// Layer cons
|
||||
///////////////////////////////
|
||||
|
||||
|
||||
//invokeAfterMsg#cb9f372d msg_id:long query:!X = X;
|
||||
//invokeAfterMsgs#3dc4b4f0 msg_ids:Vector<long> query:!X = X;
|
||||
//invokeWithLayer1#53835315 query:!X = X;
|
||||
|
@ -34,6 +33,7 @@
|
|||
//invokeWithLayer16#cf5f0987 query:!X = X;
|
||||
//invokeWithLayer17#50858a19 query:!X = X;
|
||||
//invokeWithLayer18#1c900537 query:!X = X;
|
||||
//invokeWithLayer#da9b0d0d layer:int query:!X = X; // after 18 layer
|
||||
|
||||
///////////////////////////////
|
||||
/// Authorization key creation
|
||||
|
@ -287,7 +287,7 @@ contactBlocked#561bc879 user_id:int date:int = ContactBlocked;
|
|||
|
||||
contactSuggested#3de191a1 user_id:int mutual_contacts:int = ContactSuggested;
|
||||
|
||||
contactStatus#aa77b873 user_id:int expires:int = ContactStatus;
|
||||
contactStatus#d3680c61 user_id:int status:UserStatus = ContactStatus;
|
||||
|
||||
chatLocated#3631cf4c chat_id:int distance:int = ChatLocated;
|
||||
|
||||
|
@ -510,6 +510,34 @@ contacts.found#566000e results:Vector<ContactFound> users:Vector<User> = contact
|
|||
|
||||
updateServiceNotification#382dd3e4 type:string message:string media:MessageMedia popup:Bool = Update;
|
||||
|
||||
userStatusRecently#e26f42f1 = UserStatus;
|
||||
userStatusLastWeek#7bf09fc = UserStatus;
|
||||
userStatusLastMonth#77ebc742 = UserStatus;
|
||||
|
||||
updatePrivacy#ee3b272a key:PrivacyKey rules:Vector<PrivacyRule> = Update;
|
||||
|
||||
inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey;
|
||||
|
||||
privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey;
|
||||
|
||||
inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule;
|
||||
inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule;
|
||||
inputPrivacyValueAllowUsers#131cc67f users:Vector<InputUser> = InputPrivacyRule;
|
||||
inputPrivacyValueDisallowContacts#ba52007 = InputPrivacyRule;
|
||||
inputPrivacyValueDisallowAll#d66b66c9 = InputPrivacyRule;
|
||||
inputPrivacyValueDisallowUsers#90110467 users:Vector<InputUser> = InputPrivacyRule;
|
||||
|
||||
privacyValueAllowContacts#fffe1bac = PrivacyRule;
|
||||
privacyValueAllowAll#65427b82 = PrivacyRule;
|
||||
privacyValueAllowUsers#4d5bbe0c users:Vector<int> = PrivacyRule;
|
||||
privacyValueDisallowContacts#f888fa1a = PrivacyRule;
|
||||
privacyValueDisallowAll#8b73e763 = PrivacyRule;
|
||||
privacyValueDisallowUsers#c7f49b7 users:Vector<int> = PrivacyRule;
|
||||
|
||||
account.privacyRules#554abb6f rules:Vector<PrivacyRule> users:Vector<User> = account.PrivacyRules;
|
||||
|
||||
accountDaysTTL#b8d0afdf days:int = AccountDaysTTL;
|
||||
|
||||
---functions---
|
||||
|
||||
invokeAfterMsg#cb9f372d msg_id:long query:!X = X;
|
||||
|
@ -631,3 +659,9 @@ account.checkUsername#2714d86c username:string = Bool;
|
|||
account.updateUsername#3e0bdd7c username:string = User;
|
||||
|
||||
contacts.search#11f812d8 q:string limit:int = contacts.Found;
|
||||
|
||||
account.getPrivacy#dadbc950 key:InputPrivacyKey = account.PrivacyRules;
|
||||
account.setPrivacy#c9f81ce8 key:InputPrivacyKey rules:Vector<InputPrivacyRule> = account.PrivacyRules;
|
||||
account.deleteAccount#418d4e0b reason:string = Bool;
|
||||
account.getAccountTTL#8fc711d = AccountDaysTTL;
|
||||
account.setAccountTTL#2442485e ttl:AccountDaysTTL = Bool;
|
||||
|
|
|
@ -40,6 +40,7 @@ OverviewInner::OverviewInner(OverviewWidget *overview, ScrollArea *scroll, const
|
|||
, _hist(App::history(peer->id))
|
||||
, _photosInRow(1)
|
||||
, _photosToAdd(0)
|
||||
, _selMode(false)
|
||||
, _width(0)
|
||||
, _height(0)
|
||||
, _minHeight(0)
|
||||
|
@ -425,7 +426,7 @@ void OverviewInner::dragActionFinish(const QPoint &screenPos, Qt::MouseButton bu
|
|||
dragActionUpdate(screenPos);
|
||||
|
||||
if (textlnkOver()) {
|
||||
if (textlnkDown() == textlnkOver() && _dragAction != Dragging) {
|
||||
if (textlnkDown() == textlnkOver() && _dragAction != Dragging && !_selMode) {
|
||||
needClick = textlnkDown();
|
||||
}
|
||||
}
|
||||
|
@ -662,7 +663,10 @@ void OverviewInner::paintEvent(QPaintEvent *e) {
|
|||
}
|
||||
}
|
||||
if (sel == FullItemSel) {
|
||||
p.fillRect(QRect(pos.x(), pos.y(), _vsize, _vsize), st::msgInSelectOverlay->b);
|
||||
p.fillRect(QRect(pos.x(), pos.y(), _vsize, _vsize), st::overviewPhotoSelectOverlay->b);
|
||||
p.drawPixmap(QPoint(pos.x() + _vsize - st::overviewPhotoChecked.pxWidth(), pos.y() + _vsize - st::overviewPhotoChecked.pxHeight()), App::sprite(), st::overviewPhotoChecked);
|
||||
} else if (_selMode/* || (selfrom < count && selfrom <= selto && 0 <= selto)*/) {
|
||||
p.drawPixmap(QPoint(pos.x() + _vsize - st::overviewPhotoChecked.pxWidth(), pos.y() + _vsize - st::overviewPhotoChecked.pxHeight()), App::sprite(), st::overviewPhotoCheck);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
@ -1136,6 +1140,10 @@ void OverviewInner::switchType(MediaOverviewType type) {
|
|||
if (App::wnd()) App::wnd()->update();
|
||||
}
|
||||
|
||||
void OverviewInner::setSelectMode(bool enabled) {
|
||||
_selMode = enabled;
|
||||
}
|
||||
|
||||
void OverviewInner::openContextUrl() {
|
||||
HistoryItem *was = App::hoveredLinkItem();
|
||||
App::hoveredLinkItem(App::contextItem());
|
||||
|
@ -1620,6 +1628,8 @@ MediaOverviewType OverviewWidget::type() const {
|
|||
}
|
||||
|
||||
void OverviewWidget::switchType(MediaOverviewType type) {
|
||||
_selCount = 0;
|
||||
_inner.setSelectMode(false);
|
||||
_inner.switchType(type);
|
||||
switch (type) {
|
||||
case OverviewPhotos: _header = lang(lng_profile_photos_header); break;
|
||||
|
@ -1628,7 +1638,6 @@ void OverviewWidget::switchType(MediaOverviewType type) {
|
|||
case OverviewAudios: _header = lang(lng_profile_audios_header); break;
|
||||
}
|
||||
noSelectingScroll();
|
||||
_selCount = 0;
|
||||
App::main()->topBar()->showSelected(0);
|
||||
updateTopBarSelection();
|
||||
_scroll.scrollToY(_scroll.scrollTopMax());
|
||||
|
@ -1639,6 +1648,7 @@ void OverviewWidget::updateTopBarSelection() {
|
|||
int32 selectedForForward, selectedForDelete;
|
||||
_inner.getSelectionState(selectedForForward, selectedForDelete);
|
||||
_selCount = selectedForDelete ? selectedForDelete : selectedForForward;
|
||||
_inner.setSelectMode(_selCount > 0);
|
||||
if (App::main()) {
|
||||
App::main()->topBar()->showSelected(_selCount > 0 ? _selCount : 0);
|
||||
App::main()->topBar()->update();
|
||||
|
|
|
@ -55,6 +55,8 @@ public:
|
|||
MediaOverviewType type() const;
|
||||
void switchType(MediaOverviewType type);
|
||||
|
||||
void setSelectMode(bool enabled);
|
||||
|
||||
void mediaOverviewUpdated();
|
||||
void changingMsgId(HistoryItem *row, MsgId newId);
|
||||
void msgUpdated(const HistoryItem *msg);
|
||||
|
@ -124,6 +126,7 @@ private:
|
|||
} CachedSize;
|
||||
typedef QMap<PhotoData*, CachedSize> CachedSizes;
|
||||
CachedSizes _cached;
|
||||
bool _selMode;
|
||||
|
||||
// other
|
||||
typedef struct _CachedItem {
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.6.8</string>
|
||||
<string>0.6.9</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>NOTE</key>
|
||||
|
|
Binary file not shown.
|
@ -1521,7 +1521,7 @@
|
|||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 0.6.8;
|
||||
CURRENT_PROJECT_VERSION = 0.6.9;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
|
@ -1539,7 +1539,7 @@
|
|||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
COPY_PHASE_STRIP = YES;
|
||||
CURRENT_PROJECT_VERSION = 0.6.8;
|
||||
CURRENT_PROJECT_VERSION = 0.6.9;
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
|
||||
GCC_OPTIMIZATION_LEVEL = fast;
|
||||
GCC_PREFIX_HEADER = ./SourceFiles/stdafx.h;
|
||||
|
@ -1565,10 +1565,10 @@
|
|||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 0.6.8;
|
||||
CURRENT_PROJECT_VERSION = 0.6.9;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DYLIB_COMPATIBILITY_VERSION = 0.6;
|
||||
DYLIB_CURRENT_VERSION = 0.6.8;
|
||||
DYLIB_CURRENT_VERSION = 0.6.9;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = "";
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
|
||||
|
@ -1708,10 +1708,10 @@
|
|||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 0.6.8;
|
||||
CURRENT_PROJECT_VERSION = 0.6.9;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DYLIB_COMPATIBILITY_VERSION = 0.6;
|
||||
DYLIB_CURRENT_VERSION = 0.6.8;
|
||||
DYLIB_CURRENT_VERSION = 0.6.9;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = "";
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
/*************************************************
|
||||
* Perl-Compatible Regular Expressions *
|
||||
*************************************************/
|
||||
|
||||
/* PCRE is a library of functions to support regular expressions whose syntax
|
||||
and semantics are as close as possible to those of the Perl 5 language.
|
||||
|
||||
Written by Philip Hazel
|
||||
Copyright (c) 1997-2013 University of Cambridge
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the University of Cambridge nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
/* This module contains an internal function for validating UTF-16 character
|
||||
strings. */
|
||||
|
||||
|
||||
#ifdef PCRE_HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
/* Generate code with 16 bit character support. */
|
||||
#define COMPILE_PCRE16
|
||||
|
||||
#include "pcre_internal.h"
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Validate a UTF-16 string *
|
||||
*************************************************/
|
||||
|
||||
/* This function is called (optionally) at the start of compile or match, to
|
||||
check that a supposed UTF-16 string is actually valid. The early check means
|
||||
that subsequent code can assume it is dealing with a valid string. The check
|
||||
can be turned off for maximum performance, but the consequences of supplying an
|
||||
invalid string are then undefined.
|
||||
|
||||
From release 8.21 more information about the details of the error are passed
|
||||
back in the returned value:
|
||||
|
||||
PCRE_UTF16_ERR0 No error
|
||||
PCRE_UTF16_ERR1 Missing low surrogate at the end of the string
|
||||
PCRE_UTF16_ERR2 Invalid low surrogate
|
||||
PCRE_UTF16_ERR3 Isolated low surrogate
|
||||
PCRE_UTF16_ERR4 Unused (was non-character)
|
||||
|
||||
Arguments:
|
||||
string points to the string
|
||||
length length of string, or -1 if the string is zero-terminated
|
||||
errp pointer to an error position offset variable
|
||||
|
||||
Returns: = 0 if the string is a valid UTF-16 string
|
||||
> 0 otherwise, setting the offset of the bad character
|
||||
*/
|
||||
|
||||
int
|
||||
PRIV(valid_utf)(PCRE_PUCHAR string, int length, int *erroroffset)
|
||||
{
|
||||
#ifdef SUPPORT_UTF
|
||||
register PCRE_PUCHAR p;
|
||||
register pcre_uint32 c;
|
||||
|
||||
if (length < 0)
|
||||
{
|
||||
for (p = string; *p != 0; p++);
|
||||
length = p - string;
|
||||
}
|
||||
|
||||
for (p = string; length-- > 0; p++)
|
||||
{
|
||||
c = *p;
|
||||
|
||||
if ((c & 0xf800) != 0xd800)
|
||||
{
|
||||
/* Normal UTF-16 code point. Neither high nor low surrogate. */
|
||||
}
|
||||
else if ((c & 0xfc00) == 0xd800)
|
||||
{
|
||||
/* High surrogate. Must be a followed by a low surrogate. */
|
||||
if (length == 0)
|
||||
{
|
||||
*erroroffset = p - string;
|
||||
return PCRE_UTF16_ERR1;
|
||||
}
|
||||
p++;
|
||||
length--;
|
||||
if ((*p & 0xfc00) != 0xdc00)
|
||||
{
|
||||
*erroroffset = p - string;
|
||||
return PCRE_UTF16_ERR2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Isolated low surrogate. Always an error. */
|
||||
*erroroffset = p - string;
|
||||
return PCRE_UTF16_ERR3;
|
||||
}
|
||||
}
|
||||
|
||||
#else /* SUPPORT_UTF */
|
||||
(void)(string); /* Keep picky compilers happy */
|
||||
(void)(length);
|
||||
(void)(erroroffset);
|
||||
#endif /* SUPPORT_UTF */
|
||||
|
||||
return PCRE_UTF16_ERR0; /* This indicates success */
|
||||
}
|
||||
|
||||
/* End of pcre16_valid_utf16.c */
|
Loading…
Reference in New Issue