tdesktop/Telegram/SourceFiles/api/api_sending.cpp

310 lines
9.1 KiB
C++
Raw Normal View History

2019-07-17 14:34:39 +00:00
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "api/api_sending.h"
2019-09-16 11:14:06 +00:00
#include "api/api_text_entities.h"
2019-07-17 14:34:39 +00:00
#include "base/unixtime.h"
#include "data/data_document.h"
#include "data/data_photo.h"
#include "data/data_channel.h" // ChannelData::addsSignature.
#include "data/data_user.h" // UserData::name
2019-07-17 14:34:39 +00:00
#include "data/data_session.h"
#include "data/data_file_origin.h"
#include "data/data_histories.h"
2019-07-17 14:34:39 +00:00
#include "history/history.h"
#include "history/history_message.h" // NewMessageFlags.
#include "chat_helpers/message_field.h" // ConvertTextTagsToEntities.
2019-07-17 14:34:39 +00:00
#include "ui/text/text_entity.h" // TextWithEntities.
2019-07-24 11:45:24 +00:00
#include "main/main_session.h"
2019-07-17 14:34:39 +00:00
#include "mainwidget.h"
#include "apiwrap.h"
#include "app.h"
2019-07-17 14:34:39 +00:00
namespace Api {
namespace {
template <typename MediaData>
void SendExistingMedia(
Api::MessageToSend &&message,
2019-07-17 14:34:39 +00:00
not_null<MediaData*> media,
Fn<MTPInputMedia()> inputMedia,
Data::FileOrigin origin) {
const auto history = message.action.history;
2019-07-17 14:34:39 +00:00
const auto peer = history->peer;
const auto session = &history->session();
const auto api = &session->api();
message.action.clearDraft = false;
message.action.generateLocal = true;
api->sendAction(message.action);
2019-07-17 14:34:39 +00:00
2019-08-12 16:33:36 +00:00
const auto newId = FullMsgId(
peerToChannel(peer->id),
session->data().nextLocalMessageId());
2019-07-17 14:34:39 +00:00
const auto randomId = rand_value<uint64>();
auto flags = NewMessageFlags(peer) | MTPDmessage::Flag::f_media;
auto clientFlags = NewMessageClientFlags();
2019-07-17 14:34:39 +00:00
auto sendFlags = MTPmessages_SendMedia::Flags(0);
if (message.action.replyTo) {
2019-07-17 14:34:39 +00:00
flags |= MTPDmessage::Flag::f_reply_to_msg_id;
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id;
}
2019-07-26 16:06:22 +00:00
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
const auto silentPost = message.action.options.silent
2019-07-26 16:06:22 +00:00
|| (channelPost && session->data().notifySilentPosts(peer));
2019-07-17 14:34:39 +00:00
if (channelPost) {
flags |= MTPDmessage::Flag::f_views;
flags |= MTPDmessage::Flag::f_post;
}
if (!channelPost) {
flags |= MTPDmessage::Flag::f_from_id;
} else if (peer->asChannel()->addsSignature()) {
flags |= MTPDmessage::Flag::f_post_author;
}
if (silentPost) {
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
}
auto messageFromId = channelPost ? 0 : session->userId();
auto messagePostAuthor = channelPost ? session->user()->name : QString();
2019-07-17 14:34:39 +00:00
auto caption = TextWithEntities{
message.textWithTags.text,
2019-09-16 11:14:06 +00:00
TextUtilities::ConvertTextTagsToEntities(message.textWithTags.tags)
};
2019-07-17 14:34:39 +00:00
TextUtilities::Trim(caption);
2019-09-16 11:14:06 +00:00
auto sentEntities = EntitiesToMTP(
2019-07-17 14:34:39 +00:00
caption.entities,
2019-09-16 11:14:06 +00:00
ConvertOption::SkipLocal);
2019-07-17 14:34:39 +00:00
if (!sentEntities.v.isEmpty()) {
sendFlags |= MTPmessages_SendMedia::Flag::f_entities;
}
const auto replyTo = message.action.replyTo;
2019-07-17 14:34:39 +00:00
const auto captionText = caption.text;
2019-08-12 16:33:36 +00:00
if (message.action.options.scheduled) {
flags |= MTPDmessage::Flag::f_from_scheduled;
sendFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
} else {
clientFlags |= MTPDmessage_ClientFlag::f_local_history_entry;
}
2019-07-17 14:34:39 +00:00
session->data().registerMessageRandomId(randomId, newId);
history->addNewLocalMessage(
newId.msg,
flags,
clientFlags,
2019-07-17 14:34:39 +00:00
0,
replyTo,
2019-08-12 16:33:36 +00:00
HistoryItem::NewMessageDate(message.action.options.scheduled),
2019-07-17 14:34:39 +00:00
messageFromId,
messagePostAuthor,
media,
caption,
MTPReplyMarkup());
auto failHandler = std::make_shared<Fn<void(const RPCError&, QByteArray)>>();
auto performRequest = [=] {
auto &histories = history->owner().histories();
const auto requestType = Data::Histories::RequestType::Send;
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
const auto usedFileReference = media->fileReference();
history->sendRequestId = api->request(MTPmessages_SendMedia(
MTP_flags(sendFlags),
peer->input,
MTP_int(replyTo),
inputMedia(),
MTP_string(captionText),
MTP_long(randomId),
MTPReplyMarkup(),
sentEntities,
MTP_int(message.action.options.scheduled)
)).done([=](const MTPUpdates &result) {
api->applyUpdates(result, randomId);
finish();
}).fail([=](const RPCError &error) {
(*failHandler)(error, usedFileReference);
finish();
}).afterRequest(history->sendRequestId
).send();
return history->sendRequestId;
});
2019-07-17 14:34:39 +00:00
};
*failHandler = [=](const RPCError &error, QByteArray usedFileReference) {
if (error.code() == 400
&& error.type().startsWith(qstr("FILE_REFERENCE_"))) {
api->refreshFileReference(origin, [=](const auto &result) {
if (media->fileReference() != usedFileReference) {
performRequest();
} else {
api->sendMessageFail(error, peer, randomId, newId);
2019-07-17 14:34:39 +00:00
}
});
} else {
api->sendMessageFail(error, peer, randomId, newId);
2019-07-17 14:34:39 +00:00
}
};
performRequest();
if (const auto main = App::main()) {
main->finishForwarding(message.action);
2019-07-17 14:34:39 +00:00
}
}
} // namespace
void SendExistingDocument(
Api::MessageToSend &&message,
not_null<DocumentData*> document) {
const auto inputMedia = [=] {
return MTP_inputMediaDocument(
MTP_flags(0),
document->mtpInput(),
MTPint());
};
2019-07-17 14:34:39 +00:00
SendExistingMedia(
std::move(message),
2019-07-17 14:34:39 +00:00
document,
inputMedia,
document->stickerOrGifOrigin());
2019-07-17 14:34:39 +00:00
if (document->sticker()) {
if (const auto main = App::main()) {
main->incrementSticker(document);
2020-02-21 07:58:50 +00:00
document->owner().notifyRecentStickersUpdated();
2019-07-17 14:34:39 +00:00
}
}
}
void SendExistingPhoto(
Api::MessageToSend &&message,
not_null<PhotoData*> photo) {
const auto inputMedia = [=] {
return MTP_inputMediaPhoto(
MTP_flags(0),
photo->mtpInput(),
MTPint());
};
2019-07-17 14:34:39 +00:00
SendExistingMedia(
std::move(message),
2019-07-17 14:34:39 +00:00
photo,
inputMedia,
Data::FileOrigin());
2019-07-17 14:34:39 +00:00
}
2020-03-06 12:12:03 +00:00
bool SendDice(Api::MessageToSend &message) {
static const auto kDiceString = QString::fromUtf8("\xF0\x9F\x8E\xB2");
static const auto kDartString = QString::fromUtf8("\xF0\x9F\x8E\xAF");
const auto full = message.textWithTags.text.midRef(0).trimmed();
if (full != kDiceString && full != kDartString) {
2020-03-06 12:12:03 +00:00
return false;
}
const auto emoji = full.toString();
2020-03-06 12:12:03 +00:00
const auto history = message.action.history;
const auto peer = history->peer;
const auto session = &history->session();
const auto api = &session->api();
message.textWithTags = TextWithTags();
message.action.clearDraft = false;
message.action.generateLocal = true;
api->sendAction(message.action);
const auto newId = FullMsgId(
peerToChannel(peer->id),
session->data().nextLocalMessageId());
const auto randomId = rand_value<uint64>();
auto &histories = history->owner().histories();
auto flags = NewMessageFlags(peer) | MTPDmessage::Flag::f_media;
auto clientFlags = NewMessageClientFlags();
auto sendFlags = MTPmessages_SendMedia::Flags(0);
if (message.action.replyTo) {
flags |= MTPDmessage::Flag::f_reply_to_msg_id;
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id;
}
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
const auto silentPost = message.action.options.silent
|| (channelPost && session->data().notifySilentPosts(peer));
if (channelPost) {
flags |= MTPDmessage::Flag::f_views;
flags |= MTPDmessage::Flag::f_post;
}
if (!channelPost) {
flags |= MTPDmessage::Flag::f_from_id;
} else if (peer->asChannel()->addsSignature()) {
flags |= MTPDmessage::Flag::f_post_author;
}
if (silentPost) {
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
}
auto messageFromId = channelPost ? 0 : session->userId();
auto messagePostAuthor = channelPost ? session->user()->name : QString();
const auto replyTo = message.action.replyTo;
if (message.action.options.scheduled) {
flags |= MTPDmessage::Flag::f_from_scheduled;
sendFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
} else {
clientFlags |= MTPDmessage_ClientFlag::f_local_history_entry;
}
session->data().registerMessageRandomId(randomId, newId);
history->addNewMessage(
MTP_message(
MTP_flags(flags),
MTP_int(newId.msg),
MTP_int(messageFromId),
peerToMTP(history->peer->id),
MTPMessageFwdHeader(),
MTP_int(0),
MTP_int(replyTo),
MTP_int(HistoryItem::NewMessageDate(
message.action.options.scheduled)),
MTP_string(),
MTP_messageMediaDice(MTP_int(0), MTP_string(emoji)),
2020-03-06 12:12:03 +00:00
MTPReplyMarkup(),
MTP_vector<MTPMessageEntity>(),
MTP_int(1),
MTPint(),
MTP_string(messagePostAuthor),
MTPlong(),
//MTPMessageReactions(),
MTPVector<MTPRestrictionReason>()),
clientFlags,
NewMessageType::Unread);
const auto requestType = Data::Histories::RequestType::Send;
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
history->sendRequestId = api->request(MTPmessages_SendMedia(
MTP_flags(sendFlags),
peer->input,
MTP_int(replyTo),
MTP_inputMediaDice(MTP_string(emoji)),
2020-03-06 12:12:03 +00:00
MTP_string(),
MTP_long(randomId),
MTPReplyMarkup(),
MTP_vector<MTPMessageEntity>(),
MTP_int(message.action.options.scheduled)
)).done([=](const MTPUpdates &result) {
api->applyUpdates(result, randomId);
finish();
}).fail([=](const RPCError &error) {
api->sendMessageFail(error, peer, randomId, newId);
finish();
}).afterRequest(history->sendRequestId
).send();
return history->sendRequestId;
});
return true;
}
2019-07-17 14:34:39 +00:00
} // namespace Api