Merge remote-tracking branch 'tdlib/master'
This commit is contained in:
commit
07ead2cbcb
@ -136,12 +136,9 @@ if (IOS_DEPLOYMENT_TARGET)
|
||||
endif()
|
||||
|
||||
set (CMAKE_SHARED_LINKER_FLAGS_INIT "-fapplication-extension")
|
||||
if (NOT SIMULATOR_FLAG)
|
||||
set (BITCODE "-fembed-bitcode")
|
||||
endif()
|
||||
set (CMAKE_C_FLAGS_INIT "${XCODE_IOS_PLATFORM_VERSION_FLAGS} ${BITCODE}")
|
||||
set (CMAKE_C_FLAGS_INIT "${XCODE_IOS_PLATFORM_VERSION_FLAGS}")
|
||||
# Hidden visibilty is required for cxx on iOS
|
||||
set (CMAKE_CXX_FLAGS_INIT "${XCODE_IOS_PLATFORM_VERSION_FLAGS} ${BITCODE} -fvisibility-inlines-hidden")
|
||||
set (CMAKE_CXX_FLAGS_INIT "${XCODE_IOS_PLATFORM_VERSION_FLAGS} -fvisibility-inlines-hidden")
|
||||
|
||||
set (CMAKE_C_LINK_FLAGS "${XCODE_IOS_PLATFORM_VERSION_FLAGS} -fapplication-extension -Wl,-search_paths_first ${CMAKE_C_LINK_FLAGS}")
|
||||
set (CMAKE_CXX_LINK_FLAGS "${XCODE_IOS_PLATFORM_VERSION_FLAGS} -fapplication-extension -Wl,-search_paths_first ${CMAKE_CXX_LINK_FLAGS}")
|
||||
|
@ -6,7 +6,7 @@ if (POLICY CMP0065)
|
||||
cmake_policy(SET CMP0065 NEW)
|
||||
endif()
|
||||
|
||||
project(TDLib VERSION 1.8.6 LANGUAGES CXX C)
|
||||
project(TDLib VERSION 1.8.7 LANGUAGES CXX C)
|
||||
|
||||
if (NOT DEFINED CMAKE_MODULE_PATH)
|
||||
set(CMAKE_MODULE_PATH "")
|
||||
@ -366,6 +366,7 @@ set(TDLIB_SOURCE
|
||||
td/telegram/InlineQueriesManager.cpp
|
||||
td/telegram/InputDialogId.cpp
|
||||
td/telegram/InputGroupCallId.cpp
|
||||
td/telegram/InputInvoice.cpp
|
||||
td/telegram/InputMessageText.cpp
|
||||
td/telegram/JsonValue.cpp
|
||||
td/telegram/LanguagePackManager.cpp
|
||||
@ -376,6 +377,7 @@ set(TDLIB_SOURCE
|
||||
td/telegram/MessageContent.cpp
|
||||
td/telegram/MessageContentType.cpp
|
||||
td/telegram/MessageEntity.cpp
|
||||
td/telegram/MessageExtendedMedia.cpp
|
||||
td/telegram/MessageId.cpp
|
||||
td/telegram/MessageReaction.cpp
|
||||
td/telegram/MessageReplyInfo.cpp
|
||||
@ -410,6 +412,7 @@ set(TDLIB_SOURCE
|
||||
td/telegram/NotificationSound.cpp
|
||||
td/telegram/NotificationType.cpp
|
||||
td/telegram/OptionManager.cpp
|
||||
td/telegram/OrderInfo.cpp
|
||||
td/telegram/Payments.cpp
|
||||
td/telegram/PasswordManager.cpp
|
||||
td/telegram/PhoneNumberManager.cpp
|
||||
@ -519,6 +522,7 @@ set(TDLIB_SOURCE
|
||||
td/telegram/Contact.h
|
||||
td/telegram/ContactsManager.h
|
||||
td/telegram/CountryInfoManager.h
|
||||
td/telegram/CustomEmojiId.h
|
||||
td/telegram/DelayDispatcher.h
|
||||
td/telegram/Dependencies.h
|
||||
td/telegram/DeviceTokenManager.h
|
||||
@ -590,8 +594,10 @@ set(TDLIB_SOURCE
|
||||
td/telegram/InlineQueriesManager.h
|
||||
td/telegram/InputDialogId.h
|
||||
td/telegram/InputGroupCallId.h
|
||||
td/telegram/InputInvoice.h
|
||||
td/telegram/InputMessageText.h
|
||||
td/telegram/JsonValue.h
|
||||
td/telegram/LabeledPricePart.h
|
||||
td/telegram/LanguagePackManager.h
|
||||
td/telegram/LinkManager.h
|
||||
td/telegram/Location.h
|
||||
@ -603,6 +609,7 @@ set(TDLIB_SOURCE
|
||||
td/telegram/MessageContentType.h
|
||||
td/telegram/MessageCopyOptions.h
|
||||
td/telegram/MessageEntity.h
|
||||
td/telegram/MessageExtendedMedia.h
|
||||
td/telegram/MessageId.h
|
||||
td/telegram/MessageLinkInfo.h
|
||||
td/telegram/MessageReaction.h
|
||||
@ -651,6 +658,7 @@ set(TDLIB_SOURCE
|
||||
td/telegram/NotificationSoundType.h
|
||||
td/telegram/NotificationType.h
|
||||
td/telegram/OptionManager.h
|
||||
td/telegram/OrderInfo.h
|
||||
td/telegram/PasswordManager.h
|
||||
td/telegram/Payments.h
|
||||
td/telegram/PhoneNumberManager.h
|
||||
@ -733,13 +741,15 @@ set(TDLIB_SOURCE
|
||||
td/telegram/files/FileManager.hpp
|
||||
td/telegram/files/FileSourceId.hpp
|
||||
td/telegram/Game.hpp
|
||||
td/telegram/InputInvoice.hpp
|
||||
td/telegram/InputMessageText.hpp
|
||||
td/telegram/MessageEntity.hpp
|
||||
td/telegram/MessageExtendedMedia.hpp
|
||||
td/telegram/MessageReaction.hpp
|
||||
td/telegram/MessageReplyInfo.hpp
|
||||
td/telegram/MinChannel.hpp
|
||||
td/telegram/NotificationSettings.hpp
|
||||
td/telegram/Payments.hpp
|
||||
td/telegram/OrderInfo.hpp
|
||||
td/telegram/Photo.hpp
|
||||
td/telegram/PhotoSize.hpp
|
||||
td/telegram/PhotoSizeSource.hpp
|
||||
|
@ -130,7 +130,7 @@ target_link_libraries(YourTarget PRIVATE Td::TdStatic)
|
||||
|
||||
Or you could install `TDLib` and then reference it in your CMakeLists.txt like this:
|
||||
```
|
||||
find_package(Td 1.8.6 REQUIRED)
|
||||
find_package(Td 1.8.7 REQUIRED)
|
||||
target_link_libraries(YourTarget PRIVATE Td::TdStatic)
|
||||
```
|
||||
See [example/cpp/CMakeLists.txt](https://github.com/tdlight-team/tdlight/blob/master/example/cpp/CMakeLists.txt).
|
||||
|
@ -66,7 +66,7 @@ function split_file($file, $chunks, $undo) {
|
||||
}
|
||||
|
||||
if (!file_exists($cpp_name)) {
|
||||
echo "ERROR: skip unexisting file $cpp_name".PHP_EOL;
|
||||
echo "ERROR: skip nonexistent file $cpp_name".PHP_EOL;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -291,7 +291,7 @@ function split_file($file, $chunks, $undo) {
|
||||
'group_call_manager[_(-][^.]|GroupCallManager' => 'GroupCallManager',
|
||||
'HashtagHints' => 'HashtagHints',
|
||||
'inline_queries_manager[_(-][^.]|InlineQueriesManager' => 'InlineQueriesManager',
|
||||
'language_pack_manager[_(-][^.]|LanguagePackManager' => 'LanguagePackManager',
|
||||
'language_pack_manager[_(-]|LanguagePackManager' => 'LanguagePackManager',
|
||||
'link_manager[_(-][^.]|LinkManager' => 'LinkManager',
|
||||
'LogeventIdWithGeneration|add_log_event|delete_log_event|get_erase_log_event_promise|parse_time|store_time' => 'logevent/LogEventHelper',
|
||||
'MessageCopyOptions' => 'MessageCopyOptions',
|
||||
@ -303,7 +303,7 @@ function split_file($file, $chunks, $undo) {
|
||||
'poll_manager[_(-][^.]|PollManager' => "PollManager",
|
||||
'PublicDialogType|get_public_dialog_type' => 'PublicDialogType',
|
||||
'SecretChatActor' => 'SecretChatActor',
|
||||
'secret_chats_manager[_(-][^.]|SecretChatsManager' => 'SecretChatsManager',
|
||||
'secret_chats_manager[_(-]|SecretChatsManager' => 'SecretChatsManager',
|
||||
'sponsored_message_manager[_(-][^.]|SponsoredMessageManager' => 'SponsoredMessageManager',
|
||||
'stickers_manager[_(-][^.]|StickersManager' => 'StickersManager',
|
||||
'[>](td_db[(][)]|get_td_db_impl[(])|TdDb[^A-Za-z]' => 'TdDb',
|
||||
|
@ -134,7 +134,7 @@ See [example/cpp](https://github.com/tdlight-team/tdlight/tree/master/example/cp
|
||||
See also the source code of [Fernschreiber](https://github.com/Wunderfitz/harbour-fernschreiber) and [Depecher](https://github.com/blacksailer/depecher) – Telegram apps for Sailfish OS,
|
||||
[TELEports](https://gitlab.com/ubports/development/apps/teleports) – a Qt-client for Ubuntu Touch, [tdlib-purple](https://github.com/ars3niy/tdlib-purple) - Telegram plugin for Pidgin,
|
||||
or [MeeGram](https://github.com/qtinsider/meegram2) - a Telegram client for Nokia N9,
|
||||
[TDLib Native Sciter Extension](https://github.com/RadRussianRus/TDLibNSE) - a Sciter native extension for TDLib's JSON interface, all of which are based on TDLib.
|
||||
[TDLib Native Sciter Extension](https://github.com/EricKotato/TDLibNSE) - a Sciter native extension for TDLib's JSON interface, all of which are based on TDLib.
|
||||
|
||||
<a name="swift"></a>
|
||||
## Using TDLib in Swift projects
|
||||
@ -182,7 +182,7 @@ See also [f-Telegram](https://github.com/evgfilim1/ftg) - Flutter Telegram clien
|
||||
|
||||
TDLib can be used from the Rust programming language through the [JSON](https://github.com/tdlib/td#using-json) interface.
|
||||
|
||||
See [rust-tdlib](https://github.com/aCLr/rust-tdlib), [tdlib](https://github.com/melix99/tdlib-rs), or [tdlib-rs](https://github.com/agnipau/tdlib-rs), which provide convenient TDLib clients with automatically generated and fully-documented classes for all TDLib API methods and objects.
|
||||
See [rust-tdlib](https://github.com/aCLr/rust-tdlib), or [tdlib](https://github.com/melix99/tdlib-rs), which provide convenient TDLib clients with automatically generated and fully-documented classes for all TDLib API methods and objects.
|
||||
|
||||
See [rtdlib](https://github.com/fewensa/rtdlib), [tdlib-rs](https://github.com/d653/tdlib-rs), [tdlib-futures](https://github.com/yuri91/tdlib-futures),
|
||||
[tdlib-sys](https://github.com/nuxeh/tdlib-sys), [tdjson-rs](https://github.com/mersinvald/tdjson-rs), [rust-tdlib](https://github.com/vhaoran/rust-tdlib), or [tdlib-json-sys](https://github.com/aykxt/tdlib-json-sys) for examples of TDLib Rust bindings.
|
||||
|
26
example/android/Dockerfile
Normal file
26
example/android/Dockerfile
Normal file
@ -0,0 +1,26 @@
|
||||
FROM --platform=linux/amd64 ubuntu:22.04 as build
|
||||
|
||||
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -yq default-jdk g++ git gperf make perl php-cli unzip wget && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /home
|
||||
|
||||
ARG ANDROID_NDK_VERSION=23.2.8568313
|
||||
COPY ./check-environment.sh ./fetch-sdk.sh ./
|
||||
RUN ./fetch-sdk.sh SDK "$ANDROID_NDK_VERSION"
|
||||
|
||||
ARG OPENSSL_VERSION=OpenSSL_1_1_1q
|
||||
COPY ./build-openssl.sh ./
|
||||
RUN ./build-openssl.sh SDK "$ANDROID_NDK_VERSION" openssl "$OPENSSL_VERSION"
|
||||
|
||||
ADD "https://api.github.com/repos/tdlib/td/git/refs/heads/master" version.json
|
||||
ARG COMMIT_HASH=master
|
||||
RUN git clone https://github.com/tdlib/td.git && cd td && git checkout "$COMMIT_HASH"
|
||||
RUN cd td && git merge-base --is-ancestor bcd89728c3b93b67448b93b4863dc5bd4e122a4c "$COMMIT_HASH"
|
||||
|
||||
ARG ANDROID_STL=c++_static
|
||||
RUN td/example/android/build-tdlib.sh SDK "$ANDROID_NDK_VERSION" openssl "$ANDROID_STL" && rm -rf td/example/android/build-*
|
||||
|
||||
|
||||
FROM scratch
|
||||
|
||||
COPY --from=build /home/td/example/android/tdlib/tdlib* /
|
@ -17,6 +17,8 @@ If you already have prebuilt OpenSSL, you can skip the third step and specify pa
|
||||
|
||||
If you want to update TDLib to a newer version, you need to run only the script `./build-tdlib.sh`.
|
||||
|
||||
You can specify different OpenSSL version as the fourth parameter to the script `./build-openssl.sh`. By default OpenSSL 1.1.1 is used because of much smaller binary footprint than newer OpenSSL versions.
|
||||
You can specify different OpenSSL version as the fourth parameter to the script `./build-openssl.sh`. By default OpenSSL 1.1.1 is used because of much smaller binary footprint and better performance than newer OpenSSL versions.
|
||||
|
||||
You can build TDLib against shared standard C++ library by specifying "c++_shared" as the fourth parameter to the script `./build-tdlib.sh`. This can reduce total application size if you have a lot of other C++ code and want it to use the same shared library.
|
||||
|
||||
Alternatively, you can use Docker to build TDLib for Android. Use `docker build --output tdlib .` to build the latest TDLib commit from Github, or `docker build --build-arg COMMIT_HASH=<commit-hash> --output tdlib .` to build specific commit. The output archives will be placed in the tdlib directory as specified.
|
||||
|
@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.4 FATAL_ERROR)
|
||||
|
||||
project(TdExample VERSION 1.0 LANGUAGES CXX)
|
||||
|
||||
find_package(Td 1.8.6 REQUIRED)
|
||||
find_package(Td 1.8.7 REQUIRED)
|
||||
|
||||
add_executable(tdjson_example tdjson_example.cpp)
|
||||
target_link_libraries(tdjson_example PRIVATE Td::TdJson)
|
||||
|
@ -1,10 +1,8 @@
|
||||
diff --git a/Makefile b/Makefile
|
||||
index 695be54..4efe5e5 100644
|
||||
index 695be54..eda7b0d 100644
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -5,10 +5,13 @@
|
||||
# - iOS - build everything for iOS
|
||||
# - tvOS - build everything for tvOS
|
||||
@@ -7,8 +7,11 @@
|
||||
# - watchOS - build everything for watchOS
|
||||
# - OpenSSL-macOS - build OpenSSL for macOS
|
||||
# - OpenSSL-iOS - build OpenSSL for iOS
|
||||
@ -16,7 +14,14 @@ index 695be54..4efe5e5 100644
|
||||
# - BZip2-macOS - build BZip2 for macOS
|
||||
# - BZip2-iOS - build BZip2 for iOS
|
||||
# - BZip2-tvOS - build BZip2 for tvOS
|
||||
@@ -36,31 +39,45 @@ OPENSSL_VERSION=$(OPENSSL_VERSION_NUMBER)$(OPENSSL_REVISION)
|
||||
@@ -30,37 +33,51 @@ PYTHON_VERSION=2.7.14
|
||||
PYTHON_VER=$(basename $(PYTHON_VERSION))
|
||||
|
||||
OPENSSL_VERSION_NUMBER=1.0.2
|
||||
-OPENSSL_REVISION=n
|
||||
+OPENSSL_REVISION=u
|
||||
OPENSSL_VERSION=$(OPENSSL_VERSION_NUMBER)$(OPENSSL_REVISION)
|
||||
|
||||
BZIP2_VERSION=1.0.6
|
||||
|
||||
# Supported OS
|
||||
@ -33,19 +38,23 @@ index 695be54..4efe5e5 100644
|
||||
-TARGETS-iOS=iphonesimulator.x86_64 iphonesimulator.i386 iphoneos.armv7 iphoneos.armv7s iphoneos.arm64
|
||||
+TARGETS-iOS=iphoneos.armv7 iphoneos.armv7s iphoneos.arm64
|
||||
CFLAGS-iOS=-mios-version-min=7.0
|
||||
CFLAGS-iphoneos.armv7=-fembed-bitcode
|
||||
CFLAGS-iphoneos.armv7s=-fembed-bitcode
|
||||
CFLAGS-iphoneos.arm64=-fembed-bitcode
|
||||
|
||||
-CFLAGS-iphoneos.armv7=-fembed-bitcode
|
||||
-CFLAGS-iphoneos.armv7s=-fembed-bitcode
|
||||
-CFLAGS-iphoneos.arm64=-fembed-bitcode
|
||||
+CFLAGS-iphoneos.armv7=
|
||||
+CFLAGS-iphoneos.armv7s=
|
||||
+CFLAGS-iphoneos.arm64=
|
||||
+
|
||||
+# iOS-simulator targets
|
||||
+TARGETS-iOS-simulator=iphonesimulator.x86_64 iphonesimulator.i386 iphonesimulator.arm64
|
||||
+CFLAGS-iOS-simulator=-mios-simulator-version-min=7.0
|
||||
+
|
||||
|
||||
# tvOS targets
|
||||
-TARGETS-tvOS=appletvsimulator.x86_64 appletvos.arm64
|
||||
+TARGETS-tvOS=appletvos.arm64
|
||||
CFLAGS-tvOS=-mtvos-version-min=9.0
|
||||
CFLAGS-appletvos.arm64=-fembed-bitcode
|
||||
-CFLAGS-appletvos.arm64=-fembed-bitcode
|
||||
+CFLAGS-appletvos.arm64=
|
||||
PYTHON_CONFIGURE-tvOS=ac_cv_func_sigaltstack=no
|
||||
|
||||
+# tvOS-simulator targets
|
||||
@ -56,8 +65,9 @@ index 695be54..4efe5e5 100644
|
||||
-TARGETS-watchOS=watchsimulator.i386 watchos.armv7k
|
||||
+TARGETS-watchOS=watchos.armv7k watchos.arm64_32
|
||||
CFLAGS-watchOS=-mwatchos-version-min=4.0
|
||||
CFLAGS-watchos.armv7k=-fembed-bitcode
|
||||
+CFLAGS-watchos.arm64_32=-fembed-bitcode
|
||||
-CFLAGS-watchos.armv7k=-fembed-bitcode
|
||||
+CFLAGS-watchos.armv7k=
|
||||
+CFLAGS-watchos.arm64_32=
|
||||
PYTHON_CONFIGURE-watchOS=ac_cv_func_sigaltstack=no
|
||||
|
||||
+# watchOS-simulator targets
|
||||
@ -80,3 +90,15 @@ index 695be54..4efe5e5 100644
|
||||
else
|
||||
cd $$(OPENSSL_DIR-$1) && \
|
||||
CC="$$(CC-$1)" \
|
||||
@@ -216,7 +235,10 @@ $$(OPENSSL_DIR-$1)/libssl.a $$(OPENSSL_DIR-$1)/libcrypto.a: $$(OPENSSL_DIR-$1)/M
|
||||
CC="$$(CC-$1)" \
|
||||
CROSS_TOP="$$(dir $$(SDK_ROOT-$1)).." \
|
||||
CROSS_SDK="$$(notdir $$(SDK_ROOT-$1))" \
|
||||
- make all && make install
|
||||
+ make build_libs && \
|
||||
+ mkdir -p "$(PROJECT_DIR)/build/$2/openssl/lib" && \
|
||||
+ cp libcrypto.a libssl.a "$(PROJECT_DIR)/build/$2/openssl/lib"
|
||||
+ -cd $$(OPENSSL_DIR-$1) && make install_sw 2> /dev/null
|
||||
|
||||
# Unpack BZip2
|
||||
$$(BZIP2_DIR-$1)/Makefile: downloads/bzip2-$(BZIP2_VERSION).tgz
|
||||
|
@ -26,12 +26,12 @@ do
|
||||
echo $platform
|
||||
cd Python-Apple-support
|
||||
#NB: -j will fail
|
||||
make OpenSSL-$platform
|
||||
make OpenSSL-$platform || exit 1
|
||||
cd ..
|
||||
rm -rf third_party/openssl/$platform
|
||||
mkdir -p third_party/openssl/$platform/lib
|
||||
cp ./Python-Apple-support/build/$platform/libcrypto.a third_party/openssl/$platform/lib/
|
||||
cp ./Python-Apple-support/build/$platform/libssl.a third_party/openssl/$platform/lib/
|
||||
cp -r ./Python-Apple-support/build/$platform/Support/OpenSSL/Headers/ third_party/openssl/$platform/include
|
||||
rm -rf third_party/openssl/$platform || exit 1
|
||||
mkdir -p third_party/openssl/$platform/lib || exit 1
|
||||
cp ./Python-Apple-support/build/$platform/libcrypto.a third_party/openssl/$platform/lib/ || exit 1
|
||||
cp ./Python-Apple-support/build/$platform/libssl.a third_party/openssl/$platform/lib/ || exit 1
|
||||
cp -r ./Python-Apple-support/build/$platform/openssl/include/ third_party/openssl/$platform/include || exit 1
|
||||
done
|
||||
done
|
||||
|
@ -1,6 +1,6 @@
|
||||
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011">
|
||||
<Metadata>
|
||||
<Identity Id="Telegram.Td.UWP" Version="1.8.6" Language="en-US" Publisher="Telegram LLC" />
|
||||
<Identity Id="Telegram.Td.UWP" Version="1.8.7" Language="en-US" Publisher="Telegram LLC" />
|
||||
<DisplayName>TDLib for Universal Windows Platform</DisplayName>
|
||||
<Description>TDLib is a library for building Telegram clients</Description>
|
||||
<MoreInfo>https://core.telegram.org/tdlib</MoreInfo>
|
||||
|
15
sqlite/sqlite/sqlite3.c
vendored
15
sqlite/sqlite/sqlite3.c
vendored
@ -60743,17 +60743,24 @@ act_like_temp_file:
|
||||
pPager->memDb = (u8)memDb;
|
||||
pPager->readOnly = (u8)readOnly;
|
||||
assert( useJournal || pPager->tempFile );
|
||||
pPager->noSync = pPager->tempFile;
|
||||
int level = SQLITE_DEFAULT_SYNCHRONOUS + 1;
|
||||
pPager->noSync = pPager->tempFile || level==PAGER_SYNCHRONOUS_OFF;
|
||||
if( pPager->noSync ){
|
||||
assert( pPager->fullSync==0 );
|
||||
assert( pPager->extraSync==0 );
|
||||
assert( pPager->syncFlags==0 );
|
||||
assert( pPager->walSyncFlags==0 );
|
||||
}else{
|
||||
pPager->fullSync = 1;
|
||||
pPager->extraSync = 0;
|
||||
pPager->fullSync = level>=PAGER_SYNCHRONOUS_FULL ?1:0;
|
||||
pPager->extraSync = level==PAGER_SYNCHRONOUS_EXTRA ?1:0;
|
||||
pPager->syncFlags = SQLITE_SYNC_NORMAL;
|
||||
pPager->walSyncFlags = SQLITE_SYNC_NORMAL | (SQLITE_SYNC_NORMAL<<2);
|
||||
pPager->walSyncFlags = (pPager->syncFlags<<2);
|
||||
if( pPager->fullSync ){
|
||||
pPager->walSyncFlags |= pPager->syncFlags;
|
||||
}
|
||||
#if SQLITE_DEFAULT_CKPTFULLFSYNC
|
||||
pPager->walSyncFlags |= (SQLITE_SYNC_FULL<<2);
|
||||
#endif
|
||||
}
|
||||
/* pPager->pFirst = 0; */
|
||||
/* pPager->pFirstSynced = 0; */
|
||||
|
@ -212,14 +212,14 @@ abstract class TlDocumentationGenerator
|
||||
$known_fields[$field_name] = $field_type;
|
||||
continue;
|
||||
}
|
||||
$this->printError("Have no info about field `$field_name`");
|
||||
$this->printError("Have no documentation for field `$field_name`");
|
||||
}
|
||||
|
||||
foreach ($info as $name => $value) {
|
||||
if (!$value) {
|
||||
$this->printError("info[$name] for $class_name is empty");
|
||||
$this->printError("Documentation for field $name of $class_name is empty");
|
||||
} elseif (($value[0] < 'A' || $value[0] > 'Z') && ($value[0] < '0' || $value[0] > '9')) {
|
||||
$this->printError("info[$name] for $class_name doesn't begins with capital letter");
|
||||
$this->printError("Documentation for field $name of $class_name doesn't begin with a capital letter");
|
||||
}
|
||||
}
|
||||
|
||||
@ -235,7 +235,7 @@ abstract class TlDocumentationGenerator
|
||||
}
|
||||
|
||||
foreach (array_diff_key($info, $known_fields) as $field_name => $field_info) {
|
||||
$this->printError("Have info about unexisted field `$field_name`");
|
||||
$this->printError("Have info about nonexistent field `$field_name`");
|
||||
}
|
||||
|
||||
if (array_keys($info) !== array_keys($known_fields)) {
|
||||
|
@ -15,12 +15,12 @@ vector {t:Type} # [ t ] = Vector t;
|
||||
decryptedMessage8#1f814f1f random_id:long random_bytes:bytes message:string media:DecryptedMessageMedia = DecryptedMessage;
|
||||
decryptedMessageService8#aa48327d random_id:long random_bytes:bytes action:DecryptedMessageAction = DecryptedMessage;
|
||||
decryptedMessageMediaEmpty#89f5c4a = DecryptedMessageMedia;
|
||||
decryptedMessageMediaPhoto23#32798a8c thumb:bytes thumb_w:int thumb_h:int w:int h:int size:int key:bytes iv:bytes = DecryptedMessageMedia;
|
||||
decryptedMessageMediaPhoto8#32798a8c thumb:bytes thumb_w:int thumb_h:int w:int h:int size:int key:bytes iv:bytes = DecryptedMessageMedia;
|
||||
decryptedMessageMediaVideo8#4cee6ef3 thumb:bytes thumb_w:int thumb_h:int duration:int w:int h:int size:int key:bytes iv:bytes = DecryptedMessageMedia;
|
||||
decryptedMessageMediaGeoPoint#35480a59 lat:double long:double = DecryptedMessageMedia;
|
||||
decryptedMessageMediaContact#588a0a97 phone_number:string first_name:string last_name:string user_id:int = DecryptedMessageMedia;
|
||||
decryptedMessageActionSetMessageTTL#a1733aec ttl_seconds:int = DecryptedMessageAction;
|
||||
decryptedMessageMediaDocument23#b095434b thumb:bytes thumb_w:int thumb_h:int file_name:string mime_type:string size:int key:bytes iv:bytes = DecryptedMessageMedia;
|
||||
decryptedMessageMediaDocument8#b095434b thumb:bytes thumb_w:int thumb_h:int file_name:string mime_type:string size:int key:bytes iv:bytes = DecryptedMessageMedia;
|
||||
decryptedMessageMediaAudio8#6080758f duration:int size:int key:bytes iv:bytes = DecryptedMessageMedia;
|
||||
decryptedMessageActionReadMessages#c4f40be random_ids:Vector<long> = DecryptedMessageAction;
|
||||
decryptedMessageActionDeleteMessages#65614304 random_ids:Vector<long> = DecryptedMessageAction;
|
||||
@ -59,7 +59,7 @@ decryptedMessageActionNoop#a82fdd63 = DecryptedMessageAction;
|
||||
documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute;
|
||||
documentAttributeAnimated#11b58939 = DocumentAttribute;
|
||||
documentAttributeSticker23#fb0a5727 = DocumentAttribute;
|
||||
documentAttributeVideo#5910cccb duration:int w:int h:int = DocumentAttribute;
|
||||
documentAttributeVideo23#5910cccb duration:int w:int h:int = DocumentAttribute;
|
||||
documentAttributeAudio23#51448e5 duration:int = DocumentAttribute;
|
||||
documentAttributeFilename#15590068 file_name:string = DocumentAttribute;
|
||||
photoSizeEmpty#e17e23c type:string = PhotoSize;
|
||||
@ -105,7 +105,7 @@ decryptedMessageMediaWebPage#e50511d8 url:string = DecryptedMessageMedia;
|
||||
|
||||
sendMessageRecordRoundAction#88f27fbc = SendMessageAction;
|
||||
sendMessageUploadRoundAction#bb718624 = SendMessageAction;
|
||||
documentAttributeVideo66#ef02ce6 flags:# round_message:flags.0?true duration:int w:int h:int = DocumentAttribute;
|
||||
documentAttributeVideo#ef02ce6 flags:# round_message:flags.0?true duration:int w:int h:int = DocumentAttribute;
|
||||
|
||||
// layer 73
|
||||
|
||||
|
@ -163,9 +163,6 @@ remoteFile id:string unique_id:string is_uploading_active:Bool is_uploading_comp
|
||||
//@remote Information about the remote copy of the file
|
||||
file id:int32 size:int53 expected_size:int53 local:localFile remote:remoteFile = File;
|
||||
|
||||
//@description Represents a list of files @files List of files
|
||||
files files:vector<file> = Files;
|
||||
|
||||
|
||||
//@class InputFile @description Points to a file
|
||||
|
||||
@ -334,9 +331,11 @@ voiceNote duration:int32 waveform:bytes mime_type:string speech_recognition_resu
|
||||
|
||||
//@description Describes an animated or custom representation of an emoji
|
||||
//@sticker Sticker for the emoji; may be null if yet unknown for a custom emoji. If the sticker is a custom emoji, it can have arbitrary format different from stickerFormatTgs
|
||||
//@sticker_width Expected width of the sticker, which can be used if the sticker is null
|
||||
//@sticker_height Expected height of the sticker, which can be used if the sticker is null
|
||||
//@fitzpatrick_type Emoji modifier fitzpatrick type; 0-6; 0 if none
|
||||
//@sound File containing the sound to be played when the sticker is clicked; may be null. The sound is encoded with the Opus codec, and stored inside an OGG container
|
||||
animatedEmoji sticker:sticker fitzpatrick_type:int32 sound:file = AnimatedEmoji;
|
||||
animatedEmoji sticker:sticker sticker_width:int32 sticker_height:int32 fitzpatrick_type:int32 sound:file = AnimatedEmoji;
|
||||
|
||||
//@description Describes a user contact @phone_number Phone number of the user @first_name First name of the user; 1-255 characters in length @last_name Last name of the user @vcard Additional data about the user in a form of vCard; 0-2048 bytes in length @user_id Identifier of the user, if known; otherwise 0
|
||||
contact phone_number:string first_name:string last_name:string vcard:string user_id:int53 = Contact;
|
||||
@ -493,6 +492,7 @@ chatAdministratorRights can_manage_chat:Bool can_change_info:Bool can_post_messa
|
||||
//@payment_link An internal link to be opened for buying Telegram Premium to the user if store payment isn't possible; may be null if direct payment isn't available
|
||||
premiumPaymentOption currency:string amount:int53 discount_percentage:int32 month_count:int32 store_product_id:string payment_link:InternalLinkType = PremiumPaymentOption;
|
||||
|
||||
|
||||
//@description Describes a custom emoji to be shown instead of the Telegram Premium badge @custom_emoji_id Identifier of the custom emoji in stickerFormatTgs format. If the custom emoji belongs to the sticker set GetOption("themed_emoji_statuses_sticker_set_id"), then it's color must be changed to the color of the Telegram Premium badge
|
||||
emojiStatus custom_emoji_id:int64 = EmojiStatus;
|
||||
|
||||
@ -732,7 +732,7 @@ basicGroupFullInfo photo:chatPhoto description:string creator_user_id:int53 memb
|
||||
//@id Supergroup or channel identifier
|
||||
//@username Username of the supergroup or channel; empty for private supergroups or channels
|
||||
//@date Point in time (Unix timestamp) when the current user joined, or the point in time when the supergroup or channel was created, in case the user is not a member
|
||||
//@status Status of the current user in the supergroup or channel; custom title will be always empty
|
||||
//@status Status of the current user in the supergroup or channel; custom title will always be empty
|
||||
//@member_count Number of members in the supergroup or channel; 0 if unknown. Currently, it is guaranteed to be known only if the supergroup or channel was received through searchPublicChats, searchChatsNearby, getInactiveSupergroupChats, getSuitableDiscussionChats, getGroupsInCommon, or getUserPrivacySettingRules
|
||||
//@has_linked_chat True, if the channel has a discussion group, or the supergroup is the designated discussion group for a channel
|
||||
//@has_location True, if the supergroup is connected to a location, i.e. the supergroup is a location-based supergroup
|
||||
@ -809,6 +809,13 @@ messageSenderChat chat_id:int53 = MessageSender;
|
||||
messageSenders total_count:int32 senders:vector<MessageSender> = MessageSenders;
|
||||
|
||||
|
||||
//@description Represents a message sender, which can be used to send messages in a chat @sender Available message senders @needs_premium True, if Telegram Premium is needed to use the message sender
|
||||
chatMessageSender sender:MessageSender needs_premium:Bool = ChatMessageSender;
|
||||
|
||||
//@description Represents a list of message senders, which can be used to send messages in a chat @senders List of available message senders
|
||||
chatMessageSenders senders:vector<chatMessageSender> = ChatMessageSenders;
|
||||
|
||||
|
||||
//@class MessageForwardOrigin @description Contains information about the origin of a forwarded message
|
||||
|
||||
//@description The message was originally sent by a known user @sender_user_id Identifier of the user that originally sent the message
|
||||
@ -1648,7 +1655,7 @@ paymentResult success:Bool verification_url:string = PaymentResult;
|
||||
paymentReceipt title:string description:formattedText photo:photo date:int32 seller_bot_user_id:int53 payment_provider_user_id:int53 invoice:invoice order_info:orderInfo shipping_option:shippingOption credentials_title:string tip_amount:int53 = PaymentReceipt;
|
||||
|
||||
|
||||
//@class InputInvoice @description Describe an invoice to process
|
||||
//@class InputInvoice @description Describes an invoice to process
|
||||
|
||||
//@description An invoice from a message of the type messageInvoice @chat_id Chat identifier of the message @message_id Message identifier
|
||||
inputInvoiceMessage chat_id:int53 message_id:int53 = InputInvoice;
|
||||
@ -1657,6 +1664,27 @@ inputInvoiceMessage chat_id:int53 message_id:int53 = InputInvoice;
|
||||
inputInvoiceName name:string = InputInvoice;
|
||||
|
||||
|
||||
//@class MessageExtendedMedia @description Describes a media, which is attached to an invoice
|
||||
|
||||
//@description The media is hidden until the invoice is paid
|
||||
//@width Media width; 0 if unknown
|
||||
//@height Media height; 0 if unknown
|
||||
//@duration Media duration; 0 if unknown
|
||||
//@minithumbnail Media minithumbnail; may be null
|
||||
//@caption Media caption
|
||||
messageExtendedMediaPreview width:int32 height:int32 duration:int32 minithumbnail:minithumbnail caption:formattedText = MessageExtendedMedia;
|
||||
|
||||
//@description The media is a photo @photo The photo @caption Photo caption
|
||||
messageExtendedMediaPhoto photo:photo caption:formattedText = MessageExtendedMedia;
|
||||
|
||||
//@description The media is a video @video The video @caption Photo caption
|
||||
messageExtendedMediaVideo video:video caption:formattedText = MessageExtendedMedia;
|
||||
|
||||
//@description The media is unuspported @caption Media caption
|
||||
messageExtendedMediaUnsupported caption:formattedText = MessageExtendedMedia;
|
||||
|
||||
|
||||
|
||||
//@description File with the date it was uploaded @file The file @date Point in time (Unix timestamp) when the file was uploaded
|
||||
datedFile file:file date:int32 = DatedFile;
|
||||
|
||||
@ -1974,7 +2002,8 @@ messagePoll poll:poll = MessageContent;
|
||||
//@description A message with an invoice from a bot @title Product title @param_description Product description @photo Product photo; may be null @currency Currency for the product price @total_amount Product total price in the smallest units of the currency
|
||||
//@start_parameter Unique invoice bot start_parameter. To share an invoice use the URL https://t.me/{bot_username}?start={start_parameter} @is_test True, if the invoice is a test invoice
|
||||
//@need_shipping_address True, if the shipping address must be specified @receipt_message_id The identifier of the message with the receipt, after the product has been purchased
|
||||
messageInvoice title:string description:formattedText photo:photo currency:string total_amount:int53 start_parameter:string is_test:Bool need_shipping_address:Bool receipt_message_id:int53 = MessageContent;
|
||||
//@extended_media Extended media attached to the invoice; may be null
|
||||
messageInvoice title:string description:formattedText photo:photo currency:string total_amount:int53 start_parameter:string is_test:Bool need_shipping_address:Bool receipt_message_id:int53 extended_media:MessageExtendedMedia = MessageContent;
|
||||
|
||||
//@description A message with information about an ended call @is_video True, if the call was a video call @discard_reason Reason why the call was discarded @duration Call duration, in seconds
|
||||
messageCall is_video:Bool discard_reason:CallDiscardReason duration:int32 = MessageContent;
|
||||
@ -2190,7 +2219,7 @@ inputMessageAnimation animation:InputFile thumbnail:inputThumbnail added_sticker
|
||||
//@performer Performer of the audio; 0-64 characters, may be replaced by the server @caption Audio caption; pass null to use an empty caption; 0-GetOption("message_caption_length_max") characters
|
||||
inputMessageAudio audio:InputFile album_cover_thumbnail:inputThumbnail duration:int32 title:string performer:string caption:formattedText = InputMessageContent;
|
||||
|
||||
//@description A document message (general file) @document Document to be sent @thumbnail Document thumbnail; pass null to skip thumbnail uploading @disable_content_type_detection If true, automatic file type detection will be disabled and the document will be always sent as file. Always true for files sent to secret chats @caption Document caption; pass null to use an empty caption; 0-GetOption("message_caption_length_max") characters
|
||||
//@description A document message (general file) @document Document to be sent @thumbnail Document thumbnail; pass null to skip thumbnail uploading @disable_content_type_detection If true, automatic file type detection will be disabled and the document will always be sent as file. Always true for files sent to secret chats @caption Document caption; pass null to use an empty caption; 0-GetOption("message_caption_length_max") characters
|
||||
inputMessageDocument document:InputFile thumbnail:inputThumbnail disable_content_type_detection:Bool caption:formattedText = InputMessageContent;
|
||||
|
||||
//@description A photo message @photo Photo to send. The photo must be at most 10 MB in size. The photo's width and height must not exceed 10000 in total. Width and height ratio must be at most 20 @thumbnail Photo thumbnail to be sent; pass null to skip thumbnail uploading. The thumbnail is sent to the other party only in secret chats @added_sticker_file_ids File identifiers of the stickers added to the photo, if applicable @width Photo width @height Photo height @caption Photo caption; pass null to use an empty caption; 0-GetOption("message_caption_length_max") characters
|
||||
@ -2232,7 +2261,8 @@ inputMessageGame bot_user_id:int53 game_short_name:string = InputMessageContent;
|
||||
//@photo_url Product photo URL; optional @photo_size Product photo size @photo_width Product photo width @photo_height Product photo height
|
||||
//@payload The invoice payload @provider_token Payment provider token @provider_data JSON-encoded data about the invoice, which will be shared with the payment provider
|
||||
//@start_parameter Unique invoice bot deep link parameter for the generation of this invoice. If empty, it would be possible to pay directly from forwards of the invoice message
|
||||
inputMessageInvoice invoice:invoice title:string description:string photo_url:string photo_size:int32 photo_width:int32 photo_height:int32 payload:bytes provider_token:string provider_data:string start_parameter:string = InputMessageContent;
|
||||
//@extended_media_content The content of extended media attached to the invoice. The content of the message to be sent. Must be one of the following types: inputMessagePhoto, inputMessageVideo
|
||||
inputMessageInvoice invoice:invoice title:string description:string photo_url:string photo_size:int32 photo_width:int32 photo_height:int32 payload:bytes provider_token:string provider_data:string start_parameter:string extended_media_content:InputMessageContent = InputMessageContent;
|
||||
|
||||
//@description A message with a poll. Polls can't be sent to secret chats. Polls can be sent only to a private chat with a bot @question Poll question; 1-255 characters (up to 300 characters for bots) @options List of poll answer options, 2-10 strings 1-100 characters each
|
||||
//@is_anonymous True, if the poll voters are anonymous. Non-anonymous polls can't be sent or forwarded to channels @type Type of the poll
|
||||
@ -3160,7 +3190,7 @@ pushReceiverId id:int64 = PushReceiverId;
|
||||
backgroundFillSolid color:int32 = BackgroundFill;
|
||||
|
||||
//@description Describes a gradient fill of a background @top_color A top color of the background in the RGB24 format @bottom_color A bottom color of the background in the RGB24 format
|
||||
//@rotation_angle Clockwise rotation angle of the gradient, in degrees; 0-359. Must be always divisible by 45
|
||||
//@rotation_angle Clockwise rotation angle of the gradient, in degrees; 0-359. Must always be divisible by 45
|
||||
backgroundFillGradient top_color:int32 bottom_color:int32 rotation_angle:int32 = BackgroundFill;
|
||||
|
||||
//@description Describes a freeform gradient fill of a background @colors A list of 3 or 4 colors of the freeform gradients in the RGB24 format
|
||||
@ -3739,8 +3769,8 @@ internalLinkTypeFilterSettings = InternalLinkType;
|
||||
//@bot_username Username of the bot that owns the game @game_short_name Short name of the game
|
||||
internalLinkTypeGame bot_username:string game_short_name:string = InternalLinkType;
|
||||
|
||||
//@description The link must be opened in an Instant View. Call getWebPageInstantView with the given URL to process the link @url URL to be passed to getWebPageInstantView
|
||||
internalLinkTypeInstantView url:string = InternalLinkType;
|
||||
//@description The link must be opened in an Instant View. Call getWebPageInstantView with the given URL to process the link @url URL to be passed to getWebPageInstantView @fallback_url An URL to open if getWebPageInstantView fails
|
||||
internalLinkTypeInstantView url:string fallback_url:string = InternalLinkType;
|
||||
|
||||
//@description The link is a link to an invoice. Call getPaymentForm with the given invoice name to process the link @invoice_name Name of the invoice
|
||||
internalLinkTypeInvoice invoice_name:string = InternalLinkType;
|
||||
@ -4993,6 +5023,12 @@ getChatMessageCalendar chat_id:int53 filter:SearchMessagesFilter from_message_id
|
||||
//@description Returns approximate number of messages of the specified type in the chat @chat_id Identifier of the chat in which to count messages @filter Filter for message content; searchMessagesFilterEmpty is unsupported in this function @return_local Pass true to get the number of messages without sending network requests, or -1 if the number of messages is unknown locally
|
||||
getChatMessageCount chat_id:int53 filter:SearchMessagesFilter return_local:Bool = Count;
|
||||
|
||||
//@description Returns approximate 1-based position of a message among messages, which can be found by the specified filter in the chat. Cannot be used in secret chats
|
||||
//@chat_id Identifier of the chat in which to find message position @message_id Message identifier
|
||||
//@filter Filter for message content; searchMessagesFilterEmpty, searchMessagesFilterUnreadMention, searchMessagesFilterUnreadReaction, and searchMessagesFilterFailedToSend are unsupported in this function
|
||||
//@message_thread_id If not 0, only messages in the specified thread will be considered; supergroups only
|
||||
getChatMessagePosition chat_id:int53 message_id:int53 filter:SearchMessagesFilter message_thread_id:int53 = Count;
|
||||
|
||||
//@description Returns all scheduled messages in a chat. The messages are returned in a reverse chronological order (i.e., in order of decreasing message_id) @chat_id Chat identifier
|
||||
getChatScheduledMessages chat_id:int53 = Messages;
|
||||
|
||||
@ -5048,7 +5084,7 @@ rateSpeechRecognition chat_id:int53 message_id:int53 is_good:Bool = Ok;
|
||||
|
||||
|
||||
//@description Returns list of message sender identifiers, which can be used to send messages in a chat @chat_id Chat identifier
|
||||
getChatAvailableMessageSenders chat_id:int53 = MessageSenders;
|
||||
getChatAvailableMessageSenders chat_id:int53 = ChatMessageSenders;
|
||||
|
||||
//@description Selects a message sender to send messages in a chat @chat_id Chat identifier @message_sender_id New message sender for the chat
|
||||
setChatMessageSender chat_id:int53 message_sender_id:MessageSender = Ok;
|
||||
@ -5200,8 +5236,8 @@ editMessageSchedulingState chat_id:int53 message_id:int53 scheduling_state:Messa
|
||||
//@description Returns information about a emoji reaction. Returns a 404 error if the reaction is not found @emoji Text representation of the reaction
|
||||
getEmojiReaction emoji:string = EmojiReaction;
|
||||
|
||||
//@description Returns TGS files with generic animations for custom emoji reactions
|
||||
getCustomEmojiReactionAnimations = Files;
|
||||
//@description Returns TGS stickers with generic animations for custom emoji reactions
|
||||
getCustomEmojiReactionAnimations = Stickers;
|
||||
|
||||
//@description Returns reactions, which can be added to a message. The list can change after updateActiveEmojiReactions, updateChatAvailableReactions for the chat, or updateMessageInteractionInfo for the message
|
||||
//@chat_id Identifier of the chat to which the message belongs
|
||||
@ -6045,12 +6081,12 @@ sharePhoneNumber user_id:int53 = Ok;
|
||||
getUserProfilePhotos user_id:int53 offset:int32 limit:int32 = ChatPhotos;
|
||||
|
||||
|
||||
//@description Returns stickers from the installed sticker sets that correspond to a given emoji. If the emoji is non-empty, then favorite, recently used or trending stickers may also be returned
|
||||
//@sticker_type Type of the sticker sets to return
|
||||
//@emoji String representation of emoji. If empty, returns all known installed stickers
|
||||
//@description Returns stickers from the installed sticker sets that correspond to a given emoji or can be found by sticker-specific keywords. If the query is non-empty, then favorite, recently used or trending stickers may also be returned
|
||||
//@sticker_type Type of the stickers to return
|
||||
//@query Search query; an emoji or a keyword prefix. If empty, returns all known installed stickers
|
||||
//@limit The maximum number of stickers to be returned
|
||||
//@chat_id Chat identifier for which to return stickers. Available custom emoji may be different for different chats
|
||||
getStickers sticker_type:StickerType emoji:string limit:int32 chat_id:int53 = Stickers;
|
||||
//@chat_id Chat identifier for which to return stickers. Available custom emoji stickers may be different for different chats
|
||||
getStickers sticker_type:StickerType query:string limit:int32 chat_id:int53 = Stickers;
|
||||
|
||||
//@description Searches for stickers from public sticker sets that correspond to a given emoji @emoji String representation of emoji; must be non-empty @limit The maximum number of stickers to be returned; 0-100
|
||||
searchStickers emoji:string limit:int32 = Stickers;
|
||||
|
@ -59,7 +59,7 @@ inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string pro
|
||||
inputMediaPhotoExternal#e5bbfe1a flags:# url:string ttl_seconds:flags.0?int = InputMedia;
|
||||
inputMediaDocumentExternal#fb52dc99 flags:# url:string ttl_seconds:flags.0?int = InputMedia;
|
||||
inputMediaGame#d33f43f3 id:InputGame = InputMedia;
|
||||
inputMediaInvoice#d9799874 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON start_param:flags.1?string = InputMedia;
|
||||
inputMediaInvoice#8eb5a6d5 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON start_param:flags.1?string extended_media:flags.2?InputMedia = InputMedia;
|
||||
inputMediaGeoLive#971fa843 flags:# stopped:flags.0?true geo_point:InputGeoPoint heading:flags.2?int period:flags.1?int proximity_notification_radius:flags.3?int = InputMedia;
|
||||
inputMediaPoll#f94e5f1 flags:# poll:Poll correct_answers:flags.0?Vector<bytes> solution:flags.1?string solution_entities:flags.1?Vector<MessageEntity> = InputMedia;
|
||||
inputMediaDice#e66fbf7b emoticon:string = InputMedia;
|
||||
@ -145,7 +145,7 @@ messageMediaDocument#9cb070d7 flags:# nopremium:flags.3?true document:flags.0?Do
|
||||
messageMediaWebPage#a32dd600 webpage:WebPage = MessageMedia;
|
||||
messageMediaVenue#2ec0533f geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MessageMedia;
|
||||
messageMediaGame#fdb19008 game:Game = MessageMedia;
|
||||
messageMediaInvoice#84551347 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string = MessageMedia;
|
||||
messageMediaInvoice#f6a548d3 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string extended_media:flags.4?MessageExtendedMedia = MessageMedia;
|
||||
messageMediaGeoLive#b940c666 flags:# geo:GeoPoint heading:flags.0?int period:int proximity_notification_radius:flags.1?int = MessageMedia;
|
||||
messageMediaPoll#4bd6e798 poll:Poll results:PollResults = MessageMedia;
|
||||
messageMediaDice#3f7ee58b value:int emoticon:string = MessageMedia;
|
||||
@ -388,6 +388,7 @@ updateUserEmojiStatus#28373599 user_id:long emoji_status:EmojiStatus = Update;
|
||||
updateRecentEmojiStatuses#30f443db = Update;
|
||||
updateRecentReactions#6f7863f4 = Update;
|
||||
updateMoveStickerSetToTop#86fccf85 flags:# masks:flags.0?true emojis:flags.1?true stickerset:long = Update;
|
||||
updateMessageExtendedMedia#5a73a98c peer:Peer msg_id:int extended_media:MessageExtendedMedia = Update;
|
||||
|
||||
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
|
||||
|
||||
@ -581,7 +582,7 @@ inputStickerSetEmojiDefaultStatuses#29d0f5ee = InputStickerSet;
|
||||
|
||||
stickerSet#2dd14edc flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true animated:flags.5?true videos:flags.6?true emojis:flags.7?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumbs:flags.4?Vector<PhotoSize> thumb_dc_id:flags.4?int thumb_version:flags.4?int thumb_document_id:flags.8?long count:int hash:int = StickerSet;
|
||||
|
||||
messages.stickerSet#b60a24a6 set:StickerSet packs:Vector<StickerPack> documents:Vector<Document> = messages.StickerSet;
|
||||
messages.stickerSet#6e153f16 set:StickerSet packs:Vector<StickerPack> keywords:Vector<StickerKeyword> documents:Vector<Document> = messages.StickerSet;
|
||||
messages.stickerSetNotModified#d3f924eb = messages.StickerSet;
|
||||
|
||||
botCommand#c27ac8c7 command:string description:string = BotCommand;
|
||||
@ -760,7 +761,7 @@ messages.stickerSetInstallResultArchive#35e410a8 sets:Vector<StickerSetCovered>
|
||||
|
||||
stickerSetCovered#6410a5d2 set:StickerSet cover:Document = StickerSetCovered;
|
||||
stickerSetMultiCovered#3407e51b set:StickerSet covers:Vector<Document> = StickerSetCovered;
|
||||
stickerSetFullCovered#1aed5ee5 set:StickerSet packs:Vector<StickerPack> documents:Vector<Document> = StickerSetCovered;
|
||||
stickerSetFullCovered#40d13c0e set:StickerSet packs:Vector<StickerPack> keywords:Vector<StickerKeyword> documents:Vector<Document> = StickerSetCovered;
|
||||
|
||||
maskCoords#aed6dbb2 n:int x:double y:double zoom:double = MaskCoords;
|
||||
|
||||
@ -1318,7 +1319,7 @@ searchResultPosition#7f648b67 msg_id:int date:int offset:int = SearchResultsPosi
|
||||
|
||||
messages.searchResultsPositions#53b22baf count:int positions:Vector<SearchResultsPosition> = messages.SearchResultsPositions;
|
||||
|
||||
channels.sendAsPeers#8356cda9 peers:Vector<Peer> chats:Vector<Chat> users:Vector<User> = channels.SendAsPeers;
|
||||
channels.sendAsPeers#f496b0c6 peers:Vector<SendAsPeer> chats:Vector<Chat> users:Vector<User> = channels.SendAsPeers;
|
||||
|
||||
users.userFull#3b6d152e full_user:UserFull chats:Vector<Chat> users:Vector<User> = users.UserFull;
|
||||
|
||||
@ -1433,6 +1434,13 @@ account.emailVerifiedLogin#e1bb0d61 email:string sent_code:auth.SentCode = accou
|
||||
|
||||
premiumSubscriptionOption#b6f11ebe flags:# current:flags.1?true can_purchase_upgrade:flags.2?true months:int currency:string amount:long bot_url:string store_product:flags.0?string = PremiumSubscriptionOption;
|
||||
|
||||
sendAsPeer#b81c7034 flags:# premium_required:flags.0?true peer:Peer = SendAsPeer;
|
||||
|
||||
messageExtendedMediaPreview#ad628cc8 flags:# w:flags.0?int h:flags.0?int thumb:flags.1?PhotoSize video_duration:flags.2?int = MessageExtendedMedia;
|
||||
messageExtendedMedia#ee479c64 media:MessageMedia = MessageExtendedMedia;
|
||||
|
||||
stickerKeyword#fcfeb29c document_id:long keyword:Vector<string> = StickerKeyword;
|
||||
|
||||
---functions---
|
||||
|
||||
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
|
||||
@ -1746,6 +1754,7 @@ messages.reportReaction#3f64c076 peer:InputPeer id:int reaction_peer:InputPeer =
|
||||
messages.getTopReactions#bb8125ba limit:int hash:long = messages.Reactions;
|
||||
messages.getRecentReactions#39461db2 limit:int hash:long = messages.Reactions;
|
||||
messages.clearRecentReactions#9dfeefb4 = Bool;
|
||||
messages.getExtendedMedia#84f80814 peer:InputPeer id:Vector<int> = Updates;
|
||||
|
||||
updates.getState#edd4882a = updates.State;
|
||||
updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference;
|
||||
|
@ -202,6 +202,10 @@ std::string TD_TL_writer_java::gen_output_begin() const {
|
||||
" } catch (UnsatisfiedLinkError e) {\n"
|
||||
" e.printStackTrace();\n" +
|
||||
" }\n"
|
||||
" }\n\n"
|
||||
" private " +
|
||||
tl_name +
|
||||
"() {\n"
|
||||
" }\n\n";
|
||||
}
|
||||
|
||||
|
@ -1042,7 +1042,7 @@ Status SessionConnection::do_flush() {
|
||||
auto start_time = Time::now();
|
||||
auto result = raw_connection_->flush(auth_data_->get_auth_key(), *this);
|
||||
auto elapsed_time = Time::now() - start_time;
|
||||
if (elapsed_time >= 0.01) {
|
||||
if (elapsed_time >= 0.1) {
|
||||
LOG(ERROR) << "RawConnection::flush took " << elapsed_time << " seconds, written " << last_write_size_
|
||||
<< " bytes, read " << last_read_size_ << " bytes and returned " << result;
|
||||
}
|
||||
|
@ -389,7 +389,7 @@ SecretInputMedia AnimationsManager::get_secret_input_media(FileId animation_file
|
||||
attributes.push_back(make_tl_object<secret_api::documentAttributeFilename>(animation->file_name));
|
||||
}
|
||||
if (animation->duration != 0 && animation->mime_type == "video/mp4") {
|
||||
attributes.push_back(make_tl_object<secret_api::documentAttributeVideo66>(
|
||||
attributes.push_back(make_tl_object<secret_api::documentAttributeVideo>(
|
||||
0, false, animation->duration, animation->dimensions.width, animation->dimensions.height));
|
||||
}
|
||||
if (animation->dimensions.width != 0 && animation->dimensions.height != 0) {
|
||||
|
@ -845,7 +845,7 @@ void AuthManager::on_log_out_result(NetQueryPtr &result) {
|
||||
} else {
|
||||
status = std::move(result->error());
|
||||
}
|
||||
LOG_IF(ERROR, status.is_error() && status.error().code() != 401) << "Receive error for auth.logOut: " << status;
|
||||
LOG_IF(ERROR, status.is_error() && status.code() != 401) << "Receive error for auth.logOut: " << status;
|
||||
// state_ will stay LoggingOut, so no queries will work.
|
||||
destroy_auth_keys();
|
||||
if (query_id_ != 0) {
|
||||
@ -897,7 +897,7 @@ void AuthManager::on_delete_account_result(NetQueryPtr &result) {
|
||||
} else {
|
||||
status = std::move(result->error());
|
||||
}
|
||||
if (status.is_error() && status.error().message() != "USER_DEACTIVATED") {
|
||||
if (status.is_error() && status.message() != "USER_DEACTIVATED") {
|
||||
LOG(WARNING) << "Request account.deleteAccount failed: " << status;
|
||||
// TODO handle some errors
|
||||
if (query_id_ != 0) {
|
||||
|
@ -953,6 +953,8 @@ void CallActor::loop() {
|
||||
break;
|
||||
}
|
||||
LOG(INFO) << "Close " << local_call_id_;
|
||||
container_.for_each(
|
||||
[](auto id, Promise<NetQueryPtr> &promise) { promise.set_error(Global::request_aborted_error()); });
|
||||
stop();
|
||||
break;
|
||||
}
|
||||
|
@ -9,7 +9,6 @@
|
||||
#include "td/telegram/telegram_api.hpp"
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/format.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/misc.h"
|
||||
#include "td/utils/SliceBuilder.h"
|
||||
@ -174,25 +173,24 @@ ActorId<CallActor> CallManager::get_call_actor(CallId call_id) {
|
||||
void CallManager::hangup() {
|
||||
close_flag_ = true;
|
||||
for (auto &it : id_to_actor_) {
|
||||
LOG(INFO) << "Ask close CallActor " << it.first;
|
||||
LOG(INFO) << "Ask to close CallActor " << it.first.get();
|
||||
it.second.reset();
|
||||
}
|
||||
if (id_to_actor_.empty()) {
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
void CallManager::hangup_shared() {
|
||||
auto token = narrow_cast<int32>(get_link_token());
|
||||
auto it = id_to_actor_.find(CallId(token));
|
||||
if (it != id_to_actor_.end()) {
|
||||
LOG(INFO) << "Close CallActor " << tag("id", it->first);
|
||||
it->second.release();
|
||||
id_to_actor_.erase(it);
|
||||
} else {
|
||||
LOG(FATAL) << "Unknown CallActor hangup " << tag("id", static_cast<int32>(token));
|
||||
}
|
||||
CHECK(it != id_to_actor_.end());
|
||||
LOG(INFO) << "Closed CallActor " << it->first.get();
|
||||
it->second.release();
|
||||
id_to_actor_.erase(it);
|
||||
if (close_flag_ && id_to_actor_.empty()) {
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace td
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "td/telegram/CallId.h"
|
||||
#include "td/telegram/td_api.h"
|
||||
#include "td/telegram/telegram_api.h"
|
||||
#include "td/telegram/UserId.h"
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
|
||||
|
@ -176,7 +176,7 @@ void CallbackQueriesManager::on_new_query(int32 flags, int64 callback_query_id,
|
||||
LOG(ERROR) << "Receive new callback query from invalid " << sender_user_id << " in " << dialog_id;
|
||||
return;
|
||||
}
|
||||
LOG_IF(ERROR, !td_->contacts_manager_->have_user(sender_user_id)) << "Have no info about " << sender_user_id;
|
||||
LOG_IF(ERROR, !td_->contacts_manager_->have_user(sender_user_id)) << "Receive unknown " << sender_user_id;
|
||||
if (!td_->auth_manager_->is_bot()) {
|
||||
LOG(ERROR) << "Receive new callback query";
|
||||
return;
|
||||
@ -208,7 +208,7 @@ void CallbackQueriesManager::on_new_inline_query(
|
||||
LOG(ERROR) << "Receive new callback query from invalid " << sender_user_id;
|
||||
return;
|
||||
}
|
||||
LOG_IF(ERROR, !td_->contacts_manager_->have_user(sender_user_id)) << "Have no info about " << sender_user_id;
|
||||
LOG_IF(ERROR, !td_->contacts_manager_->have_user(sender_user_id)) << "Receive unknown " << sender_user_id;
|
||||
if (!td_->auth_manager_->is_bot()) {
|
||||
LOG(ERROR) << "Receive new callback query";
|
||||
return;
|
||||
|
@ -12,10 +12,14 @@
|
||||
|
||||
namespace td {
|
||||
|
||||
ClientActor::ClientActor(unique_ptr<TdCallback> callback, Options options) {
|
||||
ClientActor::ClientActor(unique_ptr<TdCallback> callback, Options options)
|
||||
: callback_(std::move(callback)), options_(std::move(options)) {
|
||||
}
|
||||
|
||||
void ClientActor::start_up() {
|
||||
Td::Options td_options;
|
||||
td_options.net_query_stats = std::move(options.net_query_stats);
|
||||
td_ = create_actor<Td>("Td", std::move(callback), std::move(td_options));
|
||||
td_options.net_query_stats = std::move(options_.net_query_stats);
|
||||
td_ = create_actor<Td>("Td", std::move(callback_), std::move(td_options));
|
||||
}
|
||||
|
||||
void ClientActor::request(uint64 id, td_api::object_ptr<td_api::Function> request) {
|
||||
|
@ -81,7 +81,11 @@ class ClientActor final : public Actor {
|
||||
ClientActor &operator=(const ClientActor &other) = delete;
|
||||
|
||||
private:
|
||||
void start_up() final;
|
||||
|
||||
ActorOwn<Td> td_;
|
||||
unique_ptr<TdCallback> callback_;
|
||||
Options options_;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -48,8 +48,7 @@ static std::pair<td_api::object_ptr<td_api::Function>, string> to_request(Slice
|
||||
td_api::object_ptr<td_api::Function> func;
|
||||
auto status = from_json(func, std::move(json_value));
|
||||
if (status.is_error()) {
|
||||
return {get_return_error_function(PSLICE()
|
||||
<< "Failed to parse JSON object as TDLib request: " << status.error().message()),
|
||||
return {get_return_error_function(PSLICE() << "Failed to parse JSON object as TDLib request: " << status.message()),
|
||||
std::move(extra)};
|
||||
}
|
||||
return std::make_pair(std::move(func), std::move(extra));
|
||||
|
@ -5072,6 +5072,49 @@ string ContactsManager::get_dialog_about(DialogId dialog_id) {
|
||||
return string();
|
||||
}
|
||||
|
||||
string ContactsManager::get_dialog_search_text(DialogId dialog_id) const {
|
||||
switch (dialog_id.get_type()) {
|
||||
case DialogType::User:
|
||||
return get_user_search_text(dialog_id.get_user_id());
|
||||
case DialogType::Chat:
|
||||
return get_chat_title(dialog_id.get_chat_id());
|
||||
case DialogType::Channel:
|
||||
return get_channel_search_text(dialog_id.get_channel_id());
|
||||
case DialogType::SecretChat:
|
||||
return get_user_search_text(get_secret_chat_user_id(dialog_id.get_secret_chat_id()));
|
||||
case DialogType::None:
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
return string();
|
||||
}
|
||||
|
||||
string ContactsManager::get_user_search_text(UserId user_id) const {
|
||||
auto u = get_user(user_id);
|
||||
if (u == nullptr) {
|
||||
return string();
|
||||
}
|
||||
return get_user_search_text(u);
|
||||
}
|
||||
|
||||
string ContactsManager::get_user_search_text(const User *u) {
|
||||
CHECK(u != nullptr);
|
||||
return PSTRING() << u->first_name << ' ' << u->last_name << ' ' << u->username;
|
||||
}
|
||||
|
||||
string ContactsManager::get_channel_search_text(ChannelId channel_id) const {
|
||||
auto c = get_channel(channel_id);
|
||||
if (c == nullptr) {
|
||||
return get_channel_title(channel_id);
|
||||
}
|
||||
return get_channel_search_text(c);
|
||||
}
|
||||
|
||||
string ContactsManager::get_channel_search_text(const Channel *c) {
|
||||
CHECK(c != nullptr);
|
||||
return PSTRING() << c->title << ' ' << c->username;
|
||||
}
|
||||
|
||||
int32 ContactsManager::get_secret_chat_date(SecretChatId secret_chat_id) const {
|
||||
auto c = get_secret_chat(secret_chat_id);
|
||||
if (c == nullptr) {
|
||||
@ -5100,14 +5143,6 @@ string ContactsManager::get_user_username(UserId user_id) const {
|
||||
return u->username;
|
||||
}
|
||||
|
||||
string ContactsManager::get_secret_chat_username(SecretChatId secret_chat_id) const {
|
||||
auto c = get_secret_chat(secret_chat_id);
|
||||
if (c == nullptr) {
|
||||
return string();
|
||||
}
|
||||
return get_user_username(c->user_id);
|
||||
}
|
||||
|
||||
string ContactsManager::get_channel_username(ChannelId channel_id) const {
|
||||
auto c = get_channel(channel_id);
|
||||
if (c == nullptr) {
|
||||
@ -5319,7 +5354,7 @@ void ContactsManager::check_dialog_username(DialogId dialog_id, const string &us
|
||||
if (username.empty()) {
|
||||
return promise.set_value(CheckDialogUsernameResult::Ok);
|
||||
}
|
||||
if (!is_valid_username(username)) {
|
||||
if (!is_allowed_username(username)) {
|
||||
return promise.set_value(CheckDialogUsernameResult::Invalid);
|
||||
}
|
||||
|
||||
@ -5375,29 +5410,18 @@ td_api::object_ptr<td_api::CheckChatUsernameResult> ContactsManager::get_check_c
|
||||
}
|
||||
}
|
||||
|
||||
bool ContactsManager::is_valid_username(const string &username) {
|
||||
if (username.size() < 5 || username.size() > 32) {
|
||||
bool ContactsManager::is_allowed_username(const string &username) {
|
||||
if (!is_valid_username(username)) {
|
||||
return false;
|
||||
}
|
||||
if (!is_alpha(username[0])) {
|
||||
if (username.size() < 5) {
|
||||
return false;
|
||||
}
|
||||
for (auto c : username) {
|
||||
if (!is_alpha(c) && !is_digit(c) && c != '_') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (username.back() == '_') {
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 1; i < username.size(); i++) {
|
||||
if (username[i - 1] == '_' && username[i] == '_') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (username.find("admin") == 0 || username.find("telegram") == 0 || username.find("support") == 0 ||
|
||||
username.find("security") == 0 || username.find("settings") == 0 || username.find("contacts") == 0 ||
|
||||
username.find("service") == 0 || username.find("telegraph") == 0) {
|
||||
auto username_lowered = to_lower(username);
|
||||
if (username_lowered.find("admin") == 0 || username_lowered.find("telegram") == 0 ||
|
||||
username_lowered.find("support") == 0 || username_lowered.find("security") == 0 ||
|
||||
username_lowered.find("settings") == 0 || username_lowered.find("contacts") == 0 ||
|
||||
username_lowered.find("service") == 0 || username_lowered.find("telegraph") == 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -6618,7 +6642,7 @@ void ContactsManager::on_update_profile_success(int32 flags, const string &first
|
||||
}
|
||||
|
||||
void ContactsManager::set_username(const string &username, Promise<Unit> &&promise) {
|
||||
if (!username.empty() && !is_valid_username(username)) {
|
||||
if (!username.empty() && !is_allowed_username(username)) {
|
||||
return promise.set_error(Status::Error(400, "Username is invalid"));
|
||||
}
|
||||
td_->create_handler<UpdateUsernameQuery>(std::move(promise))->send(username);
|
||||
@ -6672,7 +6696,7 @@ void ContactsManager::set_channel_username(ChannelId channel_id, const string &u
|
||||
return promise.set_error(Status::Error(400, "Not enough rights to change supergroup username"));
|
||||
}
|
||||
|
||||
if (!username.empty() && !is_valid_username(username)) {
|
||||
if (!username.empty() && !is_allowed_username(username)) {
|
||||
return promise.set_error(Status::Error(400, "Username is invalid"));
|
||||
}
|
||||
|
||||
@ -8711,7 +8735,7 @@ void ContactsManager::on_get_user(tl_object_ptr<telegram_api::User> &&user_ptr,
|
||||
|
||||
User *u = get_user_force(user_id);
|
||||
if (u == nullptr && Slice(source) != Slice("GetUsersQuery")) {
|
||||
// userEmpty should be received only through getUsers for unexisting users
|
||||
// userEmpty should be received only through getUsers for nonexistent users
|
||||
LOG(ERROR) << "Have no information about " << user_id << ", but received userEmpty from " << source;
|
||||
}
|
||||
return;
|
||||
@ -10414,7 +10438,7 @@ void ContactsManager::update_user(User *u, UserId user_id, bool from_binlog, boo
|
||||
} else {
|
||||
u->need_save_to_database = true;
|
||||
}
|
||||
if (u->last_sent_emoji_status != 0) {
|
||||
if (u->last_sent_emoji_status.is_valid()) {
|
||||
auto until_date = u->emoji_status.get_until_date();
|
||||
auto left_time = until_date - unix_time;
|
||||
if (left_time >= 0 && left_time < 30 * 86400) {
|
||||
@ -11652,15 +11676,6 @@ void ContactsManager::on_get_channel_full_failed(ChannelId channel_id) {
|
||||
}
|
||||
}
|
||||
|
||||
bool ContactsManager::is_update_about_username_change_received(UserId user_id) const {
|
||||
const User *u = get_user(user_id);
|
||||
if (u != nullptr) {
|
||||
return u->is_contact;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void ContactsManager::on_update_user_name(UserId user_id, string &&first_name, string &&last_name, string &&username) {
|
||||
if (!user_id.is_valid()) {
|
||||
LOG(ERROR) << "Receive invalid " << user_id;
|
||||
@ -14541,7 +14556,7 @@ void ContactsManager::update_contacts_hints(const User *u, UserId user_id, bool
|
||||
|
||||
int64 key = user_id.get();
|
||||
string old_value = contacts_hints_.key_to_string(key);
|
||||
string new_value = is_contact ? (PSTRING() << u->first_name << ' ' << u->last_name << ' ' << u->username) : string();
|
||||
string new_value = is_contact ? get_user_search_text(u) : string();
|
||||
|
||||
if (new_value != old_value) {
|
||||
if (is_contact) {
|
||||
@ -14932,10 +14947,11 @@ FileSourceId ContactsManager::get_user_full_file_source_id(UserId user_id) {
|
||||
return FileSourceId();
|
||||
}
|
||||
|
||||
if (get_user_full(user_id) != nullptr) {
|
||||
auto user_full = get_user_full(user_id);
|
||||
if (user_full != nullptr) {
|
||||
VLOG(file_references) << "Don't need to create file source for full " << user_id;
|
||||
// user full was already added, source ID was registered and shouldn't be needed
|
||||
return FileSourceId();
|
||||
return user_full->is_update_user_full_sent ? FileSourceId() : user_full->file_source_id;
|
||||
}
|
||||
|
||||
auto &source_id = user_full_file_source_ids_[user_id];
|
||||
@ -14951,10 +14967,11 @@ FileSourceId ContactsManager::get_chat_full_file_source_id(ChatId chat_id) {
|
||||
return FileSourceId();
|
||||
}
|
||||
|
||||
if (get_chat_full(chat_id) != nullptr) {
|
||||
auto chat_full = get_chat_full(chat_id);
|
||||
if (chat_full != nullptr) {
|
||||
VLOG(file_references) << "Don't need to create file source for full " << chat_id;
|
||||
// chat full was already added, source ID was registered and shouldn't be needed
|
||||
return FileSourceId();
|
||||
return chat_full->is_update_chat_full_sent ? FileSourceId() : chat_full->file_source_id;
|
||||
}
|
||||
|
||||
auto &source_id = chat_full_file_source_ids_[chat_id];
|
||||
@ -14970,10 +14987,11 @@ FileSourceId ContactsManager::get_channel_full_file_source_id(ChannelId channel_
|
||||
return FileSourceId();
|
||||
}
|
||||
|
||||
if (get_channel_full(channel_id) != nullptr) {
|
||||
auto channel_full = get_channel_full(channel_id);
|
||||
if (channel_full != nullptr) {
|
||||
VLOG(file_references) << "Don't need to create file source for full " << channel_id;
|
||||
// channel full was already added, source ID was registered and shouldn't be needed
|
||||
return FileSourceId();
|
||||
return channel_full->is_update_channel_full_sent ? FileSourceId() : channel_full->file_source_id;
|
||||
}
|
||||
|
||||
auto &source_id = channel_full_file_source_ids_[channel_id];
|
||||
@ -15280,6 +15298,14 @@ int32 ContactsManager::get_channel_participant_count(ChannelId channel_id) const
|
||||
return c->participant_count;
|
||||
}
|
||||
|
||||
bool ContactsManager::get_channel_is_verified(ChannelId channel_id) const {
|
||||
auto c = get_channel(channel_id);
|
||||
if (c == nullptr) {
|
||||
return false;
|
||||
}
|
||||
return c->is_verified;
|
||||
}
|
||||
|
||||
bool ContactsManager::get_channel_sign_messages(ChannelId channel_id) const {
|
||||
auto c = get_channel(channel_id);
|
||||
if (c == nullptr) {
|
||||
@ -15631,7 +15657,7 @@ std::pair<int32, vector<DialogId>> ContactsManager::search_among_dialogs(const v
|
||||
if (query.empty()) {
|
||||
hints.add(dialog_id.get(), Slice(" "));
|
||||
} else {
|
||||
hints.add(dialog_id.get(), PSLICE() << u->first_name << ' ' << u->last_name << ' ' << u->username);
|
||||
hints.add(dialog_id.get(), get_user_search_text(u));
|
||||
}
|
||||
rating = -get_user_was_online(u, user_id);
|
||||
} else {
|
||||
@ -15641,7 +15667,7 @@ std::pair<int32, vector<DialogId>> ContactsManager::search_among_dialogs(const v
|
||||
if (query.empty()) {
|
||||
hints.add(dialog_id.get(), Slice(" "));
|
||||
} else {
|
||||
hints.add(dialog_id.get(), td_->messages_manager_->get_dialog_title(dialog_id));
|
||||
hints.add(dialog_id.get(), get_dialog_search_text(dialog_id));
|
||||
}
|
||||
}
|
||||
hints.set_rating(dialog_id.get(), rating);
|
||||
@ -16823,7 +16849,7 @@ td_api::object_ptr<td_api::updateUser> ContactsManager::get_update_unknown_user_
|
||||
|
||||
int64 ContactsManager::get_user_id_object(UserId user_id, const char *source) const {
|
||||
if (user_id.is_valid() && get_user(user_id) == nullptr && unknown_users_.count(user_id) == 0) {
|
||||
LOG(ERROR) << "Have no info about " << user_id << " from " << source;
|
||||
LOG(ERROR) << "Have no information about " << user_id << " from " << source;
|
||||
unknown_users_.insert(user_id);
|
||||
send_closure(G()->td(), &Td::send_update, get_update_unknown_user_object(user_id));
|
||||
}
|
||||
@ -16875,7 +16901,7 @@ tl_object_ptr<td_api::user> ContactsManager::get_user_object(UserId user_id, con
|
||||
type = make_tl_object<td_api::userTypeRegular>();
|
||||
}
|
||||
|
||||
auto emoji_status = u->last_sent_emoji_status != 0 ? u->emoji_status.get_emoji_status_object() : nullptr;
|
||||
auto emoji_status = u->last_sent_emoji_status.is_valid() ? u->emoji_status.get_emoji_status_object() : nullptr;
|
||||
return make_tl_object<td_api::user>(
|
||||
user_id.get(), u->first_name, u->last_name, u->username, u->phone_number, get_user_status_object(user_id, u),
|
||||
get_profile_photo_object(td_->file_manager_.get(), u->photo), std::move(emoji_status), u->is_contact,
|
||||
@ -16932,7 +16958,7 @@ tl_object_ptr<td_api::userFullInfo> ContactsManager::get_user_full_info_object(U
|
||||
return true;
|
||||
}
|
||||
if (entity.type == MessageEntity::Type::Url &&
|
||||
!LinkManager::is_internal_link(utf8_utf16_substr(Slice(bio.text), entity.offset, entity.length))) {
|
||||
!LinkManager::is_internal_link(utf8_utf16_substr(bio.text, entity.offset, entity.length))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -16957,7 +16983,7 @@ td_api::object_ptr<td_api::updateBasicGroup> ContactsManager::get_update_unknown
|
||||
|
||||
int64 ContactsManager::get_basic_group_id_object(ChatId chat_id, const char *source) const {
|
||||
if (chat_id.is_valid() && get_chat(chat_id) == nullptr && unknown_chats_.count(chat_id) == 0) {
|
||||
LOG(ERROR) << "Have no info about " << chat_id << " from " << source;
|
||||
LOG(ERROR) << "Have no information about " << chat_id << " from " << source;
|
||||
unknown_chats_.insert(chat_id);
|
||||
send_closure(G()->td(), &Td::send_update, get_update_unknown_basic_group_object(chat_id));
|
||||
}
|
||||
@ -17016,7 +17042,7 @@ int64 ContactsManager::get_supergroup_id_object(ChannelId channel_id, const char
|
||||
if (have_min_channel(channel_id)) {
|
||||
LOG(INFO) << "Have only min " << channel_id << " received from " << source;
|
||||
} else {
|
||||
LOG(ERROR) << "Have no info about " << channel_id << " received from " << source;
|
||||
LOG(ERROR) << "Have no information about " << channel_id << " received from " << source;
|
||||
}
|
||||
unknown_channels_.insert(channel_id);
|
||||
send_closure(G()->td(), &Td::send_update, get_update_unknown_supergroup_object(channel_id));
|
||||
@ -17090,7 +17116,7 @@ td_api::object_ptr<td_api::updateSecretChat> ContactsManager::get_update_unknown
|
||||
int32 ContactsManager::get_secret_chat_id_object(SecretChatId secret_chat_id, const char *source) const {
|
||||
if (secret_chat_id.is_valid() && get_secret_chat(secret_chat_id) == nullptr &&
|
||||
unknown_secret_chats_.count(secret_chat_id) == 0) {
|
||||
LOG(ERROR) << "Have no info about " << secret_chat_id << " from " << source;
|
||||
LOG(ERROR) << "Have no information about " << secret_chat_id << " from " << source;
|
||||
unknown_secret_chats_.insert(secret_chat_id);
|
||||
send_closure(G()->td(), &Td::send_update, get_update_unknown_secret_chat_object(secret_chat_id));
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "td/telegram/ChannelType.h"
|
||||
#include "td/telegram/ChatId.h"
|
||||
#include "td/telegram/Contact.h"
|
||||
#include "td/telegram/CustomEmojiId.h"
|
||||
#include "td/telegram/DialogAdministrator.h"
|
||||
#include "td/telegram/DialogId.h"
|
||||
#include "td/telegram/DialogInviteLink.h"
|
||||
@ -128,13 +129,12 @@ class ContactsManager final : public Actor {
|
||||
|
||||
string get_dialog_about(DialogId dialog_id);
|
||||
|
||||
bool is_update_about_username_change_received(UserId user_id) const;
|
||||
string get_dialog_search_text(DialogId dialog_id) const;
|
||||
|
||||
void for_each_secret_chat_with_user(UserId user_id, const std::function<void(SecretChatId)> &f);
|
||||
|
||||
string get_user_username(UserId user_id) const;
|
||||
string get_channel_username(ChannelId channel_id) const;
|
||||
string get_secret_chat_username(SecretChatId secret_chat_id) const;
|
||||
|
||||
int32 get_secret_chat_date(SecretChatId secret_chat_id) const;
|
||||
int32 get_secret_chat_ttl(SecretChatId secret_chat_id) const;
|
||||
@ -548,6 +548,7 @@ class ContactsManager final : public Actor {
|
||||
int32 get_channel_date(ChannelId channel_id) const;
|
||||
DialogParticipantStatus get_channel_status(ChannelId channel_id) const;
|
||||
DialogParticipantStatus get_channel_permissions(ChannelId channel_id) const;
|
||||
bool get_channel_is_verified(ChannelId channel_id) const;
|
||||
int32 get_channel_participant_count(ChannelId channel_id) const;
|
||||
bool get_channel_sign_messages(ChannelId channel_id) const;
|
||||
bool get_channel_has_linked_channel(ChannelId channel_id) const;
|
||||
@ -648,7 +649,7 @@ class ContactsManager final : public Actor {
|
||||
string phone_number;
|
||||
int64 access_hash = -1;
|
||||
EmojiStatus emoji_status;
|
||||
int64 last_sent_emoji_status = 0;
|
||||
CustomEmojiId last_sent_emoji_status;
|
||||
|
||||
ProfilePhoto photo;
|
||||
|
||||
@ -1239,6 +1240,9 @@ class ContactsManager final : public Actor {
|
||||
|
||||
SecretChat *add_secret_chat(SecretChatId secret_chat_id);
|
||||
|
||||
string get_user_search_text(UserId user_id) const;
|
||||
static string get_user_search_text(const User *u);
|
||||
|
||||
static DialogParticipantStatus get_chat_status(const Chat *c);
|
||||
DialogParticipantStatus get_chat_permissions(const Chat *c) const;
|
||||
|
||||
@ -1251,9 +1255,12 @@ class ContactsManager final : public Actor {
|
||||
static bool get_channel_join_to_send(const Channel *c);
|
||||
static bool get_channel_join_request(const Channel *c);
|
||||
|
||||
string get_channel_search_text(ChannelId channel_id) const;
|
||||
static string get_channel_search_text(const Channel *c);
|
||||
|
||||
void set_my_id(UserId my_id);
|
||||
|
||||
static bool is_valid_username(const string &username);
|
||||
static bool is_allowed_username(const string &username);
|
||||
|
||||
void on_set_emoji_status(EmojiStatus emoji_status, Promise<Unit> &&promise);
|
||||
|
||||
|
@ -136,7 +136,7 @@ void CountryInfoManager::tear_down() {
|
||||
}
|
||||
|
||||
string CountryInfoManager::get_main_language_code() {
|
||||
return to_lower(td_->language_pack_manager_->get_actor_unsafe()->get_main_language_code());
|
||||
return to_lower(td_->language_pack_manager_.get_actor_unsafe()->get_main_language_code());
|
||||
}
|
||||
|
||||
void CountryInfoManager::get_countries(Promise<td_api::object_ptr<td_api::countries>> &&promise) {
|
||||
|
65
td/telegram/CustomEmojiId.h
Normal file
65
td/telegram/CustomEmojiId.h
Normal file
@ -0,0 +1,65 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/StringBuilder.h"
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
namespace td {
|
||||
|
||||
class CustomEmojiId {
|
||||
int64 id = 0;
|
||||
|
||||
public:
|
||||
CustomEmojiId() = default;
|
||||
|
||||
explicit CustomEmojiId(int64 custom_emoji_id) : id(custom_emoji_id) {
|
||||
}
|
||||
template <class T, typename = std::enable_if_t<std::is_convertible<T, int64>::value>>
|
||||
CustomEmojiId(T custom_emoji_id) = delete;
|
||||
|
||||
bool is_valid() const {
|
||||
return id != 0;
|
||||
}
|
||||
|
||||
int64 get() const {
|
||||
return id;
|
||||
}
|
||||
|
||||
bool operator==(const CustomEmojiId &other) const {
|
||||
return id == other.id;
|
||||
}
|
||||
|
||||
bool operator!=(const CustomEmojiId &other) const {
|
||||
return id != other.id;
|
||||
}
|
||||
|
||||
template <class StorerT>
|
||||
void store(StorerT &storer) const {
|
||||
storer.store_long(id);
|
||||
}
|
||||
|
||||
template <class ParserT>
|
||||
void parse(ParserT &parser) {
|
||||
id = parser.fetch_long();
|
||||
}
|
||||
};
|
||||
|
||||
struct CustomEmojiIdHash {
|
||||
std::size_t operator()(CustomEmojiId custom_emoji_id) const {
|
||||
return std::hash<int64>()(custom_emoji_id.get());
|
||||
}
|
||||
};
|
||||
|
||||
inline StringBuilder &operator<<(StringBuilder &string_builder, CustomEmojiId custom_emoji_id) {
|
||||
return string_builder << "custom emoji " << custom_emoji_id.get();
|
||||
}
|
||||
|
||||
} // namespace td
|
@ -411,7 +411,7 @@ class GetChannelAdminLogQuery final : public Td::ResultHandler {
|
||||
LOG(ERROR) << "Receive invalid " << user_id;
|
||||
continue;
|
||||
}
|
||||
LOG_IF(ERROR, !td_->contacts_manager_->have_user(user_id)) << "Have no info about " << user_id;
|
||||
LOG_IF(ERROR, !td_->contacts_manager_->have_user(user_id)) << "Receive unknown " << user_id;
|
||||
|
||||
DialogId actor_dialog_id;
|
||||
auto action = get_chat_event_action_object(td_, channel_id_, std::move(event->action_), actor_dialog_id);
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "td/utils/misc.h"
|
||||
#include "td/utils/Slice.h"
|
||||
#include "td/utils/SliceBuilder.h"
|
||||
#include "td/utils/Status.h"
|
||||
#include "td/utils/tl_helpers.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
@ -47,12 +47,14 @@ void DownloadManagerCallback::update_file_removed(FileId file_id, DownloadManage
|
||||
void DownloadManagerCallback::start_file(FileId file_id, int8 priority, ActorShared<DownloadManager> download_manager) {
|
||||
send_closure_later(td_->file_manager_actor_, &FileManager::download, file_id,
|
||||
make_download_file_callback(td_, std::move(download_manager)), priority,
|
||||
FileManager::KEEP_DOWNLOAD_OFFSET, FileManager::IGNORE_DOWNLOAD_LIMIT);
|
||||
FileManager::KEEP_DOWNLOAD_OFFSET, FileManager::IGNORE_DOWNLOAD_LIMIT,
|
||||
Promise<td_api::object_ptr<td_api::file>>());
|
||||
}
|
||||
|
||||
void DownloadManagerCallback::pause_file(FileId file_id) {
|
||||
send_closure_later(td_->file_manager_actor_, &FileManager::download, file_id, nullptr, 0,
|
||||
FileManager::KEEP_DOWNLOAD_OFFSET, FileManager::KEEP_DOWNLOAD_LIMIT);
|
||||
FileManager::KEEP_DOWNLOAD_OFFSET, FileManager::KEEP_DOWNLOAD_LIMIT,
|
||||
Promise<td_api::object_ptr<td_api::file>>());
|
||||
}
|
||||
|
||||
void DownloadManagerCallback::delete_file(FileId file_id) {
|
||||
@ -75,7 +77,7 @@ FileView DownloadManagerCallback::get_file_view(FileId file_id) {
|
||||
}
|
||||
|
||||
FileView DownloadManagerCallback::get_sync_file_view(FileId file_id) {
|
||||
td_->file_manager_->check_local_location(file_id);
|
||||
td_->file_manager_->check_local_location(file_id, true);
|
||||
return get_file_view(file_id);
|
||||
}
|
||||
|
||||
|
@ -14,8 +14,11 @@
|
||||
|
||||
#include "td/utils/algorithm.h"
|
||||
#include "td/utils/buffer.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/Status.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace td {
|
||||
|
||||
struct EmojiStatuses {
|
||||
@ -203,7 +206,7 @@ EmojiStatus::EmojiStatus(const td_api::object_ptr<td_api::emojiStatus> &emoji_st
|
||||
return;
|
||||
}
|
||||
|
||||
custom_emoji_id_ = emoji_status->custom_emoji_id_;
|
||||
custom_emoji_id_ = CustomEmojiId(emoji_status->custom_emoji_id_);
|
||||
if (duration != 0) {
|
||||
int32 current_time = G()->unix_time();
|
||||
if (duration >= std::numeric_limits<int32>::max() - current_time) {
|
||||
@ -223,12 +226,12 @@ EmojiStatus::EmojiStatus(tl_object_ptr<telegram_api::EmojiStatus> &&emoji_status
|
||||
break;
|
||||
case telegram_api::emojiStatus::ID: {
|
||||
auto status = static_cast<const telegram_api::emojiStatus *>(emoji_status.get());
|
||||
custom_emoji_id_ = status->document_id_;
|
||||
custom_emoji_id_ = CustomEmojiId(status->document_id_);
|
||||
break;
|
||||
}
|
||||
case telegram_api::emojiStatusUntil::ID: {
|
||||
auto status = static_cast<const telegram_api::emojiStatusUntil *>(emoji_status.get());
|
||||
custom_emoji_id_ = status->document_id_;
|
||||
custom_emoji_id_ = CustomEmojiId(status->document_id_);
|
||||
until_date_ = status->until_;
|
||||
break;
|
||||
}
|
||||
@ -242,24 +245,24 @@ tl_object_ptr<telegram_api::EmojiStatus> EmojiStatus::get_input_emoji_status() c
|
||||
return make_tl_object<telegram_api::emojiStatusEmpty>();
|
||||
}
|
||||
if (until_date_ != 0) {
|
||||
return make_tl_object<telegram_api::emojiStatusUntil>(custom_emoji_id_, until_date_);
|
||||
return make_tl_object<telegram_api::emojiStatusUntil>(custom_emoji_id_.get(), until_date_);
|
||||
}
|
||||
return make_tl_object<telegram_api::emojiStatus>(custom_emoji_id_);
|
||||
return make_tl_object<telegram_api::emojiStatus>(custom_emoji_id_.get());
|
||||
}
|
||||
|
||||
td_api::object_ptr<td_api::emojiStatus> EmojiStatus::get_emoji_status_object() const {
|
||||
if (is_empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
return td_api::make_object<td_api::emojiStatus>(custom_emoji_id_);
|
||||
return td_api::make_object<td_api::emojiStatus>(custom_emoji_id_.get());
|
||||
}
|
||||
|
||||
int64 EmojiStatus::get_effective_custom_emoji_id(bool is_premium, int32 unix_time) const {
|
||||
CustomEmojiId EmojiStatus::get_effective_custom_emoji_id(bool is_premium, int32 unix_time) const {
|
||||
if (!is_premium) {
|
||||
return 0;
|
||||
return CustomEmojiId();
|
||||
}
|
||||
if (until_date_ != 0 && until_date_ <= unix_time) {
|
||||
return 0;
|
||||
return CustomEmojiId();
|
||||
}
|
||||
return custom_emoji_id_;
|
||||
}
|
||||
@ -268,7 +271,7 @@ StringBuilder &operator<<(StringBuilder &string_builder, const EmojiStatus &emoj
|
||||
if (emoji_status.is_empty()) {
|
||||
return string_builder << "DefaultProfileBadge";
|
||||
}
|
||||
string_builder << "CustomEmoji " << emoji_status.custom_emoji_id_;
|
||||
string_builder << emoji_status.custom_emoji_id_;
|
||||
if (emoji_status.until_date_ != 0) {
|
||||
string_builder << " until " << emoji_status.until_date_;
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "td/telegram/CustomEmojiId.h"
|
||||
#include "td/telegram/td_api.h"
|
||||
#include "td/telegram/telegram_api.h"
|
||||
|
||||
@ -19,7 +20,7 @@ namespace td {
|
||||
class Td;
|
||||
|
||||
class EmojiStatus {
|
||||
int64 custom_emoji_id_ = 0;
|
||||
CustomEmojiId custom_emoji_id_;
|
||||
int32 until_date_ = 0;
|
||||
|
||||
friend bool operator==(const EmojiStatus &lhs, const EmojiStatus &rhs);
|
||||
@ -37,13 +38,13 @@ class EmojiStatus {
|
||||
|
||||
td_api::object_ptr<td_api::emojiStatus> get_emoji_status_object() const;
|
||||
|
||||
int64 get_effective_custom_emoji_id(bool is_premium, int32 unix_time) const;
|
||||
CustomEmojiId get_effective_custom_emoji_id(bool is_premium, int32 unix_time) const;
|
||||
|
||||
bool is_empty() const {
|
||||
return custom_emoji_id_ == 0;
|
||||
return !custom_emoji_id_.is_valid();
|
||||
}
|
||||
|
||||
int64 get_custom_emoji_id() const {
|
||||
CustomEmojiId get_custom_emoji_id() const {
|
||||
return custom_emoji_id_;
|
||||
}
|
||||
|
||||
@ -57,7 +58,7 @@ class EmojiStatus {
|
||||
|
||||
template <class StorerT>
|
||||
void store(StorerT &storer) const {
|
||||
bool has_custom_emoji_id = custom_emoji_id_ != 0;
|
||||
bool has_custom_emoji_id = custom_emoji_id_.is_valid();
|
||||
bool has_until_date = until_date_ != 0;
|
||||
BEGIN_STORE_FLAGS();
|
||||
STORE_FLAG(has_custom_emoji_id);
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "td/telegram/files/FileType.h"
|
||||
#include "td/telegram/Game.h"
|
||||
#include "td/telegram/Global.h"
|
||||
#include "td/telegram/InputInvoice.h"
|
||||
#include "td/telegram/InputMessageText.h"
|
||||
#include "td/telegram/Location.h"
|
||||
#include "td/telegram/MessageContent.h"
|
||||
@ -27,7 +28,6 @@
|
||||
#include "td/telegram/MessagesManager.h"
|
||||
#include "td/telegram/misc.h"
|
||||
#include "td/telegram/net/DcId.h"
|
||||
#include "td/telegram/Payments.h"
|
||||
#include "td/telegram/Photo.h"
|
||||
#include "td/telegram/PhotoFormat.h"
|
||||
#include "td/telegram/PhotoSize.h"
|
||||
@ -377,8 +377,9 @@ Result<tl_object_ptr<telegram_api::InputBotInlineMessage>> InlineQueriesManager:
|
||||
return contact.get_input_bot_inline_message_media_contact(std::move(input_reply_markup));
|
||||
}
|
||||
if (constructor_id == td_api::inputMessageInvoice::ID) {
|
||||
TRY_RESULT(input_invoice, process_input_message_invoice(std::move(input_message_content), td_));
|
||||
return get_input_bot_inline_message_media_invoice(input_invoice, std::move(input_reply_markup), td_);
|
||||
TRY_RESULT(input_invoice,
|
||||
InputInvoice::process_input_message_invoice(std::move(input_message_content), td_, DialogId(), false));
|
||||
return input_invoice.get_input_bot_inline_message_media_invoice(std::move(input_reply_markup), td_);
|
||||
}
|
||||
if (constructor_id == td_api::inputMessageLocation::ID) {
|
||||
TRY_RESULT(location, process_input_message_location(std::move(input_message_content)));
|
||||
@ -2028,7 +2029,7 @@ void InlineQueriesManager::on_new_query(int64 query_id, UserId sender_user_id, L
|
||||
LOG(ERROR) << "Receive new inline query from invalid " << sender_user_id;
|
||||
return;
|
||||
}
|
||||
LOG_IF(ERROR, !td_->contacts_manager_->have_user(sender_user_id)) << "Have no info about " << sender_user_id;
|
||||
LOG_IF(ERROR, !td_->contacts_manager_->have_user(sender_user_id)) << "Receive unknown " << sender_user_id;
|
||||
if (!td_->auth_manager_->is_bot()) {
|
||||
LOG(ERROR) << "Receive new inline query";
|
||||
return;
|
||||
@ -2067,7 +2068,7 @@ void InlineQueriesManager::on_chosen_result(
|
||||
LOG(ERROR) << "Receive chosen inline query result from invalid " << user_id;
|
||||
return;
|
||||
}
|
||||
LOG_IF(ERROR, !td_->contacts_manager_->have_user(user_id)) << "Have no info about " << user_id;
|
||||
LOG_IF(ERROR, !td_->contacts_manager_->have_user(user_id)) << "Receive unknown " << user_id;
|
||||
if (!td_->auth_manager_->is_bot()) {
|
||||
LOG(ERROR) << "Receive chosen inline query result";
|
||||
return;
|
||||
|
413
td/telegram/InputInvoice.cpp
Normal file
413
td/telegram/InputInvoice.cpp
Normal file
@ -0,0 +1,413 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#include "td/telegram/InputInvoice.h"
|
||||
|
||||
#include "td/telegram/Dimensions.h"
|
||||
#include "td/telegram/files/FileManager.h"
|
||||
#include "td/telegram/files/FileType.h"
|
||||
#include "td/telegram/misc.h"
|
||||
#include "td/telegram/PhotoSize.h"
|
||||
#include "td/telegram/ServerMessageId.h"
|
||||
#include "td/telegram/Td.h"
|
||||
|
||||
#include "td/utils/algorithm.h"
|
||||
#include "td/utils/buffer.h"
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/HttpUrl.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/MimeType.h"
|
||||
#include "td/utils/PathView.h"
|
||||
|
||||
namespace td {
|
||||
|
||||
bool operator==(const InputInvoice &lhs, const InputInvoice &rhs) {
|
||||
auto are_invoice_equal = [](const InputInvoice::Invoice &lhs, const InputInvoice::Invoice &rhs) {
|
||||
return lhs.is_test_ == rhs.is_test_ && lhs.need_name_ == rhs.need_name_ &&
|
||||
lhs.need_phone_number_ == rhs.need_phone_number_ && lhs.need_email_address_ == rhs.need_email_address_ &&
|
||||
lhs.need_shipping_address_ == rhs.need_shipping_address_ &&
|
||||
lhs.send_phone_number_to_provider_ == rhs.send_phone_number_to_provider_ &&
|
||||
lhs.send_email_address_to_provider_ == rhs.send_email_address_to_provider_ &&
|
||||
lhs.is_flexible_ == rhs.is_flexible_ && lhs.currency_ == rhs.currency_ &&
|
||||
lhs.price_parts_ == rhs.price_parts_ && lhs.max_tip_amount_ == rhs.max_tip_amount_ &&
|
||||
lhs.suggested_tip_amounts_ == rhs.suggested_tip_amounts_ &&
|
||||
lhs.recurring_payment_terms_of_service_url_ == rhs.recurring_payment_terms_of_service_url_;
|
||||
};
|
||||
|
||||
return lhs.title_ == rhs.title_ && lhs.description_ == rhs.description_ && lhs.photo_ == rhs.photo_ &&
|
||||
lhs.start_parameter_ == rhs.start_parameter_ && are_invoice_equal(lhs.invoice_, rhs.invoice_) &&
|
||||
lhs.payload_ == rhs.payload_ && lhs.provider_token_ == rhs.provider_token_ &&
|
||||
lhs.provider_data_ == rhs.provider_data_ && lhs.extended_media_ == rhs.extended_media_ &&
|
||||
lhs.total_amount_ == rhs.total_amount_ && lhs.receipt_message_id_ == rhs.receipt_message_id_;
|
||||
}
|
||||
|
||||
bool operator!=(const InputInvoice &lhs, const InputInvoice &rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
InputInvoice::InputInvoice(tl_object_ptr<telegram_api::messageMediaInvoice> &&message_invoice, Td *td,
|
||||
DialogId owner_dialog_id, FormattedText &&message) {
|
||||
title_ = std::move(message_invoice->title_);
|
||||
description_ = std::move(message_invoice->description_);
|
||||
photo_ = get_web_document_photo(td->file_manager_.get(), std::move(message_invoice->photo_), owner_dialog_id);
|
||||
start_parameter_ = std::move(message_invoice->start_param_);
|
||||
invoice_.currency_ = std::move(message_invoice->currency_);
|
||||
invoice_.is_test_ = message_invoice->test_;
|
||||
invoice_.need_shipping_address_ = message_invoice->shipping_address_requested_;
|
||||
// payload_ = string();
|
||||
// provider_token_ = string();
|
||||
// provider_data_ = string();
|
||||
extended_media_ =
|
||||
MessageExtendedMedia(td, std::move(message_invoice->extended_media_), std::move(message), owner_dialog_id);
|
||||
if (message_invoice->total_amount_ <= 0 || !check_currency_amount(message_invoice->total_amount_)) {
|
||||
LOG(ERROR) << "Receive invalid total amount " << message_invoice->total_amount_;
|
||||
message_invoice->total_amount_ = 0;
|
||||
}
|
||||
total_amount_ = message_invoice->total_amount_;
|
||||
if ((message_invoice->flags_ & telegram_api::messageMediaInvoice::RECEIPT_MSG_ID_MASK) != 0) {
|
||||
receipt_message_id_ = MessageId(ServerMessageId(message_invoice->receipt_msg_id_));
|
||||
if (!receipt_message_id_.is_valid()) {
|
||||
LOG(ERROR) << "Receive as receipt message " << receipt_message_id_ << " in " << owner_dialog_id;
|
||||
receipt_message_id_ = MessageId();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
InputInvoice::InputInvoice(tl_object_ptr<telegram_api::botInlineMessageMediaInvoice> &&message_invoice, Td *td,
|
||||
DialogId owner_dialog_id) {
|
||||
title_ = std::move(message_invoice->title_);
|
||||
description_ = std::move(message_invoice->description_);
|
||||
photo_ = get_web_document_photo(td->file_manager_.get(), std::move(message_invoice->photo_), owner_dialog_id);
|
||||
// start_parameter_ = string();
|
||||
invoice_.currency_ = std::move(message_invoice->currency_);
|
||||
invoice_.is_test_ = message_invoice->test_;
|
||||
invoice_.need_shipping_address_ = message_invoice->shipping_address_requested_;
|
||||
// payload_ = string();
|
||||
// provider_token_ = string();
|
||||
// provider_data_ = string();
|
||||
// extended_media_ = MessageExtendedMedia();
|
||||
if (message_invoice->total_amount_ <= 0 || !check_currency_amount(message_invoice->total_amount_)) {
|
||||
LOG(ERROR) << "Receive invalid total amount " << message_invoice->total_amount_;
|
||||
message_invoice->total_amount_ = 0;
|
||||
}
|
||||
total_amount_ = message_invoice->total_amount_;
|
||||
// receipt_message_id_ = MessageId();
|
||||
}
|
||||
|
||||
Result<InputInvoice> InputInvoice::process_input_message_invoice(
|
||||
td_api::object_ptr<td_api::InputMessageContent> &&input_message_content, Td *td, DialogId owner_dialog_id,
|
||||
bool is_premium) {
|
||||
CHECK(input_message_content != nullptr);
|
||||
CHECK(input_message_content->get_id() == td_api::inputMessageInvoice::ID);
|
||||
auto input_invoice = move_tl_object_as<td_api::inputMessageInvoice>(input_message_content);
|
||||
if (input_invoice->invoice_ == nullptr) {
|
||||
return Status::Error(400, "Invoice must be non-empty");
|
||||
}
|
||||
|
||||
if (!clean_input_string(input_invoice->title_)) {
|
||||
return Status::Error(400, "Invoice title must be encoded in UTF-8");
|
||||
}
|
||||
if (!clean_input_string(input_invoice->description_)) {
|
||||
return Status::Error(400, "Invoice description must be encoded in UTF-8");
|
||||
}
|
||||
if (!clean_input_string(input_invoice->photo_url_)) {
|
||||
return Status::Error(400, "Invoice photo URL must be encoded in UTF-8");
|
||||
}
|
||||
if (!clean_input_string(input_invoice->start_parameter_)) {
|
||||
return Status::Error(400, "Invoice bot start parameter must be encoded in UTF-8");
|
||||
}
|
||||
if (!clean_input_string(input_invoice->provider_token_)) {
|
||||
return Status::Error(400, "Invoice provider token must be encoded in UTF-8");
|
||||
}
|
||||
if (!clean_input_string(input_invoice->provider_data_)) {
|
||||
return Status::Error(400, "Invoice provider data must be encoded in UTF-8");
|
||||
}
|
||||
if (!clean_input_string(input_invoice->invoice_->currency_)) {
|
||||
return Status::Error(400, "Invoice currency must be encoded in UTF-8");
|
||||
}
|
||||
|
||||
InputInvoice result;
|
||||
result.title_ = std::move(input_invoice->title_);
|
||||
result.description_ = std::move(input_invoice->description_);
|
||||
|
||||
auto r_http_url = parse_url(input_invoice->photo_url_);
|
||||
if (r_http_url.is_error()) {
|
||||
if (!input_invoice->photo_url_.empty()) {
|
||||
LOG(INFO) << "Can't register url " << input_invoice->photo_url_;
|
||||
}
|
||||
} else {
|
||||
auto url = r_http_url.ok().get_url();
|
||||
auto r_invoice_file_id = td->file_manager_->from_persistent_id(url, FileType::Temp);
|
||||
if (r_invoice_file_id.is_error()) {
|
||||
LOG(INFO) << "Can't register url " << url;
|
||||
} else {
|
||||
auto invoice_file_id = r_invoice_file_id.move_as_ok();
|
||||
|
||||
PhotoSize s;
|
||||
s.type = 'n';
|
||||
s.dimensions = get_dimensions(input_invoice->photo_width_, input_invoice->photo_height_, nullptr);
|
||||
s.size = input_invoice->photo_size_; // TODO use invoice_file_id size
|
||||
s.file_id = invoice_file_id;
|
||||
|
||||
result.photo_.id = 0;
|
||||
result.photo_.photos.push_back(s);
|
||||
}
|
||||
}
|
||||
result.start_parameter_ = std::move(input_invoice->start_parameter_);
|
||||
|
||||
result.invoice_.currency_ = std::move(input_invoice->invoice_->currency_);
|
||||
result.invoice_.price_parts_.reserve(input_invoice->invoice_->price_parts_.size());
|
||||
int64 total_amount = 0;
|
||||
for (auto &price : input_invoice->invoice_->price_parts_) {
|
||||
if (!clean_input_string(price->label_)) {
|
||||
return Status::Error(400, "Invoice price label must be encoded in UTF-8");
|
||||
}
|
||||
if (!check_currency_amount(price->amount_)) {
|
||||
return Status::Error(400, "Too big amount of the currency specified");
|
||||
}
|
||||
result.invoice_.price_parts_.emplace_back(std::move(price->label_), price->amount_);
|
||||
total_amount += price->amount_;
|
||||
}
|
||||
if (total_amount <= 0) {
|
||||
return Status::Error(400, "Total price must be positive");
|
||||
}
|
||||
if (!check_currency_amount(total_amount)) {
|
||||
return Status::Error(400, "Total price is too big");
|
||||
}
|
||||
result.total_amount_ = total_amount;
|
||||
|
||||
if (input_invoice->invoice_->max_tip_amount_ < 0 ||
|
||||
!check_currency_amount(input_invoice->invoice_->max_tip_amount_)) {
|
||||
return Status::Error(400, "Invalid max_tip_amount of the currency specified");
|
||||
}
|
||||
for (auto tip_amount : input_invoice->invoice_->suggested_tip_amounts_) {
|
||||
if (tip_amount <= 0) {
|
||||
return Status::Error(400, "Suggested tip amount must be positive");
|
||||
}
|
||||
if (tip_amount > input_invoice->invoice_->max_tip_amount_) {
|
||||
return Status::Error(400, "Suggested tip amount can't be bigger than max_tip_amount");
|
||||
}
|
||||
}
|
||||
if (input_invoice->invoice_->suggested_tip_amounts_.size() > 4) {
|
||||
return Status::Error(400, "There can be at most 4 suggested tip amounts");
|
||||
}
|
||||
|
||||
result.invoice_.max_tip_amount_ = input_invoice->invoice_->max_tip_amount_;
|
||||
result.invoice_.suggested_tip_amounts_ = std::move(input_invoice->invoice_->suggested_tip_amounts_);
|
||||
result.invoice_.recurring_payment_terms_of_service_url_ =
|
||||
std::move(input_invoice->invoice_->recurring_payment_terms_of_service_url_);
|
||||
result.invoice_.is_test_ = input_invoice->invoice_->is_test_;
|
||||
result.invoice_.need_name_ = input_invoice->invoice_->need_name_;
|
||||
result.invoice_.need_phone_number_ = input_invoice->invoice_->need_phone_number_;
|
||||
result.invoice_.need_email_address_ = input_invoice->invoice_->need_email_address_;
|
||||
result.invoice_.need_shipping_address_ = input_invoice->invoice_->need_shipping_address_;
|
||||
result.invoice_.send_phone_number_to_provider_ = input_invoice->invoice_->send_phone_number_to_provider_;
|
||||
result.invoice_.send_email_address_to_provider_ = input_invoice->invoice_->send_email_address_to_provider_;
|
||||
result.invoice_.is_flexible_ = input_invoice->invoice_->is_flexible_;
|
||||
if (result.invoice_.send_phone_number_to_provider_) {
|
||||
result.invoice_.need_phone_number_ = true;
|
||||
}
|
||||
if (result.invoice_.send_email_address_to_provider_) {
|
||||
result.invoice_.need_email_address_ = true;
|
||||
}
|
||||
if (result.invoice_.is_flexible_) {
|
||||
result.invoice_.need_shipping_address_ = true;
|
||||
}
|
||||
|
||||
result.payload_ = std::move(input_invoice->payload_);
|
||||
result.provider_token_ = std::move(input_invoice->provider_token_);
|
||||
result.provider_data_ = std::move(input_invoice->provider_data_);
|
||||
|
||||
TRY_RESULT(extended_media, MessageExtendedMedia::get_message_extended_media(
|
||||
td, std::move(input_invoice->extended_media_content_), owner_dialog_id, is_premium));
|
||||
result.extended_media_ = std::move(extended_media);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
tl_object_ptr<td_api::messageInvoice> InputInvoice::get_message_invoice_object(Td *td, bool skip_bot_commands,
|
||||
int32 max_media_timestamp) const {
|
||||
return make_tl_object<td_api::messageInvoice>(
|
||||
title_, get_product_description_object(description_), get_photo_object(td->file_manager_.get(), photo_),
|
||||
invoice_.currency_, total_amount_, start_parameter_, invoice_.is_test_, invoice_.need_shipping_address_,
|
||||
receipt_message_id_.get(),
|
||||
extended_media_.get_message_extended_media_object(td, skip_bot_commands, max_media_timestamp));
|
||||
}
|
||||
|
||||
tl_object_ptr<telegram_api::invoice> InputInvoice::Invoice::get_input_invoice() const {
|
||||
int32 flags = 0;
|
||||
if (is_test_) {
|
||||
flags |= telegram_api::invoice::TEST_MASK;
|
||||
}
|
||||
if (need_name_) {
|
||||
flags |= telegram_api::invoice::NAME_REQUESTED_MASK;
|
||||
}
|
||||
if (need_phone_number_) {
|
||||
flags |= telegram_api::invoice::PHONE_REQUESTED_MASK;
|
||||
}
|
||||
if (need_email_address_) {
|
||||
flags |= telegram_api::invoice::EMAIL_REQUESTED_MASK;
|
||||
}
|
||||
if (need_shipping_address_) {
|
||||
flags |= telegram_api::invoice::SHIPPING_ADDRESS_REQUESTED_MASK;
|
||||
}
|
||||
if (send_phone_number_to_provider_) {
|
||||
flags |= telegram_api::invoice::PHONE_TO_PROVIDER_MASK;
|
||||
}
|
||||
if (send_email_address_to_provider_) {
|
||||
flags |= telegram_api::invoice::EMAIL_TO_PROVIDER_MASK;
|
||||
}
|
||||
if (is_flexible_) {
|
||||
flags |= telegram_api::invoice::FLEXIBLE_MASK;
|
||||
}
|
||||
if (max_tip_amount_ != 0) {
|
||||
flags |= telegram_api::invoice::MAX_TIP_AMOUNT_MASK;
|
||||
}
|
||||
if (!recurring_payment_terms_of_service_url_.empty()) {
|
||||
flags |= telegram_api::invoice::RECURRING_TERMS_URL_MASK;
|
||||
}
|
||||
|
||||
auto prices = transform(price_parts_, [](const LabeledPricePart &price) {
|
||||
return telegram_api::make_object<telegram_api::labeledPrice>(price.label, price.amount);
|
||||
});
|
||||
return make_tl_object<telegram_api::invoice>(
|
||||
flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/,
|
||||
false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, currency_, std::move(prices),
|
||||
max_tip_amount_, vector<int64>(suggested_tip_amounts_), recurring_payment_terms_of_service_url_);
|
||||
}
|
||||
|
||||
static tl_object_ptr<telegram_api::inputWebDocument> get_input_web_document(const FileManager *file_manager,
|
||||
const Photo &photo) {
|
||||
if (photo.is_empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CHECK(photo.photos.size() == 1);
|
||||
const PhotoSize &size = photo.photos[0];
|
||||
CHECK(size.file_id.is_valid());
|
||||
|
||||
vector<tl_object_ptr<telegram_api::DocumentAttribute>> attributes;
|
||||
if (size.dimensions.width != 0 && size.dimensions.height != 0) {
|
||||
attributes.push_back(
|
||||
make_tl_object<telegram_api::documentAttributeImageSize>(size.dimensions.width, size.dimensions.height));
|
||||
}
|
||||
|
||||
auto file_view = file_manager->get_file_view(size.file_id);
|
||||
CHECK(file_view.has_url());
|
||||
|
||||
auto file_name = get_url_file_name(file_view.url());
|
||||
return make_tl_object<telegram_api::inputWebDocument>(
|
||||
file_view.url(), size.size, MimeType::from_extension(PathView(file_name).extension(), "image/jpeg"),
|
||||
std::move(attributes));
|
||||
}
|
||||
|
||||
tl_object_ptr<telegram_api::inputMediaInvoice> InputInvoice::get_input_media_invoice(
|
||||
Td *td, tl_object_ptr<telegram_api::InputFile> input_file,
|
||||
tl_object_ptr<telegram_api::InputFile> input_thumbnail) const {
|
||||
int32 flags = 0;
|
||||
if (!start_parameter_.empty()) {
|
||||
flags |= telegram_api::inputMediaInvoice::START_PARAM_MASK;
|
||||
}
|
||||
auto input_web_document = get_input_web_document(td->file_manager_.get(), photo_);
|
||||
if (input_web_document != nullptr) {
|
||||
flags |= telegram_api::inputMediaInvoice::PHOTO_MASK;
|
||||
}
|
||||
telegram_api::object_ptr<telegram_api::InputMedia> extended_media;
|
||||
if (!extended_media_.is_empty()) {
|
||||
flags |= telegram_api::inputMediaInvoice::EXTENDED_MEDIA_MASK;
|
||||
extended_media = extended_media_.get_input_media(td, std::move(input_file), std::move(input_thumbnail));
|
||||
if (extended_media == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return make_tl_object<telegram_api::inputMediaInvoice>(
|
||||
flags, title_, description_, std::move(input_web_document), invoice_.get_input_invoice(), BufferSlice(payload_),
|
||||
provider_token_,
|
||||
telegram_api::make_object<telegram_api::dataJSON>(provider_data_.empty() ? "null" : provider_data_),
|
||||
start_parameter_, std::move(extended_media));
|
||||
}
|
||||
|
||||
tl_object_ptr<telegram_api::inputBotInlineMessageMediaInvoice> InputInvoice::get_input_bot_inline_message_media_invoice(
|
||||
tl_object_ptr<telegram_api::ReplyMarkup> &&reply_markup, Td *td) const {
|
||||
int32 flags = 0;
|
||||
if (reply_markup != nullptr) {
|
||||
flags |= telegram_api::inputBotInlineMessageMediaInvoice::REPLY_MARKUP_MASK;
|
||||
}
|
||||
auto input_web_document = get_input_web_document(td->file_manager_.get(), photo_);
|
||||
if (input_web_document != nullptr) {
|
||||
flags |= telegram_api::inputBotInlineMessageMediaInvoice::PHOTO_MASK;
|
||||
}
|
||||
return make_tl_object<telegram_api::inputBotInlineMessageMediaInvoice>(
|
||||
flags, title_, description_, std::move(input_web_document), invoice_.get_input_invoice(), BufferSlice(payload_),
|
||||
provider_token_,
|
||||
telegram_api::make_object<telegram_api::dataJSON>(provider_data_.empty() ? "null" : provider_data_),
|
||||
std::move(reply_markup));
|
||||
}
|
||||
|
||||
vector<FileId> InputInvoice::get_file_ids(const Td *td) const {
|
||||
auto file_ids = photo_get_file_ids(photo_);
|
||||
extended_media_.append_file_ids(td, file_ids);
|
||||
return file_ids;
|
||||
}
|
||||
|
||||
void InputInvoice::delete_thumbnail(Td *td) {
|
||||
extended_media_.delete_thumbnail(td);
|
||||
}
|
||||
|
||||
bool InputInvoice::need_reget() const {
|
||||
return extended_media_.need_reget();
|
||||
}
|
||||
|
||||
bool InputInvoice::has_media_timestamp() const {
|
||||
return extended_media_.has_media_timestamp();
|
||||
}
|
||||
|
||||
bool InputInvoice::is_equal_but_different(const InputInvoice &other) const {
|
||||
return extended_media_.is_equal_but_different(other.extended_media_);
|
||||
}
|
||||
|
||||
const FormattedText *InputInvoice::get_caption() const {
|
||||
return extended_media_.get_caption();
|
||||
}
|
||||
|
||||
int32 InputInvoice::get_duration(const Td *td) const {
|
||||
return extended_media_.get_duration(td);
|
||||
}
|
||||
|
||||
FileId InputInvoice::get_upload_file_id() const {
|
||||
return extended_media_.get_upload_file_id();
|
||||
}
|
||||
|
||||
FileId InputInvoice::get_any_file_id() const {
|
||||
return extended_media_.get_any_file_id();
|
||||
}
|
||||
|
||||
FileId InputInvoice::get_thumbnail_file_id(const Td *td) const {
|
||||
return extended_media_.get_thumbnail_file_id(td);
|
||||
}
|
||||
|
||||
void InputInvoice::update_from(const InputInvoice &old_input_invoice) {
|
||||
extended_media_.update_from(old_input_invoice.extended_media_);
|
||||
}
|
||||
|
||||
bool InputInvoice::update_extended_media(telegram_api::object_ptr<telegram_api::MessageExtendedMedia> extended_media,
|
||||
DialogId owner_dialog_id, Td *td) {
|
||||
return extended_media_.update_to(td, std::move(extended_media), owner_dialog_id);
|
||||
}
|
||||
|
||||
bool InputInvoice::need_poll_extended_media() const {
|
||||
return extended_media_.need_poll();
|
||||
}
|
||||
|
||||
tl_object_ptr<td_api::formattedText> get_product_description_object(const string &description) {
|
||||
FormattedText result;
|
||||
result.text = description;
|
||||
result.entities = find_entities(result.text, true, true);
|
||||
return get_formatted_text_object(result, true, 0);
|
||||
}
|
||||
|
||||
} // namespace td
|
133
td/telegram/InputInvoice.h
Normal file
133
td/telegram/InputInvoice.h
Normal file
@ -0,0 +1,133 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "td/telegram/DialogId.h"
|
||||
#include "td/telegram/files/FileId.h"
|
||||
#include "td/telegram/LabeledPricePart.h"
|
||||
#include "td/telegram/MessageExtendedMedia.h"
|
||||
#include "td/telegram/MessageId.h"
|
||||
#include "td/telegram/Photo.h"
|
||||
#include "td/telegram/td_api.h"
|
||||
#include "td/telegram/telegram_api.h"
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/Status.h"
|
||||
#include "td/utils/StringBuilder.h"
|
||||
|
||||
namespace td {
|
||||
|
||||
class Td;
|
||||
|
||||
class InputInvoice {
|
||||
struct Invoice {
|
||||
string currency_;
|
||||
vector<LabeledPricePart> price_parts_;
|
||||
int64 max_tip_amount_ = 0;
|
||||
vector<int64> suggested_tip_amounts_;
|
||||
string recurring_payment_terms_of_service_url_;
|
||||
bool is_test_ = false;
|
||||
bool need_name_ = false;
|
||||
bool need_phone_number_ = false;
|
||||
bool need_email_address_ = false;
|
||||
bool need_shipping_address_ = false;
|
||||
bool send_phone_number_to_provider_ = false;
|
||||
bool send_email_address_to_provider_ = false;
|
||||
bool is_flexible_ = false;
|
||||
|
||||
Invoice() = default;
|
||||
Invoice(string &¤cy, bool is_test, bool need_shipping_address)
|
||||
: currency_(std::move(currency)), is_test_(is_test), need_shipping_address_(need_shipping_address) {
|
||||
}
|
||||
|
||||
tl_object_ptr<telegram_api::invoice> get_input_invoice() const;
|
||||
|
||||
template <class StorerT>
|
||||
void store(StorerT &storer) const;
|
||||
|
||||
template <class ParserT>
|
||||
void parse(ParserT &parser);
|
||||
};
|
||||
|
||||
string title_;
|
||||
string description_;
|
||||
Photo photo_;
|
||||
string start_parameter_;
|
||||
Invoice invoice_;
|
||||
string payload_;
|
||||
string provider_token_;
|
||||
string provider_data_;
|
||||
MessageExtendedMedia extended_media_;
|
||||
|
||||
int64 total_amount_ = 0;
|
||||
MessageId receipt_message_id_;
|
||||
|
||||
friend bool operator==(const InputInvoice &lhs, const InputInvoice &rhs);
|
||||
|
||||
public:
|
||||
InputInvoice() = default;
|
||||
|
||||
InputInvoice(tl_object_ptr<telegram_api::messageMediaInvoice> &&message_invoice, Td *td, DialogId owner_dialog_id,
|
||||
FormattedText &&message);
|
||||
|
||||
InputInvoice(tl_object_ptr<telegram_api::botInlineMessageMediaInvoice> &&message_invoice, Td *td,
|
||||
DialogId owner_dialog_id);
|
||||
|
||||
static Result<InputInvoice> process_input_message_invoice(
|
||||
td_api::object_ptr<td_api::InputMessageContent> &&input_message_content, Td *td, DialogId owner_dialog_id,
|
||||
bool is_premium);
|
||||
|
||||
tl_object_ptr<td_api::messageInvoice> get_message_invoice_object(Td *td, bool skip_bot_commands,
|
||||
int32 max_media_timestamp) const;
|
||||
|
||||
tl_object_ptr<telegram_api::inputMediaInvoice> get_input_media_invoice(
|
||||
Td *td, tl_object_ptr<telegram_api::InputFile> input_file,
|
||||
tl_object_ptr<telegram_api::InputFile> input_thumbnail) const;
|
||||
|
||||
tl_object_ptr<telegram_api::inputBotInlineMessageMediaInvoice> get_input_bot_inline_message_media_invoice(
|
||||
tl_object_ptr<telegram_api::ReplyMarkup> &&reply_markup, Td *td) const;
|
||||
|
||||
vector<FileId> get_file_ids(const Td *td) const;
|
||||
|
||||
void delete_thumbnail(Td *td);
|
||||
|
||||
bool need_reget() const;
|
||||
|
||||
bool has_media_timestamp() const;
|
||||
|
||||
bool is_equal_but_different(const InputInvoice &other) const;
|
||||
|
||||
const FormattedText *get_caption() const;
|
||||
|
||||
int32 get_duration(const Td *td) const;
|
||||
|
||||
FileId get_upload_file_id() const;
|
||||
|
||||
FileId get_any_file_id() const;
|
||||
|
||||
FileId get_thumbnail_file_id(const Td *td) const;
|
||||
|
||||
void update_from(const InputInvoice &old_input_invoice);
|
||||
|
||||
bool update_extended_media(telegram_api::object_ptr<telegram_api::MessageExtendedMedia> extended_media,
|
||||
DialogId owner_dialog_id, Td *td);
|
||||
|
||||
bool need_poll_extended_media() const;
|
||||
|
||||
template <class StorerT>
|
||||
void store(StorerT &storer) const;
|
||||
|
||||
template <class ParserT>
|
||||
void parse(ParserT &parser);
|
||||
};
|
||||
|
||||
bool operator==(const InputInvoice &lhs, const InputInvoice &rhs);
|
||||
bool operator!=(const InputInvoice &lhs, const InputInvoice &rhs);
|
||||
|
||||
tl_object_ptr<td_api::formattedText> get_product_description_object(const string &description);
|
||||
|
||||
} // namespace td
|
195
td/telegram/InputInvoice.hpp
Normal file
195
td/telegram/InputInvoice.hpp
Normal file
@ -0,0 +1,195 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "td/telegram/InputInvoice.h"
|
||||
|
||||
#include "td/telegram/MessageExtendedMedia.hpp"
|
||||
#include "td/telegram/Photo.hpp"
|
||||
#include "td/telegram/Version.h"
|
||||
|
||||
#include "td/utils/tl_helpers.h"
|
||||
|
||||
namespace td {
|
||||
|
||||
template <class StorerT>
|
||||
void InputInvoice::Invoice::store(StorerT &storer) const {
|
||||
using td::store;
|
||||
bool has_tip = max_tip_amount_ != 0;
|
||||
bool is_recurring = !recurring_payment_terms_of_service_url_.empty();
|
||||
BEGIN_STORE_FLAGS();
|
||||
STORE_FLAG(is_test_);
|
||||
STORE_FLAG(need_name_);
|
||||
STORE_FLAG(need_phone_number_);
|
||||
STORE_FLAG(need_email_address_);
|
||||
STORE_FLAG(need_shipping_address_);
|
||||
STORE_FLAG(is_flexible_);
|
||||
STORE_FLAG(send_phone_number_to_provider_);
|
||||
STORE_FLAG(send_email_address_to_provider_);
|
||||
STORE_FLAG(has_tip);
|
||||
STORE_FLAG(is_recurring);
|
||||
END_STORE_FLAGS();
|
||||
store(currency_, storer);
|
||||
store(price_parts_, storer);
|
||||
if (has_tip) {
|
||||
store(max_tip_amount_, storer);
|
||||
store(suggested_tip_amounts_, storer);
|
||||
}
|
||||
if (is_recurring) {
|
||||
store(recurring_payment_terms_of_service_url_, storer);
|
||||
}
|
||||
}
|
||||
|
||||
template <class ParserT>
|
||||
void InputInvoice::Invoice::parse(ParserT &parser) {
|
||||
using td::parse;
|
||||
bool has_tip;
|
||||
bool is_recurring;
|
||||
BEGIN_PARSE_FLAGS();
|
||||
PARSE_FLAG(is_test_);
|
||||
PARSE_FLAG(need_name_);
|
||||
PARSE_FLAG(need_phone_number_);
|
||||
PARSE_FLAG(need_email_address_);
|
||||
PARSE_FLAG(need_shipping_address_);
|
||||
PARSE_FLAG(is_flexible_);
|
||||
PARSE_FLAG(send_phone_number_to_provider_);
|
||||
PARSE_FLAG(send_email_address_to_provider_);
|
||||
PARSE_FLAG(has_tip);
|
||||
PARSE_FLAG(is_recurring);
|
||||
END_PARSE_FLAGS();
|
||||
parse(currency_, parser);
|
||||
parse(price_parts_, parser);
|
||||
if (has_tip) {
|
||||
parse(max_tip_amount_, parser);
|
||||
parse(suggested_tip_amounts_, parser);
|
||||
}
|
||||
if (is_recurring) {
|
||||
parse(recurring_payment_terms_of_service_url_, parser);
|
||||
}
|
||||
}
|
||||
|
||||
template <class StorerT>
|
||||
void InputInvoice::store(StorerT &storer) const {
|
||||
using td::store;
|
||||
bool has_description = !description_.empty();
|
||||
bool has_photo = !photo_.is_empty();
|
||||
bool has_start_parameter = !start_parameter_.empty();
|
||||
bool has_payload = !payload_.empty();
|
||||
bool has_provider_token = !provider_token_.empty();
|
||||
bool has_provider_data = !provider_data_.empty();
|
||||
bool has_total_amount = total_amount_ != 0;
|
||||
bool has_receipt_message_id = receipt_message_id_.is_valid();
|
||||
bool has_extended_media = !extended_media_.is_empty();
|
||||
BEGIN_STORE_FLAGS();
|
||||
STORE_FLAG(has_description);
|
||||
STORE_FLAG(has_photo);
|
||||
STORE_FLAG(has_start_parameter);
|
||||
STORE_FLAG(has_payload);
|
||||
STORE_FLAG(has_provider_token);
|
||||
STORE_FLAG(has_provider_data);
|
||||
STORE_FLAG(has_total_amount);
|
||||
STORE_FLAG(has_receipt_message_id);
|
||||
STORE_FLAG(has_extended_media);
|
||||
END_STORE_FLAGS();
|
||||
store(title_, storer);
|
||||
if (has_description) {
|
||||
store(description_, storer);
|
||||
}
|
||||
if (has_photo) {
|
||||
store(photo_, storer);
|
||||
}
|
||||
if (has_start_parameter) {
|
||||
store(start_parameter_, storer);
|
||||
}
|
||||
store(invoice_, storer);
|
||||
if (has_payload) {
|
||||
store(payload_, storer);
|
||||
}
|
||||
if (has_provider_token) {
|
||||
store(provider_token_, storer);
|
||||
}
|
||||
if (has_provider_data) {
|
||||
store(provider_data_, storer);
|
||||
}
|
||||
if (has_total_amount) {
|
||||
store(total_amount_, storer);
|
||||
}
|
||||
if (has_receipt_message_id) {
|
||||
store(receipt_message_id_, storer);
|
||||
}
|
||||
if (has_extended_media) {
|
||||
store(extended_media_, storer);
|
||||
}
|
||||
}
|
||||
|
||||
template <class ParserT>
|
||||
void InputInvoice::parse(ParserT &parser) {
|
||||
using td::parse;
|
||||
bool has_description;
|
||||
bool has_photo;
|
||||
bool has_start_parameter;
|
||||
bool has_payload;
|
||||
bool has_provider_token;
|
||||
bool has_provider_data;
|
||||
bool has_total_amount;
|
||||
bool has_receipt_message_id;
|
||||
bool has_extended_media;
|
||||
if (parser.version() >= static_cast<int32>(Version::AddInputInvoiceFlags)) {
|
||||
BEGIN_PARSE_FLAGS();
|
||||
PARSE_FLAG(has_description);
|
||||
PARSE_FLAG(has_photo);
|
||||
PARSE_FLAG(has_start_parameter);
|
||||
PARSE_FLAG(has_payload);
|
||||
PARSE_FLAG(has_provider_token);
|
||||
PARSE_FLAG(has_provider_data);
|
||||
PARSE_FLAG(has_total_amount);
|
||||
PARSE_FLAG(has_receipt_message_id);
|
||||
PARSE_FLAG(has_extended_media);
|
||||
END_PARSE_FLAGS();
|
||||
} else {
|
||||
has_description = true;
|
||||
has_photo = true;
|
||||
has_start_parameter = true;
|
||||
has_payload = true;
|
||||
has_provider_token = true;
|
||||
has_provider_data = parser.version() >= static_cast<int32>(Version::AddMessageInvoiceProviderData);
|
||||
has_total_amount = true;
|
||||
has_receipt_message_id = true;
|
||||
has_extended_media = false;
|
||||
}
|
||||
parse(title_, parser);
|
||||
if (has_description) {
|
||||
parse(description_, parser);
|
||||
}
|
||||
if (has_photo) {
|
||||
parse(photo_, parser);
|
||||
}
|
||||
if (has_start_parameter) {
|
||||
parse(start_parameter_, parser);
|
||||
}
|
||||
parse(invoice_, parser);
|
||||
if (has_payload) {
|
||||
parse(payload_, parser);
|
||||
}
|
||||
if (has_provider_token) {
|
||||
parse(provider_token_, parser);
|
||||
}
|
||||
if (has_provider_data) {
|
||||
parse(provider_data_, parser);
|
||||
}
|
||||
if (has_total_amount) {
|
||||
parse(total_amount_, parser);
|
||||
}
|
||||
if (has_receipt_message_id) {
|
||||
parse(receipt_message_id_, parser);
|
||||
}
|
||||
if (has_extended_media) {
|
||||
parse(extended_media_, parser);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace td
|
47
td/telegram/LabeledPricePart.h
Normal file
47
td/telegram/LabeledPricePart.h
Normal file
@ -0,0 +1,47 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/StringBuilder.h"
|
||||
|
||||
namespace td {
|
||||
|
||||
struct LabeledPricePart {
|
||||
string label;
|
||||
int64 amount = 0;
|
||||
|
||||
LabeledPricePart() = default;
|
||||
LabeledPricePart(string &&label, int64 amount) : label(std::move(label)), amount(amount) {
|
||||
}
|
||||
|
||||
template <class StorerT>
|
||||
void store(StorerT &storer) const {
|
||||
storer.store_string(label);
|
||||
storer.store_binary(amount);
|
||||
}
|
||||
|
||||
template <class ParserT>
|
||||
void parse(ParserT &parser) {
|
||||
label = parser.template fetch_string<string>();
|
||||
amount = parser.fetch_long();
|
||||
}
|
||||
};
|
||||
|
||||
inline bool operator==(const LabeledPricePart &lhs, const LabeledPricePart &rhs) {
|
||||
return lhs.label == rhs.label && lhs.amount == rhs.amount;
|
||||
}
|
||||
|
||||
inline bool operator!=(const LabeledPricePart &lhs, const LabeledPricePart &rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
inline StringBuilder &operator<<(StringBuilder &string_builder, const LabeledPricePart &labeled_price_part) {
|
||||
return string_builder << '[' << labeled_price_part.label << ": " << labeled_price_part.amount << ']';
|
||||
}
|
||||
|
||||
} // namespace td
|
@ -45,30 +45,6 @@ static bool is_valid_start_parameter(Slice start_parameter) {
|
||||
return start_parameter.size() <= 64 && is_base64url_characters(start_parameter);
|
||||
}
|
||||
|
||||
static bool is_valid_username(Slice username) {
|
||||
if (username.empty() || username.size() > 32) {
|
||||
return false;
|
||||
}
|
||||
if (!is_alpha(username[0])) {
|
||||
return false;
|
||||
}
|
||||
for (auto c : username) {
|
||||
if (!is_alpha(c) && !is_digit(c) && c != '_') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (username.back() == '_') {
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 1; i < username.size(); i++) {
|
||||
if (username[i - 1] == '_' && username[i] == '_') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool is_valid_phone_number(Slice phone_number) {
|
||||
if (phone_number.empty() || phone_number.size() > 32) {
|
||||
return false;
|
||||
@ -339,13 +315,15 @@ class LinkManager::InternalLinkGame final : public InternalLink {
|
||||
|
||||
class LinkManager::InternalLinkInstantView final : public InternalLink {
|
||||
string url_;
|
||||
string fallback_url_;
|
||||
|
||||
td_api::object_ptr<td_api::InternalLinkType> get_internal_link_type_object() const final {
|
||||
return td_api::make_object<td_api::internalLinkTypeInstantView>(url_);
|
||||
return td_api::make_object<td_api::internalLinkTypeInstantView>(url_, fallback_url_);
|
||||
}
|
||||
|
||||
public:
|
||||
explicit InternalLinkInstantView(string url) : url_(std::move(url)) {
|
||||
InternalLinkInstantView(string url, string fallback_url)
|
||||
: url_(std::move(url)), fallback_url_(std::move(fallback_url)) {
|
||||
}
|
||||
};
|
||||
|
||||
@ -975,7 +953,7 @@ unique_ptr<LinkManager::InternalLink> LinkManager::parse_internal_link(Slice lin
|
||||
case LinkType::TMe:
|
||||
return parse_t_me_link_query(info.query_, is_trusted);
|
||||
case LinkType::Telegraph:
|
||||
return td::make_unique<InternalLinkInstantView>(PSTRING() << "https://telegra.ph" << info.query_);
|
||||
return td::make_unique<InternalLinkInstantView>(PSTRING() << "https://telegra.ph" << info.query_, link.str());
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return nullptr;
|
||||
@ -1364,8 +1342,8 @@ unique_ptr<LinkManager::InternalLink> LinkManager::parse_t_me_link_query(Slice q
|
||||
} else if (path[0] == "iv") {
|
||||
if (path.size() == 1 && has_arg("url")) {
|
||||
// /iv?url=<url>&rhash=<rhash>
|
||||
return td::make_unique<InternalLinkInstantView>(PSTRING()
|
||||
<< "https://t.me/iv" << copy_arg("url") << copy_arg("rhash"));
|
||||
return td::make_unique<InternalLinkInstantView>(
|
||||
PSTRING() << "https://t.me/iv" << copy_arg("url") << copy_arg("rhash"), get_arg("url"));
|
||||
}
|
||||
} else if (is_valid_username(path[0])) {
|
||||
if (path.size() >= 2 && to_integer<int64>(path[1]) > 0) {
|
||||
@ -1615,6 +1593,37 @@ string LinkManager::get_dialog_invite_link(Slice hash, bool is_internal) {
|
||||
}
|
||||
}
|
||||
|
||||
string LinkManager::get_instant_view_link_url(Slice link) {
|
||||
auto link_info = get_link_info(link);
|
||||
if (link_info.type_ != LinkType::TMe) {
|
||||
return string();
|
||||
}
|
||||
const auto url_query = parse_url_query(link_info.query_);
|
||||
const auto &path = url_query.path_;
|
||||
if (path.size() == 1 && path[0] == "iv") {
|
||||
return url_query.get_arg("url").str();
|
||||
}
|
||||
return string();
|
||||
}
|
||||
|
||||
string LinkManager::get_instant_view_link_rhash(Slice link) {
|
||||
auto link_info = get_link_info(link);
|
||||
if (link_info.type_ != LinkType::TMe) {
|
||||
return string();
|
||||
}
|
||||
const auto url_query = parse_url_query(link_info.query_);
|
||||
const auto &path = url_query.path_;
|
||||
if (path.size() == 1 && path[0] == "iv" && !url_query.get_arg("url").empty()) {
|
||||
return url_query.get_arg("rhash").str();
|
||||
}
|
||||
return string();
|
||||
}
|
||||
|
||||
string LinkManager::get_instant_view_link(Slice url, Slice rhash) {
|
||||
return PSTRING() << G()->get_option_string("t_me_url", "https://t.me/") << "iv?url=" << url_encode(url)
|
||||
<< "&rhash=" << url_encode(rhash);
|
||||
}
|
||||
|
||||
UserId LinkManager::get_link_user_id(Slice url) {
|
||||
string lower_cased_url = to_lower(url);
|
||||
url = lower_cased_url;
|
||||
@ -1657,7 +1666,7 @@ UserId LinkManager::get_link_user_id(Slice url) {
|
||||
return UserId();
|
||||
}
|
||||
|
||||
Result<int64> LinkManager::get_link_custom_emoji_document_id(Slice url) {
|
||||
Result<CustomEmojiId> LinkManager::get_link_custom_emoji_id(Slice url) {
|
||||
string lower_cased_url = to_lower(url);
|
||||
url = lower_cased_url;
|
||||
|
||||
@ -1693,7 +1702,7 @@ Result<int64> LinkManager::get_link_custom_emoji_document_id(Slice url) {
|
||||
if (r_document_id.is_error() || r_document_id.ok() == 0) {
|
||||
return Status::Error(400, "Invalid custom emoji identifier specified");
|
||||
}
|
||||
return r_document_id.ok();
|
||||
return CustomEmojiId(r_document_id.ok());
|
||||
}
|
||||
}
|
||||
return Status::Error(400, "Custom emoji URL must have an emoji identifier");
|
||||
|
@ -6,6 +6,7 @@
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "td/telegram/CustomEmojiId.h"
|
||||
#include "td/telegram/FullMessageId.h"
|
||||
#include "td/telegram/MessageLinkInfo.h"
|
||||
#include "td/telegram/td_api.h"
|
||||
@ -78,9 +79,15 @@ class LinkManager final : public Actor {
|
||||
|
||||
static string get_dialog_invite_link(Slice hash, bool is_internal);
|
||||
|
||||
static string get_instant_view_link_url(Slice link);
|
||||
|
||||
static string get_instant_view_link_rhash(Slice link);
|
||||
|
||||
static string get_instant_view_link(Slice url, Slice rhash);
|
||||
|
||||
static UserId get_link_user_id(Slice url);
|
||||
|
||||
static Result<int64> get_link_custom_emoji_document_id(Slice url);
|
||||
static Result<CustomEmojiId> get_link_custom_emoji_id(Slice url);
|
||||
|
||||
static Result<MessageLinkInfo> get_message_link_info(Slice url);
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "td/telegram/ChatId.h"
|
||||
#include "td/telegram/Contact.h"
|
||||
#include "td/telegram/ContactsManager.h"
|
||||
#include "td/telegram/CustomEmojiId.h"
|
||||
#include "td/telegram/Dependencies.h"
|
||||
#include "td/telegram/DialogAction.h"
|
||||
#include "td/telegram/DialogParticipant.h"
|
||||
@ -34,6 +35,8 @@
|
||||
#include "td/telegram/GroupCallManager.h"
|
||||
#include "td/telegram/HashtagHints.h"
|
||||
#include "td/telegram/InputGroupCallId.h"
|
||||
#include "td/telegram/InputInvoice.h"
|
||||
#include "td/telegram/InputInvoice.hpp"
|
||||
#include "td/telegram/InputMessageText.h"
|
||||
#include "td/telegram/Location.h"
|
||||
#include "td/telegram/MessageEntity.h"
|
||||
@ -44,8 +47,8 @@
|
||||
#include "td/telegram/misc.h"
|
||||
#include "td/telegram/net/DcId.h"
|
||||
#include "td/telegram/OptionManager.h"
|
||||
#include "td/telegram/Payments.h"
|
||||
#include "td/telegram/Payments.hpp"
|
||||
#include "td/telegram/OrderInfo.h"
|
||||
#include "td/telegram/OrderInfo.hpp"
|
||||
#include "td/telegram/Photo.h"
|
||||
#include "td/telegram/Photo.hpp"
|
||||
#include "td/telegram/PhotoFormat.h"
|
||||
@ -1226,14 +1229,7 @@ static void parse(unique_ptr<MessageContent> &content, ParserT &parser) {
|
||||
case MessageContentType::Photo: {
|
||||
auto m = make_unique<MessagePhoto>();
|
||||
parse(m->photo, parser);
|
||||
for (auto &photo_size : m->photo.photos) {
|
||||
if (!photo_size.file_id.is_valid()) {
|
||||
is_bad = true;
|
||||
}
|
||||
}
|
||||
if (m->photo.is_empty()) {
|
||||
is_bad = true;
|
||||
}
|
||||
is_bad |= m->photo.is_bad();
|
||||
parse_caption(m->caption, parser);
|
||||
content = std::move(m);
|
||||
break;
|
||||
@ -1642,8 +1638,7 @@ InlineMessageContent create_inline_message_content(Td *td, FileId file_id,
|
||||
case telegram_api::botInlineMessageMediaInvoice::ID: {
|
||||
auto inline_message = move_tl_object_as<telegram_api::botInlineMessageMediaInvoice>(bot_inline_message);
|
||||
reply_markup = std::move(inline_message->reply_markup_);
|
||||
result.message_content =
|
||||
make_unique<MessageInvoice>(get_input_invoice(std::move(inline_message), td, DialogId()));
|
||||
result.message_content = make_unique<MessageInvoice>(InputInvoice(std::move(inline_message), td, DialogId()));
|
||||
break;
|
||||
}
|
||||
case telegram_api::botInlineMessageMediaGeo::ID: {
|
||||
@ -1960,7 +1955,8 @@ static Result<InputMessageContent> create_input_message_content(
|
||||
return Status::Error(400, "Invoices can be sent only by bots");
|
||||
}
|
||||
|
||||
TRY_RESULT(input_invoice, process_input_message_invoice(std::move(input_message_content), td));
|
||||
TRY_RESULT(input_invoice, InputInvoice::process_input_message_invoice(std::move(input_message_content), td,
|
||||
dialog_id, is_premium));
|
||||
content = make_unique<MessageInvoice>(std::move(input_invoice));
|
||||
break;
|
||||
}
|
||||
@ -2080,14 +2076,14 @@ Result<InputMessageContent> get_input_message_content(
|
||||
auto input_message = static_cast<td_api::inputMessageDocument *>(input_message_content.get());
|
||||
auto file_type = input_message->disable_content_type_detection_ ? FileType::DocumentAsFile : FileType::Document;
|
||||
r_file_id =
|
||||
td->file_manager_->get_input_file_id(file_type, input_message->document_, dialog_id, false, is_secret);
|
||||
td->file_manager_->get_input_file_id(file_type, input_message->document_, dialog_id, false, is_secret, true);
|
||||
input_thumbnail = std::move(input_message->thumbnail_);
|
||||
break;
|
||||
}
|
||||
case td_api::inputMessagePhoto::ID: {
|
||||
auto input_message = static_cast<td_api::inputMessagePhoto *>(input_message_content.get());
|
||||
r_file_id = td->file_manager_->get_input_file_id(FileType::Photo, input_message->photo_, dialog_id, false,
|
||||
is_secret, false, false, true);
|
||||
r_file_id =
|
||||
td->file_manager_->get_input_file_id(FileType::Photo, input_message->photo_, dialog_id, false, is_secret);
|
||||
input_thumbnail = std::move(input_message->thumbnail_);
|
||||
if (!input_message->added_sticker_file_ids_.empty()) {
|
||||
sticker_file_ids = td->stickers_manager_->get_attached_sticker_file_ids(input_message->added_sticker_file_ids_);
|
||||
@ -2363,7 +2359,7 @@ static tl_object_ptr<telegram_api::InputMedia> get_input_media_impl(
|
||||
}
|
||||
case MessageContentType::Invoice: {
|
||||
const auto *m = static_cast<const MessageInvoice *>(content);
|
||||
return get_input_media_invoice(m->input_invoice, td);
|
||||
return m->input_invoice.get_input_media_invoice(td, std::move(input_file), std::move(input_thumbnail));
|
||||
}
|
||||
case MessageContentType::LiveLocation: {
|
||||
const auto *m = static_cast<const MessageLiveLocation *>(content);
|
||||
@ -2545,6 +2541,10 @@ void delete_message_content_thumbnail(MessageContent *content, Td *td) {
|
||||
auto *m = static_cast<MessageDocument *>(content);
|
||||
return td->documents_manager_->delete_document_thumbnail(m->file_id);
|
||||
}
|
||||
case MessageContentType::Invoice: {
|
||||
auto *m = static_cast<MessageInvoice *>(content);
|
||||
return m->input_invoice.delete_thumbnail(td);
|
||||
}
|
||||
case MessageContentType::Photo: {
|
||||
auto *m = static_cast<MessagePhoto *>(content);
|
||||
return photo_delete_thumbnail(m->photo);
|
||||
@ -2564,7 +2564,6 @@ void delete_message_content_thumbnail(MessageContent *content, Td *td) {
|
||||
case MessageContentType::Contact:
|
||||
case MessageContentType::Dice:
|
||||
case MessageContentType::Game:
|
||||
case MessageContentType::Invoice:
|
||||
case MessageContentType::LiveLocation:
|
||||
case MessageContentType::Location:
|
||||
case MessageContentType::Venue:
|
||||
@ -3036,6 +3035,10 @@ bool can_message_content_have_media_timestamp(const MessageContent *content) {
|
||||
case MessageContentType::VideoNote:
|
||||
case MessageContentType::VoiceNote:
|
||||
return true;
|
||||
case MessageContentType::Invoice: {
|
||||
const auto *m = static_cast<const MessageInvoice *>(content);
|
||||
return m->input_invoice.has_media_timestamp();
|
||||
}
|
||||
default:
|
||||
return has_message_content_web_page(content);
|
||||
}
|
||||
@ -3073,7 +3076,10 @@ static void merge_location_access_hash(const Location &first, const Location &se
|
||||
|
||||
static bool need_message_text_changed_warning(const MessageText *old_content, const MessageText *new_content) {
|
||||
if (new_content->text.text == "Unsupported characters" ||
|
||||
new_content->text.text == "This channel is blocked because it was used to spread pornographic content.") {
|
||||
new_content->text.text == "This channel is blocked because it was used to spread pornographic content." ||
|
||||
begins_with(new_content->text.text,
|
||||
"This group has been temporarily suspended to give its moderators time to clean up after users who "
|
||||
"posted illegal pornographic content.")) {
|
||||
// message contained unsupported characters or is restricted, text is replaced
|
||||
return false;
|
||||
}
|
||||
@ -3219,9 +3225,12 @@ void merge_message_contents(Td *td, const MessageContent *old_content, MessageCo
|
||||
}
|
||||
case MessageContentType::Invoice: {
|
||||
const auto *old_ = static_cast<const MessageInvoice *>(old_content);
|
||||
const auto *new_ = static_cast<const MessageInvoice *>(new_content);
|
||||
auto *new_ = static_cast<MessageInvoice *>(new_content);
|
||||
new_->input_invoice.update_from(old_->input_invoice);
|
||||
if (old_->input_invoice != new_->input_invoice) {
|
||||
need_update = true;
|
||||
} else if (old_->input_invoice.is_equal_but_different(new_->input_invoice)) {
|
||||
is_content_changed = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -3668,6 +3677,7 @@ bool merge_message_content_file_id(Td *td, MessageContent *message_content, File
|
||||
return false;
|
||||
}
|
||||
|
||||
// secret chats only
|
||||
LOG(INFO) << "Merge message content of a message with file " << new_file_id;
|
||||
MessageContentType content_type = message_content->get_type();
|
||||
switch (content_type) {
|
||||
@ -3806,14 +3816,14 @@ static bool can_be_animated_emoji(const FormattedText &text) {
|
||||
}
|
||||
if (text.entities.size() == 1 && text.entities[0].type == MessageEntity::Type::CustomEmoji &&
|
||||
text.entities[0].offset == 0 && static_cast<size_t>(text.entities[0].length) == utf8_utf16_length(text.text) &&
|
||||
text.entities[0].document_id != 0) {
|
||||
text.entities[0].custom_emoji_id.is_valid()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int64 get_custom_emoji_id(const FormattedText &text) {
|
||||
return text.entities.empty() ? 0 : text.entities[0].document_id;
|
||||
static CustomEmojiId get_custom_emoji_id(const FormattedText &text) {
|
||||
return text.entities.empty() ? CustomEmojiId() : text.entities[0].custom_emoji_id;
|
||||
}
|
||||
|
||||
void register_message_content(Td *td, const MessageContent *content, FullMessageId full_message_id,
|
||||
@ -3993,8 +4003,8 @@ static auto secret_to_telegram(secret_api::documentAttributeSticker &sticker) {
|
||||
nullptr);
|
||||
}
|
||||
|
||||
// documentAttributeVideo duration:int w:int h:int = DocumentAttribute;
|
||||
static auto secret_to_telegram(secret_api::documentAttributeVideo &video) {
|
||||
// documentAttributeVideo23 duration:int w:int h:int = DocumentAttribute;
|
||||
static auto secret_to_telegram(secret_api::documentAttributeVideo23 &video) {
|
||||
return make_tl_object<telegram_api::documentAttributeVideo>(0, false /*ignored*/, false /*ignored*/, video.duration_,
|
||||
video.w_, video.h_);
|
||||
}
|
||||
@ -4007,10 +4017,10 @@ static auto secret_to_telegram(secret_api::documentAttributeFilename &filename)
|
||||
return make_tl_object<telegram_api::documentAttributeFilename>(filename.file_name_);
|
||||
}
|
||||
|
||||
// documentAttributeVideo66 flags:# round_message:flags.0?true duration:int w:int h:int = DocumentAttribute;
|
||||
static auto secret_to_telegram(secret_api::documentAttributeVideo66 &video) {
|
||||
// documentAttributeVideo flags:# round_message:flags.0?true duration:int w:int h:int = DocumentAttribute;
|
||||
static auto secret_to_telegram(secret_api::documentAttributeVideo &video) {
|
||||
return make_tl_object<telegram_api::documentAttributeVideo>(
|
||||
(video.flags_ & secret_api::documentAttributeVideo66::ROUND_MESSAGE_MASK) != 0
|
||||
(video.flags_ & secret_api::documentAttributeVideo::ROUND_MESSAGE_MASK) != 0
|
||||
? telegram_api::documentAttributeVideo::ROUND_MESSAGE_MASK
|
||||
: 0,
|
||||
video.round_message_, false, video.duration_, video.w_, video.h_);
|
||||
@ -4191,7 +4201,7 @@ unique_ptr<MessageContent> get_secret_message_content(
|
||||
auto media = move_tl_object_as<secret_api::decryptedMessageMediaVideo>(media_ptr);
|
||||
vector<tl_object_ptr<secret_api::DocumentAttribute>> attributes;
|
||||
attributes.emplace_back(
|
||||
make_tl_object<secret_api::documentAttributeVideo>(media->duration_, media->w_, media->h_));
|
||||
make_tl_object<secret_api::documentAttributeVideo>(0, false, media->duration_, media->w_, media->h_));
|
||||
media_ptr = make_tl_object<secret_api::decryptedMessageMediaDocument>(
|
||||
std::move(media->thumb_), media->thumb_w_, media->thumb_h_, media->mime_type_, media->size_,
|
||||
std::move(media->key_), std::move(media->iv_), std::move(attributes), string());
|
||||
@ -4467,15 +4477,16 @@ unique_ptr<MessageContent> get_message_content(Td *td, FormattedText message,
|
||||
case telegram_api::messageMediaGame::ID: {
|
||||
auto media = move_tl_object_as<telegram_api::messageMediaGame>(media_ptr);
|
||||
|
||||
auto m = make_unique<MessageGame>(Game(td, via_bot_user_id, std::move(media->game_), message, owner_dialog_id));
|
||||
auto m = make_unique<MessageGame>(
|
||||
Game(td, via_bot_user_id, std::move(media->game_), std::move(message), owner_dialog_id));
|
||||
if (m->game.is_empty()) {
|
||||
break;
|
||||
}
|
||||
return std::move(m);
|
||||
}
|
||||
case telegram_api::messageMediaInvoice::ID:
|
||||
return td::make_unique<MessageInvoice>(
|
||||
get_input_invoice(move_tl_object_as<telegram_api::messageMediaInvoice>(media_ptr), td, owner_dialog_id));
|
||||
return td::make_unique<MessageInvoice>(InputInvoice(
|
||||
move_tl_object_as<telegram_api::messageMediaInvoice>(media_ptr), td, owner_dialog_id, std::move(message)));
|
||||
case telegram_api::messageMediaWebPage::ID: {
|
||||
auto media = move_tl_object_as<telegram_api::messageMediaWebPage>(media_ptr);
|
||||
if (disable_web_page_preview != nullptr) {
|
||||
@ -5095,7 +5106,7 @@ tl_object_ptr<td_api::MessageContent> get_message_content_object(const MessageCo
|
||||
}
|
||||
case MessageContentType::Invoice: {
|
||||
const auto *m = static_cast<const MessageInvoice *>(content);
|
||||
return get_message_invoice_object(m->input_invoice, td);
|
||||
return m->input_invoice.get_message_invoice_object(td, skip_bot_commands, max_media_timestamp);
|
||||
}
|
||||
case MessageContentType::LiveLocation: {
|
||||
const auto *m = static_cast<const MessageLiveLocation *>(content);
|
||||
@ -5361,6 +5372,8 @@ const FormattedText *get_message_content_caption(const MessageContent *content)
|
||||
return &static_cast<const MessageAudio *>(content)->caption;
|
||||
case MessageContentType::Document:
|
||||
return &static_cast<const MessageDocument *>(content)->caption;
|
||||
case MessageContentType::Invoice:
|
||||
return static_cast<const MessageInvoice *>(content)->input_invoice.get_caption();
|
||||
case MessageContentType::Photo:
|
||||
return &static_cast<const MessagePhoto *>(content)->caption;
|
||||
case MessageContentType::Video:
|
||||
@ -5383,6 +5396,8 @@ int32 get_message_content_duration(const MessageContent *content, const Td *td)
|
||||
auto audio_file_id = static_cast<const MessageAudio *>(content)->file_id;
|
||||
return td->audios_manager_->get_audio_duration(audio_file_id);
|
||||
}
|
||||
case MessageContentType::Invoice:
|
||||
return static_cast<const MessageInvoice *>(content)->input_invoice.get_duration(td);
|
||||
case MessageContentType::Video: {
|
||||
auto video_file_id = static_cast<const MessageVideo *>(content)->file_id;
|
||||
return td->videos_manager_->get_video_duration(video_file_id);
|
||||
@ -5407,6 +5422,8 @@ int32 get_message_content_media_duration(const MessageContent *content, const Td
|
||||
auto audio_file_id = static_cast<const MessageAudio *>(content)->file_id;
|
||||
return td->audios_manager_->get_audio_duration(audio_file_id);
|
||||
}
|
||||
case MessageContentType::Invoice:
|
||||
return static_cast<const MessageInvoice *>(content)->input_invoice.get_duration(td);
|
||||
case MessageContentType::Text: {
|
||||
auto web_page_id = static_cast<const MessageText *>(content)->web_page_id;
|
||||
return td->web_pages_manager_->get_web_page_media_duration(web_page_id);
|
||||
@ -5428,6 +5445,16 @@ int32 get_message_content_media_duration(const MessageContent *content, const Td
|
||||
}
|
||||
}
|
||||
|
||||
const Photo *get_message_content_photo(const MessageContent *content) {
|
||||
switch (content->get_type()) {
|
||||
case MessageContentType::Photo:
|
||||
return &static_cast<const MessagePhoto *>(content)->photo;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FileId get_message_content_upload_file_id(const MessageContent *content) {
|
||||
switch (content->get_type()) {
|
||||
case MessageContentType::Animation:
|
||||
@ -5436,13 +5463,10 @@ FileId get_message_content_upload_file_id(const MessageContent *content) {
|
||||
return static_cast<const MessageAudio *>(content)->file_id;
|
||||
case MessageContentType::Document:
|
||||
return static_cast<const MessageDocument *>(content)->file_id;
|
||||
case MessageContentType::Invoice:
|
||||
return static_cast<const MessageInvoice *>(content)->input_invoice.get_upload_file_id();
|
||||
case MessageContentType::Photo:
|
||||
for (auto &size : static_cast<const MessagePhoto *>(content)->photo.photos) {
|
||||
if (size.type == 'i') {
|
||||
return size.file_id;
|
||||
}
|
||||
}
|
||||
break;
|
||||
return get_photo_upload_file_id(static_cast<const MessagePhoto *>(content)->photo);
|
||||
case MessageContentType::Sticker:
|
||||
return static_cast<const MessageSticker *>(content)->file_id;
|
||||
case MessageContentType::Video:
|
||||
@ -5459,10 +5483,11 @@ FileId get_message_content_upload_file_id(const MessageContent *content) {
|
||||
|
||||
FileId get_message_content_any_file_id(const MessageContent *content) {
|
||||
FileId result = get_message_content_upload_file_id(content);
|
||||
if (!result.is_valid() && content->get_type() == MessageContentType::Photo) {
|
||||
const auto &sizes = static_cast<const MessagePhoto *>(content)->photo.photos;
|
||||
if (!sizes.empty()) {
|
||||
result = sizes.back().file_id;
|
||||
if (!result.is_valid()) {
|
||||
if (content->get_type() == MessageContentType::Photo) {
|
||||
result = get_photo_any_file_id(static_cast<const MessagePhoto *>(content)->photo);
|
||||
} else if (content->get_type() == MessageContentType::Invoice) {
|
||||
result = static_cast<const MessageInvoice *>(content)->input_invoice.get_any_file_id();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@ -5499,34 +5524,31 @@ void update_message_content_file_id_remote(MessageContent *content, FileId file_
|
||||
|
||||
FileId get_message_content_thumbnail_file_id(const MessageContent *content, const Td *td) {
|
||||
if (!G()->get_option_boolean("disable_minithumbnails")) {
|
||||
switch (content->get_type()) {
|
||||
case MessageContentType::Animation:
|
||||
return td->animations_manager_->get_animation_thumbnail_file_id(
|
||||
static_cast<const MessageAnimation *>(content)->file_id);
|
||||
case MessageContentType::Audio:
|
||||
return td->audios_manager_->get_audio_thumbnail_file_id(static_cast<const MessageAudio *>(content)->file_id);
|
||||
case MessageContentType::Document:
|
||||
return td->documents_manager_->get_document_thumbnail_file_id(
|
||||
static_cast<const MessageDocument *>(content)->file_id);
|
||||
case MessageContentType::Photo:
|
||||
for (auto &size : static_cast<const MessagePhoto *>(content)->photo.photos) {
|
||||
if (size.type == 't') {
|
||||
return size.file_id;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MessageContentType::Sticker:
|
||||
return td->stickers_manager_->get_sticker_thumbnail_file_id(
|
||||
static_cast<const MessageSticker *>(content)->file_id);
|
||||
case MessageContentType::Video:
|
||||
return td->videos_manager_->get_video_thumbnail_file_id(static_cast<const MessageVideo *>(content)->file_id);
|
||||
case MessageContentType::VideoNote:
|
||||
return td->video_notes_manager_->get_video_note_thumbnail_file_id(
|
||||
static_cast<const MessageVideoNote *>(content)->file_id);
|
||||
case MessageContentType::VoiceNote:
|
||||
return FileId();
|
||||
default:
|
||||
break;
|
||||
switch (content->get_type()) {
|
||||
case MessageContentType::Animation:
|
||||
return td->animations_manager_->get_animation_thumbnail_file_id(
|
||||
static_cast<const MessageAnimation *>(content)->file_id);
|
||||
case MessageContentType::Audio:
|
||||
return td->audios_manager_->get_audio_thumbnail_file_id(static_cast<const MessageAudio *>(content)->file_id);
|
||||
case MessageContentType::Document:
|
||||
return td->documents_manager_->get_document_thumbnail_file_id(
|
||||
static_cast<const MessageDocument *>(content)->file_id);
|
||||
case MessageContentType::Invoice:
|
||||
return static_cast<const MessageInvoice *>(content)->input_invoice.get_thumbnail_file_id(td);
|
||||
case MessageContentType::Photo:
|
||||
return get_photo_thumbnail_file_id(static_cast<const MessagePhoto *>(content)->photo);
|
||||
case MessageContentType::Sticker:
|
||||
return td->stickers_manager_->get_sticker_thumbnail_file_id(
|
||||
static_cast<const MessageSticker *>(content)->file_id);
|
||||
case MessageContentType::Video:
|
||||
return td->videos_manager_->get_video_thumbnail_file_id(static_cast<const MessageVideo *>(content)->file_id);
|
||||
case MessageContentType::VideoNote:
|
||||
return td->video_notes_manager_->get_video_note_thumbnail_file_id(
|
||||
static_cast<const MessageVideoNote *>(content)->file_id);
|
||||
case MessageContentType::VoiceNote:
|
||||
return FileId();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return FileId();
|
||||
@ -5569,7 +5591,7 @@ vector<FileId> get_message_content_file_ids(const MessageContent *content, const
|
||||
case MessageContentType::Game:
|
||||
return static_cast<const MessageGame *>(content)->game.get_file_ids(td);
|
||||
case MessageContentType::Invoice:
|
||||
return get_input_invoice_file_ids(static_cast<const MessageInvoice *>(content)->input_invoice);
|
||||
return static_cast<const MessageInvoice *>(content)->input_invoice.get_file_ids(td);
|
||||
case MessageContentType::ChatChangePhoto:
|
||||
return photo_get_file_ids(static_cast<const MessageChatChangePhoto *>(content)->photo);
|
||||
case MessageContentType::PassportDataReceived: {
|
||||
@ -5604,22 +5626,26 @@ string get_message_content_search_text(const Td *td, const MessageContent *conte
|
||||
if (!text->web_page_id.is_valid()) {
|
||||
return text->text.text;
|
||||
}
|
||||
return PSTRING() << text->text.text << " " << td->web_pages_manager_->get_web_page_search_text(text->web_page_id);
|
||||
return PSTRING() << text->text.text << ' ' << td->web_pages_manager_->get_web_page_search_text(text->web_page_id);
|
||||
}
|
||||
case MessageContentType::Animation: {
|
||||
const auto *animation = static_cast<const MessageAnimation *>(content);
|
||||
return PSTRING() << td->animations_manager_->get_animation_search_text(animation->file_id) << " "
|
||||
return PSTRING() << td->animations_manager_->get_animation_search_text(animation->file_id) << ' '
|
||||
<< animation->caption.text;
|
||||
}
|
||||
case MessageContentType::Audio: {
|
||||
const auto *audio = static_cast<const MessageAudio *>(content);
|
||||
return PSTRING() << td->audios_manager_->get_audio_search_text(audio->file_id) << " " << audio->caption.text;
|
||||
return PSTRING() << td->audios_manager_->get_audio_search_text(audio->file_id) << ' ' << audio->caption.text;
|
||||
}
|
||||
case MessageContentType::Document: {
|
||||
const auto *document = static_cast<const MessageDocument *>(content);
|
||||
return PSTRING() << td->documents_manager_->get_document_search_text(document->file_id) << " "
|
||||
return PSTRING() << td->documents_manager_->get_document_search_text(document->file_id) << ' '
|
||||
<< document->caption.text;
|
||||
}
|
||||
case MessageContentType::Invoice: {
|
||||
const auto *invoice = static_cast<const MessageInvoice *>(content);
|
||||
return invoice->input_invoice.get_caption()->text;
|
||||
}
|
||||
case MessageContentType::Photo: {
|
||||
const auto *photo = static_cast<const MessagePhoto *>(content);
|
||||
return photo->caption.text;
|
||||
@ -5634,7 +5660,6 @@ string get_message_content_search_text(const Td *td, const MessageContent *conte
|
||||
}
|
||||
case MessageContentType::Contact:
|
||||
case MessageContentType::Game:
|
||||
case MessageContentType::Invoice:
|
||||
case MessageContentType::LiveLocation:
|
||||
case MessageContentType::Location:
|
||||
case MessageContentType::Sticker:
|
||||
@ -5681,6 +5706,23 @@ string get_message_content_search_text(const Td *td, const MessageContent *conte
|
||||
}
|
||||
}
|
||||
|
||||
bool update_message_content_extended_media(MessageContent *content,
|
||||
telegram_api::object_ptr<telegram_api::MessageExtendedMedia> extended_media,
|
||||
DialogId owner_dialog_id, Td *td) {
|
||||
CHECK(content != nullptr);
|
||||
CHECK(content->get_type() == MessageContentType::Invoice);
|
||||
return static_cast<MessageInvoice *>(content)->input_invoice.update_extended_media(std::move(extended_media),
|
||||
owner_dialog_id, td);
|
||||
}
|
||||
|
||||
bool need_poll_message_content_extended_media(const MessageContent *content) {
|
||||
CHECK(content != nullptr);
|
||||
if (content->get_type() != MessageContentType::Invoice) {
|
||||
return false;
|
||||
}
|
||||
return static_cast<const MessageInvoice *>(content)->input_invoice.need_poll_extended_media();
|
||||
}
|
||||
|
||||
void get_message_content_animated_emoji_click_sticker(const MessageContent *content, FullMessageId full_message_id,
|
||||
Td *td, Promise<td_api::object_ptr<td_api::sticker>> &&promise) {
|
||||
if (content->get_type() != MessageContentType::Text) {
|
||||
@ -5718,6 +5760,10 @@ bool need_reget_message_content(const MessageContent *content) {
|
||||
const auto *m = static_cast<const MessageUnsupported *>(content);
|
||||
return m->version != MessageUnsupported::CURRENT_VERSION;
|
||||
}
|
||||
case MessageContentType::Invoice: {
|
||||
const auto *m = static_cast<const MessageInvoice *>(content);
|
||||
return m->input_invoice.need_reget();
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@ -5957,10 +6003,10 @@ void move_message_content_sticker_set_to_top(Td *td, const MessageContent *conte
|
||||
if (text == nullptr) {
|
||||
return;
|
||||
}
|
||||
vector<int64> custom_emoji_ids;
|
||||
vector<CustomEmojiId> custom_emoji_ids;
|
||||
for (auto &entity : text->entities) {
|
||||
if (entity.type == MessageEntity::Type::CustomEmoji) {
|
||||
custom_emoji_ids.push_back(entity.document_id);
|
||||
custom_emoji_ids.push_back(entity.custom_emoji_id);
|
||||
}
|
||||
}
|
||||
if (!custom_emoji_ids.empty()) {
|
||||
|
@ -216,6 +216,8 @@ int32 get_message_content_duration(const MessageContent *content, const Td *td);
|
||||
|
||||
int32 get_message_content_media_duration(const MessageContent *content, const Td *td);
|
||||
|
||||
const Photo *get_message_content_photo(const MessageContent *content);
|
||||
|
||||
FileId get_message_content_upload_file_id(const MessageContent *content);
|
||||
|
||||
FileId get_message_content_any_file_id(const MessageContent *content);
|
||||
@ -228,6 +230,12 @@ vector<FileId> get_message_content_file_ids(const MessageContent *content, const
|
||||
|
||||
string get_message_content_search_text(const Td *td, const MessageContent *content);
|
||||
|
||||
bool update_message_content_extended_media(MessageContent *content,
|
||||
telegram_api::object_ptr<telegram_api::MessageExtendedMedia> extended_media,
|
||||
DialogId owner_dialog_id, Td *td);
|
||||
|
||||
bool need_poll_message_content_extended_media(const MessageContent *content);
|
||||
|
||||
void get_message_content_animated_emoji_click_sticker(const MessageContent *content, FullMessageId full_message_id,
|
||||
Td *td, Promise<td_api::object_ptr<td_api::sticker>> &&promise);
|
||||
|
||||
|
@ -364,6 +364,7 @@ uint64 get_message_content_chain_id(MessageContentType content_type) {
|
||||
case MessageContentType::Animation:
|
||||
case MessageContentType::Audio:
|
||||
case MessageContentType::Document:
|
||||
case MessageContentType::Invoice:
|
||||
case MessageContentType::Photo:
|
||||
case MessageContentType::Sticker:
|
||||
case MessageContentType::Video:
|
||||
|
@ -122,8 +122,8 @@ StringBuilder &operator<<(StringBuilder &string_builder, const MessageEntity &me
|
||||
if (message_entity.user_id.is_valid()) {
|
||||
string_builder << ", " << message_entity.user_id;
|
||||
}
|
||||
if (message_entity.document_id != 0) {
|
||||
string_builder << ", emoji = " << message_entity.document_id;
|
||||
if (message_entity.custom_emoji_id.is_valid()) {
|
||||
string_builder << ", " << message_entity.custom_emoji_id;
|
||||
}
|
||||
string_builder << ']';
|
||||
return string_builder;
|
||||
@ -173,7 +173,7 @@ tl_object_ptr<td_api::TextEntityType> MessageEntity::get_text_entity_type_object
|
||||
case MessageEntity::Type::Spoiler:
|
||||
return make_tl_object<td_api::textEntityTypeSpoiler>();
|
||||
case MessageEntity::Type::CustomEmoji:
|
||||
return make_tl_object<td_api::textEntityTypeCustomEmoji>(document_id);
|
||||
return make_tl_object<td_api::textEntityTypeCustomEmoji>(custom_emoji_id.get());
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return nullptr;
|
||||
@ -1421,7 +1421,7 @@ void remove_empty_entities(vector<MessageEntity> &entities) {
|
||||
case MessageEntity::Type::MentionName:
|
||||
return !entity.user_id.is_valid();
|
||||
case MessageEntity::Type::CustomEmoji:
|
||||
return entity.document_id == 0;
|
||||
return !entity.custom_emoji_id.is_valid();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@ -1793,7 +1793,7 @@ string get_first_url(const FormattedText &text) {
|
||||
if (entity.length <= 4) {
|
||||
continue;
|
||||
}
|
||||
Slice url = utf8_utf16_substr(text.text, entity.offset, entity.length);
|
||||
auto url = utf8_utf16_substr(text.text, entity.offset, entity.length);
|
||||
string scheme = to_lower(url.substr(0, 4));
|
||||
if (scheme == "ton:" || begins_with(scheme, "tg:") || scheme == "ftp:" || is_plain_domain(url)) {
|
||||
continue;
|
||||
@ -2126,7 +2126,7 @@ static Result<vector<MessageEntity>> do_parse_markdown_v2(CSlice text, string &r
|
||||
auto type = nested_entities.back().type;
|
||||
auto argument = std::move(nested_entities.back().argument);
|
||||
UserId user_id;
|
||||
int64 document_id = 0;
|
||||
CustomEmojiId custom_emoji_id;
|
||||
bool skip_entity = utf16_offset == nested_entities.back().entity_offset;
|
||||
switch (type) {
|
||||
case MessageEntity::Type::Bold:
|
||||
@ -2192,7 +2192,7 @@ static Result<vector<MessageEntity>> do_parse_markdown_v2(CSlice text, string &r
|
||||
return Status::Error(400, PSLICE()
|
||||
<< "Can't find end of a custom emoji URL at byte offset " << url_begin_pos);
|
||||
}
|
||||
TRY_RESULT_ASSIGN(document_id, LinkManager::get_link_custom_emoji_document_id(url));
|
||||
TRY_RESULT_ASSIGN(custom_emoji_id, LinkManager::get_link_custom_emoji_id(url));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -2205,8 +2205,8 @@ static Result<vector<MessageEntity>> do_parse_markdown_v2(CSlice text, string &r
|
||||
auto entity_length = utf16_offset - entity_offset;
|
||||
if (user_id.is_valid()) {
|
||||
entities.emplace_back(entity_offset, entity_length, user_id);
|
||||
} else if (document_id != 0) {
|
||||
entities.emplace_back(type, entity_offset, entity_length, document_id);
|
||||
} else if (custom_emoji_id.is_valid()) {
|
||||
entities.emplace_back(type, entity_offset, entity_length, custom_emoji_id);
|
||||
} else {
|
||||
entities.emplace_back(type, entity_offset, entity_length, std::move(argument));
|
||||
}
|
||||
@ -3170,7 +3170,8 @@ static Result<vector<MessageEntity>> do_parse_html(CSlice text, string &result)
|
||||
if (r_document_id.is_error() || r_document_id.ok() == 0) {
|
||||
return Status::Error(400, "Invalid custom emoji identifier specified");
|
||||
}
|
||||
entities.emplace_back(MessageEntity::Type::CustomEmoji, entity_offset, entity_length, r_document_id.ok());
|
||||
entities.emplace_back(MessageEntity::Type::CustomEmoji, entity_offset, entity_length,
|
||||
CustomEmojiId(r_document_id.ok()));
|
||||
} else if (tag_name == "a") {
|
||||
auto url = std::move(nested_entities.back().argument);
|
||||
if (url.empty()) {
|
||||
@ -3308,8 +3309,8 @@ vector<tl_object_ptr<secret_api::MessageEntity>> get_input_secret_message_entiti
|
||||
break;
|
||||
case MessageEntity::Type::CustomEmoji:
|
||||
if (layer >= static_cast<int32>(SecretChatLayer::SpoilerAndCustomEmojiEntities)) {
|
||||
result.push_back(
|
||||
make_tl_object<secret_api::messageEntityCustomEmoji>(entity.offset, entity.length, entity.document_id));
|
||||
result.push_back(make_tl_object<secret_api::messageEntityCustomEmoji>(entity.offset, entity.length,
|
||||
entity.custom_emoji_id.get()));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -3425,7 +3426,11 @@ Result<vector<MessageEntity>> get_message_entities(const ContactsManager *contac
|
||||
break;
|
||||
case td_api::textEntityTypeCustomEmoji::ID: {
|
||||
auto entity = static_cast<td_api::textEntityTypeCustomEmoji *>(input_entity->type_.get());
|
||||
entities.emplace_back(MessageEntity::Type::CustomEmoji, offset, length, entity->custom_emoji_id_);
|
||||
CustomEmojiId custom_emoji_id(entity->custom_emoji_id_);
|
||||
if (!custom_emoji_id.is_valid()) {
|
||||
return Status::Error(400, "Invalid custom emoji identifier specified");
|
||||
}
|
||||
entities.emplace_back(MessageEntity::Type::CustomEmoji, offset, length, custom_emoji_id);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -3564,7 +3569,8 @@ vector<MessageEntity> get_message_entities(const ContactsManager *contacts_manag
|
||||
}
|
||||
case telegram_api::messageEntityCustomEmoji::ID: {
|
||||
auto entity = static_cast<const telegram_api::messageEntityCustomEmoji *>(server_entity.get());
|
||||
entities.emplace_back(MessageEntity::Type::CustomEmoji, entity->offset_, entity->length_, entity->document_id_);
|
||||
entities.emplace_back(MessageEntity::Type::CustomEmoji, entity->offset_, entity->length_,
|
||||
CustomEmojiId(entity->document_id_));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -3580,7 +3586,7 @@ vector<MessageEntity> get_message_entities(Td *td, vector<tl_object_ptr<secret_a
|
||||
constexpr size_t MAX_CUSTOM_EMOJI_ENTITIES = 100;
|
||||
vector<MessageEntity> entities;
|
||||
entities.reserve(secret_entities.size());
|
||||
vector<int64> document_ids;
|
||||
vector<CustomEmojiId> custom_emoji_ids;
|
||||
for (auto &secret_entity : secret_entities) {
|
||||
switch (secret_entity->get_id()) {
|
||||
case secret_api::messageEntityUnknown::ID:
|
||||
@ -3683,11 +3689,11 @@ vector<MessageEntity> get_message_entities(Td *td, vector<tl_object_ptr<secret_a
|
||||
}
|
||||
case secret_api::messageEntityCustomEmoji::ID: {
|
||||
auto entity = static_cast<const secret_api::messageEntityCustomEmoji *>(secret_entity.get());
|
||||
if (is_premium || !td->stickers_manager_->is_premium_custom_emoji(entity->document_id_, false)) {
|
||||
if (document_ids.size() < MAX_CUSTOM_EMOJI_ENTITIES) {
|
||||
entities.emplace_back(MessageEntity::Type::CustomEmoji, entity->offset_, entity->length_,
|
||||
entity->document_id_);
|
||||
document_ids.push_back(entity->document_id_);
|
||||
CustomEmojiId custom_emoji_id(entity->document_id_);
|
||||
if (is_premium || !td->stickers_manager_->is_premium_custom_emoji(custom_emoji_id, false)) {
|
||||
if (custom_emoji_ids.size() < MAX_CUSTOM_EMOJI_ENTITIES) {
|
||||
entities.emplace_back(MessageEntity::Type::CustomEmoji, entity->offset_, entity->length_, custom_emoji_id);
|
||||
custom_emoji_ids.push_back(custom_emoji_id);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -3701,10 +3707,10 @@ vector<MessageEntity> get_message_entities(Td *td, vector<tl_object_ptr<secret_a
|
||||
}
|
||||
}
|
||||
|
||||
if (!document_ids.empty() && !is_premium) {
|
||||
if (!custom_emoji_ids.empty() && !is_premium) {
|
||||
// preload custom emoji to check that they aren't premium
|
||||
td->stickers_manager_->get_custom_emoji_stickers(
|
||||
std::move(document_ids), true,
|
||||
std::move(custom_emoji_ids), true,
|
||||
PromiseCreator::lambda(
|
||||
[promise = load_data_multipromise.get_promise()](td_api::object_ptr<td_api::stickers> result) mutable {
|
||||
promise.set_value(Unit());
|
||||
@ -4425,8 +4431,8 @@ vector<tl_object_ptr<telegram_api::MessageEntity>> get_input_message_entities(co
|
||||
break;
|
||||
}
|
||||
case MessageEntity::Type::CustomEmoji:
|
||||
result.push_back(
|
||||
make_tl_object<telegram_api::messageEntityCustomEmoji>(entity.offset, entity.length, entity.document_id));
|
||||
result.push_back(make_tl_object<telegram_api::messageEntityCustomEmoji>(entity.offset, entity.length,
|
||||
entity.custom_emoji_id.get()));
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
@ -4470,7 +4476,7 @@ vector<tl_object_ptr<telegram_api::MessageEntity>> get_input_message_entities(co
|
||||
void remove_premium_custom_emoji_entities(const Td *td, vector<MessageEntity> &entities, bool remove_unknown) {
|
||||
td::remove_if(entities, [&](const MessageEntity &entity) {
|
||||
return entity.type == MessageEntity::Type::CustomEmoji &&
|
||||
td->stickers_manager_->is_premium_custom_emoji(entity.document_id, remove_unknown);
|
||||
td->stickers_manager_->is_premium_custom_emoji(entity.custom_emoji_id, remove_unknown);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "td/telegram/CustomEmojiId.h"
|
||||
#include "td/telegram/DialogId.h"
|
||||
#include "td/telegram/secret_api.h"
|
||||
#include "td/telegram/td_api.h"
|
||||
@ -60,7 +61,7 @@ class MessageEntity {
|
||||
int32 media_timestamp = -1;
|
||||
string argument;
|
||||
UserId user_id;
|
||||
int64 document_id = 0;
|
||||
CustomEmojiId custom_emoji_id;
|
||||
|
||||
MessageEntity() = default;
|
||||
|
||||
@ -74,8 +75,8 @@ class MessageEntity {
|
||||
: type(type), offset(offset), length(length), media_timestamp(media_timestamp) {
|
||||
CHECK(type == Type::MediaTimestamp);
|
||||
}
|
||||
MessageEntity(Type type, int32 offset, int32 length, int64 document_id)
|
||||
: type(type), offset(offset), length(length), document_id(document_id) {
|
||||
MessageEntity(Type type, int32 offset, int32 length, CustomEmojiId custom_emoji_id)
|
||||
: type(type), offset(offset), length(length), custom_emoji_id(custom_emoji_id) {
|
||||
CHECK(type == Type::CustomEmoji);
|
||||
}
|
||||
|
||||
@ -84,7 +85,7 @@ class MessageEntity {
|
||||
bool operator==(const MessageEntity &other) const {
|
||||
return offset == other.offset && length == other.length && type == other.type &&
|
||||
media_timestamp == other.media_timestamp && argument == other.argument && user_id == other.user_id &&
|
||||
document_id == other.document_id;
|
||||
custom_emoji_id == other.custom_emoji_id;
|
||||
}
|
||||
|
||||
bool operator<(const MessageEntity &other) const {
|
||||
|
@ -28,7 +28,7 @@ void MessageEntity::store(StorerT &storer) const {
|
||||
store(media_timestamp, storer);
|
||||
}
|
||||
if (type == Type::CustomEmoji) {
|
||||
store(document_id, storer);
|
||||
store(custom_emoji_id, storer);
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,7 +48,7 @@ void MessageEntity::parse(ParserT &parser) {
|
||||
parse(media_timestamp, parser);
|
||||
}
|
||||
if (type == Type::CustomEmoji) {
|
||||
parse(document_id, parser);
|
||||
parse(custom_emoji_id, parser);
|
||||
}
|
||||
}
|
||||
|
||||
|
328
td/telegram/MessageExtendedMedia.cpp
Normal file
328
td/telegram/MessageExtendedMedia.cpp
Normal file
@ -0,0 +1,328 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#include "td/telegram/MessageExtendedMedia.h"
|
||||
|
||||
#include "td/telegram/Document.h"
|
||||
#include "td/telegram/DocumentsManager.h"
|
||||
#include "td/telegram/MessageContent.h"
|
||||
#include "td/telegram/MessageContentType.h"
|
||||
#include "td/telegram/PhotoSize.h"
|
||||
#include "td/telegram/Td.h"
|
||||
#include "td/telegram/VideosManager.h"
|
||||
|
||||
#include "td/utils/algorithm.h"
|
||||
#include "td/utils/logging.h"
|
||||
|
||||
namespace td {
|
||||
|
||||
MessageExtendedMedia::MessageExtendedMedia(
|
||||
Td *td, telegram_api::object_ptr<telegram_api::MessageExtendedMedia> &&extended_media, FormattedText &&caption,
|
||||
DialogId owner_dialog_id) {
|
||||
if (extended_media == nullptr) {
|
||||
return;
|
||||
}
|
||||
caption_ = std::move(caption);
|
||||
|
||||
switch (extended_media->get_id()) {
|
||||
case telegram_api::messageExtendedMediaPreview::ID: {
|
||||
auto media = move_tl_object_as<telegram_api::messageExtendedMediaPreview>(extended_media);
|
||||
type_ = Type::Preview;
|
||||
duration_ = media->video_duration_;
|
||||
dimensions_ = get_dimensions(media->w_, media->h_, "MessageExtendedMedia");
|
||||
if (media->thumb_ != nullptr) {
|
||||
if (media->thumb_->get_id() == telegram_api::photoStrippedSize::ID) {
|
||||
auto thumb = move_tl_object_as<telegram_api::photoStrippedSize>(media->thumb_);
|
||||
minithumbnail_ = thumb->bytes_.as_slice().str();
|
||||
} else {
|
||||
LOG(ERROR) << "Receive " << to_string(media->thumb_);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case telegram_api::messageExtendedMedia::ID: {
|
||||
auto media = move_tl_object_as<telegram_api::messageExtendedMedia>(extended_media);
|
||||
type_ = Type::Unsupported;
|
||||
switch (media->media_->get_id()) {
|
||||
case telegram_api::messageMediaPhoto::ID: {
|
||||
auto photo = move_tl_object_as<telegram_api::messageMediaPhoto>(media->media_);
|
||||
if (photo->photo_ == nullptr) {
|
||||
break;
|
||||
}
|
||||
|
||||
photo_ = get_photo(td->file_manager_.get(), std::move(photo->photo_), owner_dialog_id);
|
||||
if (photo_.is_empty()) {
|
||||
break;
|
||||
}
|
||||
type_ = Type::Photo;
|
||||
break;
|
||||
}
|
||||
case telegram_api::messageMediaDocument::ID: {
|
||||
auto document = move_tl_object_as<telegram_api::messageMediaDocument>(media->media_);
|
||||
if (document->document_ == nullptr) {
|
||||
break;
|
||||
}
|
||||
|
||||
auto document_ptr = std::move(document->document_);
|
||||
int32 document_id = document_ptr->get_id();
|
||||
if (document_id == telegram_api::documentEmpty::ID) {
|
||||
break;
|
||||
}
|
||||
CHECK(document_id == telegram_api::document::ID);
|
||||
|
||||
auto parsed_document = td->documents_manager_->on_get_document(
|
||||
move_tl_object_as<telegram_api::document>(document_ptr), owner_dialog_id, nullptr);
|
||||
if (parsed_document.empty() || parsed_document.type != Document::Type::Video) {
|
||||
break;
|
||||
}
|
||||
CHECK(parsed_document.file_id.is_valid());
|
||||
video_file_id_ = parsed_document.file_id;
|
||||
type_ = Type::Video;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (type_ == Type::Unsupported) {
|
||||
unsupported_version_ = CURRENT_VERSION;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
Result<MessageExtendedMedia> MessageExtendedMedia::get_message_extended_media(
|
||||
Td *td, td_api::object_ptr<td_api::InputMessageContent> &&extended_media_content, DialogId owner_dialog_id,
|
||||
bool is_premium) {
|
||||
if (extended_media_content == nullptr) {
|
||||
return MessageExtendedMedia();
|
||||
}
|
||||
if (!owner_dialog_id.is_valid()) {
|
||||
return Status::Error(400, "Extended media can't be added to the invoice");
|
||||
}
|
||||
|
||||
auto input_content_type = extended_media_content->get_id();
|
||||
if (input_content_type != td_api::inputMessagePhoto::ID && input_content_type != td_api::inputMessageVideo::ID) {
|
||||
return Status::Error("Invalid extended media content specified");
|
||||
}
|
||||
TRY_RESULT(input_message_content,
|
||||
get_input_message_content(owner_dialog_id, std::move(extended_media_content), td, is_premium));
|
||||
if (input_message_content.ttl != 0) {
|
||||
return Status::Error("Can't use self-destructing extended media");
|
||||
}
|
||||
|
||||
auto content = input_message_content.content.get();
|
||||
auto content_type = content->get_type();
|
||||
MessageExtendedMedia result;
|
||||
CHECK(content_type == MessageContentType::Photo || content_type == MessageContentType::Video);
|
||||
result.caption_ = *get_message_content_caption(content);
|
||||
if (content_type == MessageContentType::Photo) {
|
||||
result.type_ = Type::Photo;
|
||||
result.photo_ = *get_message_content_photo(content);
|
||||
} else {
|
||||
CHECK(content_type == MessageContentType::Video);
|
||||
result.type_ = Type::Video;
|
||||
result.video_file_id_ = get_message_content_upload_file_id(content);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void MessageExtendedMedia::update_from(const MessageExtendedMedia &old_extended_media) {
|
||||
if (!is_media() && old_extended_media.is_media()) {
|
||||
*this = old_extended_media;
|
||||
}
|
||||
}
|
||||
|
||||
bool MessageExtendedMedia::update_to(Td *td,
|
||||
telegram_api::object_ptr<telegram_api::MessageExtendedMedia> extended_media_ptr,
|
||||
DialogId owner_dialog_id) {
|
||||
MessageExtendedMedia new_extended_media(td, std::move(extended_media_ptr), FormattedText(caption_), owner_dialog_id);
|
||||
if (!new_extended_media.is_media() && is_media()) {
|
||||
return false;
|
||||
}
|
||||
if (*this != new_extended_media || is_equal_but_different(new_extended_media)) {
|
||||
*this = std::move(new_extended_media);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
td_api::object_ptr<td_api::MessageExtendedMedia> MessageExtendedMedia::get_message_extended_media_object(
|
||||
Td *td, bool skip_bot_commands, int32 max_media_timestamp) const {
|
||||
if (type_ == Type::Empty) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto caption = get_formatted_text_object(caption_, skip_bot_commands, max_media_timestamp);
|
||||
switch (type_) {
|
||||
case Type::Unsupported:
|
||||
return td_api::make_object<td_api::messageExtendedMediaUnsupported>(std::move(caption));
|
||||
case Type::Preview:
|
||||
return td_api::make_object<td_api::messageExtendedMediaPreview>(dimensions_.width, dimensions_.height, duration_,
|
||||
get_minithumbnail_object(minithumbnail_),
|
||||
std::move(caption));
|
||||
case Type::Photo: {
|
||||
auto photo = get_photo_object(td->file_manager_.get(), photo_);
|
||||
CHECK(photo != nullptr);
|
||||
return td_api::make_object<td_api::messageExtendedMediaPhoto>(std::move(photo), std::move(caption));
|
||||
}
|
||||
case Type::Video:
|
||||
return td_api::make_object<td_api::messageExtendedMediaVideo>(
|
||||
td->videos_manager_->get_video_object(video_file_id_), std::move(caption));
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void MessageExtendedMedia::append_file_ids(const Td *td, vector<FileId> &file_ids) const {
|
||||
switch (type_) {
|
||||
case Type::Empty:
|
||||
case Type::Unsupported:
|
||||
case Type::Preview:
|
||||
break;
|
||||
case Type::Photo:
|
||||
append(file_ids, photo_get_file_ids(photo_));
|
||||
break;
|
||||
case Type::Video:
|
||||
Document(Document::Type::Video, video_file_id_).append_file_ids(td, file_ids);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MessageExtendedMedia::delete_thumbnail(Td *td) {
|
||||
switch (type_) {
|
||||
case Type::Empty:
|
||||
case Type::Unsupported:
|
||||
case Type::Preview:
|
||||
break;
|
||||
case Type::Photo:
|
||||
photo_delete_thumbnail(photo_);
|
||||
break;
|
||||
case Type::Video:
|
||||
td->videos_manager_->delete_video_thumbnail(video_file_id_);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int32 MessageExtendedMedia::get_duration(const Td *td) const {
|
||||
if (!has_media_timestamp()) {
|
||||
return 0;
|
||||
}
|
||||
return td->videos_manager_->get_video_duration(video_file_id_);
|
||||
}
|
||||
|
||||
FileId MessageExtendedMedia::get_upload_file_id() const {
|
||||
switch (type_) {
|
||||
case Type::Empty:
|
||||
case Type::Unsupported:
|
||||
case Type::Preview:
|
||||
break;
|
||||
case Type::Photo:
|
||||
return get_photo_upload_file_id(photo_);
|
||||
case Type::Video:
|
||||
return video_file_id_;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
return FileId();
|
||||
}
|
||||
|
||||
FileId MessageExtendedMedia::get_any_file_id() const {
|
||||
switch (type_) {
|
||||
case Type::Empty:
|
||||
case Type::Unsupported:
|
||||
case Type::Preview:
|
||||
break;
|
||||
case Type::Photo:
|
||||
return get_photo_any_file_id(photo_);
|
||||
case Type::Video:
|
||||
return video_file_id_;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
return FileId();
|
||||
}
|
||||
|
||||
FileId MessageExtendedMedia::get_thumbnail_file_id(const Td *td) const {
|
||||
switch (type_) {
|
||||
case Type::Empty:
|
||||
case Type::Unsupported:
|
||||
case Type::Preview:
|
||||
break;
|
||||
case Type::Photo:
|
||||
return get_photo_thumbnail_file_id(photo_);
|
||||
case Type::Video:
|
||||
return td->videos_manager_->get_video_thumbnail_file_id(video_file_id_);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
return FileId();
|
||||
}
|
||||
|
||||
telegram_api::object_ptr<telegram_api::InputMedia> MessageExtendedMedia::get_input_media(
|
||||
Td *td, tl_object_ptr<telegram_api::InputFile> input_file,
|
||||
tl_object_ptr<telegram_api::InputFile> input_thumbnail) const {
|
||||
switch (type_) {
|
||||
case Type::Empty:
|
||||
case Type::Unsupported:
|
||||
case Type::Preview:
|
||||
break;
|
||||
case Type::Photo:
|
||||
return photo_get_input_media(td->file_manager_.get(), photo_, std::move(input_file), 0);
|
||||
case Type::Video:
|
||||
return td->videos_manager_->get_input_media(video_file_id_, std::move(input_file), std::move(input_thumbnail), 0);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool MessageExtendedMedia::is_equal_but_different(const MessageExtendedMedia &other) const {
|
||||
return type_ == Type::Unsupported && other.type_ == Type::Unsupported &&
|
||||
unsupported_version_ != other.unsupported_version_;
|
||||
}
|
||||
|
||||
bool operator==(const MessageExtendedMedia &lhs, const MessageExtendedMedia &rhs) {
|
||||
if (lhs.type_ != rhs.type_ || lhs.caption_ != rhs.caption_) {
|
||||
return false;
|
||||
}
|
||||
switch (lhs.type_) {
|
||||
case MessageExtendedMedia::Type::Empty:
|
||||
return true;
|
||||
case MessageExtendedMedia::Type::Unsupported:
|
||||
// don't compare unsupported_version_
|
||||
return true;
|
||||
case MessageExtendedMedia::Type::Preview:
|
||||
return lhs.duration_ == rhs.duration_ && lhs.dimensions_ == rhs.dimensions_ &&
|
||||
lhs.minithumbnail_ == rhs.minithumbnail_;
|
||||
case MessageExtendedMedia::Type::Photo:
|
||||
return lhs.photo_ == rhs.photo_;
|
||||
case MessageExtendedMedia::Type::Video:
|
||||
return lhs.video_file_id_ == rhs.video_file_id_;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool operator!=(const MessageExtendedMedia &lhs, const MessageExtendedMedia &rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
} // namespace td
|
118
td/telegram/MessageExtendedMedia.h
Normal file
118
td/telegram/MessageExtendedMedia.h
Normal file
@ -0,0 +1,118 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "td/telegram/DialogId.h"
|
||||
#include "td/telegram/Dimensions.h"
|
||||
#include "td/telegram/files/FileId.h"
|
||||
#include "td/telegram/MessageEntity.h"
|
||||
#include "td/telegram/Photo.h"
|
||||
#include "td/telegram/td_api.h"
|
||||
#include "td/telegram/telegram_api.h"
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/Status.h"
|
||||
|
||||
namespace td {
|
||||
|
||||
class Td;
|
||||
|
||||
class MessageExtendedMedia {
|
||||
enum class Type : int32 { Empty, Unsupported, Preview, Photo, Video };
|
||||
Type type_ = Type::Empty;
|
||||
FormattedText caption_;
|
||||
|
||||
static constexpr int32 CURRENT_VERSION = 1;
|
||||
|
||||
// for Unsupported
|
||||
int32 unsupported_version_ = 0;
|
||||
|
||||
// for Preview
|
||||
int32 duration_ = 0;
|
||||
Dimensions dimensions_;
|
||||
string minithumbnail_;
|
||||
|
||||
// for Photo
|
||||
Photo photo_;
|
||||
|
||||
// for Video
|
||||
FileId video_file_id_;
|
||||
|
||||
friend bool operator==(const MessageExtendedMedia &lhs, const MessageExtendedMedia &rhs);
|
||||
|
||||
bool is_media() const {
|
||||
return type_ != Type::Empty && type_ != Type::Preview;
|
||||
}
|
||||
|
||||
public:
|
||||
MessageExtendedMedia() = default;
|
||||
|
||||
MessageExtendedMedia(Td *td, telegram_api::object_ptr<telegram_api::MessageExtendedMedia> &&extended_media,
|
||||
FormattedText &&caption, DialogId owner_dialog_id);
|
||||
|
||||
static Result<MessageExtendedMedia> get_message_extended_media(
|
||||
Td *td, td_api::object_ptr<td_api::InputMessageContent> &&extended_media_content, DialogId owner_dialog_id,
|
||||
bool is_premium);
|
||||
|
||||
bool is_empty() const {
|
||||
return type_ == Type::Empty;
|
||||
}
|
||||
|
||||
void update_from(const MessageExtendedMedia &old_extended_media);
|
||||
|
||||
bool update_to(Td *td, telegram_api::object_ptr<telegram_api::MessageExtendedMedia> extended_media_ptr,
|
||||
DialogId owner_dialog_id);
|
||||
|
||||
td_api::object_ptr<td_api::MessageExtendedMedia> get_message_extended_media_object(Td *td, bool skip_bot_commands,
|
||||
int32 max_media_timestamp) const;
|
||||
|
||||
void append_file_ids(const Td *td, vector<FileId> &file_ids) const;
|
||||
|
||||
void delete_thumbnail(Td *td);
|
||||
|
||||
bool need_reget() const {
|
||||
return type_ == Type::Unsupported && unsupported_version_ < CURRENT_VERSION;
|
||||
}
|
||||
|
||||
bool need_poll() const {
|
||||
return type_ == Type::Preview;
|
||||
}
|
||||
|
||||
bool has_media_timestamp() const {
|
||||
return type_ == Type::Video;
|
||||
}
|
||||
|
||||
bool is_equal_but_different(const MessageExtendedMedia &other) const;
|
||||
|
||||
int32 get_duration(const Td *td) const;
|
||||
|
||||
const FormattedText *get_caption() const {
|
||||
return &caption_;
|
||||
}
|
||||
|
||||
FileId get_upload_file_id() const;
|
||||
|
||||
FileId get_any_file_id() const;
|
||||
|
||||
FileId get_thumbnail_file_id(const Td *td) const;
|
||||
|
||||
telegram_api::object_ptr<telegram_api::InputMedia> get_input_media(
|
||||
Td *td, tl_object_ptr<telegram_api::InputFile> input_file,
|
||||
tl_object_ptr<telegram_api::InputFile> input_thumbnail) const;
|
||||
|
||||
template <class StorerT>
|
||||
void store(StorerT &storer) const;
|
||||
|
||||
template <class ParserT>
|
||||
void parse(ParserT &parser);
|
||||
};
|
||||
|
||||
bool operator==(const MessageExtendedMedia &lhs, const MessageExtendedMedia &rhs);
|
||||
|
||||
bool operator!=(const MessageExtendedMedia &lhs, const MessageExtendedMedia &rhs);
|
||||
|
||||
} // namespace td
|
115
td/telegram/MessageExtendedMedia.hpp
Normal file
115
td/telegram/MessageExtendedMedia.hpp
Normal file
@ -0,0 +1,115 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "td/telegram/MessageExtendedMedia.h"
|
||||
#include "td/telegram/Photo.hpp"
|
||||
#include "td/telegram/Td.h"
|
||||
#include "td/telegram/VideosManager.h"
|
||||
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/tl_helpers.h"
|
||||
|
||||
namespace td {
|
||||
|
||||
template <class StorerT>
|
||||
void MessageExtendedMedia::store(StorerT &storer) const {
|
||||
bool has_caption = !caption_.text.empty();
|
||||
bool has_unsupported_version = unsupported_version_ != 0;
|
||||
bool has_duration = duration_ != 0;
|
||||
bool has_dimensions = dimensions_.width != 0 || dimensions_.height != 0;
|
||||
bool has_minithumbnail = !minithumbnail_.empty();
|
||||
bool has_photo = !photo_.is_empty();
|
||||
bool has_video = video_file_id_.is_valid();
|
||||
BEGIN_STORE_FLAGS();
|
||||
STORE_FLAG(has_caption);
|
||||
STORE_FLAG(has_unsupported_version);
|
||||
STORE_FLAG(has_duration);
|
||||
STORE_FLAG(has_dimensions);
|
||||
STORE_FLAG(has_minithumbnail);
|
||||
STORE_FLAG(has_photo);
|
||||
STORE_FLAG(has_video);
|
||||
END_STORE_FLAGS();
|
||||
td::store(type_, storer);
|
||||
if (has_caption) {
|
||||
td::store(caption_, storer);
|
||||
}
|
||||
if (has_unsupported_version) {
|
||||
td::store(unsupported_version_, storer);
|
||||
}
|
||||
if (has_duration) {
|
||||
td::store(duration_, storer);
|
||||
}
|
||||
if (has_dimensions) {
|
||||
td::store(dimensions_, storer);
|
||||
}
|
||||
if (has_minithumbnail) {
|
||||
td::store(minithumbnail_, storer);
|
||||
}
|
||||
if (has_photo) {
|
||||
td::store(photo_, storer);
|
||||
}
|
||||
if (has_video) {
|
||||
Td *td = storer.context()->td().get_actor_unsafe();
|
||||
td->videos_manager_->store_video(video_file_id_, storer);
|
||||
}
|
||||
}
|
||||
|
||||
template <class ParserT>
|
||||
void MessageExtendedMedia::parse(ParserT &parser) {
|
||||
bool has_caption;
|
||||
bool has_unsupported_version;
|
||||
bool has_duration;
|
||||
bool has_dimensions;
|
||||
bool has_minithumbnail;
|
||||
bool has_photo;
|
||||
bool has_video;
|
||||
BEGIN_PARSE_FLAGS();
|
||||
PARSE_FLAG(has_caption);
|
||||
PARSE_FLAG(has_unsupported_version);
|
||||
PARSE_FLAG(has_duration);
|
||||
PARSE_FLAG(has_dimensions);
|
||||
PARSE_FLAG(has_minithumbnail);
|
||||
PARSE_FLAG(has_photo);
|
||||
PARSE_FLAG(has_video);
|
||||
END_PARSE_FLAGS();
|
||||
td::parse(type_, parser);
|
||||
if (has_caption) {
|
||||
td::parse(caption_, parser);
|
||||
}
|
||||
if (has_unsupported_version) {
|
||||
td::parse(unsupported_version_, parser);
|
||||
}
|
||||
if (has_duration) {
|
||||
td::parse(duration_, parser);
|
||||
}
|
||||
if (has_dimensions) {
|
||||
td::parse(dimensions_, parser);
|
||||
}
|
||||
if (has_minithumbnail) {
|
||||
td::parse(minithumbnail_, parser);
|
||||
}
|
||||
bool is_bad = false;
|
||||
if (has_photo) {
|
||||
td::parse(photo_, parser);
|
||||
is_bad = photo_.is_bad();
|
||||
}
|
||||
if (has_video) {
|
||||
Td *td = parser.context()->td().get_actor_unsafe();
|
||||
video_file_id_ = td->videos_manager_->parse_video(parser);
|
||||
is_bad = !video_file_id_.is_valid();
|
||||
}
|
||||
if (is_bad) {
|
||||
LOG(ERROR) << "Failed to parse MessageExtendedMedia";
|
||||
photo_ = Photo();
|
||||
video_file_id_ = FileId();
|
||||
type_ = Type::Unsupported;
|
||||
unsupported_version_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace td
|
@ -9,6 +9,7 @@
|
||||
#include "td/telegram/AccessRights.h"
|
||||
#include "td/telegram/ConfigManager.h"
|
||||
#include "td/telegram/ContactsManager.h"
|
||||
#include "td/telegram/Dependencies.h"
|
||||
#include "td/telegram/Global.h"
|
||||
#include "td/telegram/MessageSender.h"
|
||||
#include "td/telegram/MessagesManager.h"
|
||||
@ -29,6 +30,8 @@
|
||||
#include "td/utils/emoji.h"
|
||||
#include "td/utils/FlatHashSet.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/Slice.h"
|
||||
#include "td/utils/SliceBuilder.h"
|
||||
#include "td/utils/Status.h"
|
||||
#include "td/utils/utf8.h"
|
||||
|
||||
@ -550,19 +553,19 @@ unique_ptr<MessageReactions> MessageReactions::get_message_reactions(
|
||||
if (dialog_type == DialogType::User) {
|
||||
auto user_id = dialog_id.get_user_id();
|
||||
if (!td->contacts_manager_->have_min_user(user_id)) {
|
||||
LOG(ERROR) << "Have no info about " << user_id;
|
||||
LOG(ERROR) << "Receive unknown " << user_id;
|
||||
continue;
|
||||
}
|
||||
} else if (dialog_type == DialogType::Channel) {
|
||||
auto channel_id = dialog_id.get_channel_id();
|
||||
auto min_channel = td->contacts_manager_->get_min_channel(channel_id);
|
||||
if (min_channel == nullptr) {
|
||||
LOG(ERROR) << "Have no info about reacted " << channel_id;
|
||||
LOG(ERROR) << "Receive unknown reacted " << channel_id;
|
||||
continue;
|
||||
}
|
||||
recent_chooser_min_channels.emplace_back(channel_id, *min_channel);
|
||||
} else {
|
||||
LOG(ERROR) << "Have no info about reacted " << dialog_id;
|
||||
LOG(ERROR) << "Receive unknown reacted " << dialog_id;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -762,6 +765,69 @@ vector<string> MessageReactions::get_chosen_reactions() const {
|
||||
return reaction_order;
|
||||
}
|
||||
|
||||
bool MessageReactions::are_consistent_with_list(const string &reaction, FlatHashMap<string, vector<DialogId>> reactions,
|
||||
int32 total_count) const {
|
||||
auto are_consistent = [](const vector<DialogId> &lhs, const vector<DialogId> &rhs) {
|
||||
size_t i = 0;
|
||||
size_t max_i = td::min(lhs.size(), rhs.size());
|
||||
while (i < max_i && lhs[i] == rhs[i]) {
|
||||
i++;
|
||||
}
|
||||
return i == max_i;
|
||||
};
|
||||
|
||||
if (reaction.empty()) {
|
||||
// received list and total_count for all reactions
|
||||
int32 old_total_count = 0;
|
||||
for (const auto &message_reaction : reactions_) {
|
||||
CHECK(!message_reaction.get_reaction().empty());
|
||||
if (!are_consistent(reactions[message_reaction.get_reaction()],
|
||||
message_reaction.get_recent_chooser_dialog_ids())) {
|
||||
return false;
|
||||
}
|
||||
old_total_count += message_reaction.get_choose_count();
|
||||
reactions.erase(message_reaction.get_reaction());
|
||||
}
|
||||
return old_total_count == total_count && reactions.empty();
|
||||
}
|
||||
|
||||
// received list and total_count for a single reaction
|
||||
const auto *message_reaction = get_reaction(reaction);
|
||||
if (message_reaction == nullptr) {
|
||||
return reactions.count(reaction) == 0 && total_count == 0;
|
||||
} else {
|
||||
return are_consistent(reactions[reaction], message_reaction->get_recent_chooser_dialog_ids()) &&
|
||||
message_reaction->get_choose_count() == total_count;
|
||||
}
|
||||
}
|
||||
|
||||
vector<td_api::object_ptr<td_api::messageReaction>> MessageReactions::get_message_reactions_object(
|
||||
Td *td, UserId my_user_id, UserId peer_user_id) const {
|
||||
return transform(reactions_, [td, my_user_id, peer_user_id](const MessageReaction &reaction) {
|
||||
return reaction.get_message_reaction_object(td, my_user_id, peer_user_id);
|
||||
});
|
||||
}
|
||||
|
||||
void MessageReactions::add_min_channels(Td *td) const {
|
||||
for (const auto &reaction : reactions_) {
|
||||
for (const auto &recent_chooser_min_channel : reaction.get_recent_chooser_min_channels()) {
|
||||
LOG(INFO) << "Add min reacted " << recent_chooser_min_channel.first;
|
||||
td->contacts_manager_->add_min_channel(recent_chooser_min_channel.first, recent_chooser_min_channel.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MessageReactions::add_dependencies(Dependencies &dependencies) const {
|
||||
for (const auto &reaction : reactions_) {
|
||||
const auto &dialog_ids = reaction.get_recent_chooser_dialog_ids();
|
||||
for (auto dialog_id : dialog_ids) {
|
||||
// don't load the dialog itself
|
||||
// it will be created in get_message_reaction_object if needed
|
||||
dependencies.add_dialog_dependencies(dialog_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool MessageReactions::need_update_message_reactions(const MessageReactions *old_reactions,
|
||||
const MessageReactions *new_reactions) {
|
||||
if (old_reactions == nullptr) {
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "td/telegram/MinChannel.h"
|
||||
#include "td/telegram/td_api.h"
|
||||
#include "td/telegram/telegram_api.h"
|
||||
#include "td/telegram/UserId.h"
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/FlatHashMap.h"
|
||||
@ -23,9 +24,15 @@
|
||||
|
||||
namespace td {
|
||||
|
||||
class Dependencies;
|
||||
|
||||
class Td;
|
||||
|
||||
class MessageReaction {
|
||||
static constexpr int32 MAX_CHOOSE_COUNT = 2147483640;
|
||||
|
||||
static constexpr size_t MAX_RECENT_CHOOSERS = 3;
|
||||
|
||||
string reaction_;
|
||||
int32 choose_count_ = 0;
|
||||
bool is_chosen_ = false;
|
||||
@ -63,16 +70,6 @@ class MessageReaction {
|
||||
|
||||
void update_recent_chooser_dialog_ids(const MessageReaction &old_reaction);
|
||||
|
||||
public:
|
||||
static constexpr size_t MAX_RECENT_CHOOSERS = 3;
|
||||
static constexpr int32 MAX_CHOOSE_COUNT = 2147483640;
|
||||
|
||||
MessageReaction() = default;
|
||||
|
||||
const string &get_reaction() const {
|
||||
return reaction_;
|
||||
}
|
||||
|
||||
int32 get_choose_count() const {
|
||||
return choose_count_;
|
||||
}
|
||||
@ -88,6 +85,13 @@ class MessageReaction {
|
||||
td_api::object_ptr<td_api::messageReaction> get_message_reaction_object(Td *td, UserId my_user_id,
|
||||
UserId peer_user_id) const;
|
||||
|
||||
public:
|
||||
MessageReaction() = default;
|
||||
|
||||
const string &get_reaction() const {
|
||||
return reaction_;
|
||||
}
|
||||
|
||||
template <class StorerT>
|
||||
void store(StorerT &storer) const;
|
||||
|
||||
@ -166,6 +170,16 @@ struct MessageReactions {
|
||||
|
||||
vector<string> get_chosen_reactions() const;
|
||||
|
||||
bool are_consistent_with_list(const string &reaction, FlatHashMap<string, vector<DialogId>> reactions,
|
||||
int32 total_count) const;
|
||||
|
||||
vector<td_api::object_ptr<td_api::messageReaction>> get_message_reactions_object(Td *td, UserId my_user_id,
|
||||
UserId peer_user_id) const;
|
||||
|
||||
void add_min_channels(Td *td) const;
|
||||
|
||||
void add_dependencies(Dependencies &dependencies) const;
|
||||
|
||||
static bool need_update_message_reactions(const MessageReactions *old_reactions,
|
||||
const MessageReactions *new_reactions);
|
||||
|
||||
|
@ -56,19 +56,19 @@ MessageReplyInfo::MessageReplyInfo(Td *td, tl_object_ptr<telegram_api::messageRe
|
||||
if (dialog_type == DialogType::User) {
|
||||
auto replier_user_id = dialog_id.get_user_id();
|
||||
if (!td->contacts_manager_->have_min_user(replier_user_id)) {
|
||||
LOG(ERROR) << "Have no info about replied " << replier_user_id;
|
||||
LOG(ERROR) << "Receive unknown replied " << replier_user_id;
|
||||
continue;
|
||||
}
|
||||
} else if (dialog_type == DialogType::Channel) {
|
||||
auto replier_channel_id = dialog_id.get_channel_id();
|
||||
auto min_channel = td->contacts_manager_->get_min_channel(replier_channel_id);
|
||||
if (min_channel == nullptr) {
|
||||
LOG(ERROR) << "Have no info about replied " << replier_channel_id;
|
||||
LOG(ERROR) << "Receive unknown replied " << replier_channel_id;
|
||||
continue;
|
||||
}
|
||||
replier_min_channels.emplace_back(replier_channel_id, *min_channel);
|
||||
} else {
|
||||
LOG(ERROR) << "Have no info about replied " << dialog_id;
|
||||
LOG(ERROR) << "Receive unknown replied " << dialog_id;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ vector<DialogId> get_message_sender_dialog_ids(Td *td,
|
||||
}
|
||||
if (dialog_id.get_type() == DialogType::User) {
|
||||
if (!td->contacts_manager_->have_user(dialog_id.get_user_id())) {
|
||||
LOG(ERROR) << "Have no info about " << dialog_id.get_user_id();
|
||||
LOG(ERROR) << "Receive unknown " << dialog_id.get_user_id();
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "td/telegram/MessagesDb.h"
|
||||
|
||||
#include "td/telegram/logevent/LogEvent.h"
|
||||
#include "td/telegram/UserId.h"
|
||||
#include "td/telegram/Version.h"
|
||||
|
||||
#include "td/db/SqliteConnectionSafe.h"
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -254,16 +254,16 @@ class MessagesManager final : public Actor {
|
||||
bool is_channel_message, bool is_scheduled, bool have_previous, bool have_next,
|
||||
const char *source);
|
||||
|
||||
void open_secret_message(SecretChatId secret_chat_id, int64 random_id, Promise<>);
|
||||
void open_secret_message(SecretChatId secret_chat_id, int64 random_id, Promise<Unit>);
|
||||
|
||||
void on_send_secret_message_success(int64 random_id, MessageId message_id, int32 date, unique_ptr<EncryptedFile> file,
|
||||
Promise<> promise);
|
||||
void on_send_secret_message_error(int64 random_id, Status error, Promise<> promise);
|
||||
Promise<Unit> promise);
|
||||
void on_send_secret_message_error(int64 random_id, Status error, Promise<Unit> promise);
|
||||
|
||||
void delete_secret_messages(SecretChatId secret_chat_id, std::vector<int64> random_ids, Promise<> promise);
|
||||
void delete_secret_messages(SecretChatId secret_chat_id, std::vector<int64> random_ids, Promise<Unit> promise);
|
||||
|
||||
void delete_secret_chat_history(SecretChatId secret_chat_id, bool remove_from_dialog_list, MessageId last_message_id,
|
||||
Promise<> promise);
|
||||
Promise<Unit> promise);
|
||||
|
||||
void read_secret_chat_outbox(SecretChatId secret_chat_id, int32 up_to_date, int32 read_date);
|
||||
|
||||
@ -271,13 +271,13 @@ class MessagesManager final : public Actor {
|
||||
|
||||
void on_get_secret_message(SecretChatId secret_chat_id, UserId user_id, MessageId message_id, int32 date,
|
||||
unique_ptr<EncryptedFile> file, tl_object_ptr<secret_api::decryptedMessage> message,
|
||||
Promise<> promise);
|
||||
Promise<Unit> promise);
|
||||
|
||||
void on_secret_chat_screenshot_taken(SecretChatId secret_chat_id, UserId user_id, MessageId message_id, int32 date,
|
||||
int64 random_id, Promise<> promise);
|
||||
int64 random_id, Promise<Unit> promise);
|
||||
|
||||
void on_secret_chat_ttl_changed(SecretChatId secret_chat_id, UserId user_id, MessageId message_id, int32 date,
|
||||
int32 ttl, int64 random_id, Promise<> promise);
|
||||
int32 ttl, int64 random_id, Promise<Unit> promise);
|
||||
|
||||
void on_update_sent_text_message(int64 random_id, tl_object_ptr<telegram_api::MessageMedia> message_media,
|
||||
vector<tl_object_ptr<telegram_api::MessageEntity>> &&entities);
|
||||
@ -366,6 +366,9 @@ class MessagesManager final : public Actor {
|
||||
|
||||
void on_update_some_live_location_viewed(Promise<Unit> &&promise);
|
||||
|
||||
void on_update_message_extended_media(FullMessageId full_message_id,
|
||||
telegram_api::object_ptr<telegram_api::MessageExtendedMedia> extended_media);
|
||||
|
||||
void on_external_update_message_content(FullMessageId full_message_id);
|
||||
|
||||
void on_update_message_content(FullMessageId full_message_id);
|
||||
@ -427,7 +430,7 @@ class MessagesManager final : public Actor {
|
||||
void reload_voice_chat_on_search(const string &username);
|
||||
|
||||
void get_dialog_send_message_as_dialog_ids(DialogId dialog_id,
|
||||
Promise<td_api::object_ptr<td_api::messageSenders>> &&promise,
|
||||
Promise<td_api::object_ptr<td_api::chatMessageSenders>> &&promise,
|
||||
bool is_recursive = false);
|
||||
|
||||
void set_dialog_default_send_message_as_dialog_id(DialogId dialog_id, DialogId message_sender_dialog_id,
|
||||
@ -715,6 +718,8 @@ class MessagesManager final : public Actor {
|
||||
|
||||
void finish_get_message_views(DialogId dialog_id, const vector<MessageId> &message_ids);
|
||||
|
||||
void finish_get_message_extended_media(DialogId dialog_id, const vector<MessageId> &message_ids);
|
||||
|
||||
Status open_message_content(FullMessageId full_message_id) TD_WARN_UNUSED_RESULT;
|
||||
|
||||
void click_animated_emoji_message(FullMessageId full_message_id,
|
||||
@ -767,7 +772,7 @@ class MessagesManager final : public Actor {
|
||||
const char *source);
|
||||
|
||||
FoundMessages offline_search_messages(DialogId dialog_id, const string &query, string offset, int32 limit,
|
||||
MessageSearchFilter filter, int64 &random_id, Promise<> &&promise);
|
||||
MessageSearchFilter filter, int64 &random_id, Promise<Unit> &&promise);
|
||||
|
||||
std::pair<int32, vector<FullMessageId>> search_messages(FolderId folder_id, bool ignore_folder_id,
|
||||
const string &query, int32 offset_date,
|
||||
@ -806,6 +811,9 @@ class MessagesManager final : public Actor {
|
||||
void get_dialog_message_count(DialogId dialog_id, MessageSearchFilter filter, bool return_local,
|
||||
Promise<int32> &&promise);
|
||||
|
||||
void get_dialog_message_position(FullMessageId full_message_id, MessageSearchFilter filter,
|
||||
MessageId top_thread_message_id, Promise<int32> &&promise);
|
||||
|
||||
vector<MessageId> get_dialog_scheduled_messages(DialogId dialog_id, bool force, bool ignore_result,
|
||||
Promise<Unit> &&promise);
|
||||
|
||||
@ -845,8 +853,6 @@ class MessagesManager final : public Actor {
|
||||
|
||||
bool is_old_channel_update(DialogId dialog_id, int32 new_pts);
|
||||
|
||||
bool is_update_about_username_change_received(DialogId dialog_id) const;
|
||||
|
||||
void on_dialog_bots_updated(DialogId dialog_id, vector<UserId> bot_user_ids, bool from_database);
|
||||
|
||||
void on_dialog_photo_updated(DialogId dialog_id);
|
||||
@ -1172,6 +1178,8 @@ class MessagesManager final : public Actor {
|
||||
bool has_get_message_views_query = false;
|
||||
bool need_view_counter_increment = false;
|
||||
|
||||
bool has_get_extended_media_query = false;
|
||||
|
||||
DialogId real_forward_from_dialog_id; // for resend_message
|
||||
MessageId real_forward_from_message_id; // for resend_message
|
||||
|
||||
@ -1414,7 +1422,7 @@ class MessagesManager final : public Actor {
|
||||
MessageId suffix_load_first_message_id_; // identifier of some message such all suffix messages in range
|
||||
// [suffix_load_first_message_id_, last_message_id] are loaded
|
||||
MessageId suffix_load_query_message_id_;
|
||||
std::vector<std::pair<Promise<>, std::function<bool(const Message *)>>> suffix_load_queries_;
|
||||
std::vector<std::pair<Promise<Unit>, std::function<bool(const Message *)>>> suffix_load_queries_;
|
||||
|
||||
FlatHashMap<MessageId, int64, MessageIdHash> pending_viewed_live_locations; // message_id -> task_id
|
||||
FlatHashSet<MessageId, MessageIdHash> pending_viewed_message_ids;
|
||||
@ -1724,7 +1732,7 @@ class MessagesManager final : public Actor {
|
||||
MessageId last_message_id;
|
||||
bool remove_from_dialog_list = false;
|
||||
|
||||
Promise<> success_promise;
|
||||
Promise<Unit> success_promise;
|
||||
};
|
||||
|
||||
struct MessageSendOptions {
|
||||
@ -1817,8 +1825,7 @@ class MessagesManager final : public Actor {
|
||||
static constexpr int32 LIVE_LOCATION_VIEW_PERIOD = 60; // seconds, server-side limit
|
||||
static constexpr int32 UPDATE_VIEWED_MESSAGES_PERIOD = 15; // seconds
|
||||
|
||||
static constexpr int32 USERNAME_CACHE_EXPIRE_TIME = 3 * 86400;
|
||||
static constexpr int32 USERNAME_CACHE_EXPIRE_TIME_SHORT = 900;
|
||||
static constexpr int32 USERNAME_CACHE_EXPIRE_TIME = 86400;
|
||||
static constexpr int32 AUTH_NOTIFICATION_ID_CACHE_TIME = 7 * 86400;
|
||||
static constexpr size_t MAX_SAVED_AUTH_NOTIFICATION_IDS = 100;
|
||||
|
||||
@ -1867,10 +1874,10 @@ class MessagesManager final : public Actor {
|
||||
|
||||
void finish_add_secret_message(unique_ptr<PendingSecretMessage> pending_secret_message);
|
||||
|
||||
void finish_delete_secret_messages(DialogId dialog_id, std::vector<int64> random_ids, Promise<> promise);
|
||||
void finish_delete_secret_messages(DialogId dialog_id, std::vector<int64> random_ids, Promise<Unit> promise);
|
||||
|
||||
void finish_delete_secret_chat_history(DialogId dialog_id, bool remove_from_dialog_list, MessageId last_message_id,
|
||||
Promise<> promise);
|
||||
Promise<Unit> promise);
|
||||
|
||||
MessageInfo parse_telegram_api_message(tl_object_ptr<telegram_api::Message> message_ptr, bool is_scheduled,
|
||||
const char *source) const;
|
||||
@ -3068,8 +3075,6 @@ class MessagesManager final : public Actor {
|
||||
|
||||
const DialogPhoto *get_dialog_photo(DialogId dialog_id) const;
|
||||
|
||||
string get_dialog_username(DialogId dialog_id) const;
|
||||
|
||||
RestrictedRights get_dialog_default_permissions(DialogId dialog_id) const;
|
||||
|
||||
bool get_dialog_has_protected_content(DialogId dialog_id) const;
|
||||
@ -3335,9 +3340,9 @@ class MessagesManager final : public Actor {
|
||||
void suffix_load_loop(Dialog *d);
|
||||
static void suffix_load_update_first_message_id(Dialog *d);
|
||||
void suffix_load_query_ready(DialogId dialog_id);
|
||||
void suffix_load_add_query(Dialog *d, std::pair<Promise<>, std::function<bool(const Message *)>> query);
|
||||
void suffix_load_till_date(Dialog *d, int32 date, Promise<> promise);
|
||||
void suffix_load_till_message_id(Dialog *d, MessageId message_id, Promise<> promise);
|
||||
void suffix_load_add_query(Dialog *d, std::pair<Promise<Unit>, std::function<bool(const Message *)>> query);
|
||||
void suffix_load_till_date(Dialog *d, int32 date, Promise<Unit> promise);
|
||||
void suffix_load_till_message_id(Dialog *d, MessageId message_id, Promise<Unit> promise);
|
||||
|
||||
bool is_group_dialog(DialogId dialog_id) const;
|
||||
|
||||
@ -3512,17 +3517,6 @@ class MessagesManager final : public Actor {
|
||||
|
||||
FlatHashSet<DialogId, DialogIdHash> postponed_chat_read_inbox_updates_;
|
||||
|
||||
struct PendingGetMessageRequest {
|
||||
MessageId message_id;
|
||||
Promise<Unit> promise;
|
||||
tl_object_ptr<telegram_api::InputMessage> input_message;
|
||||
|
||||
PendingGetMessageRequest(MessageId message_id, Promise<Unit> promise,
|
||||
tl_object_ptr<telegram_api::InputMessage> input_message)
|
||||
: message_id(message_id), promise(std::move(promise)), input_message(std::move(input_message)) {
|
||||
}
|
||||
};
|
||||
|
||||
FlatHashMap<string, vector<Promise<Unit>>> search_public_dialogs_queries_;
|
||||
FlatHashMap<string, vector<DialogId>> found_public_dialogs_; // TODO time bound cache
|
||||
FlatHashMap<string, vector<DialogId>> found_on_server_dialogs_; // TODO time bound cache
|
||||
@ -3641,8 +3635,8 @@ class MessagesManager final : public Actor {
|
||||
double expires_at;
|
||||
};
|
||||
|
||||
FlatHashMap<string, ResolvedUsername> resolved_usernames_;
|
||||
FlatHashMap<string, DialogId> inaccessible_resolved_usernames_;
|
||||
WaitFreeHashMap<string, ResolvedUsername> resolved_usernames_;
|
||||
WaitFreeHashMap<string, DialogId> inaccessible_resolved_usernames_;
|
||||
FlatHashSet<string> reload_voice_chat_on_search_usernames_;
|
||||
|
||||
struct GetDialogsTask {
|
||||
|
@ -2685,7 +2685,7 @@ void NotificationManager::process_push_notification(string payload, Promise<Unit
|
||||
}
|
||||
|
||||
auto receiver_id = r_receiver_id.move_as_ok();
|
||||
auto encryption_keys = td_->device_token_manager_->get_actor_unsafe()->get_encryption_keys();
|
||||
auto encryption_keys = td_->device_token_manager_.get_actor_unsafe()->get_encryption_keys();
|
||||
VLOG(notifications) << "Process push notification \"" << format::escaped(payload)
|
||||
<< "\" with receiver_id = " << receiver_id << " and " << encryption_keys.size()
|
||||
<< " encryption keys";
|
||||
@ -3261,7 +3261,7 @@ Status NotificationManager::process_push_notification_payload(string payload, bo
|
||||
return Status::Error(406, "Phone call notification is not supported");
|
||||
}
|
||||
|
||||
if (begins_with(loc_key, "REACT_")) {
|
||||
if (begins_with(loc_key, "REACT_") || loc_key == "READ_REACTION") {
|
||||
// TODO REACT_* notifications
|
||||
return Status::Error(406, "Reaction notifications are unsupported");
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "td/telegram/NotificationType.h"
|
||||
#include "td/telegram/Photo.h"
|
||||
#include "td/telegram/td_api.h"
|
||||
#include "td/telegram/UserId.h"
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
#include "td/actor/MultiTimeout.h"
|
||||
|
@ -47,7 +47,10 @@
|
||||
namespace td {
|
||||
|
||||
OptionManager::OptionManager(Td *td)
|
||||
: td_(td), options_(td::make_unique<TsSeqKeyValue>()), option_pmc_(G()->td_db()->get_config_pmc_shared()) {
|
||||
: td_(td)
|
||||
, current_scheduler_id_(Scheduler::instance()->sched_id())
|
||||
, options_(td::make_unique<TsSeqKeyValue>())
|
||||
, option_pmc_(G()->td_db()->get_config_pmc_shared()) {
|
||||
send_unix_time_update();
|
||||
|
||||
auto all_options = option_pmc_->get_all();
|
||||
@ -65,7 +68,13 @@ OptionManager::OptionManager(Td *td)
|
||||
send_closure(G()->td(), &Td::send_update, get_update_suggested_actions_object(added_actions, {}));
|
||||
}
|
||||
} else if (name == "default_reaction") {
|
||||
send_update_default_reaction_type(get_option_string(name));
|
||||
auto value = get_option_string(name);
|
||||
if (value.empty()) {
|
||||
// legacy
|
||||
set_option_empty(name);
|
||||
} else {
|
||||
send_update_default_reaction_type(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -181,7 +190,7 @@ string OptionManager::get_option_string(Slice name, string default_value) const
|
||||
|
||||
void OptionManager::set_option(Slice name, Slice value) {
|
||||
CHECK(!name.empty());
|
||||
CHECK(Scheduler::instance()->sched_id() == 0);
|
||||
CHECK(Scheduler::instance()->sched_id() == current_scheduler_id_);
|
||||
if (value.empty()) {
|
||||
if (option_pmc_->erase(name.str()) == 0) {
|
||||
return;
|
||||
@ -226,16 +235,6 @@ void OptionManager::on_update_server_time_difference() {
|
||||
send_unix_time_update();
|
||||
}
|
||||
|
||||
void OptionManager::clear_options() {
|
||||
for (const auto &option : options_->get_all()) {
|
||||
if (!is_internal_option(option.first)) {
|
||||
send_closure(
|
||||
G()->td(), &Td::send_update,
|
||||
td_api::make_object<td_api::updateOption>(option.first, td_api::make_object<td_api::optionValueEmpty>()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool OptionManager::is_internal_option(Slice name) {
|
||||
switch (name[0]) {
|
||||
case 'a':
|
||||
@ -511,7 +510,7 @@ td_api::object_ptr<td_api::OptionValue> OptionManager::get_option_synchronously(
|
||||
break;
|
||||
case 'v':
|
||||
if (name == "version") {
|
||||
return td_api::make_object<td_api::optionValueString>("1.8.6");
|
||||
return td_api::make_object<td_api::optionValueString>("1.8.7");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -55,8 +55,6 @@ class OptionManager {
|
||||
|
||||
void set_option(const string &name, td_api::object_ptr<td_api::OptionValue> &&value, Promise<Unit> &&promise);
|
||||
|
||||
void clear_options();
|
||||
|
||||
static bool is_synchronous_option(Slice name);
|
||||
|
||||
static td_api::object_ptr<td_api::OptionValue> get_option_synchronously(Slice name);
|
||||
@ -86,6 +84,7 @@ class OptionManager {
|
||||
bool is_td_inited_ = false;
|
||||
vector<std::pair<string, Promise<td_api::object_ptr<td_api::OptionValue>>>> pending_get_options_;
|
||||
|
||||
int32 current_scheduler_id_ = -1;
|
||||
unique_ptr<TsSeqKeyValue> options_;
|
||||
std::shared_ptr<KeyValueSyncInterface> option_pmc_;
|
||||
|
||||
|
190
td/telegram/OrderInfo.cpp
Normal file
190
td/telegram/OrderInfo.cpp
Normal file
@ -0,0 +1,190 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#include "td/telegram/OrderInfo.h"
|
||||
|
||||
#include "td/telegram/misc.h"
|
||||
|
||||
#include "td/utils/format.h"
|
||||
#include "td/utils/JsonBuilder.h"
|
||||
|
||||
namespace td {
|
||||
|
||||
bool operator==(const Address &lhs, const Address &rhs) {
|
||||
return lhs.country_code == rhs.country_code && lhs.state == rhs.state && lhs.city == rhs.city &&
|
||||
lhs.street_line1 == rhs.street_line1 && lhs.street_line2 == rhs.street_line2 &&
|
||||
lhs.postal_code == rhs.postal_code;
|
||||
}
|
||||
|
||||
bool operator!=(const Address &lhs, const Address &rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
StringBuilder &operator<<(StringBuilder &string_builder, const Address &address) {
|
||||
return string_builder << "[Address " << tag("country_code", address.country_code) << tag("state", address.state)
|
||||
<< tag("city", address.city) << tag("street_line1", address.street_line1)
|
||||
<< tag("street_line2", address.street_line2) << tag("postal_code", address.postal_code) << "]";
|
||||
}
|
||||
|
||||
unique_ptr<Address> get_address(tl_object_ptr<telegram_api::postAddress> &&address) {
|
||||
if (address == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return td::make_unique<Address>(std::move(address->country_iso2_), std::move(address->state_),
|
||||
std::move(address->city_), std::move(address->street_line1_),
|
||||
std::move(address->street_line2_), std::move(address->post_code_));
|
||||
}
|
||||
|
||||
static bool is_capital_alpha(char c) {
|
||||
return 'A' <= c && c <= 'Z';
|
||||
}
|
||||
|
||||
Status check_country_code(string &country_code) {
|
||||
if (!clean_input_string(country_code)) {
|
||||
return Status::Error(400, "Country code must be encoded in UTF-8");
|
||||
}
|
||||
if (country_code.size() != 2 || !is_capital_alpha(country_code[0]) || !is_capital_alpha(country_code[1])) {
|
||||
return Status::Error(400, "Wrong country code specified");
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
static Status check_state(string &state) {
|
||||
if (!clean_input_string(state)) {
|
||||
return Status::Error(400, "State must be encoded in UTF-8");
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
static Status check_city(string &city) {
|
||||
if (!clean_input_string(city)) {
|
||||
return Status::Error(400, "City must be encoded in UTF-8");
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
static Status check_street_line(string &street_line) {
|
||||
if (!clean_input_string(street_line)) {
|
||||
return Status::Error(400, "Street line must be encoded in UTF-8");
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
static Status check_postal_code(string &postal_code) {
|
||||
if (!clean_input_string(postal_code)) {
|
||||
return Status::Error(400, "Postal code must be encoded in UTF-8");
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Result<Address> get_address(td_api::object_ptr<td_api::address> &&address) {
|
||||
if (address == nullptr) {
|
||||
return Status::Error(400, "Address must be non-empty");
|
||||
}
|
||||
TRY_STATUS(check_country_code(address->country_code_));
|
||||
TRY_STATUS(check_state(address->state_));
|
||||
TRY_STATUS(check_city(address->city_));
|
||||
TRY_STATUS(check_street_line(address->street_line1_));
|
||||
TRY_STATUS(check_street_line(address->street_line2_));
|
||||
TRY_STATUS(check_postal_code(address->postal_code_));
|
||||
|
||||
return Address(std::move(address->country_code_), std::move(address->state_), std::move(address->city_),
|
||||
std::move(address->street_line1_), std::move(address->street_line2_),
|
||||
std::move(address->postal_code_));
|
||||
}
|
||||
|
||||
tl_object_ptr<td_api::address> get_address_object(const unique_ptr<Address> &address) {
|
||||
if (address == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return get_address_object(*address);
|
||||
}
|
||||
|
||||
tl_object_ptr<td_api::address> get_address_object(const Address &address) {
|
||||
return make_tl_object<td_api::address>(address.country_code, address.state, address.city, address.street_line1,
|
||||
address.street_line2, address.postal_code);
|
||||
}
|
||||
|
||||
string address_to_json(const Address &address) {
|
||||
return json_encode<std::string>(json_object([&](auto &o) {
|
||||
o("country_code", address.country_code);
|
||||
o("state", address.state);
|
||||
o("city", address.city);
|
||||
o("street_line1", address.street_line1);
|
||||
o("street_line2", address.street_line2);
|
||||
o("post_code", address.postal_code);
|
||||
}));
|
||||
}
|
||||
|
||||
Result<Address> address_from_json(Slice json) {
|
||||
auto json_copy = json.str();
|
||||
auto r_value = json_decode(json_copy);
|
||||
if (r_value.is_error()) {
|
||||
return Status::Error(400, "Can't parse address JSON object");
|
||||
}
|
||||
|
||||
auto value = r_value.move_as_ok();
|
||||
if (value.type() != JsonValue::Type::Object) {
|
||||
return Status::Error(400, "Address must be an Object");
|
||||
}
|
||||
|
||||
auto &object = value.get_object();
|
||||
TRY_RESULT(country_code, get_json_object_string_field(object, "country_code", true));
|
||||
TRY_RESULT(state, get_json_object_string_field(object, "state", true));
|
||||
TRY_RESULT(city, get_json_object_string_field(object, "city", true));
|
||||
TRY_RESULT(street_line1, get_json_object_string_field(object, "street_line1", true));
|
||||
TRY_RESULT(street_line2, get_json_object_string_field(object, "street_line2", true));
|
||||
TRY_RESULT(postal_code, get_json_object_string_field(object, "post_code", true));
|
||||
|
||||
TRY_STATUS(check_country_code(country_code));
|
||||
TRY_STATUS(check_state(state));
|
||||
TRY_STATUS(check_city(city));
|
||||
TRY_STATUS(check_street_line(street_line1));
|
||||
TRY_STATUS(check_street_line(street_line2));
|
||||
TRY_STATUS(check_postal_code(postal_code));
|
||||
|
||||
return Address(std::move(country_code), std::move(state), std::move(city), std::move(street_line1),
|
||||
std::move(street_line2), std::move(postal_code));
|
||||
}
|
||||
|
||||
bool operator==(const OrderInfo &lhs, const OrderInfo &rhs) {
|
||||
return lhs.name == rhs.name && lhs.phone_number == rhs.phone_number && lhs.email_address == rhs.email_address &&
|
||||
((lhs.shipping_address == nullptr && rhs.shipping_address == nullptr) ||
|
||||
(lhs.shipping_address != nullptr && rhs.shipping_address != nullptr &&
|
||||
*lhs.shipping_address == *rhs.shipping_address));
|
||||
}
|
||||
|
||||
bool operator!=(const OrderInfo &lhs, const OrderInfo &rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
StringBuilder &operator<<(StringBuilder &string_builder, const OrderInfo &order_info) {
|
||||
string_builder << "[OrderInfo " << tag("name", order_info.name) << tag("phone_number", order_info.phone_number)
|
||||
<< tag("email_address", order_info.email_address);
|
||||
if (order_info.shipping_address != nullptr) {
|
||||
string_builder << *order_info.shipping_address;
|
||||
}
|
||||
return string_builder << "]";
|
||||
}
|
||||
|
||||
unique_ptr<OrderInfo> get_order_info(tl_object_ptr<telegram_api::paymentRequestedInfo> order_info) {
|
||||
if (order_info == nullptr || order_info->flags_ == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
return td::make_unique<OrderInfo>(std::move(order_info->name_), std::move(order_info->phone_),
|
||||
std::move(order_info->email_),
|
||||
get_address(std::move(order_info->shipping_address_)));
|
||||
}
|
||||
|
||||
tl_object_ptr<td_api::orderInfo> get_order_info_object(const unique_ptr<OrderInfo> &order_info) {
|
||||
if (order_info == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return make_tl_object<td_api::orderInfo>(order_info->name, order_info->phone_number, order_info->email_address,
|
||||
get_address_object(order_info->shipping_address));
|
||||
}
|
||||
|
||||
} // namespace td
|
82
td/telegram/OrderInfo.h
Normal file
82
td/telegram/OrderInfo.h
Normal file
@ -0,0 +1,82 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "td/telegram/td_api.h"
|
||||
#include "td/telegram/telegram_api.h"
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/Slice.h"
|
||||
#include "td/utils/Status.h"
|
||||
#include "td/utils/StringBuilder.h"
|
||||
|
||||
namespace td {
|
||||
|
||||
struct Address {
|
||||
string country_code;
|
||||
string state;
|
||||
string city;
|
||||
string street_line1;
|
||||
string street_line2;
|
||||
string postal_code;
|
||||
|
||||
Address() = default;
|
||||
Address(string &&country_code, string &&state, string &&city, string &&street_line1, string &&street_line2,
|
||||
string &&postal_code)
|
||||
: country_code(std::move(country_code))
|
||||
, state(std::move(state))
|
||||
, city(std::move(city))
|
||||
, street_line1(std::move(street_line1))
|
||||
, street_line2(std::move(street_line2))
|
||||
, postal_code(std::move(postal_code)) {
|
||||
}
|
||||
};
|
||||
|
||||
struct OrderInfo {
|
||||
string name;
|
||||
string phone_number;
|
||||
string email_address;
|
||||
unique_ptr<Address> shipping_address;
|
||||
|
||||
OrderInfo() = default;
|
||||
OrderInfo(string &&name, string &&phone_number, string &&email_address, unique_ptr<Address> &&shipping_address)
|
||||
: name(std::move(name))
|
||||
, phone_number(std::move(phone_number))
|
||||
, email_address(std::move(email_address))
|
||||
, shipping_address(std::move(shipping_address)) {
|
||||
}
|
||||
};
|
||||
|
||||
bool operator==(const Address &lhs, const Address &rhs);
|
||||
bool operator!=(const Address &lhs, const Address &rhs);
|
||||
|
||||
StringBuilder &operator<<(StringBuilder &string_builder, const Address &address);
|
||||
|
||||
unique_ptr<Address> get_address(tl_object_ptr<telegram_api::postAddress> &&address);
|
||||
|
||||
Result<Address> get_address(td_api::object_ptr<td_api::address> &&address);
|
||||
|
||||
tl_object_ptr<td_api::address> get_address_object(const unique_ptr<Address> &address);
|
||||
|
||||
tl_object_ptr<td_api::address> get_address_object(const Address &address);
|
||||
|
||||
string address_to_json(const Address &address);
|
||||
|
||||
Result<Address> address_from_json(Slice json);
|
||||
|
||||
Status check_country_code(string &country_code);
|
||||
|
||||
bool operator==(const OrderInfo &lhs, const OrderInfo &rhs);
|
||||
bool operator!=(const OrderInfo &lhs, const OrderInfo &rhs);
|
||||
|
||||
StringBuilder &operator<<(StringBuilder &string_builder, const OrderInfo &order_info);
|
||||
|
||||
unique_ptr<OrderInfo> get_order_info(tl_object_ptr<telegram_api::paymentRequestedInfo> order_info);
|
||||
|
||||
tl_object_ptr<td_api::orderInfo> get_order_info_object(const unique_ptr<OrderInfo> &order_info);
|
||||
|
||||
} // namespace td
|
87
td/telegram/OrderInfo.hpp
Normal file
87
td/telegram/OrderInfo.hpp
Normal file
@ -0,0 +1,87 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "td/telegram/OrderInfo.h"
|
||||
|
||||
#include "td/utils/tl_helpers.h"
|
||||
|
||||
namespace td {
|
||||
|
||||
template <class StorerT>
|
||||
void store(const Address &address, StorerT &storer) {
|
||||
store(address.country_code, storer);
|
||||
store(address.state, storer);
|
||||
store(address.city, storer);
|
||||
store(address.street_line1, storer);
|
||||
store(address.street_line2, storer);
|
||||
store(address.postal_code, storer);
|
||||
}
|
||||
|
||||
template <class ParserT>
|
||||
void parse(Address &address, ParserT &parser) {
|
||||
parse(address.country_code, parser);
|
||||
parse(address.state, parser);
|
||||
parse(address.city, parser);
|
||||
parse(address.street_line1, parser);
|
||||
parse(address.street_line2, parser);
|
||||
parse(address.postal_code, parser);
|
||||
}
|
||||
|
||||
template <class StorerT>
|
||||
void store(const OrderInfo &order_info, StorerT &storer) {
|
||||
bool has_name = !order_info.name.empty();
|
||||
bool has_phone_number = !order_info.phone_number.empty();
|
||||
bool has_email_address = !order_info.email_address.empty();
|
||||
bool has_shipping_address = order_info.shipping_address != nullptr;
|
||||
BEGIN_STORE_FLAGS();
|
||||
STORE_FLAG(has_name);
|
||||
STORE_FLAG(has_phone_number);
|
||||
STORE_FLAG(has_email_address);
|
||||
STORE_FLAG(has_shipping_address);
|
||||
END_STORE_FLAGS();
|
||||
if (has_name) {
|
||||
store(order_info.name, storer);
|
||||
}
|
||||
if (has_phone_number) {
|
||||
store(order_info.phone_number, storer);
|
||||
}
|
||||
if (has_email_address) {
|
||||
store(order_info.email_address, storer);
|
||||
}
|
||||
if (has_shipping_address) {
|
||||
store(order_info.shipping_address, storer);
|
||||
}
|
||||
}
|
||||
|
||||
template <class ParserT>
|
||||
void parse(OrderInfo &order_info, ParserT &parser) {
|
||||
bool has_name;
|
||||
bool has_phone_number;
|
||||
bool has_email_address;
|
||||
bool has_shipping_address;
|
||||
BEGIN_PARSE_FLAGS();
|
||||
PARSE_FLAG(has_name);
|
||||
PARSE_FLAG(has_phone_number);
|
||||
PARSE_FLAG(has_email_address);
|
||||
PARSE_FLAG(has_shipping_address);
|
||||
END_PARSE_FLAGS();
|
||||
if (has_name) {
|
||||
parse(order_info.name, parser);
|
||||
}
|
||||
if (has_phone_number) {
|
||||
parse(order_info.phone_number, parser);
|
||||
}
|
||||
if (has_email_address) {
|
||||
parse(order_info.email_address, parser);
|
||||
}
|
||||
if (has_shipping_address) {
|
||||
parse(order_info.shipping_address, parser);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace td
|
@ -8,42 +8,33 @@
|
||||
|
||||
#include "td/telegram/AccessRights.h"
|
||||
#include "td/telegram/ContactsManager.h"
|
||||
#include "td/telegram/Dimensions.h"
|
||||
#include "td/telegram/files/FileManager.h"
|
||||
#include "td/telegram/files/FileType.h"
|
||||
#include "td/telegram/DialogId.h"
|
||||
#include "td/telegram/Global.h"
|
||||
#include "td/telegram/InputInvoice.h"
|
||||
#include "td/telegram/MessageEntity.h"
|
||||
#include "td/telegram/MessageId.h"
|
||||
#include "td/telegram/MessagesManager.h"
|
||||
#include "td/telegram/misc.h"
|
||||
#include "td/telegram/PasswordManager.h"
|
||||
#include "td/telegram/PhotoSize.h"
|
||||
#include "td/telegram/Photo.h"
|
||||
#include "td/telegram/ServerMessageId.h"
|
||||
#include "td/telegram/Td.h"
|
||||
#include "td/telegram/telegram_api.h"
|
||||
#include "td/telegram/ThemeManager.h"
|
||||
#include "td/telegram/UpdatesManager.h"
|
||||
#include "td/telegram/UserId.h"
|
||||
|
||||
#include "td/utils/algorithm.h"
|
||||
#include "td/utils/buffer.h"
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/format.h"
|
||||
#include "td/utils/HttpUrl.h"
|
||||
#include "td/utils/JsonBuilder.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/MimeType.h"
|
||||
#include "td/utils/PathView.h"
|
||||
#include "td/utils/Status.h"
|
||||
|
||||
namespace td {
|
||||
|
||||
namespace {
|
||||
|
||||
static tl_object_ptr<td_api::formattedText> get_product_description_object(const string &description) {
|
||||
FormattedText result;
|
||||
result.text = description;
|
||||
result.entities = find_entities(result.text, true, true);
|
||||
return get_formatted_text_object(result, true, 0);
|
||||
}
|
||||
|
||||
struct InputInvoiceInfo {
|
||||
DialogId dialog_id_;
|
||||
telegram_api::object_ptr<telegram_api::InputInvoice> input_invoice_;
|
||||
@ -707,545 +698,6 @@ class GetBankCardInfoQuery final : public Td::ResultHandler {
|
||||
}
|
||||
};
|
||||
|
||||
bool operator==(const LabeledPricePart &lhs, const LabeledPricePart &rhs) {
|
||||
return lhs.label == rhs.label && lhs.amount == rhs.amount;
|
||||
}
|
||||
|
||||
bool operator!=(const LabeledPricePart &lhs, const LabeledPricePart &rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
StringBuilder &operator<<(StringBuilder &string_builder, const LabeledPricePart &labeled_price_part) {
|
||||
return string_builder << "[" << labeled_price_part.label << ": " << labeled_price_part.amount << "]";
|
||||
}
|
||||
|
||||
bool operator==(const Invoice &lhs, const Invoice &rhs) {
|
||||
return lhs.is_test == rhs.is_test && lhs.need_name == rhs.need_name &&
|
||||
lhs.need_phone_number == rhs.need_phone_number && lhs.need_email_address == rhs.need_email_address &&
|
||||
lhs.need_shipping_address == rhs.need_shipping_address &&
|
||||
lhs.send_phone_number_to_provider == rhs.send_phone_number_to_provider &&
|
||||
lhs.send_email_address_to_provider == rhs.send_email_address_to_provider &&
|
||||
lhs.is_flexible == rhs.is_flexible && lhs.currency == rhs.currency && lhs.price_parts == rhs.price_parts &&
|
||||
lhs.max_tip_amount == rhs.max_tip_amount && lhs.suggested_tip_amounts == rhs.suggested_tip_amounts &&
|
||||
lhs.recurring_payment_terms_of_service_url == rhs.recurring_payment_terms_of_service_url;
|
||||
}
|
||||
|
||||
bool operator!=(const Invoice &lhs, const Invoice &rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
StringBuilder &operator<<(StringBuilder &string_builder, const Invoice &invoice) {
|
||||
return string_builder << "[" << (invoice.is_flexible ? "Flexible" : "") << (invoice.is_test ? "Test" : "")
|
||||
<< "Invoice" << (invoice.need_name ? ", needs name" : "")
|
||||
<< (invoice.need_phone_number ? ", needs phone number" : "")
|
||||
<< (invoice.need_email_address ? ", needs email address" : "")
|
||||
<< (invoice.need_shipping_address ? ", needs shipping address" : "")
|
||||
<< (invoice.send_phone_number_to_provider ? ", sends phone number to provider" : "")
|
||||
<< (invoice.send_email_address_to_provider ? ", sends email address to provider" : "")
|
||||
<< (invoice.recurring_payment_terms_of_service_url.empty()
|
||||
? string()
|
||||
: ", recurring payments terms of service at " +
|
||||
invoice.recurring_payment_terms_of_service_url)
|
||||
<< " in " << invoice.currency << " with price parts " << format::as_array(invoice.price_parts)
|
||||
<< " and suggested tip amounts " << invoice.suggested_tip_amounts << " up to "
|
||||
<< invoice.max_tip_amount << "]";
|
||||
}
|
||||
|
||||
bool operator==(const InputInvoice &lhs, const InputInvoice &rhs) {
|
||||
return lhs.title == rhs.title && lhs.description == rhs.description && lhs.photo == rhs.photo &&
|
||||
lhs.start_parameter == rhs.start_parameter && lhs.invoice == rhs.invoice &&
|
||||
lhs.total_amount == rhs.total_amount && lhs.receipt_message_id == rhs.receipt_message_id &&
|
||||
lhs.payload == rhs.payload && lhs.provider_token == rhs.provider_token &&
|
||||
lhs.provider_data == rhs.provider_data;
|
||||
}
|
||||
|
||||
bool operator!=(const InputInvoice &lhs, const InputInvoice &rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
InputInvoice get_input_invoice(tl_object_ptr<telegram_api::messageMediaInvoice> &&message_invoice, Td *td,
|
||||
DialogId owner_dialog_id) {
|
||||
InputInvoice result;
|
||||
result.title = std::move(message_invoice->title_);
|
||||
result.description = std::move(message_invoice->description_);
|
||||
result.photo = get_web_document_photo(td->file_manager_.get(), std::move(message_invoice->photo_), owner_dialog_id);
|
||||
result.start_parameter = std::move(message_invoice->start_param_);
|
||||
result.invoice.currency = std::move(message_invoice->currency_);
|
||||
result.invoice.is_test = message_invoice->test_;
|
||||
result.invoice.need_shipping_address = message_invoice->shipping_address_requested_;
|
||||
// result.payload = string();
|
||||
// result.provider_token = string();
|
||||
// result.provider_data = string();
|
||||
if (message_invoice->total_amount_ <= 0 || !check_currency_amount(message_invoice->total_amount_)) {
|
||||
LOG(ERROR) << "Receive invalid total amount " << message_invoice->total_amount_;
|
||||
message_invoice->total_amount_ = 0;
|
||||
}
|
||||
result.total_amount = message_invoice->total_amount_;
|
||||
if ((message_invoice->flags_ & telegram_api::messageMediaInvoice::RECEIPT_MSG_ID_MASK) != 0) {
|
||||
result.receipt_message_id = MessageId(ServerMessageId(message_invoice->receipt_msg_id_));
|
||||
if (!result.receipt_message_id.is_valid()) {
|
||||
LOG(ERROR) << "Receive as receipt message " << result.receipt_message_id << " in " << owner_dialog_id;
|
||||
result.receipt_message_id = MessageId();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
InputInvoice get_input_invoice(tl_object_ptr<telegram_api::botInlineMessageMediaInvoice> &&message_invoice, Td *td,
|
||||
DialogId owner_dialog_id) {
|
||||
InputInvoice result;
|
||||
result.title = std::move(message_invoice->title_);
|
||||
result.description = std::move(message_invoice->description_);
|
||||
result.photo = get_web_document_photo(td->file_manager_.get(), std::move(message_invoice->photo_), owner_dialog_id);
|
||||
// result.start_parameter = string();
|
||||
result.invoice.currency = std::move(message_invoice->currency_);
|
||||
result.invoice.is_test = message_invoice->test_;
|
||||
result.invoice.need_shipping_address = message_invoice->shipping_address_requested_;
|
||||
// result.payload = string();
|
||||
// result.provider_token = string();
|
||||
// result.provider_data = string();
|
||||
if (message_invoice->total_amount_ <= 0 || !check_currency_amount(message_invoice->total_amount_)) {
|
||||
LOG(ERROR) << "Receive invalid total amount " << message_invoice->total_amount_;
|
||||
message_invoice->total_amount_ = 0;
|
||||
}
|
||||
result.total_amount = message_invoice->total_amount_;
|
||||
// result.receipt_message_id = MessageId();
|
||||
return result;
|
||||
}
|
||||
|
||||
Result<InputInvoice> process_input_message_invoice(
|
||||
td_api::object_ptr<td_api::InputMessageContent> &&input_message_content, Td *td) {
|
||||
CHECK(input_message_content != nullptr);
|
||||
CHECK(input_message_content->get_id() == td_api::inputMessageInvoice::ID);
|
||||
auto input_invoice = move_tl_object_as<td_api::inputMessageInvoice>(input_message_content);
|
||||
if (input_invoice->invoice_ == nullptr) {
|
||||
return Status::Error(400, "Invoice must be non-empty");
|
||||
}
|
||||
|
||||
if (!clean_input_string(input_invoice->title_)) {
|
||||
return Status::Error(400, "Invoice title must be encoded in UTF-8");
|
||||
}
|
||||
if (!clean_input_string(input_invoice->description_)) {
|
||||
return Status::Error(400, "Invoice description must be encoded in UTF-8");
|
||||
}
|
||||
if (!clean_input_string(input_invoice->photo_url_)) {
|
||||
return Status::Error(400, "Invoice photo URL must be encoded in UTF-8");
|
||||
}
|
||||
if (!clean_input_string(input_invoice->start_parameter_)) {
|
||||
return Status::Error(400, "Invoice bot start parameter must be encoded in UTF-8");
|
||||
}
|
||||
if (!clean_input_string(input_invoice->provider_token_)) {
|
||||
return Status::Error(400, "Invoice provider token must be encoded in UTF-8");
|
||||
}
|
||||
if (!clean_input_string(input_invoice->provider_data_)) {
|
||||
return Status::Error(400, "Invoice provider data must be encoded in UTF-8");
|
||||
}
|
||||
if (!clean_input_string(input_invoice->invoice_->currency_)) {
|
||||
return Status::Error(400, "Invoice currency must be encoded in UTF-8");
|
||||
}
|
||||
|
||||
InputInvoice result;
|
||||
result.title = std::move(input_invoice->title_);
|
||||
result.description = std::move(input_invoice->description_);
|
||||
|
||||
auto r_http_url = parse_url(input_invoice->photo_url_);
|
||||
if (r_http_url.is_error()) {
|
||||
if (!input_invoice->photo_url_.empty()) {
|
||||
LOG(INFO) << "Can't register url " << input_invoice->photo_url_;
|
||||
}
|
||||
} else {
|
||||
auto url = r_http_url.ok().get_url();
|
||||
auto r_invoice_file_id = td->file_manager_->from_persistent_id(url, FileType::Temp);
|
||||
if (r_invoice_file_id.is_error()) {
|
||||
LOG(INFO) << "Can't register url " << url;
|
||||
} else {
|
||||
auto invoice_file_id = r_invoice_file_id.move_as_ok();
|
||||
|
||||
PhotoSize s;
|
||||
s.type = 'n';
|
||||
s.dimensions = get_dimensions(input_invoice->photo_width_, input_invoice->photo_height_, nullptr);
|
||||
s.size = input_invoice->photo_size_; // TODO use invoice_file_id size
|
||||
s.file_id = invoice_file_id;
|
||||
|
||||
result.photo.id = 0;
|
||||
result.photo.photos.push_back(s);
|
||||
}
|
||||
}
|
||||
result.start_parameter = std::move(input_invoice->start_parameter_);
|
||||
|
||||
result.invoice.currency = std::move(input_invoice->invoice_->currency_);
|
||||
result.invoice.price_parts.reserve(input_invoice->invoice_->price_parts_.size());
|
||||
int64 total_amount = 0;
|
||||
for (auto &price : input_invoice->invoice_->price_parts_) {
|
||||
if (!clean_input_string(price->label_)) {
|
||||
return Status::Error(400, "Invoice price label must be encoded in UTF-8");
|
||||
}
|
||||
if (!check_currency_amount(price->amount_)) {
|
||||
return Status::Error(400, "Too big amount of the currency specified");
|
||||
}
|
||||
result.invoice.price_parts.emplace_back(std::move(price->label_), price->amount_);
|
||||
total_amount += price->amount_;
|
||||
}
|
||||
if (total_amount <= 0) {
|
||||
return Status::Error(400, "Total price must be positive");
|
||||
}
|
||||
if (!check_currency_amount(total_amount)) {
|
||||
return Status::Error(400, "Total price is too big");
|
||||
}
|
||||
result.total_amount = total_amount;
|
||||
|
||||
if (input_invoice->invoice_->max_tip_amount_ < 0 ||
|
||||
!check_currency_amount(input_invoice->invoice_->max_tip_amount_)) {
|
||||
return Status::Error(400, "Invalid max_tip_amount of the currency specified");
|
||||
}
|
||||
for (auto tip_amount : input_invoice->invoice_->suggested_tip_amounts_) {
|
||||
if (tip_amount <= 0) {
|
||||
return Status::Error(400, "Suggested tip amount must be positive");
|
||||
}
|
||||
if (tip_amount > input_invoice->invoice_->max_tip_amount_) {
|
||||
return Status::Error(400, "Suggested tip amount can't be bigger than max_tip_amount");
|
||||
}
|
||||
}
|
||||
if (input_invoice->invoice_->suggested_tip_amounts_.size() > 4) {
|
||||
return Status::Error(400, "There can be at most 4 suggested tip amounts");
|
||||
}
|
||||
|
||||
result.invoice.max_tip_amount = input_invoice->invoice_->max_tip_amount_;
|
||||
result.invoice.suggested_tip_amounts = std::move(input_invoice->invoice_->suggested_tip_amounts_);
|
||||
result.invoice.recurring_payment_terms_of_service_url =
|
||||
std::move(input_invoice->invoice_->recurring_payment_terms_of_service_url_);
|
||||
result.invoice.is_test = input_invoice->invoice_->is_test_;
|
||||
result.invoice.need_name = input_invoice->invoice_->need_name_;
|
||||
result.invoice.need_phone_number = input_invoice->invoice_->need_phone_number_;
|
||||
result.invoice.need_email_address = input_invoice->invoice_->need_email_address_;
|
||||
result.invoice.need_shipping_address = input_invoice->invoice_->need_shipping_address_;
|
||||
result.invoice.send_phone_number_to_provider = input_invoice->invoice_->send_phone_number_to_provider_;
|
||||
result.invoice.send_email_address_to_provider = input_invoice->invoice_->send_email_address_to_provider_;
|
||||
result.invoice.is_flexible = input_invoice->invoice_->is_flexible_;
|
||||
if (result.invoice.send_phone_number_to_provider) {
|
||||
result.invoice.need_phone_number = true;
|
||||
}
|
||||
if (result.invoice.send_email_address_to_provider) {
|
||||
result.invoice.need_email_address = true;
|
||||
}
|
||||
if (result.invoice.is_flexible) {
|
||||
result.invoice.need_shipping_address = true;
|
||||
}
|
||||
|
||||
result.payload = std::move(input_invoice->payload_);
|
||||
result.provider_token = std::move(input_invoice->provider_token_);
|
||||
result.provider_data = std::move(input_invoice->provider_data_);
|
||||
return result;
|
||||
}
|
||||
|
||||
tl_object_ptr<td_api::messageInvoice> get_message_invoice_object(const InputInvoice &input_invoice, Td *td) {
|
||||
return make_tl_object<td_api::messageInvoice>(
|
||||
input_invoice.title, get_product_description_object(input_invoice.description),
|
||||
get_photo_object(td->file_manager_.get(), input_invoice.photo), input_invoice.invoice.currency,
|
||||
input_invoice.total_amount, input_invoice.start_parameter, input_invoice.invoice.is_test,
|
||||
input_invoice.invoice.need_shipping_address, input_invoice.receipt_message_id.get());
|
||||
}
|
||||
|
||||
static tl_object_ptr<telegram_api::invoice> get_input_invoice(const Invoice &invoice) {
|
||||
int32 flags = 0;
|
||||
if (invoice.is_test) {
|
||||
flags |= telegram_api::invoice::TEST_MASK;
|
||||
}
|
||||
if (invoice.need_name) {
|
||||
flags |= telegram_api::invoice::NAME_REQUESTED_MASK;
|
||||
}
|
||||
if (invoice.need_phone_number) {
|
||||
flags |= telegram_api::invoice::PHONE_REQUESTED_MASK;
|
||||
}
|
||||
if (invoice.need_email_address) {
|
||||
flags |= telegram_api::invoice::EMAIL_REQUESTED_MASK;
|
||||
}
|
||||
if (invoice.need_shipping_address) {
|
||||
flags |= telegram_api::invoice::SHIPPING_ADDRESS_REQUESTED_MASK;
|
||||
}
|
||||
if (invoice.send_phone_number_to_provider) {
|
||||
flags |= telegram_api::invoice::PHONE_TO_PROVIDER_MASK;
|
||||
}
|
||||
if (invoice.send_email_address_to_provider) {
|
||||
flags |= telegram_api::invoice::EMAIL_TO_PROVIDER_MASK;
|
||||
}
|
||||
if (invoice.is_flexible) {
|
||||
flags |= telegram_api::invoice::FLEXIBLE_MASK;
|
||||
}
|
||||
if (invoice.max_tip_amount != 0) {
|
||||
flags |= telegram_api::invoice::MAX_TIP_AMOUNT_MASK;
|
||||
}
|
||||
if (!invoice.recurring_payment_terms_of_service_url.empty()) {
|
||||
flags |= telegram_api::invoice::RECURRING_TERMS_URL_MASK;
|
||||
}
|
||||
|
||||
auto prices = transform(invoice.price_parts, [](const LabeledPricePart &price) {
|
||||
return telegram_api::make_object<telegram_api::labeledPrice>(price.label, price.amount);
|
||||
});
|
||||
return make_tl_object<telegram_api::invoice>(
|
||||
flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/,
|
||||
false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, invoice.currency, std::move(prices),
|
||||
invoice.max_tip_amount, vector<int64>(invoice.suggested_tip_amounts),
|
||||
invoice.recurring_payment_terms_of_service_url);
|
||||
}
|
||||
|
||||
static tl_object_ptr<telegram_api::inputWebDocument> get_input_web_document(const FileManager *file_manager,
|
||||
const Photo &photo) {
|
||||
if (photo.is_empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CHECK(photo.photos.size() == 1);
|
||||
const PhotoSize &size = photo.photos[0];
|
||||
CHECK(size.file_id.is_valid());
|
||||
|
||||
vector<tl_object_ptr<telegram_api::DocumentAttribute>> attributes;
|
||||
if (size.dimensions.width != 0 && size.dimensions.height != 0) {
|
||||
attributes.push_back(
|
||||
make_tl_object<telegram_api::documentAttributeImageSize>(size.dimensions.width, size.dimensions.height));
|
||||
}
|
||||
|
||||
auto file_view = file_manager->get_file_view(size.file_id);
|
||||
CHECK(file_view.has_url());
|
||||
|
||||
auto file_name = get_url_file_name(file_view.url());
|
||||
return make_tl_object<telegram_api::inputWebDocument>(
|
||||
file_view.url(), size.size, MimeType::from_extension(PathView(file_name).extension(), "image/jpeg"),
|
||||
std::move(attributes));
|
||||
}
|
||||
|
||||
tl_object_ptr<telegram_api::inputMediaInvoice> get_input_media_invoice(const InputInvoice &input_invoice, Td *td) {
|
||||
int32 flags = 0;
|
||||
if (!input_invoice.start_parameter.empty()) {
|
||||
flags |= telegram_api::inputMediaInvoice::START_PARAM_MASK;
|
||||
}
|
||||
auto input_web_document = get_input_web_document(td->file_manager_.get(), input_invoice.photo);
|
||||
if (input_web_document != nullptr) {
|
||||
flags |= telegram_api::inputMediaInvoice::PHOTO_MASK;
|
||||
}
|
||||
|
||||
return make_tl_object<telegram_api::inputMediaInvoice>(
|
||||
flags, input_invoice.title, input_invoice.description, std::move(input_web_document),
|
||||
get_input_invoice(input_invoice.invoice), BufferSlice(input_invoice.payload), input_invoice.provider_token,
|
||||
telegram_api::make_object<telegram_api::dataJSON>(
|
||||
input_invoice.provider_data.empty() ? "null" : input_invoice.provider_data),
|
||||
input_invoice.start_parameter);
|
||||
}
|
||||
|
||||
tl_object_ptr<telegram_api::inputBotInlineMessageMediaInvoice> get_input_bot_inline_message_media_invoice(
|
||||
const InputInvoice &input_invoice, tl_object_ptr<telegram_api::ReplyMarkup> &&reply_markup, Td *td) {
|
||||
int32 flags = 0;
|
||||
if (reply_markup != nullptr) {
|
||||
flags |= telegram_api::inputBotInlineMessageMediaInvoice::REPLY_MARKUP_MASK;
|
||||
}
|
||||
auto input_web_document = get_input_web_document(td->file_manager_.get(), input_invoice.photo);
|
||||
if (input_web_document != nullptr) {
|
||||
flags |= telegram_api::inputBotInlineMessageMediaInvoice::PHOTO_MASK;
|
||||
}
|
||||
return make_tl_object<telegram_api::inputBotInlineMessageMediaInvoice>(
|
||||
flags, input_invoice.title, input_invoice.description, std::move(input_web_document),
|
||||
get_input_invoice(input_invoice.invoice), BufferSlice(input_invoice.payload), input_invoice.provider_token,
|
||||
telegram_api::make_object<telegram_api::dataJSON>(
|
||||
input_invoice.provider_data.empty() ? "null" : input_invoice.provider_data),
|
||||
std::move(reply_markup));
|
||||
}
|
||||
|
||||
vector<FileId> get_input_invoice_file_ids(const InputInvoice &input_invoice) {
|
||||
return photo_get_file_ids(input_invoice.photo);
|
||||
}
|
||||
|
||||
bool operator==(const Address &lhs, const Address &rhs) {
|
||||
return lhs.country_code == rhs.country_code && lhs.state == rhs.state && lhs.city == rhs.city &&
|
||||
lhs.street_line1 == rhs.street_line1 && lhs.street_line2 == rhs.street_line2 &&
|
||||
lhs.postal_code == rhs.postal_code;
|
||||
}
|
||||
|
||||
bool operator!=(const Address &lhs, const Address &rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
StringBuilder &operator<<(StringBuilder &string_builder, const Address &address) {
|
||||
return string_builder << "[Address " << tag("country_code", address.country_code) << tag("state", address.state)
|
||||
<< tag("city", address.city) << tag("street_line1", address.street_line1)
|
||||
<< tag("street_line2", address.street_line2) << tag("postal_code", address.postal_code) << "]";
|
||||
}
|
||||
|
||||
unique_ptr<Address> get_address(tl_object_ptr<telegram_api::postAddress> &&address) {
|
||||
if (address == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return td::make_unique<Address>(std::move(address->country_iso2_), std::move(address->state_),
|
||||
std::move(address->city_), std::move(address->street_line1_),
|
||||
std::move(address->street_line2_), std::move(address->post_code_));
|
||||
}
|
||||
|
||||
static bool is_capital_alpha(char c) {
|
||||
return 'A' <= c && c <= 'Z';
|
||||
}
|
||||
|
||||
Status check_country_code(string &country_code) {
|
||||
if (!clean_input_string(country_code)) {
|
||||
return Status::Error(400, "Country code must be encoded in UTF-8");
|
||||
}
|
||||
if (country_code.size() != 2 || !is_capital_alpha(country_code[0]) || !is_capital_alpha(country_code[1])) {
|
||||
return Status::Error(400, "Wrong country code specified");
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
static Status check_state(string &state) {
|
||||
if (!clean_input_string(state)) {
|
||||
return Status::Error(400, "State must be encoded in UTF-8");
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
static Status check_city(string &city) {
|
||||
if (!clean_input_string(city)) {
|
||||
return Status::Error(400, "City must be encoded in UTF-8");
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
static Status check_street_line(string &street_line) {
|
||||
if (!clean_input_string(street_line)) {
|
||||
return Status::Error(400, "Street line must be encoded in UTF-8");
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
static Status check_postal_code(string &postal_code) {
|
||||
if (!clean_input_string(postal_code)) {
|
||||
return Status::Error(400, "Postal code must be encoded in UTF-8");
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Result<Address> get_address(td_api::object_ptr<td_api::address> &&address) {
|
||||
if (address == nullptr) {
|
||||
return Status::Error(400, "Address must be non-empty");
|
||||
}
|
||||
TRY_STATUS(check_country_code(address->country_code_));
|
||||
TRY_STATUS(check_state(address->state_));
|
||||
TRY_STATUS(check_city(address->city_));
|
||||
TRY_STATUS(check_street_line(address->street_line1_));
|
||||
TRY_STATUS(check_street_line(address->street_line2_));
|
||||
TRY_STATUS(check_postal_code(address->postal_code_));
|
||||
|
||||
return Address(std::move(address->country_code_), std::move(address->state_), std::move(address->city_),
|
||||
std::move(address->street_line1_), std::move(address->street_line2_),
|
||||
std::move(address->postal_code_));
|
||||
}
|
||||
|
||||
tl_object_ptr<td_api::address> get_address_object(const unique_ptr<Address> &address) {
|
||||
if (address == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return get_address_object(*address);
|
||||
}
|
||||
|
||||
tl_object_ptr<td_api::address> get_address_object(const Address &address) {
|
||||
return make_tl_object<td_api::address>(address.country_code, address.state, address.city, address.street_line1,
|
||||
address.street_line2, address.postal_code);
|
||||
}
|
||||
|
||||
string address_to_json(const Address &address) {
|
||||
return json_encode<std::string>(json_object([&](auto &o) {
|
||||
o("country_code", address.country_code);
|
||||
o("state", address.state);
|
||||
o("city", address.city);
|
||||
o("street_line1", address.street_line1);
|
||||
o("street_line2", address.street_line2);
|
||||
o("post_code", address.postal_code);
|
||||
}));
|
||||
}
|
||||
|
||||
Result<Address> address_from_json(Slice json) {
|
||||
auto json_copy = json.str();
|
||||
auto r_value = json_decode(json_copy);
|
||||
if (r_value.is_error()) {
|
||||
return Status::Error(400, "Can't parse address JSON object");
|
||||
}
|
||||
|
||||
auto value = r_value.move_as_ok();
|
||||
if (value.type() != JsonValue::Type::Object) {
|
||||
return Status::Error(400, "Address must be an Object");
|
||||
}
|
||||
|
||||
auto &object = value.get_object();
|
||||
TRY_RESULT(country_code, get_json_object_string_field(object, "country_code", true));
|
||||
TRY_RESULT(state, get_json_object_string_field(object, "state", true));
|
||||
TRY_RESULT(city, get_json_object_string_field(object, "city", true));
|
||||
TRY_RESULT(street_line1, get_json_object_string_field(object, "street_line1", true));
|
||||
TRY_RESULT(street_line2, get_json_object_string_field(object, "street_line2", true));
|
||||
TRY_RESULT(postal_code, get_json_object_string_field(object, "post_code", true));
|
||||
|
||||
TRY_STATUS(check_country_code(country_code));
|
||||
TRY_STATUS(check_state(state));
|
||||
TRY_STATUS(check_city(city));
|
||||
TRY_STATUS(check_street_line(street_line1));
|
||||
TRY_STATUS(check_street_line(street_line2));
|
||||
TRY_STATUS(check_postal_code(postal_code));
|
||||
|
||||
return Address(std::move(country_code), std::move(state), std::move(city), std::move(street_line1),
|
||||
std::move(street_line2), std::move(postal_code));
|
||||
}
|
||||
|
||||
bool operator==(const OrderInfo &lhs, const OrderInfo &rhs) {
|
||||
return lhs.name == rhs.name && lhs.phone_number == rhs.phone_number && lhs.email_address == rhs.email_address &&
|
||||
((lhs.shipping_address == nullptr && rhs.shipping_address == nullptr) ||
|
||||
(lhs.shipping_address != nullptr && rhs.shipping_address != nullptr &&
|
||||
*lhs.shipping_address == *rhs.shipping_address));
|
||||
}
|
||||
|
||||
bool operator!=(const OrderInfo &lhs, const OrderInfo &rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
StringBuilder &operator<<(StringBuilder &string_builder, const OrderInfo &order_info) {
|
||||
string_builder << "[OrderInfo " << tag("name", order_info.name) << tag("phone_number", order_info.phone_number)
|
||||
<< tag("email_address", order_info.email_address);
|
||||
if (order_info.shipping_address != nullptr) {
|
||||
string_builder << *order_info.shipping_address;
|
||||
}
|
||||
return string_builder << "]";
|
||||
}
|
||||
|
||||
unique_ptr<OrderInfo> get_order_info(tl_object_ptr<telegram_api::paymentRequestedInfo> order_info) {
|
||||
if (order_info == nullptr || order_info->flags_ == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
return td::make_unique<OrderInfo>(std::move(order_info->name_), std::move(order_info->phone_),
|
||||
std::move(order_info->email_),
|
||||
get_address(std::move(order_info->shipping_address_)));
|
||||
}
|
||||
|
||||
tl_object_ptr<td_api::orderInfo> get_order_info_object(const unique_ptr<OrderInfo> &order_info) {
|
||||
if (order_info == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return make_tl_object<td_api::orderInfo>(order_info->name, order_info->phone_number, order_info->email_address,
|
||||
get_address_object(order_info->shipping_address));
|
||||
}
|
||||
|
||||
bool operator==(const ShippingOption &lhs, const ShippingOption &rhs) {
|
||||
return lhs.id == rhs.id && lhs.title == rhs.title && lhs.price_parts == rhs.price_parts;
|
||||
}
|
||||
|
||||
bool operator!=(const ShippingOption &lhs, const ShippingOption &rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
StringBuilder &operator<<(StringBuilder &string_builder, const ShippingOption &shipping_option) {
|
||||
return string_builder << "[ShippingOption " << shipping_option.id << " " << shipping_option.title
|
||||
<< " with price parts " << format::as_array(shipping_option.price_parts) << "]";
|
||||
}
|
||||
|
||||
bool check_currency_amount(int64 amount) {
|
||||
constexpr int64 MAX_AMOUNT = 9999'9999'9999;
|
||||
return -MAX_AMOUNT <= amount && amount <= MAX_AMOUNT;
|
||||
}
|
||||
|
||||
void answer_shipping_query(Td *td, int64 shipping_query_id,
|
||||
vector<tl_object_ptr<td_api::shippingOption>> &&shipping_options,
|
||||
const string &error_message, Promise<Unit> &&promise) {
|
||||
@ -1427,8 +879,11 @@ void export_invoice(Td *td, td_api::object_ptr<td_api::InputMessageContent> &&in
|
||||
if (invoice == nullptr) {
|
||||
return promise.set_error(Status::Error(400, "Invoice must be non-empty"));
|
||||
}
|
||||
TRY_RESULT_PROMISE(promise, input_invoice, process_input_message_invoice(std::move(invoice), td));
|
||||
td->create_handler<ExportInvoiceQuery>(std::move(promise))->send(get_input_media_invoice(input_invoice, td));
|
||||
TRY_RESULT_PROMISE(promise, input_invoice,
|
||||
InputInvoice::process_input_message_invoice(std::move(invoice), td, DialogId(), false));
|
||||
auto input_media = input_invoice.get_input_media_invoice(td, nullptr, nullptr);
|
||||
CHECK(input_media != nullptr);
|
||||
td->create_handler<ExportInvoiceQuery>(std::move(promise))->send(std::move(input_media));
|
||||
}
|
||||
|
||||
void get_bank_card_info(Td *td, const string &bank_card_number,
|
||||
|
@ -6,175 +6,17 @@
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "td/telegram/DialogId.h"
|
||||
#include "td/telegram/files/FileId.h"
|
||||
#include "td/telegram/FullMessageId.h"
|
||||
#include "td/telegram/MessageId.h"
|
||||
#include "td/telegram/Photo.h"
|
||||
#include "td/telegram/td_api.h"
|
||||
#include "td/telegram/telegram_api.h"
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/Promise.h"
|
||||
#include "td/utils/Slice.h"
|
||||
#include "td/utils/Status.h"
|
||||
#include "td/utils/StringBuilder.h"
|
||||
|
||||
namespace td {
|
||||
|
||||
class Td;
|
||||
|
||||
struct LabeledPricePart {
|
||||
string label;
|
||||
int64 amount = 0;
|
||||
|
||||
LabeledPricePart() = default;
|
||||
LabeledPricePart(string &&label, int64 amount) : label(std::move(label)), amount(amount) {
|
||||
}
|
||||
};
|
||||
|
||||
struct Invoice {
|
||||
string currency;
|
||||
vector<LabeledPricePart> price_parts;
|
||||
int64 max_tip_amount = 0;
|
||||
vector<int64> suggested_tip_amounts;
|
||||
string recurring_payment_terms_of_service_url;
|
||||
bool is_test = false;
|
||||
bool need_name = false;
|
||||
bool need_phone_number = false;
|
||||
bool need_email_address = false;
|
||||
bool need_shipping_address = false;
|
||||
bool send_phone_number_to_provider = false;
|
||||
bool send_email_address_to_provider = false;
|
||||
bool is_flexible = false;
|
||||
|
||||
Invoice() = default;
|
||||
Invoice(string &¤cy, bool is_test, bool need_shipping_address)
|
||||
: currency(std::move(currency)), is_test(is_test), need_shipping_address(need_shipping_address) {
|
||||
}
|
||||
};
|
||||
|
||||
struct InputInvoice {
|
||||
string title;
|
||||
string description;
|
||||
Photo photo;
|
||||
string start_parameter;
|
||||
Invoice invoice;
|
||||
string payload;
|
||||
string provider_token;
|
||||
string provider_data;
|
||||
|
||||
int64 total_amount = 0;
|
||||
MessageId receipt_message_id;
|
||||
};
|
||||
|
||||
struct Address {
|
||||
string country_code;
|
||||
string state;
|
||||
string city;
|
||||
string street_line1;
|
||||
string street_line2;
|
||||
string postal_code;
|
||||
|
||||
Address() = default;
|
||||
Address(string &&country_code, string &&state, string &&city, string &&street_line1, string &&street_line2,
|
||||
string &&postal_code)
|
||||
: country_code(std::move(country_code))
|
||||
, state(std::move(state))
|
||||
, city(std::move(city))
|
||||
, street_line1(std::move(street_line1))
|
||||
, street_line2(std::move(street_line2))
|
||||
, postal_code(std::move(postal_code)) {
|
||||
}
|
||||
};
|
||||
|
||||
struct OrderInfo {
|
||||
string name;
|
||||
string phone_number;
|
||||
string email_address;
|
||||
unique_ptr<Address> shipping_address;
|
||||
|
||||
OrderInfo() = default;
|
||||
OrderInfo(string &&name, string &&phone_number, string &&email_address, unique_ptr<Address> &&shipping_address)
|
||||
: name(std::move(name))
|
||||
, phone_number(std::move(phone_number))
|
||||
, email_address(std::move(email_address))
|
||||
, shipping_address(std::move(shipping_address)) {
|
||||
}
|
||||
};
|
||||
|
||||
struct ShippingOption {
|
||||
string id;
|
||||
string title;
|
||||
vector<LabeledPricePart> price_parts;
|
||||
};
|
||||
|
||||
bool operator==(const LabeledPricePart &lhs, const LabeledPricePart &rhs);
|
||||
bool operator!=(const LabeledPricePart &lhs, const LabeledPricePart &rhs);
|
||||
|
||||
StringBuilder &operator<<(StringBuilder &string_builder, const LabeledPricePart &labeled_price_part);
|
||||
|
||||
bool operator==(const Invoice &lhs, const Invoice &rhs);
|
||||
bool operator!=(const Invoice &lhs, const Invoice &rhs);
|
||||
|
||||
StringBuilder &operator<<(StringBuilder &string_builder, const Invoice &invoice);
|
||||
|
||||
bool operator==(const InputInvoice &lhs, const InputInvoice &rhs);
|
||||
bool operator!=(const InputInvoice &lhs, const InputInvoice &rhs);
|
||||
|
||||
InputInvoice get_input_invoice(tl_object_ptr<telegram_api::messageMediaInvoice> &&message_invoice, Td *td,
|
||||
DialogId owner_dialog_id);
|
||||
|
||||
InputInvoice get_input_invoice(tl_object_ptr<telegram_api::botInlineMessageMediaInvoice> &&message_invoice, Td *td,
|
||||
DialogId owner_dialog_id);
|
||||
|
||||
Result<InputInvoice> process_input_message_invoice(
|
||||
td_api::object_ptr<td_api::InputMessageContent> &&input_message_content, Td *td);
|
||||
|
||||
tl_object_ptr<td_api::messageInvoice> get_message_invoice_object(const InputInvoice &input_invoice, Td *td);
|
||||
|
||||
tl_object_ptr<telegram_api::inputMediaInvoice> get_input_media_invoice(const InputInvoice &input_invoice, Td *td);
|
||||
|
||||
tl_object_ptr<telegram_api::inputBotInlineMessageMediaInvoice> get_input_bot_inline_message_media_invoice(
|
||||
const InputInvoice &input_invoice, tl_object_ptr<telegram_api::ReplyMarkup> &&reply_markup, Td *td);
|
||||
|
||||
vector<FileId> get_input_invoice_file_ids(const InputInvoice &input_invoice);
|
||||
|
||||
bool operator==(const Address &lhs, const Address &rhs);
|
||||
bool operator!=(const Address &lhs, const Address &rhs);
|
||||
|
||||
StringBuilder &operator<<(StringBuilder &string_builder, const Address &address);
|
||||
|
||||
unique_ptr<Address> get_address(tl_object_ptr<telegram_api::postAddress> &&address);
|
||||
|
||||
Result<Address> get_address(td_api::object_ptr<td_api::address> &&address);
|
||||
|
||||
tl_object_ptr<td_api::address> get_address_object(const unique_ptr<Address> &address);
|
||||
|
||||
tl_object_ptr<td_api::address> get_address_object(const Address &address);
|
||||
|
||||
string address_to_json(const Address &address);
|
||||
|
||||
Result<Address> address_from_json(Slice json);
|
||||
|
||||
Status check_country_code(string &country_code);
|
||||
|
||||
bool operator==(const OrderInfo &lhs, const OrderInfo &rhs);
|
||||
bool operator!=(const OrderInfo &lhs, const OrderInfo &rhs);
|
||||
|
||||
StringBuilder &operator<<(StringBuilder &string_builder, const OrderInfo &order_info);
|
||||
|
||||
unique_ptr<OrderInfo> get_order_info(tl_object_ptr<telegram_api::paymentRequestedInfo> order_info);
|
||||
|
||||
tl_object_ptr<td_api::orderInfo> get_order_info_object(const unique_ptr<OrderInfo> &order_info);
|
||||
|
||||
bool operator==(const ShippingOption &lhs, const ShippingOption &rhs);
|
||||
bool operator!=(const ShippingOption &lhs, const ShippingOption &rhs);
|
||||
|
||||
StringBuilder &operator<<(StringBuilder &string_builder, const ShippingOption &shipping_option);
|
||||
|
||||
bool check_currency_amount(int64 amount);
|
||||
|
||||
void answer_shipping_query(Td *td, int64 shipping_query_id,
|
||||
vector<tl_object_ptr<td_api::shippingOption>> &&shipping_options,
|
||||
const string &error_message, Promise<Unit> &&promise);
|
||||
|
@ -1,188 +0,0 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "td/telegram/Payments.h"
|
||||
|
||||
#include "td/telegram/Photo.hpp"
|
||||
#include "td/telegram/Version.h"
|
||||
|
||||
#include "td/utils/tl_helpers.h"
|
||||
|
||||
namespace td {
|
||||
|
||||
template <class StorerT>
|
||||
void store(const LabeledPricePart &labeled_price_part, StorerT &storer) {
|
||||
store(labeled_price_part.label, storer);
|
||||
store(labeled_price_part.amount, storer);
|
||||
}
|
||||
|
||||
template <class ParserT>
|
||||
void parse(LabeledPricePart &labeled_price_part, ParserT &parser) {
|
||||
parse(labeled_price_part.label, parser);
|
||||
parse(labeled_price_part.amount, parser);
|
||||
}
|
||||
|
||||
template <class StorerT>
|
||||
void store(const Invoice &invoice, StorerT &storer) {
|
||||
bool has_tip = invoice.max_tip_amount != 0;
|
||||
bool is_recurring = !invoice.recurring_payment_terms_of_service_url.empty();
|
||||
BEGIN_STORE_FLAGS();
|
||||
STORE_FLAG(invoice.is_test);
|
||||
STORE_FLAG(invoice.need_name);
|
||||
STORE_FLAG(invoice.need_phone_number);
|
||||
STORE_FLAG(invoice.need_email_address);
|
||||
STORE_FLAG(invoice.need_shipping_address);
|
||||
STORE_FLAG(invoice.is_flexible);
|
||||
STORE_FLAG(invoice.send_phone_number_to_provider);
|
||||
STORE_FLAG(invoice.send_email_address_to_provider);
|
||||
STORE_FLAG(has_tip);
|
||||
STORE_FLAG(is_recurring);
|
||||
END_STORE_FLAGS();
|
||||
store(invoice.currency, storer);
|
||||
store(invoice.price_parts, storer);
|
||||
if (has_tip) {
|
||||
store(invoice.max_tip_amount, storer);
|
||||
store(invoice.suggested_tip_amounts, storer);
|
||||
}
|
||||
if (is_recurring) {
|
||||
store(invoice.recurring_payment_terms_of_service_url, storer);
|
||||
}
|
||||
}
|
||||
|
||||
template <class ParserT>
|
||||
void parse(Invoice &invoice, ParserT &parser) {
|
||||
bool has_tip;
|
||||
bool is_recurring;
|
||||
BEGIN_PARSE_FLAGS();
|
||||
PARSE_FLAG(invoice.is_test);
|
||||
PARSE_FLAG(invoice.need_name);
|
||||
PARSE_FLAG(invoice.need_phone_number);
|
||||
PARSE_FLAG(invoice.need_email_address);
|
||||
PARSE_FLAG(invoice.need_shipping_address);
|
||||
PARSE_FLAG(invoice.is_flexible);
|
||||
PARSE_FLAG(invoice.send_phone_number_to_provider);
|
||||
PARSE_FLAG(invoice.send_email_address_to_provider);
|
||||
PARSE_FLAG(has_tip);
|
||||
PARSE_FLAG(is_recurring);
|
||||
END_PARSE_FLAGS();
|
||||
parse(invoice.currency, parser);
|
||||
parse(invoice.price_parts, parser);
|
||||
if (has_tip) {
|
||||
parse(invoice.max_tip_amount, parser);
|
||||
parse(invoice.suggested_tip_amounts, parser);
|
||||
}
|
||||
if (is_recurring) {
|
||||
parse(invoice.recurring_payment_terms_of_service_url, parser);
|
||||
}
|
||||
}
|
||||
|
||||
template <class StorerT>
|
||||
void store(const InputInvoice &input_invoice, StorerT &storer) {
|
||||
store(input_invoice.title, storer);
|
||||
store(input_invoice.description, storer);
|
||||
store(input_invoice.photo, storer);
|
||||
store(input_invoice.start_parameter, storer);
|
||||
store(input_invoice.invoice, storer);
|
||||
store(input_invoice.payload, storer);
|
||||
store(input_invoice.provider_token, storer);
|
||||
store(input_invoice.provider_data, storer);
|
||||
store(input_invoice.total_amount, storer);
|
||||
store(input_invoice.receipt_message_id, storer);
|
||||
}
|
||||
|
||||
template <class ParserT>
|
||||
void parse(InputInvoice &input_invoice, ParserT &parser) {
|
||||
parse(input_invoice.title, parser);
|
||||
parse(input_invoice.description, parser);
|
||||
parse(input_invoice.photo, parser);
|
||||
parse(input_invoice.start_parameter, parser);
|
||||
parse(input_invoice.invoice, parser);
|
||||
parse(input_invoice.payload, parser);
|
||||
parse(input_invoice.provider_token, parser);
|
||||
if (parser.version() >= static_cast<int32>(Version::AddMessageInvoiceProviderData)) {
|
||||
parse(input_invoice.provider_data, parser);
|
||||
} else {
|
||||
input_invoice.provider_data.clear();
|
||||
}
|
||||
parse(input_invoice.total_amount, parser);
|
||||
parse(input_invoice.receipt_message_id, parser);
|
||||
}
|
||||
|
||||
template <class StorerT>
|
||||
void store(const Address &address, StorerT &storer) {
|
||||
store(address.country_code, storer);
|
||||
store(address.state, storer);
|
||||
store(address.city, storer);
|
||||
store(address.street_line1, storer);
|
||||
store(address.street_line2, storer);
|
||||
store(address.postal_code, storer);
|
||||
}
|
||||
|
||||
template <class ParserT>
|
||||
void parse(Address &address, ParserT &parser) {
|
||||
parse(address.country_code, parser);
|
||||
parse(address.state, parser);
|
||||
parse(address.city, parser);
|
||||
parse(address.street_line1, parser);
|
||||
parse(address.street_line2, parser);
|
||||
parse(address.postal_code, parser);
|
||||
}
|
||||
|
||||
template <class StorerT>
|
||||
void store(const OrderInfo &order_info, StorerT &storer) {
|
||||
bool has_name = !order_info.name.empty();
|
||||
bool has_phone_number = !order_info.phone_number.empty();
|
||||
bool has_email_address = !order_info.email_address.empty();
|
||||
bool has_shipping_address = order_info.shipping_address != nullptr;
|
||||
BEGIN_STORE_FLAGS();
|
||||
STORE_FLAG(has_name);
|
||||
STORE_FLAG(has_phone_number);
|
||||
STORE_FLAG(has_email_address);
|
||||
STORE_FLAG(has_shipping_address);
|
||||
END_STORE_FLAGS();
|
||||
if (has_name) {
|
||||
store(order_info.name, storer);
|
||||
}
|
||||
if (has_phone_number) {
|
||||
store(order_info.phone_number, storer);
|
||||
}
|
||||
if (has_email_address) {
|
||||
store(order_info.email_address, storer);
|
||||
}
|
||||
if (has_shipping_address) {
|
||||
store(order_info.shipping_address, storer);
|
||||
}
|
||||
}
|
||||
|
||||
template <class ParserT>
|
||||
void parse(OrderInfo &order_info, ParserT &parser) {
|
||||
bool has_name;
|
||||
bool has_phone_number;
|
||||
bool has_email_address;
|
||||
bool has_shipping_address;
|
||||
BEGIN_PARSE_FLAGS();
|
||||
PARSE_FLAG(has_name);
|
||||
PARSE_FLAG(has_phone_number);
|
||||
PARSE_FLAG(has_email_address);
|
||||
PARSE_FLAG(has_shipping_address);
|
||||
END_PARSE_FLAGS();
|
||||
if (has_name) {
|
||||
parse(order_info.name, parser);
|
||||
}
|
||||
if (has_phone_number) {
|
||||
parse(order_info.phone_number, parser);
|
||||
}
|
||||
if (has_email_address) {
|
||||
parse(order_info.email_address, parser);
|
||||
}
|
||||
if (has_shipping_address) {
|
||||
parse(order_info.shipping_address, parser);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace td
|
@ -523,6 +523,32 @@ vector<FileId> photo_get_file_ids(const Photo &photo) {
|
||||
return result;
|
||||
}
|
||||
|
||||
FileId get_photo_upload_file_id(const Photo &photo) {
|
||||
for (auto &size : photo.photos) {
|
||||
if (size.type == 'i') {
|
||||
return size.file_id;
|
||||
}
|
||||
}
|
||||
return FileId();
|
||||
}
|
||||
|
||||
FileId get_photo_any_file_id(const Photo &photo) {
|
||||
const auto &sizes = photo.photos;
|
||||
if (!sizes.empty()) {
|
||||
return sizes.back().file_id;
|
||||
}
|
||||
return FileId();
|
||||
}
|
||||
|
||||
FileId get_photo_thumbnail_file_id(const Photo &photo) {
|
||||
for (auto &size : photo.photos) {
|
||||
if (size.type == 't') {
|
||||
return size.file_id;
|
||||
}
|
||||
}
|
||||
return FileId();
|
||||
}
|
||||
|
||||
bool operator==(const Photo &lhs, const Photo &rhs) {
|
||||
return lhs.id.get() == rhs.id.get() && lhs.photos == rhs.photos && lhs.animations == rhs.animations;
|
||||
}
|
||||
|
@ -50,6 +50,18 @@ struct Photo {
|
||||
bool is_empty() const {
|
||||
return id.get() == -2;
|
||||
}
|
||||
|
||||
bool is_bad() const {
|
||||
if (is_empty()) {
|
||||
return true;
|
||||
}
|
||||
for (auto &photo_size : photos) {
|
||||
if (!photo_size.file_id.is_valid()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
ProfilePhoto get_profile_photo(FileManager *file_manager, UserId user_id, int64 user_access_hash,
|
||||
@ -95,6 +107,12 @@ void photo_delete_thumbnail(Photo &photo);
|
||||
|
||||
bool photo_has_input_media(FileManager *file_manager, const Photo &photo, bool is_secret, bool is_bot);
|
||||
|
||||
FileId get_photo_upload_file_id(const Photo &photo);
|
||||
|
||||
FileId get_photo_any_file_id(const Photo &photo);
|
||||
|
||||
FileId get_photo_thumbnail_file_id(const Photo &photo);
|
||||
|
||||
SecretInputMedia photo_get_secret_input_media(FileManager *file_manager, const Photo &photo,
|
||||
tl_object_ptr<telegram_api::InputEncryptedFile> input_file,
|
||||
const string &caption, BufferSlice thumbnail);
|
||||
|
@ -14,10 +14,12 @@
|
||||
#include "td/telegram/DocumentsManager.h"
|
||||
#include "td/telegram/Global.h"
|
||||
#include "td/telegram/MessageEntity.h"
|
||||
#include "td/telegram/Payments.h"
|
||||
#include "td/telegram/misc.h"
|
||||
#include "td/telegram/PremiumGiftOption.h"
|
||||
#include "td/telegram/Td.h"
|
||||
#include "td/telegram/telegram_api.h"
|
||||
#include "td/telegram/UpdatesManager.h"
|
||||
#include "td/telegram/UserId.h"
|
||||
|
||||
#include "td/utils/algorithm.h"
|
||||
#include "td/utils/buffer.h"
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "td/telegram/PremiumGiftOption.h"
|
||||
|
||||
#include "td/telegram/LinkManager.h"
|
||||
#include "td/telegram/Payments.h"
|
||||
#include "td/telegram/misc.h"
|
||||
|
||||
#include "td/utils/algorithm.h"
|
||||
#include "td/utils/common.h"
|
||||
|
@ -496,7 +496,7 @@ class SecretChatActor final : public NetQueryCallback {
|
||||
public:
|
||||
Change() : message_id() {
|
||||
}
|
||||
explicit operator bool() const {
|
||||
explicit operator bool() const noexcept {
|
||||
return !data.empty();
|
||||
}
|
||||
explicit Change(const StateT &state) {
|
||||
|
@ -650,8 +650,8 @@ void SetSecureValue::merge(FileManager *file_manager, FileId file_id, EncryptedS
|
||||
LOG(ERROR) << "Hash mismatch";
|
||||
return;
|
||||
}
|
||||
auto status = file_manager->merge(encrypted_file.file.file_id, file_id);
|
||||
LOG_IF(ERROR, status.is_error()) << status.error();
|
||||
auto r_file_id = file_manager->merge(encrypted_file.file.file_id, file_id);
|
||||
LOG_IF(ERROR, r_file_id.is_error()) << r_file_id.error();
|
||||
}
|
||||
|
||||
class DeleteSecureValue final : public NetQueryCallback {
|
||||
|
@ -14,7 +14,7 @@
|
||||
#include "td/telegram/Global.h"
|
||||
#include "td/telegram/misc.h"
|
||||
#include "td/telegram/net/DcId.h"
|
||||
#include "td/telegram/Payments.h"
|
||||
#include "td/telegram/OrderInfo.h"
|
||||
#include "td/telegram/telegram_api.hpp"
|
||||
|
||||
#include "td/utils/algorithm.h"
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "td/utils/base64.h"
|
||||
#include "td/utils/buffer.h"
|
||||
#include "td/utils/Time.h"
|
||||
|
||||
namespace td {
|
||||
|
||||
|
@ -12,7 +12,6 @@
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/Slice.h"
|
||||
#include "td/utils/Status.h"
|
||||
#include "td/utils/Time.h"
|
||||
|
||||
namespace td {
|
||||
|
||||
|
@ -6,6 +6,8 @@
|
||||
//
|
||||
#include "td/telegram/SentEmailCode.h"
|
||||
|
||||
#include "td/utils/logging.h"
|
||||
|
||||
namespace td {
|
||||
|
||||
SentEmailCode::SentEmailCode(telegram_api::object_ptr<telegram_api::account_sentEmailCode> &&email_code)
|
||||
|
@ -77,7 +77,7 @@ void SequenceDispatcher::try_resend_query(Data &data, NetQueryPtr query) {
|
||||
// TODO: if query is ok, use NetQueryCallback::on_result
|
||||
if (data.callback_.empty()) {
|
||||
do_finish(data);
|
||||
send_closure(G()->td(), &Td::on_result, std::move(query));
|
||||
send_closure_later(G()->td(), &Td::on_result, std::move(query));
|
||||
loop();
|
||||
return;
|
||||
}
|
||||
@ -385,7 +385,7 @@ class MultiSequenceDispatcherImpl final : public MultiSequenceDispatcher {
|
||||
if (node.callback.empty()) {
|
||||
auto query = std::move(node.net_query);
|
||||
scheduler_.finish_task(task_id);
|
||||
send_closure(G()->td(), &Td::on_result, std::move(query));
|
||||
send_closure_later(G()->td(), &Td::on_result, std::move(query));
|
||||
loop();
|
||||
return;
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "td/telegram/ServerMessageId.h"
|
||||
#include "td/telegram/Td.h"
|
||||
#include "td/telegram/telegram_api.h"
|
||||
#include "td/telegram/UserId.h"
|
||||
|
||||
#include "td/utils/algorithm.h"
|
||||
#include "td/utils/buffer.h"
|
||||
|
@ -1304,7 +1304,9 @@ class GetCustomEmojiDocumentsQuery final : public Td::ResultHandler {
|
||||
: promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
void send(vector<int64> &&document_ids) {
|
||||
void send(vector<CustomEmojiId> &&custom_emoji_ids) {
|
||||
auto document_ids =
|
||||
transform(custom_emoji_ids, [](CustomEmojiId custom_emoji_id) { return custom_emoji_id.get(); });
|
||||
send_query(
|
||||
G()->net_query_creator().create(telegram_api::messages_getCustomEmojiDocuments(std::move(document_ids))));
|
||||
}
|
||||
@ -1891,7 +1893,7 @@ StickerType StickersManager::get_sticker_type(FileId file_id) const {
|
||||
return sticker->type_;
|
||||
}
|
||||
|
||||
bool StickersManager::is_premium_custom_emoji(int64 custom_emoji_id, bool default_result) const {
|
||||
bool StickersManager::is_premium_custom_emoji(CustomEmojiId custom_emoji_id, bool default_result) const {
|
||||
auto sticker_id = custom_emoji_to_sticker_id_.get(custom_emoji_id);
|
||||
if (!sticker_id.is_valid()) {
|
||||
return default_result;
|
||||
@ -1901,13 +1903,13 @@ bool StickersManager::is_premium_custom_emoji(int64 custom_emoji_id, bool defaul
|
||||
return s->is_premium_;
|
||||
}
|
||||
|
||||
int64 StickersManager::get_custom_emoji_id(FileId sticker_id) const {
|
||||
CustomEmojiId StickersManager::get_custom_emoji_id(FileId sticker_id) const {
|
||||
auto sticker_file_view = td_->file_manager_->get_file_view(sticker_id);
|
||||
if (sticker_file_view.is_encrypted() || !sticker_file_view.has_remote_location() ||
|
||||
!sticker_file_view.remote_location().is_document()) {
|
||||
return 0;
|
||||
return CustomEmojiId();
|
||||
}
|
||||
return sticker_file_view.remote_location().get_id();
|
||||
return CustomEmojiId(sticker_file_view.remote_location().get_id());
|
||||
}
|
||||
|
||||
vector<td_api::object_ptr<td_api::closedVectorPath>> StickersManager::get_sticker_minithumbnail(
|
||||
@ -2164,7 +2166,7 @@ tl_object_ptr<td_api::sticker> StickersManager::get_sticker_object(FileId file_i
|
||||
const PhotoSize &thumbnail = sticker->m_thumbnail_.file_id.is_valid() ? sticker->m_thumbnail_ : sticker->s_thumbnail_;
|
||||
auto thumbnail_format = PhotoFormat::Webp;
|
||||
int64 document_id = 0;
|
||||
int64 emoji_document_id = 0;
|
||||
CustomEmojiId custom_emoji_id;
|
||||
if (!sticker->set_id_.is_valid()) {
|
||||
auto sticker_file_view = td_->file_manager_->get_file_view(sticker->file_id_);
|
||||
if (sticker_file_view.is_encrypted()) {
|
||||
@ -2183,7 +2185,7 @@ tl_object_ptr<td_api::sticker> StickersManager::get_sticker_object(FileId file_i
|
||||
}
|
||||
}
|
||||
} else if (sticker->type_ == StickerType::CustomEmoji) {
|
||||
emoji_document_id = get_custom_emoji_id(sticker->file_id_);
|
||||
custom_emoji_id = get_custom_emoji_id(sticker->file_id_);
|
||||
}
|
||||
auto thumbnail_object = get_thumbnail_object(td_->file_manager_.get(), thumbnail, thumbnail_format);
|
||||
int32 width = sticker->dimensions_.width;
|
||||
@ -2191,31 +2193,31 @@ tl_object_ptr<td_api::sticker> StickersManager::get_sticker_object(FileId file_i
|
||||
double zoom = 1.0;
|
||||
if ((is_sticker_format_vector(sticker->format_) || sticker->type_ == StickerType::CustomEmoji) &&
|
||||
(for_animated_emoji || for_clicked_animated_emoji)) {
|
||||
zoom = for_clicked_animated_emoji ? 3 * animated_emoji_zoom_ : animated_emoji_zoom_;
|
||||
if (sticker->type_ == StickerType::CustomEmoji && max(width, height) <= 100) {
|
||||
zoom *= 5.12;
|
||||
}
|
||||
width = static_cast<int32>(width * zoom + 0.5);
|
||||
height = static_cast<int32>(height * zoom + 0.5);
|
||||
if (for_clicked_animated_emoji) {
|
||||
zoom *= 3;
|
||||
width *= 3;
|
||||
height *= 3;
|
||||
}
|
||||
}
|
||||
auto premium_animation_object = sticker->premium_animation_file_id_.is_valid()
|
||||
? td_->file_manager_->get_file_object(sticker->premium_animation_file_id_)
|
||||
: nullptr;
|
||||
return td_api::make_object<td_api::sticker>(
|
||||
sticker->set_id_.get(), width, height, sticker->alt_, get_sticker_format_object(sticker->format_),
|
||||
get_sticker_type_object(sticker->type_), std::move(mask_position), emoji_document_id,
|
||||
get_sticker_type_object(sticker->type_), std::move(mask_position), custom_emoji_id.get(),
|
||||
get_sticker_minithumbnail(sticker->minithumbnail_, sticker->set_id_, document_id, zoom),
|
||||
std::move(thumbnail_object), sticker->is_premium_, std::move(premium_animation_object),
|
||||
td_->file_manager_->get_file_object(file_id));
|
||||
}
|
||||
|
||||
tl_object_ptr<td_api::stickers> StickersManager::get_stickers_object(const vector<FileId> &sticker_ids) const {
|
||||
auto result = td_api::make_object<td_api::stickers>();
|
||||
result->stickers_.reserve(sticker_ids.size());
|
||||
for (auto sticker_id : sticker_ids) {
|
||||
result->stickers_.push_back(get_sticker_object(sticker_id));
|
||||
}
|
||||
return result;
|
||||
return td_api::make_object<td_api::stickers>(
|
||||
transform(sticker_ids, [&](FileId sticker_id) { return get_sticker_object(sticker_id); }));
|
||||
}
|
||||
|
||||
tl_object_ptr<td_api::DiceStickers> StickersManager::get_dice_stickers_object(const string &emoji, int32 value) const {
|
||||
@ -2582,7 +2584,7 @@ FileId StickersManager::get_animated_emoji_sound_file_id(const string &emoji) co
|
||||
return it->second;
|
||||
}
|
||||
|
||||
FileId StickersManager::get_custom_animated_emoji_sticker_id(int64 custom_emoji_id) const {
|
||||
FileId StickersManager::get_custom_animated_emoji_sticker_id(CustomEmojiId custom_emoji_id) const {
|
||||
if (disable_animated_emojis_) {
|
||||
return {};
|
||||
}
|
||||
@ -2591,16 +2593,20 @@ FileId StickersManager::get_custom_animated_emoji_sticker_id(int64 custom_emoji_
|
||||
}
|
||||
|
||||
td_api::object_ptr<td_api::animatedEmoji> StickersManager::get_animated_emoji_object(const string &emoji,
|
||||
int64 custom_emoji_id) {
|
||||
CustomEmojiId custom_emoji_id) {
|
||||
if (td_->auth_manager_->is_bot() || disable_animated_emojis_) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (custom_emoji_id != 0) {
|
||||
if (custom_emoji_id.is_valid()) {
|
||||
auto it = custom_emoji_messages_.find(custom_emoji_id);
|
||||
auto sticker_id = it == custom_emoji_messages_.end() ? get_custom_animated_emoji_sticker_id(custom_emoji_id)
|
||||
: it->second->sticker_id_;
|
||||
return td_api::make_object<td_api::animatedEmoji>(get_sticker_object(sticker_id, true), 0, nullptr);
|
||||
auto sticker = get_sticker_object(sticker_id, true);
|
||||
auto default_custom_emoji_dimension = static_cast<int32>(512 * animated_emoji_zoom_ + 0.5);
|
||||
auto sticker_width = sticker == nullptr ? default_custom_emoji_dimension : sticker->width_;
|
||||
auto sticker_height = sticker == nullptr ? default_custom_emoji_dimension : sticker->height_;
|
||||
return td_api::make_object<td_api::animatedEmoji>(std::move(sticker), sticker_width, sticker_height, 0, nullptr);
|
||||
}
|
||||
|
||||
auto it = emoji_messages_.find(emoji);
|
||||
@ -2616,8 +2622,12 @@ td_api::object_ptr<td_api::animatedEmoji> StickersManager::get_animated_emoji_ob
|
||||
if (!animated_sticker.first.is_valid()) {
|
||||
return nullptr;
|
||||
}
|
||||
auto sticker = get_sticker_object(animated_sticker.first, true);
|
||||
CHECK(sticker != nullptr);
|
||||
auto sticker_width = sticker->width_;
|
||||
auto sticker_height = sticker->height_;
|
||||
return td_api::make_object<td_api::animatedEmoji>(
|
||||
get_sticker_object(animated_sticker.first, true), animated_sticker.second,
|
||||
std::move(sticker), sticker_width, sticker_height, animated_sticker.second,
|
||||
sound_file_id.is_valid() ? td_->file_manager_->get_file_object(sound_file_id) : nullptr);
|
||||
}
|
||||
|
||||
@ -2656,14 +2666,14 @@ class StickersManager::CustomEmojiLogEvent {
|
||||
}
|
||||
};
|
||||
|
||||
string StickersManager::get_custom_emoji_database_key(int64 custom_emoji_id) {
|
||||
return PSTRING() << "emoji" << custom_emoji_id;
|
||||
string StickersManager::get_custom_emoji_database_key(CustomEmojiId custom_emoji_id) {
|
||||
return PSTRING() << "emoji" << custom_emoji_id.get();
|
||||
}
|
||||
|
||||
FileId StickersManager::on_get_sticker(unique_ptr<Sticker> new_sticker, bool replace) {
|
||||
auto file_id = new_sticker->file_id_;
|
||||
CHECK(file_id.is_valid());
|
||||
int64 updated_custom_emoji_id = 0;
|
||||
CustomEmojiId updated_custom_emoji_id;
|
||||
auto *s = get_sticker(file_id);
|
||||
if (s == nullptr) {
|
||||
s = new_sticker.get();
|
||||
@ -2673,7 +2683,7 @@ FileId StickersManager::on_get_sticker(unique_ptr<Sticker> new_sticker, bool rep
|
||||
|
||||
if (s->type_ == StickerType::CustomEmoji) {
|
||||
auto custom_emoji_id = get_custom_emoji_id(file_id);
|
||||
if (custom_emoji_id != 0 && custom_emoji_to_sticker_id_.get(custom_emoji_id) == file_id) {
|
||||
if (custom_emoji_id.is_valid() && custom_emoji_to_sticker_id_.get(custom_emoji_id) == file_id) {
|
||||
custom_emoji_to_sticker_id_.erase(custom_emoji_id);
|
||||
updated_custom_emoji_id = custom_emoji_id;
|
||||
}
|
||||
@ -2743,12 +2753,12 @@ FileId StickersManager::on_get_sticker(unique_ptr<Sticker> new_sticker, bool rep
|
||||
if (s->type_ == StickerType::CustomEmoji) {
|
||||
s->is_being_reloaded_ = false;
|
||||
auto custom_emoji_id = get_custom_emoji_id(file_id);
|
||||
if (custom_emoji_id != 0) {
|
||||
if (custom_emoji_id.is_valid()) {
|
||||
custom_emoji_to_sticker_id_.set(custom_emoji_id, file_id);
|
||||
CHECK(updated_custom_emoji_id == custom_emoji_id || updated_custom_emoji_id == 0);
|
||||
CHECK(updated_custom_emoji_id == custom_emoji_id || !updated_custom_emoji_id.is_valid());
|
||||
updated_custom_emoji_id = custom_emoji_id;
|
||||
if (!s->is_from_database_ && G()->parameters().use_file_db && !G()->close_flag()) {
|
||||
LOG(INFO) << "Save custom emoji " << custom_emoji_id << " to database";
|
||||
LOG(INFO) << "Save " << custom_emoji_id << " to database";
|
||||
s->is_from_database_ = true;
|
||||
|
||||
CustomEmojiLogEvent log_event(file_id);
|
||||
@ -2757,7 +2767,7 @@ FileId StickersManager::on_get_sticker(unique_ptr<Sticker> new_sticker, bool rep
|
||||
}
|
||||
}
|
||||
}
|
||||
if (updated_custom_emoji_id != 0) {
|
||||
if (updated_custom_emoji_id.is_valid()) {
|
||||
try_update_custom_emoji_messages(updated_custom_emoji_id);
|
||||
}
|
||||
return file_id;
|
||||
@ -3606,7 +3616,7 @@ StickerSetId StickersManager::on_get_sticker_set_covered(tl_object_ptr<telegram_
|
||||
case telegram_api::stickerSetFullCovered::ID: {
|
||||
auto set = move_tl_object_as<telegram_api::stickerSetFullCovered>(set_ptr);
|
||||
auto sticker_set = telegram_api::make_object<telegram_api::messages_stickerSet>(
|
||||
std::move(set->set_), std::move(set->packs_), std::move(set->documents_));
|
||||
std::move(set->set_), std::move(set->packs_), std::move(set->keywords_), std::move(set->documents_));
|
||||
return on_get_messages_sticker_set(StickerSetId(), std::move(sticker_set), is_changed, source);
|
||||
}
|
||||
default:
|
||||
@ -3661,16 +3671,14 @@ StickerSetId StickersManager::on_get_messages_sticker_set(StickerSetId sticker_s
|
||||
s->was_loaded_ = true;
|
||||
s->is_loaded_ = true;
|
||||
s->is_changed_ = true;
|
||||
|
||||
vector<tl_object_ptr<telegram_api::stickerPack>> packs = std::move(set->packs_);
|
||||
vector<tl_object_ptr<telegram_api::Document>> documents = std::move(set->documents_);
|
||||
s->are_keywords_loaded_ = true;
|
||||
|
||||
FlatHashMap<int64, FileId> document_id_to_sticker_id;
|
||||
|
||||
s->sticker_ids_.clear();
|
||||
s->premium_sticker_positions_.clear();
|
||||
bool is_bot = td_->auth_manager_->is_bot();
|
||||
for (auto &document_ptr : documents) {
|
||||
for (auto &document_ptr : set->documents_) {
|
||||
auto sticker_id = on_get_sticker_document(std::move(document_ptr), s->sticker_format_);
|
||||
if (!sticker_id.second.is_valid() || sticker_id.first == 0) {
|
||||
continue;
|
||||
@ -3693,7 +3701,9 @@ StickerSetId StickersManager::on_get_messages_sticker_set(StickerSetId sticker_s
|
||||
if (!is_bot) {
|
||||
s->emoji_stickers_map_.clear();
|
||||
s->sticker_emojis_map_.clear();
|
||||
for (auto &pack : packs) {
|
||||
s->keyword_stickers_map_.clear();
|
||||
s->sticker_keywords_map_.clear();
|
||||
for (auto &pack : set->packs_) {
|
||||
auto cleaned_emoji = remove_emoji_modifiers(pack->emoticon_);
|
||||
if (cleaned_emoji.empty()) {
|
||||
LOG(ERROR) << "Receive empty emoji in " << set_id << "/" << s->short_name_ << " from " << source;
|
||||
@ -3721,6 +3731,21 @@ StickerSetId StickersManager::on_get_messages_sticker_set(StickerSetId sticker_s
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto &keywords : set->keywords_) {
|
||||
auto document_id = keywords->document_id_;
|
||||
auto it = document_id_to_sticker_id.find(document_id);
|
||||
if (it == document_id_to_sticker_id.end()) {
|
||||
LOG(ERROR) << "Can't find document with ID " << document_id << " in " << set_id << "/" << s->short_name_
|
||||
<< " from " << source;
|
||||
continue;
|
||||
}
|
||||
|
||||
bool is_inserted = s->sticker_keywords_map_.emplace(it->second, std::move(keywords->keyword_)).second;
|
||||
if (!is_inserted) {
|
||||
LOG(ERROR) << "Receive twice document with ID " << document_id << " in " << set_id << "/" << s->short_name_
|
||||
<< " from " << source;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update_sticker_set(s, "on_get_messages_sticker_set 2");
|
||||
@ -4159,6 +4184,83 @@ void StickersManager::on_get_installed_sticker_sets_failed(StickerType sticker_t
|
||||
fail_promises(load_installed_sticker_sets_queries_[type], std::move(error));
|
||||
}
|
||||
|
||||
const std::map<string, vector<FileId>> &StickersManager::get_sticker_set_keywords(const StickerSet *sticker_set) {
|
||||
if (sticker_set->keyword_stickers_map_.empty()) {
|
||||
for (auto &sticker_id_keywords : sticker_set->sticker_keywords_map_) {
|
||||
for (auto &keyword : Hints::fix_words(transform(sticker_id_keywords.second, utf8_prepare_search_string))) {
|
||||
CHECK(!keyword.empty());
|
||||
sticker_set->keyword_stickers_map_[keyword].push_back(sticker_id_keywords.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
return sticker_set->keyword_stickers_map_;
|
||||
}
|
||||
|
||||
void StickersManager::find_sticker_set_stickers(const StickerSet *sticker_set, const string &query,
|
||||
const string &prepared_query, vector<FileId> &result) {
|
||||
auto it = sticker_set->emoji_stickers_map_.find(query);
|
||||
if (it != sticker_set->emoji_stickers_map_.end()) {
|
||||
LOG(INFO) << "Add " << it->second << " stickers from " << sticker_set->id_;
|
||||
append(result, it->second);
|
||||
}
|
||||
|
||||
if (!prepared_query.empty()) {
|
||||
const auto &keywords_map = get_sticker_set_keywords(sticker_set);
|
||||
auto keywords_it = keywords_map.lower_bound(prepared_query);
|
||||
if (keywords_it != keywords_map.end() && begins_with(keywords_it->first, prepared_query)) {
|
||||
FlatHashSet<FileId, FileIdHash> found_sticker_ids;
|
||||
if (it != sticker_set->emoji_stickers_map_.end()) {
|
||||
for (auto file_id : it->second) {
|
||||
found_sticker_ids.insert(file_id);
|
||||
}
|
||||
}
|
||||
do {
|
||||
for (auto file_id : keywords_it->second) {
|
||||
if (found_sticker_ids.insert(file_id).second) {
|
||||
result.push_back(file_id);
|
||||
}
|
||||
}
|
||||
++keywords_it;
|
||||
} while (keywords_it != keywords_map.end() && begins_with(keywords_it->first, prepared_query));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool StickersManager::can_found_sticker_by_query(FileId sticker_id, const string &query,
|
||||
const string &prepared_query) const {
|
||||
const Sticker *s = get_sticker(sticker_id);
|
||||
CHECK(s != nullptr);
|
||||
if (remove_emoji_modifiers(s->alt_) == query) {
|
||||
// fast path
|
||||
return true;
|
||||
}
|
||||
const StickerSet *sticker_set = get_sticker_set(s->set_id_);
|
||||
if (sticker_set == nullptr || !sticker_set->was_loaded_) {
|
||||
return false;
|
||||
}
|
||||
auto it = sticker_set->emoji_stickers_map_.find(query);
|
||||
if (it != sticker_set->emoji_stickers_map_.end()) {
|
||||
if (td::contains(it->second, sticker_id)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!prepared_query.empty()) {
|
||||
const auto &keywords_map = get_sticker_set_keywords(sticker_set);
|
||||
auto keywords_it = keywords_map.lower_bound(prepared_query);
|
||||
if (keywords_it != keywords_map.end() && begins_with(keywords_it->first, prepared_query)) {
|
||||
do {
|
||||
if (td::contains(keywords_it->second, sticker_id)) {
|
||||
return true;
|
||||
}
|
||||
++keywords_it;
|
||||
} while (keywords_it != keywords_map.end() && begins_with(keywords_it->first, prepared_query));
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::pair<vector<FileId>, vector<FileId>> StickersManager::split_stickers_by_premium(
|
||||
const vector<FileId> &sticker_ids) const {
|
||||
CHECK(!td_->auth_manager_->is_bot());
|
||||
@ -4203,7 +4305,7 @@ std::pair<vector<FileId>, vector<FileId>> StickersManager::split_stickers_by_pre
|
||||
return {std::move(regular_sticker_ids), std::move(premium_sticker_ids)};
|
||||
}
|
||||
|
||||
vector<FileId> StickersManager::get_stickers(StickerType sticker_type, string emoji, int32 limit, DialogId dialog_id,
|
||||
vector<FileId> StickersManager::get_stickers(StickerType sticker_type, string query, int32 limit, DialogId dialog_id,
|
||||
bool force, Promise<Unit> &&promise) {
|
||||
if (G()->close_flag()) {
|
||||
promise.set_error(Global::request_aborted_error());
|
||||
@ -4220,20 +4322,20 @@ vector<FileId> StickersManager::get_stickers(StickerType sticker_type, string em
|
||||
CHECK(force == false);
|
||||
load_installed_sticker_sets(
|
||||
sticker_type,
|
||||
PromiseCreator::lambda([actor_id = actor_id(this), sticker_type, emoji = std::move(emoji), limit, dialog_id,
|
||||
PromiseCreator::lambda([actor_id = actor_id(this), sticker_type, query = std::move(query), limit, dialog_id,
|
||||
force, promise = std::move(promise)](Result<Unit> result) mutable {
|
||||
if (result.is_error()) {
|
||||
promise.set_error(result.move_as_error());
|
||||
} else {
|
||||
send_closure(actor_id, &StickersManager::get_stickers, sticker_type, std::move(emoji), limit, dialog_id,
|
||||
send_closure(actor_id, &StickersManager::get_stickers, sticker_type, std::move(query), limit, dialog_id,
|
||||
force, std::move(promise));
|
||||
}
|
||||
}));
|
||||
return {};
|
||||
}
|
||||
|
||||
remove_emoji_modifiers_in_place(emoji);
|
||||
if (!emoji.empty()) {
|
||||
remove_emoji_modifiers_in_place(query);
|
||||
if (!query.empty()) {
|
||||
if (sticker_type == StickerType::Regular) {
|
||||
if (!are_recent_stickers_loaded_[0 /*is_attached*/]) {
|
||||
load_recent_stickers(false, std::move(promise));
|
||||
@ -4252,7 +4354,7 @@ vector<FileId> StickersManager::get_stickers(StickerType sticker_type, string em
|
||||
}
|
||||
|
||||
vector<StickerSetId> examined_sticker_set_ids = installed_sticker_set_ids_[type];
|
||||
if (!emoji.empty() && sticker_type == StickerType::CustomEmoji) {
|
||||
if (!query.empty() && sticker_type == StickerType::CustomEmoji) {
|
||||
append(examined_sticker_set_ids, featured_sticker_set_ids_[type]);
|
||||
}
|
||||
|
||||
@ -4271,7 +4373,7 @@ vector<FileId> StickersManager::get_stickers(StickerType sticker_type, string em
|
||||
}
|
||||
|
||||
vector<FileId> prepend_sticker_ids;
|
||||
if (!emoji.empty() && sticker_type == StickerType::Regular) {
|
||||
if (!query.empty() && sticker_type == StickerType::Regular) {
|
||||
prepend_sticker_ids.reserve(favorite_sticker_ids_.size() + recent_sticker_ids_[0].size());
|
||||
append(prepend_sticker_ids, recent_sticker_ids_[0]);
|
||||
for (auto sticker_id : favorite_sticker_ids_) {
|
||||
@ -4345,7 +4447,7 @@ vector<FileId> StickersManager::get_stickers(StickerType sticker_type, string em
|
||||
|
||||
vector<FileId> result;
|
||||
auto limit_size_t = static_cast<size_t>(limit);
|
||||
if (emoji.empty()) {
|
||||
if (query.empty()) {
|
||||
for (const auto &sticker_set_id : examined_sticker_set_ids) {
|
||||
const StickerSet *sticker_set = get_sticker_set(sticker_set_id);
|
||||
if (sticker_set == nullptr || !sticker_set->was_loaded_) {
|
||||
@ -4359,6 +4461,8 @@ vector<FileId> StickersManager::get_stickers(StickerType sticker_type, string em
|
||||
}
|
||||
}
|
||||
} else {
|
||||
auto prepared_query = utf8_prepare_search_string(query);
|
||||
LOG(INFO) << "Search stickers by " << query << " and keyword " << prepared_query;
|
||||
vector<const StickerSet *> examined_sticker_sets;
|
||||
for (const auto &sticker_set_id : examined_sticker_set_ids) {
|
||||
const StickerSet *sticker_set = get_sticker_set(sticker_set_id);
|
||||
@ -4381,11 +4485,7 @@ vector<FileId> StickersManager::get_stickers(StickerType sticker_type, string em
|
||||
return is_sticker_format_animated(lhs->sticker_format_) && !is_sticker_format_animated(rhs->sticker_format_);
|
||||
});
|
||||
for (auto sticker_set : examined_sticker_sets) {
|
||||
auto it = sticker_set->emoji_stickers_map_.find(emoji);
|
||||
if (it != sticker_set->emoji_stickers_map_.end()) {
|
||||
LOG(INFO) << "Add " << it->second << " stickers from " << sticker_set->id_;
|
||||
append(result, it->second);
|
||||
}
|
||||
find_sticker_set_stickers(sticker_set, query, prepared_query, result);
|
||||
}
|
||||
|
||||
vector<FileId> sorted;
|
||||
@ -4406,24 +4506,9 @@ vector<FileId> StickersManager::get_stickers(StickerType sticker_type, string em
|
||||
<< (it - result.begin());
|
||||
*it = FileId();
|
||||
is_good = true;
|
||||
} else {
|
||||
const Sticker *s = get_sticker(sticker_id);
|
||||
CHECK(s != nullptr);
|
||||
if (remove_emoji_modifiers(s->alt_) == emoji) {
|
||||
LOG(INFO) << "Found prepend sticker " << sticker_id << " main emoji matches";
|
||||
is_good = true;
|
||||
} else if (s->set_id_.is_valid()) {
|
||||
const StickerSet *sticker_set = get_sticker_set(s->set_id_);
|
||||
if (sticker_set != nullptr && sticker_set->was_loaded_) {
|
||||
auto map_it = sticker_set->emoji_stickers_map_.find(emoji);
|
||||
if (map_it != sticker_set->emoji_stickers_map_.end()) {
|
||||
if (td::contains(map_it->second, sticker_id)) {
|
||||
LOG(INFO) << "Found prepend sticker " << sticker_id << " has matching emoji";
|
||||
is_good = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (can_found_sticker_by_query(sticker_id, query, prepared_query)) {
|
||||
LOG(INFO) << "Found prepend sticker " << sticker_id;
|
||||
is_good = true;
|
||||
}
|
||||
|
||||
if (is_good) {
|
||||
@ -5264,7 +5349,8 @@ void StickersManager::on_load_sticker_set_from_database(StickerSetId sticker_set
|
||||
<< format::as_hex_dump<4>(Slice(value));
|
||||
}
|
||||
}
|
||||
if (!sticker_set->is_thumbnail_reloaded_ || !sticker_set->are_legacy_sticker_thumbnails_reloaded_) {
|
||||
if (!sticker_set->are_keywords_loaded_ || !sticker_set->is_thumbnail_reloaded_ ||
|
||||
!sticker_set->are_legacy_sticker_thumbnails_reloaded_) {
|
||||
do_reload_sticker_set(sticker_set_id, get_input_sticker_set(sticker_set), 0, Auto());
|
||||
}
|
||||
|
||||
@ -5461,7 +5547,7 @@ void StickersManager::on_update_disable_animated_emojis() {
|
||||
}
|
||||
try_update_animated_emoji_messages();
|
||||
|
||||
vector<int64> custom_emoji_ids;
|
||||
vector<CustomEmojiId> custom_emoji_ids;
|
||||
for (auto &it : custom_emoji_messages_) {
|
||||
custom_emoji_ids.push_back(it.first);
|
||||
}
|
||||
@ -5471,9 +5557,8 @@ void StickersManager::on_update_disable_animated_emojis() {
|
||||
|
||||
if (!disable_animated_emojis_) {
|
||||
for (size_t i = 0; i < custom_emoji_ids.size(); i += MAX_GET_CUSTOM_EMOJI_STICKERS) {
|
||||
auto end_i = i + MAX_GET_CUSTOM_EMOJI_STICKERS;
|
||||
auto end = end_i < custom_emoji_ids.size() ? custom_emoji_ids.begin() + end_i : custom_emoji_ids.end();
|
||||
get_custom_emoji_stickers({custom_emoji_ids.begin() + i, end}, true, Auto());
|
||||
auto end_i = td::min(i + MAX_GET_CUSTOM_EMOJI_STICKERS, custom_emoji_ids.size());
|
||||
get_custom_emoji_stickers({custom_emoji_ids.begin() + i, custom_emoji_ids.begin() + end_i}, true, Auto());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5504,7 +5589,7 @@ void StickersManager::try_update_animated_emoji_messages() {
|
||||
}
|
||||
}
|
||||
|
||||
void StickersManager::try_update_custom_emoji_messages(int64 custom_emoji_id) {
|
||||
void StickersManager::try_update_custom_emoji_messages(CustomEmojiId custom_emoji_id) {
|
||||
auto it = custom_emoji_messages_.find(custom_emoji_id);
|
||||
if (it == custom_emoji_messages_.end()) {
|
||||
return;
|
||||
@ -5633,16 +5718,16 @@ void StickersManager::unregister_dice(const string &emoji, int32 value, FullMess
|
||||
}
|
||||
}
|
||||
|
||||
void StickersManager::register_emoji(const string &emoji, int64 custom_emoji_id, FullMessageId full_message_id,
|
||||
void StickersManager::register_emoji(const string &emoji, CustomEmojiId custom_emoji_id, FullMessageId full_message_id,
|
||||
const char *source) {
|
||||
CHECK(!emoji.empty());
|
||||
if (td_->auth_manager_->is_bot()) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOG(INFO) << "Register emoji " << emoji << " with custom emoji " << custom_emoji_id << " from " << full_message_id
|
||||
<< " from " << source;
|
||||
if (custom_emoji_id != 0) {
|
||||
LOG(INFO) << "Register emoji " << emoji << " with " << custom_emoji_id << " from " << full_message_id << " from "
|
||||
<< source;
|
||||
if (custom_emoji_id.is_valid()) {
|
||||
auto &emoji_messages_ptr = custom_emoji_messages_[custom_emoji_id];
|
||||
if (emoji_messages_ptr == nullptr) {
|
||||
emoji_messages_ptr = make_unique<CustomEmojiMessages>();
|
||||
@ -5673,16 +5758,16 @@ void StickersManager::register_emoji(const string &emoji, int64 custom_emoji_id,
|
||||
emoji_messages.full_message_ids_.insert(full_message_id);
|
||||
}
|
||||
|
||||
void StickersManager::unregister_emoji(const string &emoji, int64 custom_emoji_id, FullMessageId full_message_id,
|
||||
const char *source) {
|
||||
void StickersManager::unregister_emoji(const string &emoji, CustomEmojiId custom_emoji_id,
|
||||
FullMessageId full_message_id, const char *source) {
|
||||
CHECK(!emoji.empty());
|
||||
if (td_->auth_manager_->is_bot()) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOG(INFO) << "Unregister emoji " << emoji << " with custom emoji " << custom_emoji_id << " from " << full_message_id
|
||||
<< " from " << source;
|
||||
if (custom_emoji_id != 0) {
|
||||
LOG(INFO) << "Unregister emoji " << emoji << " with " << custom_emoji_id << " from " << full_message_id << " from "
|
||||
<< source;
|
||||
if (custom_emoji_id.is_valid()) {
|
||||
auto it = custom_emoji_messages_.find(custom_emoji_id);
|
||||
CHECK(it != custom_emoji_messages_.end());
|
||||
auto &full_message_ids = it->second->full_message_ids_;
|
||||
@ -5766,14 +5851,14 @@ void StickersManager::get_all_animated_emojis(bool is_recursive,
|
||||
}
|
||||
|
||||
void StickersManager::get_custom_emoji_reaction_generic_animations(
|
||||
bool is_recursive, Promise<td_api::object_ptr<td_api::files>> &&promise) {
|
||||
bool is_recursive, Promise<td_api::object_ptr<td_api::stickers>> &&promise) {
|
||||
TRY_STATUS_PROMISE(promise, G()->close_status());
|
||||
|
||||
auto &special_sticker_set = add_special_sticker_set(SpecialStickerSetType::generic_animations());
|
||||
auto sticker_set = get_sticker_set(special_sticker_set.id_);
|
||||
if (sticker_set == nullptr || !sticker_set->was_loaded_) {
|
||||
if (is_recursive) {
|
||||
return promise.set_value(td_api::make_object<td_api::files>());
|
||||
return promise.set_value(td_api::make_object<td_api::stickers>());
|
||||
}
|
||||
|
||||
pending_get_generic_animations_queries_.push_back(PromiseCreator::lambda(
|
||||
@ -5789,9 +5874,7 @@ void StickersManager::get_custom_emoji_reaction_generic_animations(
|
||||
return;
|
||||
}
|
||||
|
||||
auto files = transform(sticker_set->sticker_ids_,
|
||||
[&](FileId sticker_id) { return td_->file_manager_->get_file_object(sticker_id); });
|
||||
promise.set_value(td_api::make_object<td_api::files>(std::move(files)));
|
||||
promise.set_value(get_stickers_object(sticker_set->sticker_ids_));
|
||||
}
|
||||
|
||||
void StickersManager::get_default_emoji_statuses(bool is_recursive,
|
||||
@ -5820,11 +5903,11 @@ void StickersManager::get_default_emoji_statuses(bool is_recursive,
|
||||
vector<td_api::object_ptr<td_api::emojiStatus>> statuses;
|
||||
for (auto sticker_id : sticker_set->sticker_ids_) {
|
||||
auto custom_emoji_id = get_custom_emoji_id(sticker_id);
|
||||
if (custom_emoji_id == 0) {
|
||||
if (!custom_emoji_id.is_valid()) {
|
||||
LOG(ERROR) << "Ignore wrong sticker " << sticker_id;
|
||||
continue;
|
||||
}
|
||||
statuses.emplace_back(td_api::make_object<td_api::emojiStatus>(custom_emoji_id));
|
||||
statuses.emplace_back(td_api::make_object<td_api::emojiStatus>(custom_emoji_id.get()));
|
||||
if (statuses.size() >= 8) {
|
||||
break;
|
||||
}
|
||||
@ -5832,7 +5915,7 @@ void StickersManager::get_default_emoji_statuses(bool is_recursive,
|
||||
promise.set_value(td_api::make_object<td_api::emojiStatuses>(std::move(statuses)));
|
||||
}
|
||||
|
||||
bool StickersManager::is_default_emoji_status(int64 custom_emoji_id) {
|
||||
bool StickersManager::is_default_emoji_status(CustomEmojiId custom_emoji_id) {
|
||||
auto &special_sticker_set = add_special_sticker_set(SpecialStickerSetType::default_statuses());
|
||||
auto sticker_set = get_sticker_set(special_sticker_set.id_);
|
||||
if (sticker_set == nullptr || !sticker_set->was_loaded_) {
|
||||
@ -5846,32 +5929,31 @@ bool StickersManager::is_default_emoji_status(int64 custom_emoji_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void StickersManager::load_custom_emoji_sticker_from_database_force(int64 custom_emoji_id) {
|
||||
void StickersManager::load_custom_emoji_sticker_from_database_force(CustomEmojiId custom_emoji_id) {
|
||||
if (!G()->parameters().use_file_db) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto value = G()->td_db()->get_sqlite_sync_pmc()->get(get_custom_emoji_database_key(custom_emoji_id));
|
||||
if (value.empty()) {
|
||||
LOG(INFO) << "Failed to load custom emoji " << custom_emoji_id << " from database";
|
||||
LOG(INFO) << "Failed to load " << custom_emoji_id << " from database";
|
||||
return;
|
||||
}
|
||||
|
||||
LOG(INFO) << "Synchronously loaded custom emoji " << custom_emoji_id << " of size " << value.size()
|
||||
<< " from database";
|
||||
LOG(INFO) << "Synchronously loaded " << custom_emoji_id << " of size " << value.size() << " from database";
|
||||
CustomEmojiLogEvent log_event;
|
||||
if (log_event_parse(log_event, value).is_error()) {
|
||||
LOG(ERROR) << "Delete invalid custom emoji " << custom_emoji_id << " value from database";
|
||||
LOG(ERROR) << "Delete invalid " << custom_emoji_id << " value from database";
|
||||
G()->td_db()->get_sqlite_sync_pmc()->erase(get_custom_emoji_database_key(custom_emoji_id));
|
||||
}
|
||||
}
|
||||
|
||||
void StickersManager::load_custom_emoji_sticker_from_database(int64 custom_emoji_id, Promise<Unit> &&promise) {
|
||||
CHECK(custom_emoji_id != 0);
|
||||
void StickersManager::load_custom_emoji_sticker_from_database(CustomEmojiId custom_emoji_id, Promise<Unit> &&promise) {
|
||||
CHECK(custom_emoji_id.is_valid());
|
||||
auto &queries = custom_emoji_load_queries_[custom_emoji_id];
|
||||
queries.push_back(std::move(promise));
|
||||
if (queries.size() == 1) {
|
||||
LOG(INFO) << "Trying to load custom emoji " << custom_emoji_id << " from database";
|
||||
LOG(INFO) << "Trying to load " << custom_emoji_id << " from database";
|
||||
G()->td_db()->get_sqlite_pmc()->get(
|
||||
get_custom_emoji_database_key(custom_emoji_id), PromiseCreator::lambda([custom_emoji_id](string value) {
|
||||
send_closure(G()->stickers_manager(), &StickersManager::on_load_custom_emoji_from_database, custom_emoji_id,
|
||||
@ -5880,21 +5962,20 @@ void StickersManager::load_custom_emoji_sticker_from_database(int64 custom_emoji
|
||||
}
|
||||
}
|
||||
|
||||
void StickersManager::on_load_custom_emoji_from_database(int64 custom_emoji_id, string value) {
|
||||
void StickersManager::on_load_custom_emoji_from_database(CustomEmojiId custom_emoji_id, string value) {
|
||||
if (G()->close_flag()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!value.empty()) {
|
||||
LOG(INFO) << "Successfully loaded custom emoji " << custom_emoji_id << " of size " << value.size()
|
||||
<< " from database";
|
||||
LOG(INFO) << "Successfully loaded " << custom_emoji_id << " of size " << value.size() << " from database";
|
||||
CustomEmojiLogEvent log_event;
|
||||
if (log_event_parse(log_event, value).is_error()) {
|
||||
LOG(ERROR) << "Delete invalid custom emoji " << custom_emoji_id << " value from database";
|
||||
LOG(ERROR) << "Delete invalid " << custom_emoji_id << " value from database";
|
||||
G()->td_db()->get_sqlite_pmc()->erase(get_custom_emoji_database_key(custom_emoji_id), Auto());
|
||||
}
|
||||
} else {
|
||||
LOG(INFO) << "Failed to load custom emoji " << custom_emoji_id << " from database";
|
||||
LOG(INFO) << "Failed to load " << custom_emoji_id << " from database";
|
||||
}
|
||||
|
||||
auto it = custom_emoji_load_queries_.find(custom_emoji_id);
|
||||
@ -5907,19 +5988,19 @@ void StickersManager::on_load_custom_emoji_from_database(int64 custom_emoji_id,
|
||||
}
|
||||
|
||||
td_api::object_ptr<td_api::stickers> StickersManager::get_custom_emoji_stickers_object(
|
||||
const vector<int64> &document_ids) {
|
||||
const vector<CustomEmojiId> &custom_emoji_ids) {
|
||||
vector<td_api::object_ptr<td_api::sticker>> stickers;
|
||||
auto update_before_date = G()->unix_time() - 86400;
|
||||
vector<int64> reload_document_ids;
|
||||
for (auto document_id : document_ids) {
|
||||
auto file_id = custom_emoji_to_sticker_id_.get(document_id);
|
||||
vector<CustomEmojiId> reload_custom_emoji_ids;
|
||||
for (auto custom_emoji_id : custom_emoji_ids) {
|
||||
auto file_id = custom_emoji_to_sticker_id_.get(custom_emoji_id);
|
||||
if (file_id.is_valid()) {
|
||||
auto s = get_sticker(file_id);
|
||||
CHECK(s != nullptr);
|
||||
CHECK(s->type_ == StickerType::CustomEmoji);
|
||||
if (s->emoji_receive_date_ < update_before_date && !s->is_being_reloaded_) {
|
||||
s->is_being_reloaded_ = true;
|
||||
reload_document_ids.push_back(document_id);
|
||||
reload_custom_emoji_ids.push_back(custom_emoji_id);
|
||||
}
|
||||
|
||||
auto sticker = get_sticker_object(file_id);
|
||||
@ -5927,69 +6008,77 @@ td_api::object_ptr<td_api::stickers> StickersManager::get_custom_emoji_stickers_
|
||||
stickers.push_back(std::move(sticker));
|
||||
}
|
||||
}
|
||||
if (!reload_document_ids.empty()) {
|
||||
LOG(INFO) << "Reload documents " << reload_document_ids;
|
||||
if (!reload_custom_emoji_ids.empty()) {
|
||||
LOG(INFO) << "Reload " << reload_custom_emoji_ids;
|
||||
auto promise = PromiseCreator::lambda(
|
||||
[actor_id =
|
||||
actor_id(this)](Result<vector<telegram_api::object_ptr<telegram_api::Document>>> r_documents) mutable {
|
||||
send_closure(actor_id, &StickersManager::on_get_custom_emoji_documents, std::move(r_documents),
|
||||
vector<int64>(), Promise<td_api::object_ptr<td_api::stickers>>());
|
||||
vector<CustomEmojiId>(), Promise<td_api::object_ptr<td_api::stickers>>());
|
||||
});
|
||||
td_->create_handler<GetCustomEmojiDocumentsQuery>(std::move(promise))->send(std::move(reload_document_ids));
|
||||
td_->create_handler<GetCustomEmojiDocumentsQuery>(std::move(promise))->send(std::move(reload_custom_emoji_ids));
|
||||
}
|
||||
return td_api::make_object<td_api::stickers>(std::move(stickers));
|
||||
}
|
||||
|
||||
void StickersManager::get_custom_emoji_stickers(vector<int64> &&document_ids, bool use_database,
|
||||
void StickersManager::get_custom_emoji_stickers(vector<CustomEmojiId> &&custom_emoji_ids, bool use_database,
|
||||
Promise<td_api::object_ptr<td_api::stickers>> &&promise) {
|
||||
TRY_STATUS_PROMISE(promise, G()->close_status());
|
||||
|
||||
if (document_ids.size() > MAX_GET_CUSTOM_EMOJI_STICKERS) {
|
||||
if (custom_emoji_ids.size() > MAX_GET_CUSTOM_EMOJI_STICKERS) {
|
||||
return promise.set_error(Status::Error(400, "Too many custom emoji identifiers specified"));
|
||||
}
|
||||
|
||||
td::unique(document_ids);
|
||||
td::remove(document_ids, 0);
|
||||
FlatHashSet<CustomEmojiId, CustomEmojiIdHash> unique_custom_emoji_ids;
|
||||
size_t j = 0;
|
||||
for (size_t i = 0; i < custom_emoji_ids.size(); i++) {
|
||||
auto custom_emoji_id = custom_emoji_ids[i];
|
||||
if (custom_emoji_id.is_valid() && unique_custom_emoji_ids.insert(custom_emoji_id).second) {
|
||||
custom_emoji_ids[j++] = custom_emoji_id;
|
||||
}
|
||||
}
|
||||
custom_emoji_ids.resize(j);
|
||||
|
||||
vector<int64> unknown_document_ids;
|
||||
for (auto document_id : document_ids) {
|
||||
if (custom_emoji_to_sticker_id_.count(document_id) == 0) {
|
||||
unknown_document_ids.push_back(document_id);
|
||||
vector<CustomEmojiId> unknown_custom_emoji_ids;
|
||||
for (auto custom_emoji_id : custom_emoji_ids) {
|
||||
if (custom_emoji_to_sticker_id_.count(custom_emoji_id) == 0) {
|
||||
unknown_custom_emoji_ids.push_back(custom_emoji_id);
|
||||
}
|
||||
}
|
||||
|
||||
if (unknown_document_ids.empty()) {
|
||||
return promise.set_value(get_custom_emoji_stickers_object(document_ids));
|
||||
if (unknown_custom_emoji_ids.empty()) {
|
||||
return promise.set_value(get_custom_emoji_stickers_object(custom_emoji_ids));
|
||||
}
|
||||
|
||||
if (use_database && G()->parameters().use_file_db) {
|
||||
MultiPromiseActorSafe mpas{"LoadCustomEmojiMultiPromiseActor"};
|
||||
mpas.add_promise(
|
||||
PromiseCreator::lambda([actor_id = actor_id(this), document_ids, promise = std::move(promise)](Unit) mutable {
|
||||
send_closure(actor_id, &StickersManager::get_custom_emoji_stickers, std::move(document_ids), false,
|
||||
mpas.add_promise(PromiseCreator::lambda(
|
||||
[actor_id = actor_id(this), custom_emoji_ids, promise = std::move(promise)](Unit) mutable {
|
||||
send_closure(actor_id, &StickersManager::get_custom_emoji_stickers, std::move(custom_emoji_ids), false,
|
||||
std::move(promise));
|
||||
}));
|
||||
|
||||
auto lock = mpas.get_promise();
|
||||
for (auto document_id : unknown_document_ids) {
|
||||
load_custom_emoji_sticker_from_database(document_id, mpas.get_promise());
|
||||
for (auto custom_emoji_id : unknown_custom_emoji_ids) {
|
||||
load_custom_emoji_sticker_from_database(custom_emoji_id, mpas.get_promise());
|
||||
}
|
||||
|
||||
return lock.set_value(Unit());
|
||||
}
|
||||
|
||||
auto query_promise = PromiseCreator::lambda(
|
||||
[actor_id = actor_id(this), document_ids = std::move(document_ids), promise = std::move(promise)](
|
||||
[actor_id = actor_id(this), custom_emoji_ids = std::move(custom_emoji_ids), promise = std::move(promise)](
|
||||
Result<vector<telegram_api::object_ptr<telegram_api::Document>>> r_documents) mutable {
|
||||
send_closure(actor_id, &StickersManager::on_get_custom_emoji_documents, std::move(r_documents),
|
||||
std::move(document_ids), std::move(promise));
|
||||
std::move(custom_emoji_ids), std::move(promise));
|
||||
});
|
||||
td_->create_handler<GetCustomEmojiDocumentsQuery>(std::move(query_promise))->send(std::move(unknown_document_ids));
|
||||
td_->create_handler<GetCustomEmojiDocumentsQuery>(std::move(query_promise))
|
||||
->send(std::move(unknown_custom_emoji_ids));
|
||||
}
|
||||
|
||||
void StickersManager::on_get_custom_emoji_documents(
|
||||
Result<vector<telegram_api::object_ptr<telegram_api::Document>>> &&r_documents, vector<int64> &&document_ids,
|
||||
Promise<td_api::object_ptr<td_api::stickers>> &&promise) {
|
||||
Result<vector<telegram_api::object_ptr<telegram_api::Document>>> &&r_documents,
|
||||
vector<CustomEmojiId> &&custom_emoji_ids, Promise<td_api::object_ptr<td_api::stickers>> &&promise) {
|
||||
TRY_STATUS_PROMISE(promise, G()->close_status());
|
||||
if (r_documents.is_error()) {
|
||||
return promise.set_error(r_documents.move_as_error());
|
||||
@ -6005,7 +6094,7 @@ void StickersManager::on_get_custom_emoji_documents(
|
||||
on_get_sticker_document(std::move(document), StickerFormat::Unknown);
|
||||
}
|
||||
|
||||
promise.set_value(get_custom_emoji_stickers_object(document_ids));
|
||||
promise.set_value(get_custom_emoji_stickers_object(custom_emoji_ids));
|
||||
}
|
||||
|
||||
void StickersManager::get_premium_gift_option_sticker(int32 month_count, bool is_recursive,
|
||||
@ -6186,6 +6275,9 @@ void StickersManager::flush_pending_animated_emoji_clicks() {
|
||||
if (pending_animated_emoji_clicks_.empty()) {
|
||||
return;
|
||||
}
|
||||
if (G()->close_flag()) {
|
||||
return;
|
||||
}
|
||||
auto clicks = std::move(pending_animated_emoji_clicks_);
|
||||
pending_animated_emoji_clicks_.clear();
|
||||
auto full_message_id = last_clicked_animated_emoji_full_message_id_;
|
||||
@ -7165,7 +7257,7 @@ void StickersManager::move_sticker_set_to_top_by_sticker_id(FileId sticker_id) {
|
||||
}
|
||||
}
|
||||
|
||||
void StickersManager::move_sticker_set_to_top_by_custom_emoji_ids(const vector<int64> &custom_emoji_ids) {
|
||||
void StickersManager::move_sticker_set_to_top_by_custom_emoji_ids(const vector<CustomEmojiId> &custom_emoji_ids) {
|
||||
LOG(INFO) << "Move to top sticker set of " << custom_emoji_ids;
|
||||
StickerSetId sticker_set_id;
|
||||
for (auto custom_emoji_id : custom_emoji_ids) {
|
||||
@ -7522,9 +7614,14 @@ void StickersManager::on_upload_sticker_file_error(FileId file_id, Status status
|
||||
void StickersManager::do_upload_sticker_file(UserId user_id, FileId file_id,
|
||||
tl_object_ptr<telegram_api::InputFile> &&input_file,
|
||||
Promise<Unit> &&promise) {
|
||||
TRY_STATUS_PROMISE(promise, G()->close_status());
|
||||
|
||||
DialogId dialog_id(user_id);
|
||||
auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
|
||||
if (input_peer == nullptr) {
|
||||
if (input_file != nullptr) {
|
||||
td_->file_manager_->cancel_upload(file_id);
|
||||
}
|
||||
return promise.set_error(Status::Error(400, "Have no access to the user"));
|
||||
}
|
||||
|
||||
@ -7537,7 +7634,7 @@ void StickersManager::do_upload_sticker_file(UserId user_id, FileId file_id,
|
||||
: td_->documents_manager_->get_input_media(file_id, std::move(input_file), nullptr);
|
||||
CHECK(input_media != nullptr);
|
||||
if (had_input_file && !FileManager::extract_was_uploaded(input_media)) {
|
||||
// if we had InputFile, but has failed to use it, then we need to immediately cancel file upload
|
||||
// if we had InputFile, but has failed to use it for input_media, then we need to immediately cancel file upload
|
||||
// so the next upload with the same file can succeed
|
||||
td_->file_manager_->cancel_upload(file_id);
|
||||
}
|
||||
@ -8949,7 +9046,7 @@ void StickersManager::on_get_language_codes(const string &key, Result<vector<str
|
||||
|
||||
vector<string> StickersManager::get_emoji_language_codes(const vector<string> &input_language_codes, Slice text,
|
||||
Promise<Unit> &promise) {
|
||||
vector<string> language_codes = td_->language_pack_manager_->get_actor_unsafe()->get_used_language_codes();
|
||||
vector<string> language_codes = td_->language_pack_manager_.get_actor_unsafe()->get_used_language_codes();
|
||||
auto system_language_code = G()->mtproto_header().get_system_language_code();
|
||||
if (system_language_code.size() >= 2 && system_language_code.find('$') == string::npos &&
|
||||
(system_language_code.size() == 2 || system_language_code[2] == '-')) {
|
||||
|
@ -6,6 +6,7 @@
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "td/telegram/CustomEmojiId.h"
|
||||
#include "td/telegram/DialogId.h"
|
||||
#include "td/telegram/Dimensions.h"
|
||||
#include "td/telegram/files/FileId.h"
|
||||
@ -20,6 +21,7 @@
|
||||
#include "td/telegram/StickerType.h"
|
||||
#include "td/telegram/td_api.h"
|
||||
#include "td/telegram/telegram_api.h"
|
||||
#include "td/telegram/UserId.h"
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
#include "td/actor/MultiPromise.h"
|
||||
@ -36,6 +38,7 @@
|
||||
#include "td/utils/WaitFreeHashMap.h"
|
||||
#include "td/utils/WaitFreeHashSet.h"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
@ -65,7 +68,7 @@ class StickersManager final : public Actor {
|
||||
|
||||
StickerType get_sticker_type(FileId file_id) const;
|
||||
|
||||
bool is_premium_custom_emoji(int64 custom_emoji_id, bool default_result) const;
|
||||
bool is_premium_custom_emoji(CustomEmojiId custom_emoji_id, bool default_result) const;
|
||||
|
||||
tl_object_ptr<td_api::sticker> get_sticker_object(FileId file_id, bool for_animated_emoji = false,
|
||||
bool for_clicked_animated_emoji = false) const;
|
||||
@ -84,7 +87,8 @@ class StickersManager final : public Actor {
|
||||
|
||||
td_api::object_ptr<td_api::sticker> get_premium_gift_sticker_object(int32 month_count);
|
||||
|
||||
td_api::object_ptr<td_api::animatedEmoji> get_animated_emoji_object(const string &emoji, int64 custom_emoji_id);
|
||||
td_api::object_ptr<td_api::animatedEmoji> get_animated_emoji_object(const string &emoji,
|
||||
CustomEmojiId custom_emoji_id);
|
||||
|
||||
tl_object_ptr<telegram_api::InputStickerSet> get_input_sticker_set(StickerSetId sticker_set_id) const;
|
||||
|
||||
@ -96,9 +100,11 @@ class StickersManager final : public Actor {
|
||||
|
||||
void unregister_dice(const string &emoji, int32 value, FullMessageId full_message_id, const char *source);
|
||||
|
||||
void register_emoji(const string &emoji, int64 custom_emoji_id, FullMessageId full_message_id, const char *source);
|
||||
void register_emoji(const string &emoji, CustomEmojiId custom_emoji_id, FullMessageId full_message_id,
|
||||
const char *source);
|
||||
|
||||
void unregister_emoji(const string &emoji, int64 custom_emoji_id, FullMessageId full_message_id, const char *source);
|
||||
void unregister_emoji(const string &emoji, CustomEmojiId custom_emoji_id, FullMessageId full_message_id,
|
||||
const char *source);
|
||||
|
||||
void get_animated_emoji(string emoji, bool is_recursive,
|
||||
Promise<td_api::object_ptr<td_api::animatedEmoji>> &&promise);
|
||||
@ -106,13 +112,13 @@ class StickersManager final : public Actor {
|
||||
void get_all_animated_emojis(bool is_recursive, Promise<td_api::object_ptr<td_api::emojis>> &&promise);
|
||||
|
||||
void get_custom_emoji_reaction_generic_animations(bool is_recursive,
|
||||
Promise<td_api::object_ptr<td_api::files>> &&promise);
|
||||
Promise<td_api::object_ptr<td_api::stickers>> &&promise);
|
||||
|
||||
void get_default_emoji_statuses(bool is_recursive, Promise<td_api::object_ptr<td_api::emojiStatuses>> &&promise);
|
||||
|
||||
bool is_default_emoji_status(int64 custom_emoji_id);
|
||||
bool is_default_emoji_status(CustomEmojiId custom_emoji_id);
|
||||
|
||||
void get_custom_emoji_stickers(vector<int64> &&document_ids, bool use_database,
|
||||
void get_custom_emoji_stickers(vector<CustomEmojiId> &&custom_emoji_ids, bool use_database,
|
||||
Promise<td_api::object_ptr<td_api::stickers>> &&promise);
|
||||
|
||||
void get_premium_gift_option_sticker(int32 month_count, bool is_recursive,
|
||||
@ -145,7 +151,7 @@ class StickersManager final : public Actor {
|
||||
tl_object_ptr<telegram_api::InputEncryptedFile> input_file,
|
||||
BufferSlice thumbnail, int32 layer) const;
|
||||
|
||||
vector<FileId> get_stickers(StickerType sticker_type, string emoji, int32 limit, DialogId dialog_id, bool force,
|
||||
vector<FileId> get_stickers(StickerType sticker_type, string query, int32 limit, DialogId dialog_id, bool force,
|
||||
Promise<Unit> &&promise);
|
||||
|
||||
void search_stickers(string emoji, int32 limit, Promise<td_api::object_ptr<td_api::stickers>> &&promise);
|
||||
@ -265,7 +271,7 @@ class StickersManager final : public Actor {
|
||||
|
||||
void move_sticker_set_to_top_by_sticker_id(FileId sticker_id);
|
||||
|
||||
void move_sticker_set_to_top_by_custom_emoji_ids(const vector<int64> &custom_emoji_ids);
|
||||
void move_sticker_set_to_top_by_custom_emoji_ids(const vector<CustomEmojiId> &custom_emoji_ids);
|
||||
|
||||
FileId upload_sticker_file(UserId user_id, tl_object_ptr<td_api::inputSticker> &&sticker, Promise<Unit> &&promise);
|
||||
|
||||
@ -440,6 +446,7 @@ class StickersManager final : public Actor {
|
||||
bool is_inited_ = false; // basic information about the set
|
||||
bool was_loaded_ = false;
|
||||
bool is_loaded_ = false;
|
||||
bool are_keywords_loaded_ = false;
|
||||
|
||||
StickerSetId id_;
|
||||
int64 access_hash_ = 0;
|
||||
@ -457,8 +464,10 @@ class StickersManager final : public Actor {
|
||||
|
||||
vector<FileId> sticker_ids_;
|
||||
vector<int32> premium_sticker_positions_;
|
||||
FlatHashMap<string, vector<FileId>> emoji_stickers_map_; // emoji -> stickers
|
||||
FlatHashMap<FileId, vector<string>, FileIdHash> sticker_emojis_map_; // sticker -> emojis
|
||||
FlatHashMap<string, vector<FileId>> emoji_stickers_map_; // emoji -> stickers
|
||||
FlatHashMap<FileId, vector<string>, FileIdHash> sticker_emojis_map_; // sticker -> emojis
|
||||
mutable std::map<string, vector<FileId>> keyword_stickers_map_; // keyword -> stickers
|
||||
FlatHashMap<FileId, vector<string>, FileIdHash> sticker_keywords_map_; // sticker -> keywords
|
||||
|
||||
bool is_installed_ = false;
|
||||
bool is_archived_ = false;
|
||||
@ -589,7 +598,7 @@ class StickersManager final : public Actor {
|
||||
|
||||
class UploadStickerFileCallback;
|
||||
|
||||
int64 get_custom_emoji_id(FileId sticker_id) const;
|
||||
CustomEmojiId get_custom_emoji_id(FileId sticker_id) const;
|
||||
|
||||
static vector<td_api::object_ptr<td_api::closedVectorPath>> get_sticker_minithumbnail(CSlice path,
|
||||
StickerSetId sticker_set_id,
|
||||
@ -613,17 +622,18 @@ class StickersManager final : public Actor {
|
||||
|
||||
void on_search_stickers_finished(const string &emoji, const FoundStickers &found_stickers);
|
||||
|
||||
static string get_custom_emoji_database_key(int64 custom_emoji_id);
|
||||
static string get_custom_emoji_database_key(CustomEmojiId custom_emoji_id);
|
||||
|
||||
void load_custom_emoji_sticker_from_database_force(int64 custom_emoji_id);
|
||||
void load_custom_emoji_sticker_from_database_force(CustomEmojiId custom_emoji_id);
|
||||
|
||||
void load_custom_emoji_sticker_from_database(int64 custom_emoji_id, Promise<Unit> &&promise);
|
||||
void load_custom_emoji_sticker_from_database(CustomEmojiId custom_emoji_id, Promise<Unit> &&promise);
|
||||
|
||||
void on_load_custom_emoji_from_database(int64 custom_emoji_id, string value);
|
||||
void on_load_custom_emoji_from_database(CustomEmojiId custom_emoji_id, string value);
|
||||
|
||||
FileId on_get_sticker(unique_ptr<Sticker> new_sticker, bool replace);
|
||||
|
||||
StickerSet *get_sticker_set(StickerSetId sticker_set_id);
|
||||
|
||||
const StickerSet *get_sticker_set(StickerSetId sticker_set_id) const;
|
||||
|
||||
StickerSet *add_sticker_set(StickerSetId sticker_set_id, int64 access_hash);
|
||||
@ -821,14 +831,14 @@ class StickersManager final : public Actor {
|
||||
|
||||
FileId get_animated_emoji_sound_file_id(const string &emoji) const;
|
||||
|
||||
FileId get_custom_animated_emoji_sticker_id(int64 custom_emoji_id) const;
|
||||
FileId get_custom_animated_emoji_sticker_id(CustomEmojiId custom_emoji_id) const;
|
||||
|
||||
td_api::object_ptr<td_api::animatedEmoji> get_animated_emoji_object(std::pair<FileId, int> animated_sticker,
|
||||
FileId sound_file_id) const;
|
||||
|
||||
void try_update_animated_emoji_messages();
|
||||
|
||||
void try_update_custom_emoji_messages(int64 custom_emoji_id);
|
||||
void try_update_custom_emoji_messages(CustomEmojiId custom_emoji_id);
|
||||
|
||||
static int get_emoji_number(Slice emoji);
|
||||
|
||||
@ -893,12 +903,19 @@ class StickersManager final : public Actor {
|
||||
|
||||
static void add_sticker_thumbnail(Sticker *s, PhotoSize thumbnail);
|
||||
|
||||
td_api::object_ptr<td_api::stickers> get_custom_emoji_stickers_object(const vector<int64> &document_ids);
|
||||
td_api::object_ptr<td_api::stickers> get_custom_emoji_stickers_object(const vector<CustomEmojiId> &custom_emoji_ids);
|
||||
|
||||
void on_get_custom_emoji_documents(Result<vector<telegram_api::object_ptr<telegram_api::Document>>> &&r_documents,
|
||||
vector<int64> &&document_ids,
|
||||
vector<CustomEmojiId> &&custom_emoji_ids,
|
||||
Promise<td_api::object_ptr<td_api::stickers>> &&promise);
|
||||
|
||||
static const std::map<string, vector<FileId>> &get_sticker_set_keywords(const StickerSet *sticker_set);
|
||||
|
||||
static void find_sticker_set_stickers(const StickerSet *sticker_set, const string &query,
|
||||
const string &prepared_query, vector<FileId> &result);
|
||||
|
||||
bool can_found_sticker_by_query(FileId sticker_id, const string &query, const string &prepared_query) const;
|
||||
|
||||
static string get_emoji_language_code_version_database_key(const string &language_code);
|
||||
|
||||
static string get_emoji_language_code_last_difference_time_database_key(const string &language_code);
|
||||
@ -1019,7 +1036,7 @@ class StickersManager final : public Actor {
|
||||
FlatHashMap<uint32, StickerSetLoadRequest> sticker_set_load_requests_;
|
||||
uint32 current_sticker_set_load_request_ = 0;
|
||||
|
||||
FlatHashMap<int64, vector<Promise<Unit>>> custom_emoji_load_queries_;
|
||||
FlatHashMap<CustomEmojiId, vector<Promise<Unit>>, CustomEmojiIdHash> custom_emoji_load_queries_;
|
||||
|
||||
FlatHashMap<int64, unique_ptr<PendingNewStickerSet>> pending_new_sticker_sets_;
|
||||
|
||||
@ -1089,7 +1106,7 @@ class StickersManager final : public Actor {
|
||||
WaitFreeHashSet<FullMessageId, FullMessageIdHash> full_message_ids_;
|
||||
FileId sticker_id_;
|
||||
};
|
||||
FlatHashMap<int64, unique_ptr<CustomEmojiMessages>> custom_emoji_messages_;
|
||||
FlatHashMap<CustomEmojiId, unique_ptr<CustomEmojiMessages>, CustomEmojiIdHash> custom_emoji_messages_;
|
||||
|
||||
string dice_emojis_str_;
|
||||
vector<string> dice_emojis_;
|
||||
@ -1100,7 +1117,7 @@ class StickersManager final : public Actor {
|
||||
string emoji_sounds_str_;
|
||||
FlatHashMap<string, FileId> emoji_sounds_;
|
||||
|
||||
WaitFreeHashMap<int64, FileId> custom_emoji_to_sticker_id_;
|
||||
WaitFreeHashMap<CustomEmojiId, FileId, CustomEmojiIdHash> custom_emoji_to_sticker_id_;
|
||||
|
||||
double animated_emoji_zoom_ = 0.0;
|
||||
|
||||
|
@ -204,6 +204,7 @@ void StickersManager::store_sticker_set(const StickerSet *sticker_set, bool with
|
||||
STORE_FLAG(is_webm);
|
||||
STORE_FLAG(is_emojis);
|
||||
STORE_FLAG(has_thumbnail_document_id);
|
||||
STORE_FLAG(sticker_set->are_keywords_loaded_);
|
||||
END_STORE_FLAGS();
|
||||
store(sticker_set->id_.get(), storer);
|
||||
store(sticker_set->access_hash_, storer);
|
||||
@ -239,6 +240,14 @@ void StickersManager::store_sticker_set(const StickerSet *sticker_set, bool with
|
||||
store(vector<string>(), storer);
|
||||
}
|
||||
}
|
||||
if (sticker_set->are_keywords_loaded_) {
|
||||
auto it = sticker_set->sticker_keywords_map_.find(sticker_id);
|
||||
if (it != sticker_set->sticker_keywords_map_.end()) {
|
||||
store(it->second, storer);
|
||||
} else {
|
||||
store(vector<string>(), storer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -277,6 +286,7 @@ void StickersManager::parse_sticker_set(StickerSet *sticker_set, ParserT &parser
|
||||
PARSE_FLAG(is_webm);
|
||||
PARSE_FLAG(is_emojis);
|
||||
PARSE_FLAG(has_thumbnail_document_id);
|
||||
PARSE_FLAG(sticker_set->are_keywords_loaded_);
|
||||
END_PARSE_FLAGS();
|
||||
int64 sticker_set_id;
|
||||
int64 access_hash;
|
||||
@ -367,6 +377,8 @@ void StickersManager::parse_sticker_set(StickerSet *sticker_set, ParserT &parser
|
||||
if (sticker_set->was_loaded_) {
|
||||
sticker_set->emoji_stickers_map_.clear();
|
||||
sticker_set->sticker_emojis_map_.clear();
|
||||
sticker_set->keyword_stickers_map_.clear();
|
||||
sticker_set->sticker_keywords_map_.clear();
|
||||
}
|
||||
for (uint32 i = 0; i < stored_sticker_count; i++) {
|
||||
auto sticker_id = parse_sticker(true, parser);
|
||||
@ -405,6 +417,13 @@ void StickersManager::parse_sticker_set(StickerSet *sticker_set, ParserT &parser
|
||||
}
|
||||
sticker_set->sticker_emojis_map_[sticker_id] = std::move(emojis);
|
||||
}
|
||||
if (sticker_set->are_keywords_loaded_) {
|
||||
vector<string> keywords;
|
||||
parse(keywords, parser);
|
||||
if (!keywords.empty()) {
|
||||
sticker_set->sticker_keywords_map_.emplace(sticker_id, std::move(keywords));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (expires_at > sticker_set->expires_at_) {
|
||||
sticker_set->expires_at_ = expires_at;
|
||||
|
@ -7,9 +7,11 @@
|
||||
#include "td/telegram/Support.h"
|
||||
|
||||
#include "td/telegram/ContactsManager.h"
|
||||
#include "td/telegram/DialogId.h"
|
||||
#include "td/telegram/Global.h"
|
||||
#include "td/telegram/MessageEntity.h"
|
||||
#include "td/telegram/Td.h"
|
||||
#include "td/telegram/telegram_api.h"
|
||||
|
||||
#include "td/utils/buffer.h"
|
||||
#include "td/utils/Status.h"
|
||||
@ -102,9 +104,9 @@ void get_user_info(Td *td, UserId user_id, Promise<td_api::object_ptr<td_api::us
|
||||
|
||||
void set_user_info(Td *td, UserId user_id, td_api::object_ptr<td_api::formattedText> &&message,
|
||||
Promise<td_api::object_ptr<td_api::userSupportInfo>> &&promise) {
|
||||
TRY_RESULT_PROMISE(
|
||||
promise, formatted_text,
|
||||
get_formatted_text(td, DialogId(td->contacts_manager_->get_my_id()), std::move(message), false, true, true, false));
|
||||
TRY_RESULT_PROMISE(promise, formatted_text,
|
||||
get_formatted_text(td, DialogId(td->contacts_manager_->get_my_id()), std::move(message), false,
|
||||
true, true, false));
|
||||
td->create_handler<EditUserInfoQuery>(std::move(promise))->send(user_id, std::move(formatted_text));
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "td/telegram/ConfigManager.h"
|
||||
#include "td/telegram/ContactsManager.h"
|
||||
#include "td/telegram/CountryInfoManager.h"
|
||||
#include "td/telegram/CustomEmojiId.h"
|
||||
#include "td/telegram/DeviceTokenManager.h"
|
||||
#include "td/telegram/DialogAction.h"
|
||||
#include "td/telegram/DialogEventLog.h"
|
||||
@ -41,6 +42,7 @@
|
||||
#include "td/telegram/DocumentsManager.h"
|
||||
#include "td/telegram/DownloadManager.h"
|
||||
#include "td/telegram/DownloadManagerCallback.h"
|
||||
#include "td/telegram/EmailVerification.h"
|
||||
#include "td/telegram/EmojiStatus.h"
|
||||
#include "td/telegram/FileReferenceManager.h"
|
||||
#include "td/telegram/files/FileGcParameters.h"
|
||||
@ -121,6 +123,7 @@
|
||||
#include "td/telegram/TopDialogCategory.h"
|
||||
#include "td/telegram/TopDialogManager.h"
|
||||
#include "td/telegram/UpdatesManager.h"
|
||||
#include "td/telegram/UserId.h"
|
||||
#include "td/telegram/Version.h"
|
||||
#include "td/telegram/VideoNotesManager.h"
|
||||
#include "td/telegram/VideosManager.h"
|
||||
@ -1987,14 +1990,14 @@ class GetScopeNotificationSettingsRequest final : public RequestActor<> {
|
||||
|
||||
class GetStickersRequest final : public RequestActor<> {
|
||||
StickerType sticker_type_;
|
||||
string emoji_;
|
||||
string query_;
|
||||
int32 limit_;
|
||||
DialogId dialog_id_;
|
||||
|
||||
vector<FileId> sticker_ids_;
|
||||
|
||||
void do_run(Promise<Unit> &&promise) final {
|
||||
sticker_ids_ = td_->stickers_manager_->get_stickers(sticker_type_, emoji_, limit_, dialog_id_, get_tries() < 2,
|
||||
sticker_ids_ = td_->stickers_manager_->get_stickers(sticker_type_, query_, limit_, dialog_id_, get_tries() < 2,
|
||||
std::move(promise));
|
||||
}
|
||||
|
||||
@ -2003,11 +2006,11 @@ class GetStickersRequest final : public RequestActor<> {
|
||||
}
|
||||
|
||||
public:
|
||||
GetStickersRequest(ActorShared<Td> td, uint64 request_id, StickerType sticker_type, string &&emoji, int32 limit,
|
||||
GetStickersRequest(ActorShared<Td> td, uint64 request_id, StickerType sticker_type, string &&query, int32 limit,
|
||||
int64 dialog_id)
|
||||
: RequestActor(std::move(td), request_id)
|
||||
, sticker_type_(sticker_type)
|
||||
, emoji_(std::move(emoji))
|
||||
, query_(std::move(query))
|
||||
, limit_(limit)
|
||||
, dialog_id_(dialog_id) {
|
||||
set_tries(4);
|
||||
@ -3360,13 +3363,10 @@ void Td::clear() {
|
||||
close_flag_ = 2;
|
||||
|
||||
Timer timer;
|
||||
if (destroy_flag_) {
|
||||
option_manager_->clear_options();
|
||||
if (!auth_manager_->is_bot()) {
|
||||
if (!auth_manager_->is_bot()) {
|
||||
if (destroy_flag_) {
|
||||
notification_manager_->destroy_all_notifications();
|
||||
}
|
||||
} else {
|
||||
if (!auth_manager_->is_bot()) {
|
||||
} else {
|
||||
notification_manager_->flush_all_notifications();
|
||||
}
|
||||
}
|
||||
@ -3773,10 +3773,10 @@ void Td::init_connection_creator() {
|
||||
auto net_stats_manager = create_actor<NetStatsManager>("NetStatsManager", create_reference());
|
||||
|
||||
// How else could I let two actor know about each other, without quite complex async logic?
|
||||
auto net_stats_manager_ptr = net_stats_manager->get_actor_unsafe();
|
||||
auto net_stats_manager_ptr = net_stats_manager.get_actor_unsafe();
|
||||
net_stats_manager_ptr->init();
|
||||
connection_creator->get_actor_unsafe()->set_net_stats_callback(net_stats_manager_ptr->get_common_stats_callback(),
|
||||
net_stats_manager_ptr->get_media_stats_callback());
|
||||
connection_creator.get_actor_unsafe()->set_net_stats_callback(net_stats_manager_ptr->get_common_stats_callback(),
|
||||
net_stats_manager_ptr->get_media_stats_callback());
|
||||
G()->set_net_stats_file_callbacks(net_stats_manager_ptr->get_file_stats_callbacks());
|
||||
|
||||
G()->set_connection_creator(std::move(connection_creator));
|
||||
@ -4031,7 +4031,7 @@ void Td::send_error_impl(uint64 id, tl_object_ptr<td_api::error> error) {
|
||||
auto it = request_set_.find(id);
|
||||
if (it != request_set_.end()) {
|
||||
if (error->code_ == 0 && error->message_ == "Lost promise") {
|
||||
LOG(FATAL) << "Lost promise for query " << id << " of type " << it->second;
|
||||
LOG(FATAL) << "Lost promise for query " << id << " of type " << it->second << " in close state " << close_flag_;
|
||||
}
|
||||
VLOG(td_requests) << "Sending error for request " << id << ": " << oneline(to_string(error));
|
||||
request_set_.erase(it);
|
||||
@ -4308,7 +4308,7 @@ void Td::on_request(uint64 id, const td_api::getCurrentState &request) {
|
||||
|
||||
notification_manager_->get_current_state(updates);
|
||||
|
||||
config_manager_->get_actor_unsafe()->get_current_state(updates);
|
||||
config_manager_.get_actor_unsafe()->get_current_state(updates);
|
||||
|
||||
// TODO updateFileGenerationStart generation_id:int64 original_path:string destination_path:string conversion:string = Update;
|
||||
// TODO updateCall call:call = Update;
|
||||
@ -4725,7 +4725,13 @@ void Td::on_request(uint64 id, const td_api::rateSpeechRecognition &request) {
|
||||
}
|
||||
|
||||
void Td::on_request(uint64 id, const td_api::getFile &request) {
|
||||
send_closure(actor_id(this), &Td::send_result, id, file_manager_->get_file_object(FileId(request.file_id_, 0)));
|
||||
auto file_object = file_manager_->get_file_object(FileId(request.file_id_, 0));
|
||||
if (file_object->id_ == 0) {
|
||||
file_object = nullptr;
|
||||
} else {
|
||||
file_object->id_ = request.file_id_;
|
||||
}
|
||||
send_closure(actor_id(this), &Td::send_result, id, std::move(file_object));
|
||||
}
|
||||
|
||||
void Td::on_request(uint64 id, td_api::getRemoteFile &request) {
|
||||
@ -5231,6 +5237,21 @@ void Td::on_request(uint64 id, const td_api::getChatMessageCount &request) {
|
||||
request.return_local_, std::move(query_promise));
|
||||
}
|
||||
|
||||
void Td::on_request(uint64 id, const td_api::getChatMessagePosition &request) {
|
||||
CHECK_IS_USER();
|
||||
CREATE_REQUEST_PROMISE();
|
||||
auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result<int32> result) mutable {
|
||||
if (result.is_error()) {
|
||||
promise.set_error(result.move_as_error());
|
||||
} else {
|
||||
promise.set_value(make_tl_object<td_api::count>(result.move_as_ok()));
|
||||
}
|
||||
});
|
||||
messages_manager_->get_dialog_message_position({DialogId(request.chat_id_), MessageId(request.message_id_)},
|
||||
get_message_search_filter(request.filter_),
|
||||
MessageId(request.message_thread_id_), std::move(query_promise));
|
||||
}
|
||||
|
||||
void Td::on_request(uint64 id, const td_api::getChatScheduledMessages &request) {
|
||||
CHECK_IS_USER();
|
||||
CREATE_REQUEST(GetChatScheduledMessagesRequest, request.chat_id_);
|
||||
@ -6424,11 +6445,12 @@ void Td::on_request(uint64 id, const td_api::downloadFile &request) {
|
||||
DownloadInfo *info = info_it == pending_file_downloads_.end() ? nullptr : &info_it->second;
|
||||
if (info != nullptr && (offset != info->offset || limit != info->limit)) {
|
||||
// we can't have two pending requests with different offset and limit, so cancel all previous requests
|
||||
for (auto request_id : info->request_ids) {
|
||||
auto request_ids = std::move(info->request_ids);
|
||||
info->request_ids.clear();
|
||||
for (auto request_id : request_ids) {
|
||||
send_closure(actor_id(this), &Td::send_error, request_id,
|
||||
Status::Error(200, "Canceled by another downloadFile request"));
|
||||
}
|
||||
info->request_ids.clear();
|
||||
}
|
||||
if (request.synchronous_) {
|
||||
if (info == nullptr) {
|
||||
@ -6438,10 +6460,12 @@ void Td::on_request(uint64 id, const td_api::downloadFile &request) {
|
||||
info->limit = limit;
|
||||
info->request_ids.push_back(id);
|
||||
}
|
||||
file_manager_->download(file_id, download_file_callback_, priority, offset, limit);
|
||||
Promise<td_api::object_ptr<td_api::file>> download_promise;
|
||||
if (!request.synchronous_) {
|
||||
send_closure(actor_id(this), &Td::send_result, id, file_manager_->get_file_object(file_id, false));
|
||||
CREATE_REQUEST_PROMISE();
|
||||
download_promise = std::move(promise);
|
||||
}
|
||||
file_manager_->download(file_id, download_file_callback_, priority, offset, limit, std::move(download_promise));
|
||||
}
|
||||
|
||||
void Td::on_file_download_finished(FileId file_id) {
|
||||
@ -6486,8 +6510,8 @@ void Td::on_request(uint64 id, const td_api::getFileDownloadedPrefixSize &reques
|
||||
|
||||
void Td::on_request(uint64 id, const td_api::cancelDownloadFile &request) {
|
||||
file_manager_->download(FileId(request.file_id_, 0), nullptr, request.only_if_pending_ ? -1 : 0,
|
||||
FileManager::KEEP_DOWNLOAD_OFFSET, FileManager::KEEP_DOWNLOAD_LIMIT);
|
||||
|
||||
FileManager::KEEP_DOWNLOAD_OFFSET, FileManager::KEEP_DOWNLOAD_LIMIT,
|
||||
Promise<td_api::object_ptr<td_api::file>>());
|
||||
send_closure(actor_id(this), &Td::send_result, id, make_tl_object<td_api::ok>());
|
||||
}
|
||||
|
||||
@ -6924,8 +6948,8 @@ void Td::on_request(uint64 id, td_api::closeSecretChat &request) {
|
||||
|
||||
void Td::on_request(uint64 id, td_api::getStickers &request) {
|
||||
CHECK_IS_USER();
|
||||
CLEAN_INPUT_STRING(request.emoji_);
|
||||
CREATE_REQUEST(GetStickersRequest, get_sticker_type(request.sticker_type_), std::move(request.emoji_), request.limit_,
|
||||
CLEAN_INPUT_STRING(request.query_);
|
||||
CREATE_REQUEST(GetStickersRequest, get_sticker_type(request.sticker_type_), std::move(request.query_), request.limit_,
|
||||
request.chat_id_);
|
||||
}
|
||||
|
||||
@ -7136,9 +7160,11 @@ void Td::on_request(uint64 id, td_api::getEmojiSuggestionsUrl &request) {
|
||||
CREATE_REQUEST(GetEmojiSuggestionsUrlRequest, std::move(request.language_code_));
|
||||
}
|
||||
|
||||
void Td::on_request(uint64 id, td_api::getCustomEmojiStickers &request) {
|
||||
void Td::on_request(uint64 id, const td_api::getCustomEmojiStickers &request) {
|
||||
CREATE_REQUEST_PROMISE();
|
||||
stickers_manager_->get_custom_emoji_stickers(std::move(request.custom_emoji_ids_), true, std::move(promise));
|
||||
stickers_manager_->get_custom_emoji_stickers(
|
||||
transform(request.custom_emoji_ids_, [](int64 custom_emoji_id) { return CustomEmojiId(custom_emoji_id); }), true,
|
||||
std::move(promise));
|
||||
}
|
||||
|
||||
void Td::on_request(uint64 id, const td_api::getSavedAnimations &request) {
|
||||
@ -8214,7 +8240,7 @@ td_api::object_ptr<td_api::Object> Td::do_static_request(td_api::parseMarkdown &
|
||||
auto entities = r_entities.move_as_ok();
|
||||
auto status = fix_formatted_text(request.text_->text_, entities, true, true, true, true, true);
|
||||
if (status.is_error()) {
|
||||
return make_error(400, status.error().message());
|
||||
return make_error(400, status.message());
|
||||
}
|
||||
|
||||
auto parsed_text = parse_markdown_v3({std::move(request.text_->text_), std::move(entities)});
|
||||
@ -8241,7 +8267,7 @@ td_api::object_ptr<td_api::Object> Td::do_static_request(td_api::getMarkdownText
|
||||
auto entities = r_entities.move_as_ok();
|
||||
auto status = fix_formatted_text(request.text_->text_, entities, true, true, true, true, true);
|
||||
if (status.is_error()) {
|
||||
return make_error(400, status.error().message());
|
||||
return make_error(400, status.message());
|
||||
}
|
||||
|
||||
return get_formatted_text_object(get_markdown_v3({std::move(request.text_->text_), std::move(entities)}), false,
|
||||
|
@ -100,7 +100,7 @@ extern int VERBOSITY_NAME(td_requests);
|
||||
// It happens after "hangup".
|
||||
//
|
||||
// Parent needs a way to know that it will receive no more updates.
|
||||
// It happens after destruction of callback or after on_closed.
|
||||
// It happens after destruction of callback
|
||||
class Td final : public Actor {
|
||||
public:
|
||||
Td(const Td &) = delete;
|
||||
@ -205,8 +205,8 @@ class Td final : public Actor {
|
||||
ActorOwn<NetStatsManager> net_stats_manager_;
|
||||
ActorOwn<PasswordManager> password_manager_;
|
||||
ActorOwn<PrivacyManager> privacy_manager_;
|
||||
ActorOwn<SecureManager> secure_manager_;
|
||||
ActorOwn<SecretChatsManager> secret_chats_manager_;
|
||||
ActorOwn<SecureManager> secure_manager_;
|
||||
ActorOwn<StateManager> state_manager_;
|
||||
ActorOwn<StorageManager> storage_manager_;
|
||||
ActorOwn<PhoneNumberManager> verify_phone_number_manager_;
|
||||
@ -665,6 +665,8 @@ class Td final : public Actor {
|
||||
|
||||
void on_request(uint64 id, const td_api::getChatMessageCount &request);
|
||||
|
||||
void on_request(uint64 id, const td_api::getChatMessagePosition &request);
|
||||
|
||||
void on_request(uint64 id, const td_api::getChatScheduledMessages &request);
|
||||
|
||||
void on_request(uint64 id, const td_api::getEmojiReaction &request);
|
||||
@ -1155,7 +1157,7 @@ class Td final : public Actor {
|
||||
|
||||
void on_request(uint64 id, td_api::getEmojiSuggestionsUrl &request);
|
||||
|
||||
void on_request(uint64 id, td_api::getCustomEmojiStickers &request);
|
||||
void on_request(uint64 id, const td_api::getCustomEmojiStickers &request);
|
||||
|
||||
void on_request(uint64 id, const td_api::getFavoriteStickers &request);
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "td/telegram/BackgroundManager.h"
|
||||
#include "td/telegram/BackgroundType.hpp"
|
||||
#include "td/telegram/Global.h"
|
||||
#include "td/telegram/logevent/LogEvent.h"
|
||||
#include "td/telegram/net/NetQueryCreator.h"
|
||||
#include "td/telegram/Td.h"
|
||||
#include "td/telegram/TdDb.h"
|
||||
|
@ -30,13 +30,14 @@
|
||||
#include "td/telegram/MessageId.h"
|
||||
#include "td/telegram/MessagesManager.h"
|
||||
#include "td/telegram/MessageTtl.h"
|
||||
#include "td/telegram/misc.h"
|
||||
#include "td/telegram/net/DcOptions.h"
|
||||
#include "td/telegram/net/NetQuery.h"
|
||||
#include "td/telegram/NotificationManager.h"
|
||||
#include "td/telegram/NotificationSettings.h"
|
||||
#include "td/telegram/NotificationSettingsManager.h"
|
||||
#include "td/telegram/OptionManager.h"
|
||||
#include "td/telegram/Payments.h"
|
||||
#include "td/telegram/OrderInfo.h"
|
||||
#include "td/telegram/PollId.h"
|
||||
#include "td/telegram/PollManager.h"
|
||||
#include "td/telegram/PrivacyManager.h"
|
||||
@ -991,8 +992,14 @@ void UpdatesManager::on_get_updates(tl_object_ptr<telegram_api::Updates> &&updat
|
||||
}
|
||||
case telegram_api::updates::ID: {
|
||||
auto updates = move_tl_object_as<telegram_api::updates>(updates_ptr);
|
||||
td_->contacts_manager_->on_get_users(std::move(updates->users_), "updates");
|
||||
td_->contacts_manager_->on_get_chats(std::move(updates->chats_), "updates");
|
||||
string source_str;
|
||||
const char *source = "updates";
|
||||
if (updates->updates_.size() == 1 && updates->updates_[0] != nullptr) {
|
||||
source_str = PSTRING() << "update " << updates->updates_[0]->get_id();
|
||||
source = source_str.c_str();
|
||||
}
|
||||
td_->contacts_manager_->on_get_users(std::move(updates->users_), source);
|
||||
td_->contacts_manager_->on_get_chats(std::move(updates->chats_), source);
|
||||
on_pending_updates(std::move(updates->updates_), updates->seq_, updates->seq_, updates->date_, Time::now(),
|
||||
std::move(promise), "telegram_api::updates");
|
||||
break;
|
||||
@ -3520,6 +3527,13 @@ void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateGeoLiveViewed>
|
||||
promise.set_value(Unit());
|
||||
}
|
||||
|
||||
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateMessageExtendedMedia> update,
|
||||
Promise<Unit> &&promise) {
|
||||
td_->messages_manager_->on_update_message_extended_media(
|
||||
{DialogId(update->peer_), MessageId(ServerMessageId(update->msg_id_))}, std::move(update->extended_media_));
|
||||
promise.set_value(Unit());
|
||||
}
|
||||
|
||||
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateMessagePoll> update, Promise<Unit> &&promise) {
|
||||
td_->poll_manager_->on_get_poll(PollId(update->poll_id_), std::move(update->poll_), std::move(update->results_),
|
||||
"updateMessagePoll");
|
||||
|
@ -517,6 +517,7 @@ class UpdatesManager final : public Actor {
|
||||
void on_update(tl_object_ptr<telegram_api::updateLangPack> update, Promise<Unit> &&promise);
|
||||
|
||||
void on_update(tl_object_ptr<telegram_api::updateGeoLiveViewed> update, Promise<Unit> &&promise);
|
||||
void on_update(tl_object_ptr<telegram_api::updateMessageExtendedMedia> update, Promise<Unit> &&promise);
|
||||
|
||||
void on_update(tl_object_ptr<telegram_api::updateMessagePoll> update, Promise<Unit> &&promise);
|
||||
void on_update(tl_object_ptr<telegram_api::updateMessagePollVote> update, Promise<Unit> &&promise);
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
namespace td {
|
||||
|
||||
constexpr int32 MTPROTO_LAYER = 145;
|
||||
constexpr int32 MTPROTO_LAYER = 147;
|
||||
|
||||
enum class Version : int32 {
|
||||
Initial, // 0
|
||||
@ -55,6 +55,7 @@ enum class Version : int32 {
|
||||
AddVoiceNoteFlags,
|
||||
AddMessageStickerFlags, // 40
|
||||
AddStickerSetListFlags,
|
||||
AddInputInvoiceFlags,
|
||||
Next
|
||||
};
|
||||
|
||||
|
@ -161,9 +161,9 @@ SecretInputMedia VideoNotesManager::get_secret_input_media(FileId video_note_fil
|
||||
return SecretInputMedia{};
|
||||
}
|
||||
vector<tl_object_ptr<secret_api::DocumentAttribute>> attributes;
|
||||
attributes.push_back(make_tl_object<secret_api::documentAttributeVideo66>(
|
||||
secret_api::documentAttributeVideo66::ROUND_MESSAGE_MASK, true, video_note->duration,
|
||||
video_note->dimensions.width, video_note->dimensions.height));
|
||||
attributes.push_back(make_tl_object<secret_api::documentAttributeVideo>(
|
||||
secret_api::documentAttributeVideo::ROUND_MESSAGE_MASK, true, video_note->duration, video_note->dimensions.width,
|
||||
video_note->dimensions.height));
|
||||
|
||||
return {std::move(input_file),
|
||||
std::move(thumbnail),
|
||||
|
@ -208,8 +208,8 @@ SecretInputMedia VideosManager::get_secret_input_media(FileId video_file_id,
|
||||
return {};
|
||||
}
|
||||
vector<tl_object_ptr<secret_api::DocumentAttribute>> attributes;
|
||||
attributes.emplace_back(make_tl_object<secret_api::documentAttributeVideo>(video->duration, video->dimensions.width,
|
||||
video->dimensions.height));
|
||||
attributes.emplace_back(make_tl_object<secret_api::documentAttributeVideo>(
|
||||
0, false, video->duration, video->dimensions.width, video->dimensions.height));
|
||||
|
||||
return {std::move(input_file),
|
||||
std::move(thumbnail),
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "td/telegram/DocumentsManager.h"
|
||||
#include "td/telegram/DocumentsManager.hpp"
|
||||
#include "td/telegram/files/FileId.h"
|
||||
#include "td/telegram/LinkManager.h"
|
||||
#include "td/telegram/Location.h"
|
||||
#include "td/telegram/Photo.h"
|
||||
#include "td/telegram/Photo.hpp"
|
||||
@ -32,6 +33,7 @@
|
||||
|
||||
#include "td/utils/algorithm.h"
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/HttpUrl.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/misc.h"
|
||||
#include "td/utils/SliceBuilder.h"
|
||||
@ -47,6 +49,8 @@ class RichText;
|
||||
struct GetWebPageBlockObjectContext {
|
||||
Td *td_ = nullptr;
|
||||
Slice base_url_;
|
||||
string real_url_host_;
|
||||
string real_url_rhash_;
|
||||
|
||||
bool is_first_pass_ = true;
|
||||
bool has_anchor_urls_ = false;
|
||||
@ -147,6 +151,15 @@ class RichText {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!context->real_url_rhash_.empty() && get_url_host(content) == context->real_url_host_) {
|
||||
if (context->is_first_pass_) {
|
||||
context->has_anchor_urls_ = true;
|
||||
} else {
|
||||
return make_tl_object<td_api::richTextUrl>(
|
||||
texts[0].get_rich_text_object(context),
|
||||
LinkManager::get_instant_view_link(content, context->real_url_rhash_), true);
|
||||
}
|
||||
}
|
||||
return make_tl_object<td_api::richTextUrl>(texts[0].get_rich_text_object(context), content,
|
||||
web_page_id.is_valid());
|
||||
case RichText::Type::EmailAddress:
|
||||
@ -2387,12 +2400,19 @@ vector<unique_ptr<WebPageBlock>> get_web_page_blocks(
|
||||
}
|
||||
|
||||
vector<td_api::object_ptr<td_api::PageBlock>> get_page_blocks_object(
|
||||
const vector<unique_ptr<WebPageBlock>> &page_blocks, Td *td, Slice base_url) {
|
||||
const vector<unique_ptr<WebPageBlock>> &page_blocks, Td *td, Slice base_url, Slice real_url) {
|
||||
GetWebPageBlockObjectContext context;
|
||||
context.td_ = td;
|
||||
context.base_url_ = base_url;
|
||||
context.real_url_rhash_ = LinkManager::get_instant_view_link_rhash(real_url);
|
||||
if (!context.real_url_rhash_.empty()) {
|
||||
context.real_url_host_ = get_url_host(LinkManager::get_instant_view_link_url(real_url));
|
||||
if (context.real_url_host_.empty()) {
|
||||
context.real_url_rhash_ = string();
|
||||
}
|
||||
}
|
||||
auto blocks = get_page_blocks_object(page_blocks, &context);
|
||||
if (context.anchors_.empty() || !context.has_anchor_urls_) {
|
||||
if (!context.has_anchor_urls_) {
|
||||
return blocks;
|
||||
}
|
||||
|
||||
|
@ -102,6 +102,6 @@ vector<unique_ptr<WebPageBlock>> get_web_page_blocks(
|
||||
const FlatHashMap<int64, FileId> &videos, const FlatHashMap<int64, FileId> &voice_notes);
|
||||
|
||||
vector<td_api::object_ptr<td_api::PageBlock>> get_page_blocks_object(
|
||||
const vector<unique_ptr<WebPageBlock>> &page_blocks, Td *td, Slice base_url);
|
||||
const vector<unique_ptr<WebPageBlock>> &page_blocks, Td *td, Slice base_url, Slice real_url);
|
||||
|
||||
} // namespace td
|
||||
|
@ -578,6 +578,11 @@ void WebPagesManager::update_web_page(unique_ptr<WebPage> web_page, WebPageId we
|
||||
}
|
||||
page = std::move(web_page);
|
||||
|
||||
// must be called before any other action for correct behavior of get_url_file_source_id
|
||||
if (!page->url.empty()) {
|
||||
on_get_web_page_by_url(page->url, web_page_id, from_database);
|
||||
}
|
||||
|
||||
update_web_page_instant_view(web_page_id, page->instant_view, std::move(old_instant_view));
|
||||
|
||||
auto new_file_ids = get_web_page_file_ids(page.get());
|
||||
@ -585,10 +590,6 @@ void WebPagesManager::update_web_page(unique_ptr<WebPage> web_page, WebPageId we
|
||||
td_->file_manager_->change_files_source(get_web_page_file_source_id(page.get()), old_file_ids, new_file_ids);
|
||||
}
|
||||
|
||||
if (!page->url.empty()) {
|
||||
on_get_web_page_by_url(page->url, web_page_id, from_database);
|
||||
}
|
||||
|
||||
if (is_changed && !from_database) {
|
||||
on_web_page_changed(web_page_id, true);
|
||||
|
||||
@ -1053,13 +1054,13 @@ WebPageId WebPagesManager::get_web_page_by_url(const string &url) const {
|
||||
return WebPageId();
|
||||
}
|
||||
|
||||
LOG(INFO) << "Get web page identifier for the url \"" << url << '"';
|
||||
|
||||
auto it = url_to_web_page_id_.find(url);
|
||||
if (it != url_to_web_page_id_.end()) {
|
||||
LOG(INFO) << "Return " << it->second << " for the url \"" << url << '"';
|
||||
return it->second;
|
||||
}
|
||||
|
||||
LOG(INFO) << "Can't find web page identifier for the url \"" << url << '"';
|
||||
return WebPageId();
|
||||
}
|
||||
|
||||
@ -1299,11 +1300,15 @@ tl_object_ptr<td_api::webPage> WebPagesManager::get_web_page_object(WebPageId we
|
||||
|
||||
tl_object_ptr<td_api::webPageInstantView> WebPagesManager::get_web_page_instant_view_object(
|
||||
WebPageId web_page_id) const {
|
||||
return get_web_page_instant_view_object(web_page_id, get_web_page_instant_view(web_page_id));
|
||||
const WebPage *web_page = get_web_page(web_page_id);
|
||||
if (web_page == nullptr || web_page->instant_view.is_empty) {
|
||||
return nullptr;
|
||||
}
|
||||
return get_web_page_instant_view_object(web_page_id, &web_page->instant_view, web_page->url);
|
||||
}
|
||||
|
||||
tl_object_ptr<td_api::webPageInstantView> WebPagesManager::get_web_page_instant_view_object(
|
||||
WebPageId web_page_id, const WebPageInstantView *web_page_instant_view) const {
|
||||
WebPageId web_page_id, const WebPageInstantView *web_page_instant_view, Slice web_page_url) const {
|
||||
if (web_page_instant_view == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -1314,7 +1319,7 @@ tl_object_ptr<td_api::webPageInstantView> WebPagesManager::get_web_page_instant_
|
||||
auto feedback_link = td_api::make_object<td_api::internalLinkTypeBotStart>(
|
||||
"previews", PSTRING() << "webpage" << web_page_id.get(), true);
|
||||
return td_api::make_object<td_api::webPageInstantView>(
|
||||
get_page_blocks_object(web_page_instant_view->page_blocks, td_, web_page_instant_view->url),
|
||||
get_page_blocks_object(web_page_instant_view->page_blocks, td_, web_page_instant_view->url, web_page_url),
|
||||
web_page_instant_view->view_count, web_page_instant_view->is_v2 ? 2 : 1, web_page_instant_view->is_rtl,
|
||||
web_page_instant_view->is_full, std::move(feedback_link));
|
||||
}
|
||||
@ -1500,7 +1505,7 @@ void WebPagesManager::on_get_web_page_instant_view(WebPage *web_page, tl_object_
|
||||
web_page->instant_view.is_loaded = true;
|
||||
|
||||
LOG(DEBUG) << "Receive web page instant view: "
|
||||
<< to_string(get_web_page_instant_view_object(WebPageId(), &web_page->instant_view));
|
||||
<< to_string(get_web_page_instant_view_object(WebPageId(), &web_page->instant_view, web_page->url));
|
||||
}
|
||||
|
||||
class WebPagesManager::WebPageLogEvent {
|
||||
@ -1688,6 +1693,9 @@ const WebPagesManager::WebPage *WebPagesManager::get_web_page_force(WebPageId we
|
||||
FileSourceId WebPagesManager::get_web_page_file_source_id(WebPage *web_page) {
|
||||
if (!web_page->file_source_id.is_valid()) {
|
||||
web_page->file_source_id = td_->file_reference_manager_->create_web_page_file_source(web_page->url);
|
||||
VLOG(file_references) << "Create " << web_page->file_source_id << " for URL " << web_page->url;
|
||||
} else {
|
||||
VLOG(file_references) << "Return " << web_page->file_source_id << " for URL " << web_page->url;
|
||||
}
|
||||
return web_page->file_source_id;
|
||||
}
|
||||
@ -1704,11 +1712,21 @@ FileSourceId WebPagesManager::get_url_file_source_id(const string &url) {
|
||||
if (!web_page->file_source_id.is_valid()) {
|
||||
web_pages_[web_page_id]->file_source_id =
|
||||
td_->file_reference_manager_->create_web_page_file_source(web_page->url);
|
||||
VLOG(file_references) << "Create " << web_page->file_source_id << " for " << web_page_id << " with URL " << url;
|
||||
} else {
|
||||
VLOG(file_references) << "Return " << web_page->file_source_id << " for " << web_page_id << " with URL " << url;
|
||||
}
|
||||
return web_page->file_source_id;
|
||||
}
|
||||
}
|
||||
return url_to_file_source_id_[url] = td_->file_reference_manager_->create_web_page_file_source(url);
|
||||
auto &source_id = url_to_file_source_id_[url];
|
||||
if (!source_id.is_valid()) {
|
||||
source_id = td_->file_reference_manager_->create_web_page_file_source(url);
|
||||
VLOG(file_references) << "Create " << source_id << " for URL " << url;
|
||||
} else {
|
||||
VLOG(file_references) << "Return " << source_id << " for URL " << url;
|
||||
}
|
||||
return source_id;
|
||||
}
|
||||
|
||||
string WebPagesManager::get_web_page_search_text(WebPageId web_page_id) const {
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "td/utils/FlatHashMap.h"
|
||||
#include "td/utils/FlatHashSet.h"
|
||||
#include "td/utils/Promise.h"
|
||||
#include "td/utils/Slice.h"
|
||||
#include "td/utils/Status.h"
|
||||
#include "td/utils/WaitFreeHashMap.h"
|
||||
|
||||
@ -128,7 +129,7 @@ class WebPagesManager final : public Actor {
|
||||
void get_web_page_instant_view_impl(WebPageId web_page_id, bool force_full, Promise<WebPageId> &&promise);
|
||||
|
||||
tl_object_ptr<td_api::webPageInstantView> get_web_page_instant_view_object(
|
||||
WebPageId web_page_id, const WebPageInstantView *web_page_instant_view) const;
|
||||
WebPageId web_page_id, const WebPageInstantView *web_page_instant_view, Slice web_page_url) const;
|
||||
|
||||
static void on_pending_web_page_timeout_callback(void *web_pages_manager_ptr, int64 web_page_id_int);
|
||||
|
||||
|
@ -299,15 +299,17 @@ class CliClient final : public Actor {
|
||||
void on_get_messages(const td_api::messages &messages) {
|
||||
if (get_history_chat_id_ != 0) {
|
||||
int64 last_message_id = 0;
|
||||
int32 last_message_date = 0;
|
||||
for (auto &m : messages.messages_) {
|
||||
// LOG(PLAIN) << to_string(m);
|
||||
if (m->content_->get_id() == td_api::messageText::ID) {
|
||||
LOG(PLAIN) << oneline(static_cast<const td_api::messageText *>(m->content_.get())->text_->text_) << "\n";
|
||||
}
|
||||
last_message_id = m->id_;
|
||||
last_message_date = m->date_;
|
||||
}
|
||||
|
||||
if (last_message_id > 0) {
|
||||
if (last_message_id > 0 && last_message_date > 1660000000) {
|
||||
send_request(td_api::make_object<td_api::getChatHistory>(get_history_chat_id_, last_message_id, 0, 100, false));
|
||||
} else {
|
||||
get_history_chat_id_ = 0;
|
||||
@ -1221,7 +1223,7 @@ class CliClient final : public Actor {
|
||||
return as_formatted_text(caption, std::move(entities));
|
||||
}
|
||||
|
||||
static td_api::object_ptr<td_api::NotificationSettingsScope> get_notification_settings_scope(Slice scope) {
|
||||
static td_api::object_ptr<td_api::NotificationSettingsScope> as_notification_settings_scope(Slice scope) {
|
||||
if (scope.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -1234,7 +1236,7 @@ class CliClient final : public Actor {
|
||||
return td_api::make_object<td_api::notificationSettingsScopePrivateChats>();
|
||||
}
|
||||
|
||||
static td_api::object_ptr<td_api::UserPrivacySetting> get_user_privacy_setting(MutableSlice setting) {
|
||||
static td_api::object_ptr<td_api::UserPrivacySetting> as_user_privacy_setting(MutableSlice setting) {
|
||||
setting = trim(setting);
|
||||
to_lower_inplace(setting);
|
||||
if (setting == "invite") {
|
||||
@ -1264,7 +1266,7 @@ class CliClient final : public Actor {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
td_api::object_ptr<td_api::userPrivacySettingRules> get_user_privacy_setting_rules(Slice allow, Slice ids) const {
|
||||
td_api::object_ptr<td_api::userPrivacySettingRules> as_user_privacy_setting_rules(Slice allow, Slice ids) const {
|
||||
vector<td_api::object_ptr<td_api::UserPrivacySettingRule>> rules;
|
||||
if (allow == "c" || allow == "contacts") {
|
||||
rules.push_back(td_api::make_object<td_api::userPrivacySettingRuleAllowContacts>());
|
||||
@ -1342,7 +1344,7 @@ class CliClient final : public Actor {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static td_api::object_ptr<td_api::ChatMembersFilter> get_chat_members_filter(MutableSlice filter) {
|
||||
static td_api::object_ptr<td_api::ChatMembersFilter> as_chat_members_filter(MutableSlice filter) {
|
||||
filter = trim(filter);
|
||||
to_lower_inplace(filter);
|
||||
if (filter == "a" || filter == "admin" || filter == "administrators") {
|
||||
@ -1372,9 +1374,9 @@ class CliClient final : public Actor {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static td_api::object_ptr<td_api::SupergroupMembersFilter> get_supergroup_members_filter(MutableSlice filter,
|
||||
const string &query,
|
||||
Slice message_thread_id) {
|
||||
static td_api::object_ptr<td_api::SupergroupMembersFilter> as_supergroup_members_filter(MutableSlice filter,
|
||||
const string &query,
|
||||
Slice message_thread_id) {
|
||||
filter = trim(filter);
|
||||
to_lower_inplace(filter);
|
||||
if (begins_with(filter, "get")) {
|
||||
@ -1440,7 +1442,7 @@ class CliClient final : public Actor {
|
||||
can_restrict_members, can_pin_messages, can_promote_members, can_manage_video_chats, is_anonymous);
|
||||
}
|
||||
|
||||
static td_api::object_ptr<td_api::TopChatCategory> get_top_chat_category(MutableSlice category) {
|
||||
static td_api::object_ptr<td_api::TopChatCategory> as_top_chat_category(MutableSlice category) {
|
||||
category = trim(category);
|
||||
to_lower_inplace(category);
|
||||
if (!category.empty() && category.back() == 's') {
|
||||
@ -1463,7 +1465,7 @@ class CliClient final : public Actor {
|
||||
}
|
||||
}
|
||||
|
||||
static td_api::object_ptr<td_api::ChatAction> get_chat_action(MutableSlice action) {
|
||||
static td_api::object_ptr<td_api::ChatAction> as_chat_action(MutableSlice action) {
|
||||
action = trim(action);
|
||||
to_lower_inplace(action);
|
||||
if (action == "c" || action == "cancel") {
|
||||
@ -1511,7 +1513,7 @@ class CliClient final : public Actor {
|
||||
return td_api::make_object<td_api::chatActionTyping>();
|
||||
}
|
||||
|
||||
static td_api::object_ptr<td_api::ChatReportReason> get_chat_report_reason(MutableSlice reason) {
|
||||
static td_api::object_ptr<td_api::ChatReportReason> as_chat_report_reason(MutableSlice reason) {
|
||||
reason = trim(reason);
|
||||
if (reason == "null") {
|
||||
return nullptr;
|
||||
@ -1546,7 +1548,7 @@ class CliClient final : public Actor {
|
||||
return td_api::make_object<td_api::chatReportReasonCustom>();
|
||||
}
|
||||
|
||||
static td_api::object_ptr<td_api::NetworkType> get_network_type(MutableSlice type) {
|
||||
static td_api::object_ptr<td_api::NetworkType> as_network_type(MutableSlice type) {
|
||||
type = trim(type);
|
||||
to_lower_inplace(type);
|
||||
if (type == "none") {
|
||||
@ -1728,55 +1730,55 @@ class CliClient final : public Actor {
|
||||
return td_api::make_object<td_api::messageSchedulingStateSendAtDate>(send_date);
|
||||
}
|
||||
|
||||
static td_api::object_ptr<td_api::themeParameters> get_theme_parameters() {
|
||||
static td_api::object_ptr<td_api::themeParameters> as_theme_parameters() {
|
||||
return td_api::make_object<td_api::themeParameters>(0, 1, -1, 256, 65536, 123456789, 65535);
|
||||
}
|
||||
|
||||
static td_api::object_ptr<td_api::BackgroundFill> get_background_fill(int32 color) {
|
||||
static td_api::object_ptr<td_api::BackgroundFill> as_background_fill(int32 color) {
|
||||
return td_api::make_object<td_api::backgroundFillSolid>(color);
|
||||
}
|
||||
|
||||
static td_api::object_ptr<td_api::BackgroundFill> get_background_fill(int32 top_color, int32 bottom_color) {
|
||||
static td_api::object_ptr<td_api::BackgroundFill> as_background_fill(int32 top_color, int32 bottom_color) {
|
||||
return td_api::make_object<td_api::backgroundFillGradient>(top_color, bottom_color, Random::fast(0, 7) * 45);
|
||||
}
|
||||
|
||||
static td_api::object_ptr<td_api::BackgroundFill> get_background_fill(vector<int32> colors) {
|
||||
static td_api::object_ptr<td_api::BackgroundFill> as_background_fill(vector<int32> colors) {
|
||||
return td_api::make_object<td_api::backgroundFillFreeformGradient>(std::move(colors));
|
||||
}
|
||||
|
||||
static td_api::object_ptr<td_api::BackgroundType> get_solid_pattern_background(int32 color, int32 intensity,
|
||||
bool is_moving) {
|
||||
return get_gradient_pattern_background(color, color, intensity, false, is_moving);
|
||||
static td_api::object_ptr<td_api::BackgroundType> as_solid_pattern_background(int32 color, int32 intensity,
|
||||
bool is_moving) {
|
||||
return as_gradient_pattern_background(color, color, intensity, false, is_moving);
|
||||
}
|
||||
|
||||
static td_api::object_ptr<td_api::BackgroundType> get_gradient_pattern_background(int32 top_color, int32 bottom_color,
|
||||
int32 intensity, bool is_inverted,
|
||||
bool is_moving) {
|
||||
return td_api::make_object<td_api::backgroundTypePattern>(get_background_fill(top_color, bottom_color), intensity,
|
||||
static td_api::object_ptr<td_api::BackgroundType> as_gradient_pattern_background(int32 top_color, int32 bottom_color,
|
||||
int32 intensity, bool is_inverted,
|
||||
bool is_moving) {
|
||||
return td_api::make_object<td_api::backgroundTypePattern>(as_background_fill(top_color, bottom_color), intensity,
|
||||
is_inverted, is_moving);
|
||||
}
|
||||
|
||||
static td_api::object_ptr<td_api::BackgroundType> get_freeform_gradient_pattern_background(vector<int32> colors,
|
||||
int32 intensity,
|
||||
bool is_inverted,
|
||||
bool is_moving) {
|
||||
return td_api::make_object<td_api::backgroundTypePattern>(get_background_fill(std::move(colors)), intensity,
|
||||
static td_api::object_ptr<td_api::BackgroundType> as_freeform_gradient_pattern_background(vector<int32> colors,
|
||||
int32 intensity,
|
||||
bool is_inverted,
|
||||
bool is_moving) {
|
||||
return td_api::make_object<td_api::backgroundTypePattern>(as_background_fill(std::move(colors)), intensity,
|
||||
is_inverted, is_moving);
|
||||
}
|
||||
|
||||
static td_api::object_ptr<td_api::BackgroundType> get_solid_background(int32 color) {
|
||||
return td_api::make_object<td_api::backgroundTypeFill>(get_background_fill(color));
|
||||
static td_api::object_ptr<td_api::BackgroundType> as_solid_background(int32 color) {
|
||||
return td_api::make_object<td_api::backgroundTypeFill>(as_background_fill(color));
|
||||
}
|
||||
|
||||
static td_api::object_ptr<td_api::BackgroundType> get_gradient_background(int32 top_color, int32 bottom_color) {
|
||||
return td_api::make_object<td_api::backgroundTypeFill>(get_background_fill(top_color, bottom_color));
|
||||
static td_api::object_ptr<td_api::BackgroundType> as_gradient_background(int32 top_color, int32 bottom_color) {
|
||||
return td_api::make_object<td_api::backgroundTypeFill>(as_background_fill(top_color, bottom_color));
|
||||
}
|
||||
|
||||
static td_api::object_ptr<td_api::BackgroundType> get_freeform_gradient_background(vector<int32> colors) {
|
||||
return td_api::make_object<td_api::backgroundTypeFill>(get_background_fill(std::move(colors)));
|
||||
static td_api::object_ptr<td_api::BackgroundType> as_freeform_gradient_background(vector<int32> colors) {
|
||||
return td_api::make_object<td_api::backgroundTypeFill>(as_background_fill(std::move(colors)));
|
||||
}
|
||||
|
||||
td_api::object_ptr<td_api::phoneNumberAuthenticationSettings> get_phone_number_authentication_settings() const {
|
||||
td_api::object_ptr<td_api::phoneNumberAuthenticationSettings> as_phone_number_authentication_settings() const {
|
||||
return td_api::make_object<td_api::phoneNumberAuthenticationSettings>(false, true, false, false,
|
||||
vector<string>(authentication_tokens_));
|
||||
}
|
||||
@ -1850,7 +1852,7 @@ class CliClient final : public Actor {
|
||||
LOG(ERROR) << to_string(authorization_state_);
|
||||
} else if (op == "sap" || op == "sapn") {
|
||||
send_request(
|
||||
td_api::make_object<td_api::setAuthenticationPhoneNumber>(args, get_phone_number_authentication_settings()));
|
||||
td_api::make_object<td_api::setAuthenticationPhoneNumber>(args, as_phone_number_authentication_settings()));
|
||||
} else if (op == "sae" || op == "saea") {
|
||||
send_request(td_api::make_object<td_api::setAuthenticationEmailAddress>(args));
|
||||
} else if (op == "rac") {
|
||||
@ -1932,9 +1934,9 @@ class CliClient final : public Actor {
|
||||
HttpReader http_reader;
|
||||
http_reader.init(&reader);
|
||||
HttpQuery query;
|
||||
auto status = http_reader.read_next(&query);
|
||||
if (status.is_error()) {
|
||||
LOG(ERROR) << status.error();
|
||||
auto r_size = http_reader.read_next(&query);
|
||||
if (r_size.is_error()) {
|
||||
LOG(ERROR) << r_size.error();
|
||||
return;
|
||||
}
|
||||
string bot_user_id = query.get_arg("bot_id").str();
|
||||
@ -2092,7 +2094,7 @@ class CliClient final : public Actor {
|
||||
} else if (op == "gpf") {
|
||||
InputInvoice input_invoice;
|
||||
get_args(args, input_invoice);
|
||||
send_request(td_api::make_object<td_api::getPaymentForm>(input_invoice, get_theme_parameters()));
|
||||
send_request(td_api::make_object<td_api::getPaymentForm>(input_invoice, as_theme_parameters()));
|
||||
} else if (op == "voi") {
|
||||
InputInvoice input_invoice;
|
||||
bool allow_save;
|
||||
@ -2137,14 +2139,14 @@ class CliClient final : public Actor {
|
||||
// } else if (op == "gtwps") {
|
||||
// send_request(td_api::make_object<td_api::getTonWalletPasswordSalt>());
|
||||
} else if (op == "gpr") {
|
||||
send_request(td_api::make_object<td_api::getUserPrivacySettingRules>(get_user_privacy_setting(args)));
|
||||
send_request(td_api::make_object<td_api::getUserPrivacySettingRules>(as_user_privacy_setting(args)));
|
||||
} else if (op == "spr") {
|
||||
string setting;
|
||||
string allow;
|
||||
string ids;
|
||||
get_args(args, setting, allow, ids);
|
||||
send_request(td_api::make_object<td_api::setUserPrivacySettingRules>(get_user_privacy_setting(setting),
|
||||
get_user_privacy_setting_rules(allow, ids)));
|
||||
send_request(td_api::make_object<td_api::setUserPrivacySettingRules>(as_user_privacy_setting(setting),
|
||||
as_user_privacy_setting_rules(allow, ids)));
|
||||
} else if (op == "cp" || op == "ChangePhone") {
|
||||
send_request(td_api::make_object<td_api::changePhoneNumber>(args, nullptr));
|
||||
} else if (op == "ccpc" || op == "CheckChangePhoneCode") {
|
||||
@ -2392,6 +2394,14 @@ class CliClient final : public Actor {
|
||||
get_args(args, chat_id, filter, return_local);
|
||||
send_request(
|
||||
td_api::make_object<td_api::getChatMessageCount>(chat_id, as_search_messages_filter(filter), return_local));
|
||||
} else if (op == "gcmp") {
|
||||
ChatId chat_id;
|
||||
MessageId message_id;
|
||||
string filter;
|
||||
string message_thread_id;
|
||||
get_args(args, chat_id, message_id, filter, message_thread_id);
|
||||
send_request(td_api::make_object<td_api::getChatMessagePosition>(
|
||||
chat_id, message_id, as_search_messages_filter(filter), as_message_thread_id(message_thread_id)));
|
||||
} else if (op == "gup" || op == "gupp") {
|
||||
UserId user_id;
|
||||
int32 offset;
|
||||
@ -2538,32 +2548,32 @@ class CliClient final : public Actor {
|
||||
send_get_background_url(td_api::make_object<td_api::backgroundTypeWallpaper>(false, true));
|
||||
send_get_background_url(td_api::make_object<td_api::backgroundTypeWallpaper>(true, false));
|
||||
send_get_background_url(td_api::make_object<td_api::backgroundTypeWallpaper>(true, true));
|
||||
send_get_background_url(get_solid_pattern_background(-1, 0, false));
|
||||
send_get_background_url(get_solid_pattern_background(0x1000000, 0, true));
|
||||
send_get_background_url(get_solid_pattern_background(0, -1, false));
|
||||
send_get_background_url(get_solid_pattern_background(0, 101, false));
|
||||
send_get_background_url(get_solid_pattern_background(0, 0, false));
|
||||
send_get_background_url(get_solid_pattern_background(0xFFFFFF, 100, true));
|
||||
send_get_background_url(get_solid_pattern_background(0xABCDEF, 49, true));
|
||||
send_get_background_url(get_gradient_pattern_background(0, 0, 0, false, false));
|
||||
send_get_background_url(get_gradient_pattern_background(0, 0, 0, true, false));
|
||||
send_get_background_url(get_gradient_pattern_background(0xFFFFFF, 0, 100, false, true));
|
||||
send_get_background_url(get_gradient_pattern_background(0xFFFFFF, 0, 100, true, true));
|
||||
send_get_background_url(get_gradient_pattern_background(0xABCDEF, 0xFEDCBA, 49, false, true));
|
||||
send_get_background_url(get_gradient_pattern_background(0, 0x1000000, 49, false, true));
|
||||
send_get_background_url(get_freeform_gradient_pattern_background({0xABCDEF, 0xFEDCBA}, 49, false, true));
|
||||
send_get_background_url(get_freeform_gradient_pattern_background({0xABCDEF, 0x111111, 0x222222}, 49, true, true));
|
||||
send_get_background_url(as_solid_pattern_background(-1, 0, false));
|
||||
send_get_background_url(as_solid_pattern_background(0x1000000, 0, true));
|
||||
send_get_background_url(as_solid_pattern_background(0, -1, false));
|
||||
send_get_background_url(as_solid_pattern_background(0, 101, false));
|
||||
send_get_background_url(as_solid_pattern_background(0, 0, false));
|
||||
send_get_background_url(as_solid_pattern_background(0xFFFFFF, 100, true));
|
||||
send_get_background_url(as_solid_pattern_background(0xABCDEF, 49, true));
|
||||
send_get_background_url(as_gradient_pattern_background(0, 0, 0, false, false));
|
||||
send_get_background_url(as_gradient_pattern_background(0, 0, 0, true, false));
|
||||
send_get_background_url(as_gradient_pattern_background(0xFFFFFF, 0, 100, false, true));
|
||||
send_get_background_url(as_gradient_pattern_background(0xFFFFFF, 0, 100, true, true));
|
||||
send_get_background_url(as_gradient_pattern_background(0xABCDEF, 0xFEDCBA, 49, false, true));
|
||||
send_get_background_url(as_gradient_pattern_background(0, 0x1000000, 49, false, true));
|
||||
send_get_background_url(as_freeform_gradient_pattern_background({0xABCDEF, 0xFEDCBA}, 49, false, true));
|
||||
send_get_background_url(as_freeform_gradient_pattern_background({0xABCDEF, 0x111111, 0x222222}, 49, true, true));
|
||||
send_get_background_url(
|
||||
get_freeform_gradient_pattern_background({0xABCDEF, 0xFEDCBA, 0x111111, 0x222222}, 49, false, true));
|
||||
send_get_background_url(get_solid_background(-1));
|
||||
send_get_background_url(get_solid_background(0xABCDEF));
|
||||
send_get_background_url(get_solid_background(0x1000000));
|
||||
send_get_background_url(get_gradient_background(0xABCDEF, 0xFEDCBA));
|
||||
send_get_background_url(get_gradient_background(0, 0));
|
||||
send_get_background_url(get_gradient_background(-1, -1));
|
||||
send_get_background_url(get_freeform_gradient_background({0xFEDCBA, 0x222222}));
|
||||
send_get_background_url(get_freeform_gradient_background({0xFEDCBA, 0x111111, 0x222222}));
|
||||
send_get_background_url(get_freeform_gradient_background({0xABCDEF, 0xFEDCBA, 0x111111, 0x222222}));
|
||||
as_freeform_gradient_pattern_background({0xABCDEF, 0xFEDCBA, 0x111111, 0x222222}, 49, false, true));
|
||||
send_get_background_url(as_solid_background(-1));
|
||||
send_get_background_url(as_solid_background(0xABCDEF));
|
||||
send_get_background_url(as_solid_background(0x1000000));
|
||||
send_get_background_url(as_gradient_background(0xABCDEF, 0xFEDCBA));
|
||||
send_get_background_url(as_gradient_background(0, 0));
|
||||
send_get_background_url(as_gradient_background(-1, -1));
|
||||
send_get_background_url(as_freeform_gradient_background({0xFEDCBA, 0x222222}));
|
||||
send_get_background_url(as_freeform_gradient_background({0xFEDCBA, 0x111111, 0x222222}));
|
||||
send_get_background_url(as_freeform_gradient_background({0xABCDEF, 0xFEDCBA, 0x111111, 0x222222}));
|
||||
} else {
|
||||
op_not_found_count++;
|
||||
}
|
||||
@ -2579,23 +2589,23 @@ class CliClient final : public Actor {
|
||||
} else if (op == "sbgp" || op == "sbgpd") {
|
||||
send_request(td_api::make_object<td_api::setBackground>(
|
||||
td_api::make_object<td_api::inputBackgroundLocal>(as_input_file(args)),
|
||||
get_solid_pattern_background(0xABCDEF, 49, true), op == "sbgpd"));
|
||||
as_solid_pattern_background(0xABCDEF, 49, true), op == "sbgpd"));
|
||||
} else if (op == "sbggp" || op == "sbggpd") {
|
||||
send_request(td_api::make_object<td_api::setBackground>(
|
||||
td_api::make_object<td_api::inputBackgroundLocal>(as_input_file(args)),
|
||||
get_gradient_pattern_background(0xABCDEF, 0xFE, 51, op == "sbggpd", false), op == "sbggpd"));
|
||||
as_gradient_pattern_background(0xABCDEF, 0xFE, 51, op == "sbggpd", false), op == "sbggpd"));
|
||||
} else if (op == "sbgs" || op == "sbgsd") {
|
||||
int32 color;
|
||||
get_args(args, color);
|
||||
send_request(td_api::make_object<td_api::setBackground>(nullptr, get_solid_background(color), op == "sbgsd"));
|
||||
send_request(td_api::make_object<td_api::setBackground>(nullptr, as_solid_background(color), op == "sbgsd"));
|
||||
} else if (op == "sbgg" || op == "sbggd") {
|
||||
int32 top_color;
|
||||
int32 bottom_color;
|
||||
get_args(args, top_color, bottom_color);
|
||||
auto background_type = get_gradient_background(top_color, bottom_color);
|
||||
auto background_type = as_gradient_background(top_color, bottom_color);
|
||||
send_request(td_api::make_object<td_api::setBackground>(nullptr, std::move(background_type), op == "sbggd"));
|
||||
} else if (op == "sbgfg" || op == "sbgfgd") {
|
||||
auto background_type = get_freeform_gradient_background(to_integers<int32>(args));
|
||||
auto background_type = as_freeform_gradient_background(to_integers<int32>(args));
|
||||
send_request(td_api::make_object<td_api::setBackground>(nullptr, std::move(background_type), op == "sbgfgd"));
|
||||
} else if (op == "sbgfid" || op == "sbgfidd") {
|
||||
int64 background_id;
|
||||
@ -2611,9 +2621,9 @@ class CliClient final : public Actor {
|
||||
} else if (op == "sbgpid" || op == "sbgpidd") {
|
||||
int64 background_id;
|
||||
get_args(args, background_id);
|
||||
send_request(td_api::make_object<td_api::setBackground>(
|
||||
td_api::make_object<td_api::inputBackgroundRemote>(background_id),
|
||||
get_solid_pattern_background(0xabcdef, 49, true), op == "sbgpidd"));
|
||||
send_request(
|
||||
td_api::make_object<td_api::setBackground>(td_api::make_object<td_api::inputBackgroundRemote>(background_id),
|
||||
as_solid_pattern_background(0xabcdef, 49, true), op == "sbgpidd"));
|
||||
} else if (op == "rbg") {
|
||||
int64 background_id;
|
||||
get_args(args, background_id);
|
||||
@ -2749,12 +2759,12 @@ class CliClient final : public Actor {
|
||||
} else if (op == "reset_network") {
|
||||
send_request(td_api::make_object<td_api::resetNetworkStatistics>());
|
||||
} else if (op == "snt") {
|
||||
send_request(td_api::make_object<td_api::setNetworkType>(get_network_type(args)));
|
||||
send_request(td_api::make_object<td_api::setNetworkType>(as_network_type(args)));
|
||||
} else if (op == "gadsp") {
|
||||
send_request(td_api::make_object<td_api::getAutoDownloadSettingsPresets>());
|
||||
} else if (op == "sads") {
|
||||
send_request(td_api::make_object<td_api::setAutoDownloadSettings>(
|
||||
td_api::make_object<td_api::autoDownloadSettings>(), get_network_type(args)));
|
||||
td_api::make_object<td_api::autoDownloadSettings>(), as_network_type(args)));
|
||||
} else if (op == "ansc") {
|
||||
int32 sent_bytes;
|
||||
int32 received_bytes;
|
||||
@ -2763,7 +2773,7 @@ class CliClient final : public Actor {
|
||||
get_args(args, sent_bytes, received_bytes, duration, network_type);
|
||||
send_request(
|
||||
td_api::make_object<td_api::addNetworkStatistics>(td_api::make_object<td_api::networkStatisticsEntryCall>(
|
||||
get_network_type(network_type), sent_bytes, received_bytes, to_double(duration))));
|
||||
as_network_type(network_type), sent_bytes, received_bytes, to_double(duration))));
|
||||
} else if (op == "ans") {
|
||||
int32 sent_bytes;
|
||||
int32 received_bytes;
|
||||
@ -2771,15 +2781,15 @@ class CliClient final : public Actor {
|
||||
get_args(args, sent_bytes, received_bytes, network_type);
|
||||
send_request(
|
||||
td_api::make_object<td_api::addNetworkStatistics>(td_api::make_object<td_api::networkStatisticsEntryFile>(
|
||||
td_api::make_object<td_api::fileTypeDocument>(), get_network_type(network_type), sent_bytes,
|
||||
td_api::make_object<td_api::fileTypeDocument>(), as_network_type(network_type), sent_bytes,
|
||||
received_bytes)));
|
||||
} else if (op == "gtc") {
|
||||
send_request(td_api::make_object<td_api::getTopChats>(get_top_chat_category(args), 50));
|
||||
send_request(td_api::make_object<td_api::getTopChats>(as_top_chat_category(args), 50));
|
||||
} else if (op == "rtc") {
|
||||
ChatId chat_id;
|
||||
string category;
|
||||
get_args(args, chat_id, category);
|
||||
send_request(td_api::make_object<td_api::removeTopChat>(get_top_chat_category(category), chat_id));
|
||||
send_request(td_api::make_object<td_api::removeTopChat>(as_top_chat_category(category), chat_id));
|
||||
} else if (op == "gsssn") {
|
||||
const string &title = args;
|
||||
send_request(td_api::make_object<td_api::getSuggestedStickerSetName>(title));
|
||||
@ -2885,7 +2895,7 @@ class CliClient final : public Actor {
|
||||
SearchQuery query;
|
||||
get_args(args, chat_id, filter, query);
|
||||
send_request(td_api::make_object<td_api::searchChatMembers>(chat_id, query.query, query.limit,
|
||||
get_chat_members_filter(filter)));
|
||||
as_chat_members_filter(filter)));
|
||||
} else if (op == "gcm") {
|
||||
ChatId chat_id;
|
||||
string member_id;
|
||||
@ -2907,7 +2917,7 @@ class CliClient final : public Actor {
|
||||
}
|
||||
get_args(args, supergroup_id, offset, query);
|
||||
send_request(td_api::make_object<td_api::getSupergroupMembers>(
|
||||
as_supergroup_id(supergroup_id), get_supergroup_members_filter(op, query.query, message_thread_id), offset,
|
||||
as_supergroup_id(supergroup_id), as_supergroup_members_filter(op, query.query, message_thread_id), offset,
|
||||
query.limit));
|
||||
} else if (op == "gdialog" || op == "gd") {
|
||||
ChatId chat_id;
|
||||
@ -3525,7 +3535,7 @@ class CliClient final : public Actor {
|
||||
td_api::make_object<td_api::jsonObjectMember>("a", td_api::make_object<td_api::jsonValueNull>()));
|
||||
test_get_json_string(std::move(object));
|
||||
} else if (op == "gtpjs") {
|
||||
execute(td_api::make_object<td_api::getThemeParametersJsonString>(get_theme_parameters()));
|
||||
execute(td_api::make_object<td_api::getThemeParametersJsonString>(as_theme_parameters()));
|
||||
} else if (op == "gac") {
|
||||
send_request(td_api::make_object<td_api::getApplicationConfig>());
|
||||
} else if (op == "sale") {
|
||||
@ -3616,7 +3626,7 @@ class CliClient final : public Actor {
|
||||
UserId user_id;
|
||||
string url;
|
||||
get_args(args, user_id, url);
|
||||
send_request(td_api::make_object<td_api::getWebAppUrl>(user_id, url, get_theme_parameters(), "android"));
|
||||
send_request(td_api::make_object<td_api::getWebAppUrl>(user_id, url, as_theme_parameters(), "android"));
|
||||
} else if (op == "swad") {
|
||||
UserId user_id;
|
||||
string button_text;
|
||||
@ -3629,7 +3639,7 @@ class CliClient final : public Actor {
|
||||
string url;
|
||||
MessageId reply_to_message_id;
|
||||
get_args(args, chat_id, bot_user_id, url, reply_to_message_id);
|
||||
send_request(td_api::make_object<td_api::openWebApp>(chat_id, bot_user_id, url, get_theme_parameters(), "android",
|
||||
send_request(td_api::make_object<td_api::openWebApp>(chat_id, bot_user_id, url, as_theme_parameters(), "android",
|
||||
reply_to_message_id));
|
||||
} else if (op == "cwa") {
|
||||
int64 launch_id;
|
||||
@ -3641,7 +3651,7 @@ class CliClient final : public Actor {
|
||||
string action;
|
||||
get_args(args, chat_id, message_thread_id, action);
|
||||
send_request(td_api::make_object<td_api::sendChatAction>(chat_id, as_message_thread_id(message_thread_id),
|
||||
get_chat_action(action)));
|
||||
as_chat_action(action)));
|
||||
} else if (op == "smt" || op == "smtp" || op == "smtf" || op == "smtpf") {
|
||||
ChatId chat_id;
|
||||
get_args(args, chat_id);
|
||||
@ -4743,9 +4753,9 @@ class CliClient final : public Actor {
|
||||
send_request(td_api::make_object<td_api::removeSavedNotificationSound>(notification_sound_id));
|
||||
} else if (op == "gcnse" || op == "gcnses") {
|
||||
send_request(td_api::make_object<td_api::getChatNotificationSettingsExceptions>(
|
||||
get_notification_settings_scope(args), op == "gcnses"));
|
||||
as_notification_settings_scope(args), op == "gcnses"));
|
||||
} else if (op == "gsns") {
|
||||
send_request(td_api::make_object<td_api::getScopeNotificationSettings>(get_notification_settings_scope(args)));
|
||||
send_request(td_api::make_object<td_api::getScopeNotificationSettings>(as_notification_settings_scope(args)));
|
||||
} else if (op == "scns" || op == "ssns") {
|
||||
string chat_id_or_scope;
|
||||
string mute_for;
|
||||
@ -4765,7 +4775,7 @@ class CliClient final : public Actor {
|
||||
as_bool(disable_mention_notifications))));
|
||||
} else {
|
||||
send_request(td_api::make_object<td_api::setScopeNotificationSettings>(
|
||||
get_notification_settings_scope(chat_id_or_scope),
|
||||
as_notification_settings_scope(chat_id_or_scope),
|
||||
td_api::make_object<td_api::scopeNotificationSettings>(
|
||||
to_integer<int32>(mute_for), sound_id, as_bool(show_preview),
|
||||
as_bool(disable_pinned_message_notifications), as_bool(disable_mention_notifications))));
|
||||
@ -4795,15 +4805,14 @@ class CliClient final : public Actor {
|
||||
string text;
|
||||
get_args(args, chat_id, message_ids, reason, text);
|
||||
send_request(td_api::make_object<td_api::reportChat>(chat_id, as_message_ids(message_ids),
|
||||
get_chat_report_reason(reason), text));
|
||||
as_chat_report_reason(reason), text));
|
||||
} else if (op == "rcp") {
|
||||
ChatId chat_id;
|
||||
FileId file_id;
|
||||
string reason;
|
||||
string text;
|
||||
get_args(args, chat_id, file_id, reason, text);
|
||||
send_request(
|
||||
td_api::make_object<td_api::reportChatPhoto>(chat_id, file_id, get_chat_report_reason(reason), text));
|
||||
send_request(td_api::make_object<td_api::reportChatPhoto>(chat_id, file_id, as_chat_report_reason(reason), text));
|
||||
} else if (op == "reportmr") {
|
||||
ChatId chat_id;
|
||||
MessageId message_id;
|
||||
@ -5163,7 +5172,7 @@ static void on_log_message(int verbosity_level, const char *message) {
|
||||
if (verbosity_level == 0) {
|
||||
std::cerr << "Fatal error: " << message;
|
||||
}
|
||||
std::cerr << "Log message: " << message;
|
||||
// std::cerr << "Log message: " << message;
|
||||
}
|
||||
|
||||
void main(int argc, char **argv) {
|
||||
|
@ -53,7 +53,7 @@ inline StringBuilder &operator<<(StringBuilder &sb, const FileData &file_data) {
|
||||
if (file_data.remote_.type() == RemoteFileLocation::Type::Full) {
|
||||
sb << " remote " << file_data.remote_.full();
|
||||
}
|
||||
sb << format::as_array(file_data.file_source_ids_);
|
||||
sb << ", sources = " << format::as_array(file_data.file_source_ids_);
|
||||
return sb << "]";
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "td/telegram/Td.h"
|
||||
#include "td/telegram/Version.h"
|
||||
|
||||
#include "td/utils/algorithm.h"
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/misc.h"
|
||||
#include "td/utils/tl_helpers.h"
|
||||
@ -122,7 +123,10 @@ void FileData::parse(ParserT &parser, bool register_file_sources) {
|
||||
if (parser.get_error()) {
|
||||
return;
|
||||
}
|
||||
file_source_ids_.push_back(td->file_reference_manager_->parse_file_source(td, parser));
|
||||
auto file_source_id = td->file_reference_manager_->parse_file_source(td, parser);
|
||||
if (file_source_id.is_valid() && !td::contains(file_source_ids_, file_source_id)) {
|
||||
file_source_ids_.push_back(file_source_id);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
parser.set_error("Wrong number of file source ids");
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user