Reuse sending APIs and try to fix media references

This commit is contained in:
Eric Kotato 2020-09-11 09:23:30 +03:00
parent 23c8792935
commit eeaa4923a4
5 changed files with 404 additions and 292 deletions

View file

@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/unixtime.h" #include "base/unixtime.h"
#include "data/data_document.h" #include "data/data_document.h"
#include "data/data_photo.h" #include "data/data_photo.h"
#include "data/data_location.h"
#include "data/data_channel.h" // ChannelData::addsSignature. #include "data/data_channel.h" // ChannelData::addsSignature.
#include "data/data_user.h" // UserData::name #include "data/data_user.h" // UserData::name
#include "data/data_session.h" #include "data/data_session.h"
@ -62,7 +63,9 @@ void SendExistingMedia(
Api::MessageToSend &&message, Api::MessageToSend &&message,
not_null<MediaData*> media, not_null<MediaData*> media,
Fn<MTPInputMedia()> inputMedia, Fn<MTPInputMedia()> inputMedia,
Data::FileOrigin origin) { Data::FileOrigin origin,
Fn<void()> doneCallback = nullptr,
bool forwarding = false) {
const auto history = message.action.history; const auto history = message.action.history;
const auto peer = history->peer; const auto peer = history->peer;
const auto session = &history->session(); const auto session = &history->session();
@ -135,7 +138,6 @@ void SendExistingMedia(
auto &histories = history->owner().histories(); auto &histories = history->owner().histories();
const auto requestType = Data::Histories::RequestType::Send; const auto requestType = Data::Histories::RequestType::Send;
histories.sendRequest(history, requestType, [=](Fn<void()> finish) { histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
const auto usedFileReference = media->fileReference();
history->sendRequestId = api->request(MTPmessages_SendMedia( history->sendRequestId = api->request(MTPmessages_SendMedia(
MTP_flags(sendFlags), MTP_flags(sendFlags),
peer->input, peer->input,
@ -146,12 +148,16 @@ void SendExistingMedia(
MTPReplyMarkup(), MTPReplyMarkup(),
sentEntities, sentEntities,
MTP_int(message.action.options.scheduled) MTP_int(message.action.options.scheduled)
)).done([=](const MTPUpdates &result) { )).done([=](const MTPUpdates &result, mtpRequestId requestId) {
api->applyUpdates(result, randomId); api->applyUpdates(result, randomId);
if (doneCallback) {
doneCallback();
}
finish(); finish();
}).fail([=](const RPCError &error) { }).fail([=](const RPCError &error) {
if (error.code() == 400 if (error.code() == 400
&& error.type().startsWith(qstr("FILE_REFERENCE_"))) { && error.type().startsWith(qstr("FILE_REFERENCE_"))) {
const auto usedFileReference = media->fileReference();
api->refreshFileReference(origin, [=](const auto &result) { api->refreshFileReference(origin, [=](const auto &result) {
if (media->fileReference() != usedFileReference) { if (media->fileReference() != usedFileReference) {
repeatRequest(repeatRequest); repeatRequest(repeatRequest);
@ -170,14 +176,18 @@ void SendExistingMedia(
}; };
performRequest(performRequest); performRequest(performRequest);
api->finishForwarding(message.action); if (!forwarding) {
api->finishForwarding(message.action);
}
} }
} // namespace } // namespace
void SendExistingDocument( void SendExistingDocument(
Api::MessageToSend &&message, Api::MessageToSend &&message,
not_null<DocumentData*> document) { not_null<DocumentData*> document,
Fn<void()> doneCallback,
bool forwarding) {
const auto inputMedia = [=] { const auto inputMedia = [=] {
return MTP_inputMediaDocument( return MTP_inputMediaDocument(
MTP_flags(0), MTP_flags(0),
@ -188,7 +198,9 @@ void SendExistingDocument(
std::move(message), std::move(message),
document, document,
inputMedia, inputMedia,
document->stickerOrGifOrigin()); document->stickerOrGifOrigin(),
(doneCallback ? std::move(doneCallback) : nullptr),
forwarding);
if (document->sticker()) { if (document->sticker()) {
document->owner().stickers().incrementSticker(document); document->owner().stickers().incrementSticker(document);
@ -197,7 +209,9 @@ void SendExistingDocument(
void SendExistingPhoto( void SendExistingPhoto(
Api::MessageToSend &&message, Api::MessageToSend &&message,
not_null<PhotoData*> photo) { not_null<PhotoData*> photo,
Fn<void()> doneCallback,
bool forwarding) {
const auto inputMedia = [=] { const auto inputMedia = [=] {
return MTP_inputMediaPhoto( return MTP_inputMediaPhoto(
MTP_flags(0), MTP_flags(0),
@ -208,7 +222,9 @@ void SendExistingPhoto(
std::move(message), std::move(message),
photo, photo,
inputMedia, inputMedia,
Data::FileOrigin()); Data::FileOrigin(),
(doneCallback ? std::move(doneCallback) : nullptr),
forwarding);
} }
bool SendDice(Api::MessageToSend &message) { bool SendDice(Api::MessageToSend &message) {
@ -550,4 +566,64 @@ void SendConfirmedFile(
} }
} }
void SendLocationPoint(
const Data::LocationPoint &data,
const SendAction &action,
Fn<void()> done,
Fn<void(const RPCError &error)> fail) {
const auto history = action.history;
const auto session = &history->session();
const auto api = &session->api();
const auto peer = history->peer;
api->sendAction(action);
auto sendFlags = MTPmessages_SendMedia::Flags(0);
if (action.replyTo) {
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id;
}
if (action.clearDraft) {
sendFlags |= MTPmessages_SendMedia::Flag::f_clear_draft;
history->clearLocalDraft();
history->clearCloudDraft();
}
const auto silentPost = action.options.silent
|| (peer->isBroadcast() && session->data().notifySilentPosts(peer));
if (silentPost) {
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
}
if (action.options.scheduled) {
sendFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
}
auto &histories = history->owner().histories();
const auto requestType = Data::Histories::RequestType::Send;
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
const auto replyTo = action.replyTo;
history->sendRequestId = api->request(MTPmessages_SendMedia(
MTP_flags(sendFlags),
peer->input,
MTP_int(replyTo),
MTP_inputMediaGeoPoint(
MTP_inputGeoPoint(
MTP_double(data.lat()),
MTP_double(data.lon()))),
MTP_string(),
MTP_long(rand_value<uint64>()),
MTPReplyMarkup(),
MTPVector<MTPMessageEntity>(),
MTP_int(action.options.scheduled)
)).done([=](const MTPUpdates &result) mutable {
api->applyUpdates(result);
done();
finish();
}).fail([=](const RPCError &error) mutable {
if (fail) {
fail(error);
}
finish();
}).afterRequest(history->sendRequestId
).send();
return history->sendRequestId;
});
}
} // namespace Api } // namespace Api

View file

@ -11,6 +11,11 @@ class History;
class PhotoData; class PhotoData;
class DocumentData; class DocumentData;
struct FileLoadResult; struct FileLoadResult;
class RPCError;
namespace Data {
class LocationPoint;
} // namespace Data
namespace Api { namespace Api {
@ -19,11 +24,15 @@ struct SendAction;
void SendExistingDocument( void SendExistingDocument(
Api::MessageToSend &&message, Api::MessageToSend &&message,
not_null<DocumentData*> document); not_null<DocumentData*> document,
Fn<void()> doneCallback = nullptr,
bool forwarding = false);
void SendExistingPhoto( void SendExistingPhoto(
Api::MessageToSend &&message, Api::MessageToSend &&message,
not_null<PhotoData*> photo); not_null<PhotoData*> photo,
Fn<void()> doneCallback = nullptr,
bool forwarding = false);
bool SendDice(Api::MessageToSend &message); bool SendDice(Api::MessageToSend &message);
@ -37,4 +46,10 @@ void SendConfirmedFile(
const std::shared_ptr<FileLoadResult> &file, const std::shared_ptr<FileLoadResult> &file,
const std::optional<FullMsgId> &oldId); const std::optional<FullMsgId> &oldId);
void SendLocationPoint(
const Data::LocationPoint &data,
const SendAction &action,
Fn<void()> done,
Fn<void(const RPCError &error)> fail);
} // namespace Api } // namespace Api

View file

@ -4086,7 +4086,9 @@ void ApiWrap::forwardMessages(
++shared->requestsLeft; ++shared->requestsLeft;
} }
auto medias = QVector<MTPInputSingleMedia>(); auto medias = QVector<MTPInputSingleMedia>();
auto mediaRefs = QVector<QByteArray>();
medias.reserve(ids.size()); medias.reserve(ids.size());
mediaRefs.reserve(ids.size());
for (auto i = fromIter, e = toIter; i != e; i++) { for (auto i = fromIter, e = toIter; i != e; i++) {
const auto item = *i; const auto item = *i;
@ -4125,33 +4127,74 @@ void ApiWrap::forwardMessages(
: MTPmessages_SendMultiMedia::Flag(0)); : MTPmessages_SendMultiMedia::Flag(0));
const auto requestType = Data::Histories::RequestType::Send; const auto requestType = Data::Histories::RequestType::Send;
histories.sendRequest(history, requestType, [=](Fn<void()> finish) { auto performRequest = [=, &mediaRefs, &histories](const auto &repeatRequest) -> void {
history->sendRequestId = request(MTPmessages_SendMultiMedia( mediaRefs.clear();
MTP_flags(finalFlags), for (auto i = fromIter, e = toIter; i != e; i++) {
peer->input, const auto item = *i;
MTPint(), const auto media = item->media();
MTP_vector<MTPInputSingleMedia>(medias), mediaRefs.push_back(media->photo()
MTP_int(action.options.scheduled) ? media->photo()->fileReference()
)).done([=](const MTPUpdates &result) { : media->document()->fileReference());
applyUpdates(result); }
if (shared && !--shared->requestsLeft) { histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
shared->callback(); history->sendRequestId = request(MTPmessages_SendMultiMedia(
} MTP_flags(finalFlags),
finish(); peer->input,
}).fail([=, ids = localIds](const RPCError &error) { MTPint(),
if (ids) { MTP_vector<MTPInputSingleMedia>(medias),
for (const auto &[randomId, itemId] : *ids) { MTP_int(action.options.scheduled)
sendMessageFail(error, peer, randomId, itemId); )).done([=](const MTPUpdates &result) {
applyUpdates(result);
if (shared && !--shared->requestsLeft) {
shared->callback();
} }
} else { finish();
sendMessageFail(error, peer); }).fail([=, ids = localIds](const RPCError &error) {
} if (error.code() == 400
finish(); && error.type().startsWith(qstr("FILE_REFERENCE_"))) {
}).afterRequest( auto refreshRequests = mediaRefs.size();
history->sendRequestId auto index = 0;
).send(); for (auto i = fromIter, e = toIter; i != e; i++) {
return history->sendRequestId; const auto item = *i;
}); const auto media = item->media();
const auto origin = media->document()
? media->document()->stickerOrGifOrigin()
: Data::FileOrigin();
const auto usedFileReference = mediaRefs.value(index);
refreshFileReference(origin, [=, &refreshRequests](const auto &result) {
if (refreshRequests > 0) {
refreshRequests--;
return;
}
const auto currentMediaReference = media->photo()
? media->photo()->fileReference()
: media->document()->fileReference();
if (currentMediaReference != usedFileReference) {
repeatRequest(repeatRequest);
} else {
sendMessageFail(error, peer);
}
});
index++;
}
} else if (ids) {
for (const auto &[randomId, itemId] : *ids) {
sendMessageFail(error, peer, randomId, itemId);
}
} else {
sendMessageFail(error, peer);
}
finish();
}).afterRequest(
history->sendRequestId
).send();
return history->sendRequestId;
});
};
performRequest(performRequest);
}; };
const auto forwardMediaUnquoted = [&] (not_null<HistoryItem *> item) { const auto forwardMediaUnquoted = [&] (not_null<HistoryItem *> item) {
@ -4160,86 +4203,62 @@ void ApiWrap::forwardMessages(
} }
const auto media = item->media(); const auto media = item->media();
auto newSendFlags = MTPmessages_SendMedia::Flags(0) auto message = ApiWrap::MessageToSend(history);
| (action.options.silent const auto caption = (cForwardCaptioned()
? MTPmessages_SendMedia::Flag::f_silent && !media->geoPoint()
: MTPmessages_SendMedia::Flag(0)) && !media->sharedContact())
| (action.options.scheduled ? item->originalText()
? MTPmessages_SendMedia::Flag::f_schedule_date : TextWithEntities();
: MTPmessages_SendMedia::Flag(0));
auto caption = (cForwardCaptioned() message.textWithTags = TextWithTags{
&& !media->geoPoint() caption.text,
&& !media->sharedContact()) TextUtilities::ConvertEntitiesToTextTags(caption.entities)
? item->originalText() };
: TextWithEntities(); message.action.options = action.options;
message.action.clearDraft = false;
auto sentEntities = Api::EntitiesToMTP( auto doneCallback = [=] () {
_session, if (shared && !--shared->requestsLeft) {
caption.entities, shared->callback();
Api::ConvertOption::SkipLocal); }
if (!sentEntities.v.isEmpty()) { };
newSendFlags |= MTPmessages_SendMedia::Flag::f_entities;
if (media->poll()) {
const auto poll = *(media->poll());
createPoll(
poll,
message.action,
std::move(doneCallback),
nullptr);
} else if (media->geoPoint()) {
const auto location = *(media->geoPoint());
Api::SendLocationPoint(
location,
message.action,
std::move(doneCallback),
nullptr);
} else if (media->sharedContact()) {
const auto contact = media->sharedContact();
shareContact(
contact->phoneNumber,
contact->firstName,
contact->lastName,
message.action);
} else if (media->photo()) {
Api::SendExistingPhoto(
std::move(message),
media->photo(),
std::move(doneCallback),
true); // forwarding
} else if (media->document()) {
Api::SendExistingDocument(
std::move(message),
media->document(),
std::move(doneCallback),
true); // forwarding
} else {
Unexpected("Media type in ApiWrap::forwardMessages.");
} }
auto inputMedia = media->poll()
? PollDataToInputMedia(media->poll())
: media->geoPoint()
? MTP_inputMediaGeoPoint(
MTP_inputGeoPoint(
MTP_double(media->geoPoint()->lat()),
MTP_double(media->geoPoint()->lon())))
: media->sharedContact()
? MTP_inputMediaContact(
MTP_string(media->sharedContact()->phoneNumber),
MTP_string(media->sharedContact()->firstName),
MTP_string(media->sharedContact()->lastName),
MTPstring())
: media->photo()
? MTP_inputMediaPhoto(MTP_flags(0), media->photo()->mtpInput(), MTPint())
: MTP_inputMediaDocument(MTP_flags(0), media->document()->mtpInput(), MTPint());
const auto requestType = Data::Histories::RequestType::Send;
const auto currentRandomId = randomIds.takeFirst();
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
history->sendRequestId = request(MTPmessages_SendMedia(
MTP_flags(newSendFlags),
peer->input,
MTPint(),
inputMedia,
MTP_string(caption.text),
currentRandomId,
MTPReplyMarkup(),
sentEntities,
MTP_int(action.options.scheduled)
)).done([=](const MTPUpdates &result) {
applyUpdates(result);
if (shared && !--shared->requestsLeft) {
shared->callback();
}
finish();
}).fail([=, ids = localIds](const RPCError &error) {
if (ids) {
auto found = false;
for (const auto &[randomId, itemId] : *ids) {
if (currentRandomId == MTP_long(randomId)) {
sendMessageFail(error, peer, randomId, itemId);
found = true;
break;
}
}
if (!found) {
sendMessageFail(error, peer);
}
} else {
sendMessageFail(error, peer);
}
finish();
}).afterRequest(
history->sendRequestId
).send();
return history->sendRequestId;
});
}; };
const auto forwardMessageUnquoted = [&] (not_null<HistoryItem *> item) { const auto forwardMessageUnquoted = [&] (not_null<HistoryItem *> item) {
@ -4248,65 +4267,27 @@ void ApiWrap::forwardMessages(
} }
const auto media = item->media(); const auto media = item->media();
auto newSendFlags = MTPmessages_SendMessage::Flag(0) const auto webPageId = (!media || !media->webpage())
| (!media || !media->webpage() ? CancelledWebPageId
? MTPmessages_SendMessage::Flag::f_no_webpage : media->webpage()->id;
: MTPmessages_SendMessage::Flag(0))
| (action.options.silent
? MTPmessages_SendMessage::Flag::f_silent
: MTPmessages_SendMessage::Flag(0))
| (action.options.scheduled
? MTPmessages_SendMessage::Flag::f_schedule_date
: MTPmessages_SendMessage::Flag(0));
auto sentEntities = Api::EntitiesToMTP( auto message = ApiWrap::MessageToSend(history);
_session, message.textWithTags = TextWithTags{
item->originalText().entities, item->originalText().text,
Api::ConvertOption::SkipLocal); TextUtilities::ConvertEntitiesToTextTags(item->originalText().entities)
if (!sentEntities.v.isEmpty()) { };
newSendFlags |= MTPmessages_SendMessage::Flag::f_entities; message.action.options = action.options;
} message.action.clearDraft = false;
message.webPageId = webPageId;
const auto requestType = Data::Histories::RequestType::Send; session().api().sendMessage(
const auto currentRandomId = randomIds.takeFirst(); std::move(message),
histories.sendRequest(history, requestType, [=](Fn<void()> finish) { [=] (const MTPUpdates &result, mtpRequestId requestId) {
history->sendRequestId = request(MTPmessages_SendMessage(
MTP_flags(newSendFlags),
peer->input,
MTPint(),
MTP_string(item->originalText().text),
currentRandomId,
MTPReplyMarkup(),
sentEntities,
MTP_int(action.options.scheduled)
)).done([=](const MTPUpdates &result) {
applyUpdates(result);
if (shared && !--shared->requestsLeft) { if (shared && !--shared->requestsLeft) {
shared->callback(); shared->callback();
} }
finish(); },
}).fail([=, ids = localIds](const RPCError &error) { true); // forwarding
if (ids) {
auto found = false;
for (const auto &[randomId, itemId] : *ids) {
if (currentRandomId == MTP_long(randomId)) {
sendMessageFail(error, peer, randomId, itemId);
found = true;
break;
}
}
if (!found) {
sendMessageFail(error, peer);
}
} else {
sendMessageFail(error, peer);
}
finish();
}).afterRequest(
history->sendRequestId
).send();
return history->sendRequestId;
});
}; };
const auto sendAccumulated = [&] { const auto sendAccumulated = [&] {
@ -4650,7 +4631,10 @@ void ApiWrap::cancelLocalItem(not_null<HistoryItem*> item) {
} }
} }
void ApiWrap::sendMessage(MessageToSend &&message) { void ApiWrap::sendMessage(
MessageToSend &&message,
Fn<void(const MTPUpdates &, mtpRequestId)> doneCallback,
bool forwarding) {
const auto history = message.action.history; const auto history = message.action.history;
const auto peer = history->peer; const auto peer = history->peer;
auto &textWithTags = message.textWithTags; auto &textWithTags = message.textWithTags;
@ -4779,9 +4763,12 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
MTPReplyMarkup(), MTPReplyMarkup(),
sentEntities, sentEntities,
MTP_int(action.options.scheduled) MTP_int(action.options.scheduled)
)).done([=](const MTPUpdates &result) { )).done([=](const MTPUpdates &result, mtpRequestId requestId) {
applyUpdates(result, randomId); applyUpdates(result, randomId);
history->clearSentDraftText(QString()); history->clearSentDraftText(QString());
if (doneCallback) {
doneCallback(result, requestId);
}
finish(); finish();
}).fail([=](const RPCError &error) { }).fail([=](const RPCError &error) {
if (error.type() == qstr("MESSAGE_EMPTY")) { if (error.type() == qstr("MESSAGE_EMPTY")) {
@ -4797,7 +4784,9 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
}); });
} }
finishForwarding(action); if (!forwarding) {
finishForwarding(action);
}
} }
void ApiWrap::sendBotStart(not_null<UserData*> bot, PeerData *chat) { void ApiWrap::sendBotStart(not_null<UserData*> bot, PeerData *chat) {
@ -5621,7 +5610,9 @@ void ApiWrap::createPoll(
done(); done();
finish(); finish();
}).fail([=](const RPCError &error) mutable { }).fail([=](const RPCError &error) mutable {
fail(error); if (fail) {
fail(error);
}
finish(); finish();
}).afterRequest(history->sendRequestId }).afterRequest(history->sendRequestId
).send(); ).send();

View file

@ -421,7 +421,10 @@ public:
void cancelLocalItem(not_null<HistoryItem*> item); void cancelLocalItem(not_null<HistoryItem*> item);
void sendMessage(MessageToSend &&message); void sendMessage(
MessageToSend &&message,
Fn<void(const MTPUpdates &, mtpRequestId)> doneCallback = nullptr,
bool forwarding = false);
void sendBotStart(not_null<UserData*> bot, PeerData *chat = nullptr); void sendBotStart(not_null<UserData*> bot, PeerData *chat = nullptr);
void sendInlineResult( void sendInlineResult(
not_null<UserData*> bot, not_null<UserData*> bot,

View file

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "window/window_peer_menu.h" #include "window/window_peer_menu.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "api/api_sending.h"
#include "boxes/confirm_box.h" #include "boxes/confirm_box.h"
#include "boxes/mute_settings_box.h" #include "boxes/mute_settings_box.h"
#include "boxes/add_contact_box.h" #include "boxes/add_contact_box.h"
@ -54,9 +55,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_drafts.h" #include "data/data_drafts.h"
#include "data/data_user.h" #include "data/data_user.h"
#include "data/data_game.h" #include "data/data_game.h"
#include "data/data_web_page.h"
#include "data/data_scheduled_messages.h" #include "data/data_scheduled_messages.h"
#include "data/data_histories.h" #include "data/data_histories.h"
#include "data/data_chat_filters.h" #include "data/data_chat_filters.h"
#include "data/data_file_origin.h"
#include "dialogs/dialogs_key.h" #include "dialogs/dialogs_key.h"
#include "core/application.h" #include "core/application.h"
#include "export/export_manager.h" #include "export/export_manager.h"
@ -1116,7 +1119,7 @@ QPointer<Ui::RpWidget> ShowForwardMessagesBox(
} }
not_null<PeerData*> peer; not_null<PeerData*> peer;
MessageIdsList msgIds; MessageIdsList msgIds;
base::flat_set<mtpRequestId> requests; int requestsLeft = 0;
FnMut<void()> submitCallback; FnMut<void()> submitCallback;
}; };
struct MsgIdsGroup { struct MsgIdsGroup {
@ -1188,7 +1191,7 @@ QPointer<Ui::RpWidget> ShowForwardMessagesBox(
std::vector<not_null<PeerData*>> &&result, std::vector<not_null<PeerData*>> &&result,
TextWithTags &&comment, TextWithTags &&comment,
Api::SendOptions options) { Api::SendOptions options) {
if (!data->requests.empty()) { if (data->requestsLeft > 0) {
return; // Share clicked already. return; // Share clicked already.
} }
auto items = history->owner().idsToItems(data->msgIds); auto items = history->owner().idsToItems(data->msgIds);
@ -1278,9 +1281,9 @@ QPointer<Ui::RpWidget> ShowForwardMessagesBox(
} }
return result; return result;
}; };
const auto checkAndClose = [=] (mtpRequestId requestId) { const auto checkAndClose = [=] {
data->requests.remove(requestId); data->requestsLeft--;
if (data->requests.empty()) { if (!data->requestsLeft) {
Ui::Toast::Show(tr::lng_share_done(tr::now)); Ui::Toast::Show(tr::lng_share_done(tr::now));
Ui::hideLayer(); Ui::hideLayer();
} }
@ -1304,19 +1307,21 @@ QPointer<Ui::RpWidget> ShowForwardMessagesBox(
MTP_int(options.scheduled) MTP_int(options.scheduled)
)).done([=](const MTPUpdates &updates, mtpRequestId requestId) { )).done([=](const MTPUpdates &updates, mtpRequestId requestId) {
history->session().api().applyUpdates(updates); history->session().api().applyUpdates(updates);
checkAndClose(requestId); checkAndClose();
finish(); finish();
}).fail([=](const RPCError &error) { }).fail([=](const RPCError &error) {
finish(); finish();
}).afterRequest(history->sendRequestId).send(); }).afterRequest(history->sendRequestId).send();
return history->sendRequestId; return history->sendRequestId;
}); });
data->requests.insert(history->sendRequestId); data->requestsLeft++;
}; };
const auto forwardAlbumUnquoted = [&] (MsgIdsGroup &&group, not_null<History*> history) { const auto forwardAlbumUnquoted = [&] (MsgIdsGroup &&group, not_null<History*> history) {
auto medias = QVector<MTPInputSingleMedia>(); auto medias = QVector<MTPInputSingleMedia>();
auto mediaRefs = QVector<QByteArray>();
medias.reserve(group.items.size()); medias.reserve(group.items.size());
mediaRefs.reserve(group.items.size());
auto randomIds = generateRandom(group.items.size()); auto randomIds = generateRandom(group.items.size());
@ -1345,6 +1350,9 @@ QPointer<Ui::RpWidget> ShowForwardMessagesBox(
randomId, randomId,
MTP_string(caption.text), MTP_string(caption.text),
sentEntities)); sentEntities));
mediaRefs.push_back(media->photo()
? media->photo()->fileReference()
: media->document()->fileReference());
} }
const auto flags = MTPmessages_SendMultiMedia::Flags(0) const auto flags = MTPmessages_SendMultiMedia::Flags(0)
@ -1355,135 +1363,154 @@ QPointer<Ui::RpWidget> ShowForwardMessagesBox(
? MTPmessages_SendMultiMedia::Flag::f_schedule_date ? MTPmessages_SendMultiMedia::Flag::f_schedule_date
: MTPmessages_SendMultiMedia::Flag(0)); : MTPmessages_SendMultiMedia::Flag(0));
histories.sendRequest(history, requestType, [=](Fn<void()> finish) { auto performRequest = [=, &mediaRefs, &histories](const auto &repeatRequest) -> void {
auto &api = history->session().api(); mediaRefs.clear();
history->sendRequestId = api.request(MTPmessages_SendMultiMedia( for (const auto item : group.items) {
MTP_flags(flags), const auto media = item->media();
history->peer->input, mediaRefs.push_back(media->photo()
MTPint(), ? media->photo()->fileReference()
MTP_vector<MTPInputSingleMedia>(medias), : media->document()->fileReference());
MTP_int(options.scheduled) }
)).done([=](const MTPUpdates &updates, mtpRequestId requestId) { histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
history->session().api().applyUpdates(updates); auto &api = history->session().api();
checkAndClose(requestId); history->sendRequestId = api.request(MTPmessages_SendMultiMedia(
finish(); MTP_flags(flags),
}).fail([=](const RPCError &error) { history->peer->input,
finish(); MTPint(),
}).afterRequest(history->sendRequestId).send(); MTP_vector<MTPInputSingleMedia>(medias),
return history->sendRequestId; MTP_int(options.scheduled)
}); )).done([=](const MTPUpdates &updates, mtpRequestId requestId) {
data->requests.insert(history->sendRequestId); history->session().api().applyUpdates(updates);
checkAndClose();
finish();
}).fail([=](const RPCError &error) {
if (error.code() == 400
&& error.type().startsWith(qstr("FILE_REFERENCE_"))) {
auto refreshRequests = mediaRefs.size();
auto index = 0;
for (const auto item : group.items) {
const auto media = item->media();
const auto origin = media->document()
? media->document()->stickerOrGifOrigin()
: Data::FileOrigin();
const auto usedFileReference = mediaRefs.value(index);
history->session().api().refreshFileReference(origin, [=, &refreshRequests](const auto &result) {
if (refreshRequests > 0) {
refreshRequests--;
return;
}
const auto currentMediaReference = media->photo()
? media->photo()->fileReference()
: media->document()->fileReference();
if (currentMediaReference != usedFileReference) {
repeatRequest(repeatRequest);
} else {
history->session().api().sendMessageFail(error, history->peer);
}
});
index++;
}
} else {
finish();
}
}).afterRequest(history->sendRequestId).send();
return history->sendRequestId;
});
};
performRequest(performRequest);
data->requestsLeft++;
}; };
const auto forwardMediaUnquoted = [&] (not_null<HistoryItem *> item, not_null<History*> history) { const auto forwardMediaUnquoted = [&] (not_null<HistoryItem *> item, not_null<History*> history) {
const auto media = item->media(); const auto media = item->media();
auto newSendFlags = MTPmessages_SendMedia::Flags(0) auto message = ApiWrap::MessageToSend(history);
| (options.silent
? MTPmessages_SendMedia::Flag::f_silent
: MTPmessages_SendMedia::Flag(0))
| (options.scheduled
? MTPmessages_SendMedia::Flag::f_schedule_date
: MTPmessages_SendMedia::Flag(0));
const auto caption = (cForwardCaptioned() const auto caption = (cForwardCaptioned()
&& !media->geoPoint() && !media->geoPoint()
&& !media->sharedContact()) && !media->sharedContact())
? item->originalText() ? item->originalText()
: TextWithEntities(); : TextWithEntities();
const auto sentEntities = Api::EntitiesToMTP( message.textWithTags = TextWithTags{
session, caption.text,
caption.entities, TextUtilities::ConvertEntitiesToTextTags(caption.entities)
Api::ConvertOption::SkipLocal); };
if (!sentEntities.v.isEmpty()) { message.action.options = options;
newSendFlags |= MTPmessages_SendMedia::Flag::f_entities; message.action.clearDraft = false;
auto doneCallback = [=] () {
checkAndClose();
};
auto &api = history->session().api();
if (media->poll()) {
const auto poll = *(media->poll());
api.createPoll(
poll,
message.action,
std::move(doneCallback),
nullptr);
} else if (media->geoPoint()) {
const auto location = *(media->geoPoint());
Api::SendLocationPoint(
location,
message.action,
std::move(doneCallback),
nullptr);
} else if (media->sharedContact()) {
const auto contact = media->sharedContact();
api.shareContact(
contact->phoneNumber,
contact->firstName,
contact->lastName,
message.action);
} else if (media->photo()) {
Api::SendExistingPhoto(
std::move(message),
media->photo(),
std::move(doneCallback),
true); // forwarding
} else if (media->document()) {
Api::SendExistingDocument(
std::move(message),
media->document(),
std::move(doneCallback),
true); // forwarding
} else {
Unexpected("Media type in Window::ShowForwardMessagesBox.");
} }
const auto inputMedia = media->poll() data->requestsLeft++;
? PollDataToInputMedia(media->poll())
: media->geoPoint()
? MTP_inputMediaGeoPoint(
MTP_inputGeoPoint(
MTP_double(media->geoPoint()->lat()),
MTP_double(media->geoPoint()->lon())))
: media->sharedContact()
? MTP_inputMediaContact(
MTP_string(media->sharedContact()->phoneNumber),
MTP_string(media->sharedContact()->firstName),
MTP_string(media->sharedContact()->lastName),
MTPstring())
: media->photo()
? MTP_inputMediaPhoto(MTP_flags(0), media->photo()->mtpInput(), MTPint())
: MTP_inputMediaDocument(MTP_flags(0), media->document()->mtpInput(), MTPint());
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
auto &api = history->session().api();
history->sendRequestId = api.request(MTPmessages_SendMedia(
MTP_flags(newSendFlags),
history->peer->input,
MTPint(),
inputMedia,
MTP_string(caption.text),
rand_value<MTPlong>(),
MTPReplyMarkup(),
sentEntities,
MTP_int(options.scheduled)
)).done([=](const MTPUpdates &updates, mtpRequestId requestId) {
history->session().api().applyUpdates(updates);
checkAndClose(requestId);
finish();
}).fail([=](const RPCError &error) {
finish();
}).afterRequest(history->sendRequestId).send();
return history->sendRequestId;
});
data->requests.insert(history->sendRequestId);
}; };
const auto forwardMessageUnquoted = [&] (not_null<HistoryItem *> item, not_null<History*> history) { const auto forwardMessageUnquoted = [&] (not_null<HistoryItem *> item, not_null<History*> history) {
const auto media = item->media(); const auto media = item->media();
auto newSendFlags = MTPmessages_SendMessage::Flag(0) const auto webPageId = (!media || !media->webpage())
| (!media || !media->webpage() ? CancelledWebPageId
? MTPmessages_SendMessage::Flag::f_no_webpage : media->webpage()->id;
: MTPmessages_SendMessage::Flag(0))
| (options.silent
? MTPmessages_SendMessage::Flag::f_silent
: MTPmessages_SendMessage::Flag(0))
| (options.scheduled
? MTPmessages_SendMessage::Flag::f_schedule_date
: MTPmessages_SendMessage::Flag(0));
const auto sentEntities = Api::EntitiesToMTP( auto message = ApiWrap::MessageToSend(history);
session, message.textWithTags = TextWithTags{
item->originalText().entities, item->originalText().text,
Api::ConvertOption::SkipLocal); TextUtilities::ConvertEntitiesToTextTags(item->originalText().entities)
if (!sentEntities.v.isEmpty()) { };
newSendFlags |= MTPmessages_SendMessage::Flag::f_entities; message.action.options = options;
} message.action.clearDraft = false;
message.webPageId = webPageId;
histories.sendRequest(history, requestType, [=](Fn<void()> finish) { history->session().api().sendMessage(
auto &api = history->session().api(); std::move(message),
history->sendRequestId = api.request(MTPmessages_SendMessage( [=] (const MTPUpdates &result, mtpRequestId requestId) {
MTP_flags(newSendFlags), checkAndClose();
history->peer->input, },
MTPint(), true); // forwarding
MTP_string(item->originalText().text),
rand_value<MTPlong>(), data->requestsLeft++;
MTPReplyMarkup(),
sentEntities,
MTP_int(options.scheduled)
)).done([=](const MTPUpdates &updates, mtpRequestId requestId) {
history->session().api().applyUpdates(updates);
checkAndClose(requestId);
finish();
}).fail([=](const RPCError &error) {
finish();
}).afterRequest(history->sendRequestId).send();
return history->sendRequestId;
});
data->requests.insert(history->sendRequestId);
}; };
for (const auto peer : result) { for (const auto peer : result) {