31 layer, IPv6 support, bot support started

This commit is contained in:
John Preston 2015-06-10 15:48:26 +03:00
parent 7afda6dfc3
commit 85635dbefd
25 changed files with 1232 additions and 722 deletions

View File

@ -69,6 +69,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_reconnecting_try_now" = "Try now";
"lng_status_service_notifications" = "service notifications";
"lng_status_bot" = "bot";
"lng_status_offline" = "last seen a long time ago";
"lng_status_recently" = "last seen recently";
"lng_status_last_week" = "last seen within a week";

View File

@ -206,7 +206,11 @@ namespace App {
return (peer_id & 0x100000000L) ? int32(peer_id & 0xFFFFFFFFL) : 0;
}
int32 onlineForSort(int32 online, int32 now) {
int32 onlineForSort(UserData *user, int32 now) {
if (isServiceUser(user->id) || user->botInfo) {
return now - 1;
}
int32 online = user->onlineTill;
if (online <= 0) {
switch (online) {
case 0:
@ -232,8 +236,12 @@ namespace App {
return online;
}
int32 onlineWillChangeIn(int32 online, int32 now) {
if (online <= 0) {
int32 onlineWillChangeIn(UserData *user, int32 now) {
if (isServiceUser(user->id) || user->botInfo) {
return 86400;
}
int32 online = user->onlineTill;
if (online <= 0) {
if (-online > now) return -online - now;
return 86400;
}
@ -255,6 +263,8 @@ namespace App {
QString onlineText(UserData *user, int32 now, bool precise) {
if (isServiceUser(user->id)) {
return lang(lng_status_service_notifications);
} else if (user->botInfo) {
return lang(lng_status_bot);
}
int32 online = user->onlineTill;
if (online <= 0) {
@ -337,84 +347,48 @@ namespace App {
status = &emptyStatus;
data->contact = -1;
} break;
case mtpc_userDeleted: {
const MTPDuserDeleted &d(user.c_userDeleted());
case mtpc_user: {
const MTPDuser &d(user.c_user());
PeerId peer(peerFromUser(d.vid.v));
data = App::user(peer);
data->input = MTP_inputPeerContact(d.vid);
data->inputUser = MTP_inputUserContact(d.vid);
data->setName(lang(lng_deleted), QString(), QString(), QString());
// data->setName(textOneLine(qs(d.vfirst_name)), textOneLine(qs(d.vlast_name)), QString(), textOneLine(qs(d.vusername)));
data->setPhoto(MTP_userProfilePhotoEmpty());
data->access = UserNoAccess;
int32 flags = d.vflags.v;
if (flags & MTPDuser_flag_self) {
data->input = MTP_inputPeerSelf();
data->inputUser = MTP_inputUserSelf();
} else if ((flags & (MTPDuser_flag_contact | MTPDuser_flag_mutual_contact)) || !d.has_access_hash()) {
data->input = MTP_inputPeerContact(d.vid);
data->inputUser = MTP_inputUserContact(d.vid);
} else {
data->input = MTP_inputPeerForeign(d.vid, d.vaccess_hash);
data->inputUser = MTP_inputUserForeign(d.vid, d.vaccess_hash);
}
if (flags & MTPDuser_flag_deleted) {
data->setPhone(QString());
data->setName(lang(lng_deleted), QString(), QString(), QString());
data->setPhoto(MTP_userProfilePhotoEmpty());
data->access = UserNoAccess;
status = &emptyStatus;
} else {
data->setPhone(d.has_phone() ? qs(d.vphone) : QString());
QString fname = d.has_first_name() ? textOneLine(qs(d.vfirst_name)) : QString();
QString lname = d.has_last_name() ? textOneLine(qs(d.vlast_name)) : QString();
QString uname = d.has_username() ? textOneLine(qs(d.vusername)) : QString();
bool showPhone = !isServiceUser(data->id) && !(flags & (MTPDuser_flag_self | MTPDuser_flag_contact | MTPDuser_flag_mutual_contact));
QString pname = (showPhone && !data->phone.isEmpty()) ? formatPhone(data->phone) : QString();
data->setName(fname, lname, QString(), uname);
data->setPhoto(d.has_photo() ? d.vphoto : MTP_userProfilePhotoEmpty());
if (d.has_access_hash()) data->access = d.vaccess_hash.v;
status = d.has_status() ? &d.vstatus : &emptyStatus;
}
wasContact = (data->contact > 0);
status = &emptyStatus;
data->contact = -1;
} break;
case mtpc_userSelf: {
const MTPDuserSelf &d(user.c_userSelf());
PeerId peer(peerFromUser(d.vid.v));
data = App::user(peer);
data->input = MTP_inputPeerSelf();
data->inputUser = MTP_inputUserSelf();
data->setName(textOneLine(qs(d.vfirst_name)), textOneLine(qs(d.vlast_name)), QString(), textOneLine(qs(d.vusername)));
data->setPhoto(d.vphoto);
data->setPhone(qs(d.vphone));
data->access = 0;
wasContact = (data->contact > 0);
status = &d.vstatus;
if (::self != data) {
if (d.has_bot_info_version()) data->setBotInfoVersion(d.vbot_info_version.v);
data->contact = (flags & (MTPDuser_flag_contact | MTPDuser_flag_mutual_contact)) ? 1 : (data->phone.isEmpty() ? -1 : 0);
if ((flags & MTPDuser_flag_self) && ::self != data) {
::self = data;
if (App::wnd()) App::wnd()->updateGlobalMenu();
}
} break;
case mtpc_userContact: {
const MTPDuserContact &d(user.c_userContact());
PeerId peer(peerFromUser(d.vid.v));
data = App::user(peer);
data->input = MTP_inputPeerContact(d.vid);
data->inputUser = MTP_inputUserContact(d.vid);
data->setName(textOneLine(qs(d.vfirst_name)), textOneLine(qs(d.vlast_name)), QString(), textOneLine(qs(d.vusername)));
data->setPhoto(d.vphoto);
data->setPhone(qs(d.vphone));
data->access = d.vaccess_hash.v;
wasContact = (data->contact > 0);
data->contact = 1;
status = &d.vstatus;
} break;
case mtpc_userRequest: {
const MTPDuserRequest &d(user.c_userRequest());
PeerId peer(peerFromUser(d.vid.v));
data = App::user(peer);
data->input = MTP_inputPeerForeign(d.vid, d.vaccess_hash);
data->inputUser = MTP_inputUserForeign(d.vid, d.vaccess_hash);
data->setPhone(qs(d.vphone));
data->setName(textOneLine(qs(d.vfirst_name)), textOneLine(qs(d.vlast_name)), (!isServiceUser(data->id) && !data->phone.isEmpty()) ? formatPhone(data->phone) : QString(), textOneLine(qs(d.vusername)));
data->setPhoto(d.vphoto);
data->access = d.vaccess_hash.v;
wasContact = (data->contact > 0);
data->contact = 0;
status = &d.vstatus;
} break;
case mtpc_userForeign: {
const MTPDuserForeign &d(user.c_userForeign());
PeerId peer(peerFromUser(d.vid.v));
data = App::user(peer);
data->input = MTP_inputPeerForeign(d.vid, d.vaccess_hash);
data->inputUser = MTP_inputUserForeign(d.vid, d.vaccess_hash);
data->setName(textOneLine(qs(d.vfirst_name)), textOneLine(qs(d.vlast_name)), QString(), textOneLine(qs(d.vusername)));
data->setPhoto(d.vphoto);
data->access = d.vaccess_hash.v;
wasContact = (data->contact > 0);
data->contact = -1;
status = &d.vstatus;
} break;
}
if (!data) continue;
@ -731,11 +705,7 @@ namespace App {
MTPint userId(MTP_int(0));
switch (dv.vuser.type()) {
case mtpc_userEmpty: userId = dv.vuser.c_userEmpty().vid; break;
case mtpc_userDeleted: userId = dv.vuser.c_userDeleted().vid; break;
case mtpc_userContact: userId = dv.vuser.c_userContact().vid; break;
case mtpc_userSelf: userId = dv.vuser.c_userSelf().vid; break;
case mtpc_userRequest: userId = dv.vuser.c_userRequest().vid; break;
case mtpc_userForeign: userId = dv.vuser.c_userForeign().vid; break;
case mtpc_user: userId = dv.vuser.c_user().vid; break;
}
if (userId.v) {
feedUserLink(userId, dv.vmy_link, dv.vforeign_link);
@ -1183,6 +1153,7 @@ namespace App {
}
DocumentData *documentSet(const DocumentId &document, DocumentData *convert, const uint64 &access, int32 date, const QVector<MTPDocumentAttribute> &attributes, const QString &mime, const ImagePtr &thumb, int32 dc, int32 size, const StorageImageLocation &thumbLocation) {
bool sentSticker = false;
if (convert) {
if (convert->id != document) {
DocumentsData::iterator i = documentsData.find(convert->id);
@ -1191,6 +1162,7 @@ namespace App {
}
convert->id = document;
convert->status = FileReady;
sentSticker = !!convert->sticker;
}
convert->access = access;
if (!convert->date && date) {
@ -1266,6 +1238,7 @@ namespace App {
}
}
}
if (sentSticker && App::main()) App::main()->incrementSticker(result);
return result;
}

View File

@ -92,8 +92,8 @@ namespace App {
int32 userFromPeer(const PeerId &peer_id);
int32 chatFromPeer(const PeerId &peer_id);
int32 onlineForSort(int32 online, int32 now);
int32 onlineWillChangeIn(int32 onlineOnServer, int32 nowOnServer);
int32 onlineForSort(UserData *user, int32 now);
int32 onlineWillChangeIn(UserData *user, int32 nowOnServer);
QString onlineText(UserData *user, int32 nowOnServer, bool precise = false);
bool onlineColorUse(int32 online, int32 now);

View File

@ -43,7 +43,8 @@ enum {
MTPMinConnectDelay = 1000, // tcp connect should take less then 1 second
MTPMaxConnectDelay = 8000, // tcp connect should take 8 seconds max
MTPConnectionOldTimeout = 192000, // 192 seconds
MTPTcpConnectionWaitTimeout = 3000, // 3 seconds waiting for tcp, until we accept http
MTPTcpConnectionWaitTimeout = 2000, // 2 seconds waiting for tcp, until we accept http
MTPIPv4ConnectionWaitTimeout = 1000, // 1 seconds waiting for ipv4, until we accept ipv6
MTPMillerRabinIterCount = 30, // 30 Miller-Rabin iterations for dh_prime primality check
MTPUploadSessionsCount = 4, // max 4 upload sessions is created
@ -125,7 +126,7 @@ enum {
SaveDraftTimeout = 1000, // save draft after 1 secs of not changing text
SaveDraftAnywayTimeout = 5000, // or save anyway each 5 secs
HiddenIsOnlineAfterMessage = 30, // user with hidden last seen stays online for such amount of seconds in the interface
SetOnlineAfterActivity = 30, // user with hidden last seen stays online for such amount of seconds in the interface
ServiceUserId = 777000,
WebPageUserId = 701000,
@ -186,10 +187,24 @@ static const BuiltInDc _builtInDcs[] = {
{ 5, "149.154.171.5", 443 }
};
static const BuiltInDc _builtInDcsIPv6[] = {
{ 1, "2001:b28:f23d:f001::a", 443 },
{ 2, "2001:67c:4e8:f002::a", 443 },
{ 3, "2001:b28:f23d:f003::a", 443 },
{ 4, "2001:67c:4e8:f004::a", 443 },
{ 5, "2001:b28:f23f:f005::a", 443 }
};
static const BuiltInDc _builtInTestDcs[] = {
{ 1, "149.154.175.10", 443 },
{ 2, "149.154.167.40", 443 },
{ 3, "174.140.142.5", 443 }
{ 3, "149.154.175.117", 443 }
};
static const BuiltInDc _builtInTestDcsIPv6[] = {
{ 1, "2001:b28:f23d:f001::e", 443 },
{ 2, "2001:67c:4e8:f002::e", 443 },
{ 3, "2001:b28:f23d:f003::e", 443 }
};
inline const BuiltInDc *builtInDcs() {
@ -200,6 +215,14 @@ inline int builtInDcsCount() {
return (cTestMode() ? sizeof(_builtInTestDcs) : sizeof(_builtInDcs)) / sizeof(BuiltInDc);
}
inline const BuiltInDc *builtInDcsIPv6() {
return cTestMode() ? _builtInTestDcsIPv6 : _builtInDcsIPv6;
}
inline int builtInDcsCountIPv6() {
return (cTestMode() ? sizeof(_builtInTestDcsIPv6) : sizeof(_builtInDcsIPv6)) / sizeof(BuiltInDc);
}
static const char *UpdatesPublicKey = "\
-----BEGIN RSA PUBLIC KEY-----\n\
MIGJAoGBAMA4ViQrjkPZ9xj0lrer3r23JvxOnrtE8nI69XLGSr+sRERz9YnUptnU\n\

View File

@ -2635,7 +2635,7 @@ void MentionsDropdown::updateFiltered(bool toDown) {
UserData *user = i.key();
if (user->username.isEmpty()) continue;
if (_filter.size() > 1 && (!user->username.startsWith(_filter.midRef(1), Qt::CaseInsensitive) || user->username.size() + 1 == _filter.size())) continue;
ordered.insertMulti(App::onlineForSort(user->onlineTill, now), user);
ordered.insertMulti(App::onlineForSort(user, now), user);
}
}
for (MentionRows::const_iterator i = _chat->lastAuthors.cbegin(), e = _chat->lastAuthors.cend(); i != e; ++i) {
@ -2644,7 +2644,7 @@ void MentionsDropdown::updateFiltered(bool toDown) {
if (_filter.size() > 1 && (!user->username.startsWith(_filter.midRef(1), Qt::CaseInsensitive) || user->username.size() + 1 == _filter.size())) continue;
rows.push_back(user);
if (!ordered.isEmpty()) {
ordered.remove(App::onlineForSort(user->onlineTill, now), user);
ordered.remove(App::onlineForSort(user, now), user);
}
}
if (!ordered.isEmpty()) {

View File

@ -460,6 +460,8 @@ void Histories::regTyping(History *history, UserData *user) {
uint64 ms = getms(true);
history->typing[user] = ms + 6000;
user->madeAction();
TypingHistories::const_iterator i = typing.find(history);
if (i == typing.cend()) {
typing.insert(history, ms);
@ -802,10 +804,7 @@ void History::newItemAdded(HistoryItem *item) {
App::checkImageCacheSize();
if (item->from()) {
unregTyping(item->from());
if (item->from()->onlineTill < 0) {
item->from()->onlineTill = -unixtime() - HiddenIsOnlineAfterMessage; // pseudo-online
if (App::main()) App::main()->peerUpdated(item->from());
}
item->from()->madeAction();
}
if (item->out()) {
if (unreadBar) unreadBar->destroy();
@ -3083,7 +3082,6 @@ void HistorySticker::updateFrom(const MTPMessageMedia &media) {
if (!data->data.isEmpty()) {
Local::writeStickerImage(mediaKey(mtpToLocationType(mtpc_inputDocumentFileLocation), data->dc, data->id), data->data);
}
if (App::main()) App::main()->incrementSticker(data);
}
}
@ -3417,11 +3415,13 @@ void HistoryWebPage::initDimensions(const HistoryItem *parent) {
}
QString title(data->title.isEmpty() ? data->author : data->title);
if (!title.isEmpty()) {
_title.setText(st::webPageTitleFont, textClean(title), _webpageTitleOptions);
title = textClean(title);
if (!_asArticle && !data->photo && data->description.isEmpty()) title += textcmdSkipBlock(parent->timeWidth(true), st::msgDateFont->height - st::msgDateDelta.y());
_title.setText(st::webPageTitleFont, title, _webpageTitleOptions);
if (_asArticle) {
_maxw = qMax(_maxw, int32(st::webPageLeft + _title.maxWidth() + st::webPagePhotoDelta + st::webPagePhotoSize));
} else {
_maxw = qMax(_maxw, int32(st::webPageLeft + _title.maxWidth() + (data->photo ? parent->timeWidth(true) : 0)));
_maxw = qMax(_maxw, int32(st::webPageLeft + _title.maxWidth()));
_minh += qMin(_title.minHeight(), 2 * st::webPageTitleFont->height);
}
}

View File

@ -2779,14 +2779,15 @@ void HistoryWidget::shareContact(const PeerId &peer, const QString &phone, const
h->loadAround(0);
PeerData *p = App::peer(peer);
int32 flags = (p->input.type() == mtpc_inputPeerSelf) ? 0 : (MTPDmessage_flag_unread | MTPDmessage_flag_out); // unread, out
int32 flags = newMessageFlags(p); // unread, out
int32 sendFlags = 0;
if (replyTo) {
flags |= MTPDmessage::flag_reply_to_msg_id;
sendFlags |= MTPmessages_SendMedia::flag_reply_to_msg_id;
}
h->addToBack(MTP_message(MTP_int(flags), MTP_int(newId), MTP_int(MTP::authedId()), App::peerToMTP(peer), MTPint(), MTPint(), MTP_int(_replyToId), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaContact(MTP_string(phone), MTP_string(fname), MTP_string(lname), MTP_int(userId))));
h->sendRequestId = MTP::send(MTPmessages_SendMedia(MTP_int(sendFlags), p->input, MTP_int(replyTo), MTP_inputMediaContact(MTP_string(phone), MTP_string(fname), MTP_string(lname)), MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), RPCFailHandlerPtr(), 0, 0, hist->sendRequestId);
h->addToBack(MTP_message(MTP_int(flags), MTP_int(newId), MTP_int(MTP::authedId()), App::peerToMTP(peer), MTPint(), MTPint(), MTP_int(_replyToId), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaContact(MTP_string(phone), MTP_string(fname), MTP_string(lname), MTP_int(userId)), MTPnullMarkup));
h->sendRequestId = MTP::send(MTPmessages_SendMedia(MTP_int(sendFlags), p->input, MTP_int(replyTo), MTP_inputMediaContact(MTP_string(phone), MTP_string(fname), MTP_string(lname)), MTP_long(randomId), MTPnullMarkup), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), RPCFailHandlerPtr(), 0, 0, hist->sendRequestId);
App::historyRegRandom(randomId, newId);
@ -3287,13 +3288,13 @@ void HistoryWidget::updateOnlineDisplayTimer() {
if (chat->participants.isEmpty()) return;
for (ChatData::Participants::const_iterator i = chat->participants.cbegin(), e = chat->participants.cend(); i != e; ++i) {
int32 onlineWillChangeIn = App::onlineWillChangeIn(i.key()->onlineTill, t);
int32 onlineWillChangeIn = App::onlineWillChangeIn(i.key(), t);
if (onlineWillChangeIn < minIn) {
minIn = onlineWillChangeIn;
}
}
} else {
minIn = App::onlineWillChangeIn(histPeer->asUser()->onlineTill, t);
minIn = App::onlineWillChangeIn(histPeer->asUser(), t);
}
App::main()->updateOnlineDisplayIn(minIn * 1000);
}
@ -3458,21 +3459,15 @@ void HistoryWidget::confirmSendImage(const ReadyLocalMedia &img) {
App::uploader()->uploadMedia(newId, img);
History *h = App::history(img.peer);
h->loadAround(0);
int32 flags = newMessageFlags(h->peer); // unread, out
if (img.replyTo) flags |= MTPDmessage::flag_reply_to_msg_id;
if (img.type == ToPreparePhoto) {
h->loadAround(0);
int32 flags = (h->peer->input.type() == mtpc_inputPeerSelf) ? 0 : (MTPDmessage_flag_unread | MTPDmessage_flag_out); // unread, out
if (img.replyTo) flags |= MTPDmessage::flag_reply_to_msg_id;
h->addToBack(MTP_message(MTP_int(flags), MTP_int(newId), MTP_int(MTP::authedId()), App::peerToMTP(img.peer), MTPint(), MTPint(), MTP_int(img.replyTo), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaPhoto(img.photo, MTP_string(""))));
h->addToBack(MTP_message(MTP_int(flags), MTP_int(newId), MTP_int(MTP::authedId()), App::peerToMTP(img.peer), MTPint(), MTPint(), MTP_int(img.replyTo), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaPhoto(img.photo, MTP_string("")), MTPnullMarkup));
} else if (img.type == ToPrepareDocument) {
h->loadAround(0);
int32 flags = (h->peer->input.type() == mtpc_inputPeerSelf) ? 0 : (MTPDmessage_flag_unread | MTPDmessage_flag_out); // unread, out
if (img.replyTo) flags |= MTPDmessage::flag_reply_to_msg_id;
h->addToBack(MTP_message(MTP_int(flags), MTP_int(newId), MTP_int(MTP::authedId()), App::peerToMTP(img.peer), MTPint(), MTPint(), MTP_int(img.replyTo), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaDocument(img.document)));
h->addToBack(MTP_message(MTP_int(flags), MTP_int(newId), MTP_int(MTP::authedId()), App::peerToMTP(img.peer), MTPint(), MTPint(), MTP_int(img.replyTo), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaDocument(img.document), MTPnullMarkup));
} else if (img.type == ToPrepareAudio) {
h->loadAround(0);
int32 flags = (h->peer->input.type() == mtpc_inputPeerSelf) ? 0 : (MTPDmessage_flag_unread | MTPDmessage_flag_out | MTPDmessage_flag_media_unread); // unread, out
if (img.replyTo) flags |= MTPDmessage::flag_reply_to_msg_id;
h->addToBack(MTP_message(MTP_int(flags), MTP_int(newId), MTP_int(MTP::authedId()), App::peerToMTP(img.peer), MTPint(), MTPint(), MTP_int(img.replyTo), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaAudio(img.audio)));
h->addToBack(MTP_message(MTP_int(flags), MTP_int(newId), MTP_int(MTP::authedId()), App::peerToMTP(img.peer), MTPint(), MTPint(), MTP_int(img.replyTo), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaAudio(img.audio), MTPnullMarkup));
}
if (hist && histPeer && img.peer == histPeer->id) {
@ -3503,7 +3498,7 @@ void HistoryWidget::onPhotoUploaded(MsgId newId, const MTPInputFile &file) {
if (replyTo) {
sendFlags |= MTPmessages_SendMedia::flag_reply_to_msg_id;
}
hist->sendRequestId = MTP::send(MTPmessages_SendMedia(MTP_int(sendFlags), item->history()->peer->input, MTP_int(replyTo), MTP_inputMediaUploadedPhoto(file, MTP_string("")), MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::sendPhotoFailed, randomId), 0, 0, hist->sendRequestId);
hist->sendRequestId = MTP::send(MTPmessages_SendMedia(MTP_int(sendFlags), item->history()->peer->input, MTP_int(replyTo), MTP_inputMediaUploadedPhoto(file, MTP_string("")), MTP_long(randomId), MTPnullMarkup), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::sendPhotoFailed, randomId), 0, 0, hist->sendRequestId);
}
}
@ -3543,7 +3538,7 @@ void HistoryWidget::onDocumentUploaded(MsgId newId, const MTPInputFile &file) {
if (replyTo) {
sendFlags |= MTPmessages_SendMedia::flag_reply_to_msg_id;
}
hist->sendRequestId = MTP::send(MTPmessages_SendMedia(MTP_int(sendFlags), item->history()->peer->input, MTP_int(replyTo), MTP_inputMediaUploadedDocument(file, MTP_string(document->mime), _composeDocumentAttributes(document)), MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), RPCFailHandlerPtr(), 0, 0, hist->sendRequestId);
hist->sendRequestId = MTP::send(MTPmessages_SendMedia(MTP_int(sendFlags), item->history()->peer->input, MTP_int(replyTo), MTP_inputMediaUploadedDocument(file, MTP_string(document->mime), _composeDocumentAttributes(document)), MTP_long(randomId), MTPnullMarkup), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), RPCFailHandlerPtr(), 0, 0, hist->sendRequestId);
}
}
}
@ -3569,7 +3564,7 @@ void HistoryWidget::onThumbDocumentUploaded(MsgId newId, const MTPInputFile &fil
if (replyTo) {
sendFlags |= MTPmessages_SendMedia::flag_reply_to_msg_id;
}
hist->sendRequestId = MTP::send(MTPmessages_SendMedia(MTP_int(sendFlags), item->history()->peer->input, MTP_int(replyTo), MTP_inputMediaUploadedThumbDocument(file, thumb, MTP_string(document->mime), _composeDocumentAttributes(document)), MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), RPCFailHandlerPtr(), 0, 0, hist->sendRequestId);
hist->sendRequestId = MTP::send(MTPmessages_SendMedia(MTP_int(sendFlags), item->history()->peer->input, MTP_int(replyTo), MTP_inputMediaUploadedThumbDocument(file, thumb, MTP_string(document->mime), _composeDocumentAttributes(document)), MTP_long(randomId), MTPnullMarkup), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), RPCFailHandlerPtr(), 0, 0, hist->sendRequestId);
}
}
}
@ -3593,7 +3588,7 @@ void HistoryWidget::onAudioUploaded(MsgId newId, const MTPInputFile &file) {
if (replyTo) {
sendFlags |= MTPmessages_SendMedia::flag_reply_to_msg_id;
}
hist->sendRequestId = MTP::send(MTPmessages_SendMedia(MTP_int(sendFlags), item->history()->peer->input, MTP_int(replyTo), MTP_inputMediaUploadedAudio(file, MTP_int(audio->duration), MTP_string(audio->mime)), MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), RPCFailHandlerPtr(), 0, 0, hist->sendRequestId);
hist->sendRequestId = MTP::send(MTPmessages_SendMedia(MTP_int(sendFlags), item->history()->peer->input, MTP_int(replyTo), MTP_inputMediaUploadedAudio(file, MTP_int(audio->duration), MTP_string(audio->mime)), MTP_long(randomId), MTPnullMarkup), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), RPCFailHandlerPtr(), 0, 0, hist->sendRequestId);
}
}
}
@ -3895,7 +3890,7 @@ void HistoryWidget::onStickerSend(DocumentData *sticker) {
hist->loadAround(0);
bool out = (histPeer->input.type() != mtpc_inputPeerSelf), unread = (histPeer->input.type() != mtpc_inputPeerSelf);
int32 flags = (histPeer->input.type() != mtpc_inputPeerSelf) ? (MTPDmessage_flag_out | MTPDmessage_flag_unread) : 0;
int32 flags = newMessageFlags(histPeer); // unread, out
int32 sendFlags = 0;
if (_replyToId) {
flags |= MTPDmessage::flag_reply_to_msg_id;
@ -3903,7 +3898,7 @@ void HistoryWidget::onStickerSend(DocumentData *sticker) {
}
hist->addToBackDocument(newId, flags, _replyToId, date(MTP_int(unixtime())), MTP::authedId(), sticker);
hist->sendRequestId = MTP::send(MTPmessages_SendMedia(MTP_int(sendFlags), histPeer->input, MTP_int(_replyToId), MTP_inputMediaDocument(MTP_inputDocument(MTP_long(sticker->id), MTP_long(sticker->access))), MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), RPCFailHandlerPtr(), 0, 0, hist->sendRequestId);
hist->sendRequestId = MTP::send(MTPmessages_SendMedia(MTP_int(sendFlags), histPeer->input, MTP_int(_replyToId), MTP_inputMediaDocument(MTP_inputDocument(MTP_long(sticker->id), MTP_long(sticker->access))), MTP_long(randomId), MTPnullMarkup), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), RPCFailHandlerPtr(), 0, 0, hist->sendRequestId);
App::main()->finishForwarding(hist);
cancelReply();

View File

@ -202,7 +202,7 @@ void IntroCode::codeSubmitDone(const MTPauth_Authorization &result) {
stopCheck();
code.setDisabled(false);
const MTPDauth_authorization &d(result.c_auth_authorization());
if (d.vuser.type() != mtpc_userSelf) { // wtf?
if (d.vuser.type() != mtpc_user || !(d.vuser.c_user().vflags.v & MTPDuser_flag_self)) { // wtf?
showError(lang(lng_server_error));
return;
}

View File

@ -181,7 +181,7 @@ void IntroPwdCheck::pwdSubmitDone(bool recover, const MTPauth_Authorization &res
_pwdField.setDisabled(false);
_codeField.setDisabled(false);
const MTPDauth_authorization &d(result.c_auth_authorization());
if (d.vuser.type() != mtpc_userSelf) { // wtf?
if (d.vuser.type() != mtpc_user || !(d.vuser.c_user().vflags.v & MTPDuser_flag_self)) { // wtf?
showError(lang(lng_server_error));
return;
}

View File

@ -216,7 +216,7 @@ void IntroSignup::nameSubmitDone(const MTPauth_Authorization &result) {
first.setDisabled(false);
last.setDisabled(false);
const MTPDauth_authorization &d(result.c_auth_authorization());
if (d.vuser.type() != mtpc_userSelf) { // wtf?
if (d.vuser.type() != mtpc_user || !(d.vuser.c_user().vflags.v & MTPDuser_flag_self)) { // wtf?
showError(lang(lng_server_error));
return;
}

View File

@ -609,13 +609,22 @@ namespace {
mtpDcOptions *_dcOpts = 0;
bool _readSetting(quint32 blockId, QDataStream &stream, int version) {
switch (blockId) {
case dbiDcOption: {
case dbiDcOptionOld: {
quint32 dcId, port;
QString host, ip;
stream >> dcId >> host >> ip >> port;
if (!_checkStreamStatus(stream)) return false;
if (_dcOpts) _dcOpts->insert(dcId, mtpDcOption(dcId, host.toUtf8().constData(), ip.toUtf8().constData(), port));
if (_dcOpts) _dcOpts->insert(dcId, mtpDcOption(dcId, 0, ip.toUtf8().constData(), port));
} break;
case dbiDcOption: {
quint32 dcIdWithShift, flags, port;
QString ip;
stream >> dcIdWithShift >> flags >> ip >> port;
if (!_checkStreamStatus(stream)) return false;
if (_dcOpts) _dcOpts->insert(dcIdWithShift, mtpDcOption(dcIdWithShift % _mtp_internal::dcShift, flags, ip.toUtf8().constData(), port));
} break;
case dbiMaxGroupCount: {
@ -1723,9 +1732,16 @@ namespace Local {
if (dcOpts.isEmpty()) {
const BuiltInDc *bdcs = builtInDcs();
for (int i = 0, l = builtInDcsCount(); i < l; ++i) {
dcOpts.insert(bdcs[i].id, mtpDcOption(bdcs[i].id, "", bdcs[i].ip, bdcs[i].port));
dcOpts.insert(bdcs[i].id, mtpDcOption(bdcs[i].id, 0, bdcs[i].ip, bdcs[i].port));
DEBUG_LOG(("MTP Info: adding built in DC %1 connect option: %2:%3").arg(bdcs[i].id).arg(bdcs[i].ip).arg(bdcs[i].port));
}
const BuiltInDc *bdcsipv6 = builtInDcsIPv6();
for (int i = 0, l = builtInDcsCountIPv6(); i < l; ++i) {
int32 flags = MTPDdcOption_flag_ipv6, idWithShift = bdcsipv6[i].id + (flags * _mtp_internal::dcShift);
dcOpts.insert(idWithShift, mtpDcOption(bdcsipv6[i].id, flags, bdcsipv6[i].ip, bdcsipv6[i].port));
DEBUG_LOG(("MTP Info: adding built in DC %1 IPv6 connect option: %2:%3").arg(bdcsipv6[i].id).arg(bdcsipv6[i].ip).arg(bdcsipv6[i].port));
}
}
{
QWriteLocker lock(MTP::dcOptionsMutex());
@ -1759,10 +1775,16 @@ namespace Local {
if (dcOpts.isEmpty()) {
const BuiltInDc *bdcs = builtInDcs();
for (int i = 0, l = builtInDcsCount(); i < l; ++i) {
dcOpts.insert(bdcs[i].id, mtpDcOption(bdcs[i].id, "", bdcs[i].ip, bdcs[i].port));
dcOpts.insert(bdcs[i].id, mtpDcOption(bdcs[i].id, 0, bdcs[i].ip, bdcs[i].port));
DEBUG_LOG(("MTP Info: adding built in DC %1 connect option: %2:%3").arg(bdcs[i].id).arg(bdcs[i].ip).arg(bdcs[i].port));
}
const BuiltInDc *bdcsipv6 = builtInDcsIPv6();
for (int i = 0, l = builtInDcsCountIPv6(); i < l; ++i) {
dcOpts.insert(bdcsipv6[i].id + (MTPDdcOption_flag_ipv6 * _mtp_internal::dcShift), mtpDcOption(bdcsipv6[i].id, MTPDdcOption_flag_ipv6, bdcsipv6[i].ip, bdcsipv6[i].port));
DEBUG_LOG(("MTP Info: adding built in DC %1 IPv6 connect option: %2:%3").arg(bdcsipv6[i].id).arg(bdcsipv6[i].ip).arg(bdcsipv6[i].port));
}
QWriteLocker lock(MTP::dcOptionsMutex());
cSetDcOptions(dcOpts);
}
@ -1770,7 +1792,7 @@ namespace Local {
quint32 size = 10 * (sizeof(quint32) + sizeof(qint32));
for (mtpDcOptions::const_iterator i = dcOpts.cbegin(), e = dcOpts.cend(); i != e; ++i) {
size += sizeof(quint32) + sizeof(quint32) + sizeof(quint32);
size += _stringSize(QString::fromUtf8(i->host.data(), i->host.size())) + _stringSize(QString::fromUtf8(i->ip.data(), i->ip.size()));
size += sizeof(quint32) + _stringSize(QString::fromUtf8(i->ip.data(), i->ip.size()));
}
size += sizeof(quint32) + _stringSize(cLangFile());
@ -1794,8 +1816,8 @@ namespace Local {
data.stream << quint32(dbiScale) << qint32(cConfigScale());
data.stream << quint32(dbiLang) << qint32(cLang());
for (mtpDcOptions::const_iterator i = dcOpts.cbegin(), e = dcOpts.cend(); i != e; ++i) {
data.stream << quint32(dbiDcOption) << quint32(i->id);
data.stream << QString::fromUtf8(i->host.data(), i->host.size()) << QString::fromUtf8(i->ip.data(), i->ip.size());
data.stream << quint32(dbiDcOption) << quint32(i.key());
data.stream << quint32(i->flags) << QString::fromUtf8(i->ip.data(), i->ip.size());
data.stream << quint32(i->port);
}
data.stream << quint32(dbiLangFile) << cLangFile();

View File

@ -494,9 +494,13 @@ void MainWidget::finishForwarding(History *hist) {
if (_toForward.size() < 2) {
uint64 randomId = MTP::nonce<uint64>();
MsgId newId = clientMsgId();
hist->addToBackForwarded(newId, static_cast<HistoryMessage*>(_toForward.cbegin().value()));
HistoryMessage *msg = static_cast<HistoryMessage*>(_toForward.cbegin().value());
hist->addToBackForwarded(newId, msg);
App::historyRegRandom(randomId, newId);
hist->sendRequestId = MTP::send(MTPmessages_ForwardMessage(hist->peer->input, MTP_int(_toForward.cbegin().key()), MTP_long(randomId)), rpcDone(&MainWidget::sentUpdatesReceived), RPCFailHandlerPtr(), 0, 0, hist->sendRequestId);
if (HistorySticker *sticker = dynamic_cast<HistorySticker*>(msg->getMedia())) {
App::main()->incrementSticker(sticker->document());
}
} else {
QVector<MTPint> ids;
QVector<MTPlong> randomIds;
@ -940,7 +944,7 @@ void MainWidget::sendPreparedText(History *hist, const QString &text, MsgId repl
App::historyRegRandom(randomId, newId);
MTPstring msgText(MTP_string(sendingText));
int32 flags = (hist->peer->input.type() == mtpc_inputPeerSelf) ? 0 : (MTPDmessage_flag_unread | MTPDmessage_flag_out);
int32 flags = newMessageFlags(hist->peer); // unread, out
int32 sendFlags = 0;
if (replyTo) {
flags |= MTPDmessage::flag_reply_to_msg_id;
@ -953,8 +957,8 @@ void MainWidget::sendPreparedText(History *hist, const QString &text, MsgId repl
WebPageData *page = App::webPage(webPageId);
media = MTP_messageMediaWebPage(MTP_webPagePending(MTP_long(page->id), MTP_int(page->pendingTill)));
}
hist->addToBack(MTP_message(MTP_int(flags), MTP_int(newId), MTP_int(MTP::authedId()), App::peerToMTP(hist->peer->id), MTPint(), MTPint(), MTP_int(replyTo), MTP_int(unixtime()), msgText, media));
hist->sendRequestId = MTP::send(MTPmessages_SendMessage(MTP_int(sendFlags), hist->peer->input, MTP_int(replyTo), msgText, MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentDataReceived, randomId), RPCFailHandlerPtr(), 0, 0, hist->sendRequestId);
hist->addToBack(MTP_message(MTP_int(flags), MTP_int(newId), MTP_int(MTP::authedId()), App::peerToMTP(hist->peer->id), MTPint(), MTPint(), MTP_int(replyTo), MTP_int(unixtime()), msgText, media, MTPnullMarkup));
hist->sendRequestId = MTP::send(MTPmessages_SendMessage(MTP_int(sendFlags), hist->peer->input, MTP_int(replyTo), msgText, MTP_long(randomId), MTPnullMarkup), App::main()->rpcDone(&MainWidget::sentDataReceived, randomId), RPCFailHandlerPtr(), 0, 0, hist->sendRequestId);
}
finishForwarding(hist);
@ -1575,7 +1579,7 @@ void MainWidget::serviceNotification(const QString &msg, const MTPMessageMedia &
QString sendingText, leftText = msg;
HistoryItem *item = 0;
while (textSplit(sendingText, leftText, MaxMessageSize)) {
item = App::histories().addToBack(MTP_message(MTP_int(flags), MTP_int(clientMsgId()), MTP_int(ServiceUserId), MTP_peerUser(MTP_int(MTP::authedId())), MTPint(), MTPint(), MTPint(), MTP_int(unixtime()), MTP_string(sendingText), media), unread ? 1 : 2);
item = App::histories().addToBack(MTP_message(MTP_int(flags), MTP_int(clientMsgId()), MTP_int(ServiceUserId), MTP_peerUser(MTP_int(MTP::authedId())), MTPint(), MTPint(), MTPint(), MTP_int(unixtime()), MTP_string(sendingText), media, MTPnullMarkup), unread ? 1 : 2);
}
if (item) {
history.peerMessagesUpdated(item->history()->peer->id);
@ -2491,7 +2495,7 @@ void MainWidget::mtpPing() {
}
void MainWidget::start(const MTPUser &user) {
int32 uid = user.c_userSelf().vid.v;
int32 uid = user.c_user().vid.v;
if (MTP::authedId() != uid) {
MTP::authed(uid);
Local::writeMtpData();
@ -2666,7 +2670,7 @@ bool MainWidget::inviteImportFail(const RPCError &error) {
void MainWidget::startFull(const MTPVector<MTPUser> &users) {
const QVector<MTPUser> &v(users.c_vector().v);
if (v.isEmpty() || v[0].type() != mtpc_userSelf) { // wtf?..
if (v.isEmpty() || v[0].type() != mtpc_user || !(v[0].c_user().vflags.v & MTPDuser_flag_self)) { // wtf?..
return App::logOut();
}
start(v[0]);
@ -3054,7 +3058,7 @@ void MainWidget::handleUpdates(const MTPUpdates &updates) {
return;
}
bool out = (d.vflags.v & MTPDmessage_flag_out);
HistoryItem *item = App::histories().addToBack(MTP_message(d.vflags, d.vid, out ? MTP_int(MTP::authedId()) : d.vuser_id, MTP_peerUser(out ? d.vuser_id : MTP_int(MTP::authedId())), d.vfwd_from_id, d.vfwd_date, d.vreply_to_msg_id, d.vdate, d.vmessage, MTP_messageMediaEmpty()));
HistoryItem *item = App::histories().addToBack(MTP_message(d.vflags, d.vid, out ? MTP_int(MTP::authedId()) : d.vuser_id, MTP_peerUser(out ? d.vuser_id : MTP_int(MTP::authedId())), d.vfwd_from_id, d.vfwd_date, d.vreply_to_msg_id, d.vdate, d.vmessage, MTP_messageMediaEmpty(), MTPnullMarkup));
if (item) {
history.peerMessagesUpdated(item->history()->peer->id);
}
@ -3074,7 +3078,7 @@ void MainWidget::handleUpdates(const MTPUpdates &updates) {
_byPtsUpdates.insert(ptsKey(SkippedUpdates), updates);
return;
}
HistoryItem *item = App::histories().addToBack(MTP_message(d.vflags, d.vid, d.vfrom_id, MTP_peerChat(d.vchat_id), d.vfwd_from_id, d.vfwd_date, d.vreply_to_msg_id, d.vdate, d.vmessage, MTP_messageMediaEmpty()));
HistoryItem *item = App::histories().addToBack(MTP_message(d.vflags, d.vid, d.vfrom_id, MTP_peerChat(d.vchat_id), d.vfwd_from_id, d.vfwd_date, d.vreply_to_msg_id, d.vdate, d.vmessage, MTP_messageMediaEmpty(), MTPnullMarkup));
if (item) {
history.peerMessagesUpdated(item->history()->peer->id);
}

View File

@ -743,8 +743,9 @@ void MTPautoConnection::disconnectFromServer() {
status = FinishedWork;
}
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
void MTPautoConnection::connectToServer(const QString &addr, int32 port, int32 flags) {
address = QUrl(((flags & MTPDdcOption_flag_ipv6) ? qsl("http://[%1]:%2/api") : qsl("http://%1:%2/api")).arg(addr).arg(80));//not p - always 80 port for http transport
TCP_LOG(("HTTP Info: address is %1").arg(address.toDisplayString()));
connect(&manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestFinished(QNetworkReply*)));
_addr = addr;
@ -943,7 +944,7 @@ void MTPtcpConnection::disconnectFromServer() {
sock.close();
}
void MTPtcpConnection::connectToServer(const QString &addr, int32 port) {
void MTPtcpConnection::connectToServer(const QString &addr, int32 port, int32 flags) {
connect(&sock, SIGNAL(readyRead()), this, SLOT(socketRead()));
sock.connectToHost(QHostAddress(addr), port);
}
@ -1013,8 +1014,9 @@ void MTPhttpConnection::disconnectFromServer() {
address = QUrl();
}
void MTPhttpConnection::connectToServer(const QString &addr, int32 p) {
address = QUrl(qsl("http://%1:%2/api").arg(addr).arg(80));//not p - always 80 port for http transport
void MTPhttpConnection::connectToServer(const QString &addr, int32 p, int32 flags) {
address = QUrl(((flags & MTPDdcOption_flag_ipv6) ? qsl("http://[%1]:%2/api") : qsl("http://%1:%2/api")).arg(addr).arg(80));//not p - always 80 port for http transport
TCP_LOG(("HTTP Info: address is %1").arg(address.toDisplayString()));
connect(&manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestFinished(QNetworkReply*)));
emit connected();
}
@ -1062,19 +1064,30 @@ QString MTPhttpConnection::transport() const {
return qsl("HTTP");
}
void MTProtoConnectionPrivate::createConn() {
if (conn) {
conn->deleteLater();
void MTProtoConnectionPrivate::createConn(bool createIPv4, bool createIPv6) {
destroyConn();
if (createIPv4) {
if (cConnectionType() == dbictAuto) {
_conn4 = new MTPautoConnection(thread());
} else if (cConnectionType() == dbictTcpProxy) {
_conn4 = new MTPtcpConnection(thread());
} else {
_conn4 = new MTPhttpConnection(thread());
}
connect(_conn4, SIGNAL(error(bool)), this, SLOT(onError4(bool)));
connect(_conn4, SIGNAL(receivedSome()), this, SLOT(onReceivedSome()));
}
if (cConnectionType() == dbictAuto) {
conn = new MTPautoConnection(thread());
} else if (cConnectionType() == dbictTcpProxy) {
conn = new MTPtcpConnection(thread());
} else {
conn = new MTPhttpConnection(thread());
if (createIPv6) {
if (cConnectionType() == dbictAuto) {
_conn6 = new MTPautoConnection(thread());
} else if (cConnectionType() == dbictTcpProxy) {
_conn6 = new MTPtcpConnection(thread());
} else {
_conn6 = new MTPhttpConnection(thread());
}
connect(_conn6, SIGNAL(error(bool)), this, SLOT(onError6(bool)));
connect(_conn6, SIGNAL(receivedSome()), this, SLOT(onReceivedSome()));
}
connect(conn, SIGNAL(error(bool)), this, SLOT(onError(bool)));
connect(conn, SIGNAL(receivedSome()), this, SLOT(onReceivedSome()));
firstSentAt = 0;
if (oldConnection) {
oldConnection = false;
@ -1083,17 +1096,35 @@ void MTProtoConnectionPrivate::createConn() {
oldConnectionTimer.start(MTPConnectionOldTimeout);
}
void MTProtoConnectionPrivate::destroyConn(MTPabstractConnection **conn) {
if (conn) {
if (*conn) {
disconnect(*conn, SIGNAL(disconnected()), 0, 0);
disconnect(*conn, SIGNAL(receivedData()), 0, 0);
disconnect(*conn, SIGNAL(receivedSome()), 0, 0);
(*conn)->disconnectFromServer();
(*conn)->deleteLater();
*conn = 0;
}
} else {
destroyConn(&_conn4);
destroyConn(&_conn6);
_conn = 0;
}
}
MTProtoConnectionPrivate::MTProtoConnectionPrivate(QThread *thread, MTProtoConnection *owner, MTPSessionData *data, uint32 _dc)
: QObject(0)
, _state(MTProtoConnection::Disconnected)
, _needSessionReset(false)
, dc(_dc)
, _owner(owner)
, conn(0)
, _conn(0), _conn4(0), _conn6(0)
, retryTimeout(1)
, oldConnection(true)
, receiveDelay(MTPMinReceiveDelay)
, connectDelay(MTPMinConnectDelay)
, _waitForReceived(MTPMinReceiveDelay)
, _waitForConnected(MTPMinConnectDelay)
, firstSentAt(-1)
, _pingId(0)
, _pingIdToSend(0)
@ -1107,14 +1138,13 @@ MTProtoConnectionPrivate::MTProtoConnectionPrivate(QThread *thread, MTProtoConne
, authKeyStrings(0) {
oldConnectionTimer.moveToThread(thread);
cantConnectTimer.moveToThread(thread);
connCheckTimer.moveToThread(thread);
_waitForConnectedTimer.moveToThread(thread);
_waitForReceivedTimer.moveToThread(thread);
_waitForIPv4Timer.moveToThread(thread);
_pingSender.moveToThread(thread);
retryTimer.moveToThread(thread);
moveToThread(thread);
// createConn();
if (!dc) {
QReadLocker lock(mtpDcOptionsMutex());
const mtpDcOptions &options(cDcOptions());
@ -1131,8 +1161,9 @@ MTProtoConnectionPrivate::MTProtoConnectionPrivate(QThread *thread, MTProtoConne
connect(thread, SIGNAL(finished()), this, SLOT(doFinish()));
connect(&retryTimer, SIGNAL(timeout()), this, SLOT(retryByTimer()));
connect(&connCheckTimer, SIGNAL(timeout()), this, SLOT(onBadConnection()));
connect(&cantConnectTimer, SIGNAL(timeout()), this, SLOT(onCantConnect()));
connect(&_waitForConnectedTimer, SIGNAL(timeout()), this, SLOT(onWaitConnectedFailed()));
connect(&_waitForReceivedTimer, SIGNAL(timeout()), this, SLOT(onWaitReceivedFailed()));
connect(&_waitForIPv4Timer, SIGNAL(timeout()), this, SLOT(onWaitIPv4Failed()));
connect(&oldConnectionTimer, SIGNAL(timeout()), this, SLOT(onOldConnection()));
connect(&_pingSender, SIGNAL(timeout()), this, SLOT(onPingSender()));
connect(sessionData->owner(), SIGNAL(authKeyCreated()), this, SLOT(updateAuthKey()), Qt::QueuedConnection);
@ -1183,10 +1214,10 @@ int32 MTProtoConnectionPrivate::getState() const {
}
QString MTProtoConnectionPrivate::transport() const {
if (!conn || _state < 0) {
if ((!_conn4 && !_conn6) || _state < 0) {
return QString();
}
return conn->transport();
return (_conn4 ? _conn4 : _conn6)->transport();
}
bool MTProtoConnectionPrivate::setState(int32 state, int32 ifState) {
@ -1421,7 +1452,7 @@ mtpMsgId MTProtoConnectionPrivate::placeToContainer(mtpRequest &toSendRequest, m
void MTProtoConnectionPrivate::tryToSend() {
QReadLocker lockFinished(&sessionDataMutex);
if (!sessionData || !conn) {
if (!sessionData || !_conn) {
return;
}
@ -1513,7 +1544,7 @@ void MTProtoConnectionPrivate::tryToSend() {
stateRequest->msDate = getms(true); // > 0 - can send without container
stateRequest->requestId = reqid();// add to haveSent / wereAcked maps, but don't add to requestMap
}
if (conn->usingHttpWait()) {
if (_conn->usingHttpWait()) {
MTPHttpWait req(MTP_http_wait(MTP_int(100), MTP_int(30), MTP_int(25000)));
httpWaitRequest = mtpRequestData::prepare(req.innerLength() >> 2);
@ -1734,47 +1765,63 @@ void MTProtoConnectionPrivate::restartNow() {
}
void MTProtoConnectionPrivate::socketStart(bool afterConfig) {
if (!conn) createConn();
retryTimer.stop();
cantConnectTimer.stop();
if (conn->isConnected()) {
onConnected();
return;
}
setState(MTProtoConnection::Connecting);
_pingId = _pingMsgId = _pingIdToSend = _pingSendAt = 0;
_pingSender.stop();
std::string ip;
uint32 port = 0;
int32 flags4 = 0, flags6 = 0;
std::string ip4, ip6;
uint32 port4 = 0, port6 = 0;
{
QReadLocker lock(mtpDcOptionsMutex());
const mtpDcOptions &options(cDcOptions());
mtpDcOptions::const_iterator dcIndex = options.constFind(dc % _mtp_internal::dcShift);
DEBUG_LOG(("MTP Info: connecting to DC %1..").arg(dc));
if (dcIndex != options.cend()) {
ip = dcIndex->ip;
port = dcIndex->port;
mtpDcOptions::const_iterator dcIndex4 = options.constFind(dc % _mtp_internal::dcShift);
if (dcIndex4 != options.cend()) {
ip4 = dcIndex4->ip;
flags4 = dcIndex4->flags;
port4 = dcIndex4->port;
}
mtpDcOptions::const_iterator dcIndex6 = options.constFind((dc % _mtp_internal::dcShift) + (_mtp_internal::dcShift * MTPDdcOption_flag_ipv6));
if (dcIndex6 != options.cend()) {
ip6 = dcIndex6->ip;
flags6 = dcIndex6->flags;
port6 = dcIndex6->port;
}
}
if (!port || ip.empty()) {
bool noIPv4 = (!port4 || ip4.empty()), noIPv6 = (!port6 || ip6.empty());
if (noIPv4 && noIPv6) {
if (afterConfig) {
LOG(("MTP Error: DC %1 options not found right after config load!").arg(dc));
if (noIPv4) LOG(("MTP Error: DC %1 options for IPv4 not found right after config load!").arg(dc));
if (noIPv6) LOG(("MTP Error: DC %1 options for IPv6 not found right after config load!").arg(dc));
return restart();
}
DEBUG_LOG(("MTP Info: DC %1 options not found, waiting for config").arg(dc));
if (noIPv4) DEBUG_LOG(("MTP Info: DC %1 options for IPv4 not found, waiting for config").arg(dc));
if (noIPv6) DEBUG_LOG(("MTP Info: DC %1 options for IPv6 not found, waiting for config").arg(dc));
connect(mtpConfigLoader(), SIGNAL(loaded()), this, SLOT(onConfigLoaded()));
mtpConfigLoader()->load();
return;
}
DEBUG_LOG(("MTP Info: socket connection to %1:%2..").arg(ip.c_str()).arg(port));
connect(conn, SIGNAL(connected()), this, SLOT(onConnected()));
connect(conn, SIGNAL(disconnected()), this, SLOT(restart()));
if (afterConfig && (_conn4 || _conn6)) return;
cantConnectTimer.start(connectDelay);
conn->connectToServer(ip.c_str(), port);
createConn(!noIPv4, !noIPv6);
retryTimer.stop();
_waitForConnectedTimer.stop();
setState(MTProtoConnection::Connecting);
_pingId = _pingMsgId = _pingIdToSend = _pingSendAt = 0;
_pingSender.stop();
if (!noIPv4) DEBUG_LOG(("MTP Info: creating IPv4 connection to %1:%2..").arg(ip4.c_str()).arg(port4));
if (!noIPv6) DEBUG_LOG(("MTP Info: creating IPv6 connection to [%1]:%2..").arg(ip6.c_str()).arg(port6));
_waitForConnectedTimer.start(_waitForConnected);
if (_conn4) {
connect(_conn4, SIGNAL(connected()), this, SLOT(onConnected4()));
connect(_conn4, SIGNAL(disconnected()), this, SLOT(onDisconnected4()));
_conn4->connectToServer(ip4.c_str(), port4, flags4);
}
if (_conn6) {
connect(_conn6, SIGNAL(connected()), this, SLOT(onConnected6()));
connect(_conn6, SIGNAL(disconnected()), this, SLOT(onDisconnected6()));
_conn6->connectToServer(ip6.c_str(), port6, flags6);
}
}
void MTProtoConnectionPrivate::restart(bool maybeBadKey) {
@ -1783,8 +1830,8 @@ void MTProtoConnectionPrivate::restart(bool maybeBadKey) {
DEBUG_LOG(("MTP Info: restarting MTProtoConnection, maybe bad key = %1").arg(logBool(maybeBadKey)));
connCheckTimer.stop();
cantConnectTimer.stop();
_waitForReceivedTimer.stop();
_waitForConnectedTimer.stop();
mtpAuthKeyPtr key(sessionData->getKey());
if (key) {
@ -1812,12 +1859,12 @@ void MTProtoConnectionPrivate::restart(bool maybeBadKey) {
}
void MTProtoConnectionPrivate::onSentSome(uint64 size) {
if (!connCheckTimer.isActive()) {
uint64 remain = receiveDelay;
if (!_waitForReceivedTimer.isActive()) {
uint64 remain = _waitForReceived;
if (!oldConnection) {
uint64 remainBySize = size * receiveDelay / 8192; // 8kb / sec, so 512 kb give 64 sec
uint64 remainBySize = size * _waitForReceived / 8192; // 8kb / sec, so 512 kb give 64 sec
remain = snap(remainBySize, remain, uint64(MTPMaxReceiveDelay));
if (remain != receiveDelay) {
if (remain != _waitForReceived) {
DEBUG_LOG(("Checking connect for request with size %1 bytes, delay will be %2").arg(size).arg(remain));
}
}
@ -1826,7 +1873,7 @@ void MTProtoConnectionPrivate::onSentSome(uint64 size) {
} else if (dc >= MTP::dld[0] && dc < MTP::dld[MTPDownloadSessionsCount - 1] + _mtp_internal::dcShift) {
remain *= MTPDownloadSessionsCount;
}
connCheckTimer.start(remain);
_waitForReceivedTimer.start(remain);
}
if (!firstSentAt) firstSentAt = getms(true);
}
@ -1837,20 +1884,20 @@ void MTProtoConnectionPrivate::onReceivedSome() {
DEBUG_LOG(("This connection marked as not old!"));
}
oldConnectionTimer.start(MTPConnectionOldTimeout);
connCheckTimer.stop();
_waitForReceivedTimer.stop();
if (firstSentAt > 0) {
int32 ms = getms(true) - firstSentAt;
DEBUG_LOG(("MTP Info: response in %1ms, receiveDelay: %2ms").arg(ms).arg(receiveDelay));
DEBUG_LOG(("MTP Info: response in %1ms, _waitForReceived: %2ms").arg(ms).arg(_waitForReceived));
if (ms > 0 && ms * 2 < int32(receiveDelay)) receiveDelay = qMax(ms * 2, int32(MTPMinReceiveDelay));
if (ms > 0 && ms * 2 < int32(_waitForReceived)) _waitForReceived = qMax(ms * 2, int32(MTPMinReceiveDelay));
firstSentAt = -1;
}
}
void MTProtoConnectionPrivate::onOldConnection() {
oldConnection = true;
receiveDelay = MTPMinReceiveDelay;
DEBUG_LOG(("This connection marked as old! delay now %1ms").arg(receiveDelay));
_waitForReceived = MTPMinReceiveDelay;
DEBUG_LOG(("This connection marked as old! _waitForReceived now %1ms").arg(_waitForReceived));
}
void MTProtoConnectionPrivate::onPingSender() {
@ -1874,14 +1921,14 @@ void MTProtoConnectionPrivate::onPingSendForce() {
}
}
void MTProtoConnectionPrivate::onBadConnection() {
void MTProtoConnectionPrivate::onWaitReceivedFailed() {
if (cConnectionType() != dbictAuto && cConnectionType() != dbictTcpProxy) {
return;
}
DEBUG_LOG(("MTP Info: bad connection, delay: %1ms").arg(receiveDelay));
if (receiveDelay < MTPMaxReceiveDelay) {
receiveDelay *= 2;
DEBUG_LOG(("MTP Info: bad connection, _waitForReceived: %1ms").arg(_waitForReceived));
if (_waitForReceived < MTPMaxReceiveDelay) {
_waitForReceived *= 2;
}
doDisconnect();
restarted = true;
@ -1891,9 +1938,9 @@ void MTProtoConnectionPrivate::onBadConnection() {
QTimer::singleShot(0, this, SLOT(socketStart()));
}
void MTProtoConnectionPrivate::onCantConnect() {
DEBUG_LOG(("MTP Info: can't connect in %1ms").arg(connectDelay));
if (connectDelay < MTPMaxConnectDelay) connectDelay *= 2;
void MTProtoConnectionPrivate::onWaitConnectedFailed() {
DEBUG_LOG(("MTP Info: can't connect in %1ms").arg(_waitForConnected));
if (_waitForConnected < MTPMaxConnectDelay) _waitForConnected *= 2;
doDisconnect();
restarted = true;
@ -1902,16 +1949,21 @@ void MTProtoConnectionPrivate::onCantConnect() {
QTimer::singleShot(0, this, SLOT(socketStart()));
}
void MTProtoConnectionPrivate::doDisconnect() {
if (conn) {
disconnect(conn, SIGNAL(disconnected()), 0, 0);
disconnect(conn, SIGNAL(receivedData()), 0, 0);
disconnect(conn, SIGNAL(receivedSome()), 0, 0);
void MTProtoConnectionPrivate::onWaitIPv4Failed() {
_conn = _conn6;
destroyConn(&_conn4);
if (_conn) {
DEBUG_LOG(("MTP Info: can't connect through IPv4, using IPv6 connection."));
conn->disconnectFromServer();
conn->deleteLater();
conn = 0;
updateAuthKey();
} else {
restart();
}
}
void MTProtoConnectionPrivate::doDisconnect() {
destroyConn();
unlockKey();
@ -1946,9 +1998,8 @@ void MTProtoConnectionPrivate::handleReceived() {
return restart();
}
while (conn->received().size()) {
const mtpBuffer &encryptedBuf(conn->received().front());
while (_conn->received().size()) {
const mtpBuffer &encryptedBuf(_conn->received().front());
uint32 len = encryptedBuf.size();
const mtpPrime *encrypted(encryptedBuf.data());
if (len < 18) { // 2 auth_key_id, 4 msg_key, 2 salt, 2 session, 2 msg_id, 1 seq_no, 1 length, (1 data + 3 padding) min
@ -1976,14 +2027,14 @@ void MTProtoConnectionPrivate::handleReceived() {
if (uint32(dataBuffer.size()) < msgLen + 8 * sizeof(mtpPrime) || (msgLen & 0x03)) {
LOG(("TCP Error: bad msg_len received %1, data size: %2").arg(msgLen).arg(dataBuffer.size()));
TCP_LOG(("TCP Error: bad message %1").arg(mb(encrypted, len * sizeof(mtpPrime)).str()));
conn->received().pop_front();
_conn->received().pop_front();
return restart();
}
uchar sha1Buffer[20];
if (memcmp(&msgKey, hashSha1(data, msgLen + 8 * sizeof(mtpPrime), sha1Buffer) + 1, sizeof(msgKey))) {
LOG(("TCP Error: bad SHA1 hash after aesDecrypt in message"));
TCP_LOG(("TCP Error: bad message %1").arg(mb(encrypted, len * sizeof(mtpPrime)).str()));
conn->received().pop_front();
_conn->received().pop_front();
return restart();
}
TCP_LOG(("TCP Info: decrypted message %1,%2,%3 is %4 len").arg(msgId).arg(seqNo).arg(logBool(needAck)).arg(msgLen + 8 * sizeof(mtpPrime)));
@ -1992,11 +2043,11 @@ void MTProtoConnectionPrivate::handleReceived() {
if (session != serverSession) {
LOG(("MTP Error: bad server session received"));
TCP_LOG(("MTP Error: bad server session %1 instead of %2 in message received").arg(session).arg(serverSession));
conn->received().pop_front();
_conn->received().pop_front();
return restart();
}
conn->received().pop_front();
_conn->received().pop_front();
int32 serverTime((int32)(msgId >> 32)), clientTime(unixtime());
bool isReply = ((msgId & 0x03) == 1);
@ -2079,6 +2130,7 @@ void MTProtoConnectionPrivate::handleReceived() {
_needSessionReset = (res < -1);
return restart();
}
retryTimeout = 1; // reset restart() timer
if (!sessionData->isCheckedKey()) {
DEBUG_LOG(("MTP Info: marked auth key as checked"));
@ -2091,7 +2143,7 @@ void MTProtoConnectionPrivate::handleReceived() {
}
}
}
if (conn->needHttpWait()) {
if (_conn->needHttpWait()) {
emit sendHttpWaitAsync();
}
}
@ -2588,8 +2640,6 @@ int32 MTProtoConnectionPrivate::handleOneReceived(const mtpPrime *from, const mt
}
}
requestsAcked(ids, true);
retryTimeout = 1; // reset restart() timer
} return 1;
}
@ -2836,27 +2886,72 @@ void MTProtoConnectionPrivate::resendMany(QVector<quint64> msgIds, quint64 msCan
emit resendManyAsync(msgIds, msCanWait, forceContainer, sendMsgStateInfo);
}
void MTProtoConnectionPrivate::onConnected() {
connectDelay = MTPMinConnectDelay;
cantConnectTimer.stop();
void MTProtoConnectionPrivate::onConnected4() {
_waitForConnected = MTPMinConnectDelay;
_waitForConnectedTimer.stop();
_waitForIPv4Timer.stop();
QReadLocker lockFinished(&sessionDataMutex);
if (!sessionData) return;
disconnect(conn, SIGNAL(connected()), this, SLOT(onConnected()));
if (!conn->isConnected()) {
LOG(("Connection Error: not connected in onConnected(), state: %1").arg(conn->debugState()));
disconnect(_conn4, SIGNAL(connected()), this, SLOT(onConnected4()));
if (!_conn4->isConnected()) {
LOG(("Connection Error: not connected in onConnected4(), state: %1").arg(_conn4->debugState()));
return restart();
}
TCP_LOG(("Connection Info: connection succeed."));
_conn = _conn4;
destroyConn(&_conn6);
DEBUG_LOG(("MTP Info: connection through IPv4 succeed."));
updateAuthKey();
}
void MTProtoConnectionPrivate::onConnected6() {
_waitForConnected = MTPMinConnectDelay;
_waitForConnectedTimer.stop();
QReadLocker lockFinished(&sessionDataMutex);
if (!sessionData) return;
disconnect(_conn6, SIGNAL(connected()), this, SLOT(onConnected()));
if (!_conn6->isConnected()) {
LOG(("Connection Error: not connected in onConnected(), state: %1").arg(_conn6->debugState()));
return restart();
}
DEBUG_LOG(("MTP Info: connection through IPv6 succeed, waiting IPv4 for %1ms.").arg(MTPIPv4ConnectionWaitTimeout));
_waitForIPv4Timer.start(MTPIPv4ConnectionWaitTimeout);
}
void MTProtoConnectionPrivate::onDisconnected4() {
if (_conn && _conn == _conn6) return; // disconnected the unused
if (_conn || !_conn6) {
destroyConn();
restart();
} else {
destroyConn(&_conn4);
}
}
void MTProtoConnectionPrivate::onDisconnected6() {
if (_conn && _conn == _conn4) return; // disconnected the unused
if (_conn || !_conn4) {
destroyConn();
restart();
} else {
destroyConn(&_conn6);
}
}
void MTProtoConnectionPrivate::updateAuthKey() {
QReadLocker lockFinished(&sessionDataMutex);
if (!sessionData || !conn) return;
if (!sessionData || !_conn) return;
DEBUG_LOG(("AuthKey Info: MTProtoConnection updating key from MTProtoSession, dc %1").arg(dc));
uint64 newKeyId = 0;
@ -2899,20 +2994,20 @@ void MTProtoConnectionPrivate::updateAuthKey() {
MTPReq_pq req_pq;
req_pq.vnonce = authKeyData->nonce;
connect(conn, SIGNAL(receivedData()), this, SLOT(pqAnswered()));
connect(_conn, SIGNAL(receivedData()), this, SLOT(pqAnswered()));
DEBUG_LOG(("AuthKey Info: sending Req_pq.."));
sendRequestNotSecure(req_pq);
}
void MTProtoConnectionPrivate::clearMessages() {
if (keyId && keyId != mtpAuthKey::RecreateKeyId && conn) {
conn->received().clear();
if (keyId && keyId != mtpAuthKey::RecreateKeyId && _conn) {
_conn->received().clear();
}
}
void MTProtoConnectionPrivate::pqAnswered() {
disconnect(conn, SIGNAL(receivedData()), this, SLOT(pqAnswered()));
disconnect(_conn, SIGNAL(receivedData()), this, SLOT(pqAnswered()));
DEBUG_LOG(("AuthKey Info: receiving Req_pq answer.."));
MTPReq_pq::ResponseType res_pq;
@ -3008,14 +3103,14 @@ void MTProtoConnectionPrivate::pqAnswered() {
return restart();
}
connect(conn, SIGNAL(receivedData()), this, SLOT(dhParamsAnswered()));
connect(_conn, SIGNAL(receivedData()), this, SLOT(dhParamsAnswered()));
DEBUG_LOG(("AuthKey Info: sending Req_DH_params.."));
sendRequestNotSecure(req_DH_params);
}
void MTProtoConnectionPrivate::dhParamsAnswered() {
disconnect(conn, SIGNAL(receivedData()), this, SLOT(dhParamsAnswered()));
disconnect(_conn, SIGNAL(receivedData()), this, SLOT(dhParamsAnswered()));
DEBUG_LOG(("AuthKey Info: receiving Req_DH_params answer.."));
MTPReq_DH_params::ResponseType res_DH_params;
@ -3190,7 +3285,7 @@ void MTProtoConnectionPrivate::dhClientParamsSend() {
aesEncrypt(&encBuffer[0], &sdhEncString[0], encFullSize * sizeof(mtpPrime), authKeyData->aesKey, authKeyData->aesIV);
connect(conn, SIGNAL(receivedData()), this, SLOT(dhClientParamsAnswered()));
connect(_conn, SIGNAL(receivedData()), this, SLOT(dhClientParamsAnswered()));
DEBUG_LOG(("AuthKey Info: sending Req_client_DH_params.."));
sendRequestNotSecure(req_client_DH_params);
@ -3200,7 +3295,7 @@ void MTProtoConnectionPrivate::dhClientParamsAnswered() {
QReadLocker lockFinished(&sessionDataMutex);
if (!sessionData) return;
disconnect(conn, SIGNAL(receivedData()), this, SLOT(dhClientParamsAnswered()));
disconnect(_conn, SIGNAL(receivedData()), this, SLOT(dhClientParamsAnswered()));
DEBUG_LOG(("AuthKey Info: receiving Req_client_DH_params answer.."));
MTPSet_client_DH_params::ResponseType res_client_DH_params;
@ -3295,7 +3390,7 @@ void MTProtoConnectionPrivate::dhClientParamsAnswered() {
void MTProtoConnectionPrivate::authKeyCreated() {
clearAuthKeyData();
connect(conn, SIGNAL(receivedData()), this, SLOT(handleReceived()));
connect(_conn, SIGNAL(receivedData()), this, SLOT(handleReceived()));
if (sessionData->getSalt()) { // else receive salt in bad_server_salt first, then try to send all the requests
setState(MTProtoConnection::Connected);
@ -3328,11 +3423,32 @@ void MTProtoConnectionPrivate::clearAuthKeyData() {
}
}
void MTProtoConnectionPrivate::onError(bool mayBeBadKey) {
cantConnectTimer.stop();
void MTProtoConnectionPrivate::onError4(bool mayBeBadKey) {
if (_conn && _conn == _conn6) return; // error in the unused
MTP_LOG(dc, ("Restarting after error, maybe bad key: %1..").arg(logBool(mayBeBadKey)));
return restart(mayBeBadKey);
if (_conn || !_conn6) {
destroyConn();
_waitForConnectedTimer.stop();
MTP_LOG(dc, ("Restarting after error in IPv4 connection, maybe bad key: %1..").arg(logBool(mayBeBadKey)));
return restart(mayBeBadKey);
} else {
destroyConn(&_conn4);
}
}
void MTProtoConnectionPrivate::onError6(bool mayBeBadKey) {
if (_conn && _conn == _conn4) return; // error in the unused
if (_conn || !_conn4) {
destroyConn();
_waitForConnectedTimer.stop();
MTP_LOG(dc, ("Restarting after error in IPv6 connection, maybe bad key: %1..").arg(logBool(mayBeBadKey)));
return restart(mayBeBadKey);
} else {
destroyConn(&_conn6);
}
}
void MTProtoConnectionPrivate::onReadyData() {
@ -3359,7 +3475,7 @@ void MTProtoConnectionPrivate::sendRequestNotSecure(const TRequest &request) {
DEBUG_LOG(("AuthKey Info: sending request, size: %1, num: %2, time: %3").arg(requestSize).arg(authKeyData->req_num).arg(buffer[5]));
conn->sendData(buffer);
_conn->sendData(buffer);
onSentSome(buffer.size() * sizeof(mtpPrime));
@ -3373,12 +3489,12 @@ bool MTProtoConnectionPrivate::readResponseNotSecure(TResponse &response) {
onReceivedSome();
try {
if (conn->received().isEmpty()) {
if (_conn->received().isEmpty()) {
LOG(("AuthKey Error: trying to read response from empty received list"));
return false;
}
mtpBuffer buffer(conn->received().front());
conn->received().pop_front();
mtpBuffer buffer(_conn->received().front());
_conn->received().pop_front();
const mtpPrime *answer(buffer.constData());
uint32 len = buffer.size();
@ -3449,8 +3565,8 @@ 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);
_conn->setSentEncrypted();
_conn->sendData(result);
if (needAnyResponse) {
onSentSome(result.size() * sizeof(mtpPrime));

View File

@ -25,9 +25,23 @@ enum {
MTPDmessage_flag_out = (1 << 1),
MTPDmessage_flag_notify_by_from = (1 << 4),
MTPDmessage_flag_media_unread = (1 << 5),
MTPmessages_SendMessage_flag_skipWebPage = (1 << 1),
MTPDdcOption_flag_ipv6 = (1 << 0),
MTPDdcOption_flag_files = (1 << 1),
MTPDuser_flag_self = (1 << 10),
MTPDuser_flag_contact = (1 << 11),
MTPDuser_flag_mutual_contact = (1 << 12),
MTPDuser_flag_deleted = (1 << 13),
MTPDuser_flag_bot = (1 << 14),
MTPDuser_flag_bot_reads_all = (1 << 15),
MTPDuser_flag_bot_cant_join = (1 << 16),
};
static const MTPReplyMarkup MTPnullMarkup = MTP_replyKeyboardMarkup(MTP_vector<MTPKeyboardButtonRow>(0));
#include "mtproto/mtpPublicRSA.h"
#include "mtproto/mtpAuthKey.h"
@ -97,11 +111,6 @@ public:
int32 state() const;
QString transport() const;
/*template <typename TRequest> // not used
uint64 sendAsync(const TRequest &request) {
return data->sendAsync(request);
}*/
private:
QThread *thread;
@ -125,7 +134,7 @@ public:
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;
virtual void connectToServer(const QString &addr, int32 port, int32 flags) = 0;
virtual bool isConnected() = 0;
virtual bool usingHttpWait() {
return false;
@ -193,7 +202,7 @@ public:
void sendData(mtpBuffer &buffer);
void disconnectFromServer();
void connectToServer(const QString &addr, int32 port);
void connectToServer(const QString &addr, int32 port, int32 flags);
bool isConnected();
bool usingHttpWait();
bool needHttpWait();
@ -255,7 +264,7 @@ public:
void sendData(mtpBuffer &buffer);
void disconnectFromServer();
void connectToServer(const QString &addr, int32 port);
void connectToServer(const QString &addr, int32 port, int32 flags);
bool isConnected();
int32 debugState() const;
@ -281,7 +290,7 @@ public:
void sendData(mtpBuffer &buffer);
void disconnectFromServer();
void connectToServer(const QString &addr, int32 port);
void connectToServer(const QString &addr, int32 port, int32 flags);
bool isConnected();
bool usingHttpWait();
bool needHttpWait();
@ -343,16 +352,25 @@ public slots:
void onPingSender();
void onPingSendForce();
void onBadConnection();
void onCantConnect();
void onWaitConnectedFailed();
void onWaitReceivedFailed();
void onWaitIPv4Failed();
void onOldConnection();
void onSentSome(uint64 size);
void onReceivedSome();
void onError(bool maybeBadKey = false);
void onReadyData();
void socketStart(bool afterConfig = false);
void onConnected();
void onConnected4();
void onConnected6();
void onDisconnected4();
void onDisconnected6();
void onError4(bool maybeBadKey = false);
void onError6(bool maybeBadKey = false);
void doDisconnect();
void doFinish();
@ -373,7 +391,8 @@ public slots:
private:
void createConn();
void createConn(bool createIPv4, bool createIPv6);
void destroyConn(MTPabstractConnection **conn = 0); // 0 - destory all
mtpMsgId placeToContainer(mtpRequest &toSendRequest, mtpMsgId &bigMsgId, mtpMsgId *&haveSentArr, mtpRequest &req);
mtpMsgId prepareToSend(mtpRequest &request, mtpMsgId currentLastId);
@ -397,7 +416,7 @@ private:
uint32 dc;
MTProtoConnection *_owner;
MTPabstractConnection *conn;
MTPabstractConnection *_conn, *_conn4, *_conn6;
SingleTimer retryTimer; // exp retry timer
uint32 retryTimeout;
@ -406,8 +425,8 @@ private:
SingleTimer oldConnectionTimer;
bool oldConnection;
SingleTimer connCheckTimer, cantConnectTimer;
uint32 receiveDelay, connectDelay;
SingleTimer _waitForConnectedTimer, _waitForReceivedTimer, _waitForIPv4Timer;
uint32 _waitForReceived, _waitForConnected;
int64 firstSentAt;
QVector<MTPlong> ackRequestData, resendRequestData;

View File

@ -366,7 +366,7 @@ static const mtpTypeId mtpLayers[] = {
mtpc_invokeWithLayer17,
mtpc_invokeWithLayer18,
}, mtpLayerMaxSingle = sizeof(mtpLayers) / sizeof(mtpLayers[0]);
static const mtpPrime mtpCurrentLayer = 29;
static const mtpPrime mtpCurrentLayer = 31;
template <typename bareT>
class MTPBoxed : public bareT {

View File

@ -175,15 +175,16 @@ void mtpUpdateDcOptions(const QVector<MTPDcOption> &options) {
}
for (QVector<MTPDcOption>::const_iterator i = options.cbegin(), e = options.cend(); i != e; ++i) {
const MTPDdcOption &optData(i->c_dcOption());
if (already.constFind(optData.vid.v) == already.cend()) {
already.insert(optData.vid.v);
mtpDcOptions::const_iterator a = opts.constFind(optData.vid.v);
int32 id = optData.vid.v, idWithShift = id + (optData.vflags.v * _mtp_internal::dcShift);
if (already.constFind(idWithShift) == already.cend()) {
already.insert(idWithShift);
mtpDcOptions::const_iterator a = opts.constFind(idWithShift);
if (a != opts.cend()) {
if (a.value().ip != optData.vip_address.c_string().v || a.value().port != optData.vport.v) {
restart.insert(optData.vid.v);
restart.insert(id);
}
}
opts.insert(optData.vid.v, mtpDcOption(optData.vid.v, optData.vhostname.c_string().v, optData.vip_address.c_string().v, optData.vport.v));
opts.insert(idWithShift, mtpDcOption(id, optData.vflags.v, optData.vip_address.c_string().v, optData.vport.v));
}
}
{

View File

@ -1109,96 +1109,24 @@ void mtpTextSerializeType(MTPStringLogger &to, const mtpPrime *&from, const mtpP
}
break;
case mtpc_userSelf:
case mtpc_user:
if (stage) {
to.add(",\n").addSpaces(lev);
} else {
to.add("{ userSelf");
to.add("{ user");
to.add("\n").addSpaces(lev);
}
switch (stage) {
case 0: to.add(" id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 1: to.add(" first_name: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 2: to.add(" last_name: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 3: to.add(" username: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 4: to.add(" phone: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 5: to.add(" photo: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 6: to.add(" status: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
break;
case mtpc_userContact:
if (stage) {
to.add(",\n").addSpaces(lev);
} else {
to.add("{ userContact");
to.add("\n").addSpaces(lev);
}
switch (stage) {
case 0: to.add(" id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 1: to.add(" first_name: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 2: to.add(" last_name: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 3: to.add(" username: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 4: to.add(" access_hash: "); ++stages.back(); types.push_back(mtpc_long); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 5: to.add(" phone: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 6: to.add(" photo: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 7: to.add(" status: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
break;
case mtpc_userRequest:
if (stage) {
to.add(",\n").addSpaces(lev);
} else {
to.add("{ userRequest");
to.add("\n").addSpaces(lev);
}
switch (stage) {
case 0: to.add(" id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 1: to.add(" first_name: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 2: to.add(" last_name: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 3: to.add(" username: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 4: to.add(" access_hash: "); ++stages.back(); types.push_back(mtpc_long); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 5: to.add(" phone: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 6: to.add(" photo: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 7: to.add(" status: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
break;
case mtpc_userForeign:
if (stage) {
to.add(",\n").addSpaces(lev);
} else {
to.add("{ userForeign");
to.add("\n").addSpaces(lev);
}
switch (stage) {
case 0: to.add(" id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 1: to.add(" first_name: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 2: to.add(" last_name: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 3: to.add(" username: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 4: to.add(" access_hash: "); ++stages.back(); types.push_back(mtpc_long); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 5: to.add(" photo: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 6: to.add(" status: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
break;
case mtpc_userDeleted:
if (stage) {
to.add(",\n").addSpaces(lev);
} else {
to.add("{ userDeleted");
to.add("\n").addSpaces(lev);
}
switch (stage) {
case 0: to.add(" id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 1: to.add(" first_name: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 2: to.add(" last_name: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 3: to.add(" username: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 0: to.add(" flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 1: to.add(" id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 2: to.add(" access_hash: "); ++stages.back(); if (flag & MTPDuser::flag_access_hash) { types.push_back(mtpc_long); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break;
case 3: to.add(" first_name: "); ++stages.back(); if (flag & MTPDuser::flag_first_name) { types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 1 IN FIELD flags ]"); } break;
case 4: to.add(" last_name: "); ++stages.back(); if (flag & MTPDuser::flag_last_name) { types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 2 IN FIELD flags ]"); } break;
case 5: to.add(" username: "); ++stages.back(); if (flag & MTPDuser::flag_username) { types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 3 IN FIELD flags ]"); } break;
case 6: to.add(" phone: "); ++stages.back(); if (flag & MTPDuser::flag_phone) { types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 4 IN FIELD flags ]"); } break;
case 7: to.add(" photo: "); ++stages.back(); if (flag & MTPDuser::flag_photo) { types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 5 IN FIELD flags ]"); } break;
case 8: to.add(" status: "); ++stages.back(); if (flag & MTPDuser::flag_status) { types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 6 IN FIELD flags ]"); } break;
case 9: to.add(" bot_info_version: "); ++stages.back(); if (flag & MTPDuser::flag_bot_info_version) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 14 IN FIELD flags ]"); } break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
break;
@ -1347,6 +1275,7 @@ void mtpTextSerializeType(MTPStringLogger &to, const mtpPrime *&from, const mtpP
case 2: to.add(" chat_photo: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 3: to.add(" notify_settings: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 4: to.add(" exported_invite: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 5: to.add(" bot_info: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
break;
@ -1444,6 +1373,7 @@ void mtpTextSerializeType(MTPStringLogger &to, const mtpPrime *&from, const mtpP
case 7: to.add(" date: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 8: to.add(" message: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 9: to.add(" media: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 10: to.add(" reply_markup: "); ++stages.back(); if (flag & MTPDmessage::flag_reply_markup) { types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 6 IN FIELD flags ]"); } break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
break;
@ -1893,8 +1823,7 @@ void mtpTextSerializeType(MTPStringLogger &to, const mtpPrime *&from, const mtpP
to.add("\n").addSpaces(lev);
}
switch (stage) {
case 0: to.add(" expires: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 1: to.add(" user: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 0: to.add(" user: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
break;
@ -2048,8 +1977,7 @@ void mtpTextSerializeType(MTPStringLogger &to, const mtpPrime *&from, const mtpP
case 2: to.add(" profile_photo: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 3: to.add(" notify_settings: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 4: to.add(" blocked: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 5: to.add(" real_first_name: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 6: to.add(" real_last_name: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 5: to.add(" bot_info: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
break;
@ -3057,8 +2985,8 @@ void mtpTextSerializeType(MTPStringLogger &to, const mtpPrime *&from, const mtpP
to.add("\n").addSpaces(lev);
}
switch (stage) {
case 0: to.add(" id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 1: to.add(" hostname: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 0: to.add(" flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 1: to.add(" id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 2: to.add(" ip_address: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 3: to.add(" port: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
@ -4353,6 +4281,81 @@ void mtpTextSerializeType(MTPStringLogger &to, const mtpPrime *&from, const mtpP
}
break;
case mtpc_botCommand:
if (stage) {
to.add(",\n").addSpaces(lev);
} else {
to.add("{ botCommand");
to.add("\n").addSpaces(lev);
}
switch (stage) {
case 0: to.add(" command: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 1: to.add(" params: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 2: to.add(" description: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
break;
case mtpc_botInfoEmpty:
to.add("{ botInfoEmpty }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back();
break;
case mtpc_botInfo:
if (stage) {
to.add(",\n").addSpaces(lev);
} else {
to.add("{ botInfo");
to.add("\n").addSpaces(lev);
}
switch (stage) {
case 0: to.add(" user_id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 1: to.add(" version: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 2: to.add(" share_text: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 3: to.add(" description: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 4: to.add(" commands: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
break;
case mtpc_keyboardButton:
if (stage) {
to.add(",\n").addSpaces(lev);
} else {
to.add("{ keyboardButton");
to.add("\n").addSpaces(lev);
}
switch (stage) {
case 0: to.add(" text: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
break;
case mtpc_keyboardButtonRow:
if (stage) {
to.add(",\n").addSpaces(lev);
} else {
to.add("{ keyboardButtonRow");
to.add("\n").addSpaces(lev);
}
switch (stage) {
case 0: to.add(" buttons: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
break;
case mtpc_replyKeyboardMarkup:
if (stage) {
to.add(",\n").addSpaces(lev);
} else {
to.add("{ replyKeyboardMarkup");
to.add("\n").addSpaces(lev);
}
switch (stage) {
case 0: to.add(" rows: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
break;
case mtpc_req_pq:
if (stage) {
to.add(",\n").addSpaces(lev);
@ -5018,6 +5021,22 @@ void mtpTextSerializeType(MTPStringLogger &to, const mtpPrime *&from, const mtpP
}
break;
case mtpc_auth_importBotAuthorization:
if (stage) {
to.add(",\n").addSpaces(lev);
} else {
to.add("{ auth_importBotAuthorization");
to.add("\n").addSpaces(lev);
}
switch (stage) {
case 0: to.add(" flags: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 1: to.add(" api_id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 2: to.add(" api_hash: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 3: to.add(" bot_auth_token: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
break;
case mtpc_auth_checkPassword:
if (stage) {
to.add(",\n").addSpaces(lev);
@ -5388,6 +5407,7 @@ void mtpTextSerializeType(MTPStringLogger &to, const mtpPrime *&from, const mtpP
case 2: to.add(" reply_to_msg_id: "); ++stages.back(); if (flag & MTPmessages_sendMessage::flag_reply_to_msg_id) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break;
case 3: to.add(" message: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 4: to.add(" random_id: "); ++stages.back(); types.push_back(mtpc_long); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 5: to.add(" reply_markup: "); ++stages.back(); if (flag & MTPmessages_sendMessage::flag_reply_markup) { types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 2 IN FIELD flags ]"); } break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
break;
@ -5405,6 +5425,7 @@ void mtpTextSerializeType(MTPStringLogger &to, const mtpPrime *&from, const mtpP
case 2: to.add(" reply_to_msg_id: "); ++stages.back(); if (flag & MTPmessages_sendMedia::flag_reply_to_msg_id) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break;
case 3: to.add(" media: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 4: to.add(" random_id: "); ++stages.back(); types.push_back(mtpc_long); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 5: to.add(" reply_markup: "); ++stages.back(); if (flag & MTPmessages_sendMedia::flag_reply_markup) { types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 2 IN FIELD flags ]"); } break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
break;

File diff suppressed because it is too large Load Diff

View File

@ -193,11 +193,6 @@ fileLocationUnavailable#7c596b46 volume_id:long local_id:int secret:long = FileL
fileLocation#53d69076 dc_id:int volume_id:long local_id:int secret:long = FileLocation;
userEmpty#200250ba id:int = User;
userSelf#1c60e608 id:int first_name:string last_name:string username:string phone:string photo:UserProfilePhoto status:UserStatus = User;
userContact#cab35e18 id:int first_name:string last_name:string username:string access_hash:long phone:string photo:UserProfilePhoto status:UserStatus = User;
userRequest#d9ccc4ef id:int first_name:string last_name:string username:string access_hash:long phone:string photo:UserProfilePhoto status:UserStatus = User;
userForeign#75cf7a8 id:int first_name:string last_name:string username:string access_hash:long photo:UserProfilePhoto status:UserStatus = User;
userDeleted#d6016d7a id:int first_name:string last_name:string username:string = User;
userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto;
userProfilePhoto#d559d8c8 photo_id:long photo_small:FileLocation photo_big:FileLocation = UserProfilePhoto;
@ -210,7 +205,7 @@ chatEmpty#9ba2d800 id:int = Chat;
chat#6e9c9bc7 id:int title:string photo:ChatPhoto participants_count:int date:int left:Bool version:int = Chat;
chatForbidden#fb0ccc41 id:int title:string date:int = Chat;
chatFull#cade0791 id:int participants:ChatParticipants chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite = ChatFull;
chatFull#2e02a614 id:int participants:ChatParticipants chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> = ChatFull;
chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant;
@ -221,7 +216,7 @@ chatPhotoEmpty#37c1011c = ChatPhoto;
chatPhoto#6153276a photo_small:FileLocation photo_big:FileLocation = ChatPhoto;
messageEmpty#83e5de54 id:int = Message;
message#a7ab1991 flags:# id:int from_id:int to_id:Peer fwd_from_id:flags.2?int fwd_date:flags.2?int reply_to_msg_id:flags.3?int date:int message:string media:MessageMedia = Message;
message#c3060325 flags:# id:int from_id:int to_id:Peer fwd_from_id:flags.2?int fwd_date:flags.2?int reply_to_msg_id:flags.3?int date:int message:string media:MessageMedia reply_markup:flags.6?ReplyMarkup = Message;
messageService#1d86f70e flags:int id:int from_id:int to_id:Peer date:int action:MessageAction = Message;
messageMediaEmpty#3ded6320 = MessageMedia;
@ -258,7 +253,7 @@ auth.checkedPhone#811ea28e phone_registered:Bool = auth.CheckedPhone;
auth.sentCode#efed51d9 phone_registered:Bool phone_code_hash:string send_call_timeout:int is_password:Bool = auth.SentCode;
auth.authorization#f6b673a4 expires:int user:User = auth.Authorization;
auth.authorization#ff036af1 user:User = auth.Authorization;
auth.exportedAuthorization#df969c2d id:int bytes:bytes = auth.ExportedAuthorization;
@ -280,7 +275,7 @@ peerNotifySettings#8d5e11ee mute_until:int sound:string show_previews:Bool event
wallPaper#ccb03657 id:int title:string sizes:Vector<PhotoSize> color:int = WallPaper;
userFull#771095da user:User link:contacts.Link profile_photo:Photo notify_settings:PeerNotifySettings blocked:Bool real_first_name:string real_last_name:string = UserFull;
userFull#5a89ac5b user:User link:contacts.Link profile_photo:Photo notify_settings:PeerNotifySettings blocked:Bool bot_info:BotInfo = UserFull;
contact#f911c994 user_id:int mutual:Bool = Contact;
@ -363,7 +358,7 @@ photos.photo#20212ca8 photo:Photo users:Vector<User> = photos.Photo;
upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File;
dcOption#2ec2a43c id:int hostname:string ip_address:string port:int = DcOption;
dcOption#5d8c6cc flags:# id:int ip_address:string port:int = DcOption;
config#4e32b894 date:int expires:int test_mode:Bool this_dc:int dc_options:Vector<DcOption> chat_size_max:int broadcast_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int chat_big_size:int push_chat_period_ms:int push_chat_limit:int disabled_features:Vector<DisabledFeature> = Config;
@ -596,6 +591,19 @@ stickerSet#a7a43b17 id:long access_hash:long title:string short_name:string = St
messages.stickerSet#b60a24a6 set:StickerSet packs:Vector<StickerPack> documents:Vector<Document> = messages.StickerSet;
user#22e49072 flags:# id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int = User;
botCommand#b79d22ab command:string params:string description:string = BotCommand;
botInfoEmpty#bb2e37ce = BotInfo;
botInfo#9cf585d user_id:int version:int share_text:string description:string commands:Vector<BotCommand> = BotInfo;
keyboardButton#a2fa4880 text:string = KeyboardButton;
keyboardButtonRow#77608b83 buttons:Vector<KeyboardButton> = KeyboardButtonRow;
replyKeyboardMarkup#d59bfc31 rows:Vector<KeyboardButtonRow> = ReplyMarkup;
---functions---
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
@ -647,8 +655,8 @@ messages.deleteHistory#f4f8fb61 peer:InputPeer offset:int = messages.AffectedHis
messages.deleteMessages#a5f18925 id:Vector<int> = messages.AffectedMessages;
messages.receivedMessages#5a954c0 max_id:int = Vector<ReceivedNotifyMessage>;
messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool;
messages.sendMessage#9add8f26 flags:# peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long = messages.SentMessage;
messages.sendMedia#2d7923b1 flags:# peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia random_id:long = Updates;
messages.sendMessage#fc55e6b5 flags:# peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup = messages.SentMessage;
messages.sendMedia#c8f16791 flags:# peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia random_id:long reply_markup:flags.2?ReplyMarkup = Updates;
messages.forwardMessages#55e1728d peer:InputPeer id:Vector<int> random_id:Vector<long> = Updates;
messages.getChats#3c6aa187 id:Vector<int> = messages.Chats;
messages.getFullChat#3b831c66 chat_id:int = messages.ChatFull;
@ -736,6 +744,8 @@ messages.getAllStickers#aa3bc868 hash:string = messages.AllStickers;
account.updateDeviceLocked#38df3532 period:int = Bool;
auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization;
messages.getWebPagePreview#25223e24 message:string = MessageMedia;
account.getAuthorizations#e320c158 = account.Authorizations;

View File

@ -325,13 +325,13 @@ void ProfileInner::updateOnlineDisplayTimer() {
if (_peerChat->participants.isEmpty()) return;
for (ChatData::Participants::const_iterator i = _peerChat->participants.cbegin(), e = _peerChat->participants.cend(); i != e; ++i) {
int32 onlineWillChangeIn = App::onlineWillChangeIn(i.key()->onlineTill, t);
int32 onlineWillChangeIn = App::onlineWillChangeIn(i.key(), t);
if (onlineWillChangeIn < minIn) {
minIn = onlineWillChangeIn;
}
}
} else {
minIn = App::onlineWillChangeIn(_peerUser->onlineTill, t);
minIn = App::onlineWillChangeIn(_peerUser, t);
}
App::main()->updateOnlineDisplayIn(minIn * 1000);
}
@ -354,13 +354,13 @@ void ProfileInner::reorderParticipants() {
bool onlyMe = true;
for (ChatData::Participants::const_iterator i = _peerChat->participants.cbegin(), e = _peerChat->participants.cend(); i != e; ++i) {
UserData *user = i.key();
int32 until = App::onlineForSort(user->onlineTill, t);
int32 until = App::onlineForSort(user, t);
Participants::iterator before = _participants.begin();
if (user != self) {
if (before != _participants.end() && (*before) == self) {
++before;
}
while (before != _participants.end() && App::onlineForSort((*before)->onlineTill, t) >= until) {
while (before != _participants.end() && App::onlineForSort(*before, t) >= until) {
++before;
}
if (until > t && onlyMe) onlyMe = false;

View File

@ -53,11 +53,11 @@ inline bool rtl() {
}
struct mtpDcOption {
mtpDcOption(int _id, const string &_host, const string &_ip, int _port) : id(_id), host(_host), ip(_ip), port(_port) {
mtpDcOption(int id, int flags, const string &ip, int port) : id(id), flags(flags), ip(ip), port(port) {
}
int id;
string host;
int flags;
string ip;
int port;
};

View File

@ -201,10 +201,58 @@ void UserData::setPhone(const QString &newPhone) {
++nameVersion;
}
void UserData::setBotInfoVersion(int32 version) {
if (!botInfo) {
botInfo = new BotInfo();
botInfo->version = version;
} else if (botInfo->version < version) {
botInfo->commands.clear();
botInfo->description.clear();
botInfo->shareText.clear();
botInfo->version = version;
}
}
void UserData::setBotInfo(const MTPBotInfo &info) {
switch (info.type()) {
case mtpc_botInfoEmpty:
delete botInfo;
botInfo = 0;
break;
case mtpc_botInfo: {
const MTPDbotInfo &d(info.c_botInfo());
if (d.vuser_id.v != id) return;
setBotInfoVersion(d.vversion.v);
if (botInfo->version > d.vversion.v) return;
botInfo->description = qs(d.vdescription);
botInfo->shareText = qs(d.vshare_text);
const QVector<MTPBotCommand> &v(d.vcommands.c_vector().v);
botInfo->commands.clear();
botInfo->commands.reserve(v.size());
for (int32 i = 0, l = v.size(); i < l; ++i) {
if (v.at(i).type() == mtpc_botCommand) {
botInfo->commands.push_back(BotCommand(qs(v.at(i).c_botCommand().vcommand), qs(v.at(i).c_botCommand().vparams), qs(v.at(i).c_botCommand().vdescription)));
}
}
} break;
}
}
void UserData::nameUpdated() {
nameText.setText(st::msgNameFont, name, _textNameOptions);
}
void UserData::madeAction() {
int32 t = unixtime();
if (onlineTill <= 0 && -onlineTill < t) {
onlineTill = -t - SetOnlineAfterActivity;
if (App::main()) App::main()->peerUpdated(this);
} else if (onlineTill > 0 && onlineTill < t + 1) {
onlineTill = t + SetOnlineAfterActivity;
if (App::main()) App::main()->peerUpdated(this);
}
}
void ChatData::setPhoto(const MTPChatPhoto &p, const PhotoId &phId) {
switch (p.type()) {
case mtpc_chatPhoto: {

View File

@ -118,15 +118,30 @@ private:
PeerData *_peer;
};
struct BotCommand {
BotCommand(const QString &command, const QString &params, const QString &description) : command(command), params(params), description(description) {
}
QString command, params, description;
};
struct BotInfo {
int32 version;
QString shareText, description;
QList<BotCommand> commands;
};
struct PhotoData;
struct UserData : public PeerData {
UserData(const PeerId &id) : PeerData(id), lnk(new PeerLink(this)), onlineTill(0), contact(-1), photosCount(-1) {
UserData(const PeerId &id) : PeerData(id), lnk(new PeerLink(this)), photoId(0), onlineTill(0), contact(-1), photosCount(-1), botInfo(0) {
}
void setPhoto(const MTPUserProfilePhoto &photo);
void setName(const QString &first, const QString &last, const QString &phoneName, const QString &username);
void setPhone(const QString &newPhone);
void setBotInfoVersion(int32 version);
void setBotInfo(const MTPBotInfo &info);
void nameUpdated();
void madeAction(); // pseudo-online
QString firstName;
QString lastName;
QString username;
@ -140,6 +155,8 @@ struct UserData : public PeerData {
typedef QList<PhotoData*> Photos;
Photos photos;
int32 photosCount; // -1 not loaded, 0 all loaded
BotInfo *botInfo;
};
struct ChatData : public PeerData {
@ -164,6 +181,10 @@ struct ChatData : public PeerData {
// geo
};
inline int32 newMessageFlags(PeerData *p) {
return (p->input.type() == mtpc_inputPeerSelf) ? 0 : (((p->chat || !p->asUser()->botInfo) ? MTPDmessage_flag_unread : 0) | MTPDmessage_flag_out);
}
typedef QMap<char, QPixmap> PreparedPhotoThumbs;
struct PhotoData {
PhotoData(const PhotoId &id, const uint64 &access = 0, int32 user = 0, int32 date = 0, const ImagePtr &thumb = ImagePtr(), const ImagePtr &medium = ImagePtr(), const ImagePtr &full = ImagePtr()) :

View File

@ -233,7 +233,7 @@ QString rusKeyboardLayoutSwitch(const QString &from);
enum DataBlockId {
dbiKey = 0x00,
dbiUser = 0x01,
dbiDcOption = 0x02,
dbiDcOptionOld = 0x02,
dbiMaxGroupCount = 0x03,
dbiMutePeer = 0x04,
dbiSendKey = 0x05,
@ -270,6 +270,7 @@ enum DataBlockId {
dbiRecentEmojis = 0x24,
dbiEmojiVariants = 0x25,
dbiRecentStickers = 0x26,
dbiDcOption = 0x27,
dbiEncryptedWithSalt = 333,
dbiEncrypted = 444,

View File

@ -606,7 +606,8 @@ void Window::sendServiceHistoryRequest() {
UserData *user = App::userLoaded(ServiceUserId);
if (!user) {
user = App::feedUsers(MTP_vector<MTPUser>(1, MTP_userRequest(MTP_int(ServiceUserId), MTP_string("Telegram"), MTP_string(""), MTP_string(""), MTP_long(-1), MTP_string("42777"), MTP_userProfilePhotoEmpty(), MTP_userStatusRecently())));
int32 userFlags = MTPDuser::flag_first_name | MTPDuser::flag_phone | MTPDuser::flag_status;
user = App::feedUsers(MTP_vector<MTPUser>(1, MTP_user(MTP_int(userFlags), MTP_int(ServiceUserId), MTPlong(), MTP_string("Telegram"), MTPstring(), MTPstring(), MTP_string("42777"), MTP_userProfilePhotoEmpty(), MTP_userStatusRecently(), MTPint())));
}
_serviceHistoryRequest = MTP::send(MTPmessages_GetHistory(user->input, MTP_int(0), MTP_int(0), MTP_int(1)), main->rpcDone(&MainWidget::serviceHistoryDone), main->rpcFail(&MainWidget::serviceHistoryFail));
}