File: api_text_entities.cpp

package info (click to toggle)
telegram-desktop 4.6.5%2Bds-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 53,300 kB
  • sloc: cpp: 605,857; python: 3,978; ansic: 1,636; sh: 965; makefile: 841; objc: 652; javascript: 187; xml: 165
file content (184 lines) | stat: -rw-r--r-- 8,398 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/*
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_text_entities.h"

#include "main/main_session.h"
#include "data/stickers/data_custom_emoji.h"
#include "data/stickers/data_stickers_set.h"
#include "data/data_session.h"
#include "data/data_document.h"
#include "data/data_user.h"

namespace Api {
namespace {

using namespace TextUtilities;

[[nodiscard]] QString CustomEmojiEntityData(
		const MTPDmessageEntityCustomEmoji &data) {
	return Data::SerializeCustomEmojiId(data.vdocument_id().v);
}

[[nodiscard]] std::optional<MTPMessageEntity> CustomEmojiEntity(
		MTPint offset,
		MTPint length,
		const QString &data) {
	const auto parsed = Data::ParseCustomEmojiData(data);
	if (!parsed) {
		return {};
	}
	return MTP_messageEntityCustomEmoji(
		offset,
		length,
		MTP_long(parsed));
}

[[nodiscard]] std::optional<MTPMessageEntity> MentionNameEntity(
		not_null<Main::Session*> session,
		MTPint offset,
		MTPint length,
		const QString &data) {
	const auto parsed = MentionNameDataToFields(data);
	if (!parsed.userId || parsed.selfId != session->userId().bare) {
		return {};
	}
	return MTP_inputMessageEntityMentionName(
		offset,
		length,
		(parsed.userId == parsed.selfId
			? MTP_inputUserSelf()
			: MTP_inputUser(
				MTP_long(parsed.userId),
				MTP_long(parsed.accessHash))));
}

} // namespace

EntitiesInText EntitiesFromMTP(
		Main::Session *session,
		const QVector<MTPMessageEntity> &entities) {
	auto result = EntitiesInText();
	if (!entities.isEmpty()) {
		result.reserve(entities.size());
		for (const auto &entity : entities) {
			switch (entity.type()) {
			case mtpc_messageEntityUrl: { auto &d = entity.c_messageEntityUrl(); result.push_back({ EntityType::Url, d.voffset().v, d.vlength().v }); } break;
			case mtpc_messageEntityTextUrl: { auto &d = entity.c_messageEntityTextUrl(); result.push_back({ EntityType::CustomUrl, d.voffset().v, d.vlength().v, qs(d.vurl()) }); } break;
			case mtpc_messageEntityEmail: { auto &d = entity.c_messageEntityEmail(); result.push_back({ EntityType::Email, d.voffset().v, d.vlength().v }); } break;
			case mtpc_messageEntityHashtag: { auto &d = entity.c_messageEntityHashtag(); result.push_back({ EntityType::Hashtag, d.voffset().v, d.vlength().v }); } break;
			case mtpc_messageEntityCashtag: { auto &d = entity.c_messageEntityCashtag(); result.push_back({ EntityType::Cashtag, d.voffset().v, d.vlength().v }); } break;
			case mtpc_messageEntityPhone: break; // Skipping phones.
			case mtpc_messageEntityMention: { auto &d = entity.c_messageEntityMention(); result.push_back({ EntityType::Mention, d.voffset().v, d.vlength().v }); } break;
			case mtpc_messageEntityMentionName: if (session) {
				const auto &d = entity.c_messageEntityMentionName();
				const auto userId = UserId(d.vuser_id());
				const auto user = session->data().userLoaded(userId);
				const auto data = MentionNameDataFromFields({
					.selfId = session->userId().bare,
					.userId = userId.bare,
					.accessHash = user ? user->accessHash() : 0,
				});
				result.push_back({ EntityType::MentionName, d.voffset().v, d.vlength().v, data });
			} break;
			case mtpc_inputMessageEntityMentionName: if (session) {
				const auto &d = entity.c_inputMessageEntityMentionName();
				const auto data = d.vuser_id().match([&](
						const MTPDinputUserSelf &) {
					return MentionNameDataFromFields({
						.selfId = session->userId().bare,
						.userId = session->userId().bare,
						.accessHash = session->user()->accessHash(),
					});
				}, [&](const MTPDinputUser &data) {
					return MentionNameDataFromFields({
						.selfId = session->userId().bare,
						.userId = UserId(data.vuser_id()).bare,
						.accessHash = data.vaccess_hash().v,
					});
				}, [&](const auto &) {
					return QString();
				});
				if (!data.isEmpty()) {
					result.push_back({ EntityType::MentionName, d.voffset().v, d.vlength().v, data });
				}
			} break;
			case mtpc_messageEntityBotCommand: { auto &d = entity.c_messageEntityBotCommand(); result.push_back({ EntityType::BotCommand, d.voffset().v, d.vlength().v }); } break;
			case mtpc_messageEntityBold: { auto &d = entity.c_messageEntityBold(); result.push_back({ EntityType::Bold, d.voffset().v, d.vlength().v }); } break;
			case mtpc_messageEntityItalic: { auto &d = entity.c_messageEntityItalic(); result.push_back({ EntityType::Italic, d.voffset().v, d.vlength().v }); } break;
			case mtpc_messageEntityUnderline: { auto &d = entity.c_messageEntityUnderline(); result.push_back({ EntityType::Underline, d.voffset().v, d.vlength().v }); } break;
			case mtpc_messageEntityStrike: { auto &d = entity.c_messageEntityStrike(); result.push_back({ EntityType::StrikeOut, d.voffset().v, d.vlength().v }); } break;
			case mtpc_messageEntityCode: { auto &d = entity.c_messageEntityCode(); result.push_back({ EntityType::Code, d.voffset().v, d.vlength().v }); } break;
			case mtpc_messageEntityPre: { auto &d = entity.c_messageEntityPre(); result.push_back({ EntityType::Pre, d.voffset().v, d.vlength().v, qs(d.vlanguage()) }); } break;
			case mtpc_messageEntityBankCard: break; // Skipping cards. // #TODO entities
			case mtpc_messageEntitySpoiler: { auto &d = entity.c_messageEntitySpoiler(); result.push_back({ EntityType::Spoiler, d.voffset().v, d.vlength().v }); } break;
			case mtpc_messageEntityCustomEmoji: {
				const auto &d = entity.c_messageEntityCustomEmoji();
				result.push_back({ EntityType::CustomEmoji, d.voffset().v, d.vlength().v, CustomEmojiEntityData(d) });
			} break;
			}
		}
	}
	return result;
}

MTPVector<MTPMessageEntity> EntitiesToMTP(
		not_null<Main::Session*> session,
		const EntitiesInText &entities,
		ConvertOption option) {
	auto v = QVector<MTPMessageEntity>();
	v.reserve(entities.size());
	for (const auto &entity : entities) {
		if (entity.length() <= 0) continue;
		if (option == ConvertOption::SkipLocal
			&& entity.type() != EntityType::Bold
			//&& entity.type() != EntityType::Semibold // Not in API.
			&& entity.type() != EntityType::Italic
			&& entity.type() != EntityType::Underline
			&& entity.type() != EntityType::StrikeOut
			&& entity.type() != EntityType::Code // #TODO entities
			&& entity.type() != EntityType::Pre
			&& entity.type() != EntityType::Spoiler
			&& entity.type() != EntityType::MentionName
			&& entity.type() != EntityType::CustomUrl
			&& entity.type() != EntityType::CustomEmoji) {
			continue;
		}

		auto offset = MTP_int(entity.offset());
		auto length = MTP_int(entity.length());
		switch (entity.type()) {
		case EntityType::Url: v.push_back(MTP_messageEntityUrl(offset, length)); break;
		case EntityType::CustomUrl: v.push_back(MTP_messageEntityTextUrl(offset, length, MTP_string(entity.data()))); break;
		case EntityType::Email: v.push_back(MTP_messageEntityEmail(offset, length)); break;
		case EntityType::Hashtag: v.push_back(MTP_messageEntityHashtag(offset, length)); break;
		case EntityType::Cashtag: v.push_back(MTP_messageEntityCashtag(offset, length)); break;
		case EntityType::Mention: v.push_back(MTP_messageEntityMention(offset, length)); break;
		case EntityType::MentionName: {
			if (const auto valid = MentionNameEntity(session, offset, length, entity.data())) {
				v.push_back(*valid);
			}
		} break;
		case EntityType::BotCommand: v.push_back(MTP_messageEntityBotCommand(offset, length)); break;
		case EntityType::Bold: v.push_back(MTP_messageEntityBold(offset, length)); break;
		case EntityType::Italic: v.push_back(MTP_messageEntityItalic(offset, length)); break;
		case EntityType::Underline: v.push_back(MTP_messageEntityUnderline(offset, length)); break;
		case EntityType::StrikeOut: v.push_back(MTP_messageEntityStrike(offset, length)); break;
		case EntityType::Code: v.push_back(MTP_messageEntityCode(offset, length)); break; // #TODO entities
		case EntityType::Pre: v.push_back(MTP_messageEntityPre(offset, length, MTP_string(entity.data()))); break;
		case EntityType::Spoiler: v.push_back(MTP_messageEntitySpoiler(offset, length)); break;
		case EntityType::CustomEmoji: {
			if (const auto valid = CustomEmojiEntity(offset, length, entity.data())) {
				v.push_back(*valid);
			}
		} break;
		}
	}
	return MTP_vector<MTPMessageEntity>(std::move(v));
}

} // namespace Api