mirror of https://github.com/procxx/kepka.git
Export my messages from left channels.
This commit is contained in:
parent
e8d619c740
commit
1bfe409c93
|
@ -1266,6 +1266,7 @@ channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet =
|
||||||
channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector<int> = Bool;
|
channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector<int> = Bool;
|
||||||
channels.deleteHistory#af369d42 channel:InputChannel max_id:int = Bool;
|
channels.deleteHistory#af369d42 channel:InputChannel max_id:int = Bool;
|
||||||
channels.togglePreHistoryHidden#eabbb94c channel:InputChannel enabled:Bool = Updates;
|
channels.togglePreHistoryHidden#eabbb94c channel:InputChannel enabled:Bool = Updates;
|
||||||
|
channels.getLeftChannels#90920196 = messages.Chats;
|
||||||
|
|
||||||
bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON;
|
bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON;
|
||||||
bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool;
|
bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool;
|
||||||
|
|
|
@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#include "export/data/export_data_types.h"
|
#include "export/data/export_data_types.h"
|
||||||
|
|
||||||
|
#include "export/export_settings.h"
|
||||||
#include "core/mime_type.h"
|
#include "core/mime_type.h"
|
||||||
|
|
||||||
#include <QtCore/QDateTime>
|
#include <QtCore/QDateTime>
|
||||||
|
@ -891,6 +892,21 @@ SessionsList ParseSessionsList(const MTPaccount_Authorizations &data) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DialogInfo::Type DialogTypeFromChat(const Chat &chat) {
|
||||||
|
using Type = DialogInfo::Type;
|
||||||
|
return chat.username.isEmpty()
|
||||||
|
? (chat.broadcast
|
||||||
|
? Type::PrivateChannel
|
||||||
|
: Type::PrivateGroup)
|
||||||
|
: (chat.broadcast
|
||||||
|
? Type::PublicChannel
|
||||||
|
: Type::PublicGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
DialogInfo::Type DialogTypeFromUser(const User &user) {
|
||||||
|
return user.isBot ? DialogInfo::Type::Bot : DialogInfo::Type::Personal;
|
||||||
|
}
|
||||||
|
|
||||||
DialogsInfo ParseDialogsInfo(const MTPmessages_Dialogs &data) {
|
DialogsInfo ParseDialogsInfo(const MTPmessages_Dialogs &data) {
|
||||||
auto result = DialogsInfo();
|
auto result = DialogsInfo();
|
||||||
const auto folder = QString();
|
const auto folder = QString();
|
||||||
|
@ -905,22 +921,14 @@ DialogsInfo ParseDialogsInfo(const MTPmessages_Dialogs &data) {
|
||||||
const auto &fields = dialog.c_dialog();
|
const auto &fields = dialog.c_dialog();
|
||||||
|
|
||||||
auto info = DialogInfo();
|
auto info = DialogInfo();
|
||||||
const auto peerId = ParsePeerId(fields.vpeer);
|
info.peerId = ParsePeerId(fields.vpeer);
|
||||||
const auto peerIt = peers.find(peerId);
|
const auto peerIt = peers.find(info.peerId);
|
||||||
if (peerIt != end(peers)) {
|
if (peerIt != end(peers)) {
|
||||||
using Type = DialogInfo::Type;
|
using Type = DialogInfo::Type;
|
||||||
const auto &peer = peerIt->second;
|
const auto &peer = peerIt->second;
|
||||||
info.type = peer.user()
|
info.type = peer.user()
|
||||||
? (peer.user()->isBot
|
? DialogTypeFromUser(*peer.user())
|
||||||
? Type::Bot
|
: DialogTypeFromChat(*peer.chat());
|
||||||
: Type::Personal)
|
|
||||||
: (peer.chat()->broadcast
|
|
||||||
? (peer.chat()->username.isEmpty()
|
|
||||||
? Type::PrivateChannel
|
|
||||||
: Type::PublicChannel)
|
|
||||||
: (peer.chat()->username.isEmpty()
|
|
||||||
? Type::PrivateGroup
|
|
||||||
: Type::PublicGroup));
|
|
||||||
info.name = peer.name();
|
info.name = peer.name();
|
||||||
info.input = peer.input();
|
info.input = peer.input();
|
||||||
}
|
}
|
||||||
|
@ -936,6 +944,57 @@ DialogsInfo ParseDialogsInfo(const MTPmessages_Dialogs &data) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InsertLeftDialog(
|
||||||
|
DialogsInfo &info,
|
||||||
|
const Chat &chat,
|
||||||
|
Message &&message) {
|
||||||
|
const auto projection = [](const DialogInfo &dialog) {
|
||||||
|
return std::make_tuple(
|
||||||
|
dialog.topMessageDate,
|
||||||
|
dialog.topMessageId,
|
||||||
|
BarePeerId(dialog.peerId));
|
||||||
|
};
|
||||||
|
const auto i = ranges::lower_bound(
|
||||||
|
info.list,
|
||||||
|
std::make_tuple(message.date, message.id, chat.id),
|
||||||
|
ranges::ordered_less{},
|
||||||
|
projection);
|
||||||
|
|
||||||
|
auto insert = DialogInfo();
|
||||||
|
insert.input = chat.input;
|
||||||
|
insert.name = chat.title;
|
||||||
|
insert.peerId = ChatPeerId(chat.id);
|
||||||
|
insert.topMessageDate = message.date;
|
||||||
|
insert.topMessageId = message.id;
|
||||||
|
insert.type = DialogTypeFromChat(chat);
|
||||||
|
info.list.insert(i, std::move(insert));
|
||||||
|
}
|
||||||
|
|
||||||
|
void FinalizeDialogsInfo(DialogsInfo &info, const Settings &settings) {
|
||||||
|
auto &list = info.list;
|
||||||
|
const auto digits = Data::NumberToString(list.size() - 1).size();
|
||||||
|
auto index = 0;
|
||||||
|
for (auto &dialog : list) {
|
||||||
|
const auto number = Data::NumberToString(++index, digits, '0');
|
||||||
|
dialog.relativePath = "Chats/chat_" + number + '/';
|
||||||
|
|
||||||
|
using DialogType = DialogInfo::Type;
|
||||||
|
using Type = Settings::Type;
|
||||||
|
const auto setting = [&] {
|
||||||
|
switch (dialog.type) {
|
||||||
|
case DialogType::Personal: return Type::PersonalChats;
|
||||||
|
case DialogType::Bot: return Type::BotChats;
|
||||||
|
case DialogType::PrivateGroup: return Type::PrivateGroups;
|
||||||
|
case DialogType::PrivateChannel: return Type::PrivateChannels;
|
||||||
|
case DialogType::PublicGroup: return Type::PublicGroups;
|
||||||
|
case DialogType::PublicChannel: return Type::PublicChannels;
|
||||||
|
}
|
||||||
|
Unexpected("Type in ApiWrap::onlyMyMessages.");
|
||||||
|
}();
|
||||||
|
dialog.onlyMyMessages = ((settings.fullChats & setting) != setting);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MessagesSlice ParseMessagesSlice(
|
MessagesSlice ParseMessagesSlice(
|
||||||
const MTPVector<MTPMessage> &data,
|
const MTPVector<MTPMessage> &data,
|
||||||
const MTPVector<MTPUser> &users,
|
const MTPVector<MTPUser> &users,
|
||||||
|
|
|
@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace Export {
|
namespace Export {
|
||||||
|
struct Settings;
|
||||||
namespace Data {
|
namespace Data {
|
||||||
|
|
||||||
using TimeId = int32;
|
using TimeId = int32;
|
||||||
|
@ -420,7 +421,10 @@ struct DialogInfo {
|
||||||
MTPInputPeer input = MTP_inputPeerEmpty();
|
MTPInputPeer input = MTP_inputPeerEmpty();
|
||||||
int32 topMessageId = 0;
|
int32 topMessageId = 0;
|
||||||
TimeId topMessageDate = 0;
|
TimeId topMessageDate = 0;
|
||||||
|
PeerId peerId = 0;
|
||||||
|
|
||||||
|
// Filled after the whole dialogs list is accumulated.
|
||||||
|
bool onlyMyMessages = false;
|
||||||
QString relativePath;
|
QString relativePath;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -430,6 +434,11 @@ struct DialogsInfo {
|
||||||
};
|
};
|
||||||
|
|
||||||
DialogsInfo ParseDialogsInfo(const MTPmessages_Dialogs &data);
|
DialogsInfo ParseDialogsInfo(const MTPmessages_Dialogs &data);
|
||||||
|
void InsertLeftDialog(
|
||||||
|
DialogsInfo &info,
|
||||||
|
const Chat &chat,
|
||||||
|
Message &&message);
|
||||||
|
void FinalizeDialogsInfo(DialogsInfo &info, const Settings &settings);
|
||||||
|
|
||||||
struct MessagesSlice {
|
struct MessagesSlice {
|
||||||
std::vector<Message> list;
|
std::vector<Message> list;
|
||||||
|
|
|
@ -114,6 +114,7 @@ struct ApiWrap::FileProcess {
|
||||||
|
|
||||||
struct ApiWrap::DialogsProcess {
|
struct ApiWrap::DialogsProcess {
|
||||||
Data::DialogsInfo info;
|
Data::DialogsInfo info;
|
||||||
|
std::map<int32, Data::Chat> left;
|
||||||
|
|
||||||
FnMut<void(const Data::DialogsInfo&)> start;
|
FnMut<void(const Data::DialogsInfo&)> start;
|
||||||
Fn<void(const Data::DialogInfo&)> startOne;
|
Fn<void(const Data::DialogInfo&)> startOne;
|
||||||
|
@ -350,8 +351,9 @@ void ApiWrap::loadNextUserpic() {
|
||||||
? base::none
|
? base::none
|
||||||
: base::make_optional(list.back().id);
|
: base::make_optional(list.back().id);
|
||||||
|
|
||||||
_userpicsProcess->handleSlice(*base::take(_userpicsProcess->slice));
|
if (!list.empty()) {
|
||||||
|
_userpicsProcess->handleSlice(*base::take(_userpicsProcess->slice));
|
||||||
|
}
|
||||||
if (_userpicsProcess->lastSlice) {
|
if (_userpicsProcess->lastSlice) {
|
||||||
finishUserpics();
|
finishUserpics();
|
||||||
return;
|
return;
|
||||||
|
@ -431,19 +433,16 @@ void ApiWrap::requestDialogsSlice() {
|
||||||
_dialogsProcess->offsetPeer,
|
_dialogsProcess->offsetPeer,
|
||||||
MTP_int(kChatsSliceLimit)
|
MTP_int(kChatsSliceLimit)
|
||||||
)).done([=](const MTPmessages_Dialogs &result) mutable {
|
)).done([=](const MTPmessages_Dialogs &result) mutable {
|
||||||
const auto finished = [&] {
|
const auto finished = result.match(
|
||||||
switch (result.type()) {
|
[](const MTPDmessages_dialogs &data) {
|
||||||
case mtpc_messages_dialogs: return true;
|
return true;
|
||||||
case mtpc_messages_dialogsSlice: {
|
}, [](const MTPDmessages_dialogsSlice &data) {
|
||||||
const auto &data = result.c_messages_dialogsSlice();
|
return data.vdialogs.v.isEmpty();
|
||||||
return data.vdialogs.v.isEmpty();
|
});
|
||||||
} break;
|
|
||||||
default: Unexpected("Type in ApiWrap::requestChatsSlice.");
|
|
||||||
}
|
|
||||||
}();
|
|
||||||
auto info = Data::ParseDialogsInfo(result);
|
auto info = Data::ParseDialogsInfo(result);
|
||||||
if (finished || info.list.empty()) {
|
if (finished || info.list.empty()) {
|
||||||
finishDialogsList();
|
requestLeftChannels();
|
||||||
} else {
|
} else {
|
||||||
const auto &last = info.list.back();
|
const auto &last = info.list.back();
|
||||||
_dialogsProcess->offsetId = last.topMessageId;
|
_dialogsProcess->offsetId = last.topMessageId;
|
||||||
|
@ -492,28 +491,83 @@ void ApiWrap::appendDialogsSlice(Data::DialogsInfo &&info) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ApiWrap::requestLeftChannels() {
|
||||||
|
Expects(_dialogsProcess != nullptr);
|
||||||
|
|
||||||
|
mainRequest(MTPchannels_GetLeftChannels(
|
||||||
|
)).done([=](const MTPmessages_Chats &result) mutable {
|
||||||
|
Expects(_dialogsProcess != nullptr);
|
||||||
|
|
||||||
|
const auto finished = result.match(
|
||||||
|
[](const MTPDmessages_chats &data) {
|
||||||
|
return true;
|
||||||
|
}, [](const MTPDmessages_chatsSlice &data) {
|
||||||
|
return data.vchats.v.isEmpty();
|
||||||
|
});
|
||||||
|
|
||||||
|
_dialogsProcess->left = Data::ParseChatsList(*result.match(
|
||||||
|
[](const auto &data) {
|
||||||
|
return &data.vchats;
|
||||||
|
}));
|
||||||
|
requestLeftDialog();
|
||||||
|
}).send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApiWrap::requestLeftDialog() {
|
||||||
|
Expects(_dialogsProcess != nullptr);
|
||||||
|
|
||||||
|
auto &left = _dialogsProcess->left;
|
||||||
|
if (true || left.empty()) { // #TODO export
|
||||||
|
finishDialogsList();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto key = std::move(*left.begin());
|
||||||
|
left.erase(key.first);
|
||||||
|
|
||||||
|
mainRequest(MTPmessages_Search(
|
||||||
|
MTP_flags(MTPmessages_Search::Flag::f_from_id),
|
||||||
|
key.second.input,
|
||||||
|
MTP_string(""), // query
|
||||||
|
_user,
|
||||||
|
MTP_inputMessagesFilterEmpty(),
|
||||||
|
MTP_int(0), // min_date
|
||||||
|
MTP_int(0), // max_date
|
||||||
|
MTP_int(0), // offset_id
|
||||||
|
MTP_int(0), // add_offset
|
||||||
|
MTP_int(1), // limit
|
||||||
|
MTP_int(0), // max_id
|
||||||
|
MTP_int(0), // min_id
|
||||||
|
MTP_int(0) // hash
|
||||||
|
)).done([=](const MTPmessages_Messages &result) {
|
||||||
|
Expects(_dialogsProcess != nullptr);
|
||||||
|
|
||||||
|
result.match([=](const MTPDmessages_messagesNotModified &data) {
|
||||||
|
error("Unexpected messagesNotModified received.");
|
||||||
|
}, [=](const auto &data) {
|
||||||
|
auto messages = Data::ParseMessagesList(
|
||||||
|
data.vmessages,
|
||||||
|
QString());
|
||||||
|
if (!messages.empty() && messages.begin()->second.date > 0) {
|
||||||
|
Data::InsertLeftDialog(
|
||||||
|
_dialogsProcess->info,
|
||||||
|
key.second,
|
||||||
|
std::move(messages.begin()->second));
|
||||||
|
}
|
||||||
|
requestLeftDialog();
|
||||||
|
});
|
||||||
|
}).send();
|
||||||
|
}
|
||||||
|
|
||||||
void ApiWrap::finishDialogsList() {
|
void ApiWrap::finishDialogsList() {
|
||||||
Expects(_dialogsProcess != nullptr);
|
Expects(_dialogsProcess != nullptr);
|
||||||
|
|
||||||
ranges::reverse(_dialogsProcess->info.list);
|
ranges::reverse(_dialogsProcess->info.list);
|
||||||
fillDialogsPaths();
|
Data::FinalizeDialogsInfo(_dialogsProcess->info, *_settings);
|
||||||
|
|
||||||
_dialogsProcess->start(_dialogsProcess->info);
|
_dialogsProcess->start(_dialogsProcess->info);
|
||||||
requestNextDialog();
|
requestNextDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApiWrap::fillDialogsPaths() {
|
|
||||||
Expects(_dialogsProcess != nullptr);
|
|
||||||
|
|
||||||
auto &list = _dialogsProcess->info.list;
|
|
||||||
const auto digits = Data::NumberToString(list.size() - 1).size();
|
|
||||||
auto index = 0;
|
|
||||||
for (auto &dialog : list) {
|
|
||||||
const auto number = Data::NumberToString(++index, digits, '0');
|
|
||||||
dialog.relativePath = "Chats/chat_" + number + '/';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ApiWrap::requestNextDialog() {
|
void ApiWrap::requestNextDialog() {
|
||||||
Expects(_dialogsProcess != nullptr);
|
Expects(_dialogsProcess != nullptr);
|
||||||
Expects(_dialogsProcess->single == nullptr);
|
Expects(_dialogsProcess->single == nullptr);
|
||||||
|
@ -534,6 +588,15 @@ void ApiWrap::requestMessagesSlice() {
|
||||||
Expects(_dialogsProcess->single != nullptr);
|
Expects(_dialogsProcess->single != nullptr);
|
||||||
|
|
||||||
const auto process = _dialogsProcess->single.get();
|
const auto process = _dialogsProcess->single.get();
|
||||||
|
|
||||||
|
// #TODO export
|
||||||
|
if (process->info.input.match([](const MTPDinputPeerUser &value) {
|
||||||
|
return !value.vaccess_hash.v;
|
||||||
|
}, [](const auto &data) { return false; })) {
|
||||||
|
finishMessages();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto handleResult = [=](const MTPmessages_Messages &result) mutable {
|
auto handleResult = [=](const MTPmessages_Messages &result) mutable {
|
||||||
Expects(_dialogsProcess != nullptr);
|
Expects(_dialogsProcess != nullptr);
|
||||||
Expects(_dialogsProcess->single != nullptr);
|
Expects(_dialogsProcess->single != nullptr);
|
||||||
|
@ -552,7 +615,7 @@ void ApiWrap::requestMessagesSlice() {
|
||||||
process->info.relativePath));
|
process->info.relativePath));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
if (onlyMyMessages()) {
|
if (process->info.onlyMyMessages) {
|
||||||
mainRequest(MTPmessages_Search(
|
mainRequest(MTPmessages_Search(
|
||||||
MTP_flags(MTPmessages_Search::Flag::f_from_id),
|
MTP_flags(MTPmessages_Search::Flag::f_from_id),
|
||||||
process->info.input,
|
process->info.input,
|
||||||
|
@ -582,26 +645,6 @@ void ApiWrap::requestMessagesSlice() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ApiWrap::onlyMyMessages() const {
|
|
||||||
Expects(_dialogsProcess != nullptr);
|
|
||||||
Expects(_dialogsProcess->single != nullptr);
|
|
||||||
|
|
||||||
const auto process = _dialogsProcess->single.get();
|
|
||||||
using Type = Data::DialogInfo::Type;
|
|
||||||
const auto setting = [&] {
|
|
||||||
switch (process->info.type) {
|
|
||||||
case Type::Personal: return Settings::Type::PersonalChats;
|
|
||||||
case Type::Bot: return Settings::Type::BotChats;
|
|
||||||
case Type::PrivateGroup: return Settings::Type::PrivateGroups;
|
|
||||||
case Type::PrivateChannel: return Settings::Type::PrivateChannels;
|
|
||||||
case Type::PublicGroup: return Settings::Type::PublicGroups;
|
|
||||||
case Type::PublicChannel: return Settings::Type::PublicChannels;
|
|
||||||
}
|
|
||||||
Unexpected("Type in ApiWrap::onlyMyMessages.");
|
|
||||||
}();
|
|
||||||
return (_settings->fullChats & setting) != setting;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ApiWrap::loadMessagesFiles(Data::MessagesSlice &&slice) {
|
void ApiWrap::loadMessagesFiles(Data::MessagesSlice &&slice) {
|
||||||
Expects(_dialogsProcess != nullptr);
|
Expects(_dialogsProcess != nullptr);
|
||||||
Expects(_dialogsProcess->single != nullptr);
|
Expects(_dialogsProcess->single != nullptr);
|
||||||
|
@ -637,12 +680,20 @@ void ApiWrap::loadNextMessageFile() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
finishMessagesSlice();
|
||||||
|
}
|
||||||
|
|
||||||
if (!list.empty()) {
|
void ApiWrap::finishMessagesSlice() {
|
||||||
process->offsetId = list.back().id + 1;
|
Expects(_dialogsProcess != nullptr);
|
||||||
|
Expects(_dialogsProcess->single != nullptr);
|
||||||
|
Expects(_dialogsProcess->single->slice.has_value());
|
||||||
|
|
||||||
|
const auto process = _dialogsProcess->single.get();
|
||||||
|
auto slice = *base::take(process->slice);
|
||||||
|
if (!slice.list.empty()) {
|
||||||
|
process->offsetId = slice.list.back().id + 1;
|
||||||
|
_dialogsProcess->sliceOne(std::move(slice));
|
||||||
}
|
}
|
||||||
_dialogsProcess->sliceOne(*base::take(process->slice));
|
|
||||||
|
|
||||||
if (process->lastSlice) {
|
if (process->lastSlice) {
|
||||||
finishMessages();
|
finishMessages();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
namespace Export {
|
namespace Export {
|
||||||
namespace Data {
|
namespace Data {
|
||||||
struct File;
|
struct File;
|
||||||
|
struct Chat;
|
||||||
struct FileLocation;
|
struct FileLocation;
|
||||||
struct PersonalInfo;
|
struct PersonalInfo;
|
||||||
struct UserpicsInfo;
|
struct UserpicsInfo;
|
||||||
|
@ -72,16 +73,16 @@ private:
|
||||||
|
|
||||||
void requestDialogsSlice();
|
void requestDialogsSlice();
|
||||||
void appendDialogsSlice(Data::DialogsInfo &&info);
|
void appendDialogsSlice(Data::DialogsInfo &&info);
|
||||||
|
void requestLeftChannels();
|
||||||
|
void requestLeftDialog();
|
||||||
void finishDialogsList();
|
void finishDialogsList();
|
||||||
void fillDialogsPaths();
|
|
||||||
|
|
||||||
void requestNextDialog();
|
void requestNextDialog();
|
||||||
void requestMessagesSlice();
|
void requestMessagesSlice();
|
||||||
bool onlyMyMessages() const;
|
|
||||||
void loadMessagesFiles(Data::MessagesSlice &&slice);
|
void loadMessagesFiles(Data::MessagesSlice &&slice);
|
||||||
void loadNextMessageFile();
|
void loadNextMessageFile();
|
||||||
|
|
||||||
void loadMessageFileDone(const QString &relativePath);
|
void loadMessageFileDone(const QString &relativePath);
|
||||||
|
void finishMessagesSlice();
|
||||||
void finishMessages();
|
void finishMessages();
|
||||||
void finishDialogs();
|
void finishDialogs();
|
||||||
|
|
||||||
|
|
|
@ -30,12 +30,17 @@ void SerializeMultiline(
|
||||||
auto offset = 0;
|
auto offset = 0;
|
||||||
do {
|
do {
|
||||||
appendTo.append("> ");
|
appendTo.append("> ");
|
||||||
|
const auto win = (newline > 0 && *(data + newline - 1) == '\r');
|
||||||
|
if (win) --newline;
|
||||||
appendTo.append(data + offset, newline - offset).append(kLineBreak);
|
appendTo.append(data + offset, newline - offset).append(kLineBreak);
|
||||||
|
if (win) ++newline;
|
||||||
offset = newline + 1;
|
offset = newline + 1;
|
||||||
newline = value.indexOf('\n', offset);
|
newline = value.indexOf('\n', offset);
|
||||||
} while (newline > 0);
|
} while (newline > 0);
|
||||||
appendTo.append("> ");
|
if (const auto size = value.size(); size > offset) {
|
||||||
appendTo.append(data + offset).append(kLineBreak);
|
appendTo.append("> ");
|
||||||
|
appendTo.append(data + offset, size - offset).append(kLineBreak);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray JoinList(
|
QByteArray JoinList(
|
||||||
|
@ -467,6 +472,9 @@ bool TextWriter::writeUserpicsStart(const Data::UserpicsInfo &data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TextWriter::writeUserpicsSlice(const Data::UserpicsSlice &data) {
|
bool TextWriter::writeUserpicsSlice(const Data::UserpicsSlice &data) {
|
||||||
|
Expects(_result != nullptr);
|
||||||
|
Expects(!data.list.empty());
|
||||||
|
|
||||||
auto lines = QByteArray();
|
auto lines = QByteArray();
|
||||||
for (const auto &userpic : data.list) {
|
for (const auto &userpic : data.list) {
|
||||||
if (!userpic.date) {
|
if (!userpic.date) {
|
||||||
|
@ -485,12 +493,16 @@ bool TextWriter::writeUserpicsSlice(const Data::UserpicsSlice &data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TextWriter::writeUserpicsEnd() {
|
bool TextWriter::writeUserpicsEnd() {
|
||||||
|
Expects(_result != nullptr);
|
||||||
|
|
||||||
return (_userpicsCount > 0)
|
return (_userpicsCount > 0)
|
||||||
? _result->writeBlock(kLineBreak) == File::Result::Success
|
? _result->writeBlock(kLineBreak) == File::Result::Success
|
||||||
: true;
|
: true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TextWriter::writeContactsList(const Data::ContactsList &data) {
|
bool TextWriter::writeContactsList(const Data::ContactsList &data) {
|
||||||
|
Expects(_result != nullptr);
|
||||||
|
|
||||||
if (data.list.empty()) {
|
if (data.list.empty()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -529,6 +541,8 @@ bool TextWriter::writeContactsList(const Data::ContactsList &data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TextWriter::writeSessionsList(const Data::SessionsList &data) {
|
bool TextWriter::writeSessionsList(const Data::SessionsList &data) {
|
||||||
|
Expects(_result != nullptr);
|
||||||
|
|
||||||
if (data.list.empty()) {
|
if (data.list.empty()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -568,6 +582,8 @@ bool TextWriter::writeSessionsList(const Data::SessionsList &data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TextWriter::writeDialogsStart(const Data::DialogsInfo &data) {
|
bool TextWriter::writeDialogsStart(const Data::DialogsInfo &data) {
|
||||||
|
Expects(_result != nullptr);
|
||||||
|
|
||||||
if (data.list.empty()) {
|
if (data.list.empty()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -635,12 +651,16 @@ bool TextWriter::writeDialogStart(const Data::DialogInfo &data) {
|
||||||
const auto digits = Data::NumberToString(_dialogsCount - 1).size();
|
const auto digits = Data::NumberToString(_dialogsCount - 1).size();
|
||||||
const auto number = Data::NumberToString(++_dialogIndex, digits, '0');
|
const auto number = Data::NumberToString(++_dialogIndex, digits, '0');
|
||||||
_dialog = fileWithRelativePath(data.relativePath + "messages.txt");
|
_dialog = fileWithRelativePath(data.relativePath + "messages.txt");
|
||||||
|
_dialogEmpty = true;
|
||||||
|
_dialogOnlyMy = data.onlyMyMessages;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TextWriter::writeMessagesSlice(const Data::MessagesSlice &data) {
|
bool TextWriter::writeMessagesSlice(const Data::MessagesSlice &data) {
|
||||||
Expects(_dialog != nullptr);
|
Expects(_dialog != nullptr);
|
||||||
|
Expects(!data.list.empty());
|
||||||
|
|
||||||
|
_dialogEmpty = false;
|
||||||
auto list = std::vector<QByteArray>();
|
auto list = std::vector<QByteArray>();
|
||||||
list.reserve(data.list.size());
|
list.reserve(data.list.size());
|
||||||
auto index = 0;
|
auto index = 0;
|
||||||
|
@ -659,6 +679,11 @@ bool TextWriter::writeMessagesSlice(const Data::MessagesSlice &data) {
|
||||||
bool TextWriter::writeDialogEnd() {
|
bool TextWriter::writeDialogEnd() {
|
||||||
Expects(_dialog != nullptr);
|
Expects(_dialog != nullptr);
|
||||||
|
|
||||||
|
if (_dialogEmpty) {
|
||||||
|
_dialog->writeBlock(_dialogOnlyMy
|
||||||
|
? "No outgoing messages in this chat."
|
||||||
|
: "No messages in this chat.");
|
||||||
|
}
|
||||||
_dialog = nullptr;
|
_dialog = nullptr;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,8 @@ private:
|
||||||
|
|
||||||
int _dialogsCount = 0;
|
int _dialogsCount = 0;
|
||||||
int _dialogIndex = 0;
|
int _dialogIndex = 0;
|
||||||
|
bool _dialogOnlyMy = false;
|
||||||
|
bool _dialogEmpty = true;
|
||||||
std::unique_ptr<File> _dialog;
|
std::unique_ptr<File> _dialog;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue