This commit is contained in:
John Preston 2014-12-05 16:46:03 +03:00
commit 7170a0e5c0
27 changed files with 607 additions and 154 deletions

View File

@ -1,8 +1,8 @@
@echo OFF
set "AppVersionStrSmall=0.6.15"
set "AppVersionStr=0.6.15"
set "AppVersionStrFull=0.6.15.0"
set "AppVersionStrSmall=0.6.16"
set "AppVersionStr=0.6.16"
set "AppVersionStrFull=0.6.16.0"
echo.
echo Preparing version %AppVersionStr%..

View File

@ -59,6 +59,7 @@ lng_month_day: "{month} {day}";
lng_cancel: "Cancel";
lng_continue: "Continue";
lng_close: "Close";
lng_connecting: "Connecting..";
lng_reconnecting: "Reconnect in %1 s..";
lng_reconnecting_try_now: "Try now";
@ -161,6 +162,7 @@ lng_username_occupied: "This name is already occupied.";
lng_username_too_short: "This name is too short.";
lng_username_bad_symbols: "This name has bad symbols.";
lng_username_available: "This name is available.";
lng_username_not_found: "User @{user} not found.";
lng_settings_section_contact_info: "Contact info";
lng_settings_phone_number: "Phone number:";

View File

@ -1272,6 +1272,9 @@ aboutCloseButton: flatButton(contactsClose) {
overTextTop: 15px;
downTextTop: 16px;
}
btnInfoClose: flatButton(aboutCloseButton) {
width: confirmWidth;
}
emojiTextFont: font(16px);
emojiReplaceWidth: 56px;

View File

@ -1088,6 +1088,10 @@ namespace App {
convert->dc = dc;
convert->size = size;
}
if (convert->location.check()) {
Local::writeFileLocation(mediaKey(mtpc_inputDocumentFileLocation, convert->dc, convert->id), convert->location);
}
}
DocumentsData::const_iterator i = documentsData.constFind(document);
DocumentData *result;

View File

@ -368,8 +368,8 @@ void Application::killDownloadSessions() {
uint64 ms = getms(), left = MTPAckSendWaiting + MTPKillFileSessionTimeout;
for (QMap<int32, uint64>::iterator i = killDownloadSessionTimes.begin(); i != killDownloadSessionTimes.end(); ) {
if (i.value() <= ms) {
for (int j = 1; j < MTPDownloadSessionsCount; ++j) {
MTP::killSession(MTP::dld[j] + i.key());
for (int j = 0; j < MTPDownloadSessionsCount; ++j) {
MTP::stopSession(MTP::dld[j] + i.key());
}
i = killDownloadSessionTimes.erase(i);
} else {
@ -677,7 +677,7 @@ void Application::startApp() {
}
QNetworkProxyFactory::setUseSystemConfiguration(true);
if (Local::oldMapVersion() < AppVersion) {
if (Local::oldMapVersion() < AppVersion) {
psRegisterCustomScheme();
}
}

View File

@ -22,23 +22,53 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
#include "mainwidget.h"
#include "window.h"
ConfirmBox::ConfirmBox(QString text, QString doneText, QString cancelText) :
_confirm(this, doneText.isEmpty() ? lang(lng_continue) : doneText, st::btnSelectDone),
_cancel(this, cancelText.isEmpty() ? lang(lng_cancel) : cancelText, st::btnSelectCancel),
_text(100), _hiding(false), a_opacity(0, 1), af_opacity(anim::linear) {
TextParseOptions _confirmBoxTextOptions = {
TextParseLinks | TextParseMultiline | TextParseRichText, // flags
0, // maxw
0, // maxh
Qt::LayoutDirectionAuto, // dir
};
_text.setText(st::boxFont, text, _textPlainOptions);
ConfirmBox::ConfirmBox(const QString &text, const QString &doneText, const QString &cancelText) : _infoMsg(false),
_confirm(this, doneText.isEmpty() ? lang(lng_continue) : doneText, st::btnSelectDone),
_cancel(this, cancelText.isEmpty() ? lang(lng_cancel) : cancelText, st::btnSelectCancel),
_close(this, QString(), st::btnInfoClose),
_text(100), _hiding(false), a_opacity(0, 1), af_opacity(anim::linear) {
init(text);
}
ConfirmBox::ConfirmBox(const QString &text, bool noDone, const QString &cancelText) : _infoMsg(true),
_confirm(this, QString(), st::btnSelectDone),
_cancel(this, QString(), st::btnSelectCancel),
_close(this, cancelText.isEmpty() ? lang(lng_close) : cancelText, st::btnInfoClose),
_text(100), _hiding(false), a_opacity(0, 1), af_opacity(anim::linear) {
init(text);
}
void ConfirmBox::init(const QString &text) {
_text.setText(st::boxFont, text, (_infoMsg ? _confirmBoxTextOptions : _textPlainOptions));
_width = st::confirmWidth;
_textWidth = _width - st::boxPadding.left() - st::boxPadding.right();
_textHeight = _text.countHeight(_textWidth);
_height = st::boxPadding.top() + _textHeight + st::boxPadding.bottom() + _confirm.height();
_height = st::boxPadding.top() + _textHeight + st::boxPadding.bottom() + (_infoMsg ? _close.height() : _confirm.height());
_confirm.move(_width - _confirm.width(), st::boxPadding.top() + _textHeight + st::boxPadding.bottom());
_cancel.move(0, st::boxPadding.top() + _textHeight + st::boxPadding.bottom());
if (_infoMsg) {
_confirm.hide();
_cancel.hide();
_close.move(0, st::boxPadding.top() + _textHeight + st::boxPadding.bottom());
connect(&_confirm, SIGNAL(clicked()), this, SIGNAL(confirmed()));
connect(&_cancel, SIGNAL(clicked()), this, SLOT(onCancel()));
connect(&_close, SIGNAL(clicked()), this, SLOT(onCancel()));
setMouseTracking(_text.hasLinks());
} else {
_confirm.move(_width - _confirm.width(), st::boxPadding.top() + _textHeight + st::boxPadding.bottom());
_cancel.move(0, st::boxPadding.top() + _textHeight + st::boxPadding.bottom());
_close.hide();
connect(&_confirm, SIGNAL(clicked()), this, SIGNAL(confirmed()));
connect(&_cancel, SIGNAL(clicked()), this, SLOT(onCancel()));
}
resize(_width, _height);
@ -47,14 +77,73 @@ ConfirmBox::ConfirmBox(QString text, QString doneText, QString cancelText) :
hideAll();
}
void ConfirmBox::mouseMoveEvent(QMouseEvent *e) {
_lastMousePos = e->globalPos();
updateHover();
}
void ConfirmBox::mousePressEvent(QMouseEvent *e) {
_lastMousePos = e->globalPos();
updateHover();
if (textlnkOver()) {
textlnkDown(textlnkOver());
update();
}
}
void ConfirmBox::mouseReleaseEvent(QMouseEvent *e) {
_lastMousePos = e->globalPos();
updateHover();
if (textlnkOver() && textlnkOver() == textlnkDown()) {
App::wnd()->hideLayer();
textlnkOver()->onClick(e->button());
}
textlnkDown(TextLinkPtr());
}
void ConfirmBox::leaveEvent(QEvent *e) {
if (_myLink) {
if (textlnkOver() == _myLink) {
textlnkOver(TextLinkPtr());
update();
}
_myLink = TextLinkPtr();
setCursor(style::cur_default);
update();
}
}
void ConfirmBox::updateLink() {
_lastMousePos = QCursor::pos();
updateHover();
}
void ConfirmBox::updateHover() {
QPoint m(mapFromGlobal(_lastMousePos));
bool wasMy = (_myLink == textlnkOver());
_myLink = _text.link(m.x() - st::boxPadding.left(), m.y() - st::boxPadding.top(), _textWidth, (_text.maxWidth() < _width) ? style::al_center : style::al_left);
if (_myLink != textlnkOver()) {
if (wasMy || _myLink || rect().contains(m)) {
textlnkOver(_myLink);
}
setCursor(_myLink ? style::cur_pointer : style::cur_default);
update();
}
}
void ConfirmBox::hideAll() {
_confirm.hide();
_cancel.hide();
_close.hide();
}
void ConfirmBox::showAll() {
_confirm.show();
_cancel.show();
if (_infoMsg) {
_close.show();
} else {
_confirm.show();
_cancel.show();
}
}
void ConfirmBox::keyPressEvent(QKeyEvent *e) {
@ -78,11 +167,13 @@ void ConfirmBox::paintEvent(QPaintEvent *e) {
// fill bg
p.fillRect(0, 0, _width, _height, st::boxBG->b);
// paint shadows
p.fillRect(0, _height - st::btnSelectCancel.height - st::scrollDef.bottomsh, _width, st::scrollDef.bottomsh, st::scrollDef.shColor->b);
if (!_infoMsg) {
// paint shadows
p.fillRect(0, _height - st::btnSelectCancel.height - st::scrollDef.bottomsh, _width, st::scrollDef.bottomsh, st::scrollDef.shColor->b);
// paint button sep
p.fillRect(st::btnSelectCancel.width, _height - st::btnSelectCancel.height, st::lineWidth, st::btnSelectCancel.height, st::btnSelectSep->b);
// paint button sep
p.fillRect(st::btnSelectCancel.width, _height - st::btnSelectCancel.height, st::lineWidth, st::btnSelectCancel.height, st::btnSelectSep->b);
}
// draw box title / text
p.setFont(st::boxFont->f);

View File

@ -24,11 +24,17 @@ class ConfirmBox : public LayeredWidget, public RPCSender {
public:
ConfirmBox(QString text, QString doneText = QString(), QString cancelText = QString());
ConfirmBox(const QString &text, const QString &doneText = QString(), const QString &cancelText = QString());
ConfirmBox(const QString &text, bool noDone, const QString &cancelText = QString());
void parentResized();
void animStep(float64 ms);
void keyPressEvent(QKeyEvent *e);
void paintEvent(QPaintEvent *e);
void mouseMoveEvent(QMouseEvent *e);
void mousePressEvent(QMouseEvent *e);
void mouseReleaseEvent(QMouseEvent *e);
void leaveEvent(QEvent *e);
void updateLink();
void startHide();
~ConfirmBox();
@ -43,11 +49,16 @@ public slots:
private:
void init(const QString &text);
bool _infoMsg;
void hideAll();
void showAll();
int32 _width, _height;
FlatButton _confirm, _cancel;
BottomButton _close;
Text _text;
int32 _textWidth, _textHeight;
@ -56,4 +67,9 @@ private:
anim::fvalue a_opacity;
anim::transition af_opacity;
void updateHover();
QPoint _lastMousePos;
TextLinkPtr _myLink;
};

View File

@ -17,8 +17,8 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
*/
#pragma once
static const int32 AppVersion = 6015;
static const wchar_t *AppVersionStr = L"0.6.15";
static const int32 AppVersion = 6016;
static const wchar_t *AppVersionStr = L"0.6.16";
static const wchar_t *AppNameOld = L"Telegram Win (Unofficial)";
static const wchar_t *AppName = L"Telegram Desktop";

View File

@ -38,8 +38,7 @@ void FileUploader::uploadMedia(MsgId msgId, const ReadyLocalMedia &media) {
}
document->status = FileUploading;
if (!media.file.isEmpty()) {
document->fileName = media.file;
document->modDate = QFileInfo(media.file).lastModified();
document->location = FileLocation(mtpc_storage_filePartial, media.file);
}
}
queue.insert(msgId, File(media));
@ -75,7 +74,7 @@ void FileUploader::currentFailed() {
void FileUploader::killSessions() {
for (int i = 0; i < MTPUploadSessionsCount; ++i) {
MTP::killSession(MTP::upl[i]);
MTP::stopSession(MTP::upl[i]);
}
}
@ -204,7 +203,7 @@ void FileUploader::clear() {
dcMap.clear();
sentSize = 0;
for (int32 i = 0; i < MTPUploadSessionsCount; ++i) {
MTP::killSession(MTP::upl[i]);
MTP::stopSession(MTP::upl[i]);
sentSizes[i] = 0;
}
killSessionsTimer.stop();

View File

@ -203,3 +203,59 @@ public:
void clearStorageImages();
void clearAllImages();
int64 imageCacheSize();
struct FileLocation {
FileLocation(mtpTypeId type, const QString &name, const QDateTime &modified, qint32 size) : type(type), name(name), modified(modified), size(size) {
}
FileLocation(mtpTypeId type, const QString &name) : type(type), name(name) {
QFileInfo f(name);
if (f.exists()) {
qint64 s = f.size();
if (s > INT_MAX) {
this->name = QString();
size = 0;
type = mtpc_storage_fileUnknown;
} else {
modified = f.lastModified();
size = qint32(s);
}
} else {
this->name = QString();
size = 0;
type = mtpc_storage_fileUnknown;
}
}
FileLocation() : size(0) {
}
bool check() const {
if (name.isEmpty()) return false;
QFileInfo f(name);
if (!f.exists()) return false;
quint64 s = f.size();
if (s > INT_MAX) return false;
return (f.lastModified() == modified) && (qint32(s) == size);
}
mtpTypeId type;
QString name;
QDateTime modified;
qint32 size;
};
inline bool operator==(const FileLocation &a, const FileLocation &b) {
return a.type == b.type && a.name == b.name && a.modified == b.modified && a.size == b.size;
}
inline bool operator!=(const FileLocation &a, const FileLocation &b) {
return !(a == b);
}
typedef QPair<uint64, uint64> MediaKey;
inline uint64 mediaMix32To64(mtpTypeId a, int32 b) {
return (uint64(*reinterpret_cast<uint32*>(&a)) << 32) | uint64(*reinterpret_cast<uint32*>(&b));
}
inline MediaKey mediaKey(mtpTypeId type, int32 dc, const int64 &id) {
return MediaKey(mediaMix32To64(type, dc), id);
}
inline StorageKey mediaKey(const MTPDfileLocation &location) {
return storageKey(location.vdc_id.v, location.vvolume_id.v, location.vlocal_id.v);
}

View File

@ -516,6 +516,11 @@ void VideoCancelLink::onClick(Qt::MouseButton button) const {
data->cancel();
}
VideoData::VideoData(const VideoId &id, const uint64 &access, int32 user, int32 date, int32 duration, int32 w, int32 h, const ImagePtr &thumb, int32 dc, int32 size) :
id(id), access(access), user(user), date(date), duration(duration), w(w), h(h), thumb(thumb), dc(dc), size(size), status(FileReady), uploadOffset(0), fileType(0), openOnSave(0), openOnSaveMsgId(0), loader(0) {
location = Local::readFileLocation(mediaKey(mtpc_inputVideoFileLocation, dc, id));
}
void VideoData::save(const QString &toFile) {
cancel(true);
loader = new mtpFileLoader(dc, id, access, mtpc_inputVideoFileLocation, toFile, size);
@ -524,6 +529,12 @@ void VideoData::save(const QString &toFile) {
loader->start();
}
QString VideoData::already(bool check) {
if (!check) return location.name;
if (!location.check()) location = Local::readFileLocation(mediaKey(mtpc_inputVideoFileLocation, dc, id));
return location.name;
}
void AudioOpenLink::onClick(Qt::MouseButton button) const {
AudioData *data = audio();
if ((!data->user && !data->date) || button != Qt::LeftButton) return;
@ -591,6 +602,11 @@ void AudioCancelLink::onClick(Qt::MouseButton button) const {
data->cancel();
}
AudioData::AudioData(const AudioId &id, const uint64 &access, int32 user, int32 date, int32 duration, int32 dc, int32 size) :
id(id), access(access), user(user), date(date), duration(duration), dc(dc), size(size), status(FileReady), uploadOffset(0), openOnSave(0), openOnSaveMsgId(0), loader(0) {
location = Local::readFileLocation(mediaKey(mtpc_inputAudioFileLocation, dc, id));
}
void AudioData::save(const QString &toFile) {
cancel(true);
loader = new mtpFileLoader(dc, id, access, mtpc_inputAudioFileLocation, toFile, size, (size < AudioVoiceMsgInMemory));
@ -599,6 +615,12 @@ void AudioData::save(const QString &toFile) {
loader->start();
}
QString AudioData::already(bool check) {
if (!check) return location.name;
if (!location.check()) location = Local::readFileLocation(mediaKey(mtpc_inputAudioFileLocation, dc, id));
return location.name;
}
void DocumentOpenLink::onClick(Qt::MouseButton button) const {
DocumentData *data = document();
if ((!data->user && !data->date) || button != Qt::LeftButton) return;
@ -694,6 +716,11 @@ void DocumentCancelLink::onClick(Qt::MouseButton button) const {
data->cancel();
}
DocumentData::DocumentData(const DocumentId &id, const uint64 &access, int32 user, int32 date, const QString &name, const QString &mime, const ImagePtr &thumb, int32 dc, int32 size) :
id(id), access(access), user(user), date(date), name(name), mime(mime), thumb(thumb), dc(dc), size(size), status(FileReady), uploadOffset(0), openOnSave(0), openOnSaveMsgId(0), loader(0) {
location = Local::readFileLocation(mediaKey(mtpc_inputDocumentFileLocation, dc, id));
}
void DocumentData::save(const QString &toFile) {
cancel(true);
loader = new mtpFileLoader(dc, id, access, mtpc_inputDocumentFileLocation, toFile, size);
@ -702,6 +729,12 @@ void DocumentData::save(const QString &toFile) {
loader->start();
}
QString DocumentData::already(bool check) {
if (!check) return location.name;
if (!location.check()) location = Local::readFileLocation(mediaKey(mtpc_inputDocumentFileLocation, dc, id));
return location.name;
}
void PeerLink::onClick(Qt::MouseButton button) const {
if (button == Qt::LeftButton && App::main()) {
App::main()->showPeerProfile(peer());
@ -4089,6 +4122,7 @@ void HistoryMessage::drawInDialog(QPainter &p, const QRect &r, bool act, const H
p.setFont(st::dlgHistFont->f);
p.setPen((act ? st::dlgActiveColor : (_media ? st::dlgSystemColor : st::dlgTextColor))->p);
cache.drawElided(p, r.left(), r.top(), r.width(), r.height() / st::dlgHistFont->height);
textstyleRestore();
}
}

View File

@ -219,10 +219,8 @@ enum FileStatus {
};
struct VideoData {
VideoData(const VideoId &id, const uint64 &access = 0, int32 user = 0, int32 date = 0, int32 duration = 0, int32 w = 0, int32 h = 0, const ImagePtr &thumb = ImagePtr(), int32 dc = 0, int32 size = 0) :
id(id), access(access), user(user), date(date), duration(duration), w(w), h(h), thumb(thumb), dc(dc), size(size), status(FileReady), uploadOffset(0), fileType(0), openOnSave(0), openOnSaveMsgId(0), loader(0) {
memset(md5, 0, sizeof(md5));
}
VideoData(const VideoId &id, const uint64 &access = 0, int32 user = 0, int32 date = 0, int32 duration = 0, int32 w = 0, int32 h = 0, const ImagePtr &thumb = ImagePtr(), int32 dc = 0, int32 size = 0);
void forget() {
thumb->forget();
}
@ -237,8 +235,7 @@ struct VideoData {
l->deleteLater();
l->rpcInvalidate();
}
fileName = QString();
modDate = QDateTime();
location = FileLocation();
if (!beforeDownload) {
openOnSave = openOnSaveMsgId = 0;
}
@ -246,26 +243,14 @@ struct VideoData {
void finish() {
if (loader->done()) {
fileName = loader->fileName();
modDate = fileName.isEmpty() ? QDateTime() : QFileInfo(fileName).lastModified();
location = FileLocation(loader->fileType(), loader->fileName());
}
loader->deleteLater();
loader->rpcInvalidate();
loader = 0;
}
QString already(bool check = false) {
if (!check) return fileName;
QString res = modDate.isNull() ? QString() : fileName;
if (!res.isEmpty()) {
QFileInfo f(res);
if (f.exists() && f.lastModified() <= modDate) {
return res;
}
}
return QString();
}
QString already(bool check = false);
VideoId id;
uint64 access;
@ -283,9 +268,7 @@ struct VideoData {
mtpTypeId fileType;
int32 openOnSave, openOnSaveMsgId;
mtpFileLoader *loader;
QString fileName;
QDateTime modDate;
int32 md5[8];
FileLocation location;
};
class VideoLink : public ITextLink {
@ -323,10 +306,8 @@ public:
};
struct AudioData {
AudioData(const AudioId &id, const uint64 &access = 0, int32 user = 0, int32 date = 0, int32 duration = 0, int32 dc = 0, int32 size = 0) :
id(id), access(access), user(user), date(date), duration(duration), dc(dc), size(size), status(FileReady), uploadOffset(0), openOnSave(0), openOnSaveMsgId(0), loader(0) {
memset(md5, 0, sizeof(md5));
}
AudioData(const AudioId &id, const uint64 &access = 0, int32 user = 0, int32 date = 0, int32 duration = 0, int32 dc = 0, int32 size = 0);
void forget() {
}
@ -340,8 +321,7 @@ struct AudioData {
l->deleteLater();
l->rpcInvalidate();
}
fileName = QString();
modDate = QDateTime();
location = FileLocation();
if (!beforeDownload) {
openOnSave = openOnSaveMsgId = 0;
}
@ -349,8 +329,7 @@ struct AudioData {
void finish() {
if (loader->done()) {
fileName = loader->fileName();
modDate = fileName.isEmpty() ? QDateTime() : QFileInfo(fileName).lastModified();
location = FileLocation(loader->fileType(), loader->fileName());
data = loader->bytes();
}
loader->deleteLater();
@ -358,18 +337,7 @@ struct AudioData {
loader = 0;
}
QString already(bool check = false) {
if (!check) return fileName;
QString res = modDate.isNull() ? QString() : fileName;
if (!res.isEmpty()) {
QFileInfo f(res);
if (f.exists() && f.lastModified() <= modDate) {
return res;
}
}
return QString();
}
QString already(bool check = false);
AudioId id;
uint64 access;
@ -384,8 +352,7 @@ struct AudioData {
int32 openOnSave, openOnSaveMsgId;
mtpFileLoader *loader;
QString fileName;
QDateTime modDate;
FileLocation location;
QByteArray data;
int32 md5[8];
};
@ -425,10 +392,8 @@ public:
};
struct DocumentData {
DocumentData(const DocumentId &id, const uint64 &access = 0, int32 user = 0, int32 date = 0, const QString &name = QString(), const QString &mime = QString(), const ImagePtr &thumb = ImagePtr(), int32 dc = 0, int32 size = 0) :
id(id), access(access), user(user), date(date), name(name), mime(mime), thumb(thumb), dc(dc), size(size), status(FileReady), uploadOffset(0), openOnSave(0), openOnSaveMsgId(0), loader(0) {
memset(md5, 0, sizeof(md5));
}
DocumentData(const DocumentId &id, const uint64 &access = 0, int32 user = 0, int32 date = 0, const QString &name = QString(), const QString &mime = QString(), const ImagePtr &thumb = ImagePtr(), int32 dc = 0, int32 size = 0);
void forget() {
thumb->forget();
}
@ -443,8 +408,7 @@ struct DocumentData {
l->deleteLater();
l->rpcInvalidate();
}
fileName = QString();
modDate = QDateTime();
location = FileLocation();
if (!beforeDownload) {
openOnSave = openOnSaveMsgId = 0;
}
@ -452,26 +416,14 @@ struct DocumentData {
void finish() {
if (loader->done()) {
fileName = loader->fileName();
modDate = fileName.isEmpty() ? QDateTime() : QFileInfo(fileName).lastModified();
location = FileLocation(loader->fileType(), loader->fileName());
}
loader->deleteLater();
loader->rpcInvalidate();
loader = 0;
}
QString already(bool check = false) {
if (!check) return fileName;
QString res = modDate.isNull() ? QString() : fileName;
if (!res.isEmpty()) {
QFileInfo f(res);
if (f.exists() && f.lastModified() <= modDate) {
return res;
}
}
return QString();
}
QString already(bool check = false);
DocumentId id;
uint64 access;
@ -487,8 +439,7 @@ struct DocumentData {
int32 openOnSave, openOnSaveMsgId;
mtpFileLoader *loader;
QString fileName;
QDateTime modDate;
FileLocation location;
int32 md5[8];
};

View File

@ -438,6 +438,7 @@ namespace {
lskDraft, // data: PeerId peer
lskDraftPosition, // data: PeerId peer
lskStorage, // data: StorageKey location
lskLocations, // no data
};
typedef QMap<PeerId, FileKey> DraftsMap;
@ -450,8 +451,85 @@ namespace {
StorageMap _storageMap;
int32 _storageFilesSize = 0;
typedef QMultiMap<MediaKey, FileLocation> FileLocations;
FileLocations _fileLocations;
typedef QPair<MediaKey, FileLocation> FileLocationPair;
typedef QMap<QString, FileLocationPair> FileLocationPairs;
FileLocationPairs _fileLocationPairs;
FileKey _locationsKey = 0;
bool _mapChanged = false;
int32 _oldMapVersion = 0;
enum WriteMapWhen {
WriteMapNow,
WriteMapFast,
WriteMapSoon,
};
void _writeMap(WriteMapWhen when = WriteMapSoon);
void _writeLocations(WriteMapWhen when = WriteMapSoon) {
if (when != WriteMapNow) {
_manager->writeLocations(when == WriteMapFast);
return;
}
_manager->writingLocations();
if (_fileLocations.isEmpty()) {
if (_locationsKey) {
clearKey(_locationsKey);
_locationsKey = 0;
_mapChanged = true;
_writeMap();
}
} else {
if (!_locationsKey) {
while (!_locationsKey) {
_locationsKey = genKey();
}
_mapChanged = true;
_writeMap(WriteMapFast);
}
quint32 size = 0;
for (FileLocations::const_iterator i = _fileLocations.cbegin(); i != _fileLocations.cend(); ++i) {
size += sizeof(quint64) * 2 + sizeof(quint32) + sizeof(quint32) + i.value().name.size() * sizeof(ushort) + sizeof(qint64) + sizeof(quint32) + sizeof(qint8) + sizeof(quint32);
}
EncryptedDescriptor data(size);
for (FileLocations::const_iterator i = _fileLocations.cbegin(); i != _fileLocations.cend(); ++i) {
data.stream << quint64(i.key().first) << quint64(i.key().second) << quint32(i.value().type) << i.value().name << i.value().modified << quint32(i.value().size);
}
FileWriteDescriptor file(_locationsKey);
file.writeEncrypted(data);
}
}
void _readLocations() {
FileReadDescriptor locations;
if (!readEncryptedFile(locations, toFilePart(_locationsKey))) {
clearKey(_locationsKey);
_locationsKey = 0;
_writeMap();
return;
}
while (!locations.stream.atEnd()) {
quint64 first, second;
FileLocation loc;
quint32 type;
locations.stream >> first >> second >> type >> loc.name >> loc.modified >> loc.size;
MediaKey key(first, second);
loc.type = type;
if (loc.check()) {
_fileLocations.insert(key, loc);
_fileLocationPairs.insert(loc.name, FileLocationPair(key, loc));
} else {
_writeLocations();
}
}
}
Local::ReadMapState _readMap(const QByteArray &pass) {
uint64 ms = getms();
QByteArray dataNameUtf8 = cDataFile().toUtf8();
@ -500,6 +578,7 @@ namespace {
DraftsNotReadMap draftsNotReadMap;
StorageMap storageMap;
qint64 storageFilesSize = 0;
quint64 locationsKey = 0;
while (!map.stream.atEnd()) {
quint32 keyType;
map.stream >> keyType;
@ -537,6 +616,9 @@ namespace {
storageFilesSize += size;
}
} break;
case lskLocations: {
map.stream >> locationsKey;
} break;
default:
LOG(("App Error: unknown key type in encrypted map: %1").arg(keyType));
return Local::ReadMapFailed;
@ -552,19 +634,19 @@ namespace {
_draftsNotReadMap = draftsNotReadMap;
_storageMap = storageMap;
_storageFilesSize = storageFilesSize;
_locationsKey = locationsKey;
_mapChanged = false;
_oldMapVersion = mapData.version;
if (_locationsKey) {
_readLocations();
}
LOG(("Map read time: %1").arg(getms() - ms));
return Local::ReadMapDone;
}
enum WriteMapWhen {
WriteMapNow,
WriteMapFast,
WriteMapSoon,
};
void _writeMap(WriteMapWhen when = WriteMapSoon) {
void _writeMap(WriteMapWhen when) {
if (when != WriteMapNow) {
_manager->writeMap(when == WriteMapFast);
return;
@ -601,6 +683,7 @@ namespace {
if (!_draftsMap.isEmpty()) mapSize += sizeof(quint32) * 2 + _draftsMap.size() * sizeof(quint64) * 2;
if (!_draftsPositionsMap.isEmpty()) mapSize += sizeof(quint32) * 2 + _draftsPositionsMap.size() * sizeof(quint64) * 2;
if (!_storageMap.isEmpty()) mapSize += sizeof(quint32) * 2 + _storageMap.size() * (sizeof(quint64) * 3 + sizeof(qint32));
if (_locationsKey) mapSize += sizeof(quint32) + sizeof(quint64);
EncryptedDescriptor mapData(mapSize);
if (!_draftsMap.isEmpty()) {
mapData.stream << quint32(lskDraft) << quint32(_draftsMap.size());
@ -620,6 +703,9 @@ namespace {
mapData.stream << quint64(i.value().first) << quint64(i.key().first) << quint64(i.key().second) << qint32(i.value().second);
}
}
if (_locationsKey) {
mapData.stream << quint32(lskLocations) << quint64(_locationsKey);
}
map.writeEncrypted(mapData);
map.finish();
@ -634,6 +720,8 @@ namespace _local_inner {
Manager::Manager() {
_mapWriteTimer.setSingleShot(true);
connect(&_mapWriteTimer, SIGNAL(timeout()), this, SLOT(mapWriteTimeout()));
_locationsWriteTimer.setSingleShot(true);
connect(&_locationsWriteTimer, SIGNAL(timeout()), this, SLOT(locationsWriteTimeout()));
}
void Manager::writeMap(bool fast) {
@ -648,14 +736,32 @@ namespace _local_inner {
_mapWriteTimer.stop();
}
void Manager::writeLocations(bool fast) {
if (!_locationsWriteTimer.isActive() || fast) {
_locationsWriteTimer.start(fast ? 1 : WriteMapTimeout);
} else if (_locationsWriteTimer.remainingTime() <= 0) {
locationsWriteTimeout();
}
}
void Manager::writingLocations() {
_locationsWriteTimer.stop();
}
void Manager::mapWriteTimeout() {
_writeMap(WriteMapNow);
}
void Manager::locationsWriteTimeout() {
_writeLocations(WriteMapNow);
}
void Manager::finish() {
if (_mapWriteTimer.isActive()) {
mapWriteTimeout();
_mapWriteTimer.stop();
}
if (_locationsWriteTimer.isActive()) {
locationsWriteTimeout();
}
}
@ -799,6 +905,46 @@ namespace Local {
return (_draftsPositionsMap.constFind(peer) != _draftsPositionsMap.cend());
}
void writeFileLocation(const MediaKey &location, const FileLocation &local) {
if (local.name.isEmpty()) return;
FileLocationPairs::iterator i = _fileLocationPairs.find(local.name);
if (i != _fileLocationPairs.cend()) {
if (i.value().second == local) {
return;
}
if (i.value().first != location) {
for (FileLocations::iterator j = _fileLocations.find(i.value().first), e = _fileLocations.end(); (j != e) && (j.key() == i.value().first);) {
if (j.value() == i.value().second) {
_fileLocations.erase(j);
break;
}
}
_fileLocationPairs.erase(i);
}
}
_fileLocations.insert(location, local);
_fileLocationPairs.insert(local.name, FileLocationPair(location, local));
_writeLocations(WriteMapFast);
}
FileLocation readFileLocation(const MediaKey &location, bool check) {
FileLocations::iterator i = _fileLocations.find(location);
for (FileLocations::iterator i = _fileLocations.find(location); (i != _fileLocations.end()) && (i.key() == location);) {
if (check) {
QFileInfo info(i.value().name);
if (!info.exists() || info.lastModified() != i.value().modified || info.size() != i.value().size) {
_fileLocationPairs.remove(i.value().name);
i = _fileLocations.erase(i);
_writeLocations();
continue;
}
}
return i.value();
}
return FileLocation();
}
qint32 _storageImageSize(qint32 rawlen) {
// fulllen + storagekey + type + len + data
qint32 result = sizeof(uint32) + sizeof(quint64) * 2 + sizeof(quint32) + sizeof(quint32) + rawlen;

View File

@ -30,15 +30,20 @@ namespace _local_inner {
void writeMap(bool fast);
void writingMap();
void writeLocations(bool fast);
void writingLocations();
void finish();
public slots:
void mapWriteTimeout();
void locationsWriteTimeout();
private:
QTimer _mapWriteTimer;
QTimer _locationsWriteTimer;
};
}
@ -94,6 +99,9 @@ namespace Local {
MessageCursor readDraftPositions(const PeerId &peer);
bool hasDraftPositions(const PeerId &peer);
void writeFileLocation(const StorageKey &location, const FileLocation &local);
FileLocation readFileLocation(const StorageKey &location, bool check = true);
void writeImage(const StorageKey &location, const ImagePtr &img);
void writeImage(const StorageKey &location, const StorageImageSaved &jpeg, bool overwrite = true);
StorageImageSaved readImage(const StorageKey &location);

View File

@ -1854,14 +1854,22 @@ void MainWidget::openUserByName(const QString &username) {
if (user) {
emit showPeerAsync(user->id, 0, false, true);
} else {
MTP::send(MTPcontacts_ResolveUsername(MTP_string(username)), rpcDone(&MainWidget::usernameResolveDone));
MTP::send(MTPcontacts_ResolveUsername(MTP_string(username)), rpcDone(&MainWidget::usernameResolveDone), rpcFail(&MainWidget::usernameResolveFail, username));
}
}
void MainWidget::usernameResolveDone(const MTPUser &user) {
App::wnd()->hideLayer();
showPeer(App::feedUsers(MTP_vector<MTPUser>(1, user))->id, 0, false, true);
}
bool MainWidget::usernameResolveFail(QString name, const RPCError &error) {
if (error.code() == 400) {
App::wnd()->showLayer(new ConfirmBox(lang(lng_username_not_found).replace(qsl("{user}"), name), true));
}
return true;
}
void MainWidget::startFull(const MTPVector<MTPUser> &users) {
const QVector<MTPUser> &v(users.c_vector().v);
if (v.isEmpty() || v[0].type() != mtpc_userSelf) { // wtf?..
@ -2408,6 +2416,9 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
case mtpc_updateServiceNotification: {
const MTPDupdateServiceNotification &d(update.c_updateServiceNotification());
if (d.vpopup.v) {
App::wnd()->showLayer(new ConfirmBox(qs(d.vmessage), true));
}
} break;
case mtpc_updatePrivacy: {

View File

@ -361,6 +361,7 @@ private:
bool updateFail(const RPCError &e);
void usernameResolveDone(const MTPUser &user);
bool usernameResolveFail(QString name, const RPCError &error);
void hideAll();
void showAll();

View File

@ -711,6 +711,15 @@ namespace MTP {
}
}
void stopSession(int32 dc) {
Sessions::iterator i = sessions.find(dc);
if (i != sessions.end()) {
if (i.value() != mainSession) { // don't stop main session
i.value()->stop();
}
}
}
int32 state(mtpRequestId requestId) {
if (requestId > 0) {
QMutexLocker locker(&requestByDCLock);

View File

@ -99,6 +99,7 @@ namespace MTP {
}
void cancel(mtpRequestId req);
void killSession(int32 dc);
void stopSession(int32 dc);
enum {
RequestSent = 0,

View File

@ -1125,7 +1125,7 @@ MTProtoConnectionPrivate::MTProtoConnectionPrivate(QThread *thread, MTProtoConne
qRegisterMetaType<QVector<quint64> >("QVector<quint64>");
}
connect(this, SIGNAL(needToSendAsync()), sessionData->owner(), SIGNAL(needToSend()), Qt::QueuedConnection);
connect(this, SIGNAL(needToSendAsync()), sessionData->owner(), SLOT(needToResumeAndSend()), Qt::QueuedConnection);
connect(this, SIGNAL(sendAnythingAsync(quint64)), sessionData->owner(), SLOT(sendAnything(quint64)), Qt::QueuedConnection);
connect(this, SIGNAL(sendHttpWaitAsync()), sessionData->owner(), SLOT(sendHttpWait()), Qt::QueuedConnection);
connect(this, SIGNAL(sendPongAsync(quint64,quint64)), sessionData->owner(), SLOT(sendPong(quint64,quint64)), Qt::QueuedConnection);

View File

@ -57,7 +57,7 @@ id(0), access(0), fileIsOpen(false), size(size), type(mtpc_storage_fileUnknown)
mtpFileLoader::mtpFileLoader(int32 dc, const uint64 &id, const uint64 &access, mtpTypeId locType, const QString &to, int32 size) : prev(0), next(0),
priority(0), inQueue(false), complete(false), triedLocal(false), skippedBytes(0), nextRequestOffset(0), lastComplete(false),
dc(dc), locationType(locType),
dc(dc), locationType(locType), volume(0), local(0), secret(0),
id(id), access(access), file(to), fname(to), fileIsOpen(false), duplicateInData(false), size(size), type(mtpc_storage_fileUnknown) {
LoaderQueues::iterator i = queues.find(MTP::dld[0] + dc);
if (i == queues.cend()) {
@ -68,7 +68,7 @@ id(id), access(access), file(to), fname(to), fileIsOpen(false), duplicateInData(
mtpFileLoader::mtpFileLoader(int32 dc, const uint64 &id, const uint64 &access, mtpTypeId locType, const QString &to, int32 size, bool todata) : prev(0), next(0),
priority(0), inQueue(false), complete(false), triedLocal(false), skippedBytes(0), nextRequestOffset(0), lastComplete(false),
dc(dc), locationType(locType),
dc(dc), locationType(locType), volume(0), local(0), secret(0),
id(id), access(access), file(to), fname(to), fileIsOpen(false), duplicateInData(todata), size(size), type(mtpc_storage_fileUnknown) {
LoaderQueues::iterator i = queues.find(MTP::dld[0] + dc);
if (i == queues.cend()) {
@ -171,9 +171,7 @@ bool mtpFileLoader::loadPart() {
}
}
if (dcIndex) {
App::app()->killDownloadSessionsStop(dc);
}
App::app()->killDownloadSessionsStop(dc);
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);
@ -250,12 +248,14 @@ void mtpFileLoader::partLoaded(int32 offset, const MTPupload_File &result, mtpRe
removeFromQueue();
App::wnd()->update();
App::wnd()->notifyUpdateAllPhotos();
if (!queue->queries && dcIndex) {
if (!queue->queries) {
App::app()->killDownloadSessionsStart(dc);
}
if (!locationType && triedLocal && (fname.isEmpty() || duplicateInData)) {
Local::writeImage(storageKey(dc, volume, local), StorageImageSaved(type, data));
} else if (locationType && triedLocal && !fname.isEmpty()) {
Local::writeFileLocation(mediaKey(locationType, dc, id), FileLocation(type, fname));
}
}
emit progress(this);
@ -291,31 +291,35 @@ void mtpFileLoader::pause() {
void mtpFileLoader::start(bool loadFirst, bool prior) {
if (complete) return;
if (!locationType && !triedLocal) {
triedLocal = true;
StorageImageSaved cached = Local::readImage(storageKey(dc, volume, local));
if (cached.type != mtpc_storage_fileUnknown) {
data = cached.data;
if (!fname.isEmpty() && duplicateInData) {
if (!fileIsOpen) fileIsOpen = file.open(QIODevice::WriteOnly);
if (!fileIsOpen) {
return finishFail();
if (!triedLocal) {
if (!locationType) {
triedLocal = true;
StorageImageSaved cached = Local::readImage(storageKey(dc, volume, local));
if (cached.type != mtpc_storage_fileUnknown) {
data = cached.data;
if (!fname.isEmpty() && duplicateInData) {
if (!fileIsOpen) fileIsOpen = file.open(QIODevice::WriteOnly);
if (!fileIsOpen) {
return finishFail();
}
if (file.write(data) != qint64(data.size())) {
return finishFail();
}
}
if (file.write(data) != qint64(data.size())) {
return finishFail();
type = cached.type;
complete = true;
if (fileIsOpen) {
file.close();
fileIsOpen = false;
psPostprocessFile(QFileInfo(file).absoluteFilePath());
}
App::wnd()->update();
App::wnd()->notifyUpdateAllPhotos();
emit progress(this);
return loadNext();
}
type = cached.type;
complete = true;
if (fileIsOpen) {
file.close();
fileIsOpen = false;
psPostprocessFile(QFileInfo(file).absoluteFilePath());
}
App::wnd()->update();
App::wnd()->notifyUpdateAllPhotos();
emit progress(this);
return loadNext();
} else if (locationType && !fname.isEmpty()) {
triedLocal = true;
}
}
@ -433,18 +437,16 @@ void mtpFileLoader::cancelRequests() {
if (requests.isEmpty()) return;
int32 limit = locationType ? DocumentDownloadPartSize : DownloadPartSize;
bool wasIndex = false;
DataRequested &dr(_dataRequested[dc]);
for (Requests::const_iterator i = requests.cbegin(), e = requests.cend(); i != e; ++i) {
MTP::cancel(i.key());
int32 dcIndex = i.value();
dr.v[dcIndex] -= limit;
if (dcIndex) wasIndex = true;
}
queue->queries -= requests.size();
requests.clear();
if (!queue->queries && wasIndex) {
if (!queue->queries) {
App::app()->killDownloadSessionsStart(dc);
}
}

View File

@ -82,7 +82,7 @@ void MTProtoSession::start(int32 dcenter, uint32 connects) {
connect(&timeouter, SIGNAL(timeout()), this, SLOT(checkRequestsByTimer()));
timeouter.start(1000);
connect(&sender, SIGNAL(timeout()), this, SIGNAL(needToSend()));
connect(&sender, SIGNAL(timeout()), this, SLOT(needToResumeAndSend()));
MTProtoDCMap &dcs(mtpDCMap());
@ -124,6 +124,7 @@ void MTProtoSession::restart() {
}
void MTProtoSession::stop() {
DEBUG_LOG(("Session Info: stopping session %1").arg(dcId));
while (!connections.isEmpty()) {
connections.back()->stop();
connections.pop_back();
@ -152,10 +153,32 @@ void MTProtoSession::sendAnything(quint64 msCanWait) {
DEBUG_LOG(("MTP Info: dc %1 stopped send timer, can wait for %2ms from current %3").arg(dcId).arg(msWait).arg(msSendCall));
sender.stop();
msSendCall = 0;
emit needToSend();
needToResumeAndSend();
}
}
void MTProtoSession::needToResumeAndSend() {
if (connections.isEmpty()) {
DEBUG_LOG(("Session Info: resuming session %1").arg(dcId));
MTProtoDCMap &dcs(mtpDCMap());
connections.reserve(cConnectionsInSession());
for (uint32 i = 0; i < cConnectionsInSession(); ++i) {
connections.push_back(new MTProtoConnection());
if (!connections.back()->start(&data, dcId)) {
for (MTProtoConnections::const_iterator j = connections.cbegin(), e = connections.cend(); j != e; ++j) {
delete *j;
}
connections.clear();
DEBUG_LOG(("Session Info: could not start connection %1 to dc %2").arg(i).arg(dcId));
dcId = 0;
return;
}
}
}
emit needToSend();
}
void MTProtoSession::sendHttpWait() {
send(MTPHttpWait(MTP_http_wait(MTP_int(100), MTP_int(30), MTP_int(25000))), RPCResponseHandler(), 50);
}

View File

@ -251,6 +251,8 @@ signals:
public slots:
void needToResumeAndSend();
mtpRequestId resend(quint64 msgId, quint64 msCanWait = 0, bool forceContainer = false, bool sendMsgStateInfo = false);
void resendMany(QVector<quint64> msgIds, quint64 msCanWait, bool forceContainer, bool sendMsgStateInfo);
void resendAll(); // after connection restart

View File

@ -783,12 +783,16 @@ QString psCurrentLanguage() {
return lng.isEmpty() ? QString::fromLatin1(DefaultLanguage) : lng;
}
QString psAppDataPath() {
struct passwd *pw = getpwuid(getuid());
if (pw && pw->pw_dir && strlen(pw->pw_dir)) {
return QString::fromLocal8Bit(pw->pw_dir) + qsl("/.TelegramDesktop/");
namespace {
QString _psHomeDir() {
struct passwd *pw = getpwuid(getuid());
return (pw && pw->pw_dir && strlen(pw->pw_dir)) ? (QString::fromLocal8Bit(pw->pw_dir) + '/') : QString();
}
return QString();
}
QString psAppDataPath() {
QString home(_psHomeDir());
return home.isEmpty() ? QString() : (home + qsl(".TelegramDesktop/"));
}
QString psDownloadPath() {
@ -966,14 +970,11 @@ void psPostprocessFile(const QString &name) {
void psOpenFile(const QString &name, bool openWith) {
QDesktopServices::openUrl(QUrl::fromLocalFile(name));
//objc_openFile(name, openWith);
}
void psShowInFolder(const QString &name) {
// QDesktopServices::openUrl(QFileInfo(name).absoluteDir().absolutePath());
App::wnd()->layerHidden();
system(("nautilus \"" + QFileInfo(name).absoluteDir().absolutePath() + "\"").toUtf8().constData());
//objc_showInFinder(name, QFileInfo(name).absolutePath());
}
void psStart() {
@ -982,7 +983,100 @@ void psStart() {
void psFinish() {
}
namespace {
bool _psRunCommand(const QString &command) {
int result = system(command.toLocal8Bit().constData());
if (result) {
DEBUG_LOG(("App Error: command failed, code: %1, command: %2").arg(result).arg(command.toLocal8Bit().constData()));
return false;
}
DEBUG_LOG(("App Info: command succeeded, command: %1").arg(command.toLocal8Bit().constData()));
return true;
}
}
void psRegisterCustomScheme() {
QString home(_psHomeDir());
if (home.isEmpty()) return;
DEBUG_LOG(("App Info: placing .desktop file"));
if (QDir(home + qsl(".local/")).exists()) {
QString apps = home + qsl(".local/share/applications/");
if (!QDir(apps).exists()) QDir().mkpath(apps);
QString path = cWorkingDir() + qsl("tdata/"), file = path + qsl("telegramdesktop.desktop");
QDir().mkpath(path);
QFile f(file);
if (f.open(QIODevice::WriteOnly)) {
QString icon = path + qsl("icon.png");
if (!QFile(icon).exists()) {
if (QFile(qsl(":/gui/art/icon256.png")).copy(icon)) {
DEBUG_LOG(("App Info: Icon copied to 'tdata'"));
}
}
QTextStream s(&f);
s.setCodec("UTF-8");
s << "[Desktop Entry]\n";
s << "Encoding=UTF-8\n";
s << "Version=1.0\n";
s << "Name=Telegram Desktop\n";
s << "Comment=Official desktop version of Telegram messaging app\n";
s << "Exec=" << cExeDir().toLocal8Bit().constData() << cExeName().toLocal8Bit().constData() << " -- %u\n";
s << "Icon=" << icon.toLocal8Bit().constData() << "\n";
s << "Terminal=false\n";
s << "Type=Application\n";
s << "Categories=Network;\n";
s << "MimeType=application/x-xdg-protocol-tg;x-scheme-handler/tg;\n";
f.close();
if (_psRunCommand(qsl("desktop-file-install --dir=%1.local/share/applications --delete-original \"%2\"").arg(home).arg(file))) {
_psRunCommand(qsl("update-desktop-database %1.local/share/applications").arg(home));
_psRunCommand(qsl("xdg-mime default telegramdesktop.desktop x-scheme-handler/tg"));
}
} else {
LOG(("App Error: Could not open '%1' for write").arg(file));
}
}
DEBUG_LOG(("App Info: registerting for Gnome"));
if (_psRunCommand(qsl("gconftool-2 -t string -s /desktop/gnome/url-handlers/tg/command \"%1 -- %s\"").arg(cExeDir() + cExeName()))) {
_psRunCommand(qsl("gconftool-2 -t bool -s /desktop/gnome/url-handlers/tg/needs_terminal false"));
_psRunCommand(qsl("gconftool-2 -t bool -s /desktop/gnome/url-handlers/tg/enabled true"));
}
DEBUG_LOG(("App Info: placing .protocol file"));
QString services;
if (QDir(home + qsl(".kde4/")).exists()) {
services = home + qsl(".kde4/share/kde4/services/");
} else if (QDir(home + qsl(".kde/")).exists()) {
services = home + qsl(".kde/share/kde4/services/");
}
if (!services.isEmpty()) {
if (!QDir(services).exists()) QDir().mkpath(services);
QString path = services, file = path + qsl("tg.protocol");
QFile f(file);
if (f.open(QIODevice::WriteOnly)) {
QTextStream s(&f);
s.setCodec("UTF-8");
s << "[Protocol]\n";
s << "exec=" << cExeDir().toLocal8Bit().constData() << cExeName().toLocal8Bit().constData() << " -- %u\n";
s << "protocol=tg\n";
s << "input=none\n";
s << "output=none\n";
s << "helper=true\n";
s << "listing=false\n";
s << "reading=false\n";
s << "writing=false\n";
s << "makedir=false\n";
s << "deleting=false\n";
f.close();
} else {
LOG(("App Error: Could not open '%1' for write").arg(file));
}
}
}
bool _execUpdater(bool update = true) {

View File

@ -11,7 +11,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>0.6.15</string>
<string>0.6.16</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>

Binary file not shown.

View File

@ -1577,7 +1577,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 0.6.15;
CURRENT_PROJECT_VERSION = 0.6.16;
DEBUG_INFORMATION_FORMAT = dwarf;
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
@ -1595,7 +1595,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
COPY_PHASE_STRIP = YES;
CURRENT_PROJECT_VERSION = 0.6.15;
CURRENT_PROJECT_VERSION = 0.6.16;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_OPTIMIZATION_LEVEL = fast;
GCC_PREFIX_HEADER = ./SourceFiles/stdafx.h;
@ -1621,10 +1621,10 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 0.6.15;
CURRENT_PROJECT_VERSION = 0.6.16;
DEBUG_INFORMATION_FORMAT = dwarf;
DYLIB_COMPATIBILITY_VERSION = 0.6;
DYLIB_CURRENT_VERSION = 0.6.15;
DYLIB_CURRENT_VERSION = 0.6.16;
ENABLE_STRICT_OBJC_MSGSEND = YES;
FRAMEWORK_SEARCH_PATHS = "";
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
@ -1764,10 +1764,10 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 0.6.15;
CURRENT_PROJECT_VERSION = 0.6.16;
DEBUG_INFORMATION_FORMAT = dwarf;
DYLIB_COMPATIBILITY_VERSION = 0.6;
DYLIB_CURRENT_VERSION = 0.6.15;
DYLIB_CURRENT_VERSION = 0.6.16;
ENABLE_STRICT_OBJC_MSGSEND = YES;
FRAMEWORK_SEARCH_PATHS = "";
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;

View File

@ -1,2 +1,2 @@
echo 6015 0.6.15
echo 6016 0.6.16