1 /*
2 This file is part of Telegram Desktop,
3 the official desktop application for the Telegram messaging service.
4
5 For license and copyright information please follow this link:
6 https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
7 */
8 #include "api/api_text_entities.h"
9
10 #include "main/main_session.h"
11 #include "data/data_session.h"
12 #include "data/data_user.h"
13
14 namespace Api {
15 namespace {
16
17 using namespace TextUtilities;
18
19 } // namespace
20
EntitiesFromMTP(Main::Session * session,const QVector<MTPMessageEntity> & entities)21 EntitiesInText EntitiesFromMTP(
22 Main::Session *session,
23 const QVector<MTPMessageEntity> &entities) {
24 auto result = EntitiesInText();
25 if (!entities.isEmpty()) {
26 result.reserve(entities.size());
27 for (const auto &entity : entities) {
28 switch (entity.type()) {
29 case mtpc_messageEntityUrl: { auto &d = entity.c_messageEntityUrl(); result.push_back({ EntityType::Url, d.voffset().v, d.vlength().v }); } break;
30 case mtpc_messageEntityTextUrl: { auto &d = entity.c_messageEntityTextUrl(); result.push_back({ EntityType::CustomUrl, d.voffset().v, d.vlength().v, Clean(qs(d.vurl())) }); } break;
31 case mtpc_messageEntityEmail: { auto &d = entity.c_messageEntityEmail(); result.push_back({ EntityType::Email, d.voffset().v, d.vlength().v }); } break;
32 case mtpc_messageEntityHashtag: { auto &d = entity.c_messageEntityHashtag(); result.push_back({ EntityType::Hashtag, d.voffset().v, d.vlength().v }); } break;
33 case mtpc_messageEntityCashtag: { auto &d = entity.c_messageEntityCashtag(); result.push_back({ EntityType::Cashtag, d.voffset().v, d.vlength().v }); } break;
34 case mtpc_messageEntityPhone: break; // Skipping phones.
35 case mtpc_messageEntityMention: { auto &d = entity.c_messageEntityMention(); result.push_back({ EntityType::Mention, d.voffset().v, d.vlength().v }); } break;
36 case mtpc_messageEntityMentionName: {
37 const auto &d = entity.c_messageEntityMentionName();
38 const auto userId = UserId(d.vuser_id());
39 const auto data = [&] {
40 if (session) {
41 if (const auto user = session->data().userLoaded(userId)) {
42 return MentionNameDataFromFields({
43 userId.bare,
44 user->accessHash()
45 });
46 }
47 }
48 return MentionNameDataFromFields(userId.bare);
49 }();
50 result.push_back({ EntityType::MentionName, d.voffset().v, d.vlength().v, data });
51 } break;
52 case mtpc_inputMessageEntityMentionName: {
53 const auto &d = entity.c_inputMessageEntityMentionName();
54 const auto data = [&] {
55 if (session && d.vuser_id().type() == mtpc_inputUserSelf) {
56 return MentionNameDataFromFields(session->userId().bare);
57 } else if (d.vuser_id().type() == mtpc_inputUser) {
58 auto &user = d.vuser_id().c_inputUser();
59 const auto userId = UserId(user.vuser_id());
60 return MentionNameDataFromFields({ userId.bare, user.vaccess_hash().v });
61 }
62 return QString();
63 }();
64 if (!data.isEmpty()) {
65 result.push_back({ EntityType::MentionName, d.voffset().v, d.vlength().v, data });
66 }
67 } break;
68 case mtpc_messageEntityBotCommand: { auto &d = entity.c_messageEntityBotCommand(); result.push_back({ EntityType::BotCommand, d.voffset().v, d.vlength().v }); } break;
69 case mtpc_messageEntityBold: { auto &d = entity.c_messageEntityBold(); result.push_back({ EntityType::Bold, d.voffset().v, d.vlength().v }); } break;
70 case mtpc_messageEntityItalic: { auto &d = entity.c_messageEntityItalic(); result.push_back({ EntityType::Italic, d.voffset().v, d.vlength().v }); } break;
71 case mtpc_messageEntityUnderline: { auto &d = entity.c_messageEntityUnderline(); result.push_back({ EntityType::Underline, d.voffset().v, d.vlength().v }); } break;
72 case mtpc_messageEntityStrike: { auto &d = entity.c_messageEntityStrike(); result.push_back({ EntityType::StrikeOut, d.voffset().v, d.vlength().v }); } break;
73 case mtpc_messageEntityCode: { auto &d = entity.c_messageEntityCode(); result.push_back({ EntityType::Code, d.voffset().v, d.vlength().v }); } break;
74 case mtpc_messageEntityPre: { auto &d = entity.c_messageEntityPre(); result.push_back({ EntityType::Pre, d.voffset().v, d.vlength().v, Clean(qs(d.vlanguage())) }); } break;
75 case mtpc_messageEntityBankCard: break; // Skipping cards.
76 // #TODO entities
77 }
78 }
79 }
80 return result;
81 }
82
EntitiesToMTP(not_null<Main::Session * > session,const EntitiesInText & entities,ConvertOption option)83 MTPVector<MTPMessageEntity> EntitiesToMTP(
84 not_null<Main::Session*> session,
85 const EntitiesInText &entities,
86 ConvertOption option) {
87 auto v = QVector<MTPMessageEntity>();
88 v.reserve(entities.size());
89 for (const auto &entity : entities) {
90 if (entity.length() <= 0) continue;
91 if (option == ConvertOption::SkipLocal
92 && entity.type() != EntityType::Bold
93 //&& entity.type() != EntityType::Semibold // Not in API.
94 && entity.type() != EntityType::Italic
95 && entity.type() != EntityType::Underline
96 && entity.type() != EntityType::StrikeOut
97 && entity.type() != EntityType::Code // #TODO entities
98 && entity.type() != EntityType::Pre
99 && entity.type() != EntityType::MentionName
100 && entity.type() != EntityType::CustomUrl) {
101 continue;
102 }
103
104 auto offset = MTP_int(entity.offset());
105 auto length = MTP_int(entity.length());
106 switch (entity.type()) {
107 case EntityType::Url: v.push_back(MTP_messageEntityUrl(offset, length)); break;
108 case EntityType::CustomUrl: v.push_back(MTP_messageEntityTextUrl(offset, length, MTP_string(entity.data()))); break;
109 case EntityType::Email: v.push_back(MTP_messageEntityEmail(offset, length)); break;
110 case EntityType::Hashtag: v.push_back(MTP_messageEntityHashtag(offset, length)); break;
111 case EntityType::Cashtag: v.push_back(MTP_messageEntityCashtag(offset, length)); break;
112 case EntityType::Mention: v.push_back(MTP_messageEntityMention(offset, length)); break;
113 case EntityType::MentionName: {
114 auto inputUser = [&](const QString &data) -> MTPInputUser {
115 auto fields = MentionNameDataToFields(data);
116 if (session && fields.userId == session->userId().bare) {
117 return MTP_inputUserSelf();
118 } else if (fields.userId) {
119 return MTP_inputUser(MTP_long(fields.userId), MTP_long(fields.accessHash));
120 }
121 return MTP_inputUserEmpty();
122 }(entity.data());
123 if (inputUser.type() != mtpc_inputUserEmpty) {
124 v.push_back(MTP_inputMessageEntityMentionName(offset, length, inputUser));
125 }
126 } break;
127 case EntityType::BotCommand: v.push_back(MTP_messageEntityBotCommand(offset, length)); break;
128 case EntityType::Bold: v.push_back(MTP_messageEntityBold(offset, length)); break;
129 case EntityType::Italic: v.push_back(MTP_messageEntityItalic(offset, length)); break;
130 case EntityType::Underline: v.push_back(MTP_messageEntityUnderline(offset, length)); break;
131 case EntityType::StrikeOut: v.push_back(MTP_messageEntityStrike(offset, length)); break;
132 case EntityType::Code: v.push_back(MTP_messageEntityCode(offset, length)); break; // #TODO entities
133 case EntityType::Pre: v.push_back(MTP_messageEntityPre(offset, length, MTP_string(entity.data()))); break;
134 }
135 }
136 return MTP_vector<MTPMessageEntity>(std::move(v));
137 }
138
139 } // namespace Api
140