version 0.6.9 - some network and protocol improvements, checkboxes in photos overview, other fixes

This commit is contained in:
John Preston 2014-11-15 02:23:35 +03:00
parent c89f13bb53
commit 868b9843b0
46 changed files with 5618 additions and 4310 deletions

View File

@ -1,5 +1,5 @@
AppVersionStr=0.6.8
AppVersion=6008
AppVersionStr=0.6.9
AppVersion=6009
if [ ! -f "./../Linux/Release/deploy/$AppVersionStr/tlinuxupd$AppVersion" ]; then
echo "tlinuxupd$AppVersion not found!";

View File

@ -1,5 +1,5 @@
AppVersionStr=0.6.8
AppVersion=6008
AppVersionStr=0.6.9
AppVersion=6009
if [ ! -f "./../Linux/Release/deploy/$AppVersionStr/tlinux32upd$AppVersion" ]; then
echo "tlinux32upd$AppVersion not found!"

View File

@ -1,5 +1,5 @@
AppVersionStr=0.6.8
AppVersion=6008
AppVersionStr=0.6.9
AppVersion=6009
if [ ! -f "./../Mac/Release/deploy/$AppVersionStr/tmacupd$AppVersion" ]; then
echo "tmacupd$AppVersion not found!"

View File

@ -1,5 +1,5 @@
AppVersionStr=0.6.8
AppVersion=6008
AppVersionStr=0.6.9
AppVersion=6009
if [ ! -f "./../Win32/Deploy/deploy/$AppVersionStr/tupdate$AppVersion" ]; then
echo "tupdate$AppVersion not found!"

View File

@ -1,5 +1,5 @@
AppVersionStr=0.6.8
AppVersion=6008
AppVersionStr=0.6.9
AppVersion=6009
if [ -d "./../Linux/Release/deploy/$AppVersionStr" ]; then
echo "Deploy folder for version $AppVersionStr already exists!"

View File

@ -1,5 +1,5 @@
AppVersionStr=0.6.8
AppVersion=6008
AppVersionStr=0.6.9
AppVersion=6009
if [ -d "./../Linux/Release/deploy/$AppVersionStr" ]; then
echo "Deploy folder for version $AppVersionStr already exists!"

View File

@ -1,5 +1,5 @@
AppVersionStr=0.6.8
AppVersion=6008
AppVersionStr=0.6.9
AppVersion=6009
echo ""
echo "Preparing version $AppVersionStr.."

View File

@ -1,6 +1,6 @@
@echo OFF
set "AppVersionStr=0.6.8"
set "AppVersionStr=0.6.9"
echo.
echo Preparing version %AppVersionStr%..
echo.

View File

@ -61,7 +61,10 @@ lng_connecting: "Connecting..";
lng_reconnecting: "Reconnect in %1 s..";
lng_reconnecting_try_now: "Try now";
lng_status_offline: "offline";
lng_status_offline: "last seen a long time ago";
lng_status_recently: "last seen recently";
lng_status_last_week: "last seen within a week";
lng_status_last_month: "last seen within a month";
lng_status_invisible: "invisible";
lng_status_lastseen: "last seen {when}";
lng_status_lastseen_now: "just now";

View File

@ -1572,6 +1572,9 @@ medviewPhotoSpritePos: point(14px, 14px);
overviewPhotoSkip: 10px;
overviewPhotoMinSize: 100px;
overviewPhotoCheck: sprite(245px, 308px, 32px, 32px);
overviewPhotoChecked: sprite(278px, 308px, 32px, 32px);
overviewPhotoSelectOverlay: #0a7bb03f;
// Mac specific

View File

@ -3,9 +3,9 @@
#define MyAppShortName "Telegram"
#define MyAppName "Telegram Desktop"
#define MyAppVersion "0.6.8"
#define MyAppVersionZero "0.6.8"
#define MyAppFullVersion "0.6.8.0"
#define MyAppVersion "0.6.9"
#define MyAppVersionZero "0.6.9"
#define MyAppFullVersion "0.6.9.0"
#define MyAppPublisher "Telegram Messenger LLP"
#define MyAppURL "https://tdesktop.com"
#define MyAppExeName "Telegram.exe"

View File

@ -183,8 +183,15 @@ namespace App {
}
QString onlineText(int32 online, int32 now, bool precise) {
if (!online) return lang(lng_status_offline);
if (online < 0) return lang(lng_status_invisible);
if (online <= 0) {
switch (online) {
case 0: return lang(lng_status_offline);
case -2: return lang(lng_status_recently);
case -3: return lang(lng_status_last_week);
case -4: return lang(lng_status_last_month);
}
return lang(lng_status_invisible);
}
if (online > now) {
return lang(lng_status_online);
}
@ -329,6 +336,10 @@ namespace App {
data->loaded = true;
if (status) switch (status->type()) {
case mtpc_userStatusEmpty: data->onlineTill = 0; break;
case mtpc_userStatusRecently: data->onlineTill = -2; break;
case mtpc_userStatusLastWeek: data->onlineTill = -3; break;
case mtpc_userStatusLastMonth: data->onlineTill = -4; break;
case mtpc_userStatusOffline: data->onlineTill = status->c_userStatusOffline().vwas_online.v; break;
case mtpc_userStatusOnline: data->onlineTill = status->c_userStatusOnline().vexpires.v; break;
}
@ -408,7 +419,7 @@ namespace App {
if (!data) continue;
data->loaded = true;
data->updateName(title.trimmed(), QString());
data->updateName(title.trimmed(), QString(), QString());
if (App::main()) App::main()->peerUpdated(data);
}

View File

@ -633,7 +633,6 @@ void Application::startApp() {
readSupportTemplates();
MTP::setLayer(mtpLayerMax);
MTP::start();
MTP::setStateChangedHandler(mtpStateChanged);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 97 KiB

View File

@ -281,7 +281,7 @@ bool AddContactBox::onSaveFail(const RPCError &error) {
QString err(error.type());
QString firstName = _firstInput.text().trimmed(), lastName = _lastInput.text().trimmed();
if (err == "CHAT_TITLE_NOT_MODIFIED") {
_peer->updateName(firstName, QString());
_peer->updateName(firstName, QString(), QString());
emit closed();
return true;
} else if (err == "NO_CHAT_TITLE") {

View File

@ -231,6 +231,7 @@ void AddParticipantInner::mousePressEvent(QMouseEvent *e) {
}
void AddParticipantInner::chooseParticipant() {
_time = unixtime();
int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2, from;
if (_filter.isEmpty()) {
if (!_sel || contactData(_sel)->inchat) return;
@ -293,6 +294,7 @@ void AddParticipantInner::updateSel() {
}
void AddParticipantInner::updateFilter(QString filter) {
_time = unixtime();
QStringList f;
if (!filter.isEmpty()) {
QStringList filterList = filter.split(cWordSplit(), QString::SkipEmptyParts);
@ -405,6 +407,7 @@ AddParticipantInner::~AddParticipantInner() {
}
void AddParticipantInner::selectSkip(int32 dir) {
_time = unixtime();
_mouseSel = false;
int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2, origDir = dir;
if (_filter.isEmpty()) {

View File

@ -17,8 +17,8 @@ Copyright (c) 2014 John Preston, https://tdesktop.com
*/
#pragma once
static const int32 AppVersion = 6008;
static const wchar_t *AppVersionStr = L"0.6.8";
static const int32 AppVersion = 6009;
static const wchar_t *AppVersionStr = L"0.6.9";
static const wchar_t *AppNameOld = L"Telegram Win (Unofficial)";
static const wchar_t *AppName = L"Telegram Desktop";

View File

@ -3975,7 +3975,7 @@ QString textAccentFold(const QString &text) {
continue;
}
if (ch->isHighSurrogate() && ch + 1 < e && (ch + 1)->isLowSurrogate()) {
QChar noAccent = QChar::surrogateToUcs4(*ch, *(ch + 1));
QChar noAccent = chNoAccent(QChar::surrogateToUcs4(*ch, *(ch + 1)));
if (noAccent.unicode() > 0) {
copying = true;
result[i] = noAccent;

View File

@ -296,12 +296,13 @@ const ChatData *PeerData::asChat() const {
return chat ? static_cast<const ChatData *>(this) : App::chat(id | 0x100000000L);
}
void PeerData::updateName(const QString &newName, const QString &newNameOrPhone) {
if (name == newName && nameOrPhone == newNameOrPhone) return;
void PeerData::updateName(const QString &newName, const QString &newNameOrPhone, const QString &newUsername) {
if (name == newName && nameOrPhone == newNameOrPhone && (chat || asUser()->username == newUsername)) return;
++nameVersion;
name = newName;
nameOrPhone = newNameOrPhone;
if (!chat) asUser()->username = newUsername;
Names oldNames = names;
NameFirstChars oldChars = chars;
fillNames();
@ -352,24 +353,23 @@ void PeerData::fillNames() {
void UserData::setName(const QString &first, const QString &last, const QString &phoneName, const QString &usern) {
bool updName = !first.isEmpty() || !last.isEmpty();
if (username != usern) {
username = usern;
if (App::main()) {
App::main()->peerUsernameChanged(this);
}
}
bool updName = !first.isEmpty() || !last.isEmpty(), updUsername = (username != usern);
if (updName && first.trimmed().isEmpty()) {
firstName = last;
lastName = QString();
updateName(firstName, phoneName);
updateName(firstName, phoneName, usern);
} else {
if (updName) {
firstName = first;
lastName = last;
}
updateName(firstName + ' ' + lastName, phoneName);
updateName(firstName + ' ' + lastName, phoneName, usern);
}
if (updUsername) {
if (App::main()) {
App::main()->peerUsernameChanged(this);
}
}
}
@ -1168,7 +1168,7 @@ HistoryItem *History::createItem(HistoryBlock *block, const MTPmessage &msg, boo
case mtpc_messageActionChatEditTitle: {
const MTPDmessageActionChatEditTitle &d(action.c_messageActionChatEditTitle());
ChatData *chat = peer->asChat();
if (chat) chat->updateName(qs(d.vtitle), QString());
if (chat) chat->updateName(qs(d.vtitle), QString(), QString());
} break;
}
}
@ -3074,7 +3074,7 @@ void ImageLinkManager::init() {
App::setProxySettings(*manager);
connect(manager, SIGNAL(authenticationRequired(QNetworkReply*, QAuthenticator*)), this, SLOT(onFailed(QNetworkReply*)));
connect(manager, SIGNAL(sslErrors(QNetworkReply*, const QList<QSslError>&errors)), this, SLOT(onFailed(QNetworkReply*)));
connect(manager, SIGNAL(sslErrors(QNetworkReply*, const QList<QSslError>&)), this, SLOT(onFailed(QNetworkReply*)));
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(onFinished(QNetworkReply*)));
if (black) delete black;

View File

@ -82,7 +82,7 @@ struct PeerData {
ChatData *asChat();
const ChatData *asChat() const;
void updateName(const QString &newName, const QString &newNameOrPhone);
void updateName(const QString &newName, const QString &newNameOrPhone, const QString &newUsername);
void fillNames();

View File

@ -1548,7 +1548,7 @@ HistoryWidget::HistoryWidget(QWidget *parent) : QWidget(parent)
connect(&_attachDocument, SIGNAL(clicked()), this, SLOT(onDocumentSelect()));
connect(&_attachPhoto, SIGNAL(clicked()), this, SLOT(onPhotoSelect()));
connect(&_field, SIGNAL(submitted(bool)), this, SLOT(onSend(bool)));
connect(&_field, SIGNAL(cancelled()), this, SIGNAL(cancelled()));
connect(&_field, SIGNAL(cancelled()), this, SLOT(onCancel()));
connect(&_field, SIGNAL(tabbed()), this, SLOT(onFieldTabbed()));
connect(&_field, SIGNAL(resized()), this, SLOT(onFieldResize()));
connect(&_field, SIGNAL(focused()), this, SLOT(onFieldFocused()));
@ -3161,6 +3161,11 @@ void HistoryWidget::setFieldText(const QString &text) {
noTypingUpdate = false;
}
void HistoryWidget::onCancel() {
showPeer(0);
emit cancelled();
}
void HistoryWidget::peerUpdated(PeerData *data) {
if (data && data == histPeer) {
updateListSize();

View File

@ -343,6 +343,8 @@ signals:
public slots:
void onCancel();
void peerUpdated(PeerData *data);
void cancelTyping();

View File

@ -2252,6 +2252,9 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
if (user) {
switch (d.vstatus.type()) {
case mtpc_userStatusEmpty: user->onlineTill = 0; break;
case mtpc_userStatusRecently: user->onlineTill = -2; break;
case mtpc_userStatusLastWeek: user->onlineTill = -3; break;
case mtpc_userStatusLastMonth: user->onlineTill = -4; break;
case mtpc_userStatusOffline: user->onlineTill = d.vstatus.c_userStatusOffline().vwas_online.v; break;
case mtpc_userStatusOnline: user->onlineTill = d.vstatus.c_userStatusOnline().vexpires.v; break;
}
@ -2263,8 +2266,12 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
case mtpc_updateUserName: {
const MTPDupdateUserName &d(update.c_updateUserName());
UserData *user = App::userLoaded(d.vuser_id.v);
if (user && user->contact <= 0) {
user->setName(textOneLine(qs(d.vfirst_name)), textOneLine(qs(d.vlast_name)), user->nameOrPhone, textOneLine(qs(d.vusername)));
if (user) {
if (user->contact <= 0) {
user->setName(textOneLine(qs(d.vfirst_name)), textOneLine(qs(d.vlast_name)), user->nameOrPhone, textOneLine(qs(d.vusername)));
} else {
user->setName(textOneLine(user->firstName), textOneLine(user->lastName), user->nameOrPhone, textOneLine(qs(d.vusername)));
}
if (App::main()) App::main()->peerUpdated(user);
}
} break;

View File

@ -177,11 +177,11 @@ with open('scheme.tl') as f:
funcsText += '\tMTP' + name + '(' + ', '.join(prmsStr) + ') : ' + ', '.join(prmsInit) + ' {\n\t}\n';
funcsText += '\n';
funcsText += '\tuint32 size() const {\n'; # count size
funcsText += '\tuint32 innerLength() const {\n'; # count size
size = [];
for k in prmsList:
v = prms[k];
size.append('v' + k + '.size()');
size.append('v' + k + '.innerLength()');
if (not len(size)):
size.append('0');
funcsText += '\t\treturn ' + ' + '.join(size) + ';\n';
@ -402,7 +402,7 @@ for restype in typesList:
writeText += '\t\t';
readText += '\tv.v' + paramName + '.read(from, end);\n';
writeText += '\tv.v' + paramName + '.write(to);\n';
sizeList.append('v.v' + paramName + '.size()');
sizeList.append('v.v' + paramName + '.innerLength()');
forwards += 'class MTPD' + name + ';\n'; # data class forward declaration
@ -505,8 +505,8 @@ for restype in typesList:
if (withData):
typesText += getters;
typesText += '\n\tuint32 size() const;\n'; # size method
inlineMethods += '\ninline uint32 MTP' + restype + '::size() const {\n';
typesText += '\n\tuint32 innerLength() const;\n'; # size method
inlineMethods += '\ninline uint32 MTP' + restype + '::innerLength() const {\n';
if (withType and sizeCases):
inlineMethods += '\tswitch (_type) {\n';
inlineMethods += sizeCases;

View File

@ -350,10 +350,6 @@ namespace _mtp_internal {
requestsByDC.remove(requestId);
}
uint32 getLayer() {
return layer;
}
mtpRequestId storeRequest(mtpRequest &request, const RPCResponseHandler &parser) {
mtpRequestId res = reqid();
request->requestId = res;
@ -379,20 +375,25 @@ namespace _mtp_internal {
return req;
}
void wrapInvokeAfter(mtpRequest &to, const mtpRequest &from, const mtpRequestMap &haveSent) {
void wrapInvokeAfter(mtpRequest &to, const mtpRequest &from, const mtpRequestMap &haveSent, int32 skipBeforeRequest) {
mtpMsgId afterId(*(mtpMsgId*)(from->after->data() + 4));
mtpRequestMap::const_iterator i = afterId ? haveSent.constFind(afterId) : haveSent.cend();
int32 size = to->size(), len = (*from)[7] >> 2, headlen = 4, fulllen = headlen + len;
int32 size = to->size(), lenInInts = (from.innerLength() >> 2), headlen = 4, fulllen = headlen + lenInInts;
if (i == haveSent.constEnd()) { // no invoke after or such msg was not sent or was completed recently
to->resize(size + fulllen);
memcpy(to->data() + size, from->constData() + 4, fulllen * sizeof(mtpPrime));
to->resize(size + fulllen + skipBeforeRequest);
if (skipBeforeRequest) {
memcpy(to->data() + size, from->constData() + 4, headlen * sizeof(mtpPrime));
memcpy(to->data() + size + headlen + skipBeforeRequest, from->constData() + 4 + headlen, lenInInts * sizeof(mtpPrime));
} else {
memcpy(to->data() + size, from->constData() + 4, fulllen * sizeof(mtpPrime));
}
} else {
to->resize(size + fulllen + 3);
to->resize(size + fulllen + skipBeforeRequest + 3);
memcpy(to->data() + size, from->constData() + 4, headlen * sizeof(mtpPrime));
(*to)[size + 3] += 3 * sizeof(mtpPrime);
*((mtpTypeId*)&((*to)[size + headlen])) = mtpc_invokeAfterMsg;
memcpy(to->data() + size + headlen + 1, &afterId, 2 * sizeof(mtpPrime));
memcpy(to->data() + size + headlen + 3, from->constData() + 4 + headlen, len * sizeof(mtpPrime));
*((mtpTypeId*)&((*to)[size + headlen + skipBeforeRequest])) = mtpc_invokeAfterMsg;
memcpy(to->data() + size + headlen + skipBeforeRequest + 1, &afterId, 2 * sizeof(mtpPrime));
memcpy(to->data() + size + headlen + skipBeforeRequest + 3, from->constData() + 4 + headlen, lenInInts * sizeof(mtpPrime));
if (size + 3 != 7) (*to)[7] += 3 * sizeof(mtpPrime);
}
}
@ -624,15 +625,6 @@ namespace MTP {
}
}
void setLayer(uint32 l) {
if (l > mtpLayerMax) {
l = mtpLayerMax;
} else if (!l) {
l = 1;
}
layer = l - 1;
}
void setdc(int32 dc, bool fromZeroOnly) {
if (!started) return;

View File

@ -26,13 +26,11 @@ namespace _mtp_internal {
void registerRequest(mtpRequestId requestId, int32 dc);
void unregisterRequest(mtpRequestId requestId);
uint32 getLayer();
static const uint32 dcShift = 10000;
mtpRequestId storeRequest(mtpRequest &request, const RPCResponseHandler &parser);
mtpRequest getRequest(mtpRequestId req);
void wrapInvokeAfter(mtpRequest &to, const mtpRequest &from, const mtpRequestMap &haveSent);
void wrapInvokeAfter(mtpRequest &to, const mtpRequest &from, const mtpRequestMap &haveSent, int32 skipBeforeRequest = 0);
void clearCallbacks(mtpRequestId requestId, int32 errorCode = RPCError::NoError); // 0 - do not toggle onError callback
void clearCallbacksDelayed(const RPCCallbackClears &requestIds);
void performDelayedClear();
@ -86,8 +84,6 @@ namespace MTP {
void restart();
void restart(int32 dcMask);
void setLayer(uint32 layer);
void setdc(int32 dc, bool fromZeroOnly = false);
int32 maindc();
int32 dcstate(int32 dc = 0);
@ -98,7 +94,7 @@ namespace MTP {
MTProtoSessionPtr session = _mtp_internal::getSession(dc);
if (!session) return 0;
return session->send(request, callbacks, msCanWait, _mtp_internal::getLayer(), !dc, after);
return session->send(request, callbacks, msCanWait, true, !dc, after);
}
template <typename TRequest>
inline mtpRequestId send(const TRequest &request, RPCDoneHandlerPtr onDone, RPCFailHandlerPtr onFail = RPCFailHandlerPtr(), int32 dc = 0, uint64 msCanWait = 0, mtpRequestId after = 0) {

View File

@ -473,7 +473,7 @@ namespace {
mtpBuffer _preparePQFake(const MTPint128 &nonce) {
MTPReq_pq req_pq(nonce);
mtpBuffer buffer;
uint32 requestSize = req_pq.size() >> 2;
uint32 requestSize = req_pq.innerLength() >> 2;
buffer.resize(0);
buffer.reserve(8 + requestSize);
@ -604,7 +604,7 @@ void MTPabstractTcpConnection::socketRead() {
}
MTPautoConnection::MTPautoConnection(QThread *thread) : status(WaitingBoth),
tcpNonce(MTP::nonce<MTPint128>()), httpNonce(MTP::nonce<MTPint128>()) {
tcpNonce(MTP::nonce<MTPint128>()), httpNonce(MTP::nonce<MTPint128>()), _tcpTimeout(1) {
moveToThread(thread);
manager.moveToThread(thread);
@ -613,6 +613,9 @@ tcpNonce(MTP::nonce<MTPint128>()), httpNonce(MTP::nonce<MTPint128>()) {
httpStartTimer.moveToThread(thread);
httpStartTimer.setSingleShot(true);
connect(&httpStartTimer, SIGNAL(timeout()), this, SLOT(onHttpStart()));
tcpTimeoutTimer.moveToThread(thread);
tcpTimeoutTimer.setSingleShot(true);
connect(&tcpTimeoutTimer, SIGNAL(timeout()), this, SLOT(onTcpTimeoutTimer()));
sock.moveToThread(thread);
sock.setProxy(QNetworkProxy(QNetworkProxy::NoProxy));
@ -627,7 +630,7 @@ void MTPautoConnection::onHttpStart() {
if (status == HttpReady) {
DEBUG_LOG(("Connection Info: Http-transport chosen by timer"));
status = UsingHttp;
sock.disconnect();
sock.disconnectFromHost();
emit connected();
}
}
@ -638,13 +641,37 @@ void MTPautoConnection::onSocketConnected() {
DEBUG_LOG(("Connection Info: sending fake req_pq through tcp transport"));
if (_tcpTimeout < 0) _tcpTimeout = -_tcpTimeout;
tcpTimeoutTimer.start(_tcpTimeout * 1000);
tcpSend(buffer);
} else if (status == WaitingHttp || status == UsingHttp) {
sock.disconnect();
sock.disconnectFromHost();
}
}
void MTPautoConnection::onTcpTimeoutTimer() {
if (status == HttpReady || status == WaitingBoth || status == WaitingTcp) {
if (_tcpTimeout < 64) _tcpTimeout *= 2;
_tcpTimeout = -_tcpTimeout;
QAbstractSocket::SocketState state = sock.state();
if (state == QAbstractSocket::ConnectedState || state == QAbstractSocket::ConnectingState || state == QAbstractSocket::HostLookupState) {
sock.disconnectFromHost();
} else if (state != QAbstractSocket::ClosingState) {
sock.connectToHost(QHostAddress(_addr), _port);
}
}
}
void MTPautoConnection::onSocketDisconnected() {
if (_tcpTimeout < 0) {
_tcpTimeout = -_tcpTimeout;
if (status == HttpReady || status == WaitingBoth || status == WaitingTcp) {
sock.connectToHost(QHostAddress(_addr), _port);
return;
}
}
if (status == WaitingBoth) {
status = WaitingHttp;
} else if (status == WaitingTcp || status == UsingTcp) {
@ -725,14 +752,17 @@ void MTPautoConnection::connectToServer(const QString &addr, int32 port) {
address = QUrl(qsl("http://%1:%2/api").arg(addr).arg(80));//not port - always 80 port for http transport
connect(&manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestFinished(QNetworkReply*)));
_addr = addr;
_port = port;
connect(&sock, SIGNAL(readyRead()), this, SLOT(socketRead()));
sock.connectToHost(QHostAddress(_addr), _port);
mtpBuffer buffer(_preparePQFake(httpNonce));
DEBUG_LOG(("Connection Info: sending fake req_pq through http transport"));
httpSend(buffer);
sock.connectToHost(QHostAddress(addr), port);
connect(&sock, SIGNAL(readyRead()), this, SLOT(socketRead()));
}
bool MTPautoConnection::isConnected() {
@ -766,7 +796,7 @@ void MTPautoConnection::requestFinished(QNetworkReply *reply) {
} else {
DEBUG_LOG(("Connection Info: Http-transport chosen by pq-response, awaited"));
status = UsingHttp;
sock.disconnect();
sock.disconnectFromHost();
emit connected();
}
}
@ -786,7 +816,7 @@ void MTPautoConnection::requestFinished(QNetworkReply *reply) {
return;
}
bool mayBeBadKey = _handleHttpError(reply);
bool mayBeBadKey = _handleHttpError(reply) && _sentEncrypted;
if (status == WaitingBoth) {
status = WaitingTcp;
} else if (status == WaitingHttp || status == UsingHttp) {
@ -802,14 +832,15 @@ void MTPautoConnection::socketPacket(mtpPrime *packet, uint32 size) {
if (data.size() == 1) {
if (status == WaitingBoth) {
status = WaitingHttp;
sock.disconnect();
sock.disconnectFromHost();
} else if (status == HttpReady) {
DEBUG_LOG(("Connection Info: Http-transport chosen by bad tcp response, ready"));
status = UsingHttp;
sock.disconnect();
sock.disconnectFromHost();
emit connected();
} else if (status == WaitingTcp || status == UsingTcp) {
emit error(data[0] == -404);
bool mayBeBadKey = (data[0] == -404) && _sentEncrypted;
emit error(mayBeBadKey);
} else {
LOG(("Strange Tcp Error; status %1").arg(status));
}
@ -817,6 +848,7 @@ void MTPautoConnection::socketPacket(mtpPrime *packet, uint32 size) {
receivedQueue.push_back(data);
emit receivedData();
} else if (status == WaitingBoth || status == WaitingTcp || status == HttpReady) {
tcpTimeoutTimer.stop();
try {
MTPResPQ res_pq = _readPQFakeReply(data);
const MTPDresPQ &res_pq_data(res_pq.c_resPQ());
@ -828,11 +860,11 @@ void MTPautoConnection::socketPacket(mtpPrime *packet, uint32 size) {
} catch (Exception &e) {
if (status == WaitingBoth) {
status = WaitingHttp;
sock.disconnect();
sock.disconnectFromHost();
} else if (status == HttpReady) {
DEBUG_LOG(("Connection Info: Http-transport chosen by bad tcp response, awaited"));
status = UsingHttp;
sock.disconnect();
sock.disconnectFromHost();
emit connected();
} else {
emit error();
@ -907,14 +939,15 @@ void MTPtcpConnection::disconnectFromServer() {
}
void MTPtcpConnection::connectToServer(const QString &addr, int32 port) {
sock.connectToHost(QHostAddress(addr), port);
connect(&sock, SIGNAL(readyRead()), this, SLOT(socketRead()));
sock.connectToHost(QHostAddress(addr), port);
}
void MTPtcpConnection::socketPacket(mtpPrime *packet, uint32 size) {
mtpBuffer data = _handleTcpResponse(packet, size);
if (data.size() == 1) {
emit error(data[0] == -404);
bool mayBeBadKey = (data[0] == -404) && _sentEncrypted;
emit error(mayBeBadKey);
}
receivedQueue.push_back(data);
@ -1002,7 +1035,7 @@ void MTPhttpConnection::requestFinished(QNetworkReply *reply) {
return;
}
bool mayBeBadKey = _handleHttpError(reply);
bool mayBeBadKey = _handleHttpError(reply) && _sentEncrypted;
emit error(mayBeBadKey);
}
@ -1362,6 +1395,7 @@ void MTProtoConnectionPrivate::tryToSend() {
return;
}
bool needsLayer = !sessionData->layerWasInited();
bool prependOnly = false;
mtpRequest pingRequest;
if (toSendPingId) {
@ -1370,7 +1404,7 @@ void MTProtoConnectionPrivate::tryToSend() {
prependOnly = (getState() != MTProtoConnection::Connected);
DEBUG_LOG(("MTP Info: sending ping, ping_id: %1, prepend_only: %2").arg(ping.vping_id.v).arg(prependOnly ? "[TRUE]" : "[FALSE]"));
uint32 pingSize = ping.size() >> 2; // copy from MTProtoSession::send
uint32 pingSize = ping.innerLength() >> 2; // copy from MTProtoSession::send
pingRequest = mtpRequestData::prepare(pingSize);
ping.write(*pingRequest);
@ -1391,7 +1425,7 @@ void MTProtoConnectionPrivate::tryToSend() {
if (!prependOnly && !ackRequestData.isEmpty()) {
MTPMsgsAck ack(MTP_msgs_ack(MTP_vector<MTPlong>(ackRequestData)));
ackRequest = mtpRequestData::prepare(ack.size() >> 2);
ackRequest = mtpRequestData::prepare(ack.innerLength() >> 2);
ack.write(*ackRequest);
ackRequest->msDate = getms(true); // > 0 - can send without container
@ -1402,7 +1436,7 @@ void MTProtoConnectionPrivate::tryToSend() {
if (!prependOnly && !resendRequestData.isEmpty()) {
MTPMsgResendReq resend(MTP_msg_resend_req(MTP_vector<MTPlong>(resendRequestData)));
resendRequest = mtpRequestData::prepare(resend.size() >> 2);
resendRequest = mtpRequestData::prepare(resend.innerLength() >> 2);
resend.write(*resendRequest);
resendRequest->msDate = getms(true); // > 0 - can send without container
@ -1426,7 +1460,7 @@ void MTProtoConnectionPrivate::tryToSend() {
if (!stateReq.isEmpty()) {
MTPMsgsStateReq req(MTP_msgs_state_req(MTP_vector<MTPlong>(stateReq)));
stateRequest = mtpRequestData::prepare(req.size() >> 2);
stateRequest = mtpRequestData::prepare(req.innerLength() >> 2);
req.write(*stateRequest);
stateRequest->msDate = getms(true); // > 0 - can send without container
@ -1434,6 +1468,14 @@ void MTProtoConnectionPrivate::tryToSend() {
}
}
MTPInitConnection<mtpRequest> initWrapperImpl, *initWrapper = &initWrapperImpl;
int32 initSize = 0, initSizeInInts = 0;
if (needsLayer) {
initWrapperImpl = MTPInitConnection<mtpRequest>(MTP_int(ApiId), MTP_string(cApiDeviceModel()), MTP_string(cApiSystemVersion()), MTP_string(cApiAppVersion()), MTP_string(ApiLang), mtpRequest());
initSizeInInts = (initWrapper->innerLength() >> 2) + 2;
initSize = initSizeInInts * sizeof(mtpPrime);
}
bool needAnyResponse = false;
mtpRequest toSendRequest;
{
@ -1473,14 +1515,27 @@ void MTProtoConnectionPrivate::tryToSend() {
QWriteLocker locker2(sessionData->haveSentMutex());
mtpRequestMap &haveSent(sessionData->haveSentMap());
haveSent.insert(msgId, toSendRequest);
if (needsLayer && !toSendRequest->needsLayer) needsLayer = false;
if (toSendRequest->after) {
int32 toSendSize = toSendRequest->at(7) >> 2;
int32 toSendSize = toSendRequest.innerLength() >> 2;
mtpRequest wrappedRequest(mtpRequestData::prepare(toSendSize, toSendSize + 3)); // cons + msg_id
wrappedRequest->resize(4);
memcpy(wrappedRequest->data(), toSendRequest->constData(), 4 * sizeof(mtpPrime));
_mtp_internal::wrapInvokeAfter(wrappedRequest, toSendRequest, haveSent);
toSendRequest = wrappedRequest;
}
if (needsLayer) {
int32 noWrapSize = (toSendRequest.innerLength() >> 2), toSendSize = noWrapSize + initSizeInInts;
mtpRequest wrappedRequest(mtpRequestData::prepare(toSendSize));
memcpy(wrappedRequest->data(), toSendRequest->constData(), 7 * sizeof(mtpPrime)); // all except length
wrappedRequest->push_back(mtpc_invokeWithLayer);
wrappedRequest->push_back(mtpCurrentLayer);
initWrapper->write(*wrappedRequest);
wrappedRequest->resize(wrappedRequest->size() + noWrapSize);
memcpy(wrappedRequest->data() + wrappedRequest->size() - noWrapSize, toSendRequest->constData() + 8, noWrapSize * sizeof(mtpPrime));
toSendRequest = wrappedRequest;
}
needAnyResponse = true;
} else {
@ -1489,6 +1544,7 @@ void MTProtoConnectionPrivate::tryToSend() {
}
}
} else { // send in container
bool willNeedInit = false;
uint32 containerSize = 1 + 1, idsWrapSize = (toSendCount << 1); // cons + vector size, idsWrapSize - size of "request-like" wrap for msgId vector
if (pingRequest) containerSize += mtpRequestData::messageSize(pingRequest);
if (ackRequest) containerSize += mtpRequestData::messageSize(ackRequest);
@ -1496,6 +1552,17 @@ void MTProtoConnectionPrivate::tryToSend() {
if (stateRequest) containerSize += mtpRequestData::messageSize(stateRequest);
for (mtpPreRequestMap::iterator i = toSend.begin(), e = toSend.end(); i != e; ++i) {
containerSize += mtpRequestData::messageSize(i.value());
if (needsLayer && i.value()->needsLayer) {
containerSize += initSizeInInts;
willNeedInit = true;
}
}
mtpBuffer initSerialized;
if (willNeedInit) {
initSerialized.reserve(initSizeInInts);
initSerialized.push_back(mtpc_invokeWithLayer);
initSerialized.push_back(mtpCurrentLayer);
initWrapper->write(initSerialized);
}
toSendRequest = mtpRequestData::prepare(containerSize, containerSize + 3 * toSend.size()); // prepare container + each in invoke after
toSendRequest->push_back(mtpc_msg_container);
@ -1530,8 +1597,20 @@ void MTProtoConnectionPrivate::tryToSend() {
if (req->requestId) {
if (mtpRequestData::needAck(req)) {
req->msDate = mtpRequestData::isStateRequest(req) ? 0 : getms(true);
int32 reqNeedsLayer = (needsLayer && req->needsLayer) ? toSendRequest->size() : 0;
if (req->after) {
_mtp_internal::wrapInvokeAfter(toSendRequest, req, haveSent);
_mtp_internal::wrapInvokeAfter(toSendRequest, req, haveSent, reqNeedsLayer ? initSizeInInts : 0);
if (reqNeedsLayer) {
memcpy(toSendRequest->data() + reqNeedsLayer + 4, initSerialized.constData(), initSize);
*(toSendRequest->data() + reqNeedsLayer + 3) += initSize;
}
added = true;
} else if (reqNeedsLayer) {
toSendRequest->resize(reqNeedsLayer + initSizeInInts + mtpRequestData::messageSize(req));
memcpy(toSendRequest->data() + reqNeedsLayer, req->constData() + 4, 4 * sizeof(mtpPrime));
memcpy(toSendRequest->data() + reqNeedsLayer + 4, initSerialized.constData(), initSize);
memcpy(toSendRequest->data() + reqNeedsLayer + 4 + initSizeInInts, req->constData() + 8, req.innerLength());
*(toSendRequest->data() + reqNeedsLayer + 3) += initSize;
added = true;
}
haveSent.insert(msgId, req);
@ -2329,6 +2408,10 @@ int32 MTProtoConnectionPrivate::handleOneReceived(const mtpPrime *from, const mt
response.resize(end - from);
memcpy(response.data(), from, (end - from) * sizeof(mtpPrime));
}
if (!sessionData->layerWasInited()) {
sessionData->setLayerWasInited(true);
sessionData->owner()->notifyLayerInited(true);
}
mtpRequestId requestId = wasSent(reqMsgId.v);
if (requestId && requestId != mtpRequestId(0xFFFFFFFF)) {
@ -2787,7 +2870,7 @@ void MTProtoConnectionPrivate::pqAnswered() {
string &dhEncString(req_DH_params.vencrypted_data._string().v);
uint32 p_q_inner_size = p_q_inner.size(), encSize = (p_q_inner_size >> 2) + 6;
uint32 p_q_inner_size = p_q_inner.innerLength(), encSize = (p_q_inner_size >> 2) + 6;
if (encSize >= 65) {
mtpBuffer tmp;
tmp.reserve(encSize);
@ -2854,7 +2937,7 @@ void MTProtoConnectionPrivate::dhParamsAnswered() {
return restart();
}
uint32 nlen = authKeyData->new_nonce.size(), slen = authKeyData->server_nonce.size();
uint32 nlen = authKeyData->new_nonce.innerLength(), slen = authKeyData->server_nonce.innerLength();
uchar tmp_aes[1024], sha1ns[20], sha1sn[20], sha1nn[20];
memcpy(tmp_aes, &authKeyData->new_nonce, nlen);
memcpy(tmp_aes + nlen, &authKeyData->server_nonce, slen);
@ -2979,7 +3062,7 @@ void MTProtoConnectionPrivate::dhClientParamsSend() {
string &sdhEncString(req_client_DH_params.vencrypted_data._string().v);
uint32 client_dh_inner_size = client_dh_inner.size(), encSize = (client_dh_inner_size >> 2) + 5, encFullSize = encSize;
uint32 client_dh_inner_size = client_dh_inner.innerLength(), encSize = (client_dh_inner_size >> 2) + 5, encFullSize = encSize;
if (encSize & 0x03) {
encFullSize += 4 - (encSize & 0x03);
}
@ -3047,7 +3130,7 @@ void MTProtoConnectionPrivate::dhClientParamsAnswered() {
DEBUG_LOG(("AuthKey Info: auth key gen succeed, id: %1, server salt: %2, auth key: %3").arg(authKey->keyId()).arg(serverSalt).arg(mb(authKeyData->auth_key, 256).str()));
sessionData->owner()->keyCreated(authKey); // slot will call authKeyCreated()
sessionData->owner()->notifyKeyCreated(authKey); // slot will call authKeyCreated()
sessionData->clear();
unlockKey();
} return;
@ -3146,7 +3229,7 @@ void MTProtoConnectionPrivate::sendPing() {
}
void MTProtoConnectionPrivate::onError(bool mayBeBadKey) {
MTP_LOG(dc, ("Restarting after error.."));
MTP_LOG(dc, ("Restarting after error, maybe bad key: %1..").arg(logBool(mayBeBadKey)));
return restart(mayBeBadKey);
}
@ -3157,7 +3240,7 @@ template <typename TRequest>
void MTProtoConnectionPrivate::sendRequestNotSecure(const TRequest &request) {
try {
mtpBuffer buffer;
uint32 requestSize = request.size() >> 2;
uint32 requestSize = request.innerLength() >> 2;
buffer.resize(0);
buffer.reserve(8 + requestSize);
@ -3264,6 +3347,7 @@ bool MTProtoConnectionPrivate::sendRequest(mtpRequest &request, bool needAnyResp
DEBUG_LOG(("MTP Info: sending request, size: %1, num: %2, time: %3").arg(fullSize + 6).arg((*request)[4]).arg((*request)[5]));
conn->setSentEncrypted();
conn->sendData(result);
if (needAnyResponse) {

View File

@ -106,6 +106,13 @@ class MTPabstractConnection : public QObject {
public:
MTPabstractConnection() : _sentEncrypted(false) {
}
void setSentEncrypted() {
_sentEncrypted = true;
}
virtual void sendData(mtpBuffer &buffer) = 0; // has size + 3, buffer[0] = len, buffer[1] = packetnum, buffer[last] = crc32
virtual void disconnectFromServer() = 0;
virtual void connectToServer(const QString &addr, int32 port) = 0;
@ -135,6 +142,7 @@ signals:
protected:
BuffersQueue receivedQueue; // list of received packets, not processed yet
bool _sentEncrypted;
};
@ -189,6 +197,8 @@ public slots:
void onSocketDisconnected();
void onHttpStart();
void onTcpTimeoutTimer();
protected:
void socketPacket(mtpPrime *packet, uint32 packetSize);
@ -215,6 +225,10 @@ private:
typedef QSet<QNetworkReply*> Requests;
Requests requests;
QString _addr;
int32 _port, _tcpTimeout;
QTimer tcpTimeoutTimer;
};
class MTPtcpConnection : public MTPabstractTcpConnection {

View File

@ -172,12 +172,20 @@ void mtpTextSerializeCore(MTPStringLogger &to, const mtpPrime *&from, const mtpP
} break;
default: {
for (uint32 i = 1; i < mtpLayerMax; ++i) {
for (uint32 i = 1; i < mtpLayerMaxSingle; ++i) {
if (cons == mtpLayers[i]) {
to.add("[LAYER").add(mtpWrapNumber(i + 1)).add("] "); mtpTextSerializeType(to, from, end, 0, level);
return;
}
}
if (cons == mtpc_invokeWithLayer) {
if (from >= end) {
throw Exception("from >= end in invokeWithLayer");
}
int32 layer = *(from++);
to.add("[LAYER").add(mtpWrapNumber(layer)).add("] "); mtpTextSerializeType(to, from, end, 0, level);
return;
}
throw Exception(QString("unknown cons 0x%1").arg(cons, 0, 16));
} break;
}

View File

@ -62,7 +62,7 @@ public:
explicit mtpRequest(mtpRequestData *ptr) : QSharedPointer<mtpRequestData>(ptr) {
}
uint32 size() const;
uint32 innerLength() const;
void write(mtpBuffer &to) const;
typedef void ResponseType; // don't know real response type =(
@ -74,10 +74,12 @@ public:
// in toSend: = 0 - must send in container, > 0 - can send without container
// in haveSent: = 0 - container with msgIds, > 0 - when was sent
uint64 msDate;
mtpRequestId requestId;
mtpRequest after;
bool needsLayer;
mtpRequestData(bool/* sure*/) : msDate(0), requestId(0) {
mtpRequestData(bool/* sure*/) : msDate(0), requestId(0), needsLayer(false) {
}
static mtpRequest prepare(uint32 requestSize, uint32 maxSize = 0) {
@ -92,7 +94,7 @@ public:
static void padding(mtpRequest &request) {
if (request->size() < 9) return;
uint32 requestSize = ((*request)[7] >> 2), padding = _padding(requestSize), fullSize = 8 + requestSize + padding; // 2: salt, 2: session_id, 2: msg_id, 1: seq_no, 1: message_length
uint32 requestSize = (request.innerLength() >> 2), padding = _padding(requestSize), fullSize = 8 + requestSize + padding; // 2: salt, 2: session_id, 2: msg_id, 1: seq_no, 1: message_length
if (uint32(request->size()) != fullSize) {
request->resize(fullSize);
if (padding) {
@ -103,7 +105,7 @@ public:
static uint32 messageSize(const mtpRequest &request) {
if (request->size() < 9) return 0;
return 4 + ((*request)[7] >> 2); // 2: msg_id, 1: seq_no, q: message_length
return 4 + (request.innerLength() >> 2); // 2: msg_id, 1: seq_no, q: message_length
}
static bool isSentContainer(const mtpRequest &request); // "request-like" wrap for msgIds vector
@ -119,7 +121,7 @@ private:
};
inline uint32 mtpRequest::size() const { // for template MTP requests and MTPBoxed instanciation
inline uint32 mtpRequest::innerLength() const { // for template MTP requests and MTPBoxed instanciation
mtpRequestData *value = data();
if (!value || value->size() < 9) return 0;
return value->at(7);
@ -128,7 +130,7 @@ inline uint32 mtpRequest::size() const { // for template MTP requests and MTPBox
inline void mtpRequest::write(mtpBuffer &to) const {
mtpRequestData *value = data();
if (!value || value->size() < 9) return;
uint32 was = to.size(), s = size() / sizeof(mtpPrime);
uint32 was = to.size(), s = innerLength() / sizeof(mtpPrime);
to.resize(was + s);
memcpy(to.data() + was, value->constData() + 8, s * sizeof(mtpPrime));
}
@ -335,6 +337,8 @@ enum {
mtpc_invokeWithLayer17 = 0x50858a19,
mtpc_invokeWithLayer18 = 0x1c900537,
mtpc_invokeWithLayer = 0xda9b0d0d, // after 18 layer
// manually parsed
mtpc_rpc_result = 0xf35c6d01,
mtpc_msg_container = 0x73f1f8dc,
@ -362,7 +366,8 @@ static const mtpTypeId mtpLayers[] = {
mtpc_invokeWithLayer16,
mtpc_invokeWithLayer17,
mtpc_invokeWithLayer18,
}, mtpLayerMax = sizeof(mtpLayers) / sizeof(mtpLayers[0]);
}, mtpLayerMaxSingle = sizeof(mtpLayers) / sizeof(mtpLayers[0]);
static const mtpPrime mtpCurrentLayer = 19;
template <typename bareT>
class MTPBoxed : public bareT {
@ -386,8 +391,8 @@ public:
return *this;
}
uint32 size() const {
return sizeof(mtpTypeId) + bareT::size();
uint32 innerLength() const {
return sizeof(mtpTypeId) + bareT::innerLength();
}
void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) {
if (from + 1 > end) throw mtpErrorInsufficient();
@ -414,7 +419,7 @@ public:
read(from, end, cons);
}
uint32 size() const {
uint32 innerLength() const {
return sizeof(int32);
}
mtpTypeId type() const {
@ -457,7 +462,7 @@ public:
read(from, end, cons);
}
uint32 size() const {
uint32 innerLength() const {
return sizeof(uint64);
}
mtpTypeId type() const {
@ -503,7 +508,7 @@ public:
read(from, end, cons);
}
uint32 size() const {
uint32 innerLength() const {
return sizeof(uint64) + sizeof(uint64);
}
mtpTypeId type() const {
@ -552,8 +557,8 @@ public:
read(from, end, cons);
}
uint32 size() const {
return l.size() + h.size();
uint32 innerLength() const {
return l.innerLength() + h.innerLength();
}
mtpTypeId type() const {
return mtpc_int256;
@ -596,7 +601,7 @@ public:
read(from, end, cons);
}
uint32 size() const {
uint32 innerLength() const {
return sizeof(float64);
}
mtpTypeId type() const {
@ -666,7 +671,7 @@ public:
return *(const MTPDstring*)data;
}
uint32 size() const {
uint32 innerLength() const {
uint32 l = c_string().v.length();
if (l < 254) {
l += 1;
@ -770,7 +775,7 @@ public:
read(from, end, cons);
}
uint32 size() const {
uint32 innerLength() const {
return 0;
}
mtpTypeId type() const {
@ -858,10 +863,10 @@ public:
return *(const MTPDvector<T>*)data;
}
uint32 size() const {
uint32 innerLength() const {
uint32 result(sizeof(uint32));
for (typename VType::const_iterator i = c_vector().v.cbegin(), e = c_vector().v.cend(); i != e; ++i) {
result += i->size();
result += i->innerLength();
}
return result;
}
@ -961,8 +966,8 @@ public:
return *(const MTPDerror*)data;
}
uint32 size() const {
return c_error().vcode.size() + c_error().vtext.size();
uint32 innerLength() const {
return c_error().vcode.innerLength() + c_error().vtext.innerLength();
}
mtpTypeId type() const {
return mtpc_error;
@ -999,7 +1004,7 @@ public:
read(from, end, cons);
}
uint32 size() const {
uint32 innerLength() const {
return 0;
}
mtpTypeId type() const {

View File

@ -350,7 +350,7 @@ void mtpSetDC(int32 dc) {
}
}
MTProtoDC::MTProtoDC(int32 id, const mtpAuthKeyPtr &key) : _id(id), _key(key), _connectionInited(false), _connectionInitSent(false) {
MTProtoDC::MTProtoDC(int32 id, const mtpAuthKeyPtr &key) : _id(id), _key(key), _connectionInited(false) {
connect(this, SIGNAL(authKeyCreated()), this, SLOT(authKeyWrite()), Qt::QueuedConnection);
QMutexLocker lock(&_keysMapForWriteMutex);
@ -371,6 +371,7 @@ void MTProtoDC::authKeyWrite() {
void MTProtoDC::setKey(const mtpAuthKeyPtr &key) {
DEBUG_LOG(("AuthKey Info: MTProtoDC::setKey(%1), emitting authKeyCreated, dc %2").arg(key ? key->keyId() : 0).arg(_id));
_key = key;
_connectionInited = false;
emit authKeyCreated();
QMutexLocker lock(&_keysMapForWriteMutex);

View File

@ -29,13 +29,6 @@ public:
void setKey(const mtpAuthKeyPtr &key);
void destroyKey();
bool needConnectionInit() {
QMutexLocker lock(&initLock);
if (_connectionInited || _connectionInitSent) return false;
_connectionInitSent = true;
return true;
}
bool connectionInited() const {
QMutexLocker lock(&initLock);
bool res = _connectionInited;
@ -49,6 +42,7 @@ public:
signals:
void authKeyCreated();
void layerWasInited(bool was);
private slots:
@ -61,7 +55,6 @@ private:
int32 _id;
mtpAuthKeyPtr _key;
bool _connectionInited;
bool _connectionInitSent;
};
typedef QSharedPointer<MTProtoDC> MTProtoDCPtr;

View File

@ -174,8 +174,7 @@ bool mtpFileLoader::loadPart() {
App::app()->killDownloadSessionsStop(dc);
}
MTPupload_GetFile request(MTPupload_getFile(loc, MTP_int(offset), MTP_int(limit)));
mtpRequestId reqId = MTP::send(request, rpcDone(&mtpFileLoader::partLoaded, offset), rpcFail(&mtpFileLoader::partFailed), MTP::dld[dcIndex] + dc, 50);
mtpRequestId reqId = MTP::send(MTPupload_GetFile(MTPupload_getFile(loc, MTP_int(offset), MTP_int(limit))), rpcDone(&mtpFileLoader::partLoaded, offset), rpcFail(&mtpFileLoader::partFailed), MTP::dld[dcIndex] + dc, 50);
++queue->queries;
dr.v[dcIndex] += limit;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -113,8 +113,11 @@ void MTProtoSession::start(int32 dcenter, uint32 connects) {
ReadLockerAttempt lock(keyMutex());
data.setKey(lock ? dc->getKey() : mtpAuthKeyPtr(0));
if (lock && dc->connectionInited()) {
data.setLayerWasInited(true);
}
connect(dc.data(), SIGNAL(authKeyCreated()), this, SLOT(authKeyCreatedForDC()));
connect(dc.data(), SIGNAL(layerWasInited(bool)), this, SLOT(layerWasInitedForDC(bool)));
}
}
}
@ -376,21 +379,9 @@ void MTProtoSession::sendPrepared(const mtpRequest &request, uint64 msCanWait, b
sendAnything(msCanWait);
}
void MTProtoSession::sendPreparedWithInit(const mtpRequest &request, uint64 msCanWait) { // returns true, if emit of needToSend() is needed
if (request->size() > 8 && request->at(8) == mtpc_initConnection) {
sendPrepared(request, msCanWait, false);
return;
}
{
MTPInitConnection<mtpRequest> requestWrap(MTPinitConnection<mtpRequest>(MTP_int(ApiId), MTP_string(cApiDeviceModel()), MTP_string(cApiSystemVersion()), MTP_string(cApiAppVersion()), MTP_string(ApiLang), request));
uint32 requestSize = requestWrap.size() >> 2;
mtpRequest reqSerialized(mtpRequestData::prepare(requestSize));
requestWrap.write(*reqSerialized);
request->resize(reqSerialized->size());
memcpy(request->data(), reqSerialized->constData(), reqSerialized->size());
}
request->msDate = getms(true); // > 0 - can send without container
sendPrepared(request, msCanWait);
void MTProtoSession::sendPreparedWithInit(const mtpRequest &request, uint64 msCanWait) {
request->needsLayer = true;
sendPrepared(request, msCanWait, false);
}
QReadWriteLock *MTProtoSession::keyMutex() const {
@ -403,11 +394,22 @@ void MTProtoSession::authKeyCreatedForDC() {
emit authKeyCreated();
}
void MTProtoSession::keyCreated(const mtpAuthKeyPtr &key) {
void MTProtoSession::notifyKeyCreated(const mtpAuthKeyPtr &key) {
DEBUG_LOG(("AuthKey Info: MTProtoSession::keyCreated(), setting, dc %1").arg(dcId));
dc->setKey(key);
}
void MTProtoSession::layerWasInitedForDC(bool wasInited) {
DEBUG_LOG(("MTP Info: MTProtoSession::layerWasInitedForDC slot, dc %1").arg(dcId));
data.setLayerWasInited(wasInited);
}
void MTProtoSession::notifyLayerInited(bool wasInited) {
DEBUG_LOG(("MTP Info: emitting MTProtoDC::layerWasInited(%1), dc %2").arg(logBool(wasInited)).arg(dcId));
dc->setConnectionInited(wasInited);
emit dc->layerWasInited(wasInited);
}
void MTProtoSession::destroyKey() {
if (!dc) return;

View File

@ -28,8 +28,8 @@ public:
MTPSessionData(MTProtoSession *creator)
: _session(0), _salt(0)
, _messagesSent(0), fakeRequestId(-2000000000)
, _owner(creator), keyChecked(false) {
, _messagesSent(0), _fakeRequestId(-2000000000)
, _owner(creator), _keyChecked(false), _layerInited(false) {
}
void setSession(uint64 session) {
@ -45,6 +45,14 @@ public:
QReadLocker locker(&lock);
return _session;
}
bool layerWasInited() const {
QReadLocker locker(&lock);
return _layerInited;
}
void setLayerWasInited(bool was) {
QWriteLocker locker(&lock);
_layerInited = was;
}
void setSalt(uint64 salt) {
QWriteLocker locker(&lock);
@ -56,26 +64,31 @@ public:
}
const mtpAuthKeyPtr &getKey() const {
return authKey;
return _authKey;
}
void setKey(const mtpAuthKeyPtr &key) {
if (authKey != key) {
if (_authKey != key) {
uint64 session;
memsetrnd(session);
authKey = key;
_authKey = key;
DEBUG_LOG(("MTP Info: new auth key set in SessionData, id %1, setting random server_session %2").arg(key ? key->keyId() : 0).arg(session));
setSession(session);
QWriteLocker locker(&lock);
if (_session != session) {
_session = session;
_messagesSent = 0;
}
_layerInited = false;
}
}
bool isCheckedKey() const {
QReadLocker locker(&lock);
return keyChecked;
return _keyChecked;
}
void setCheckedKey(bool checked) {
QWriteLocker locker(&lock);
keyChecked = checked;
_keyChecked = checked;
}
QReadWriteLock *keyMutex() const;
@ -147,11 +160,11 @@ public:
mtpRequestId nextFakeRequestId() { // must be locked by haveReceivedMutex()
if (haveReceived.isEmpty() || haveReceived.cbegin().key() > 0) {
fakeRequestId = -2000000000;
_fakeRequestId = -2000000000;
} else {
++fakeRequestId;
++_fakeRequestId;
}
return fakeRequestId;
return _fakeRequestId;
}
MTProtoSession *owner() {
@ -174,12 +187,12 @@ private:
uint64 _session, _salt;
uint32 _messagesSent;
mtpRequestId fakeRequestId;
mtpRequestId _fakeRequestId;
MTProtoSession *_owner;
mtpAuthKeyPtr authKey;
bool keyChecked;
mtpAuthKeyPtr _authKey;
bool _keyChecked, _layerInited;
mtpPreRequestMap toSend; // map of request_id -> request, that is waiting to be sent
mtpRequestMap haveSent; // map of msg_id -> request, that was sent, msDate = 0 for msgs_state_req (no resend / state req), msDate = 0, seqNo = 0 for containers
@ -216,11 +229,12 @@ public:
~MTProtoSession();
QReadWriteLock *keyMutex() const;
void keyCreated(const mtpAuthKeyPtr &key);
void notifyKeyCreated(const mtpAuthKeyPtr &key);
void destroyKey();
void notifyLayerInited(bool wasInited);
template <typename TRequest>
mtpRequestId send(const TRequest &request, RPCResponseHandler callbacks = RPCResponseHandler(), uint64 msCanWait = 0, uint32 layer = 0, bool toMainDC = false, mtpRequestId after = 0); // send mtp request
mtpRequestId send(const TRequest &request, RPCResponseHandler callbacks = RPCResponseHandler(), uint64 msCanWait = 0, bool needsLayer = false, bool toMainDC = false, mtpRequestId after = 0); // send mtp request
void sendAnything(uint64 msCanWait);
void cancel(mtpRequestId requestId, mtpMsgId msgId);
@ -247,6 +261,7 @@ signals:
public slots:
void authKeyCreatedForDC();
void layerWasInitedForDC(bool wasInited);
void tryToReceive();
void checkRequestsByTimer();
@ -255,9 +270,6 @@ public slots:
private:
template <typename TRequest>
mtpRequestId sendFirst(const MTPInitConnection<TRequest> &request, RPCResponseHandler callbacks = RPCResponseHandler(), uint64 msCanWait = 0, uint32 layer = 0, bool toMainDC = false, mtpRequestId after = 0); // send first mtp request
typedef QList<MTProtoConnection*> MTProtoConnections;
MTProtoConnections connections;

View File

@ -18,22 +18,17 @@ Copyright (c) 2014 John Preston, https://tdesktop.com
#pragma once
template <typename TRequest>
mtpRequestId MTProtoSession::send(const TRequest &request, RPCResponseHandler callbacks, uint64 msCanWait, uint32 layer, bool toMainDC, mtpRequestId after) {
mtpRequestId MTProtoSession::send(const TRequest &request, RPCResponseHandler callbacks, uint64 msCanWait, bool needsLayer, bool toMainDC, mtpRequestId after) {
mtpRequestId requestId = 0;
if (layer && dc->needConnectionInit()) {
MTPInitConnection<TRequest> requestWrap(MTPinitConnection<TRequest>(MTP_int(ApiId), MTP_string(cApiDeviceModel()), MTP_string(cApiSystemVersion()), MTP_string(cApiAppVersion()), MTP_string(ApiLang), request));
return sendFirst(requestWrap, callbacks, msCanWait, layer, toMainDC, after);
}
try {
uint32 requestSize = request.size() >> 2;
if (dc->connectionInited()) layer = 0;
mtpRequest reqSerialized(mtpRequestData::prepare(requestSize + (layer ? 1 : 0)));
if (layer) reqSerialized->push_back(mtpLayers[layer]);
uint32 requestSize = request.innerLength() >> 2;
mtpRequest reqSerialized(mtpRequestData::prepare(requestSize));
request.write(*reqSerialized);
DEBUG_LOG(("MTP Info: adding request to toSendMap, msCanWait %1").arg(msCanWait));
reqSerialized->msDate = getms(true); // > 0 - can send without container
reqSerialized->needsLayer = needsLayer;
if (after) reqSerialized->after = _mtp_internal::getRequest(after);
requestId = _mtp_internal::storeRequest(reqSerialized, callbacks);
@ -45,44 +40,3 @@ mtpRequestId MTProtoSession::send(const TRequest &request, RPCResponseHandler ca
if (requestId) _mtp_internal::registerRequest(requestId, toMainDC ? -getDC() : getDC());
return requestId;
}
class RPCWrappedDcDoneHandler : public RPCAbstractDoneHandler {
public:
RPCWrappedDcDoneHandler(const MTProtoDCPtr &dc, const RPCDoneHandlerPtr &ondone) : _dc(dc), _ondone(ondone) {
}
void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const {
_dc->setConnectionInited();
if (_ondone) (*_ondone)(requestId, from, end);
}
private:
MTProtoDCPtr _dc;
RPCDoneHandlerPtr _ondone;
};
template <typename TRequest>
mtpRequestId MTProtoSession::sendFirst(const MTPInitConnection<TRequest> &request, RPCResponseHandler callbacks, uint64 msCanWait, uint32 layer, bool toMainDC, mtpRequestId after) {
mtpRequestId requestId = 0;
try {
uint32 requestSize = request.size() >> 2;
mtpRequest reqSerialized(mtpRequestData::prepare(requestSize + (layer ? 1 : 0)));
if (layer) reqSerialized->push_back(mtpLayers[layer]);
request.write(*reqSerialized);
DEBUG_LOG(("MTP Info: adding wrapped to init connection request to toSendMap, msCanWait %1").arg(msCanWait));
callbacks.onDone = RPCDoneHandlerPtr(new RPCWrappedDcDoneHandler(dc, callbacks.onDone));
reqSerialized->msDate = getms(true); // > 0 - can send without container
if (after) reqSerialized->after = _mtp_internal::getRequest(after);
requestId = _mtp_internal::storeRequest(reqSerialized, callbacks);
sendPrepared(reqSerialized, msCanWait);
} catch (Exception &e) {
requestId = 0;
_mtp_internal::rpcErrorOccured(requestId, callbacks, rpcClientError("NO_REQUEST_ID", QString("sendFirst() failed to queue request, exception: %1").arg(e.what())));
}
if (requestId) {
_mtp_internal::registerRequest(requestId, toMainDC ? -getDC() : getDC());
}
return requestId;
}

View File

@ -13,7 +13,6 @@
/////////////////// Layer cons
///////////////////////////////
//invokeAfterMsg#cb9f372d msg_id:long query:!X = X;
//invokeAfterMsgs#3dc4b4f0 msg_ids:Vector<long> query:!X = X;
//invokeWithLayer1#53835315 query:!X = X;
@ -34,6 +33,7 @@
//invokeWithLayer16#cf5f0987 query:!X = X;
//invokeWithLayer17#50858a19 query:!X = X;
//invokeWithLayer18#1c900537 query:!X = X;
//invokeWithLayer#da9b0d0d layer:int query:!X = X; // after 18 layer
///////////////////////////////
/// Authorization key creation
@ -287,7 +287,7 @@ contactBlocked#561bc879 user_id:int date:int = ContactBlocked;
contactSuggested#3de191a1 user_id:int mutual_contacts:int = ContactSuggested;
contactStatus#aa77b873 user_id:int expires:int = ContactStatus;
contactStatus#d3680c61 user_id:int status:UserStatus = ContactStatus;
chatLocated#3631cf4c chat_id:int distance:int = ChatLocated;
@ -510,6 +510,34 @@ contacts.found#566000e results:Vector<ContactFound> users:Vector<User> = contact
updateServiceNotification#382dd3e4 type:string message:string media:MessageMedia popup:Bool = Update;
userStatusRecently#e26f42f1 = UserStatus;
userStatusLastWeek#7bf09fc = UserStatus;
userStatusLastMonth#77ebc742 = UserStatus;
updatePrivacy#ee3b272a key:PrivacyKey rules:Vector<PrivacyRule> = Update;
inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey;
privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey;
inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule;
inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule;
inputPrivacyValueAllowUsers#131cc67f users:Vector<InputUser> = InputPrivacyRule;
inputPrivacyValueDisallowContacts#ba52007 = InputPrivacyRule;
inputPrivacyValueDisallowAll#d66b66c9 = InputPrivacyRule;
inputPrivacyValueDisallowUsers#90110467 users:Vector<InputUser> = InputPrivacyRule;
privacyValueAllowContacts#fffe1bac = PrivacyRule;
privacyValueAllowAll#65427b82 = PrivacyRule;
privacyValueAllowUsers#4d5bbe0c users:Vector<int> = PrivacyRule;
privacyValueDisallowContacts#f888fa1a = PrivacyRule;
privacyValueDisallowAll#8b73e763 = PrivacyRule;
privacyValueDisallowUsers#c7f49b7 users:Vector<int> = PrivacyRule;
account.privacyRules#554abb6f rules:Vector<PrivacyRule> users:Vector<User> = account.PrivacyRules;
accountDaysTTL#b8d0afdf days:int = AccountDaysTTL;
---functions---
invokeAfterMsg#cb9f372d msg_id:long query:!X = X;
@ -631,3 +659,9 @@ account.checkUsername#2714d86c username:string = Bool;
account.updateUsername#3e0bdd7c username:string = User;
contacts.search#11f812d8 q:string limit:int = contacts.Found;
account.getPrivacy#dadbc950 key:InputPrivacyKey = account.PrivacyRules;
account.setPrivacy#c9f81ce8 key:InputPrivacyKey rules:Vector<InputPrivacyRule> = account.PrivacyRules;
account.deleteAccount#418d4e0b reason:string = Bool;
account.getAccountTTL#8fc711d = AccountDaysTTL;
account.setAccountTTL#2442485e ttl:AccountDaysTTL = Bool;

View File

@ -40,6 +40,7 @@ OverviewInner::OverviewInner(OverviewWidget *overview, ScrollArea *scroll, const
, _hist(App::history(peer->id))
, _photosInRow(1)
, _photosToAdd(0)
, _selMode(false)
, _width(0)
, _height(0)
, _minHeight(0)
@ -425,7 +426,7 @@ void OverviewInner::dragActionFinish(const QPoint &screenPos, Qt::MouseButton bu
dragActionUpdate(screenPos);
if (textlnkOver()) {
if (textlnkDown() == textlnkOver() && _dragAction != Dragging) {
if (textlnkDown() == textlnkOver() && _dragAction != Dragging && !_selMode) {
needClick = textlnkDown();
}
}
@ -662,7 +663,10 @@ void OverviewInner::paintEvent(QPaintEvent *e) {
}
}
if (sel == FullItemSel) {
p.fillRect(QRect(pos.x(), pos.y(), _vsize, _vsize), st::msgInSelectOverlay->b);
p.fillRect(QRect(pos.x(), pos.y(), _vsize, _vsize), st::overviewPhotoSelectOverlay->b);
p.drawPixmap(QPoint(pos.x() + _vsize - st::overviewPhotoChecked.pxWidth(), pos.y() + _vsize - st::overviewPhotoChecked.pxHeight()), App::sprite(), st::overviewPhotoChecked);
} else if (_selMode/* || (selfrom < count && selfrom <= selto && 0 <= selto)*/) {
p.drawPixmap(QPoint(pos.x() + _vsize - st::overviewPhotoChecked.pxWidth(), pos.y() + _vsize - st::overviewPhotoChecked.pxHeight()), App::sprite(), st::overviewPhotoCheck);
}
} break;
}
@ -1136,6 +1140,10 @@ void OverviewInner::switchType(MediaOverviewType type) {
if (App::wnd()) App::wnd()->update();
}
void OverviewInner::setSelectMode(bool enabled) {
_selMode = enabled;
}
void OverviewInner::openContextUrl() {
HistoryItem *was = App::hoveredLinkItem();
App::hoveredLinkItem(App::contextItem());
@ -1620,6 +1628,8 @@ MediaOverviewType OverviewWidget::type() const {
}
void OverviewWidget::switchType(MediaOverviewType type) {
_selCount = 0;
_inner.setSelectMode(false);
_inner.switchType(type);
switch (type) {
case OverviewPhotos: _header = lang(lng_profile_photos_header); break;
@ -1628,7 +1638,6 @@ void OverviewWidget::switchType(MediaOverviewType type) {
case OverviewAudios: _header = lang(lng_profile_audios_header); break;
}
noSelectingScroll();
_selCount = 0;
App::main()->topBar()->showSelected(0);
updateTopBarSelection();
_scroll.scrollToY(_scroll.scrollTopMax());
@ -1639,6 +1648,7 @@ void OverviewWidget::updateTopBarSelection() {
int32 selectedForForward, selectedForDelete;
_inner.getSelectionState(selectedForForward, selectedForDelete);
_selCount = selectedForDelete ? selectedForDelete : selectedForForward;
_inner.setSelectMode(_selCount > 0);
if (App::main()) {
App::main()->topBar()->showSelected(_selCount > 0 ? _selCount : 0);
App::main()->topBar()->update();

View File

@ -55,6 +55,8 @@ public:
MediaOverviewType type() const;
void switchType(MediaOverviewType type);
void setSelectMode(bool enabled);
void mediaOverviewUpdated();
void changingMsgId(HistoryItem *row, MsgId newId);
void msgUpdated(const HistoryItem *msg);
@ -124,6 +126,7 @@ private:
} CachedSize;
typedef QMap<PhotoData*, CachedSize> CachedSizes;
CachedSizes _cached;
bool _selMode;
// other
typedef struct _CachedItem {

View File

@ -11,7 +11,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>0.6.8</string>
<string>0.6.9</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>NOTE</key>

Binary file not shown.

View File

@ -1521,7 +1521,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 0.6.8;
CURRENT_PROJECT_VERSION = 0.6.9;
DEBUG_INFORMATION_FORMAT = dwarf;
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
@ -1539,7 +1539,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
COPY_PHASE_STRIP = YES;
CURRENT_PROJECT_VERSION = 0.6.8;
CURRENT_PROJECT_VERSION = 0.6.9;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_OPTIMIZATION_LEVEL = fast;
GCC_PREFIX_HEADER = ./SourceFiles/stdafx.h;
@ -1565,10 +1565,10 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 0.6.8;
CURRENT_PROJECT_VERSION = 0.6.9;
DEBUG_INFORMATION_FORMAT = dwarf;
DYLIB_COMPATIBILITY_VERSION = 0.6;
DYLIB_CURRENT_VERSION = 0.6.8;
DYLIB_CURRENT_VERSION = 0.6.9;
ENABLE_STRICT_OBJC_MSGSEND = YES;
FRAMEWORK_SEARCH_PATHS = "";
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
@ -1708,10 +1708,10 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 0.6.8;
CURRENT_PROJECT_VERSION = 0.6.9;
DEBUG_INFORMATION_FORMAT = dwarf;
DYLIB_COMPATIBILITY_VERSION = 0.6;
DYLIB_CURRENT_VERSION = 0.6.8;
DYLIB_CURRENT_VERSION = 0.6.9;
ENABLE_STRICT_OBJC_MSGSEND = YES;
FRAMEWORK_SEARCH_PATHS = "";
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;

View File

@ -0,0 +1,137 @@
/*************************************************
* Perl-Compatible Regular Expressions *
*************************************************/
/* PCRE is a library of functions to support regular expressions whose syntax
and semantics are as close as possible to those of the Perl 5 language.
Written by Philip Hazel
Copyright (c) 1997-2013 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the University of Cambridge nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
-----------------------------------------------------------------------------
*/
/* This module contains an internal function for validating UTF-16 character
strings. */
#ifdef PCRE_HAVE_CONFIG_H
#include "config.h"
#endif
/* Generate code with 16 bit character support. */
#define COMPILE_PCRE16
#include "pcre_internal.h"
/*************************************************
* Validate a UTF-16 string *
*************************************************/
/* This function is called (optionally) at the start of compile or match, to
check that a supposed UTF-16 string is actually valid. The early check means
that subsequent code can assume it is dealing with a valid string. The check
can be turned off for maximum performance, but the consequences of supplying an
invalid string are then undefined.
From release 8.21 more information about the details of the error are passed
back in the returned value:
PCRE_UTF16_ERR0 No error
PCRE_UTF16_ERR1 Missing low surrogate at the end of the string
PCRE_UTF16_ERR2 Invalid low surrogate
PCRE_UTF16_ERR3 Isolated low surrogate
PCRE_UTF16_ERR4 Unused (was non-character)
Arguments:
string points to the string
length length of string, or -1 if the string is zero-terminated
errp pointer to an error position offset variable
Returns: = 0 if the string is a valid UTF-16 string
> 0 otherwise, setting the offset of the bad character
*/
int
PRIV(valid_utf)(PCRE_PUCHAR string, int length, int *erroroffset)
{
#ifdef SUPPORT_UTF
register PCRE_PUCHAR p;
register pcre_uint32 c;
if (length < 0)
{
for (p = string; *p != 0; p++);
length = p - string;
}
for (p = string; length-- > 0; p++)
{
c = *p;
if ((c & 0xf800) != 0xd800)
{
/* Normal UTF-16 code point. Neither high nor low surrogate. */
}
else if ((c & 0xfc00) == 0xd800)
{
/* High surrogate. Must be a followed by a low surrogate. */
if (length == 0)
{
*erroroffset = p - string;
return PCRE_UTF16_ERR1;
}
p++;
length--;
if ((*p & 0xfc00) != 0xdc00)
{
*erroroffset = p - string;
return PCRE_UTF16_ERR2;
}
}
else
{
/* Isolated low surrogate. Always an error. */
*erroroffset = p - string;
return PCRE_UTF16_ERR3;
}
}
#else /* SUPPORT_UTF */
(void)(string); /* Keep picky compilers happy */
(void)(length);
(void)(erroroffset);
#endif /* SUPPORT_UTF */
return PCRE_UTF16_ERR0; /* This indicates success */
}
/* End of pcre16_valid_utf16.c */