Compare commits

...

182 Commits

Author SHA1 Message Date
Andrea Cavalli 4cbd9d26c8 Update .gitignore 2024-03-20 23:26:40 +01:00
Andrea Cavalli 69bb2b9b9e Update memory manager json 2024-03-20 23:26:18 +01:00
Andrea Cavalli 33131b65c3 Add memory manager json code generator 2024-03-20 23:26:07 +01:00
Andrea Cavalli ab68dabe74 Fix actor leak 2024-03-20 15:56:35 +01:00
Andrea Cavalli 608b0208af Code cleanup 2024-03-20 15:56:35 +01:00
Andrea Cavalli 88c26a55f8 Fix json 2024-03-20 15:56:35 +01:00
Andrea Cavalli 0a90633864 Always use 128 client threads (todo: make this behavior optional)
This change fixes some memory management issues
2024-03-20 15:56:35 +01:00
Andrea Cavalli 215c2bcd13 Disable ccache script 2024-03-20 15:56:35 +01:00
Andrea Cavalli 13648d1fca Apply tdlight patch 2024-03-20 15:56:35 +01:00
levlam b41f3219dc Fix uname on visionOS by @vincentneo. 2024-03-12 09:43:49 +03:00
levlam 44b42cc659 Support visionOS in TDLib. 2024-03-11 22:47:54 +03:00
levlam 23c7a6caee Improve visionOS support. 2024-03-11 22:41:06 +03:00
Vincent Neo d326e32a84 Rename xrOS to visionOS 2024-03-11 22:33:56 +03:00
Vincent Neo 874796ef24 build tdlib for xros/visionos 2024-03-11 22:33:56 +03:00
Vincent Neo d57fdc5155 Support building for xrOS targets
based on openssl-3.1.1 build script.
2024-03-11 22:33:56 +03:00
levlam 2c61318a11 Move some methods to PeopleNearbyManager. 2024-03-11 01:42:08 +03:00
levlam 1e6c1dbb12 Add empty PeopleNearbyManager. 2024-03-11 01:08:29 +03:00
levlam 1fba0f0c84 Move can_use_premium_custom_emoji to DialogManager. 2024-03-10 03:15:01 +03:00
levlam 919a1d8329 Move on_update_bot_commands to DialogManager. 2024-03-09 23:35:12 +03:00
levlam b1b33cf427 Fix compilation error. 2024-03-08 23:32:57 +03:00
levlam b3b63bbdc1 Update version to 1.8.26. 2024-03-08 14:33:22 +03:00
levlam 52d9ac02ba Split business opening hours by week days. 2024-03-08 14:14:28 +03:00
levlam 64094e17c0 Sanitize business work hours. 2024-03-08 13:03:23 +03:00
levlam 046ed45152 Various fixes. 2024-03-07 14:09:31 +03:00
levlam 6e44c27db0 Improve includes. 2024-03-07 13:56:57 +03:00
levlam d08ad22a2b Use explicit cast. 2024-03-07 12:03:22 +03:00
levlam a1bcec491d Fix QuickReplyManager::get_shortcut_it. 2024-03-06 17:05:30 +03:00
levlam 2d43bdf03c Fix query promise. 2024-03-06 16:52:54 +03:00
levlam bc1a8d2bc2 Add quickReplyMessage.reply_markup. 2024-03-06 15:56:50 +03:00
levlam 06831c2836 Return null as businessInfo if empty. 2024-03-06 15:11:16 +03:00
levlam b255a21733 Fix chat folder tags. 2024-03-05 23:27:56 +03:00
levlam d1638a0fc4 Allow to add any WEBP sticker to favorite stickers. 2024-03-05 22:01:19 +03:00
levlam ef636ea07c Improve QuickReplyManager::update_shortcut_from. 2024-03-05 18:12:05 +03:00
levlam b69eaf8669 Send update about quick reply messages only after shortcut updates. 2024-03-05 18:04:40 +03:00
levlam 85f8f5ec87 Improve QuickReplyManager::get_current_state. 2024-03-05 18:02:11 +03:00
levlam a9ab6b739c Disable QuickReplyManager for bots. 2024-03-05 17:58:40 +03:00
levlam 2e0d52f618 Ignore service and live location messages in quick replies. 2024-03-05 16:41:10 +03:00
levlam e91b946015 Remove get_shortcut_it(const string &name). 2024-03-05 16:40:17 +03:00
levlam eaba45ebcb Load quick replies from database in more places. 2024-03-05 16:25:39 +03:00
levlam 401318d812 Reget messages with unsupported or legacy content. 2024-03-05 15:49:42 +03:00
levlam dd06d5ccb2 Combine get_quick_reply_shortcuts and load_quick_reply_shortcuts. 2024-03-05 15:38:56 +03:00
levlam 3d397c1d35 Add load_quick_reply_shortcuts. 2024-03-05 15:30:57 +03:00
levlam b53fca6284 Rename option to "quick_reply_shortcut_message_count_max". 2024-03-05 14:44:57 +03:00
levlam f1c3bb5c33 Fix sending update about changed shortcut. 2024-03-05 14:41:35 +03:00
levlam c4d92b3f00 Ignore edit_hide for quick replies. 2024-03-05 14:25:09 +03:00
levlam 8dcf5c4bca Fix quick reply count updating. 2024-03-05 14:17:18 +03:00
levlam f0b745b291 Save only server and local quick reply messages. 2024-03-05 13:42:21 +03:00
levlam bd97e81c32 Add td_api::sendQuickReplyShortcutMessages. 2024-03-05 13:08:26 +03:00
levlam 5a0a3f2c14 Add chat type check in get_quick_reply_message_contents. 2024-03-04 22:33:25 +03:00
levlam f11ad19a4f Ignore saved_peer_id in quick reply messages. 2024-03-04 22:30:24 +03:00
levlam 464973839e Add QuickReplyManager::get_quick_reply_message_contents. 2024-03-04 20:06:32 +03:00
levlam 848b907b1a Remove comment about disable_web_page_preview being a local field. 2024-03-04 18:55:03 +03:00
levlam 3103a6d82c Remove QuickReplyMessage.noforwards. 2024-03-04 18:53:51 +03:00
levlam f43ba61252 Add td_api::deleteBusinessConnectedBot. 2024-03-04 18:17:57 +03:00
levlam 84ecc89d20 Add td_api::setBusinessConnectedBot. 2024-03-04 17:59:29 +03:00
levlam 5c764d1716 tg_cli: add as_business_recipients. 2024-03-04 17:55:29 +03:00
levlam d56025f609 Add td_api::getBusinessConnectedBot. 2024-03-04 17:17:10 +03:00
levlam 261a3d0c22 Move business info setters to BusinessManager. 2024-03-04 16:57:36 +03:00
levlam e78c0aa360 Add empty BusinessManager. 2024-03-04 16:39:30 +03:00
levlam a629700b3c Add class BusinessConnectedBot. 2024-03-04 16:06:36 +03:00
levlam fbc738c8df Improve updates after quick reply message deletion. 2024-03-04 15:11:36 +03:00
levlam f03bdc7e50 Add td_api::setQuickReplyShortcutName. 2024-03-04 15:00:00 +03:00
levlam 74c5ba7087 Add td_api::checkQuickReplyShortcutName. 2024-03-04 14:34:47 +03:00
levlam e61c4d03e5 Add "quick_reply_message_count_max" option. 2024-03-04 13:28:55 +03:00
levlam f7b6f81c52 Add "quick_reply_shortcut_count_max" option. 2024-03-04 13:27:23 +03:00
levlam e2eba91ee2 Allow to add to recent stickers arbitrary WEBP stickers. 2024-03-01 22:35:48 +03:00
levlam f726ca930b Add td_api::toggleChatFolderTags. 2024-03-01 19:28:32 +03:00
levlam 3221d42d7b Add updateChatFolders.are_tags_enabled. 2024-03-01 16:57:10 +03:00
levlam b9c66aaea6 Support chat folder color. 2024-03-01 15:57:30 +03:00
levlam 60ee05aef7 Support Away messages sent only when the user is offline. 2024-03-01 14:44:42 +03:00
levlam 00e9793f09 Improve reload_quick_reply_messages. 2024-03-01 13:39:26 +03:00
levlam 8a5f4afa91 Add source to delete_quick_reply_messages. 2024-02-29 21:59:53 +03:00
levlam de6f15c973 Add td_api::deleteQuickReplyShortcutMessages. 2024-02-29 21:34:45 +03:00
levlam 3d60b43196 Register quick reply message files. 2024-02-29 21:05:56 +03:00
levlam 3022da6b83 Add and use QuickReplyManager::update_quick_reply_message. 2024-02-29 20:58:30 +03:00
levlam fd5a6389ec Delete files from deleted quick reply messages. 2024-02-29 19:01:40 +03:00
levlam 3f85140627 Support file reference repair for quick reply messages. 2024-02-29 17:41:05 +03:00
levlam ee25355ba6 Prevent adding back of deleted messages. 2024-02-29 17:27:12 +03:00
levlam 29718b5880 Add delete_quick_reply_messages(Shortcut *). 2024-02-29 17:21:55 +03:00
levlam cc40178558 Add class QuickReplyMessageFullId. 2024-02-29 17:11:39 +03:00
levlam b2884dcd0b Add QuickReplyManager::reload_quick_reply_message. 2024-02-29 17:05:00 +03:00
levlam 23af1419d0 Support telegram_api::updateQuickReplyMessage. 2024-02-29 16:39:38 +03:00
levlam fb85728597 Add source to get_update_quick_reply_shortcut_messages_object. 2024-02-29 16:10:15 +03:00
levlam 3b62a65bea Add td_api::loadQuickReplyShortcutMessages instead of getQuickReplyShortcutMessages. 2024-02-29 16:05:16 +03:00
levlam c99dd3d59d Add td_api::updateQuickReplyShortcutMessages. 2024-02-29 15:55:38 +03:00
levlam b7ee5c2ada Support updateDeleteQuickReplyMessages. 2024-02-29 14:43:32 +03:00
levlam 2e4a9c11d3 Reload quick reply messages after reloading the list of quick reply shortcuts. 2024-02-28 17:42:41 +03:00
levlam 9720651164 Add and use QuickReplyManager::get_quick_reply_messages_hash. 2024-02-28 17:38:17 +03:00
levlam aeea69e674 Add td_api::getQuickReplyShortcutMessages. 2024-02-28 17:19:28 +03:00
levlam 139d1d92ae Save quick reply shortcuts to binlog. 2024-02-27 23:47:29 +03:00
levlam b7e8584260 Remove QuickReplyMessage.is_copy. 2024-02-27 22:06:01 +03:00
levlam 4e198f0fe5 Remove quickReplyMessage.forward_info. 2024-02-27 20:52:59 +03:00
levlam f13f409e5f Send shortcut identifiers in updates and receive them in requests. 2024-02-27 18:10:11 +03:00
levlam 88363b1113 tg_cli: add ShortcutId. 2024-02-27 16:16:28 +03:00
levlam 7b257b4def Rename work hours to opening hours. 2024-02-27 16:03:34 +03:00
levlam 50ba48fbfa Add td_api::setBusinessGreetingMessageSettings. 2024-02-27 14:26:19 +03:00
levlam 66761d1950 Add td_api::setBusinessAwayMessageSettings. 2024-02-27 14:18:56 +03:00
levlam 44bdcd4920 Add businessInfo.greeting_message_settings. 2024-02-27 02:07:21 +03:00
levlam 74fbe7f549 Add businessInfo.away_message_settings. 2024-02-27 01:58:14 +03:00
levlam 8c82a19ca9 Improve README wording. 2024-02-27 00:40:47 +03:00
levlam 72a4cd0398 Add td_api::businessInfo. 2024-02-26 23:09:52 +03:00
levlam 0636fb180e Reload userFull after User.is_premium changes. 2024-02-26 22:43:17 +03:00
levlam 5bde9c6fb6 Add td_api::businessAwayMessageSettings. 2024-02-26 20:27:17 +03:00
levlam 4c469a3f2c Add td_api::BusinessAwayMessageSchedule. 2024-02-26 20:15:16 +03:00
levlam 3d43bbb80d Add td_api::businessGreetingMessageSettings. 2024-02-26 19:09:58 +03:00
levlam bdb3088a0c Add quickReplyShortcut.id. 2024-02-26 18:18:53 +03:00
levlam b84c36626a Move public BusinessWorkHours fields before private one. 2024-02-26 17:06:29 +03:00
levlam 4513cf75b8 Add td_api::businessRecipients. 2024-02-26 16:35:20 +03:00
levlam 7476ff34de Combine local and server shortcuts by name. 2024-02-26 13:48:19 +03:00
levlam 693bb5f09e Add td_api::reorderQuickReplyShortcuts. 2024-02-24 14:40:25 +03:00
levlam bf01eb3b91 Add and use QuickReplyManager::is_shortcut_list_changed. 2024-02-24 14:22:01 +03:00
levlam bf825d76cb Don't invoke quick reply queries simultaneously. 2024-02-24 13:42:34 +03:00
levlam 2c8c883fbf Add and use QuickReplyManager::get_shortcut_it. 2024-02-24 13:37:02 +03:00
levlam 5ef3562533 Add QuickReplyShortcutId::is_server(). 2024-02-24 03:28:55 +03:00
levlam 817a64ce0e Add class QuickReplyShortcutId. 2024-02-24 03:16:56 +03:00
levlam 274720f395 Don't add back deleted shortcuts. 2024-02-24 03:06:20 +03:00
levlam 44366bd208 Add td_api::deleteQuickReplyShortcut. 2024-02-24 03:02:42 +03:00
levlam 370d862acf Support address-only business location. 2024-02-23 21:03:44 +03:00
levlam 6cecda5d40 Add quickReplyMessage.can_be_edited. 2024-02-23 20:22:33 +03:00
levlam 5d1dcd204d Add storers and parsers for quick reply shortcuts. 2024-02-23 16:17:37 +03:00
levlam f0dcf7ebe2 Calculate quick reply shortcuts hash. 2024-02-23 14:49:29 +03:00
levlam 08084f35e3 Added updateChatAddedToList and updateChatRemovedFromList. 2024-02-23 13:38:51 +03:00
levlam 77abbdba60 Support telegram_api::updateDeleteQuickReply. 2024-02-22 23:17:02 +03:00
levlam 70b45fc3db Support telegram_api::updateNewQuickReply. 2024-02-22 23:14:08 +03:00
levlam de8afdd0a8 Store separately server and local shortcut message total_count. 2024-02-22 23:08:38 +03:00
levlam 1d76beadeb Replace getQuickReplyShortcuts with loadQuickReplyShortcuts. 2024-02-22 23:04:36 +03:00
levlam 99f1369e8c Add updateQuickReplyShortcuts. 2024-02-22 22:55:09 +03:00
levlam c73a19c319 Send update only if the first shortcut message changes. 2024-02-22 21:57:43 +03:00
levlam 9af1639168 Add QuickReplyManager::get_quick_reply_unique_id. 2024-02-22 21:47:34 +03:00
levlam f1fbd90ae6 Add QuickReplyMessageUniqueId typedef. 2024-02-22 21:44:13 +03:00
levlam d478ba05c4 Support edit date for quick replies. 2024-02-22 21:40:07 +03:00
levlam d813b5c438 Support updateQuickReplyShortcut in getCurrentState. 2024-02-22 21:26:17 +03:00
levlam 6b97b9289e Add updateQuickReplyShortcut and updateQuickReplyShortcutDeleted. 2024-02-22 21:23:19 +03:00
levlam dbc7bddf80 Support updateQuickReplies. 2024-02-22 20:12:06 +03:00
levlam c42a9d5652 Merge new received shortcut data with previously known data. 2024-02-22 19:45:49 +03:00
levlam ef90da3fd1 Update shortcut message count with the number of known messages. 2024-02-22 18:47:01 +03:00
levlam 96ddf0441c Add td_api::getQuickReplyShortcuts. 2024-02-22 17:32:12 +03:00
levlam a92c34fe30 Remove self_destruct_type from QuickReplyMessage. 2024-02-22 00:48:05 +03:00
levlam 4fff9a0417 Add td_api::quickReplyMessage. 2024-02-21 22:43:29 +03:00
levlam 768afb8815 Keep only reply_to_message_id for quick replies. 2024-02-21 22:27:46 +03:00
levlam e8f58d7dd4 Add class QuickReplyMessage. 2024-02-21 22:06:07 +03:00
levlam 094066eceb Add QuickReplyManager. 2024-02-21 20:43:55 +03:00
levlam 94ae90dcaf Check that quick reply messages aren't received by MessagesManager. 2024-02-21 20:36:33 +03:00
levlam 5097989a4d Add td_api::setBusinessWorkHours. 2024-02-20 15:55:17 +03:00
levlam ea58ed8831 Add userFullInfo.business_work_hours. 2024-02-20 15:22:02 +03:00
levlam 8d9edcb31d Add td_api::setBusinessLocation. 2024-02-20 12:49:30 +03:00
levlam 9c51809490 Add userFullInfo.business_location. 2024-02-20 00:33:40 +03:00
levlam d5af2f6ced Save time zones to binlog. 2024-02-19 22:30:07 +03:00
levlam ab1b7cf20f Add td_api::getTimeZones. 2024-02-19 22:12:28 +03:00
levlam 552e6ba35a Add TimeZoneManager. 2024-02-19 14:34:28 +03:00
levlam dc2300d7ae Update layer to 176. 2024-02-19 14:07:10 +03:00
levlam 1c06f69a03 Move on_view_dialog_active_stories to StoryManager. 2024-03-06 14:46:52 +03:00
levlam 0e8f076bab Move is_dialog_info_received_from_server to DialogManager. 2024-03-05 12:47:42 +03:00
levlam d66e3657a3 Move cached_channel_participants_ to DialogParticipantManager. 2024-03-04 03:16:20 +03:00
levlam b788136508 Minor improvements. 2024-03-03 02:14:53 +03:00
levlam 1e8e2fcecc Move search_among_dialogs to DialogParticipantManager. 2024-03-03 01:43:42 +03:00
levlam 958f6ddffd Add ContactsManager::get_user_was_online. 2024-03-03 01:39:00 +03:00
levlam 854b054ed6 Fix default parameter value. 2024-03-03 01:35:17 +03:00
levlam 22d9c86b57 Move get_channel_participants to DialogParticipantManager. 2024-03-03 01:22:49 +03:00
levlam 6399c64252 Drop username if it is invalid. 2024-03-03 00:41:09 +03:00
levlam d809329044 Combine resolveUsername queries. 2024-03-03 00:39:11 +03:00
levlam 3d9d6f51f4 Move search_chat_participants to DialogParticipantManager. 2024-03-02 03:02:34 +03:00
levlam 82e109a4d5 Simplify search_private_chat_participants. 2024-03-02 02:09:56 +03:00
levlam 465fdd8505 Move search_dialog_participants to DialogParticipantManager. 2024-03-02 02:02:01 +03:00
levlam 29a8e8062b Don't use std::map and Container to store DC OptionStat. 2024-03-01 14:01:10 +03:00
levlam 0761329c61 Remove explicit limit on HTTP chunk size. 2024-02-29 19:38:57 +03:00
levlam 0a3fa80e40 Remove another unused field. 2024-02-29 19:32:49 +03:00
levlam e82007e708 Remove unused field. 2024-02-29 19:28:15 +03:00
levlam f8342527ca Don't resave DcOptions on launch. 2024-02-28 13:47:17 +03:00
levlam 36e95649cc Make AuthData the last field of Session. 2024-02-27 13:51:39 +03:00
levlam 555aa71f59 Move chat ownership transfer to DialogParticipantManager. 2024-02-26 14:14:54 +03:00
levlam 49674bb431 Move methods for chat participant changes to DialogParticipantManager. 2024-02-25 00:45:19 +03:00
levlam 3d80f1ae6f Move get_dialog_search_text to DialogManager. 2024-02-24 23:47:30 +03:00
levlam 899587e4fa Add and use is_editable_message_content. 2024-02-23 20:19:54 +03:00
levlam fe6201556b Fix GCC 4.9 compilation errors. 2024-02-22 13:08:31 +03:00
levlam 0862f03be2 Don't mark FolderId constructor as constexpr. 2024-02-22 01:12:50 +03:00
levlam ba2f63f8b0 Remove LambdaPromise debug to avoid compiler errors because of #define lambda(...). 2024-02-22 00:57:54 +03:00
levlam 62d87ab433 Link atomic with target_link_libraries. 2024-02-21 18:40:53 +03:00
levlam edb552df68 Support FindAtomics on NetBSD. 2024-02-21 18:31:03 +03:00
levlam 69908ae3c4 Rewrite FindAtomics.cmake. 2024-02-21 18:29:35 +03:00
levlam 3967634933 Try to find atomics only after setting up compiler flags, because the test will never work without C++11. 2024-02-21 16:31:12 +03:00
levlam fe749cfb9b Add DialogManager::set_dialog_location. 2024-02-20 00:43:04 +03:00
209 changed files with 10229 additions and 2353 deletions

50
.github/workflows/build.yaml vendored Normal file
View File

@ -0,0 +1,50 @@
name: Build TDLib
on:
push:
pull_request:
schedule:
- cron: '0 0 * * 0' # weekly
jobs:
build:
runs-on: ubuntu-20.04
strategy:
matrix:
arch: [linux/386, linux/amd64, linux/arm/v6, linux/arm/v7, linux/arm64, linux/ppc64le]
steps:
- name: Setup variables
run: |
ARCH=${{ matrix.arch }}
SAFE_ARCH=$(echo $ARCH | sed 's/\//\-/g')
echo "SAFE_ARCH=$SAFE_ARCH" >> $GITHUB_ENV
- name: Install sudo package
run: |
(apt-get update || true) 2>/dev/null
(apt-get install -y sudo || true) 2>/dev/null
sudo apt update
- uses: actions/checkout@v2
with:
submodules: "recursive"
- name: Cache ccache
id: cache-ccache
uses: actions/cache@v2
with:
path: ~/.ccache
key: ${{ runner.os }}-${{ env.SAFE_ARCH }}-ccache-all
restore-keys: |
${{ runner.os }}-${{ env.SAFE_ARCH }}-ccache-
- name: Install build tools
run: sudo apt-get install -y make git zlib1g-dev libssl-dev gperf php-cli cmake clang-6.0 libc++-dev libc++abi-dev ccache
- name: Build
run: |
mkdir build
cd build
CXXFLAGS="-stdlib=libc++" CC=/usr/bin/clang-10 CXX=/usr/bin/clang++-10 cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX:PATH=../tdlib ..
cmake --build . --target install -- -j4
- uses: actions/upload-artifact@v2
with:
name: tdlight-${{ env.SAFE_ARCH }}
path: tdlib/lib

10
.gitignore vendored
View File

@ -4,4 +4,14 @@
**/auto/
docs/
tdlib/
.idea/
vcpkg/
*.tlo
td.binlog
tg_cli.log
tg_cli.log.old
.attach_pid*

View File

@ -1024,7 +1024,7 @@ Changes in 1.5.0 (9 Sep 2019):
* Added the class `chatEventPollStopped` representing the closing of a poll in a message in the chat event log.
* Added ability to specify the exact types of problems with a call in the method `sendCallRating` and
the new class `CallProblem`.
* Changes in [tdweb](https://github.com/tdlib/td/blob/master/example/web/):
* Changes in [tdweb](https://github.com/tdlight-team/tdlight/blob/master/example/web/):
- Supported non-zero `offset` and `limit` in `readFilePart`.
-----------------------------------------------------------------------------------------------------------------------
@ -1034,7 +1034,7 @@ Changes in 1.4.0 (1 May 2019):
* Added a [TDLib build instructions generator](https://tdlib.github.io/td/build.html), covering in details
TDLib building on the most popular operating systems.
* Added an example of TDLib building and usage from a browser.
See https://github.com/tdlib/td/blob/master/example/web/ for more details.
See https://github.com/tdlight-team/tdlight/blob/master/example/web/ for more details.
* Allowed to pass NULL pointer to `td_json_client_execute` instead of a previously created JSON client.
Now you can use synchronous TDLib methods through a JSON interface before creating a TDLib JSON client.
* Added support for media streaming by allowing to download any part of a file:
@ -1285,7 +1285,7 @@ Changes in 1.4.0 (1 May 2019):
Changes in 1.3.0 (5 Sep 2018):
* Added a review of existing TDLib based [frameworks](https://github.com/tdlib/td/blob/master/example/README.md)
* Added a review of existing TDLib based [frameworks](https://github.com/tdlight-team/tdlight/blob/master/example/README.md)
in different programming languages.
* Added a [Getting started](https://core.telegram.org/tdlib/getting-started) guide describing the main TDLib concepts
and basic principles required for library usage.

View File

@ -7,50 +7,56 @@
# riscv64 specific:
# * https://lists.debian.org/debian-riscv/2022/01/msg00009.html
#
# ATOMICS_FOUND - system has c++ atomics
# ATOMICS_LIBRARIES - libraries needed to use c++ atomics
# ATOMICS_LIBRARY_FLAGS - flags required to link with c++ atomics library
# ATOMICS_FOUND - system has C++ atomics
# ATOMICS_LIBRARIES - libraries needed to use C++ atomics
if (ATOMICS_FOUND)
return()
endif()
include(CheckCXXSourceCompiles)
# RISC-V only has 32-bit and 64-bit atomic instructions. GCC is supposed
# to convert smaller atomics to those larger ones via masking and
# shifting like LLVM, but it’s a known bug that it does not. This means
# shifting like LLVM, but it's a known bug that it does not. This means
# anything that wants to use atomics on 1-byte or 2-byte types needs
# -latomic, but not 4-byte or 8-byte (though it does no harm).
set(atomic_code
# to link atomic library, but not 4-byte or 8-byte (though it does no harm).
set(ATOMIC_CODE
"
#include <atomic>
#include <cstdint>
std::atomic<uint8_t> n8 (0); // riscv64
std::atomic<uint64_t> n64 (0); // armel, mipsel, powerpc
int main() {
++n8;
++n64;
return 0;
}")
#include <atomic>
#include <cstdint>
std::atomic<std::uint8_t> n8{0}; // riscv64
std::atomic<std::uint64_t> n64{0}; // armel, mipsel, powerpc
int main() {
++n8;
++n64;
}")
check_cxx_source_compiles("${atomic_code}" ATOMICS_LOCK_FREE_INSTRUCTIONS)
if (ATOMICS_LOCK_FREE_INSTRUCTIONS)
set(ATOMICS_FOUND TRUE)
set(ATOMICS_LIBRARIES)
set(ATOMICS_LIBRARY_FLAGS)
else()
set(CMAKE_REQUIRED_LIBRARIES "-latomic")
check_cxx_source_compiles("${atomic_code}" ATOMICS_IN_LIBRARY)
set(CMAKE_REQUIRED_LIBRARIES)
if (ATOMICS_IN_LIBRARY)
set(ATOMICS_LIBRARY atomic)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Atomics DEFAULT_MSG ATOMICS_LIBRARY)
set(ATOMICS_LIBRARIES ${ATOMICS_LIBRARY})
set(ATOMICS_LIBRARY_FLAGS "-latomic")
unset(ATOMICS_LIBRARY)
else()
if (Atomics_FIND_REQUIRED)
message(FATAL_ERROR "Neither lock free instructions nor -latomic found.")
endif()
endif()
set(ATOMICS_LIBS " " "-latomic")
if (CMAKE_SYSTEM_NAME MATCHES "NetBSD")
set(ATOMICS_LIBS "${ATOMICS_LIBS}" /usr/pkg/gcc12/x86_64--netbsd/lib/libatomic.so /usr/pkg/gcc12/i486--netbsdelf/lib/libatomic.so)
endif()
unset(atomic_code)
foreach (ATOMICS_LIBRARY ${ATOMICS_LIBS})
unset(ATOMICS_FOUND CACHE)
set(CMAKE_REQUIRED_LIBRARIES "${ATOMICS_LIBRARY}")
check_cxx_source_compiles("${ATOMIC_CODE}" ATOMICS_FOUND)
unset(CMAKE_REQUIRED_LIBRARIES)
if (ATOMICS_FOUND)
if (NOT ATOMICS_LIBRARY STREQUAL " ")
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Atomics DEFAULT_MSG ATOMICS_LIBRARY)
set(ATOMICS_LIBRARIES "${ATOMICS_LIBRARY}" CACHE STRING "Atomic library" FORCE)
else()
set(ATOMICS_LIBRARIES "" CACHE STRING "Atomic operations library" FORCE)
endif()
break()
endif()
endforeach()
if (Atomics_FIND_REQUIRED AND NOT ATOMICS_FOUND)
message(FATAL_ERROR "Atomic operations library isn't found.")
endif()
unset(ATOMICS_LIBRARY)
unset(ATOMICS_LIBS)
unset(ATOMIC_CODE)

View File

@ -114,6 +114,23 @@ elseif (IOS_PLATFORM STREQUAL "TVSIMULATOR")
set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-tvsimulator")
set (APPLE_TV True)
elseif (IOS_PLATFORM STREQUAL "VISIONOS")
set (IOS_PLATFORM_LOCATION "XROS.platform")
set (XCODE_IOS_PLATFORM xros)
# This causes the installers to properly locate the output libraries
set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-xros")
set (APPLE_VISION True)
elseif (IOS_PLATFORM STREQUAL "VISIONSIMULATOR")
set (SIMULATOR_FLAG true)
set (IOS_PLATFORM_LOCATION "XRSimulator.platform")
set (XCODE_IOS_PLATFORM xros-simulator)
# This causes the installers to properly locate the output libraries
set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-xrsimulator")
set (APPLE_VISION True)
else (IOS_PLATFORM STREQUAL "OS")
message (FATAL_ERROR "Unsupported IOS_PLATFORM value selected. Please choose OS, SIMULATOR, or WATCHOS.")
endif ()
@ -212,6 +229,10 @@ if (NOT DEFINED IOS_ARCH)
set (IOS_ARCH "arm64")
elseif (IOS_PLATFORM STREQUAL "TVSIMULATOR")
set (IOS_ARCH "x86_64;arm64")
elseif (IOS_PLATFORM STREQUAL "VISIONOS")
set (IOS_ARCH "arm64")
elseif (IOS_PLATFORM STREQUAL "VISIONSIMULATOR")
set (IOS_ARCH "x86_64;arm64")
endif()
endif()
message (STATUS "The iOS architectures: ${IOS_ARCH}")

View File

@ -6,7 +6,7 @@ if (POLICY CMP0065)
cmake_policy(SET CMP0065 NEW)
endif()
project(TDLib VERSION 1.8.25 LANGUAGES CXX C)
project(TDLib VERSION 1.8.26 LANGUAGES CXX C)
if (NOT DEFINED CMAKE_MODULE_PATH)
set(CMAKE_MODULE_PATH "")
@ -73,15 +73,15 @@ if (POLICY CMP0069)
endif()
# Configure CCache if available
find_program(CCACHE_FOUND ccache)
#find_program(CCACHE_FOUND ccache)
#set(CCACHE_FOUND 0)
if (CCACHE_FOUND)
message(STATUS "Found ccache")
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
else()
message(STATUS "Could NOT find ccache (this is NOT an error)")
endif()
#if (CCACHE_FOUND)
# message(STATUS "Found ccache")
# set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
# set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
#else()
# message(STATUS "Could NOT find ccache (this is NOT an error)")
#endif()
set(MEMPROF "" CACHE STRING "Use one of \"ON\", \"FAST\" or \"SAFE\" to enable memory profiling. \
Works under macOS and Linux when compiled using glibc. \
@ -129,11 +129,6 @@ if (THREADS_HAVE_PTHREAD_ARG)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
endif()
find_package(Atomics REQUIRED)
if (ATOMICS_LIBRARY_FLAGS)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ATOMICS_LIBRARY_FLAGS}")
endif()
include(TdSetUpCompiler)
td_set_up_compiler()
@ -212,9 +207,13 @@ add_subdirectory(sqlite)
add_subdirectory(tddb)
add_subdirectory(test)
option(TD_SKIP_TEST "Use \"ON\" to skip building/running the test harness.")
if (NOT TD_SKIP_TEST)
add_subdirectory(test)
endif()
if (NOT CMAKE_CROSSCOMPILING)
option(TD_SKIP_BENCHMARK "Use \"ON\" to skip building/running the benchmarks.")
if (NOT CMAKE_CROSSCOMPILING AND NOT TD_SKIP_BENCHMARK)
add_subdirectory(benchmark)
endif()
@ -306,6 +305,14 @@ set(TDLIB_SOURCE
td/telegram/BotCommandScope.cpp
td/telegram/BotInfoManager.cpp
td/telegram/BotMenuButton.cpp
td/telegram/BusinessAwayMessage.cpp
td/telegram/BusinessAwayMessageSchedule.cpp
td/telegram/BusinessConnectedBot.cpp
td/telegram/BusinessGreetingMessage.cpp
td/telegram/BusinessInfo.cpp
td/telegram/BusinessManager.cpp
td/telegram/BusinessRecipients.cpp
td/telegram/BusinessWorkHours.cpp
td/telegram/CallActor.cpp
td/telegram/CallbackQueriesManager.cpp
td/telegram/CallDiscardReason.cpp
@ -456,6 +463,7 @@ set(TDLIB_SOURCE
td/telegram/PasswordManager.cpp
td/telegram/Payments.cpp
td/telegram/PeerColor.cpp
td/telegram/PeopleNearbyManager.cpp
td/telegram/PhoneNumberManager.cpp
td/telegram/Photo.cpp
td/telegram/PhotoSize.cpp
@ -466,6 +474,7 @@ set(TDLIB_SOURCE
td/telegram/PrivacyManager.cpp
td/telegram/QueryCombiner.cpp
td/telegram/QueryMerger.cpp
td/telegram/QuickReplyManager.cpp
td/telegram/ReactionListType.cpp
td/telegram/ReactionManager.cpp
td/telegram/ReactionType.cpp
@ -500,6 +509,7 @@ set(TDLIB_SOURCE
td/telegram/StickersManager.cpp
td/telegram/StickerType.cpp
td/telegram/StorageManager.cpp
td/telegram/MemoryManager.cpp
td/telegram/StoryContent.cpp
td/telegram/StoryContentType.cpp
td/telegram/StoryDb.cpp
@ -514,6 +524,7 @@ set(TDLIB_SOURCE
td/telegram/TdDb.cpp
td/telegram/TermsOfService.cpp
td/telegram/ThemeManager.cpp
td/telegram/TimeZoneManager.cpp
td/telegram/TopDialogCategory.cpp
td/telegram/TopDialogManager.cpp
td/telegram/TranscriptionInfo.cpp
@ -582,6 +593,14 @@ set(TDLIB_SOURCE
td/telegram/BotCommandScope.h
td/telegram/BotInfoManager.h
td/telegram/BotMenuButton.h
td/telegram/BusinessAwayMessage.h
td/telegram/BusinessAwayMessageSchedule.h
td/telegram/BusinessConnectedBot.h
td/telegram/BusinessGreetingMessage.h
td/telegram/BusinessInfo.h
td/telegram/BusinessManager.h
td/telegram/BusinessRecipients.h
td/telegram/BusinessWorkHours.h
td/telegram/CallActor.h
td/telegram/CallDiscardReason.h
td/telegram/CallId.h
@ -777,6 +796,7 @@ set(TDLIB_SOURCE
td/telegram/PasswordManager.h
td/telegram/Payments.h
td/telegram/PeerColor.h
td/telegram/PeopleNearbyManager.h
td/telegram/PhoneNumberManager.h
td/telegram/Photo.h
td/telegram/PhotoFormat.h
@ -791,6 +811,9 @@ set(TDLIB_SOURCE
td/telegram/PublicDialogType.h
td/telegram/QueryCombiner.h
td/telegram/QueryMerger.h
td/telegram/QuickReplyManager.h
td/telegram/QuickReplyMessageFullId.h
td/telegram/QuickReplyShortcutId.h
td/telegram/ReactionListType.h
td/telegram/ReactionManager.h
td/telegram/ReactionType.h
@ -832,6 +855,7 @@ set(TDLIB_SOURCE
td/telegram/StickersManager.h
td/telegram/StickerType.h
td/telegram/StorageManager.h
td/telegram/MemoryManager.h
td/telegram/StoryContent.h
td/telegram/StoryContentType.h
td/telegram/StoryDb.h
@ -851,6 +875,7 @@ set(TDLIB_SOURCE
td/telegram/TdDb.h
td/telegram/TermsOfService.h
td/telegram/ThemeManager.h
td/telegram/TimeZoneManager.h
td/telegram/TopDialogCategory.h
td/telegram/TopDialogManager.h
td/telegram/TranscriptionInfo.h
@ -877,6 +902,13 @@ set(TDLIB_SOURCE
td/telegram/AuthManager.hpp
td/telegram/BackgroundInfo.hpp
td/telegram/BackgroundType.hpp
td/telegram/BusinessAwayMessage.hpp
td/telegram/BusinessAwayMessageSchedule.hpp
td/telegram/BusinessConnectedBot.hpp
td/telegram/BusinessGreetingMessage.hpp
td/telegram/BusinessInfo.hpp
td/telegram/BusinessRecipients.hpp
td/telegram/BusinessWorkHours.hpp
td/telegram/ChatReactions.hpp
td/telegram/DialogNotificationSettings.hpp
td/telegram/DialogFilter.hpp
@ -1098,6 +1130,8 @@ endif()
#EXECUTABLES
if (NOT CMAKE_CROSSCOMPILING)
option(TD_SKIP_TG_CLI "Use \"ON\" to skip building tg_cli.")
if (NOT CMAKE_CROSSCOMPILING AND NOT TD_SKIP_TG_CLI)
add_executable(tg_cli td/telegram/cli.cpp ${TL_TD_JSON_SOURCE})
if (NOT READLINE_FOUND)
@ -1126,6 +1160,7 @@ if (NOT CMAKE_CROSSCOMPILING)
target_link_libraries(tg_cli PRIVATE memprof tdclient tdcore)
add_dependencies(tg_cli tl_generate_json)
endif()
endif()
#Exported libraries
add_library(TdStatic INTERFACE)

View File

@ -1,9 +1,12 @@
# TDLib
# TDLight
TDLib (Telegram Database library) is a cross-platform library for building [Telegram](https://telegram.org) clients. It can be easily used from almost any programming language.
TDLight is a fork of TDLib, a cross-platform library for building [Telegram](https://telegram.org) clients. It can be easily used from almost any programming language.
## Table of Contents
- [Features](#features)
- [TDLight extra features](#tdlight-extra-features)
- [TDLight extra API functions](#tdlight-extra-api-functions)
- [TDLight recommended options](#tdlight-recommended-options)
- [Examples and documentation](#usage)
- [Dependencies](#dependencies)
- [Building](#building)
@ -18,7 +21,7 @@ TDLib (Telegram Database library) is a cross-platform library for building [Tele
`TDLib` has many advantages. Notably `TDLib` is:
* **Cross-platform**: `TDLib` can be used on Android, iOS, Windows, macOS, Linux, FreeBSD, OpenBSD, NetBSD, illumos, Windows Phone, WebAssembly, watchOS, tvOS, Tizen, Cygwin. It should also work on other *nix systems with or without minimal effort.
* **Cross-platform**: `TDLib` can be used on Android, iOS, Windows, macOS, Linux, FreeBSD, OpenBSD, NetBSD, illumos, Windows Phone, WebAssembly, watchOS, tvOS, visionOS, Tizen, Cygwin. It should also work on other *nix systems with or without minimal effort.
* **Multilanguage**: `TDLib` can be easily used with any programming language that is able to execute C functions. Additionally, it already has native Java (using `JNI`) bindings and .NET (using `C++/CLI` and `C++/CX`) bindings.
* **Easy to use**: `TDLib` takes care of all network implementation details, encryption and local data storage.
* **High-performance**: in the [Telegram Bot API](https://core.telegram.org/bots/api), each `TDLib` instance handles more than 24000 active bots simultaneously.
@ -28,17 +31,42 @@ TDLib (Telegram Database library) is a cross-platform library for building [Tele
* **Secure**: all local data is encrypted using a user-provided encryption key.
* **Fully-asynchronous**: requests to `TDLib` don't block each other or anything else, responses are sent when they are available.
<a name="tdlight-extra-features"></a>
### TDLight extra features
#### TDLight extra options
* **disable_minithumbnails** (true/**false**) This setting removes minithumbnails everywhere. It reduces memory usage because tdlib keeps them in RAM
* **disable_document_filenames** (true/**false**) If you don't care about having the original filenames of every file stored in RAM, you can disable them using this option. It reduces memory usage
* **disable_notifications** (true/**false**) In TDLib pending notification updates are stored in ram until you "read" them. This option disables completely notifications and keeps the pending notifications queue empty, reducing memory usage
* **ignore_update_chat_last_message** (true/**false**) If you don't care about have updateChatLastMessage updates enable this
* **ignore_update_chat_read_inbox** (true/**false**) If you don't care about have updateChatReadInbox updates enable this
* **ignore_update_user_chat_action** (true/**false**) If you don't care about have updateUserChatAction updates enable this
* **ignore_server_deletes_and_reads** (true/**false**) If you don't care about receiving read receipts and remote deletes from other users, enable this, it will reduce memory usage
* **receive_access_hashes** (true/**false**) Receive chats and users access hash as updates
* **disable_auto_download** (true/**false**) Forcefully ignore auto download settings of all sessions
<a name="tdlight-extra-api-functions"></a>
### TDLight extra API functions
#### TdApi.GetMemoryStatistics
This method is used to read the size of all the internal TDLib data structures.
The output contains a string that can be parsed as a JSON.
<a name="tdlight-recommended-options"></a>
## TDLight recommended options
* Options:
* ignore_inline_thumbnails: true
* disable_top_chats: true
* ignore_platform_restrictions: true
* ignore_sensitive_content_restrictions: true
* Disable all the databases (messages_db, users_db, files_db)
<a name="usage"></a>
## Examples and documentation
See our [Getting Started](https://core.telegram.org/tdlib/getting-started) tutorial for a description of basic TDLib concepts.
Take a look at our [examples](https://github.com/tdlib/td/blob/master/example/README.md#tdlib-usage-and-build-examples).
Take a look at our [examples](https://github.com/tdlight-team/tdlight/blob/master/example/README.md#tdlib-usage-and-build-examples).
See a [TDLib build instructions generator](https://tdlib.github.io/td/build.html) for detailed instructions on how to build TDLib.
See a [TDLight build instructions generator](https://tdlight-team.github.io/tdlight/build.html) for detailed instructions on how to build TDLib.
See description of our [JSON](#using-json), [C++](#using-cxx), [Java](#using-java) and [.NET](#using-dotnet) interfaces.
See the [td_api.tl](https://github.com/tdlib/td/blob/master/td/generate/scheme/td_api.tl) scheme or the automatically generated [HTML documentation](https://core.telegram.org/tdlib/docs/td__api_8h.html)
See the [td_api.tl](https://github.com/tdlight-team/tdlight/blob/master/td/generate/scheme/td_api.tl) scheme or the automatically generated [HTML documentation](https://core.telegram.org/tdlib/docs/td__api_8h.html)
for a list of all available `TDLib` [methods](https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_function.html) and [classes](https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_object.html).
<a name="dependencies"></a>
@ -55,7 +83,7 @@ for a list of all available `TDLib` [methods](https://core.telegram.org/tdlib/do
<a name="building"></a>
## Building
The simplest way to build `TDLib` is to use our [TDLib build instructions generator](https://tdlib.github.io/td/build.html).
The simplest way to build `TDLight` is to use our [TDLight build instructions generator](https://tdlight-team.github.io/tdlight/build.html).
You need only to choose your programming language and target operating system to receive complete build instructions.
In general, you need to install all `TDLib` [dependencies](#dependencies), enter directory containing `TDLib` sources and compile them using CMake:
@ -67,7 +95,7 @@ cmake -DCMAKE_BUILD_TYPE=Release ..
cmake --build .
```
To build `TDLib` on low memory devices you can run [SplitSource.php](https://github.com/tdlib/td/blob/master/SplitSource.php) script
To build `TDLib` on low memory devices you can run [SplitSource.php](https://github.com/tdlight-team/tdlight/blob/master/SplitSource.php) script
before compiling main `TDLib` source code and compile only needed targets:
```
mkdir build
@ -103,24 +131,24 @@ 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.25 REQUIRED)
find_package(Td 1.8.26 REQUIRED)
target_link_libraries(YourTarget PRIVATE Td::TdStatic)
```
See [example/cpp/CMakeLists.txt](https://github.com/tdlib/td/blob/master/example/cpp/CMakeLists.txt).
See [example/cpp/CMakeLists.txt](https://github.com/tdlight-team/tdlight/blob/master/example/cpp/CMakeLists.txt).
<a name="using-java"></a>
## Using in Java projects
`TDLib` provides native Java interface through JNI. To enable it, specify option `-DTD_ENABLE_JNI=ON` to CMake.
See [example/java](https://github.com/tdlib/td/tree/master/example/java) for example of using `TDLib` from Java and detailed build and usage instructions.
See [example/java](https://github.com/tdlight-team/tdlight/tree/master/example/java) for example of using `TDLib` from Java and detailed build and usage instructions.
<a name="using-dotnet"></a>
## Using in .NET projects
`TDLib` provides native .NET interface through `C++/CLI` and `C++/CX`. To enable it, specify option `-DTD_ENABLE_DOTNET=ON` to CMake.
.NET Core supports `C++/CLI` only since version 3.1 and only on Windows, so if older .NET Core is used or portability is needed, then `TDLib` JSON interface should be used through P/Invoke instead.
See [example/csharp](https://github.com/tdlib/td/tree/master/example/csharp) for example of using `TDLib` from C# and detailed build and usage instructions.
See [example/uwp](https://github.com/tdlib/td/tree/master/example/uwp) for example of using `TDLib` from C# UWP application and detailed build and usage instructions for Visual Studio Extension "TDLib for Universal Windows Platform".
See [example/csharp](https://github.com/tdlight-team/tdlight/tree/master/example/csharp) for example of using `TDLib` from C# and detailed build and usage instructions.
See [example/uwp](https://github.com/tdlight-team/tdlight/tree/master/example/uwp) for example of using `TDLib` from C# UWP application and detailed build and usage instructions for Visual Studio Extension "TDLib for Universal Windows Platform".
When `TDLib` is built with `TD_ENABLE_DOTNET` option enabled, `C++` documentation is removed from some files. You need to checkout these files to return `C++` documentation back:
```
@ -132,13 +160,13 @@ git checkout td/telegram/Client.h td/telegram/Log.h td/tl/TlObject.h
`TDLib` provides efficient native C++, Java, and .NET interfaces.
But for most use cases we suggest to use the JSON interface, which can be easily used with any programming language that is able to execute C functions.
See [td_json_client](https://core.telegram.org/tdlib/docs/td__json__client_8h.html) documentation for detailed JSON interface description,
the [td_api.tl](https://github.com/tdlib/td/blob/master/td/generate/scheme/td_api.tl) scheme or the automatically generated [HTML documentation](https://core.telegram.org/tdlib/docs/td__api_8h.html) for a list of
the [td_api.tl](https://github.com/tdlight-team/tdlight/blob/master/td/generate/scheme/td_api.tl) scheme or the automatically generated [HTML documentation](https://core.telegram.org/tdlib/docs/td__api_8h.html) for a list of
all available `TDLib` [methods](https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_function.html) and [classes](https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_object.html).
`TDLib` JSON interface adheres to semantic versioning and versions with the same major version number are binary and backward compatible, but the underlying `TDLib` API can be different for different minor and even patch versions.
If you need to support different `TDLib` versions, then you can use a value of the `version` option to find exact `TDLib` version to use appropriate API methods.
See [example/python/tdjson_example.py](https://github.com/tdlib/td/blob/master/example/python/tdjson_example.py) for an example of such usage.
See [example/python/tdjson_example.py](https://github.com/tdlight-team/tdlight/tree/master/example/python/tdjson_example.py) for an example of such usage.
<a name="license"></a>
## License

View File

@ -309,6 +309,13 @@ function split_file($file, $chunks, $undo) {
'BotMenuButton|[a-z_]*_menu_button' => 'BotMenuButton',
'boost_manager[_(-](?![.]get[(][)])|BoostManager' => 'BoostManager',
'bot_info_manager[_(-](?![.]get[(][)])|BotInfoManager' => 'BotInfoManager',
'BusinessAwayMessage' => 'BusinessAwayMessage',
'BusinessConnectedBot' => 'BusinessConnectedBot',
'BusinessGreetingMessage' => 'BusinessGreetingMessage',
'BusinessInfo|business_info' => 'BusinessInfo',
'business_manager[_(-](?![.]get[(][)])|BusinessManager' => 'BusinessManager',
'BusinessRecipients' => 'BusinessRecipients',
'BusinessWorkHours' => 'BusinessWorkHours',
'callback_queries_manager[_(-](?![.]get[(][)])|CallbackQueriesManager' => 'CallbackQueriesManager',
'CallId' => 'CallId',
'call_manager[_(-](?![.]get[(][)])|CallManager' => 'CallManager',
@ -367,11 +374,13 @@ function split_file($file, $chunks, $undo) {
'notification_settings_manager[_(-](?![.]get[(][)])|NotificationSettingsManager' => 'NotificationSettingsManager',
'option_manager[_(-](?![.]get[(][)])|OptionManager' => 'OptionManager',
'password_manager[_(-](?![.]get[(][)])|PasswordManager' => 'PasswordManager',
'people_nearby_manager[_(-](?![.]get[(][)])|PeopleNearbyManager' => 'PeopleNearbyManager',
'[a-z_]*phone_number_manager[_(-](?![.]get[(][)])|PhoneNumberManager' => 'PhoneNumberManager',
'PhotoSizeSource' => 'PhotoSizeSource',
'poll_manager[_(-](?![.]get[(][)])|PollManager' => 'PollManager',
'privacy_manager[_(-](?![.]get[(][)])|PrivacyManager' => 'PrivacyManager',
'PublicDialogType|get_public_dialog_type' => 'PublicDialogType',
'quick_reply_manager[_(-](?![.]get[(][)])|QuickReplyManager' => 'QuickReplyManager',
'ReactionListType|[a-z_]*_reaction_list_type' => 'ReactionListType',
'reaction_manager[_(-](?![.]get[(][)])|ReactionManager' => 'ReactionManager',
'ReactionType|[a-z_]*_reaction_type' => 'ReactionType',
@ -396,6 +405,7 @@ function split_file($file, $chunks, $undo) {
'td_db[(][)]|TdDb[^A-Za-z]' => 'TdDb',
'telegram_api' => 'telegram_api',
'theme_manager[_(-](?![.]get[(][)])|ThemeManager' => 'ThemeManager',
'time_zone_manager[_(-](?![.]get[(][)])|TimeZoneManager' => 'TimeZoneManager',
'TopDialogCategory|get_top_dialog_category' => 'TopDialogCategory',
'top_dialog_manager[_(-](?![.]get[(][)])|TopDialogManager' => 'TopDialogManager',
'translation_manager[_(-](?![.]get[(][)])|TranslationManager' => 'TranslationManager',

378
UpdateMemoryManager.javash Executable file
View File

@ -0,0 +1,378 @@
#!/usr/bin/java --source 21
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileVisitOption;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import java.util.SequencedSet;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class UpdateMemoryManager {
static final Set<String> EXCLUDED_MANAGERS = Set.of("Memory",
"Call",
"DeviceToken",
"LanguagePack",
"Pts",
"Password",
"SecretChats",
"Secure",
"Config",
"Storage",
"FileLoad",
"Parts",
"FileGenerate",
"Resource",
"NetStats",
"DcAuth",
"State",
"PhoneNumber"
);
record Manager(Path directory, String name) {
String includePath() {
return directory.toString().substring(2) + "/" + name + "Manager.h";
}
}
public static void main(String[] args) throws Exception {
if (args.length == 0) {
System.err.println("Arguments: PATH");
System.exit(1);
}
var path = Path.of(args[0]);
var telegramPath = path.resolve("td/telegram");
var memoryManager = new Manager(telegramPath, "Memory");
SequencedSet<Manager> managers;
try (var stream = Files.walk(telegramPath, 16)) {
var endNamePattern = "Manager.h";
managers = stream
.filter(Files::isRegularFile)
.filter(p -> p.getFileName().toString().endsWith(endNamePattern))
.map(p -> new Manager(p.getParent(), p.getFileName().toString().substring(0, p.getFileName().toString().length() - endNamePattern.length())))
.filter(name -> !EXCLUDED_MANAGERS.contains(name.name))
.collect(Collectors.toCollection(LinkedHashSet::new));
}
System.out.printf("Found %d managers%n", managers.size());
int fieldsFound = 0;
int updatedManagers = 0;
int totalManagers = 0;
List<Manager> invalidManagers = new ArrayList<>();
for (Manager manager : managers) {
totalManagers++;
var result = updateManagerJson(manager);
if (result != null) {
fieldsFound += result.fieldsFound();
if (result.changed) {
updatedManagers++;
}
} else {
invalidManagers.add(manager);
}
}
updateMemoryManagerJson(memoryManager, managers);
System.out.printf("%n%nDone.%n");
if (!invalidManagers.isEmpty()) {
System.out.printf("%d invalid managers found:%n%s",
invalidManagers.size(),
invalidManagers.stream()
.map(x -> "\t\"" + x.directory + "\": " + x.name + "\n")
.collect(Collectors.joining(", ")));
}
System.out.printf("%d/%d managers updated, %d total fields%n", updatedManagers, totalManagers, fieldsFound);
}
enum FieldType {
WaitFreeHashMap("WaitFreeHashMap", "calc_size"),
WaitFreeHashSet("WaitFreeHashSet", "calc_size"),
Vector("vector", "size"),
FlatHashMap("FlatHashMap", "size"),
FlatHashSet("FlatHashSet", "size")
;
private final String fieldName;
private final String sizeMethodName;
public final Pattern pattern;
FieldType(String fieldName, String sizeMethodName) {
this.fieldName = fieldName;
this.sizeMethodName = sizeMethodName;
this.pattern = Pattern.compile("^ {2}(mutable )?" + fieldName + "(<([^ ]|, )+>)? +(?<field>[a-zA-Z_]+);?[ \t/]*$");
}
Pattern getPattern() {
return pattern;
}
}
record FoundField(FieldType type, String name) {}
record UpdateResult(boolean changed, int fieldsFound) {}
private static UpdateResult updateManagerJson(Manager manager) throws IOException {
Path hFile = manager.directory.resolve(manager.name + "Manager.h");
Path cppFile = manager.directory.resolve(manager.name + "Manager.cpp");
System.out.printf("Updating manager \"%s\" files: [\"%s\", \"%s\"]%n", manager.name, hFile, cppFile);
if (Files.notExists(hFile)) {
System.out.printf("File not found, ignoring manager \"%s\": \"%s\"%n", manager.name, hFile);
return null;
}
if (Files.notExists(cppFile)) {
System.out.printf("File not found, ignoring manager \"%s\": \"%s\"%n", manager.name, cppFile);
return null;
}
List<FoundField> fields = new ArrayList<>();
var hLines = normalizeSourceFile(readSourceFile(hFile));
boolean currentClass = false;
for (String hLine : hLines) {
FoundField field = null;
if (hLine.startsWith("class ")) {
currentClass = hLine.contains(" " + manager.name + "Manager");
}
if (currentClass) {
for (FieldType possibleFieldType : FieldType.values()) {
var m = possibleFieldType.getPattern().matcher(hLine);
if (m.matches()) {
var fieldName = m.group("field");
field = new FoundField(possibleFieldType, fieldName);
break;
}
}
}
if (field != null) {
System.out.println("\tFound field: (%s) %s".formatted(field.type, field.name));
fields.add(field);
}
}
StringBuilder memoryStatsMethod = new StringBuilder();
memoryStatsMethod.append("void %sManager::memory_stats(vector<string> &output) {\n".formatted(manager.name));
memoryStatsMethod.append(fields.stream()
.map(field -> " output.emplace_back(\"\\\"%s\\\":\"); output.emplace_back(std::to_string(this->%s.%s()));\n".formatted(field.name, field.name, field.type.sizeMethodName))
.collect(Collectors.joining(" output.emplace_back(\",\");\n")));
memoryStatsMethod.append("}\n");
List<String> memoryStatsMethodLines = Arrays.asList(memoryStatsMethod.toString().split("\n"));
var cppLines = readSourceFile(cppFile);
var inputCppLines = new ArrayList<>(cppLines);
// Remove the old memory_stats method
var indexOfMemoryStatsStart = -1;
var indexOfMemoryStatsEnd = -1;
for (int i = 0; i < cppLines.size(); i++) {
if (cppLines.get(i).contains("::memory_stats(")) {
indexOfMemoryStatsStart = i;
for (int j = i - 1; j >= 0; j--) {
if (cppLines.get(j).isBlank()) {
indexOfMemoryStatsStart = j;
} else {
break;
}
}
break;
}
}
if (indexOfMemoryStatsStart != -1) {
for (int i = indexOfMemoryStatsStart + 1; i < cppLines.size(); i++) {
if (cppLines.get(i).trim().equals("}")) {
indexOfMemoryStatsEnd = i;
break;
}
}
if (indexOfMemoryStatsEnd == -1) {
throw new IllegalStateException("memory_stats method end not found");
}
cppLines.subList(indexOfMemoryStatsStart, indexOfMemoryStatsEnd + 1).clear();
}
var last = cppLines.removeLast();
cppLines.addAll(memoryStatsMethodLines);
cppLines.add("");
cppLines.addLast(last);
boolean changed = !Objects.equals(inputCppLines, cppLines);
if (changed) {
System.out.printf("\tDone: %s.cpp file has been updated!%n", manager.name);
Files.write(cppFile, cppLines, StandardCharsets.UTF_8);
} else {
System.out.printf("\tDone: %s.cpp file did not change.%n", manager.name);
}
return new UpdateResult(changed, fields.size());
}
private static void updateMemoryManagerJson(Manager manager, SequencedSet<Manager> managers) throws IOException {
Path hFile = manager.directory.resolve(manager.name + "Manager.h");
Path cppFile = manager.directory.resolve(manager.name + "Manager.cpp");
System.out.printf("Updating memory manager \"%s\" files: [\"%s\", \"%s\"]%n", manager.name, hFile, cppFile);
if (Files.notExists(hFile)) {
System.out.printf("File not found for manager \"%s\": \"%s\"%n", manager.name, hFile);
System.exit(1);
return;
}
if (Files.notExists(cppFile)) {
System.out.printf("File not found for manager \"%s\": \"%s\"%n", manager.name, cppFile);
System.exit(1);
return;
}
StringBuilder memoryStatsMethod = new StringBuilder();
memoryStatsMethod.append("void %sManager::print_managers_memory_stats(vector<string> &output) const {\n".formatted(manager.name));
memoryStatsMethod.append(managers.stream()
.map(m -> """
output.emplace_back("\\"%s_manager_\\":{"); td_->%s_manager_->memory_stats(output); output.emplace_back("}");
""".formatted(toSnakeCase(m.name), toSnakeCase(m.name)))
.collect(Collectors.joining(" output.emplace_back(\",\");\n")));
memoryStatsMethod.append("}\n");
List<String> memoryStatsMethodLines = Arrays.asList(memoryStatsMethod.toString().split("\n"));
var cppLines = readSourceFile(cppFile);
var inputCppLines = new ArrayList<>(cppLines);
// Remove the old memory_stats method
var indexOfMemoryStatsStart = -1;
var indexOfMemoryStatsEnd = -1;
for (int i = 0; i < cppLines.size(); i++) {
if (cppLines.get(i).contains("::print_managers_memory_stats(")) {
indexOfMemoryStatsStart = i;
for (int j = i - 1; j >= 0; j--) {
if (cppLines.get(j).isBlank()) {
indexOfMemoryStatsStart = j;
} else {
break;
}
}
break;
}
}
if (indexOfMemoryStatsStart != -1) {
for (int i = indexOfMemoryStatsStart + 1; i < cppLines.size(); i++) {
if (cppLines.get(i).trim().equals("}")) {
indexOfMemoryStatsEnd = i;
break;
}
}
if (indexOfMemoryStatsEnd == -1) {
throw new IllegalStateException("print_managers_memory_stats method end not found");
}
cppLines.subList(indexOfMemoryStatsStart, indexOfMemoryStatsEnd + 1).clear();
}
var last = cppLines.removeLast();
cppLines.addAll(memoryStatsMethodLines);
cppLines.add("");
cppLines.addLast(last);
for (Manager m : managers) {
var mInclude = "#include \"%s\"".formatted(m.includePath());
if (!cppLines.contains(mInclude)) {
System.out.printf("\tMissing include, adding \"" + m.includePath() + "\"%n");
int includeInsertIndex = -1;
for (int i = 0; i < cppLines.size(); i++) {
if (cppLines.get(i).startsWith("#include")) {
includeInsertIndex = i;
}
}
if (includeInsertIndex == -1) {
throw new IllegalStateException("Cannot find a place to put the include");
}
cppLines.add(includeInsertIndex + 1, mInclude);
}
}
boolean changed = !Objects.equals(inputCppLines, cppLines);
if (changed) {
System.out.printf("\tDone: %s.cpp file has been updated!%n", manager.name);
Files.write(cppFile, cppLines, StandardCharsets.UTF_8);
} else {
System.out.printf("\tDone: %s.cpp file did not change.%n", manager.name);
}
}
private static String toSnakeCase(String name) {
var initialChar = name.codePoints()
.limit(1)
.map(Character::toLowerCase);
var restOfString = name.codePoints()
.skip(1)
.flatMap(codePoint -> {
if (Character.isUpperCase(codePoint)) {
return IntStream.of('_', Character.toLowerCase(codePoint));
} else {
return IntStream.of(codePoint);
}
});
var resultStream = IntStream.concat(initialChar, restOfString);
return resultStream.collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append).toString();
}
private static List<String> readSourceFile(Path path) throws IOException {
return Files.readAllLines(path, StandardCharsets.UTF_8);
}
private static List<String> normalizeSourceFile(List<String> lines) throws IOException {
List<String> srcLines = new ArrayList<>(lines);
// Remove empty lines
srcLines.removeIf(String::isBlank);
// Remove unexpected newlines
List<String> srcLinesWithoutNewlines = new ArrayList<>();
StringBuilder buf = new StringBuilder();
for (String srcLine : srcLines) {
if (!buf.isEmpty()) {
buf.append(" ");
}
buf.append(srcLine);
var trimmedLine = srcLine.trim();
if (!trimmedLine.endsWith(">")) {
srcLinesWithoutNewlines.add(buf.toString());
buf.setLength(0);
}
}
if (!buf.isEmpty()) {
srcLinesWithoutNewlines.add(buf.toString());
}
srcLinesWithoutNewlines.replaceAll(p -> {
var commentStart = p.indexOf("//");
if (commentStart >= 0) {
return p.substring(0, commentStart);
} else {
return p;
}
});
return srcLinesWithoutNewlines;
}
}

View File

@ -2,7 +2,7 @@
<html>
<head>
<title>TDLib build instructions</title>
<title>TDLight build instructions</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style>
:root {
@ -193,7 +193,7 @@
<div class="main">
<div id="languageSelectDiv">
<p>Choose a programming language from which you want to use TDLib:</p>
<p>Choose a programming language from which you want to use TDLight:</p>
<select id="languageSelect" onchange="onLanguageChanged(false)" autofocus class="large">
<option>Choose a programming language:</option>
<option>Python</option>
@ -226,7 +226,7 @@
</div>
<div id="osSelectDiv" class="hide">
<p>Choose an operating system on which you want to use TDLib:</p>
<p>Choose an operating system on which you want to use TDLight:</p>
<select id="osSelect" onchange="onOsChanged()" class="large">
<option>Choose an operating system:</option>
</select>
@ -234,7 +234,7 @@
</div>
<div id="linuxSelectDiv" class="hide">
<p>Choose a Linux distro on which you want to use TDLib:</p>
<p>Choose a Linux distro on which you want to use TDLight:</p>
<select id="linuxSelect" onchange="onOsChanged()" class="large">
<option>Choose a Linux distro:</option>
<option>Alpine</option>
@ -263,13 +263,13 @@
</div>
<div id="buildInstallLocalDiv" class="hide">
<label><input type="checkbox" id="buildInstallLocalCheckbox" onchange="onOptionsChanged()"/>Install built TDLib to /usr/local instead of placing the files to td/tdlib.</label>
<label><input type="checkbox" id="buildInstallLocalCheckbox" onchange="onOptionsChanged()"/>Install built TDLight to /usr/local instead of placing the files to td/tdlib.</label>
</div>
<p></p>
<div id="buildCompilerDiv" class="hide">
<span>Choose which compiler you want to use to build TDLib:</span><br>
<span>Choose which compiler you want to use to build TDLight:</span><br>
<label><input type="radio" id="buildCompilerRadioGcc" name="buildCompilerRadio" onchange="onOptionsChanged()" checked/>g++</label>
<label><input type="radio" id="buildCompilerRadioClang" name="buildCompilerRadio" onchange="onOptionsChanged()"/>clang (recommended)</label>
<p></p>
@ -305,7 +305,7 @@
</div>
<div id="buildBitnessDiv" class="hide">
<span>Choose for which bitness you want to build TDLib:</span><br>
<span>Choose for which bitness you want to build TDLight:</span><br>
<label><input type="radio" id="buildBitnessRadio32" name="buildBitnessRadio" onchange="onOptionsChanged()" checked/>32</label>
<label><input type="radio" id="buildBitnessRadio64" name="buildBitnessRadio" onchange="onOptionsChanged()"/>64</label>
<p></p>
@ -327,7 +327,7 @@
</div>
<div id="buildCommandsDiv" class="hide">
<p id="buildCommandsHeader">Here is complete instruction for TDLib binaries building:</p>
<p id="buildCommandsHeader">Here is complete instruction for TDLight binaries building:</p>
<p id="buildPre">Hidden text</p>
<code id="buildCommands">Empty commands</code>
<button id="copyBuildCommandsButton" onclick="copyBuildInstructions()">
@ -368,10 +368,10 @@ function getSupportedOs(language) {
case 'C#':
return ['Windows (through C++/CLI)', 'Universal Windows Platform (through C++/CX)', 'Windows (.NET Core)', 'Linux (.NET Core)', 'macOS (.NET Core)', 'FreeBSD (.NET Core)'];
case 'Dart':
return ['Android', 'iOS', 'Windows', 'Linux', 'macOS', 'tvOS', 'watchOS'];
return ['Android', 'iOS', 'Windows', 'Linux', 'macOS', 'tvOS', 'visionOS', 'watchOS'];
case 'Swift':
case 'Objective-C':
return ['Windows', 'Linux', 'macOS', 'iOS', 'tvOS', 'watchOS'];
return ['Windows', 'Linux', 'macOS', 'iOS', 'tvOS', 'visionOS', 'watchOS'];
default:
return ['Windows', 'Linux', 'macOS', 'FreeBSD', 'OpenBSD', 'NetBSD'];
}
@ -474,7 +474,7 @@ function getTarget(language, os) {
if (os.includes('Android')) {
return 'Android';
}
if (os.includes('iOS') || os.includes('tvOS') || os.includes('watchOS')) {
if (os.includes('iOS') || os.includes('tvOS') || os.includes('visionOS') || os.includes('watchOS')) {
return 'iOS';
}
@ -494,14 +494,14 @@ function getTargetName(target) {
case 'tdjson':
case 'WebAssembly':
case 'iOS':
return '<a href="https://github.com/tdlib/td#using-json">JSON</a>';
return '<a href="https://github.com/tdlight-team/tdlight#using-json">JSON</a>';
case 'tdclient':
return '<a href="https://github.com/tdlib/td#using-cxx">a simple and convenient C++11-interface</a>';
return '<a href="https://github.com/tdlight-team/tdlight#using-cxx">a simple and convenient C++11-interface</a>';
case 'JNI':
case 'Android':
return '<a href="https://github.com/tdlib/td#using-java">native ' + target + '</a>';
return '<a href="https://github.com/tdlight-team/tdlight#using-java">native ' + target + '</a>';
default:
return '<a href="https://github.com/tdlib/td#using-dotnet">native ' + target + '</a>';
return '<a href="https://github.com/tdlight-team/tdlight#using-dotnet">native ' + target + '</a>';
}
}
@ -515,17 +515,17 @@ function onOsChanged() {
if (language === 'Other') {
language = 'any other programming language';
}
var text = 'TDLib can be used from ' + language + ' on ' + os + ' through the ' + getTargetName(target) + ' interface.<br>' +
'See <a href="https://github.com/tdlib/td/blob/master/example/README.md#' + getExampleAnchor(language) + '">examples</a> of such usage and already available third-party frameworks.<br>';
var text = 'TDLight can be used from ' + language + ' on ' + os + ' through the ' + getTargetName(target) + ' interface.<br>' +
'See <a href="https://github.com/tdlight-team/tdlight/blob/master/example/README.md#' + getExampleAnchor(language) + '">examples</a> of such usage and already available third-party frameworks.<br>';
if (target === 'WebAssembly') {
text = 'TDLib is available in a prebuilt form as an <a href="https://www.npmjs.com/">NPM</a> package <a href="https://www.npmjs.com/package/tdweb">tdweb</a>.<br>' +
'If you want to build it manually, take a look at our <a href="https://github.com/tdlib/td/tree/master/example/web">example</a>.';
text = 'TDLight is available in a prebuilt form as an <a href="https://www.npmjs.com/">NPM</a> package <a href="https://www.npmjs.com/package/tdweb">tdweb</a>.<br>' +
'If you want to build it manually, take a look at our <a href="https://github.com/tdlight-team/tdlight/tree/master/example/web">example</a>.';
target = '';
}
if (target === 'Android') {
text = 'TDLib for Android is available in a prebuilt form and can be downloaded from <a href="https://core.telegram.org/tdlib/tdlib.zip">there</a>.<br>' +
'See <a href="https://github.com/tdlib/td/issues/77#issuecomment-640719893">build instructions</a> if you want to build the latest TDLib version or want to build TDLib with different interface.';
text = 'TDLight for Android is available in a prebuilt form and can be downloaded from <a href="https://core.telegram.org/tdlight-team/tdlightlib.zip">there</a>.<br>' +
'See <a href="https://github.com/tdlight-team/tdlight/issues/77#issuecomment-640719893">build instructions</a> if you want to build the latest TDLight version or want to build TDLight with different interface.';
target = '';
}
if (target === 'iOS') {
@ -590,7 +590,7 @@ function onOptionsChanged() {
if (os_linux || os_freebsd || os_netbsd) {
low_memory = document.getElementById('buildLowMemoryCheckbox').checked;
document.getElementById('buildLowMemoryText').innerHTML = 'I have less than ' + (use_clang ? '1.5' : '3.5') +' GB of RAM.' +
(low_memory ? ' Now you will need only ' + (use_clang ? '0.5' : '1') +' GB of RAM to build TDLib.' : '');
(low_memory ? ' Now you will need only ' + (use_clang ? '0.5' : '1') +' GB of RAM to build TDLight.' : '');
document.getElementById('buildLowMemoryDiv').style.display = 'block';
} else {
if (os_openbsd) {
@ -751,8 +751,8 @@ function onOptionsChanged() {
pre_text.push('Note that the following instruction is for NetBSD 8+ and default SH shell.');
}
if (os_mac) {
pre_text.push('Note that the following instruction will build TDLib only for ' + os_mac_host_name + '.');
pre_text.push('If you want to create a universal XCFramework, take a look at our <a href="https://github.com/tdlib/td/tree/master/example/ios">example</a> instead.');
pre_text.push('Note that the following instruction will build TDLight only for ' + os_mac_host_name + '.');
pre_text.push('If you want to create a universal XCFramework, take a look at our <a href="https://github.com/tdlight-team/tdlight/tree/master/example/ios">example</a> instead.');
}
var terminal_name = (function () {
@ -776,12 +776,12 @@ function onOptionsChanged() {
if (os_windows) {
pre_text.push('Close and re-open ' + terminal_name + ' if the PATH environment variable was changed.');
}
pre_text.push('Run these commands in ' + terminal_name + ' to build TDLib and to install it to ' + install_dir + ':');
pre_text.push('Run these commands in ' + terminal_name + ' to build TDLight and to install it to ' + install_dir + ':');
document.getElementById('buildPre').innerHTML = '<ul><li>' + pre_text.join('</li><li>') + '</li></ul>';
document.getElementById('buildPre').style.display = 'block';
if (install_dir && install_dir !== '/usr/local') {
install_dir = '../tdlib';
install_dir = '../tdlight';
if (target === 'JNI' || target === 'C++/CX') {
install_dir = '../../' + install_dir;
}
@ -926,9 +926,9 @@ function onOptionsChanged() {
commands.push('exit');
}
}
commands.push('git clone https://github.com/tdlib/td.git');
commands.push('git clone https://github.com/tdlight-team/tdlight.git');
commands.push('cd td');
commands.push('cd tdlight');
// commands.push('git checkout v1.8.0');
if (use_vcpkg) {

View File

@ -1,7 +1,7 @@
# TDLib usage and build examples
This directory contains basic examples of TDLib usage from different programming languages and examples of library building for different platforms.
If you are looking for documentation of all available TDLib methods, see the [td_api.tl](https://github.com/tdlib/td/blob/master/td/generate/scheme/td_api.tl) scheme or the
If you are looking for documentation of all available TDLib methods, see the [td_api.tl](https://github.com/tdlight-team/tdlight/blob/master/td/generate/scheme/td_api.tl) scheme or the
automatically generated [HTML documentation](https://core.telegram.org/tdlib/docs/td__api_8h.html) for a list of all available TDLib
[methods](https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_function.html) and [classes](https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_object.html).
Also, take a look at our [Getting Started](https://core.telegram.org/tdlib/getting-started) tutorial for a description of basic TDLib concepts.
@ -54,13 +54,13 @@ If you want to use TDLib with asyncio and Python >= 3.9, take a look at [aiotdli
For older Python versions you can use [pytdlib](https://github.com/pytdlib/pytdlib).
This wrapper contains generator for TDLib API classes and basic interface for interaction with TDLib.
You can also check out [example/python/tdjson_example.py](https://github.com/tdlib/td/blob/master/example/python/tdjson_example.py),
You can also check out [example/python/tdjson_example.py](https://github.com/tdlight-team/tdlight/blob/master/example/python/tdjson_example.py),
[tdlib-python](https://github.com/JunaidBabu/tdlib-python), or [Python Wrapper TDLib](https://github.com/alvhix/pywtdlib) for some basic examples of TDLib JSON interface integration with Python.
<a name="javascript"></a>
## Using TDLib in JavaScript projects
TDLib can be compiled to WebAssembly or asm.js and used in a browser from JavaScript. See [tdweb](https://github.com/tdlib/td/tree/master/example/web) as a convenient wrapper for TDLib in a browser
TDLib can be compiled to WebAssembly or asm.js and used in a browser from JavaScript. See [tdweb](https://github.com/tdlight-team/tdlight/tree/master/example/web) as a convenient wrapper for TDLib in a browser
and [telegram-react](https://github.com/evgeny-nadymov/telegram-react) as an example of a TDLib-based Telegram client.
See also [Svelte-tdweb-starter](https://github.com/gennadypolakov/svelte-tdweb-starter) - Svelte wrapper for tdweb, and [Telegram-Photoframe](https://github.com/lukefx/telegram-photoframe) - a web application that displays your preferred group or channel as Photoframe.
@ -95,7 +95,7 @@ You can also see [github.com/aliforever/go-tdlib](https://github.com/aliforever/
TDLib can be used from the Java programming language through native [JNI](https://github.com/tdlib/td#using-java) binding.
We provide a generator for JNI bridge methods and Java classes for all TDLib API methods and objects.
See [example/java](https://github.com/tdlib/td/tree/master/example/java) for an example of using TDLib from desktop Java along with detailed building and usage instructions.
See [example/java](https://github.com/tdlight-team/tdlight/tree/master/example/java) for an example of using TDLib from desktop Java along with detailed building and usage instructions.
To use TDLib to create Android Java applications, use our [prebuilt library for Android](https://core.telegram.org/tdlib/tdlib.zip).
<a name="kotlin"></a>
@ -112,8 +112,8 @@ See also [td-ktx](https://github.com/tdlibx/td-ktx) - Kotlin coroutines wrapper
TDLib provides a native [.NET](https://github.com/tdlib/td#using-dotnet) interface through `C++/CLI` and `C++/CX`.
See [tdlib-netcore](https://github.com/dantmnf/tdlib-netcore) for a SWIG-like binding with automatically generated classes for TDLib API.
See [example/uwp](https://github.com/tdlib/td/tree/master/example/uwp) for an example of building TDLib SDK for the Universal Windows Platform and an example of its usage from C#.
See [example/csharp](https://github.com/tdlib/td/tree/master/example/csharp) for an example of building TDLib with `C++/CLI` support and an example of TDLib usage from C# on Windows.
See [example/uwp](https://github.com/tdlight-team/tdlight/tree/master/example/uwp) for an example of building TDLib SDK for the Universal Windows Platform and an example of its usage from C#.
See [example/csharp](https://github.com/tdlight-team/tdlight/tree/master/example/csharp) for an example of building TDLib with `C++/CLI` support and an example of TDLib usage from C# on Windows.
If you want to write a cross-platform C# application using .NET Core, see [tdsharp](https://github.com/egramtel/tdsharp). It uses our [JSON](https://github.com/tdlib/td#using-json) interface,
provides an asynchronous interface for interaction with TDLib, automatically generated classes for TDLib API and has some examples.
@ -127,8 +127,8 @@ Also, see [Unigram](https://github.com/UnigramDev/Unigram), which is a full-feat
TDLib has a simple and convenient C++11-interface for sending and receiving requests and can be statically linked to your application.
See [example/cpp](https://github.com/tdlib/td/tree/master/example/cpp) for an example of TDLib usage from C++.
[td_example.cpp](https://github.com/tdlib/td/blob/master/example/cpp/td_example.cpp) contains an example of authorization, processing new incoming messages, getting a list of chats and sending a text message.
See [example/cpp](https://github.com/tdlight-team/tdlight/tree/master/example/cpp) for an example of TDLib usage from C++.
[td_example.cpp](https://github.com/tdlight-team/tdlight/blob/master/example/cpp/td_example.cpp) contains an example of authorization, processing new incoming messages, getting a list of chats and sending a text message.
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,
@ -140,20 +140,20 @@ or [MeeGram](https://github.com/qtinsider/meegram2) - a Telegram client for Noki
TDLib can be used from the Swift programming language through the [JSON](https://github.com/tdlib/td#using-json) interface and can be linked statically or dynamically.
See [example/ios](https://github.com/tdlib/td/tree/master/example/ios) for an example of building TDLib for iOS, watchOS, tvOS, and macOS.
See [example/ios](https://github.com/tdlight-team/tdlight/tree/master/example/ios) for an example of building TDLib for iOS, watchOS, tvOS, visionOS, and macOS.
See [TDLibKit](https://github.com/Swiftgram/TDLibKit), [tdlib-swift](https://github.com/modestman/tdlib-swift), or [TDLib-iOS](https://github.com/leoMehlig/TDLib-iOS), which provide convenient TDLib clients with automatically generated and fully-documented classes for all TDLib API methods and objects.
See also the source code of [Moc](https://github.com/mock-foundation/moc) - a native and powerful macOS and iPadOS Telegram client, optimized for moderating large communities and personal use.
See [example/swift](https://github.com/tdlib/td/tree/master/example/swift) for an example of a macOS Swift application.
See [example/swift](https://github.com/tdlight-team/tdlight/tree/master/example/swift) for an example of a macOS Swift application.
<a name="objective-c"></a>
## Using TDLib in Objective-C projects
TDLib can be used from the Objective-C programming language through [JSON](https://github.com/tdlib/td#using-json) interface and can be linked statically or dynamically.
See [example/ios](https://github.com/tdlib/td/tree/master/example/ios) for an example of building TDLib for iOS, watchOS, tvOS, and macOS.
See [example/ios](https://github.com/tdlight-team/tdlight/tree/master/example/ios) for an example of building TDLib for iOS, watchOS, tvOS, visionOS, and macOS.
<a name="object-pascal"></a>
## Using TDLib in Object Pascal projects with Delphi and Lazarus
@ -300,7 +300,7 @@ TDLib can be used from the C programming language through the [JSON](https://git
See [easy-tg](https://github.com/Trumeet/easy-tg) for an example of such usage.
You can also try to use our [C](https://github.com/tdlib/td/blob/master/td/telegram/td_c_client.h) client, which was used by the private TDLib-based version of [telegram-cli](https://github.com/vysheng/tg).
You can also try to use our [C](https://github.com/tdlight-team/tdlight/blob/master/td/telegram/td_c_client.h) client, which was used by the private TDLib-based version of [telegram-cli](https://github.com/vysheng/tg).
<a name="g"></a>
## Using TDLib from G projects

View File

@ -21,4 +21,4 @@ You can specify different OpenSSL version as the fourth parameter to the script
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.
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 directory "tdlib" as specified.

View File

@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.4 FATAL_ERROR)
project(TdExample VERSION 1.0 LANGUAGES CXX)
find_package(Td 1.8.25 REQUIRED)
find_package(Td 1.8.26 REQUIRED)
add_executable(tdjson_example tdjson_example.cpp)
target_link_libraries(tdjson_example PRIVATE Td::TdJson)

View File

@ -1,8 +1,8 @@
diff --git a/Makefile b/Makefile
index a1d13e9..a0841cf 100644
index a1d13e9..8efcf20 100644
--- a/Makefile
+++ b/Makefile
@@ -18,8 +18,11 @@
@@ -18,8 +18,13 @@
# - OpenSSL - build OpenSSL for all platforms
# - OpenSSL-macOS - build OpenSSL for macOS
# - OpenSSL-iOS - build OpenSSL for iOS
@ -11,10 +11,12 @@ index a1d13e9..a0841cf 100644
+# - OpenSSL-tvOS-simulator - build OpenSSL for tvOS-simulator
# - OpenSSL-watchOS - build OpenSSL for watchOS
+# - OpenSSL-watchOS-simulator - build OpenSSL for watchOS-simulator
+# - OpenSSL-visionOS - build OpenSSL for visionOS
+# - OpenSSL-visionOS-simulator - build OpenSSL for visionOS-simulator
# - libFFI - build libFFI for all platforms (except macOS)
# - libFFI-iOS - build libFFI for iOS
# - libFFI-tvOS - build libFFI for tvOS
@@ -50,7 +53,7 @@ XZ_VERSION=5.4.2
@@ -50,7 +55,7 @@ XZ_VERSION=5.4.2
# Preference is to use OpenSSL 3; however, Cryptography 3.4.8 (and
# probably some other packages as well) only works with 1.1.1, so
# we need to preserve the ability to build the older OpenSSL (for now...)
@ -23,16 +25,16 @@ index a1d13e9..a0841cf 100644
# OPENSSL_VERSION_NUMBER=1.1.1
# OPENSSL_REVISION=q
# OPENSSL_VERSION=$(OPENSSL_VERSION_NUMBER)$(OPENSSL_REVISION)
@@ -59,7 +62,7 @@ LIBFFI_VERSION=3.4.2
@@ -59,7 +64,7 @@ LIBFFI_VERSION=3.4.2
# Supported OS and dependencies
DEPENDENCIES=BZip2 XZ OpenSSL libFFI
-OS_LIST=macOS iOS tvOS watchOS
+OS_LIST=macOS iOS iOS-simulator tvOS tvOS-simulator watchOS watchOS-simulator
+OS_LIST=macOS iOS iOS-simulator tvOS tvOS-simulator watchOS watchOS-simulator visionOS visionOS-simulator
CURL_FLAGS=--disable --fail --location --create-dirs --progress-bar
@@ -69,22 +72,34 @@ VERSION_MIN-macOS=10.15
@@ -69,22 +74,41 @@ VERSION_MIN-macOS=10.15
CFLAGS-macOS=-mmacosx-version-min=$(VERSION_MIN-macOS)
# iOS targets
@ -66,11 +68,29 @@ index a1d13e9..a0841cf 100644
+# watchOS-simulator targets
+TARGETS-watchOS-simulator=watchsimulator.i386 watchsimulator.x86_64 watchsimulator.arm64
+CFLAGS-watchOS-simulator=-mwatchos-simulator-version-min=$(VERSION_MIN-watchOS)
+
+# visionOS targets
+TARGETS-visionOS=xros.arm64
+PYTHON_CONFIGURE-visionOS=ac_cv_func_sigaltstack=no
+
+# visionOS-simulator targets
+TARGETS-visionOS-simulator=xrsimulator.x86_64 xrsimulator.arm64
+
# The architecture of the machine doing the build
HOST_ARCH=$(shell uname -m)
HOST_PYTHON=install/macOS/macosx/python-$(PYTHON_VERSION)
@@ -662,7 +677,7 @@ BZIP2_FATLIB-$(sdk)=$$(BZIP2_MERGE-$(sdk))/lib/libbz2.a
@@ -212,6 +236,10 @@ ARCH-$(target)=$$(subst .,,$$(suffix $(target)))
ifeq ($(os),macOS)
TARGET_TRIPLE-$(target)=$$(ARCH-$(target))-apple-darwin
+else ifeq ($(os),visionOS)
+TARGET_TRIPLE-$(target)=$$(ARCH-$(target))-apple-xros
+else ifeq ($(os),visionOS-simulator)
+TARGET_TRIPLE-$(target)=$$(ARCH-$(target))-apple-xros-simulator
else
ifeq ($$(findstring simulator,$$(SDK-$(target))),)
TARGET_TRIPLE-$(target)=$$(ARCH-$(target))-apple-$$(OS_LOWER-$(target))
@@ -662,7 +690,7 @@ BZIP2_FATLIB-$(sdk)=$$(BZIP2_MERGE-$(sdk))/lib/libbz2.a
XZ_MERGE-$(sdk)=$(PROJECT_DIR)/merge/$(os)/$(sdk)/xz-$(XZ_VERSION)
XZ_FATLIB-$(sdk)=$$(XZ_MERGE-$(sdk))/lib/liblzma.a
@ -79,7 +99,7 @@ index a1d13e9..a0841cf 100644
OPENSSL_FATINCLUDE-$(sdk)=$$(OPENSSL_MERGE-$(sdk))/include
OPENSSL_SSL_FATLIB-$(sdk)=$$(OPENSSL_MERGE-$(sdk))/lib/libssl.a
OPENSSL_CRYPTO_FATLIB-$(sdk)=$$(OPENSSL_MERGE-$(sdk))/lib/libcrypto.a
@@ -716,14 +731,14 @@ $$(OPENSSL_SSL_FATLIB-$(sdk)): $$(foreach target,$$(SDK_TARGETS-$(sdk)),$$(OPENS
@@ -716,14 +744,14 @@ $$(OPENSSL_SSL_FATLIB-$(sdk)): $$(foreach target,$$(SDK_TARGETS-$(sdk)),$$(OPENS
mkdir -p $$(OPENSSL_MERGE-$(sdk))/lib
lipo -create -output $$@ \
$$(foreach target,$$(SDK_TARGETS-$(sdk)),$$(OPENSSL_SSL_LIB-$$(target))) \

View File

@ -1,10 +1,10 @@
# Universal XCFramework build example
Below are instructions for building TDLib for iOS, watchOS, tvOS, and also macOS.
Below are instructions for building TDLib for iOS, watchOS, tvOS, visionOS, and also macOS.
If you need only a macOS build for the current architecture, take a look at [TDLib build instructions generator](https://tdlib.github.io/td/build.html).
For example of usage take a look at our [Swift example](https://github.com/tdlib/td/tree/master/example/swift).
For example of usage take a look at our [Swift example](https://github.com/tdlight-team/tdlight/tree/master/example/swift).
To compile `TDLib` you will need to:
* Install the latest Xcode via `xcode-select --install` or downloading it from [Xcode website](https://developer.apple.com/xcode/).
@ -21,7 +21,7 @@ cd native-build
cmake ..
cmake --build . --target prepare_cross_compiling
```
* Build OpenSSL for iOS, watchOS, tvOS, and macOS:
* Build OpenSSL for iOS, watchOS, tvOS, visionOS, and macOS:
```
cd <path to TDLib sources>/example/ios
./build-openssl.sh
@ -30,14 +30,14 @@ Here we use scripts from [Python Apple support](https://github.com/beeware/Pytho
[Python Apple support](https://github.com/beeware/Python-Apple-support) has known problems with spaces in the path to the current directory, so
you need to ensure that there are no spaces in the path.
Built OpenSSL libraries should be stored in the directory `third_party/openssl/<platform>`, because the next script will rely on this location.
* Build TDLib for iOS, watchOS, tvOS, and macOS:
* Build TDLib for iOS, watchOS, tvOS, visionOS, and macOS:
```
cd <path to TDLib sources>/example/ios
./build.sh
```
This may take a while, because TDLib will be built about 16 times.
Resulting XCFramework will work on any architecture and even on a simulator.
We use [CMake/iOS.cmake](https://github.com/tdlib/td/blob/master/CMake/iOS.cmake) toolchain, other toolchains may work too.
We use [CMake/iOS.cmake](https://github.com/tdlight-team/tdlight/blob/master/CMake/iOS.cmake) toolchain, other toolchains may work too.
Built libraries and XCFramework will be stored in `tdjson` directory.

View File

@ -8,7 +8,7 @@ git reset --hard || exit 1
git apply ../Python-Apple-support.patch || exit 1
cd ..
platforms="macOS iOS watchOS tvOS"
platforms="macOS iOS watchOS tvOS visionOS"
for platform in $platforms;
do

View File

@ -21,7 +21,7 @@ set_cmake_options () {
options="$options -DCMAKE_BUILD_TYPE=Release"
}
platforms="macOS iOS watchOS tvOS"
platforms="macOS iOS watchOS tvOS visionOS"
#platforms="watchOS"
for platform in $platforms;
do
@ -41,6 +41,8 @@ do
ios_platform="WATCH"
elif [[ $platform = "tvOS" ]]; then
ios_platform="TV"
elif [[ $platform = "visionOS" ]]; then
ios_platform="VISION"
else
ios_platform=""
fi

View File

@ -3,7 +3,7 @@
To run this example, you will need installed JDK >= 1.6.
For Javadoc documentation generation PHP is needed.
You can find complete build instructions for your operating system at https://tdlib.github.io/td/build.html?language=Java.
You can find complete build instructions for your operating system at https://tdlight-team.github.io/tdlight/build.html?language=Java.
In general, the build process looks as follows.

View File

@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2013/01/nuspec.xsd">
<metadata>
<id>Telegram.Td.UWP</id>
<version>1.8.25</version>
<version>1.8.26</version>
<title>TDLib for Universal Windows Platform</title>
<authors>Telegram</authors>
<owners>Telegram</owners>

View File

@ -1,12 +1,12 @@
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011">
<Metadata>
<Identity Id="Telegram.Td.UWP" Version="1.8.25" Language="en-US" Publisher="Telegram LLC" />
<Identity Id="Telegram.Td.UWP" Version="1.8.26" 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>
<Tags>Telegram, TDLib, library, client, API</Tags>
<License>LICENSE_1_0.txt</License>
<ReleaseNotes>https://github.com/tdlib/td/blob/master/CHANGELOG.md</ReleaseNotes>
<ReleaseNotes>https://github.com/tdlight-team/tdlight/blob/master/CHANGELOG.md</ReleaseNotes>
</Metadata>
<Installation Scope="Global">
<InstallationTarget Id="Microsoft.ExtensionSDK" TargetPlatformIdentifier="UAP" TargetPlatformVersion="v0.8.0.0" SdkName="Telegram.Td.UWP" SdkVersion="1.0" />

View File

@ -26,4 +26,4 @@ cd <path to TDLib sources>/example/web
## Using tdweb NPM package
See [tdweb](https://www.npmjs.com/package/tdweb) or [README.md](https://github.com/tdlib/td/tree/master/example/web/tdweb/README.md) for package documentation.
See [tdweb](https://www.npmjs.com/package/tdweb) or [README.md](https://github.com/tdlight-team/tdlight/tree/master/example/web/tdweb/README.md) for package documentation.

View File

@ -8,11 +8,11 @@ Once this is done, you can send queries to the TDLib instance using the method `
See [Getting Started](https://core.telegram.org/tdlib/getting-started) for a description of basic TDLib concepts and a short introduction to TDLib usage.
See the [td_api.tl](https://github.com/tdlib/td/blob/master/td/generate/scheme/td_api.tl) scheme or
See the [td_api.tl](https://github.com/tdlight-team/tdlight/blob/master/td/generate/scheme/td_api.tl) scheme or
the automatically generated [HTML documentation](https://core.telegram.org/tdlib/docs/td__api_8h.html) for a list of all available
TDLib [methods](https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_function.html) and [classes](https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_object.html).
The JSON representation of TDLib API objects is straightforward: all API objects are represented as JSON objects with the same keys as the API object field names in the
[td_api.tl](https://github.com/tdlib/td/blob/master/td/generate/scheme/td_api.tl) scheme. Note that in the automatically generated C++ documentation all fields have an additional terminating underscore
[td_api.tl](https://github.com/tdlight-team/tdlight/blob/master/td/generate/scheme/td_api.tl) scheme. Note that in the automatically generated C++ documentation all fields have an additional terminating underscore
which shouldn't be used in the JSON interface. The object type name is stored in the special field '@type' which is optional in places where type is uniquely determined by the context.
Fields of Bool type are stored as Boolean, fields of int32, int53, and double types are stored as Number, fields of int64 and string types are stored as String,
fields of bytes type are base64 encoded and then stored as String, fields of array type are stored as Array.

View File

@ -65,7 +65,7 @@ class TdClient {
*
* If the query contains the field '@extra', the same field will be added into the result.
*
* @param {Object} query - The query for TDLib. See the [td_api.tl]{@link https://github.com/tdlib/td/blob/master/td/generate/scheme/td_api.tl} scheme or
* @param {Object} query - The query for TDLib. See the [td_api.tl]{@link https://github.com/tdlight-team/tdlight/blob/master/td/generate/scheme/td_api.tl} scheme or
* the automatically generated [HTML documentation]{@link https://core.telegram.org/tdlib/docs/td__api_8h.html}
* for a list of all available TDLib [methods]{@link https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_function.html} and
* [classes]{@link https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_object.html}.

1
td/generate/scheme/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.tlo

View File

@ -561,6 +561,21 @@ userTypeBot can_be_edited:Bool can_join_groups:Bool can_read_all_group_messages:
//@description No information on the user besides the user identifier is available, yet this user has not been deleted. This object is extremely rare and must be handled like a deleted user. It is not possible to perform any actions on users of this type
userTypeUnknown = UserType;
//@class AccessHashType @description Represents the type of an access hash. The following types are possible: user, channel
//@description An access hash of an user
accessHashTypeUser = AccessHashType;
//@description An access hash of a channel
accessHashTypeChannel = AccessHashType;
//@description Access hash
//@chat_id Chat identifier
//@type Access hash type
//@access_hash Access hash
accessHash chat_id:int53 type:AccessHashType access_hash:int64 = AccessHash;
//@description Represents a command supported by a bot @command Text of the bot command @param_description Description of the bot command
botCommand command:string description:string = BotCommand;
@ -576,6 +591,67 @@ botMenuButton text:string url:string = BotMenuButton;
chatLocation location:location address:string = ChatLocation;
//@class BusinessAwayMessageSchedule @description Describes conditions for sending of away messages by a Telegram Business account
//@description Send away messages always
businessAwayMessageScheduleAlways = BusinessAwayMessageSchedule;
//@description Send away messages outside of the business opening hours
businessAwayMessageScheduleOutsideOfOpeningHours = BusinessAwayMessageSchedule;
//@description Send away messages only in the specified time span
//@start_date Point in time (Unix timestamp) when the away messages will start to be sent
//@end_date Point in time (Unix timestamp) when the away messages will stop to be sent
businessAwayMessageScheduleCustom start_date:int32 end_date:int32 = BusinessAwayMessageSchedule;
//@description Represents a location of a business @location The location; may be null if not specified @address Location address; 1-96 characters
businessLocation location:location address:string = BusinessLocation;
//@description Describes private chats chosen for automatic interaction with a business
//@chat_ids Identifiers of selected private chats
//@select_existing_chats True, if all existing private chats are selected
//@select_new_chats True, if all new private chats are selected
//@select_contacts True, if all private chats with contacts are selected
//@select_non_contacts True, if all private chats with non-contacts are selected
//@exclude_selected If true, then all private chats except the selected are chosen. Otherwise, only the selected chats are chosen
businessRecipients chat_ids:vector<int53> select_existing_chats:Bool select_new_chats:Bool select_contacts:Bool select_non_contacts:Bool exclude_selected:Bool = BusinessRecipients;
//@description Describes settings for messages that are automatically sent by a Telegram Business account when it is away
//@shortcut_id Unique quick reply shortcut identifier for the away messages
//@recipients Chosen recipients of the away messages
//@schedule Settings used to check whether the current user is away
//@offline_only True, if the messages must not be sent if the account was online in the last 10 minutes
businessAwayMessageSettings shortcut_id:int32 recipients:businessRecipients schedule:BusinessAwayMessageSchedule offline_only:Bool = BusinessAwayMessageSettings;
//@description Describes settings for greeting messages that are automatically sent by a Telegram Business account as response to incoming messages in an inactive private chat
//@shortcut_id Unique quick reply shortcut identifier for the greeting messages
//@recipients Chosen recipients of the greeting messages
//@inactivity_days The number of days after which a chat will be considered as inactive; currently, must be on of 7, 14, 21, or 28
businessGreetingMessageSettings shortcut_id:int32 recipients:businessRecipients inactivity_days:int32 = BusinessGreetingMessageSettings;
//@description Describes a bot connected to a business account
//@bot_user_id User identifier of the bot
//@recipients Private chats that will be accessible to the bot
//@can_reply True, if the bot can send messages to the private chats; false otherwise
businessConnectedBot bot_user_id:int53 recipients:businessRecipients can_reply:Bool = BusinessConnectedBot;
//@description Describes an interval of time when the business is open
//@start_minute The first minute of the interval since start of the week; 0-7*24*60
//@end_minute The first minute after the end of the interval since start of the week; 1-8*24*60
businessOpeningHoursInterval start_minute:int32 end_minute:int32 = BusinessOpeningHoursInterval;
//@description Describes opening hours of a business @time_zone_id Unique time zone identifier @opening_hours Intervals of the time when the business is open
businessOpeningHours time_zone_id:string opening_hours:vector<businessOpeningHoursInterval> = BusinessOpeningHours;
//@description Contains information about a Telegram Business account
//@location Location of the business; may be null if none
//@opening_hours Opening hours of the business; may be null if none. The hours are guaranteed to be valid and has already been split by week days
//@greeting_message_settings The greeting message; may be null if none or the Business account is not of the current user
//@away_message_settings The away message; may be null if none or the Business account is not of the current user
businessInfo location:businessLocation opening_hours:businessOpeningHours greeting_message_settings:businessGreetingMessageSettings away_message_settings:businessAwayMessageSettings = BusinessInfo;
//@class ChatPhotoStickerType @description Describes type of a sticker, which was used to create a chat photo
//@description Information about the sticker, which was used to create the chat photo
@ -847,8 +923,9 @@ botInfo short_description:string description:string photo:photo animation:animat
//@bio A short user bio; may be null for bots
//@premium_gift_options The list of available options for gifting Telegram Premium to the user
//@group_in_common_count Number of group chats where both the other user and the current user are a member; 0 for the current user
//@business_info Information about business settings for Telegram Business accounts; may be null if none
//@bot_info For bots, information about the bot; may be null if the user isn't a bot
userFullInfo personal_photo:chatPhoto photo:chatPhoto public_photo:chatPhoto block_list:BlockList can_be_called:Bool supports_video_calls:Bool has_private_calls:Bool has_private_forwards:Bool has_restricted_voice_and_video_note_messages:Bool has_pinned_stories:Bool need_phone_number_privacy_exception:Bool set_chat_background:Bool bio:formattedText premium_gift_options:vector<premiumPaymentOption> group_in_common_count:int32 bot_info:botInfo = UserFullInfo;
userFullInfo personal_photo:chatPhoto photo:chatPhoto public_photo:chatPhoto block_list:BlockList can_be_called:Bool supports_video_calls:Bool has_private_calls:Bool has_private_forwards:Bool has_restricted_voice_and_video_note_messages:Bool has_pinned_stories:Bool need_phone_number_privacy_exception:Bool set_chat_background:Bool bio:formattedText premium_gift_options:vector<premiumPaymentOption> group_in_common_count:int32 business_info:businessInfo bot_info:botInfo = UserFullInfo;
//@description Represents a list of users @total_count Approximate total number of users found @user_ids A list of user identifiers
users total_count:int32 user_ids:vector<int53> = Users;
@ -1560,6 +1637,7 @@ chatFolderIcon name:string = ChatFolderIcon;
//@description Represents a folder for user chats
//@title The title of the folder; 1-12 characters without line feeds
//@icon The chosen icon for the chat folder; may be null. If null, use getChatFolderDefaultIconName to get default icon name for the folder
//@color_id The identifier of the chosen color for the chat folder icon; from -1 to 6. If -1, then color is didabled
//@is_shareable True, if at least one link has been created for the folder
//@pinned_chat_ids The chat identifiers of pinned chats in the folder. There can be up to getOption("chat_folder_chosen_chat_count_max") pinned and always included non-secret chats and the same number of secret chats, but the limit can be increased with Telegram Premium
//@included_chat_ids The chat identifiers of always included chats in the folder. There can be up to getOption("chat_folder_chosen_chat_count_max") pinned and always included non-secret chats and the same number of secret chats, but the limit can be increased with Telegram Premium
@ -1572,15 +1650,16 @@ chatFolderIcon name:string = ChatFolderIcon;
//@include_bots True, if bots need to be included
//@include_groups True, if basic groups and supergroups need to be included
//@include_channels True, if channels need to be included
chatFolder title:string icon:chatFolderIcon is_shareable:Bool pinned_chat_ids:vector<int53> included_chat_ids:vector<int53> excluded_chat_ids:vector<int53> exclude_muted:Bool exclude_read:Bool exclude_archived:Bool include_contacts:Bool include_non_contacts:Bool include_bots:Bool include_groups:Bool include_channels:Bool = ChatFolder;
chatFolder title:string icon:chatFolderIcon color_id:int32 is_shareable:Bool pinned_chat_ids:vector<int53> included_chat_ids:vector<int53> excluded_chat_ids:vector<int53> exclude_muted:Bool exclude_read:Bool exclude_archived:Bool include_contacts:Bool include_non_contacts:Bool include_bots:Bool include_groups:Bool include_channels:Bool = ChatFolder;
//@description Contains basic information about a chat folder
//@id Unique chat folder identifier
//@title The title of the folder; 1-12 characters without line feeds
//@icon The chosen or default icon for the chat folder
//@color_id The identifier of the chosen color for the chat folder icon; from -1 to 6. If -1, then color is didabled
//@is_shareable True, if at least one link has been created for the folder
//@has_my_invite_links True, if the chat folder has invite links created by the current user
chatFolderInfo id:int32 title:string icon:chatFolderIcon is_shareable:Bool has_my_invite_links:Bool = ChatFolderInfo;
chatFolderInfo id:int32 title:string icon:chatFolderIcon color_id:int32 is_shareable:Bool has_my_invite_links:Bool = ChatFolderInfo;
//@description Contains a chat folder invite link
//@invite_link The chat folder invite link
@ -1680,6 +1759,7 @@ videoChat group_call_id:int32 has_participants:Bool default_participant_id:Messa
//@permissions Actions that non-administrator chat members are allowed to take in the chat
//@last_message Last message in the chat; may be null if none or unknown
//@positions Positions of the chat in chat lists
//@chat_lists Chat lists to which the chat belongs. A chat can have a non-zero position in a chat list even it doesn't belong to the chat list and have no position in a chat list even it belongs to the chat list
//@message_sender_id Identifier of a user or chat that is selected to send messages in the chat; may be null if the user can't change message sender
//@block_list Block list to which the chat is added; may be null if none
//@has_protected_content True, if chat content can't be saved locally, forwarded, or copied
@ -1708,7 +1788,7 @@ videoChat group_call_id:int32 has_participants:Bool default_participant_id:Messa
//@reply_markup_message_id Identifier of the message from which reply markup needs to be used; 0 if there is no default custom reply markup in the chat
//@draft_message A draft of a message in the chat; may be null if none
//@client_data Application-specific data associated with the chat. (For example, the chat scroll position or local chat notification settings can be stored here.) Persistent if the message database is used
chat id:int53 type:ChatType title:string photo:chatPhotoInfo accent_color_id:int32 background_custom_emoji_id:int64 profile_accent_color_id:int32 profile_background_custom_emoji_id:int64 permissions:chatPermissions last_message:message positions:vector<chatPosition> message_sender_id:MessageSender block_list:BlockList has_protected_content:Bool is_translatable:Bool is_marked_as_unread:Bool view_as_topics:Bool has_scheduled_messages:Bool can_be_deleted_only_for_self:Bool can_be_deleted_for_all_users:Bool can_be_reported:Bool default_disable_notification:Bool unread_count:int32 last_read_inbox_message_id:int53 last_read_outbox_message_id:int53 unread_mention_count:int32 unread_reaction_count:int32 notification_settings:chatNotificationSettings available_reactions:ChatAvailableReactions message_auto_delete_time:int32 emoji_status:emojiStatus background:chatBackground theme_name:string action_bar:ChatActionBar video_chat:videoChat pending_join_requests:chatJoinRequestsInfo reply_markup_message_id:int53 draft_message:draftMessage client_data:string = Chat;
chat id:int53 type:ChatType title:string photo:chatPhotoInfo accent_color_id:int32 background_custom_emoji_id:int64 profile_accent_color_id:int32 profile_background_custom_emoji_id:int64 permissions:chatPermissions last_message:message positions:vector<chatPosition> chat_lists:vector<ChatList> message_sender_id:MessageSender block_list:BlockList has_protected_content:Bool is_translatable:Bool is_marked_as_unread:Bool view_as_topics:Bool has_scheduled_messages:Bool can_be_deleted_only_for_self:Bool can_be_deleted_for_all_users:Bool can_be_reported:Bool default_disable_notification:Bool unread_count:int32 last_read_inbox_message_id:int53 last_read_outbox_message_id:int53 unread_mention_count:int32 unread_reaction_count:int32 notification_settings:chatNotificationSettings available_reactions:ChatAvailableReactions message_auto_delete_time:int32 emoji_status:emojiStatus background:chatBackground theme_name:string action_bar:ChatActionBar video_chat:videoChat pending_join_requests:chatJoinRequestsInfo reply_markup_message_id:int53 draft_message:draftMessage client_data:string = Chat;
//@description Represents a list of chats @total_count Approximate total number of chats found @chat_ids List of chat identifiers
chats total_count:int32 chat_ids:vector<int53> = Chats;
@ -3711,6 +3791,25 @@ storyInteraction actor_id:MessageSender interaction_date:int32 block_list:BlockL
storyInteractions total_count:int32 total_forward_count:int32 total_reaction_count:int32 interactions:vector<storyInteraction> next_offset:string = StoryInteractions;
//@description Describes a message that can be used for quick reply
//@id Unique message identifier among all quick replies
//@sending_state The sending state of the message; may be null if the message isn't being sent and didn't fail to be sent
//@can_be_edited True, if the message can be edited
//@reply_to_message_id Information about the identifier of the quick reply message to which the message replies
//@via_bot_user_id If non-zero, the user identifier of the bot through which this message was sent
//@media_album_id Unique identifier of an album this message belongs to. Only audios, documents, photos and videos can be grouped together in albums
//@content Content of the message
//@reply_markup Inline keyboard reply markup for the message; may be null if none
quickReplyMessage id:int53 sending_state:MessageSendingState can_be_edited:Bool reply_to_message_id:int53 via_bot_user_id:int53 media_album_id:int64 content:MessageContent reply_markup:ReplyMarkup = QuickReplyMessage;
//@description Describes a shortcut that can be used for a quick reply
//@id Unique shortcut identifier
//@name The name of the shortcut that can be used to use the shortcut
//@first_message The first shortcut message
//@message_count The total number of messages in the shortcut
quickReplyShortcut id:int32 name:string first_message:quickReplyMessage message_count:int32 = QuickReplyShortcut;
//@class PublicForward @description Describes a public forward or repost of a story
//@description Contains a public forward as a message @message Information about the message
@ -5021,6 +5120,16 @@ themeSettings accent_color:int32 background:background outgoing_message_fill:Bac
chatTheme name:string light_settings:themeSettings dark_settings:themeSettings = ChatTheme;
//@description Describes a time zone
//@id Unique time zone identifier
//@name Time zone name
//@utc_time_offset Current UTC time offset for the time zone
timeZone id:string name:string utc_time_offset:int32 = TimeZone;
//@description Contains a list of time zones @time_zones A list of time zones
timeZones time_zones:vector<timeZone> = TimeZones;
//@description Contains a list of hashtags @hashtags A list of hashtags
hashtags hashtags:vector<string> = Hashtags;
@ -5955,6 +6064,10 @@ storageStatisticsFast files_size:int53 file_count:int32 database_size:int53 lang
//@statistics Database statistics in an unspecified human-readable format
databaseStatistics statistics:string = DatabaseStatistics;
//@description Contains memory statistics
//@statistics Memory statistics in an unspecified human-readable format
memoryStatistics statistics:string = MemoryStatistics;
//@class NetworkType @description Represents the type of a network
@ -6450,6 +6563,12 @@ updateChatLastMessage chat_id:int53 last_message:message positions:vector<chatPo
//@position New chat position. If new order is 0, then the chat needs to be removed from the list
updateChatPosition chat_id:int53 position:chatPosition = Update;
//@description A chat was added to a chat list @chat_id Chat identifier @chat_list The chat list to which the chat was added
updateChatAddedToList chat_id:int53 chat_list:ChatList = Update;
//@description A chat was removed from a chat list @chat_id Chat identifier @chat_list The chat list from which the chat was removed
updateChatRemovedFromList chat_id:int53 chat_list:ChatList = Update;
//@description Incoming messages were read or the number of unread messages has been changed @chat_id Chat identifier @last_read_inbox_message_id Identifier of the last read incoming message @unread_count The number of unread messages left in the chat
updateChatReadInbox chat_id:int53 last_read_inbox_message_id:int53 unread_count:int32 = Update;
@ -6526,8 +6645,11 @@ updateChatBlockList chat_id:int53 block_list:BlockList = Update;
//@description A chat's has_scheduled_messages field has changed @chat_id Chat identifier @has_scheduled_messages New value of has_scheduled_messages
updateChatHasScheduledMessages chat_id:int53 has_scheduled_messages:Bool = Update;
//@description The list of chat folders or a chat folder has changed @chat_folders The new list of chat folders @main_chat_list_position Position of the main chat list among chat folders, 0-based
updateChatFolders chat_folders:vector<chatFolderInfo> main_chat_list_position:int32 = Update;
//@description The list of chat folders or a chat folder has changed
//@chat_folders The new list of chat folders
//@main_chat_list_position Position of the main chat list among chat folders, 0-based
//@are_tags_enabled True, if folder tags are enabled
updateChatFolders chat_folders:vector<chatFolderInfo> main_chat_list_position:int32 are_tags_enabled:Bool = Update;
//@description The number of online group members has changed. This update with non-zero number of online group members is sent only for currently opened chats.
//-There is no guarantee that it is sent just after the number of online users has changed
@ -6542,6 +6664,21 @@ updateSavedMessagesTopic topic:savedMessagesTopic = Update;
//@description Number of Saved Messages topics has changed @topic_count Approximate total number of Saved Messages topics
updateSavedMessagesTopicCount topic_count:int32 = Update;
//@description Basic information about a quick reply shortcut has changed. This update is guaranteed to come before the quick shortcut name is returned to the application
//@shortcut New data about the shortcut
updateQuickReplyShortcut shortcut:quickReplyShortcut = Update;
//@description A quick reply shortcut and all its messages were deleted @shortcut_id The identifier of the deleted shortcut
updateQuickReplyShortcutDeleted shortcut_id:int32 = Update;
//@description The list of quick reply shortcuts has changed @shortcut_ids The new list of identifiers of quick reply shortcuts
updateQuickReplyShortcuts shortcut_ids:vector<int32> = Update;
//@description The list of quick reply shortcut messages has changed
//@shortcut_id The identifier of the shortcut
//@messages The new list of quick reply messages for the shortcut in order from the first to the last sent
updateQuickReplyShortcutMessages shortcut_id:int32 messages:vector<quickReplyMessage> = Update;
//@description Basic information about a topic in a forum chat was changed @chat_id Chat identifier @info New information about the topic
updateForumTopicInfo chat_id:int53 info:forumTopicInfo = Update;
@ -6590,6 +6727,9 @@ updateUserStatus user_id:int53 status:UserStatus = Update;
//@description Some data of a user has changed. This update is guaranteed to come before the user identifier is returned to the application @user New data about the user
updateUser user:user = Update;
//@description Some data of a user or a chat has changed. This update is guaranteed to come before the user or chat identifier is returned to the application @access_hash Access hash
updateAccessHash access_hash:accessHash = Update;
//@description Some data of a basic group has changed. This update is guaranteed to come before the basic group identifier is returned to the application @basic_group New data about the group
updateBasicGroup basic_group:basicGroup = Update;
@ -7565,6 +7705,12 @@ sendInlineQueryResultMessage chat_id:int53 message_thread_id:int53 reply_to:Inpu
//@remove_caption Pass true to remove media captions of message copies. Ignored if send_copy is false
forwardMessages chat_id:int53 message_thread_id:int53 from_chat_id:int53 message_ids:vector<int53> options:messageSendOptions send_copy:Bool remove_caption:Bool = Messages;
//@description Sends messages from a quick reply shortcut. Requires Telegram Business subscription
//@chat_id Identifier of the chat to which to send messages. The chat must be a private chat with a regular user
//@shortcut_id Unique identifier of the quick reply shortcut
//@sending_id Non-persistent identifier, which will be returned back in messageSendingStatePending object and can be used to match sent messages and corresponding updateNewMessage updates
sendQuickReplyShortcutMessages chat_id:int53 shortcut_id:int32 sending_id:int32 = Messages;
//@description Resends messages which failed to send. Can be called only for messages for which messageSendingStateFailed.can_retry is true and after specified in messageSendingStateFailed.retry_after time passed.
//-If a message is re-sent, the corresponding failed to send message is deleted. Returns the sent messages in the same order as the message identifiers passed in message_ids. If a message can't be re-sent, null will be returned instead of the message
//@chat_id Identifier of the chat to send messages
@ -7669,6 +7815,31 @@ editInlineMessageReplyMarkup inline_message_id:string reply_markup:ReplyMarkup =
editMessageSchedulingState chat_id:int53 message_id:int53 scheduling_state:MessageSchedulingState = Ok;
//@description Checks validness of a name for a quick reply shortcut. Can be called synchronously @name The name of the shortcut; 1-32 characters
checkQuickReplyShortcutName name:string = Ok;
//@description Loads quick reply shortcuts created by the current user. The loaded topics will be sent through updateQuickReplyShortcuts
loadQuickReplyShortcuts = Ok;
//@description Changes name of a quick reply shortcut @shortcut_id Unique identifier of the quick reply shortcut @name New name for the shortcut. Use checkQuickReplyShortcutName to check its validness
setQuickReplyShortcutName shortcut_id:int32 name:string = Ok;
//@description Deletes a quick reply shortcut @shortcut_id Unique identifier of the quick reply shortcut
deleteQuickReplyShortcut shortcut_id:int32 = Ok;
//@description Changes the order of quick reply shortcuts @shortcut_ids The new order of quick reply shortcuts
reorderQuickReplyShortcuts shortcut_ids:vector<int32> = Ok;
//@description Loads quick reply messages that can be sent by a given quick reply shortcut. The loaded messages will be sent through updateQuickReplyShortcutMessages
//@shortcut_id Unique identifier of the quick reply shortcut
loadQuickReplyShortcutMessages shortcut_id:int32 = Ok;
//@description Deletes specified quick reply messages
//@shortcut_id Unique identifier of the quick reply shortcut to which the messages belong
//@message_ids Unique identifiers of the messages
deleteQuickReplyShortcutMessages shortcut_id:int32 message_ids:vector<int53> = Ok;
//@description Returns list of custom emojis, which can be used as forum topic icon by all users
getForumTopicDefaultIcons = Stickers;
@ -8132,6 +8303,9 @@ getChatFolderChatCount folder:chatFolder = Count;
//@description Changes the order of chat folders @chat_folder_ids Identifiers of chat folders in the new correct order @main_chat_list_position Position of the main chat list among chat folders, 0-based. Can be non-zero only for Premium users
reorderChatFolders chat_folder_ids:vector<int32> main_chat_list_position:int32 = Ok;
//@description Toggles whether chat folder tags are enabled @are_tags_enabled Pass true to enable folder tags; pass false to disable them
toggleChatFolderTags are_tags_enabled:Bool = Ok;
//@description Returns recommended chat folders for the current user
getRecommendedChatFolders = RecommendedChatFolders;
@ -9106,7 +9280,7 @@ reorderInstalledStickerSets sticker_type:StickerType sticker_set_ids:vector<int6
getRecentStickers is_attached:Bool = Stickers;
//@description Manually adds a new sticker to the list of recently used stickers. The new sticker is added to the top of the list. If the sticker was already in the list, it is removed from the list first.
//-Only stickers belonging to a sticker set can be added to this list. Emoji stickers can't be added to recent stickers
//-Only stickers belonging to a sticker set or in WEBP format can be added to this list. Emoji stickers can't be added to recent stickers
//@is_attached Pass true to add the sticker to the list of stickers recently attached to photo or video files; pass false to add the sticker to the list of recently sent stickers
//@sticker Sticker file to add
addRecentSticker is_attached:Bool sticker:InputFile = Stickers;
@ -9121,7 +9295,7 @@ clearRecentStickers is_attached:Bool = Ok;
getFavoriteStickers = Stickers;
//@description Adds a new sticker to the list of favorite stickers. The new sticker is added to the top of the list. If the sticker was already in the list, it is removed from the list first.
//-Only stickers belonging to a sticker set can be added to this list. Emoji stickers can't be added to favorite stickers
//-Only stickers belonging to a sticker set or in WEBP format can be added to this list. Emoji stickers can't be added to favorite stickers
//@sticker Sticker file to add
addFavoriteSticker sticker:InputFile = Ok;
@ -9233,9 +9407,21 @@ reorderActiveUsernames usernames:vector<string> = Ok;
//@description Changes the emoji status of the current user; for Telegram Premium users only @emoji_status New emoji status; pass null to switch to the default badge
setEmojiStatus emoji_status:emojiStatus = Ok;
//@description Changes the location of the current user. Needs to be called if getOption("is_location_visible") is true and location changes for more than 1 kilometer @location The new location of the user
//@description Changes the location of the current user. Needs to be called if getOption("is_location_visible") is true and location changes for more than 1 kilometer. Must not be called if the user has a business location @location The new location of the user
setLocation location:location = Ok;
//@description Changes the business location of the current user. Requires Telegram Business subscription @location The new location of the business; pass null to remove the location
setBusinessLocation location:businessLocation = Ok;
//@description Changes the business opening hours of the current user. Requires Telegram Business subscription @opening_hours The new opening hours of the business; pass null to remove the opening hours
setBusinessOpeningHours opening_hours:businessOpeningHours = Ok;
//@description Changes the business greeting message settings of the current user. Requires Telegram Business subscription @greeting_message_settings The new settings for the greeting message of the business; pass null to disable the greeting message
setBusinessGreetingMessageSettings greeting_message_settings:businessGreetingMessageSettings = Ok;
//@description Changes the business away message settings of the current user. Requires Telegram Business subscription @away_message_settings The new settings for the away message of the business; pass null to disable the away message
setBusinessAwayMessageSettings away_message_settings:businessAwayMessageSettings = Ok;
//@description Changes the phone number of the user and sends an authentication code to the user's new phone number; for official Android and iOS applications only. On success, returns information about the sent code
//@phone_number The new phone number of the user in international format
//@settings Settings for the authentication of the user's phone number; pass null to use default settings
@ -9248,6 +9434,16 @@ resendChangePhoneNumberCode = AuthenticationCodeInfo;
checkChangePhoneNumberCode code:string = Ok;
//@description Returns the business bot that is connected to the current user account. Returns a 404 error if there is no connected bot
getBusinessConnectedBot = BusinessConnectedBot;
//@description Adds or changes business bot that is connected to the current user account @bot Connection settings for the bot
setBusinessConnectedBot bot:businessConnectedBot = Ok;
//@description Deletes the business bot that is connected to the current user account @bot_user_id Unique user identifier for the bot
deleteBusinessConnectedBot bot_user_id:int53 = Ok;
//@description Returns an HTTPS link, which can be used to get information about the current user
getUserLink = UserLink;
@ -9468,6 +9664,10 @@ closeSecretChat secret_chat_id:int32 = Ok;
getChatEventLog chat_id:int53 query:string from_event_id:int64 limit:int32 filters:chatEventLogFilters user_ids:vector<int53> = ChatEvents;
//@description Returns the list of supported time zones
getTimeZones = TimeZones;
//@description Returns an invoice payment form. This method must be called when the user presses inline button of the type inlineKeyboardButtonTypeBuy
//@input_invoice The invoice
//@theme Preferred payment form theme; pass null to use the default theme
@ -9694,6 +9894,10 @@ getStorageStatisticsFast = StorageStatisticsFast;
//@description Returns database statistics
getDatabaseStatistics = DatabaseStatistics;
//@description Returns memory statistics
//@full Full memory statistics calculation
getMemoryStatistics full:Bool = MemoryStatistics;
//@description Optimizes storage usage, i.e. deletes some files and returns new storage usage statistics. Secret thumbnails can't be deleted
//@size Limit on the total size of files after deletion, in bytes. Pass -1 to use the default limit
//@ttl Limit on the time that has passed since the last time a file was accessed (or creation time for some filesystems). Pass -1 to use the default limit

View File

@ -135,7 +135,7 @@ chatPhotoEmpty#37c1011c = ChatPhoto;
chatPhoto#1c6e1c11 flags:# has_video:flags.0?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = ChatPhoto;
messageEmpty#90a6ca84 flags:# id:int peer_id:flags.0?Peer = Message;
message#1e4c8a69 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true pinned:flags.24?true noforwards:flags.26?true invert_media:flags.27?true id:int from_id:flags.8?Peer from_boosts_applied:flags.29?int peer_id:Peer saved_peer_id:flags.28?Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int forwards:flags.10?int replies:flags.23?MessageReplies edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long reactions:flags.20?MessageReactions restriction_reason:flags.22?Vector<RestrictionReason> ttl_period:flags.25?int = Message;
message#a66c7efc flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true pinned:flags.24?true noforwards:flags.26?true invert_media:flags.27?true id:int from_id:flags.8?Peer from_boosts_applied:flags.29?int peer_id:Peer saved_peer_id:flags.28?Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int forwards:flags.10?int replies:flags.23?MessageReplies edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long reactions:flags.20?MessageReactions restriction_reason:flags.22?Vector<RestrictionReason> ttl_period:flags.25?int quick_reply_shortcut_id:flags.30?int = Message;
messageService#2b085862 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true legacy:flags.19?true id:int from_id:flags.8?Peer peer_id:Peer reply_to:flags.3?MessageReplyHeader date:int action:MessageAction ttl_period:flags.25?int = Message;
messageMediaEmpty#3ded6320 = MessageMedia;
@ -248,7 +248,7 @@ inputReportReasonFake#f5ddd6e7 = ReportReason;
inputReportReasonIllegalDrugs#a8eb2be = ReportReason;
inputReportReasonPersonalDetails#9ec7863d = ReportReason;
userFull#b9b12c6c flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true voice_messages_forbidden:flags.20?true translations_disabled:flags.23?true stories_pinned_available:flags.26?true blocked_my_stories_from:flags.27?true wallpaper_overridden:flags.28?true contact_require_premium:flags.29?true read_dates_private:flags.30?true id:long about:flags.1?string settings:PeerSettings personal_photo:flags.21?Photo profile_photo:flags.2?Photo fallback_photo:flags.22?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int ttl_period:flags.14?int theme_emoticon:flags.15?string private_forward_name:flags.16?string bot_group_admin_rights:flags.17?ChatAdminRights bot_broadcast_admin_rights:flags.18?ChatAdminRights premium_gifts:flags.19?Vector<PremiumGiftOption> wallpaper:flags.24?WallPaper stories:flags.25?PeerStories = UserFull;
userFull#22ff3e85 flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true voice_messages_forbidden:flags.20?true translations_disabled:flags.23?true stories_pinned_available:flags.26?true blocked_my_stories_from:flags.27?true wallpaper_overridden:flags.28?true contact_require_premium:flags.29?true read_dates_private:flags.30?true flags2:# id:long about:flags.1?string settings:PeerSettings personal_photo:flags.21?Photo profile_photo:flags.2?Photo fallback_photo:flags.22?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int ttl_period:flags.14?int theme_emoticon:flags.15?string private_forward_name:flags.16?string bot_group_admin_rights:flags.17?ChatAdminRights bot_broadcast_admin_rights:flags.18?ChatAdminRights premium_gifts:flags.19?Vector<PremiumGiftOption> wallpaper:flags.24?WallPaper stories:flags.25?PeerStories business_work_hours:flags2.0?BusinessWorkHours business_location:flags2.1?BusinessLocation business_greeting_message:flags2.2?BusinessGreetingMessage business_away_message:flags2.3?BusinessAwayMessage = UserFull;
contact#145ade0b user_id:long mutual:Bool = Contact;
@ -423,6 +423,12 @@ updateBotMessageReactions#9cb7759 peer:Peer msg_id:int date:int reactions:Vector
updateSavedDialogPinned#aeaf9e74 flags:# pinned:flags.0?true peer:DialogPeer = Update;
updatePinnedSavedDialogs#686c85a6 flags:# order:flags.0?Vector<DialogPeer> = Update;
updateSavedReactionTags#39c67432 = Update;
updateSmsJob#f16269d4 job_id:string = Update;
updateQuickReplies#f9470ab2 quick_replies:Vector<QuickReply> = Update;
updateNewQuickReply#f53da717 quick_reply:QuickReply = Update;
updateDeleteQuickReply#53e6f1ec shortcut_id:int = Update;
updateQuickReplyMessage#3e050d0f message:Message = Update;
updateDeleteQuickReplyMessages#566fe7cd shortcut_id:int messages:Vector<int> = Update;
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
@ -1249,9 +1255,9 @@ bankCardOpenUrl#f568028a url:string name:string = BankCardOpenUrl;
payments.bankCardData#3e24e573 title:string open_urls:Vector<BankCardOpenUrl> = payments.BankCardData;
dialogFilter#7438f7e8 flags:# contacts:flags.0?true non_contacts:flags.1?true groups:flags.2?true broadcasts:flags.3?true bots:flags.4?true exclude_muted:flags.11?true exclude_read:flags.12?true exclude_archived:flags.13?true id:int title:string emoticon:flags.25?string pinned_peers:Vector<InputPeer> include_peers:Vector<InputPeer> exclude_peers:Vector<InputPeer> = DialogFilter;
dialogFilter#5fb5523b flags:# contacts:flags.0?true non_contacts:flags.1?true groups:flags.2?true broadcasts:flags.3?true bots:flags.4?true exclude_muted:flags.11?true exclude_read:flags.12?true exclude_archived:flags.13?true id:int title:string emoticon:flags.25?string color:flags.27?int pinned_peers:Vector<InputPeer> include_peers:Vector<InputPeer> exclude_peers:Vector<InputPeer> = DialogFilter;
dialogFilterDefault#363293ae = DialogFilter;
dialogFilterChatlist#d64a04a8 flags:# has_my_invites:flags.26?true id:int title:string emoticon:flags.25?string pinned_peers:Vector<InputPeer> include_peers:Vector<InputPeer> = DialogFilter;
dialogFilterChatlist#9fe28ea4 flags:# has_my_invites:flags.26?true id:int title:string emoticon:flags.25?string color:flags.27?int pinned_peers:Vector<InputPeer> include_peers:Vector<InputPeer> = DialogFilter;
dialogFilterSuggested#77744d4a filter:DialogFilter description:string = DialogFilterSuggested;
@ -1674,6 +1680,53 @@ messages.savedReactionTags#3259950a tags:Vector<SavedReactionTag> hash:long = me
outboxReadDate#3bb842ac date:int = OutboxReadDate;
smsjobs.eligibleToJoin#dc8b44cf terms_url:string monthly_sent_sms:int = smsjobs.EligibilityToJoin;
smsjobs.status#2aee9191 flags:# allow_international:flags.0?true recent_sent:int recent_since:int recent_remains:int total_sent:int total_since:int last_gift_slug:flags.1?string terms_url:string = smsjobs.Status;
smsJob#e6a1eeb8 job_id:string phone_number:string text:string = SmsJob;
businessWeeklyOpen#120b1ab9 start_minute:int end_minute:int = BusinessWeeklyOpen;
businessWorkHours#8c92b098 flags:# open_now:flags.0?true timezone_id:string weekly_open:Vector<BusinessWeeklyOpen> = BusinessWorkHours;
businessLocation#ac5c1af7 flags:# geo_point:flags.0?GeoPoint address:string = BusinessLocation;
inputBusinessRecipients#6f8b32aa flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector<InputUser> = InputBusinessRecipients;
businessRecipients#21108ff7 flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector<long> = BusinessRecipients;
businessAwayMessageScheduleAlways#c9b9e2b9 = BusinessAwayMessageSchedule;
businessAwayMessageScheduleOutsideWorkHours#c3f2f501 = BusinessAwayMessageSchedule;
businessAwayMessageScheduleCustom#cc4d9ecc start_date:int end_date:int = BusinessAwayMessageSchedule;
inputBusinessGreetingMessage#194cb3b shortcut_id:int recipients:InputBusinessRecipients no_activity_days:int = InputBusinessGreetingMessage;
businessGreetingMessage#e519abab shortcut_id:int recipients:BusinessRecipients no_activity_days:int = BusinessGreetingMessage;
inputBusinessAwayMessage#832175e0 flags:# offline_only:flags.0?true shortcut_id:int schedule:BusinessAwayMessageSchedule recipients:InputBusinessRecipients = InputBusinessAwayMessage;
businessAwayMessage#ef156a5c flags:# offline_only:flags.0?true shortcut_id:int schedule:BusinessAwayMessageSchedule recipients:BusinessRecipients = BusinessAwayMessage;
timezone#ff9289f5 id:string name:string utc_offset:int = Timezone;
help.timezonesListNotModified#970708cc = help.TimezonesList;
help.timezonesList#7b74ed71 timezones:Vector<Timezone> hash:int = help.TimezonesList;
quickReply#697102b shortcut_id:int shortcut:string top_message:int count:int = QuickReply;
inputQuickReplyShortcut#24596d41 shortcut:string = InputQuickReplyShortcut;
inputQuickReplyShortcutId#1190cf1 shortcut_id:int = InputQuickReplyShortcut;
messages.quickReplies#c68d6695 quick_replies:Vector<QuickReply> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.QuickReplies;
messages.quickRepliesNotModified#5f91eb5b = messages.QuickReplies;
connectedBot#e7e999e7 flags:# can_reply:flags.0?true bot_id:long recipients:BusinessRecipients = ConnectedBot;
account.connectedBots#17d7f87b connected_bots:Vector<ConnectedBot> users:Vector<User> = account.ConnectedBots;
messages.dialogFilters#2ad93719 flags:# tags_enabled:flags.0?true filters:Vector<DialogFilter> = messages.DialogFilters;
---functions---
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
@ -1799,6 +1852,12 @@ account.updateColor#7cefa15d flags:# for_profile:flags.1?true color:flags.2?int
account.getDefaultBackgroundEmojis#a60ab9ce hash:long = EmojiList;
account.getChannelDefaultEmojiStatuses#7727a7d5 hash:long = account.EmojiStatuses;
account.getChannelRestrictedStatusEmojis#35a9e0d5 hash:long = EmojiList;
account.updateBusinessWorkHours#4b00e066 flags:# business_work_hours:flags.0?BusinessWorkHours = Bool;
account.updateBusinessLocation#9e6b131a flags:# geo_point:flags.1?InputGeoPoint address:flags.0?string = Bool;
account.updateBusinessGreetingMessage#66cdafc4 flags:# message:flags.0?InputBusinessGreetingMessage = Bool;
account.updateBusinessAwayMessage#a26a7fa5 flags:# message:flags.0?InputBusinessAwayMessage = Bool;
account.updateConnectedBot#9c2d527d flags:# can_reply:flags.0?true deleted:flags.1?true bot:InputUser recipients:InputBusinessRecipients = Updates;
account.getConnectedBots#4ea4c80f = account.ConnectedBots;
users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
users.getFullUser#b60f5918 id:InputUser = users.UserFull;
@ -1840,9 +1899,9 @@ messages.deleteHistory#b08f922a flags:# just_clear:flags.0?true revoke:flags.1?t
messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector<int> = messages.AffectedMessages;
messages.receivedMessages#5a954c0 max_id:int = Vector<ReceivedNotifyMessage>;
messages.setTyping#58943ee2 flags:# peer:InputPeer top_msg_id:flags.0?int action:SendMessageAction = Bool;
messages.sendMessage#280d096f flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true peer:InputPeer reply_to:flags.0?InputReplyTo message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.10?int send_as:flags.13?InputPeer = Updates;
messages.sendMedia#72ccc23d flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true peer:InputPeer reply_to:flags.0?InputReplyTo media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.10?int send_as:flags.13?InputPeer = Updates;
messages.forwardMessages#c661bbc4 flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true drop_author:flags.11?true drop_media_captions:flags.12?true noforwards:flags.14?true from_peer:InputPeer id:Vector<int> random_id:Vector<long> to_peer:InputPeer top_msg_id:flags.9?int schedule_date:flags.10?int send_as:flags.13?InputPeer = Updates;
messages.sendMessage#dff8042c flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true peer:InputPeer reply_to:flags.0?InputReplyTo message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut = Updates;
messages.sendMedia#7bd66041 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true peer:InputPeer reply_to:flags.0?InputReplyTo media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut = Updates;
messages.forwardMessages#d5039208 flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true drop_author:flags.11?true drop_media_captions:flags.12?true noforwards:flags.14?true from_peer:InputPeer id:Vector<int> random_id:Vector<long> to_peer:InputPeer top_msg_id:flags.9?int schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut = Updates;
messages.reportSpam#cf1592db peer:InputPeer = Bool;
messages.getPeerSettings#efd9a6a2 peer:InputPeer = messages.PeerSettings;
messages.report#8953ab4e peer:InputPeer id:Vector<int> reason:ReportReason message:string = Bool;
@ -1885,9 +1944,9 @@ messages.getSavedGifs#5cf09635 hash:long = messages.SavedGifs;
messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool;
messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults;
messages.setInlineBotResults#bb12a419 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector<InputBotInlineResult> cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM switch_webview:flags.4?InlineBotWebView = Bool;
messages.sendInlineBotResult#f7bc68ba flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true hide_via:flags.11?true peer:InputPeer reply_to:flags.0?InputReplyTo random_id:long query_id:long id:string schedule_date:flags.10?int send_as:flags.13?InputPeer = Updates;
messages.sendInlineBotResult#3ebee86a flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true hide_via:flags.11?true peer:InputPeer reply_to:flags.0?InputReplyTo random_id:long query_id:long id:string schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut = Updates;
messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData;
messages.editMessage#48f71778 flags:# no_webpage:flags.1?true invert_media:flags.16?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.15?int = Updates;
messages.editMessage#dfd14005 flags:# no_webpage:flags.1?true invert_media:flags.16?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.15?int quick_reply_shortcut_id:flags.17?int = Updates;
messages.editInlineBotMessage#83557dba flags:# no_webpage:flags.1?true invert_media:flags.16?true id:InputBotInlineMessageID message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Bool;
messages.getBotCallbackAnswer#9342ca07 flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes password:flags.2?InputCheckPasswordSRP = messages.BotCallbackAnswer;
messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool;
@ -1920,7 +1979,7 @@ messages.faveSticker#b9ffc55b id:InputDocument unfave:Bool = Bool;
messages.getUnreadMentions#f107e790 flags:# peer:InputPeer top_msg_id:flags.0?int offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages;
messages.readMentions#36e5bf4d flags:# peer:InputPeer top_msg_id:flags.0?int = messages.AffectedHistory;
messages.getRecentLocations#702a40e0 peer:InputPeer limit:int hash:long = messages.Messages;
messages.sendMultiMedia#456e8987 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true peer:InputPeer reply_to:flags.0?InputReplyTo multi_media:Vector<InputSingleMedia> schedule_date:flags.10?int send_as:flags.13?InputPeer = Updates;
messages.sendMultiMedia#c964709 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true peer:InputPeer reply_to:flags.0?InputReplyTo multi_media:Vector<InputSingleMedia> schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut = Updates;
messages.uploadEncryptedFile#5057c497 peer:InputEncryptedChat file:InputEncryptedFile = EncryptedFile;
messages.searchStickerSets#35705b8a flags:# exclude_featured:flags.0?true q:string hash:long = messages.FoundStickerSets;
messages.getSplitRanges#1cff7e08 = Vector<MessageRange>;
@ -1947,7 +2006,7 @@ messages.sendScheduledMessages#bd38850a peer:InputPeer id:Vector<int> = Updates;
messages.deleteScheduledMessages#59ae2b16 peer:InputPeer id:Vector<int> = Updates;
messages.getPollVotes#b86e380e flags:# peer:InputPeer id:int option:flags.0?bytes offset:flags.1?string limit:int = messages.VotesList;
messages.toggleStickerSets#b5052fea flags:# uninstall:flags.0?true archive:flags.1?true unarchive:flags.2?true stickersets:Vector<InputStickerSet> = Bool;
messages.getDialogFilters#f19ed96d = Vector<DialogFilter>;
messages.getDialogFilters#efd48c89 = messages.DialogFilters;
messages.getSuggestedDialogFilters#a29cd42c = Vector<DialogFilterSuggested>;
messages.updateDialogFilter#1ad4a04a flags:# id:int filter:flags.0?DialogFilter = Bool;
messages.updateDialogFiltersOrder#c563c1e4 order:Vector<int> = Bool;
@ -2029,6 +2088,15 @@ messages.getSavedReactionTags#3637e05b flags:# peer:flags.0?InputPeer hash:long
messages.updateSavedReactionTag#60297dec flags:# reaction:Reaction title:flags.0?string = Bool;
messages.getDefaultTagReactions#bdf93428 hash:long = messages.Reactions;
messages.getOutboxReadDate#8c4bfe5d peer:InputPeer msg_id:int = OutboxReadDate;
messages.getQuickReplies#d483f2a8 hash:long = messages.QuickReplies;
messages.reorderQuickReplies#60331907 order:Vector<int> = Bool;
messages.checkQuickReplyShortcut#f1d0fbd3 shortcut:string = Bool;
messages.editQuickReplyShortcut#5c003cef shortcut_id:int shortcut:string = Bool;
messages.deleteQuickReplyShortcut#3cc04740 shortcut_id:int = Bool;
messages.getQuickReplyMessages#94a495c3 flags:# shortcut_id:int id:flags.0?Vector<int> hash:long = messages.Messages;
messages.sendQuickReplyMessages#33153ad4 peer:InputPeer shortcut_id:int = Updates;
messages.deleteQuickReplyMessages#e105e910 shortcut_id:int id:Vector<int> = Updates;
messages.toggleDialogFilterTags#fd2dda49 enabled:Bool = Bool;
updates.getState#edd4882a = updates.State;
updates.getDifference#19c2f763 flags:# pts:int pts_limit:flags.1?int pts_total_limit:flags.0?int date:int qts:int qts_limit:flags.2?int = updates.Difference;
@ -2073,6 +2141,7 @@ help.getCountriesList#735787a8 lang_code:string hash:int = help.CountriesList;
help.getPremiumPromo#b81b93d4 = help.PremiumPromo;
help.getPeerColors#da80f42f hash:int = help.PeerColors;
help.getPeerProfileColors#abcfa9fd hash:int = help.PeerColors;
help.getTimezonesList#49b30240 hash:int = help.TimezonesList;
channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool;
channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector<int> = messages.AffectedMessages;
@ -2272,3 +2341,11 @@ premium.getMyBoosts#be77b4a = premium.MyBoosts;
premium.applyBoost#6b7da746 flags:# slots:flags.0?Vector<int> peer:InputPeer = premium.MyBoosts;
premium.getBoostsStatus#42f1f61 peer:InputPeer = premium.BoostsStatus;
premium.getUserBoosts#39854d1f peer:InputPeer user_id:InputUser = premium.BoostsList;
smsjobs.isEligibleToJoin#edc39d0 = smsjobs.EligibilityToJoin;
smsjobs.join#a74ece2d = Bool;
smsjobs.leave#9898ad73 = Bool;
smsjobs.updateSettings#93fa0bf flags:# allow_international:flags.0?true = Bool;
smsjobs.getStatus#10a698e8 = smsjobs.Status;
smsjobs.getSmsJob#778d902f job_id:string = SmsJob;
smsjobs.finishJob#4f1ebf24 flags:# job_id:string error:flags.0?string = Bool;

View File

@ -185,7 +185,7 @@ void tl_print_parse_error (void) {
}
char *parse_lex (void) {
while (1) {
while (1) {
while (curch && is_whitespace (curch)) { nextch (); }
if (curch == '/' && nextch () == '/') {
while (nextch () != 10);
@ -235,7 +235,7 @@ char *parse_lex (void) {
case '.':
nextch ();
parse.lex.len = 1;
parse.lex.type = lex_char;
parse.lex.type = lex_char;
return (parse.lex.ptr = p);
case 'a':
case 'b':
@ -334,10 +334,10 @@ char *parse_lex (void) {
int ok = 1;
for (i = 0; i < 8; i++) {
if (!is_hexdigit (nextch())) {
if (curch == ' ' && i >= 5) {
if (curch == ' ' && i >= 5) {
ok = 2;
break;
} else {
} else {
parse_error ("Hex digit expected");
parse.lex.type = lex_error;
return (parse.lex.ptr = (void *)-1);
@ -370,7 +370,7 @@ char *parse_lex (void) {
parse.lex.type = lex_error;
return (parse.lex.ptr = (void *)-1);
}
}
int expect (char *s) {
@ -453,7 +453,7 @@ struct tree *parse_full_combinator_id (void) {
} else {
parse_error ("Can not parse full combinator id");
PARSE_FAIL;
}
}
}
struct tree *parse_combinator_id (void) {
@ -467,7 +467,7 @@ struct tree *parse_combinator_id (void) {
} else {
parse_error ("Can not parse combinator id");
PARSE_FAIL;
}
}
}
struct tree *parse_var_ident (void) {
@ -595,7 +595,7 @@ struct tree *parse_subexpr (void) {
was_term = 1;
PARSE_TRY (parse_term);
if (S) {
tree_add_child (T, S);
tree_add_child (T, S);
} else {
break;
}
@ -714,7 +714,7 @@ struct tree *parse_args4 (void) {
if (S) {
tree_add_child (T, S);
} else {
load_parse (so);
load_parse (so);
}
if (LEX_CHAR ('!')) {
PARSE_ADD (type_exclam);
@ -733,7 +733,7 @@ struct tree *parse_args3 (void) {
if (S) {
tree_add_child (T, S);
} else {
load_parse (so);
load_parse (so);
}
if (LEX_CHAR ('!')) {
PARSE_ADD (type_exclam);
@ -757,7 +757,7 @@ struct tree *parse_args2 (void) {
if (S) {
tree_add_child (T, S);
} else {
load_parse (so);
load_parse (so);
}
struct parse save2 = save_parse ();
PARSE_TRY (parse_multiplicity);
@ -789,7 +789,7 @@ struct tree *parse_args1 (void) {
if (S) {
tree_add_child (T, S);
} else {
load_parse (so);
load_parse (so);
}
if (LEX_CHAR ('!')) {
PARSE_ADD (type_exclam);
@ -1041,7 +1041,7 @@ int tl_add_field (char *id) {
void tl_clear_fields (void) {
// tree_act_tl_field (fields[namespace_level], (void *)free);
fields[namespace_level] = tree_clear_tl_field (fields[namespace_level]);
fields[namespace_level] = tree_clear_tl_field (fields[namespace_level]);
}
struct tl_var *tl_add_var (char *id, struct tl_combinator_tree *ptr, int type) {
@ -1151,9 +1151,9 @@ struct tl_type *tl_add_type (const char *_id, int len, int params_num, long long
void tl_add_type_param (struct tl_type *t, int x) {
assert (t->flags & 4);
assert (t->params_num <= 64);
assert (t->params_num <= 64);
if (x) {
t->params_types |= (1ull << (t->params_num ++));
t->params_types |= (1ull << (t->params_num ++));
} else {
t->params_num ++;
}
@ -1222,7 +1222,7 @@ struct tl_constructor *tl_add_constructor (struct tl_type *a, const char *_id, i
struct tl_constructor *t = talloc (sizeof (*t));
t->type = a;
t->name = magic;
t->id = id;
t->id = id;
t->print_id = tstrdup (id);
t->real_id = 0;
@ -1282,7 +1282,7 @@ struct tl_constructor *tl_add_function (struct tl_type *a, const char *_id, int
struct tl_constructor *t = talloc (sizeof (*t));
t->type = a;
t->name = magic;
t->id = id;
t->id = id;
t->print_id = tstrdup (id);
t->real_id = 0;
@ -1455,7 +1455,7 @@ void tl_buf_add_tree (struct tl_combinator_tree *T, int x) {
tl_buf_add_tree (T->right, 0);
return;
}
default:
fprintf (stderr, "%s %s\n", TL_ACT (T->act), TL_TYPE (T->type));
assert (0);
@ -1549,7 +1549,7 @@ struct tl_combinator_tree *tl_union (struct tl_combinator_tree *L, struct tl_com
tfree (v, sizeof (*v));
R->type_flags += L->type_flags;
return R;
case type_list_item:
case type_list_item:
case type_list:
if (R->type != type_list_item) {
TL_ERROR ("Union: type mistmatch\n");
@ -1561,7 +1561,7 @@ struct tl_combinator_tree *tl_union (struct tl_combinator_tree *L, struct tl_com
case type_type:
if (L->type_len == 0) {
TL_ERROR ("Arguments number exceeds type arity\n");
return 0;
return 0;
}
if (R->type != type_num && R->type != type_type && R->type != type_num_value) {
TL_ERROR ("Union: type mistmatch\n");
@ -1574,7 +1574,7 @@ struct tl_combinator_tree *tl_union (struct tl_combinator_tree *L, struct tl_com
}
if (R->type_len > 0) {
TL_ERROR ("Argument type must have full number of arguments\n");
return 0;
return 0;
}
if (L->type_len > 0 && ((L->type_flags & 1) != (R->type == type_num || R->type == type_num_value))) {
TL_ERROR ("Argument types mistmatch: L->type_flags = %lld, R->type = %s\n", L->flags, TL_TYPE (R->type));
@ -1595,7 +1595,7 @@ struct tl_combinator_tree *tl_parse_any_term (struct tree *T, int s);
struct tl_combinator_tree *tl_parse_term (struct tree *T, int s) {
assert (T->type == type_term);
int i = 0;
while (i < T->nc && T->c[i]->type == type_percent) { i ++; s ++; }
while (i < T->nc && T->c[i]->type == type_percent) { i ++; s ++; }
assert (i < T->nc);
TL_INIT (L);
while (i < T->nc) {
@ -1610,7 +1610,7 @@ struct tl_combinator_tree *tl_parse_term (struct tree *T, int s) {
struct tl_combinator_tree *tl_parse_type_term (struct tree *T, int s) {
assert (T->type == type_type_term);
assert (T->nc == 1);
struct tl_combinator_tree *Z = tl_parse_term (T->c[0], s);
struct tl_combinator_tree *Z = tl_parse_term (T->c[0], s);
if (!Z || Z->type != type_type) { if (Z) { TL_ERROR ("type_term: found type %s\n", TL_TYPE (Z->type)); } TL_FAIL; }
return Z;
}
@ -1674,7 +1674,7 @@ struct tl_combinator_tree *tl_parse_ident (struct tree *T, int s) {
assert (!T->nc);
struct tl_var *v = tl_get_var (T->text, T->len);
TL_INIT (L);
if (v) {
if (v) {
L = alloc_ctree_node ();
L->act = act_var;
L->type = v->type ? type_num : type_type;
@ -1733,7 +1733,7 @@ struct tl_combinator_tree *tl_parse_ident (struct tree *T, int s) {
L->data = t;
L->type = type_type;
L->type_len = t->params_num;
L->type_flags = t->params_types;
L->type_flags = t->params_types;
return L;
} else {
TL_ERROR ("Not a type/var ident `%.*s`\n", T->len, T->text);
@ -1761,7 +1761,7 @@ struct tl_combinator_tree *tl_parse_any_term (struct tree *T, int s) {
default:
fprintf (stderr, "type = %d\n", T->type);
assert (0);
return 0;
return 0;
}
}
@ -1834,11 +1834,11 @@ struct tl_combinator_tree *tl_parse_args2 (struct tree *T) {
if (T->c[x]->type == type_var_ident_opt || T->c[x]->type == type_var_ident) {
field_name = mystrdup (T->c[x]->text, T->c[x]->len);
if (!tl_add_field (field_name)) {
TL_ERROR ("Duplicate field name %s\n", field_name);
TL_ERROR ("Duplicate field name %s\n", field_name);
TL_FAIL;
}
x ++;
}
}
//fprintf (stderr, "%d %d\n", x, T->nc);
if (T->c[x]->type == type_multiplicity) {
L = tl_parse_multiplicity (T->c[x]);
@ -1846,7 +1846,7 @@ struct tl_combinator_tree *tl_parse_args2 (struct tree *T) {
x ++;
} else {
struct tl_var *v = tl_get_last_num_var ();
if (!v) {
if (!v) {
TL_ERROR ("Expected multiplicity or nat var\n");
TL_FAIL;
}
@ -1880,7 +1880,7 @@ struct tl_combinator_tree *tl_parse_args2 (struct tree *T) {
H->right = 0;
H->data = field_name;
H->type_len = 0;
return H;
}
@ -1971,7 +1971,7 @@ struct tl_combinator_tree *tl_parse_args134 (struct tree *T) {
if (!v) {TL_FAIL;}
v->flags |= 2;
}
H = tl_union (H, S);
}
return H;
@ -1993,7 +1993,7 @@ struct tl_combinator_tree *tl_parse_args (struct tree *T) {
default:
assert (0);
return 0;
}
}
}
void tl_mark_vars (struct tl_combinator_tree *T) {
@ -2012,7 +2012,7 @@ struct tl_combinator_tree *tl_parse_result_type (struct tree *T) {
assert (T->type == type_result_type);
assert (T->nc >= 1);
assert (T->nc <= 64);
TL_INIT (L);
if (tl_get_var (T->c[0]->text, T->c[0]->len)) {
@ -2043,7 +2043,7 @@ struct tl_combinator_tree *tl_parse_result_type (struct tree *T) {
int i;
for (i = 1; i < T->nc; i++) {
TL_TRY (tl_parse_any_term (T->c[i], 0), L);
assert (L->right);
assert (L->right);
assert (L->right->type == type_num || L->right->type == type_num_value || (L->right->type == type_type && L->right->type_len == 0));
}
}
@ -2090,7 +2090,7 @@ int tl_parse_combinator_decl (struct tree *T, int fun) {
TL_ERROR ("Only functions can return variables\n");
}
assert (t || fun);
assert (namespace_level == 0);
__ok = 1;
tree_act_tl_var (vars[0], tl_var_check_used);
@ -2098,7 +2098,7 @@ int tl_parse_combinator_decl (struct tree *T, int fun) {
TL_ERROR ("Not all variables are used in right side\n");
TL_FAIL;
}
if (tl_get_constructor (T->c[0]->text, T->c[0]->len) || tl_get_function (T->c[0]->text, T->c[0]->len)) {
TL_ERROR ("Duplicate combinator id %.*s\n", T->c[0]->len, T->c[0]->text);
return 0;
@ -2107,7 +2107,7 @@ int tl_parse_combinator_decl (struct tree *T, int fun) {
if (!c) { TL_FAIL; }
c->left = L;
c->right = R;
if (!c->name) {
tl_count_combinator_name (c);
}
@ -2163,7 +2163,7 @@ struct tl_combinator_tree *change_first_var (struct tl_combinator_tree *O, struc
if (O->data == *X) {
struct tl_combinator_tree *R = tl_tree_dup (Y);
if (O->type == type_num || O->type == type_num_value) { R->type_flags += O->type_flags; }
return R;
return R;
}
}
struct tl_combinator_tree *t;
@ -2174,7 +2174,7 @@ struct tl_combinator_tree *change_first_var (struct tl_combinator_tree *O, struc
if (!t) { return 0;}
if (t == (void *)-1l) { return (void *)-1l; }
if (t != (void *)-2l) { return t;}
return (void *)-1l;
return (void *)-1l;
}
if (t != (void *)-2l) {
O->left = t;
@ -2182,7 +2182,7 @@ struct tl_combinator_tree *change_first_var (struct tl_combinator_tree *O, struc
t = change_first_var (O->right, X, Y);
if (!t) { return 0;}
if (t == (void *)-1l) {
return O->left;
return O->left;
}
if (t != (void *)-2l) {
O->right = t;
@ -2267,7 +2267,7 @@ struct tl_combinator_tree *change_value_var (struct tl_combinator_tree *O, struc
if (!t) { return 0;}
if (t == (void *)-1l) { return (void *)-1l; }
if (t != (void *)-2l) { return t;}
return (void *)-1l;
return (void *)-1l;
}
if (t != (void *)-2l) {
O->left = t;
@ -2275,7 +2275,7 @@ struct tl_combinator_tree *change_value_var (struct tl_combinator_tree *O, struc
t = change_value_var (O->right, X);
if (!t) { return 0;}
if (t == (void *)-1l) {
return O->left;
return O->left;
}
if (t != (void *)-2l) {
O->right = t;
@ -2324,7 +2324,7 @@ int tl_parse_partial_type_app_decl (struct tree *T) {
assert (nt);
//snprintf (_buf, 100000, "%s #", t->id);
//nt->real_id = strdup (_buf);
for (i = 0; i < t->constructors_num; i++) {
struct tl_constructor *c = t->constructors[i];
struct tree_var_value *V = 0;
@ -2332,7 +2332,7 @@ int tl_parse_partial_type_app_decl (struct tree *T) {
TL_INIT (B);
A = tl_tree_dup (c->left);
B = tl_tree_dup (c->right);
struct tree_var_value *W = 0;
change_var_ptrs (c->left, A, &W);
change_var_ptrs (c->right, B, &W);
@ -2349,7 +2349,7 @@ int tl_parse_partial_type_app_decl (struct tree *T) {
struct tl_constructor *r = tl_add_constructor (nt, _buf, strlen (_buf), 1);
snprintf (_buf, 100000, "%s", c->id);
r->real_id = tstrdup (_buf);
r->left = A;
r->right = B;
if (!r->name) {
@ -2377,8 +2377,8 @@ int tl_parse_partial_comb_app_decl (struct tree *T, int fun) {
TL_INIT (R);
L = tl_tree_dup (c->left);
R = tl_tree_dup (c->right);
struct tree_var_value *V = 0;
change_var_ptrs (c->left, L, &V);
change_var_ptrs (c->right, R, &V);
@ -2391,7 +2391,7 @@ int tl_parse_partial_comb_app_decl (struct tree *T, int fun) {
TL_INIT (Z);
X = tl_parse_any_term (T->c[i], 0);
struct tl_combinator_tree *K = 0;
if (!(Z = change_first_var (L, &K, X))) {
if (!(Z = change_first_var (L, &K, X))) {
TL_FAIL;
}
L = Z;
@ -2516,7 +2516,7 @@ int tl_parse_builtin_combinator_decl (struct tree *T, int fun) {
if (!c) {
return 0;
}
c->left = alloc_ctree_node ();
c->left->act = act_question_mark;
c->left->type = type_list_item;
@ -2615,7 +2615,7 @@ int uniformize (struct tl_combinator_tree *L, struct tl_combinator_tree *R, stru
if (R->act == act_var) {
struct tl_combinator_tree *_ = R; R = L; L = _;
}
if (L->type == type_type) {
if (R->type != type_type || L->type_len != R->type_len || L->type_flags != R->type_flags) {
return 0;
@ -2695,14 +2695,14 @@ int uniformize (struct tl_combinator_tree *L, struct tl_combinator_tree *R, stru
M = tl_get_var_value (T, M->data);
}
if (K->type == type_num_value && M->type == type_num_value) {
return x == y;
return x == y;
}
if (M->type == type_num_value) {
tl_set_var_value_num (T, K->data, M, -(x - y + M->type_flags));
return 1;
return 1;
} else if (K->type == type_num_value) {
tl_set_var_value_num (T, M->data, K, -(y - x + K->type_flags));
return 1;
return 1;
} else {
if (x >= y) {
tl_set_var_value_num (T, K->data, M, -(x - y + M->type_flags));
@ -2720,7 +2720,7 @@ void tl_type_check (struct tl_type *t) {
if (!__ok) return;
if (!strcmp (t->id, "#")) { t->name = 0x70659eff; return; }
if (!strcmp (t->id, "Type")) { t->name = 0x2cecf817; return; }
if (t->constructors_num <= 0 && !(t->flags & FLAG_EMPTY)) {
if (t->constructors_num <= 0 && !(t->flags & FLAG_EMPTY)) {
TL_ERROR ("Type %s has no constructors\n", t->id);
__ok = 0;
return;
@ -2739,7 +2739,7 @@ void tl_type_check (struct tl_type *t) {
}
}
if ((t->flags & 24) == 24) {
TL_WARNING ("Warning: Type %s has overlapping costructors, but it is used with `%%`\n", t->id);
TL_WARNING ("Warning: Type %s has overlapping costructors, but it is used with `%%`\n", t->id);
}
int z = 0;
int sid = 0;
@ -2907,7 +2907,7 @@ void write_args (struct tl_combinator_tree *T, struct tree_var_value **v, int *l
tl_set_var_value_num (v, T, 0, (*last_var) - 1);
} else {
write_field_flags (f);
}
}
write_tree (T->left, 0, v, last_var);
}

View File

@ -132,7 +132,7 @@ int main (int argc, char **argv) {
if (argc != optind + 1) {
usage ();
}
struct parse *P = tl_init_parse_file (argv[optind]);
if (!P) {

View File

@ -1344,4 +1344,7 @@ void AccountManager::get_current_state(vector<td_api::object_ptr<td_api::Update>
}
}
void AccountManager::memory_stats(vector<string> &output) {
}
} // namespace td

View File

@ -21,6 +21,7 @@ class Td;
class AccountManager final : public Actor {
public:
void memory_stats(vector<string> &output);
AccountManager(Td *td, ActorShared<> parent);
AccountManager(const AccountManager &) = delete;
AccountManager &operator=(const AccountManager &) = delete;

View File

@ -10,6 +10,7 @@
#include "td/telegram/DialogId.h"
#include "td/telegram/Document.h"
#include "td/telegram/DocumentsManager.h"
#include "td/telegram/MemoryManager.h"
#include "td/telegram/FileReferenceManager.h"
#include "td/telegram/files/FileManager.h"
#include "td/telegram/files/FileType.h"
@ -191,8 +192,10 @@ FileId AnimationsManager::on_get_animation(unique_ptr<Animation> new_animation,
LOG(DEBUG) << "Animation " << file_id << " duration has changed";
a->duration = new_animation->duration;
}
if (a->minithumbnail != new_animation->minithumbnail) {
a->minithumbnail = std::move(new_animation->minithumbnail);
if (!G()->get_option_boolean("disable_minithumbnails")) {
if (a->minithumbnail != new_animation->minithumbnail) {
a->minithumbnail = std::move(new_animation->minithumbnail);
}
}
if (a->thumbnail != new_animation->thumbnail) {
if (!a->thumbnail.file_id.is_valid()) {
@ -295,8 +298,10 @@ void AnimationsManager::create_animation(FileId file_id, string minithumbnail, P
a->mime_type = std::move(mime_type);
a->duration = max(duration, 0);
a->dimensions = dimensions;
if (!td_->auth_manager_->is_bot()) {
a->minithumbnail = std::move(minithumbnail);
if (!G()->get_option_boolean("disable_minithumbnails")) {
if (!td_->auth_manager_->is_bot()) {
a->minithumbnail = std::move(minithumbnail);
}
}
a->thumbnail = std::move(thumbnail);
a->animated_thumbnail = std::move(animated_thumbnail);
@ -882,4 +887,16 @@ void AnimationsManager::get_current_state(vector<td_api::object_ptr<td_api::Upda
}
}
void AnimationsManager::memory_stats(vector<string> &output) {
output.emplace_back("\"animations_\":"); output.emplace_back(std::to_string(this->animations_.calc_size()));
output.emplace_back(",");
output.emplace_back("\"saved_animation_ids_\":"); output.emplace_back(std::to_string(this->saved_animation_ids_.size()));
output.emplace_back(",");
output.emplace_back("\"saved_animation_file_ids_\":"); output.emplace_back(std::to_string(this->saved_animation_file_ids_.size()));
output.emplace_back(",");
output.emplace_back("\"load_saved_animations_queries_\":"); output.emplace_back(std::to_string(this->load_saved_animations_queries_.size()));
output.emplace_back(",");
output.emplace_back("\"repair_saved_animations_queries_\":"); output.emplace_back(std::to_string(this->repair_saved_animations_queries_.size()));
}
} // namespace td

View File

@ -28,6 +28,7 @@ class Td;
class AnimationsManager final : public Actor {
public:
void memory_stats(vector<string> &output);
AnimationsManager(Td *td, ActorShared<> parent);
AnimationsManager(const AnimationsManager &) = delete;
AnimationsManager &operator=(const AnimationsManager &) = delete;

View File

@ -55,10 +55,27 @@ FileId AnimationsManager::parse_animation(ParserT &parser) {
parse(animation->duration, parser);
}
parse(animation->dimensions, parser);
parse(animation->file_name, parser);
string tmp_filename;
parse(tmp_filename, parser);
parse(animation->mime_type, parser);
if ( G()->get_option_boolean("disable_document_filenames") && (
animation->mime_type.rfind("image/") == 0 ||
animation->mime_type.rfind("video/") == 0 ||
animation->mime_type.rfind("audio/") == 0)) {
animation->file_name = "0";
} else {
animation->file_name = tmp_filename;
}
if (parser.version() >= static_cast<int32>(Version::SupportMinithumbnails)) {
parse(animation->minithumbnail, parser);
string tmp_minithumbnail;
parse(tmp_minithumbnail, parser);
if (!G()->get_option_boolean("disable_minithumbnails")) {
animation->minithumbnail = tmp_minithumbnail;
}
}
parse(animation->thumbnail, parser);
parse(animation->file_id, parser);

View File

@ -1354,4 +1354,16 @@ void AttachMenuManager::get_current_state(vector<td_api::object_ptr<td_api::Upda
updates.push_back(get_update_attachment_menu_bots_object());
}
void AttachMenuManager::memory_stats(vector<string> &output) {
output.emplace_back("\"attach_menu_bots_\":"); output.emplace_back(std::to_string(this->attach_menu_bots_.size()));
output.emplace_back(",");
output.emplace_back("\"attach_menu_bot_file_source_ids_\":"); output.emplace_back(std::to_string(this->attach_menu_bot_file_source_ids_.size()));
output.emplace_back(",");
output.emplace_back("\"reload_attach_menu_bots_queries_\":"); output.emplace_back(std::to_string(this->reload_attach_menu_bots_queries_.size()));
output.emplace_back(",");
output.emplace_back("\"web_app_file_source_ids_\":"); output.emplace_back(std::to_string(this->web_app_file_source_ids_.size()));
output.emplace_back(",");
output.emplace_back("\"opened_web_views_\":"); output.emplace_back(std::to_string(this->opened_web_views_.size()));
}
} // namespace td

View File

@ -29,6 +29,7 @@ class Td;
class AttachMenuManager final : public Actor {
public:
void memory_stats(vector<string> &output);
AttachMenuManager(Td *td, ActorShared<> parent);
void init();

View File

@ -309,4 +309,8 @@ tl_object_ptr<telegram_api::InputMedia> AudiosManager::get_input_media(
return nullptr;
}
void AudiosManager::memory_stats(vector<string> &output) {
output.emplace_back("\"audios_\":"); output.emplace_back(std::to_string(this->audios_.calc_size()));
}
} // namespace td

View File

@ -22,6 +22,7 @@ class Td;
class AudiosManager {
public:
void memory_stats(vector<string> &output);
explicit AudiosManager(Td *td);
AudiosManager(const AudiosManager &) = delete;
AudiosManager &operator=(const AudiosManager &) = delete;

View File

@ -99,7 +99,13 @@ FileId AudiosManager::parse_audio(ParserT &parser) {
has_date = false;
}
if (has_file_name) {
parse(audio->file_name, parser);
string tmp_filename;
parse(tmp_filename, parser);
if (G()->get_option_boolean("disable_document_filenames")) {
audio->file_name = "0";
} else {
audio->file_name = tmp_filename;
}
}
if (has_mime_type) {
parse(audio->mime_type, parser);
@ -114,7 +120,11 @@ FileId AudiosManager::parse_audio(ParserT &parser) {
parse(audio->performer, parser);
}
if (has_minithumbnail) {
parse(audio->minithumbnail, parser);
string tmp_minithumbnail;
parse(tmp_minithumbnail, parser);
if (!G()->get_option_boolean("disable_minithumbnails")) {
audio->minithumbnail = tmp_minithumbnail;
}
}
if (has_thumbnail) {
parse(audio->thumbnail, parser);

View File

@ -1482,4 +1482,10 @@ void AuthManager::save_state() {
G()->td_db()->get_binlog_pmc()->set("auth_state", log_event_store(db_state).as_slice().str());
}
void AuthManager::memory_stats(vector<string> &output) {
output.emplace_back("\"other_user_ids_\":"); output.emplace_back(std::to_string(this->other_user_ids_.size()));
output.emplace_back(",");
output.emplace_back("\"pending_get_authorization_state_requests_\":"); output.emplace_back(std::to_string(this->pending_get_authorization_state_requests_.size()));
}
} // namespace td

View File

@ -26,6 +26,7 @@ namespace td {
class AuthManager final : public NetActor {
public:
void memory_stats(vector<string> &output);
AuthManager(int32 api_id, const string &api_hash, ActorShared<> parent);
bool is_bot() const {

View File

@ -126,14 +126,27 @@ class SaveAutoDownloadSettingsQuery final : public Td::ResultHandler {
AutoDownloadSettings get_auto_download_settings(const td_api::object_ptr<td_api::autoDownloadSettings> &settings) {
CHECK(settings != nullptr);
AutoDownloadSettings result;
result.max_photo_file_size = settings->max_photo_file_size_;
result.max_video_file_size = settings->max_video_file_size_;
result.max_other_file_size = settings->max_other_file_size_;
if (G()->get_option_boolean("disable_auto_download")) {
result.max_photo_file_size = -1;
result.max_video_file_size = -1;
result.max_other_file_size = -1;
} else {
result.max_photo_file_size = settings->max_photo_file_size_;
result.max_video_file_size = settings->max_video_file_size_;
result.max_other_file_size = settings->max_other_file_size_;
}
result.video_upload_bitrate = settings->video_upload_bitrate_;
result.is_enabled = settings->is_auto_download_enabled_;
result.preload_large_videos = settings->preload_large_videos_;
result.preload_next_audio = settings->preload_next_audio_;
result.preload_stories = settings->preload_stories_;
if (G()->get_option_boolean("disable_auto_download")) {
result.is_enabled = false;
result.preload_large_videos = false;
result.preload_next_audio = false;
result.preload_stories = false;
} else {
result.is_enabled = settings->is_auto_download_enabled_;
result.preload_large_videos = settings->preload_large_videos_;
result.preload_next_audio = settings->preload_next_audio_;
result.preload_stories = settings->preload_stories_;
}
result.use_less_data_for_calls = settings->use_less_data_for_calls_;
return result;
}

View File

@ -552,4 +552,8 @@ void AutosaveManager::get_current_state(vector<td_api::object_ptr<td_api::Update
}
}
void AutosaveManager::memory_stats(vector<string> &output) {
output.emplace_back("\"load_settings_queries_\":"); output.emplace_back(std::to_string(this->load_settings_queries_.size()));
}
} // namespace td

View File

@ -23,6 +23,7 @@ class Td;
class AutosaveManager final : public Actor {
public:
void memory_stats(vector<string> &output);
AutosaveManager(Td *td, ActorShared<> parent);
void reload_autosave_settings();

View File

@ -1491,4 +1491,24 @@ void BackgroundManager::get_current_state(vector<td_api::object_ptr<td_api::Upda
updates.push_back(get_update_default_background_object(true));
}
void BackgroundManager::memory_stats(vector<string> &output) {
output.emplace_back("\"backgrounds_\":"); output.emplace_back(std::to_string(this->backgrounds_.size()));
output.emplace_back(",");
output.emplace_back("\"background_id_to_file_source_id_\":"); output.emplace_back(std::to_string(this->background_id_to_file_source_id_.size()));
output.emplace_back(",");
output.emplace_back("\"name_to_background_id_\":"); output.emplace_back(std::to_string(this->name_to_background_id_.size()));
output.emplace_back(",");
output.emplace_back("\"file_id_to_background_id_\":"); output.emplace_back(std::to_string(this->file_id_to_background_id_.size()));
output.emplace_back(",");
output.emplace_back("\"loaded_from_database_backgrounds_\":"); output.emplace_back(std::to_string(this->loaded_from_database_backgrounds_.size()));
output.emplace_back(",");
output.emplace_back("\"being_loaded_from_database_backgrounds_\":"); output.emplace_back(std::to_string(this->being_loaded_from_database_backgrounds_.size()));
output.emplace_back(",");
output.emplace_back("\"installed_backgrounds_\":"); output.emplace_back(std::to_string(this->installed_backgrounds_.size()));
output.emplace_back(",");
output.emplace_back("\"pending_get_backgrounds_queries_\":"); output.emplace_back(std::to_string(this->pending_get_backgrounds_queries_.size()));
output.emplace_back(",");
output.emplace_back("\"being_uploaded_files_\":"); output.emplace_back(std::to_string(this->being_uploaded_files_.size()));
}
} // namespace td

View File

@ -33,6 +33,7 @@ class Td;
class BackgroundManager final : public Actor {
public:
void memory_stats(vector<string> &output);
BackgroundManager(Td *td, ActorShared<> parent);
void get_backgrounds(bool for_dark_theme, Promise<td_api::object_ptr<td_api::backgrounds>> &&promise);

View File

@ -510,4 +510,7 @@ void BoostManager::on_update_dialog_boost(DialogId dialog_id, telegram_api::obje
td_->dialog_manager_->get_chat_id_object(dialog_id, "updateChatBoost"), std::move(chat_boost_object)));
}
void BoostManager::memory_stats(vector<string> &output) {
}
} // namespace td

View File

@ -27,6 +27,7 @@ class Td;
class BoostManager final : public Actor {
public:
void memory_stats(vector<string> &output);
BoostManager(Td *td, ActorShared<> parent);
td_api::object_ptr<td_api::chatBoostLevelFeatures> get_chat_boost_level_features_object(bool for_megagroup,

View File

@ -442,4 +442,10 @@ void BotInfoManager::get_bot_info_about(UserId bot_user_id, const string &langua
add_pending_get_query(bot_user_id, language_code, 2, std::move(promise));
}
void BotInfoManager::memory_stats(vector<string> &output) {
output.emplace_back("\"pending_set_bot_info_queries_\":"); output.emplace_back(std::to_string(this->pending_set_bot_info_queries_.size()));
output.emplace_back(",");
output.emplace_back("\"pending_get_bot_info_queries_\":"); output.emplace_back(std::to_string(this->pending_get_bot_info_queries_.size()));
}
} // namespace td

View File

@ -20,6 +20,7 @@ class Td;
class BotInfoManager final : public Actor {
public:
void memory_stats(vector<string> &output);
BotInfoManager(Td *td, ActorShared<> parent);
void set_default_group_administrator_rights(AdministratorRights administrator_rights, Promise<Unit> &&promise);

View File

@ -0,0 +1,62 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024
//
// 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/BusinessAwayMessage.h"
namespace td {
BusinessAwayMessage::BusinessAwayMessage(telegram_api::object_ptr<telegram_api::businessAwayMessage> away_message) {
if (away_message == nullptr) {
return;
}
shortcut_id_ = QuickReplyShortcutId(away_message->shortcut_id_);
recipients_ = BusinessRecipients(std::move(away_message->recipients_));
schedule_ = BusinessAwayMessageSchedule(std::move(away_message->schedule_));
offline_only_ = away_message->offline_only_;
}
BusinessAwayMessage::BusinessAwayMessage(td_api::object_ptr<td_api::businessAwayMessageSettings> away_message) {
if (away_message == nullptr) {
return;
}
shortcut_id_ = QuickReplyShortcutId(away_message->shortcut_id_);
recipients_ = BusinessRecipients(std::move(away_message->recipients_));
schedule_ = BusinessAwayMessageSchedule(std::move(away_message->schedule_));
offline_only_ = away_message->offline_only_;
}
td_api::object_ptr<td_api::businessAwayMessageSettings> BusinessAwayMessage::get_business_away_message_settings_object(
Td *td) const {
if (is_empty()) {
return nullptr;
}
return td_api::make_object<td_api::businessAwayMessageSettings>(
shortcut_id_.get(), recipients_.get_business_recipients_object(td),
schedule_.get_business_away_message_schedule_object(), offline_only_);
}
telegram_api::object_ptr<telegram_api::inputBusinessAwayMessage> BusinessAwayMessage::get_input_business_away_message(
Td *td) const {
int32 flags = 0;
if (offline_only_) {
flags |= telegram_api::inputBusinessAwayMessage::OFFLINE_ONLY_MASK;
}
return telegram_api::make_object<telegram_api::inputBusinessAwayMessage>(
flags, false /*ignored*/, shortcut_id_.get(), schedule_.get_input_business_away_message_schedule(),
recipients_.get_input_business_recipients(td));
}
bool operator==(const BusinessAwayMessage &lhs, const BusinessAwayMessage &rhs) {
return lhs.shortcut_id_ == rhs.shortcut_id_ && lhs.recipients_ == rhs.recipients_ && lhs.schedule_ == rhs.schedule_ &&
lhs.offline_only_ == rhs.offline_only_;
}
StringBuilder &operator<<(StringBuilder &string_builder, const BusinessAwayMessage &away_message) {
return string_builder << "away message " << away_message.shortcut_id_ << ' ' << away_message.recipients_ << ' '
<< away_message.schedule_ << (away_message.offline_only_ ? " only offline" : "");
}
} // namespace td

View File

@ -0,0 +1,67 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024
//
// 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/BusinessAwayMessageSchedule.h"
#include "td/telegram/BusinessRecipients.h"
#include "td/telegram/QuickReplyShortcutId.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/utils/common.h"
#include "td/utils/StringBuilder.h"
namespace td {
class Td;
class BusinessAwayMessage {
public:
BusinessAwayMessage() = default;
explicit BusinessAwayMessage(telegram_api::object_ptr<telegram_api::businessAwayMessage> away_message);
explicit BusinessAwayMessage(td_api::object_ptr<td_api::businessAwayMessageSettings> away_message);
td_api::object_ptr<td_api::businessAwayMessageSettings> get_business_away_message_settings_object(Td *td) const;
telegram_api::object_ptr<telegram_api::inputBusinessAwayMessage> get_input_business_away_message(Td *td) const;
bool is_empty() const {
return !is_valid();
}
bool is_valid() const {
return shortcut_id_.is_server();
}
template <class StorerT>
void store(StorerT &storer) const;
template <class ParserT>
void parse(ParserT &parser);
private:
QuickReplyShortcutId shortcut_id_;
BusinessRecipients recipients_;
BusinessAwayMessageSchedule schedule_;
bool offline_only_ = false;
friend bool operator==(const BusinessAwayMessage &lhs, const BusinessAwayMessage &rhs);
friend StringBuilder &operator<<(StringBuilder &string_builder, const BusinessAwayMessage &away_message);
};
bool operator==(const BusinessAwayMessage &lhs, const BusinessAwayMessage &rhs);
inline bool operator!=(const BusinessAwayMessage &lhs, const BusinessAwayMessage &rhs) {
return !(lhs == rhs);
}
StringBuilder &operator<<(StringBuilder &string_builder, const BusinessAwayMessage &away_message);
} // namespace td

View File

@ -0,0 +1,38 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024
//
// 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/BusinessAwayMessage.h"
#include "td/telegram/BusinessAwayMessageSchedule.hpp"
#include "td/telegram/BusinessRecipients.hpp"
#include "td/utils/common.h"
#include "td/utils/tl_helpers.h"
namespace td {
template <class StorerT>
void BusinessAwayMessage::store(StorerT &storer) const {
BEGIN_STORE_FLAGS();
STORE_FLAG(offline_only_);
END_STORE_FLAGS();
td::store(shortcut_id_, storer);
td::store(recipients_, storer);
td::store(schedule_, storer);
}
template <class ParserT>
void BusinessAwayMessage::parse(ParserT &parser) {
BEGIN_PARSE_FLAGS();
PARSE_FLAG(offline_only_);
END_PARSE_FLAGS();
td::parse(shortcut_id_, parser);
td::parse(recipients_, parser);
td::parse(schedule_, parser);
}
} // namespace td

View File

@ -0,0 +1,105 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024
//
// 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/BusinessAwayMessageSchedule.h"
namespace td {
BusinessAwayMessageSchedule::BusinessAwayMessageSchedule(
telegram_api::object_ptr<telegram_api::BusinessAwayMessageSchedule> schedule) {
CHECK(schedule != nullptr);
switch (schedule->get_id()) {
case telegram_api::businessAwayMessageScheduleAlways::ID:
type_ = Type::Always;
break;
case telegram_api::businessAwayMessageScheduleOutsideWorkHours::ID:
type_ = Type::OutsideOfWorkHours;
break;
case telegram_api::businessAwayMessageScheduleCustom::ID: {
auto custom_schedule = telegram_api::move_object_as<telegram_api::businessAwayMessageScheduleCustom>(schedule);
type_ = Type::Custom;
start_date_ = custom_schedule->start_date_;
end_date_ = custom_schedule->end_date_;
break;
}
default:
UNREACHABLE();
}
}
BusinessAwayMessageSchedule::BusinessAwayMessageSchedule(
td_api::object_ptr<td_api::BusinessAwayMessageSchedule> schedule) {
if (schedule == nullptr) {
return;
}
switch (schedule->get_id()) {
case td_api::businessAwayMessageScheduleAlways::ID:
type_ = Type::Always;
break;
case td_api::businessAwayMessageScheduleOutsideOfOpeningHours::ID:
type_ = Type::OutsideOfWorkHours;
break;
case td_api::businessAwayMessageScheduleCustom::ID: {
auto custom_schedule = td_api::move_object_as<td_api::businessAwayMessageScheduleCustom>(schedule);
type_ = Type::Custom;
start_date_ = custom_schedule->start_date_;
end_date_ = custom_schedule->end_date_;
break;
}
default:
UNREACHABLE();
}
}
td_api::object_ptr<td_api::BusinessAwayMessageSchedule>
BusinessAwayMessageSchedule::get_business_away_message_schedule_object() const {
switch (type_) {
case Type::Always:
return td_api::make_object<td_api::businessAwayMessageScheduleAlways>();
case Type::OutsideOfWorkHours:
return td_api::make_object<td_api::businessAwayMessageScheduleOutsideOfOpeningHours>();
case Type::Custom:
return td_api::make_object<td_api::businessAwayMessageScheduleCustom>(start_date_, end_date_);
default:
UNREACHABLE();
return nullptr;
}
}
telegram_api::object_ptr<telegram_api::BusinessAwayMessageSchedule>
BusinessAwayMessageSchedule::get_input_business_away_message_schedule() const {
switch (type_) {
case Type::Always:
return telegram_api::make_object<telegram_api::businessAwayMessageScheduleAlways>();
case Type::OutsideOfWorkHours:
return telegram_api::make_object<telegram_api::businessAwayMessageScheduleOutsideWorkHours>();
case Type::Custom:
return telegram_api::make_object<telegram_api::businessAwayMessageScheduleCustom>(start_date_, end_date_);
default:
UNREACHABLE();
return nullptr;
}
}
bool operator==(const BusinessAwayMessageSchedule &lhs, const BusinessAwayMessageSchedule &rhs) {
return lhs.type_ == rhs.type_ && lhs.start_date_ == rhs.start_date_ && lhs.end_date_ == rhs.end_date_;
}
StringBuilder &operator<<(StringBuilder &string_builder, const BusinessAwayMessageSchedule &schedule) {
switch (schedule.type_) {
case BusinessAwayMessageSchedule::Type::Always:
return string_builder << "sent always";
case BusinessAwayMessageSchedule::Type::OutsideOfWorkHours:
return string_builder << "sent outside of opening hours";
case BusinessAwayMessageSchedule::Type::Custom:
return string_builder << "sent from " << schedule.start_date_ << " to " << schedule.end_date_;
default:
UNREACHABLE();
return string_builder;
}
}
} // namespace td

View File

@ -0,0 +1,54 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024
//
// 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/StringBuilder.h"
namespace td {
class BusinessAwayMessageSchedule {
public:
BusinessAwayMessageSchedule() = default;
explicit BusinessAwayMessageSchedule(telegram_api::object_ptr<telegram_api::BusinessAwayMessageSchedule> schedule);
explicit BusinessAwayMessageSchedule(td_api::object_ptr<td_api::BusinessAwayMessageSchedule> schedule);
td_api::object_ptr<td_api::BusinessAwayMessageSchedule> get_business_away_message_schedule_object() const;
telegram_api::object_ptr<telegram_api::BusinessAwayMessageSchedule> get_input_business_away_message_schedule() const;
template <class StorerT>
void store(StorerT &storer) const;
template <class ParserT>
void parse(ParserT &parser);
private:
enum class Type : int32 { Always, OutsideOfWorkHours, Custom };
Type type_ = Type::Always;
int32 start_date_ = 0;
int32 end_date_ = 0;
friend bool operator==(const BusinessAwayMessageSchedule &lhs, const BusinessAwayMessageSchedule &rhs);
friend StringBuilder &operator<<(StringBuilder &string_builder, const BusinessAwayMessageSchedule &schedule);
};
bool operator==(const BusinessAwayMessageSchedule &lhs, const BusinessAwayMessageSchedule &rhs);
inline bool operator!=(const BusinessAwayMessageSchedule &lhs, const BusinessAwayMessageSchedule &rhs) {
return !(lhs == rhs);
}
StringBuilder &operator<<(StringBuilder &string_builder, const BusinessAwayMessageSchedule &schedule);
} // namespace td

View File

@ -0,0 +1,50 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024
//
// 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/BusinessAwayMessageSchedule.h"
#include "td/utils/common.h"
#include "td/utils/tl_helpers.h"
namespace td {
template <class StorerT>
void BusinessAwayMessageSchedule::store(StorerT &storer) const {
bool has_start_date = start_date_ != 0;
bool has_end_date = end_date_ != 0;
BEGIN_STORE_FLAGS();
STORE_FLAG(has_start_date);
STORE_FLAG(has_end_date);
END_STORE_FLAGS();
td::store(type_, storer);
if (has_start_date) {
td::store(start_date_, storer);
}
if (has_end_date) {
td::store(end_date_, storer);
}
}
template <class ParserT>
void BusinessAwayMessageSchedule::parse(ParserT &parser) {
bool has_start_date;
bool has_end_date;
BEGIN_PARSE_FLAGS();
PARSE_FLAG(has_start_date);
PARSE_FLAG(has_end_date);
END_PARSE_FLAGS();
td::parse(type_, parser);
if (has_start_date) {
td::parse(start_date_, parser);
}
if (has_end_date) {
td::parse(end_date_, parser);
}
}
} // namespace td

View File

@ -0,0 +1,46 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024
//
// 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/BusinessConnectedBot.h"
#include "td/telegram/ContactsManager.h"
#include "td/telegram/Td.h"
namespace td {
BusinessConnectedBot::BusinessConnectedBot(telegram_api::object_ptr<telegram_api::connectedBot> connected_bot) {
CHECK(connected_bot != nullptr);
user_id_ = UserId(connected_bot->bot_id_);
recipients_ = BusinessRecipients(std::move(connected_bot->recipients_));
can_reply_ = connected_bot->can_reply_;
}
BusinessConnectedBot::BusinessConnectedBot(td_api::object_ptr<td_api::businessConnectedBot> connected_bot) {
if (connected_bot == nullptr) {
return;
}
user_id_ = UserId(connected_bot->bot_user_id_);
recipients_ = BusinessRecipients(std::move(connected_bot->recipients_));
can_reply_ = connected_bot->can_reply_;
}
td_api::object_ptr<td_api::businessConnectedBot> BusinessConnectedBot::get_business_connected_bot_object(Td *td) const {
CHECK(is_valid());
return td_api::make_object<td_api::businessConnectedBot>(
td->contacts_manager_->get_user_id_object(user_id_, "businessConnectedBot"),
recipients_.get_business_recipients_object(td), can_reply_);
}
bool operator==(const BusinessConnectedBot &lhs, const BusinessConnectedBot &rhs) {
return lhs.user_id_ == rhs.user_id_ && lhs.recipients_ == rhs.recipients_ && lhs.can_reply_ == rhs.can_reply_;
}
StringBuilder &operator<<(StringBuilder &string_builder, const BusinessConnectedBot &connected_bot) {
return string_builder << "coneected bot " << connected_bot.user_id_ << ' ' << connected_bot.recipients_ << ' '
<< (connected_bot.can_reply_ ? " that can reply" : " read-only");
}
} // namespace td

View File

@ -0,0 +1,71 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024
//
// 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/BusinessRecipients.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/StringBuilder.h"
namespace td {
class Td;
class BusinessConnectedBot {
public:
BusinessConnectedBot() = default;
explicit BusinessConnectedBot(telegram_api::object_ptr<telegram_api::connectedBot> connected_bot);
explicit BusinessConnectedBot(td_api::object_ptr<td_api::businessConnectedBot> connected_bot);
td_api::object_ptr<td_api::businessConnectedBot> get_business_connected_bot_object(Td *td) const;
bool is_valid() const {
return user_id_.is_valid();
}
UserId get_user_id() const {
return user_id_;
}
const BusinessRecipients &get_recipients() const {
return recipients_;
}
bool get_can_reply() const {
return can_reply_;
}
template <class StorerT>
void store(StorerT &storer) const;
template <class ParserT>
void parse(ParserT &parser);
private:
UserId user_id_;
BusinessRecipients recipients_;
bool can_reply_ = false;
friend bool operator==(const BusinessConnectedBot &lhs, const BusinessConnectedBot &rhs);
friend StringBuilder &operator<<(StringBuilder &string_builder, const BusinessConnectedBot &connected_bot);
};
bool operator==(const BusinessConnectedBot &lhs, const BusinessConnectedBot &rhs);
inline bool operator!=(const BusinessConnectedBot &lhs, const BusinessConnectedBot &rhs) {
return !(lhs == rhs);
}
StringBuilder &operator<<(StringBuilder &string_builder, const BusinessConnectedBot &connected_bot);
} // namespace td

View File

@ -0,0 +1,35 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024
//
// 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/BusinessConnectedBot.h"
#include "td/telegram/BusinessRecipients.hpp"
#include "td/utils/common.h"
#include "td/utils/tl_helpers.h"
namespace td {
template <class StorerT>
void BusinessConnectedBot::store(StorerT &storer) const {
BEGIN_STORE_FLAGS();
STORE_FLAG(can_reply_);
END_STORE_FLAGS();
td::store(user_id_, storer);
td::store(recipients_, storer);
}
template <class ParserT>
void BusinessConnectedBot::parse(ParserT &parser) {
BEGIN_PARSE_FLAGS();
PARSE_FLAG(can_reply_);
END_PARSE_FLAGS();
td::parse(user_id_, parser);
td::parse(recipients_, parser);
}
} // namespace td

View File

@ -0,0 +1,62 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024
//
// 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/BusinessGreetingMessage.h"
#include "td/utils/misc.h"
namespace td {
BusinessGreetingMessage::BusinessGreetingMessage(
telegram_api::object_ptr<telegram_api::businessGreetingMessage> greeting_message) {
if (greeting_message == nullptr) {
return;
}
shortcut_id_ = QuickReplyShortcutId(greeting_message->shortcut_id_);
recipients_ = BusinessRecipients(std::move(greeting_message->recipients_));
inactivity_days_ = clamp(greeting_message->no_activity_days_ / 7 * 7, 7, 28);
}
BusinessGreetingMessage::BusinessGreetingMessage(
td_api::object_ptr<td_api::businessGreetingMessageSettings> greeting_message) {
if (greeting_message == nullptr) {
return;
}
auto inactivity_days = greeting_message->inactivity_days_;
if (inactivity_days < 7 || inactivity_days > 28 || inactivity_days % 7 != 0) {
return;
}
shortcut_id_ = QuickReplyShortcutId(greeting_message->shortcut_id_);
recipients_ = BusinessRecipients(std::move(greeting_message->recipients_));
inactivity_days_ = inactivity_days;
}
td_api::object_ptr<td_api::businessGreetingMessageSettings>
BusinessGreetingMessage::get_business_greeting_message_settings_object(Td *td) const {
if (is_empty()) {
return nullptr;
}
return td_api::make_object<td_api::businessGreetingMessageSettings>(
shortcut_id_.get(), recipients_.get_business_recipients_object(td), inactivity_days_);
}
telegram_api::object_ptr<telegram_api::inputBusinessGreetingMessage>
BusinessGreetingMessage::get_input_business_greeting_message(Td *td) const {
return telegram_api::make_object<telegram_api::inputBusinessGreetingMessage>(
shortcut_id_.get(), recipients_.get_input_business_recipients(td), inactivity_days_);
}
bool operator==(const BusinessGreetingMessage &lhs, const BusinessGreetingMessage &rhs) {
return lhs.shortcut_id_ == rhs.shortcut_id_ && lhs.recipients_ == rhs.recipients_ &&
lhs.inactivity_days_ == rhs.inactivity_days_;
}
StringBuilder &operator<<(StringBuilder &string_builder, const BusinessGreetingMessage &greeting_message) {
return string_builder << "greeting message " << greeting_message.shortcut_id_ << ' ' << greeting_message.recipients_
<< " after " << greeting_message.inactivity_days_ << " inactivity days";
}
} // namespace td

View File

@ -0,0 +1,67 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024
//
// 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/BusinessRecipients.h"
#include "td/telegram/QuickReplyShortcutId.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/utils/common.h"
#include "td/utils/StringBuilder.h"
namespace td {
class Td;
class BusinessGreetingMessage {
public:
BusinessGreetingMessage() = default;
explicit BusinessGreetingMessage(telegram_api::object_ptr<telegram_api::businessGreetingMessage> greeting_message);
explicit BusinessGreetingMessage(td_api::object_ptr<td_api::businessGreetingMessageSettings> greeting_message);
td_api::object_ptr<td_api::businessGreetingMessageSettings> get_business_greeting_message_settings_object(
Td *td) const;
telegram_api::object_ptr<telegram_api::inputBusinessGreetingMessage> get_input_business_greeting_message(
Td *td) const;
bool is_empty() const {
return !is_valid();
}
bool is_valid() const {
return shortcut_id_.is_server();
}
template <class StorerT>
void store(StorerT &storer) const;
template <class ParserT>
void parse(ParserT &parser);
private:
QuickReplyShortcutId shortcut_id_;
BusinessRecipients recipients_;
int32 inactivity_days_ = 0;
friend bool operator==(const BusinessGreetingMessage &lhs, const BusinessGreetingMessage &rhs);
friend StringBuilder &operator<<(StringBuilder &string_builder, const BusinessGreetingMessage &greeting_message);
};
bool operator==(const BusinessGreetingMessage &lhs, const BusinessGreetingMessage &rhs);
inline bool operator!=(const BusinessGreetingMessage &lhs, const BusinessGreetingMessage &rhs) {
return !(lhs == rhs);
}
StringBuilder &operator<<(StringBuilder &string_builder, const BusinessGreetingMessage &greeting_message);
} // namespace td

View File

@ -0,0 +1,35 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024
//
// 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/BusinessGreetingMessage.h"
#include "td/telegram/BusinessRecipients.hpp"
#include "td/utils/common.h"
#include "td/utils/tl_helpers.h"
namespace td {
template <class StorerT>
void BusinessGreetingMessage::store(StorerT &storer) const {
BEGIN_STORE_FLAGS();
END_STORE_FLAGS();
td::store(shortcut_id_, storer);
td::store(recipients_, storer);
td::store(inactivity_days_, storer);
}
template <class ParserT>
void BusinessGreetingMessage::parse(ParserT &parser) {
BEGIN_PARSE_FLAGS();
END_PARSE_FLAGS();
td::parse(shortcut_id_, parser);
td::parse(recipients_, parser);
td::parse(inactivity_days_, parser);
}
} // namespace td

View File

@ -0,0 +1,87 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024
//
// 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/BusinessInfo.h"
namespace td {
td_api::object_ptr<td_api::businessInfo> BusinessInfo::get_business_info_object(Td *td) const {
if (is_empty()) {
return nullptr;
}
return td_api::make_object<td_api::businessInfo>(location_.get_business_location_object(),
work_hours_.get_business_opening_hours_object(),
greeting_message_.get_business_greeting_message_settings_object(td),
away_message_.get_business_away_message_settings_object(td));
}
bool BusinessInfo::is_empty_location(const DialogLocation &location) {
return location.empty() && location.get_address().empty();
}
bool BusinessInfo::is_empty() const {
return is_empty_location(location_) && work_hours_.is_empty() && away_message_.is_empty() &&
greeting_message_.is_empty();
}
bool BusinessInfo::set_location(unique_ptr<BusinessInfo> &business_info, DialogLocation &&location) {
if (business_info == nullptr) {
if (is_empty_location(location)) {
return false;
}
business_info = make_unique<BusinessInfo>();
}
if (business_info->location_ != location) {
business_info->location_ = std::move(location);
return true;
}
return false;
}
bool BusinessInfo::set_work_hours(unique_ptr<BusinessInfo> &business_info, BusinessWorkHours &&work_hours) {
if (business_info == nullptr) {
if (work_hours.is_empty()) {
return false;
}
business_info = make_unique<BusinessInfo>();
}
if (business_info->work_hours_ != work_hours) {
business_info->work_hours_ = std::move(work_hours);
return true;
}
return false;
}
bool BusinessInfo::set_away_message(unique_ptr<BusinessInfo> &business_info, BusinessAwayMessage &&away_message) {
if (business_info == nullptr) {
if (away_message.is_empty()) {
return false;
}
business_info = make_unique<BusinessInfo>();
}
if (business_info->away_message_ != away_message) {
business_info->away_message_ = std::move(away_message);
return true;
}
return false;
}
bool BusinessInfo::set_greeting_message(unique_ptr<BusinessInfo> &business_info,
BusinessGreetingMessage &&greeting_message) {
if (business_info == nullptr) {
if (greeting_message.is_empty()) {
return false;
}
business_info = make_unique<BusinessInfo>();
}
if (business_info->greeting_message_ != greeting_message) {
business_info->greeting_message_ = std::move(greeting_message);
return true;
}
return false;
}
} // namespace td

View File

@ -0,0 +1,50 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024
//
// 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/BusinessAwayMessage.h"
#include "td/telegram/BusinessGreetingMessage.h"
#include "td/telegram/BusinessWorkHours.h"
#include "td/telegram/DialogLocation.h"
#include "td/telegram/td_api.h"
#include "td/utils/common.h"
namespace td {
class Td;
class BusinessInfo {
public:
td_api::object_ptr<td_api::businessInfo> get_business_info_object(Td *td) const;
bool is_empty() const;
static bool set_location(unique_ptr<BusinessInfo> &business_info, DialogLocation &&location);
static bool set_work_hours(unique_ptr<BusinessInfo> &business_info, BusinessWorkHours &&work_hours);
static bool set_away_message(unique_ptr<BusinessInfo> &business_info, BusinessAwayMessage &&away_message);
static bool set_greeting_message(unique_ptr<BusinessInfo> &business_info, BusinessGreetingMessage &&greeting_message);
template <class StorerT>
void store(StorerT &storer) const;
template <class ParserT>
void parse(ParserT &parser);
private:
static bool is_empty_location(const DialogLocation &location);
DialogLocation location_;
BusinessWorkHours work_hours_;
BusinessAwayMessage away_message_;
BusinessGreetingMessage greeting_message_;
};
} // namespace td

View File

@ -0,0 +1,72 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024
//
// 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/BusinessInfo.h"
#include "td/telegram/BusinessAwayMessage.hpp"
#include "td/telegram/BusinessGreetingMessage.hpp"
#include "td/telegram/BusinessWorkHours.hpp"
#include "td/utils/common.h"
#include "td/utils/tl_helpers.h"
namespace td {
template <class StorerT>
void BusinessInfo::store(StorerT &storer) const {
bool has_location = !is_empty_location(location_);
bool has_work_hours = !work_hours_.is_empty();
bool has_away_message = away_message_.is_valid();
bool has_greeting_message = greeting_message_.is_valid();
BEGIN_STORE_FLAGS();
STORE_FLAG(has_location);
STORE_FLAG(has_work_hours);
STORE_FLAG(has_away_message);
STORE_FLAG(has_greeting_message);
END_STORE_FLAGS();
if (has_location) {
td::store(location_, storer);
}
if (has_work_hours) {
td::store(work_hours_, storer);
}
if (has_away_message) {
td::store(away_message_, storer);
}
if (has_greeting_message) {
td::store(greeting_message_, storer);
}
}
template <class ParserT>
void BusinessInfo::parse(ParserT &parser) {
bool has_location;
bool has_work_hours;
bool has_away_message;
bool has_greeting_message;
BEGIN_PARSE_FLAGS();
PARSE_FLAG(has_location);
PARSE_FLAG(has_work_hours);
PARSE_FLAG(has_away_message);
PARSE_FLAG(has_greeting_message);
END_PARSE_FLAGS();
if (has_location) {
td::parse(location_, parser);
}
if (has_work_hours) {
td::parse(work_hours_, parser);
}
if (has_away_message) {
td::parse(away_message_, parser);
}
if (has_greeting_message) {
td::parse(greeting_message_, parser);
}
}
} // namespace td

View File

@ -0,0 +1,298 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
//
// 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/BusinessManager.h"
#include "td/telegram/BusinessAwayMessage.h"
#include "td/telegram/BusinessConnectedBot.h"
#include "td/telegram/BusinessGreetingMessage.h"
#include "td/telegram/BusinessRecipients.h"
#include "td/telegram/BusinessWorkHours.h"
#include "td/telegram/ContactsManager.h"
#include "td/telegram/DialogLocation.h"
#include "td/telegram/Global.h"
#include "td/telegram/Td.h"
#include "td/telegram/telegram_api.h"
#include "td/telegram/UpdatesManager.h"
#include "td/utils/buffer.h"
#include "td/utils/logging.h"
#include "td/utils/Status.h"
namespace td {
class GetConnectedBotsQuery final : public Td::ResultHandler {
Promise<td_api::object_ptr<td_api::businessConnectedBot>> promise_;
public:
explicit GetConnectedBotsQuery(Promise<td_api::object_ptr<td_api::businessConnectedBot>> &&promise)
: promise_(std::move(promise)) {
}
void send() {
send_query(G()->net_query_creator().create(telegram_api::account_getConnectedBots(), {{"me"}}));
}
void on_result(BufferSlice packet) final {
auto result_ptr = fetch_result<telegram_api::account_getConnectedBots>(packet);
if (result_ptr.is_error()) {
return on_error(result_ptr.move_as_error());
}
auto result = result_ptr.move_as_ok();
LOG(INFO) << "Receive result for GetConnectedBotsQuery: " << to_string(result);
td_->contacts_manager_->on_get_users(std::move(result->users_), "GetConnectedBotsQuery");
if (result->connected_bots_.size() > 1u) {
return on_error(Status::Error(500, "Receive invalid response"));
}
if (result->connected_bots_.empty()) {
return promise_.set_value(nullptr);
}
auto bot = BusinessConnectedBot(std::move(result->connected_bots_[0]));
if (!bot.is_valid()) {
return on_error(Status::Error(500, "Receive invalid bot"));
}
promise_.set_value(bot.get_business_connected_bot_object(td_));
}
void on_error(Status status) final {
promise_.set_error(std::move(status));
}
};
class UpdateConnectedBotQuery final : public Td::ResultHandler {
Promise<Unit> promise_;
public:
explicit UpdateConnectedBotQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
void send(const BusinessConnectedBot &bot, telegram_api::object_ptr<telegram_api::InputUser> &&input_user) {
int32 flags = 0;
if (bot.get_can_reply()) {
flags |= telegram_api::account_updateConnectedBot::CAN_REPLY_MASK;
}
send_query(G()->net_query_creator().create(
telegram_api::account_updateConnectedBot(flags, false /*ignored*/, false /*ignored*/, std::move(input_user),
bot.get_recipients().get_input_business_recipients(td_)),
{{"me"}}));
}
void send(telegram_api::object_ptr<telegram_api::InputUser> &&input_user) {
int32 flags = telegram_api::account_updateConnectedBot::DELETED_MASK;
send_query(G()->net_query_creator().create(
telegram_api::account_updateConnectedBot(flags, false /*ignored*/, false /*ignored*/, std::move(input_user),
BusinessRecipients().get_input_business_recipients(td_)),
{{"me"}}));
}
void on_result(BufferSlice packet) final {
auto result_ptr = fetch_result<telegram_api::account_updateConnectedBot>(packet);
if (result_ptr.is_error()) {
return on_error(result_ptr.move_as_error());
}
auto ptr = result_ptr.move_as_ok();
LOG(INFO) << "Receive result for UpdateConnectedBotQuery: " << to_string(ptr);
td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
}
void on_error(Status status) final {
promise_.set_error(std::move(status));
}
};
class UpdateBusinessLocationQuery final : public Td::ResultHandler {
Promise<Unit> promise_;
DialogLocation location_;
public:
explicit UpdateBusinessLocationQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
void send(DialogLocation &&location) {
location_ = std::move(location);
int32 flags = 0;
if (!location_.empty()) {
flags |= telegram_api::account_updateBusinessLocation::GEO_POINT_MASK;
}
if (!location_.get_address().empty()) {
flags |= telegram_api::account_updateBusinessLocation::ADDRESS_MASK;
}
send_query(G()->net_query_creator().create(
telegram_api::account_updateBusinessLocation(flags, location_.get_input_geo_point(), location_.get_address()),
{{"me"}}));
}
void on_result(BufferSlice packet) final {
auto result_ptr = fetch_result<telegram_api::account_updateBusinessLocation>(packet);
if (result_ptr.is_error()) {
return on_error(result_ptr.move_as_error());
}
td_->contacts_manager_->on_update_user_location(td_->contacts_manager_->get_my_id(), std::move(location_));
promise_.set_value(Unit());
}
void on_error(Status status) final {
promise_.set_error(std::move(status));
}
};
class UpdateBusinessWorkHoursQuery final : public Td::ResultHandler {
Promise<Unit> promise_;
BusinessWorkHours work_hours_;
public:
explicit UpdateBusinessWorkHoursQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
void send(BusinessWorkHours &&work_hours) {
work_hours_ = std::move(work_hours);
int32 flags = 0;
if (!work_hours_.is_empty()) {
flags |= telegram_api::account_updateBusinessWorkHours::BUSINESS_WORK_HOURS_MASK;
}
send_query(G()->net_query_creator().create(
telegram_api::account_updateBusinessWorkHours(flags, work_hours_.get_input_business_work_hours()), {{"me"}}));
}
void on_result(BufferSlice packet) final {
auto result_ptr = fetch_result<telegram_api::account_updateBusinessWorkHours>(packet);
if (result_ptr.is_error()) {
return on_error(result_ptr.move_as_error());
}
td_->contacts_manager_->on_update_user_work_hours(td_->contacts_manager_->get_my_id(), std::move(work_hours_));
promise_.set_value(Unit());
}
void on_error(Status status) final {
promise_.set_error(std::move(status));
}
};
class UpdateBusinessGreetingMessageQuery final : public Td::ResultHandler {
Promise<Unit> promise_;
BusinessGreetingMessage greeting_message_;
public:
explicit UpdateBusinessGreetingMessageQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
void send(BusinessGreetingMessage &&greeting_message) {
greeting_message_ = std::move(greeting_message);
int32 flags = 0;
if (!greeting_message_.is_empty()) {
flags |= telegram_api::account_updateBusinessGreetingMessage::MESSAGE_MASK;
}
send_query(G()->net_query_creator().create(telegram_api::account_updateBusinessGreetingMessage(
flags, greeting_message_.get_input_business_greeting_message(td_)),
{{"me"}}));
}
void on_result(BufferSlice packet) final {
auto result_ptr = fetch_result<telegram_api::account_updateBusinessGreetingMessage>(packet);
if (result_ptr.is_error()) {
return on_error(result_ptr.move_as_error());
}
td_->contacts_manager_->on_update_user_greeting_message(td_->contacts_manager_->get_my_id(),
std::move(greeting_message_));
promise_.set_value(Unit());
}
void on_error(Status status) final {
promise_.set_error(std::move(status));
}
};
class UpdateBusinessAwayMessageQuery final : public Td::ResultHandler {
Promise<Unit> promise_;
BusinessAwayMessage away_message_;
public:
explicit UpdateBusinessAwayMessageQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
void send(BusinessAwayMessage &&away_message) {
away_message_ = std::move(away_message);
int32 flags = 0;
if (!away_message_.is_empty()) {
flags |= telegram_api::account_updateBusinessAwayMessage::MESSAGE_MASK;
}
send_query(G()->net_query_creator().create(
telegram_api::account_updateBusinessAwayMessage(flags, away_message_.get_input_business_away_message(td_)),
{{"me"}}));
}
void on_result(BufferSlice packet) final {
auto result_ptr = fetch_result<telegram_api::account_updateBusinessAwayMessage>(packet);
if (result_ptr.is_error()) {
return on_error(result_ptr.move_as_error());
}
td_->contacts_manager_->on_update_user_away_message(td_->contacts_manager_->get_my_id(), std::move(away_message_));
promise_.set_value(Unit());
}
void on_error(Status status) final {
promise_.set_error(std::move(status));
}
};
BusinessManager::BusinessManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) {
}
void BusinessManager::tear_down() {
parent_.reset();
}
void BusinessManager::get_business_connected_bot(Promise<td_api::object_ptr<td_api::businessConnectedBot>> &&promise) {
td_->create_handler<GetConnectedBotsQuery>(std::move(promise))->send();
}
void BusinessManager::set_business_connected_bot(td_api::object_ptr<td_api::businessConnectedBot> &&bot,
Promise<Unit> &&promise) {
if (bot == nullptr) {
return promise.set_error(Status::Error(400, "Bot must be non-empty"));
}
BusinessConnectedBot connected_bot(std::move(bot));
TRY_RESULT_PROMISE(promise, input_user, td_->contacts_manager_->get_input_user(connected_bot.get_user_id()));
td_->create_handler<UpdateConnectedBotQuery>(std::move(promise))->send(connected_bot, std::move(input_user));
}
void BusinessManager::delete_business_connected_bot(UserId bot_user_id, Promise<Unit> &&promise) {
TRY_RESULT_PROMISE(promise, input_user, td_->contacts_manager_->get_input_user(bot_user_id));
td_->create_handler<UpdateConnectedBotQuery>(std::move(promise))->send(std::move(input_user));
}
void BusinessManager::set_business_location(DialogLocation &&location, Promise<Unit> &&promise) {
td_->create_handler<UpdateBusinessLocationQuery>(std::move(promise))->send(std::move(location));
}
void BusinessManager::set_business_work_hours(BusinessWorkHours &&work_hours, Promise<Unit> &&promise) {
td_->create_handler<UpdateBusinessWorkHoursQuery>(std::move(promise))->send(std::move(work_hours));
}
void BusinessManager::set_business_greeting_message(BusinessGreetingMessage &&greeting_message,
Promise<Unit> &&promise) {
td_->create_handler<UpdateBusinessGreetingMessageQuery>(std::move(promise))->send(std::move(greeting_message));
}
void BusinessManager::set_business_away_message(BusinessAwayMessage &&away_message, Promise<Unit> &&promise) {
td_->create_handler<UpdateBusinessAwayMessageQuery>(std::move(promise))->send(std::move(away_message));
}
void BusinessManager::memory_stats(vector<string> &output) {
}
} // namespace td

View File

@ -0,0 +1,51 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
//
// 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/UserId.h"
#include "td/actor/actor.h"
#include "td/utils/common.h"
#include "td/utils/Promise.h"
namespace td {
class BusinessAwayMessage;
class BusinessGreetingMessage;
class BusinessWorkHours;
class DialogLocation;
class Td;
class BusinessManager final : public Actor {
public:
void memory_stats(vector<string> &output);
BusinessManager(Td *td, ActorShared<> parent);
void get_business_connected_bot(Promise<td_api::object_ptr<td_api::businessConnectedBot>> &&promise);
void set_business_connected_bot(td_api::object_ptr<td_api::businessConnectedBot> &&bot, Promise<Unit> &&promise);
void delete_business_connected_bot(UserId bot_user_id, Promise<Unit> &&promise);
void set_business_location(DialogLocation &&location, Promise<Unit> &&promise);
void set_business_work_hours(BusinessWorkHours &&work_hours, Promise<Unit> &&promise);
void set_business_greeting_message(BusinessGreetingMessage &&greeting_message, Promise<Unit> &&promise);
void set_business_away_message(BusinessAwayMessage &&away_message, Promise<Unit> &&promise);
private:
void tear_down() final;
Td *td_;
ActorShared<> parent_;
};
} // namespace td

View File

@ -0,0 +1,104 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024
//
// 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/BusinessRecipients.h"
#include "td/telegram/ContactsManager.h"
#include "td/telegram/DialogId.h"
#include "td/telegram/DialogManager.h"
#include "td/telegram/Td.h"
#include "td/utils/algorithm.h"
namespace td {
BusinessRecipients::BusinessRecipients(telegram_api::object_ptr<telegram_api::businessRecipients> recipients)
: user_ids_(UserId::get_user_ids(recipients->users_))
, existing_chats_(recipients->existing_chats_)
, new_chats_(recipients->new_chats_)
, contacts_(recipients->contacts_)
, non_contacts_(recipients->non_contacts_)
, exclude_selected_(recipients->exclude_selected_) {
td::remove_if(user_ids_, [](UserId user_id) { return !user_id.is_valid(); });
}
BusinessRecipients::BusinessRecipients(td_api::object_ptr<td_api::businessRecipients> recipients) {
if (recipients == nullptr) {
return;
}
for (auto chat_id : recipients->chat_ids_) {
DialogId dialog_id(chat_id);
if (dialog_id.get_type() == DialogType::User) {
user_ids_.push_back(dialog_id.get_user_id());
}
}
existing_chats_ = recipients->select_existing_chats_;
new_chats_ = recipients->select_new_chats_;
contacts_ = recipients->select_contacts_;
non_contacts_ = recipients->select_non_contacts_;
exclude_selected_ = recipients->exclude_selected_;
}
td_api::object_ptr<td_api::businessRecipients> BusinessRecipients::get_business_recipients_object(Td *td) const {
vector<int64> chat_ids;
for (auto user_id : user_ids_) {
DialogId dialog_id(user_id);
td->dialog_manager_->force_create_dialog(dialog_id, "get_business_recipients_object", true);
CHECK(td->dialog_manager_->have_dialog_force(dialog_id, "get_business_recipients_object"));
chat_ids.push_back(td->dialog_manager_->get_chat_id_object(dialog_id, "businessRecipients"));
}
return td_api::make_object<td_api::businessRecipients>(std::move(chat_ids), existing_chats_, new_chats_, contacts_,
non_contacts_, exclude_selected_);
}
telegram_api::object_ptr<telegram_api::inputBusinessRecipients> BusinessRecipients::get_input_business_recipients(
Td *td) const {
int32 flags = 0;
if (existing_chats_) {
flags |= telegram_api::inputBusinessRecipients::EXISTING_CHATS_MASK;
}
if (new_chats_) {
flags |= telegram_api::inputBusinessRecipients::NEW_CHATS_MASK;
}
if (contacts_) {
flags |= telegram_api::inputBusinessRecipients::CONTACTS_MASK;
}
if (non_contacts_) {
flags |= telegram_api::inputBusinessRecipients::NON_CONTACTS_MASK;
}
if (exclude_selected_) {
flags |= telegram_api::inputBusinessRecipients::EXCLUDE_SELECTED_MASK;
}
vector<telegram_api::object_ptr<telegram_api::InputUser>> input_users;
for (auto user_id : user_ids_) {
auto r_input_user = td->contacts_manager_->get_input_user(user_id);
if (r_input_user.is_ok()) {
input_users.push_back(r_input_user.move_as_ok());
}
}
if (!input_users.empty()) {
flags |= telegram_api::inputBusinessRecipients::USERS_MASK;
}
return telegram_api::make_object<telegram_api::inputBusinessRecipients>(flags, false /*ignored*/, false /*ignored*/,
false /*ignored*/, false /*ignored*/,
false /*ignored*/, std::move(input_users));
}
bool operator==(const BusinessRecipients &lhs, const BusinessRecipients &rhs) {
return lhs.user_ids_ == rhs.user_ids_ && lhs.existing_chats_ == rhs.existing_chats_ &&
lhs.new_chats_ == rhs.new_chats_ && lhs.contacts_ == rhs.contacts_ && lhs.non_contacts_ == rhs.non_contacts_ &&
lhs.exclude_selected_ == rhs.exclude_selected_;
}
StringBuilder &operator<<(StringBuilder &string_builder, const BusinessRecipients &recipients) {
return string_builder << "received by " << (recipients.exclude_selected_ ? "all private chats except " : "")
<< recipients.user_ids_ << (recipients.contacts_ ? ", contacts " : "")
<< (recipients.non_contacts_ ? ", non-contacts " : "")
<< (recipients.existing_chats_ ? ", existing chats " : "")
<< (recipients.new_chats_ ? ", new chats " : "");
}
} // namespace td

View File

@ -0,0 +1,59 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024
//
// 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/telegram/UserId.h"
#include "td/utils/common.h"
#include "td/utils/StringBuilder.h"
namespace td {
class Td;
class BusinessRecipients {
public:
BusinessRecipients() = default;
explicit BusinessRecipients(telegram_api::object_ptr<telegram_api::businessRecipients> recipients);
explicit BusinessRecipients(td_api::object_ptr<td_api::businessRecipients> recipients);
td_api::object_ptr<td_api::businessRecipients> get_business_recipients_object(Td *td) const;
telegram_api::object_ptr<telegram_api::inputBusinessRecipients> get_input_business_recipients(Td *td) const;
template <class StorerT>
void store(StorerT &storer) const;
template <class ParserT>
void parse(ParserT &parser);
private:
vector<UserId> user_ids_;
bool existing_chats_ = false;
bool new_chats_ = false;
bool contacts_ = false;
bool non_contacts_ = false;
bool exclude_selected_ = false;
friend bool operator==(const BusinessRecipients &lhs, const BusinessRecipients &rhs);
friend StringBuilder &operator<<(StringBuilder &string_builder, const BusinessRecipients &recipients);
};
bool operator==(const BusinessRecipients &lhs, const BusinessRecipients &rhs);
inline bool operator!=(const BusinessRecipients &lhs, const BusinessRecipients &rhs) {
return !(lhs == rhs);
}
StringBuilder &operator<<(StringBuilder &string_builder, const BusinessRecipients &recipients);
} // namespace td

View File

@ -0,0 +1,48 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024
//
// 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/BusinessRecipients.h"
#include "td/utils/common.h"
#include "td/utils/tl_helpers.h"
namespace td {
template <class StorerT>
void BusinessRecipients::store(StorerT &storer) const {
bool has_user_ids = !user_ids_.empty();
BEGIN_STORE_FLAGS();
STORE_FLAG(existing_chats_);
STORE_FLAG(new_chats_);
STORE_FLAG(contacts_);
STORE_FLAG(non_contacts_);
STORE_FLAG(exclude_selected_);
STORE_FLAG(has_user_ids);
END_STORE_FLAGS();
if (has_user_ids) {
td::store(user_ids_, storer);
}
}
template <class ParserT>
void BusinessRecipients::parse(ParserT &parser) {
bool has_user_ids;
BEGIN_PARSE_FLAGS();
PARSE_FLAG(existing_chats_);
PARSE_FLAG(new_chats_);
PARSE_FLAG(contacts_);
PARSE_FLAG(non_contacts_);
PARSE_FLAG(exclude_selected_);
PARSE_FLAG(has_user_ids);
END_PARSE_FLAGS();
if (has_user_ids) {
td::parse(user_ids_, parser);
}
}
} // namespace td

View File

@ -0,0 +1,179 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024
//
// 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/BusinessWorkHours.h"
#include "td/utils/algorithm.h"
#include "td/utils/format.h"
#include "td/utils/logging.h"
#include <algorithm>
namespace td {
td_api::object_ptr<td_api::businessOpeningHoursInterval>
BusinessWorkHours::WorkHoursInterval::get_business_opening_hours_interval_object() const {
return td_api::make_object<td_api::businessOpeningHoursInterval>(start_minute_, end_minute_);
}
telegram_api::object_ptr<telegram_api::businessWeeklyOpen>
BusinessWorkHours::WorkHoursInterval::get_input_business_weekly_open() const {
return telegram_api::make_object<telegram_api::businessWeeklyOpen>(start_minute_, end_minute_);
}
BusinessWorkHours::BusinessWorkHours(telegram_api::object_ptr<telegram_api::businessWorkHours> &&work_hours) {
if (work_hours != nullptr) {
work_hours_ = transform(work_hours->weekly_open_,
[](const telegram_api::object_ptr<telegram_api::businessWeeklyOpen> &weekly_open) {
return WorkHoursInterval(weekly_open->start_minute_, weekly_open->end_minute_);
});
sanitize_work_hours();
time_zone_id_ = std::move(work_hours->timezone_id_);
}
}
BusinessWorkHours::BusinessWorkHours(td_api::object_ptr<td_api::businessOpeningHours> &&work_hours) {
if (work_hours != nullptr) {
work_hours_ = transform(work_hours->opening_hours_,
[](const td_api::object_ptr<td_api::businessOpeningHoursInterval> &interval) {
return WorkHoursInterval(interval->start_minute_, interval->end_minute_);
});
sanitize_work_hours();
time_zone_id_ = std::move(work_hours->time_zone_id_);
}
}
bool BusinessWorkHours::is_empty() const {
return work_hours_.empty();
}
td_api::object_ptr<td_api::businessOpeningHours> BusinessWorkHours::get_business_opening_hours_object() const {
if (is_empty()) {
return nullptr;
}
vector<td_api::object_ptr<td_api::businessOpeningHoursInterval>> intervals;
for (const auto &work_hour : work_hours_) {
auto interval = work_hour;
while (interval.start_minute_ / (24 * 60) + 1 < interval.end_minute_ / (24 * 60)) {
auto prefix = interval;
prefix.end_minute_ = (interval.start_minute_ / (24 * 60) + 1) * 24 * 60;
interval.start_minute_ = prefix.end_minute_;
intervals.push_back(prefix.get_business_opening_hours_interval_object());
}
intervals.push_back(interval.get_business_opening_hours_interval_object());
}
return td_api::make_object<td_api::businessOpeningHours>(time_zone_id_, std::move(intervals));
}
telegram_api::object_ptr<telegram_api::businessWorkHours> BusinessWorkHours::get_input_business_work_hours() const {
if (is_empty()) {
return nullptr;
}
return telegram_api::make_object<telegram_api::businessWorkHours>(
0, false, time_zone_id_, transform(work_hours_, [](const WorkHoursInterval &interval) {
return interval.get_input_business_weekly_open();
}));
}
void BusinessWorkHours::sanitize_work_hours() {
// remove invalid work hour intervals
td::remove_if(work_hours_, [](const WorkHoursInterval &interval) {
if (interval.start_minute_ >= interval.end_minute_ || interval.start_minute_ < 0 ||
interval.end_minute_ > 8 * 24 * 60) {
LOG(INFO) << "Ignore interval " << interval;
return true;
}
return false;
});
combine_work_hour_intervals();
}
void BusinessWorkHours::combine_work_hour_intervals() {
if (work_hours_.empty()) {
return;
}
// sort intervals
std::sort(work_hours_.begin(), work_hours_.end(), [](const WorkHoursInterval &lhs, const WorkHoursInterval &rhs) {
return lhs.start_minute_ < rhs.start_minute_;
});
// combine intersecting intervals
size_t j = 0;
for (size_t i = 1; i < work_hours_.size(); i++) {
CHECK(work_hours_[i].start_minute_ >= work_hours_[j].start_minute_);
if (work_hours_[i].start_minute_ <= work_hours_[j].end_minute_) {
work_hours_[j].end_minute_ = max(work_hours_[j].end_minute_, work_hours_[i].end_minute_);
} else {
work_hours_[++j] = work_hours_[i];
}
}
work_hours_.resize(j + 1);
// there must be no intervals longer than 1 week
for (auto &interval : work_hours_) {
interval.end_minute_ = min(interval.end_minute_, interval.start_minute_ + 7 * 24 * 60);
}
CHECK(!work_hours_.empty());
// if the last interval can be exactly merged with the first one, merge them
if (work_hours_[0].start_minute_ != 0 &&
work_hours_[0].start_minute_ + 7 * 24 * 60 == work_hours_.back().end_minute_) {
if (work_hours_.back().start_minute_ >= 7 * 24 * 60) {
work_hours_[0].start_minute_ = work_hours_.back().start_minute_ - 7 * 24 * 60;
work_hours_.pop_back();
CHECK(!work_hours_.empty());
} else {
work_hours_[0].start_minute_ = 0;
work_hours_.back().end_minute_ = 7 * 24 * 60;
}
}
// if there are intervals that intersect the first interval or start after the end of the week,
// then they must be normalized
auto max_minute = work_hours_[0].start_minute_ + 7 * 24 * 60;
if (work_hours_.back().end_minute_ > max_minute || work_hours_.back().start_minute_ >= 7 * 24 * 60) {
auto size = work_hours_.size();
for (size_t i = 1; i < size; i++) {
if (work_hours_[i].start_minute_ >= 7 * 24 * 60) {
work_hours_[i].start_minute_ -= 7 * 24 * 60;
work_hours_[i].end_minute_ -= 7 * 24 * 60;
} else if (work_hours_[i].end_minute_ > max_minute) {
work_hours_.emplace_back(max_minute - 7 * 24 * 60, work_hours_[i].end_minute_ - 7 * 24 * 60);
work_hours_[i].end_minute_ = max_minute;
}
}
combine_work_hour_intervals();
}
}
bool operator==(const BusinessWorkHours::WorkHoursInterval &lhs, const BusinessWorkHours::WorkHoursInterval &rhs) {
return lhs.start_minute_ == rhs.start_minute_ && lhs.end_minute_ == rhs.end_minute_;
}
bool operator!=(const BusinessWorkHours::WorkHoursInterval &lhs, const BusinessWorkHours::WorkHoursInterval &rhs) {
return !(lhs == rhs);
}
StringBuilder &operator<<(StringBuilder &string_builder, const BusinessWorkHours::WorkHoursInterval &interval) {
return string_builder << '[' << interval.start_minute_ << ',' << interval.end_minute_ << ')';
}
bool operator==(const BusinessWorkHours &lhs, const BusinessWorkHours &rhs) {
return lhs.work_hours_ == rhs.work_hours_ && lhs.time_zone_id_ == rhs.time_zone_id_;
}
bool operator!=(const BusinessWorkHours &lhs, const BusinessWorkHours &rhs) {
return !(lhs == rhs);
}
StringBuilder &operator<<(StringBuilder &string_builder, const BusinessWorkHours &work_hours) {
return string_builder << "BusinessWorkHours[" << work_hours.work_hours_ << " in " << work_hours.time_zone_id_ << ']';
}
} // namespace td

View File

@ -0,0 +1,85 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024
//
// 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/StringBuilder.h"
namespace td {
class BusinessWorkHours {
public:
BusinessWorkHours() = default;
explicit BusinessWorkHours(telegram_api::object_ptr<telegram_api::businessWorkHours> &&work_hours);
explicit BusinessWorkHours(td_api::object_ptr<td_api::businessOpeningHours> &&work_hours);
bool is_empty() const;
td_api::object_ptr<td_api::businessOpeningHours> get_business_opening_hours_object() const;
telegram_api::object_ptr<telegram_api::businessWorkHours> get_input_business_work_hours() const;
template <class StorerT>
void store(StorerT &storer) const;
template <class ParserT>
void parse(ParserT &parser);
private:
struct WorkHoursInterval {
int32 start_minute_ = 0;
int32 end_minute_ = 0;
WorkHoursInterval() = default;
WorkHoursInterval(int32 start_minute, int32 end_minute) : start_minute_(start_minute), end_minute_(end_minute) {
}
td_api::object_ptr<td_api::businessOpeningHoursInterval> get_business_opening_hours_interval_object() const;
telegram_api::object_ptr<telegram_api::businessWeeklyOpen> get_input_business_weekly_open() const;
template <class StorerT>
void store(StorerT &storer) const;
template <class ParserT>
void parse(ParserT &parser);
};
void sanitize_work_hours();
void combine_work_hour_intervals();
friend bool operator==(const WorkHoursInterval &lhs, const WorkHoursInterval &rhs);
friend bool operator!=(const WorkHoursInterval &lhs, const WorkHoursInterval &rhs);
friend bool operator==(const BusinessWorkHours &lhs, const BusinessWorkHours &rhs);
friend bool operator!=(const BusinessWorkHours &lhs, const BusinessWorkHours &rhs);
friend StringBuilder &operator<<(StringBuilder &string_builder, const WorkHoursInterval &interval);
friend StringBuilder &operator<<(StringBuilder &string_builder, const BusinessWorkHours &work_hours);
vector<WorkHoursInterval> work_hours_;
string time_zone_id_;
};
bool operator==(const BusinessWorkHours::WorkHoursInterval &lhs, const BusinessWorkHours::WorkHoursInterval &rhs);
bool operator!=(const BusinessWorkHours::WorkHoursInterval &lhs, const BusinessWorkHours::WorkHoursInterval &rhs);
StringBuilder &operator<<(StringBuilder &string_builder, const BusinessWorkHours::WorkHoursInterval &interval);
bool operator==(const BusinessWorkHours &lhs, const BusinessWorkHours &rhs);
bool operator!=(const BusinessWorkHours &lhs, const BusinessWorkHours &rhs);
StringBuilder &operator<<(StringBuilder &string_builder, const BusinessWorkHours &work_hours);
} // namespace td

View File

@ -0,0 +1,43 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024
//
// 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/BusinessWorkHours.h"
#include "td/utils/tl_helpers.h"
namespace td {
template <class StorerT>
void BusinessWorkHours::WorkHoursInterval::store(StorerT &storer) const {
td::store(start_minute_, storer);
td::store(end_minute_, storer);
}
template <class ParserT>
void BusinessWorkHours::WorkHoursInterval::parse(ParserT &parser) {
td::parse(start_minute_, parser);
td::parse(end_minute_, parser);
}
template <class StorerT>
void BusinessWorkHours::store(StorerT &storer) const {
BEGIN_STORE_FLAGS();
END_STORE_FLAGS();
td::store(work_hours_, storer);
td::store(time_zone_id_, storer);
}
template <class ParserT>
void BusinessWorkHours::parse(ParserT &parser) {
BEGIN_PARSE_FLAGS();
END_PARSE_FLAGS();
td::parse(work_hours_, parser);
td::parse(time_zone_id_, parser);
}
} // namespace td

View File

@ -290,4 +290,7 @@ void CallbackQueriesManager::send_get_callback_answer_query(
->send(dialog_id, message_full_id.get_message_id(), payload, std::move(password));
}
void CallbackQueriesManager::memory_stats(vector<string> &output) {
}
} // namespace td

View File

@ -23,6 +23,7 @@ class Td;
class CallbackQueriesManager {
public:
void memory_stats(vector<string> &output);
explicit CallbackQueriesManager(Td *td);
void answer_callback_query(int64 callback_query_id, const string &text, bool show_alert, const string &url,

View File

@ -435,8 +435,17 @@ class MultiImplPool {
#if TD_OPENBSD
max_client_threads = td::min(max_client_threads, 4u);
#endif
// Start TDLight - increment this to 128, otherwise the memory will not be freed when a session is closed
max_client_threads = 128;
// End TDLight - increment this to 128, otherwise the memory will not be freed when a session is closed
impls_.resize(max_client_threads);
// Start TDLight - disable check
# if false
// End TDLight - disable check
CHECK(impls_.size() * (1 + MultiImpl::ADDITIONAL_THREAD_COUNT + 1 /* IOCP */) < 128);
// Start TDLight - disable check
# endif
// End TDLight - disable check
net_query_stats_ = std::make_shared<NetQueryStats>();
}

View File

@ -221,4 +221,8 @@ void CommonDialogManager::on_get_common_dialogs(UserId user_id, int64 offset_cha
common_dialogs.total_count = total_count;
}
void CommonDialogManager::memory_stats(vector<string> &output) {
output.emplace_back("\"found_common_dialogs_\":"); output.emplace_back(std::to_string(this->found_common_dialogs_.size()));
}
} // namespace td

View File

@ -24,6 +24,7 @@ class Td;
class CommonDialogManager final : public Actor {
public:
void memory_stats(vector<string> &output);
CommonDialogManager(Td *td, ActorShared<> parent);
CommonDialogManager(const CommonDialogManager &) = delete;
CommonDialogManager &operator=(const CommonDialogManager &) = delete;

View File

@ -1980,6 +1980,16 @@ void ConfigManager::process_app_config(tl_object_ptr<telegram_api::JSONValue> &c
G()->set_option_integer(key, get_json_value_int(std::move(key_value->value_), key));
continue;
}
if (key == "quick_replies_limit") {
G()->set_option_integer("quick_reply_shortcut_count_max",
get_json_value_int(std::move(key_value->value_), key));
continue;
}
if (key == "quick_reply_messages_limit") {
G()->set_option_integer("quick_reply_shortcut_message_count_max",
get_json_value_int(std::move(key_value->value_), key));
continue;
}
new_values.push_back(std::move(key_value));
}

View File

@ -102,7 +102,7 @@ class ConfigManager final : public NetQueryCallback {
private:
struct AppConfig {
static constexpr int32 CURRENT_VERSION = 30;
static constexpr int32 CURRENT_VERSION = 32;
int32 version_ = 0;
int32 hash_ = 0;
telegram_api::object_ptr<telegram_api::JSONValue> config_;

File diff suppressed because it is too large Load Diff

View File

@ -19,12 +19,10 @@
#include "td/telegram/DialogInviteLink.h"
#include "td/telegram/DialogLocation.h"
#include "td/telegram/DialogParticipant.h"
#include "td/telegram/DialogParticipantFilter.h"
#include "td/telegram/EmojiStatus.h"
#include "td/telegram/files/FileId.h"
#include "td/telegram/files/FileSourceId.h"
#include "td/telegram/FolderId.h"
#include "td/telegram/Location.h"
#include "td/telegram/MessageFullId.h"
#include "td/telegram/MessageId.h"
#include "td/telegram/MessageTtl.h"
@ -67,15 +65,16 @@
namespace td {
struct BinlogEvent;
class ChannelParticipantFilter;
class BusinessAwayMessage;
class BusinessGreetingMessage;
class BusinessInfo;
class BusinessWorkHours;
struct MinChannel;
class Td;
class ContactsManager final : public Actor {
public:
void memory_stats(vector<string> &output);
ContactsManager(Td *td, ActorShared<> parent);
ContactsManager(const ContactsManager &) = delete;
ContactsManager &operator=(const ContactsManager &) = delete;
@ -113,6 +112,10 @@ class ContactsManager final : public Actor {
AccessRights access_rights) const;
bool have_input_encrypted_peer(SecretChatId secret_chat_id, AccessRights access_rights) const;
bool is_user_received_from_server(UserId user_id) const;
bool is_chat_received_from_server(ChatId chat_id) const;
bool is_channel_received_from_server(ChannelId channel_id) const;
const DialogPhoto *get_user_dialog_photo(UserId user_id);
const DialogPhoto *get_chat_dialog_photo(ChatId chat_id) const;
const DialogPhoto *get_channel_dialog_photo(ChannelId channel_id) const;
@ -166,13 +169,20 @@ class ContactsManager final : public Actor {
bool get_user_stories_hidden(UserId user_id) const;
bool get_channel_stories_hidden(ChannelId channel_id) const;
bool can_poll_user_active_stories(UserId user_id) const;
bool can_poll_channel_active_stories(ChannelId channel_id) const;
bool can_use_premium_custom_emoji_in_channel(ChannelId channel_id) const;
string get_user_private_forward_name(UserId user_id);
bool get_user_voice_messages_forbidden(UserId user_id) const;
bool get_user_read_dates_private(UserId user_id);
string get_dialog_search_text(DialogId dialog_id) const;
string get_user_search_text(UserId user_id) const;
string get_channel_search_text(ChannelId channel_id) const;
void for_each_secret_chat_with_user(UserId user_id, const std::function<void(SecretChatId)> &f);
@ -180,6 +190,8 @@ class ContactsManager final : public Actor {
string get_channel_first_username(ChannelId channel_id) const;
string get_channel_editable_username(ChannelId channel_id) const;
bool has_user_fragment_username(UserId user_id) const;
int32 get_secret_chat_date(SecretChatId secret_chat_id) const;
int32 get_secret_chat_ttl(SecretChatId secret_chat_id) const;
UserId get_secret_chat_user_id(SecretChatId secret_chat_id) const;
@ -244,8 +256,14 @@ class ContactsManager final : public Actor {
void on_update_user_is_blocked(UserId user_id, bool is_blocked, bool is_blocked_for_stories);
void on_update_user_has_pinned_stories(UserId user_id, bool has_pinned_stories);
void on_update_user_common_chat_count(UserId user_id, int32 common_chat_count);
void on_update_user_location(UserId user_id, DialogLocation &&location);
void on_update_user_work_hours(UserId user_id, BusinessWorkHours &&work_hours);
void on_update_user_away_message(UserId user_id, BusinessAwayMessage &&away_message);
void on_update_user_greeting_message(UserId user_id, BusinessGreetingMessage &&greeting_message);
void on_update_user_need_phone_number_privacy_exception(UserId user_id, bool need_phone_number_privacy_exception);
void on_update_user_wallpaper_overridden(UserId user_id, bool wallpaper_overridden);
void on_update_user_commands(UserId user_id,
vector<telegram_api::object_ptr<telegram_api::botCommand>> &&bot_commands);
void on_set_profile_photo(UserId user_id, tl_object_ptr<telegram_api::photos_photo> &&photo, bool is_fallback,
int64 old_photo_id, Promise<Unit> &&promise);
@ -261,6 +279,7 @@ class ContactsManager final : public Actor {
void on_update_chat_delete_user(ChatId chat_id, UserId user_id, int32 version);
void on_update_chat_default_permissions(ChatId chat_id, RestrictedRights default_permissions, int32 version);
void on_update_chat_pinned_message(ChatId chat_id, MessageId pinned_message_id, int32 version);
void on_update_chat_bot_commands(ChatId chat_id, BotCommands &&bot_commands);
void on_update_channel_participant_count(ChannelId channel_id, int32 participant_count);
void on_update_channel_editable_username(ChannelId channel_id, string &&username);
@ -285,11 +304,7 @@ class ContactsManager final : public Actor {
void on_update_channel_has_pinned_stories(ChannelId channel_id, bool has_pinned_stories);
void on_update_channel_default_permissions(ChannelId channel_id, RestrictedRights default_permissions);
void on_update_channel_administrator_count(ChannelId channel_id, int32 administrator_count);
int32 on_update_peer_located(vector<tl_object_ptr<telegram_api::PeerLocated>> &&peers, bool from_update);
void on_update_bot_commands(DialogId dialog_id, UserId bot_user_id,
vector<tl_object_ptr<telegram_api::botCommand>> &&bot_commands);
void on_update_channel_bot_commands(ChannelId channel_id, BotCommands &&bot_commands);
void on_update_bot_menu_button(UserId bot_user_id, tl_object_ptr<telegram_api::BotMenuButton> &&bot_menu_button);
@ -320,8 +335,6 @@ class ContactsManager final : public Actor {
void unregister_message_channels(MessageFullId message_full_id, vector<ChannelId> channel_ids);
bool can_use_premium_custom_emoji(DialogId dialog_id) const;
UserId get_my_id() const;
void set_my_online_status(bool is_online, bool send_update, bool is_local);
@ -355,9 +368,7 @@ class ContactsManager final : public Actor {
void update_chat_online_member_count(ChatId chat_id, bool is_from_server);
void update_channel_online_member_count(ChannelId channel_id, bool is_from_server);
void drop_cached_channel_participants(ChannelId channel_id);
void on_update_channel_bot_user_ids(ChannelId channel_id, vector<UserId> &&bot_user_ids);
void on_update_username_is_active(UserId user_id, string &&username, bool is_active, Promise<Unit> &&promise);
@ -410,14 +421,6 @@ class ContactsManager final : public Actor {
void share_phone_number(UserId user_id, Promise<Unit> &&promise);
void search_dialogs_nearby(const Location &location, Promise<td_api::object_ptr<td_api::chatsNearby>> &&promise);
void set_location(const Location &location, Promise<Unit> &&promise);
static void set_location_visibility(Td *td);
void get_is_location_visible(Promise<Unit> &&promise);
void register_suggested_profile_photo(const Photo &photo);
FileId get_profile_photo_file_id(int64 photo_id) const;
@ -506,7 +509,7 @@ class ContactsManager final : public Actor {
void set_channel_discussion_group(DialogId dialog_id, DialogId discussion_dialog_id, Promise<Unit> &&promise);
void set_channel_location(DialogId dialog_id, const DialogLocation &location, Promise<Unit> &&promise);
void set_channel_location(ChannelId dialog_id, const DialogLocation &location, Promise<Unit> &&promise);
void set_channel_slow_mode_delay(DialogId dialog_id, int32 slow_mode_delay, Promise<Unit> &&promise);
@ -524,18 +527,6 @@ class ContactsManager final : public Actor {
bool can_get_channel_story_statistics(DialogId dialog_id) const;
struct CanTransferOwnershipResult {
enum class Type : uint8 { Ok, PasswordNeeded, PasswordTooFresh, SessionTooFresh };
Type type = Type::Ok;
int32 retry_after = 0;
};
void can_transfer_ownership(Promise<CanTransferOwnershipResult> &&promise);
static td_api::object_ptr<td_api::CanTransferOwnershipResult> get_can_transfer_ownership_result_object(
CanTransferOwnershipResult result);
void transfer_dialog_ownership(DialogId dialog_id, UserId user_id, const string &password, Promise<Unit> &&promise);
void migrate_dialog_to_megagroup(DialogId dialog_id, Promise<td_api::object_ptr<td_api::chat>> &&promise);
void get_channel_recommendations(DialogId dialog_id, bool return_local,
@ -578,7 +569,9 @@ class ContactsManager final : public Actor {
};
Result<BotData> get_bot_data(UserId user_id) const TD_WARN_UNUSED_RESULT;
bool is_user_online(UserId user_id, int32 tolerance = 0, int32 unix_time = 07) const;
bool is_user_online(UserId user_id, int32 tolerance = 0, int32 unix_time = 0) const;
int32 get_user_was_online(UserId user_id, int32 unix_time = 0) const;
bool is_user_status_exact(UserId user_id) const;
@ -588,8 +581,6 @@ class ContactsManager final : public Actor {
bool have_min_user(UserId user_id) const;
bool have_user_force(UserId user_id, const char *source);
bool is_dialog_info_received_from_server(DialogId dialog_id) const;
static void send_get_me_query(Td *td, Promise<Unit> &&promise);
UserId get_me(Promise<Unit> &&promise);
bool get_user(UserId user_id, int left_tries, Promise<Unit> &&promise);
@ -621,6 +612,8 @@ class ContactsManager final : public Actor {
DialogParticipantStatus get_chat_status(ChatId chat_id) const;
DialogParticipantStatus get_chat_permissions(ChatId chat_id) const;
bool is_appointed_chat_administrator(ChatId chat_id) const;
const DialogParticipant *get_chat_participant(ChatId chat_id, UserId user_id) const;
const vector<DialogParticipant> *get_chat_participants(ChatId chat_id) const;
void create_new_channel(const string &title, bool is_forum, bool is_megagroup, const string &description,
const DialogLocation &location, bool for_import, MessageTtl message_ttl,
@ -667,25 +660,11 @@ class ContactsManager final : public Actor {
bool get_channel_effective_has_hidden_participants(ChannelId channel_id, const char *source);
int32 get_channel_my_boost_count(ChannelId channel_id);
void add_chat_participant(ChatId chat_id, UserId user_id, int32 forward_limit, Promise<Unit> &&promise);
void set_chat_participant_status(ChatId chat_id, UserId user_id, DialogParticipantStatus status,
Promise<Unit> &&promise);
void delete_chat_participant(ChatId chat_id, UserId user_id, bool revoke_messages, Promise<Unit> &&promise);
void get_chat_participant(ChatId chat_id, UserId user_id, Promise<DialogParticipant> &&promise);
void speculative_add_channel_user(ChannelId channel_id, UserId user_id, const DialogParticipantStatus &new_status,
const DialogParticipantStatus &old_status);
void search_dialog_participants(DialogId dialog_id, const string &query, int32 limit, DialogParticipantFilter filter,
Promise<DialogParticipants> &&promise);
void get_channel_participants(ChannelId channel_id, tl_object_ptr<td_api::SupergroupMembersFilter> &&filter,
string additional_query, int32 offset, int32 limit, int32 additional_limit,
Promise<DialogParticipants> &&promise);
int64 get_user_id_object(UserId user_id, const char *source) const;
tl_object_ptr<td_api::user> get_user_object(UserId user_id) const;
@ -721,10 +700,6 @@ class ContactsManager final : public Actor {
void get_support_user(Promise<td_api::object_ptr<td_api::user>> &&promise);
void on_view_dialog_active_stories(vector<DialogId> dialog_ids);
void on_get_dialog_max_active_story_ids(const vector<DialogId> &dialog_ids, const vector<int32> &max_story_ids);
void repair_chat_participants(ChatId chat_id);
void get_current_state(vector<td_api::object_ptr<td_api::Update>> &updates) const;
@ -791,8 +766,6 @@ class ContactsManager final : public Actor {
bool is_repaired = false; // whether cached value is rechecked
bool is_max_active_story_id_being_reloaded = false;
bool is_name_changed = true;
bool is_username_changed = true;
bool is_photo_changed = true;
@ -850,6 +823,8 @@ class ContactsManager final : public Actor {
int32 common_chat_count = 0;
unique_ptr<BusinessInfo> business_info;
bool is_blocked = false;
bool is_blocked_for_stories = false;
bool can_be_called = false;
@ -1004,8 +979,6 @@ class ContactsManager final : public Actor {
bool is_scam = false;
bool is_fake = false;
bool is_max_active_story_id_being_reloaded = false;
bool is_title_changed = true;
bool is_username_changed = true;
bool is_photo_changed = true;
@ -1155,26 +1128,6 @@ class ContactsManager final : public Actor {
vector<PendingGetPhotoRequest> pending_requests;
};
struct DialogNearby {
DialogId dialog_id;
int32 distance;
DialogNearby(DialogId dialog_id, int32 distance) : dialog_id(dialog_id), distance(distance) {
}
bool operator<(const DialogNearby &other) const {
return distance < other.distance || (distance == other.distance && dialog_id.get() < other.dialog_id.get());
}
bool operator==(const DialogNearby &other) const {
return distance == other.distance && dialog_id == other.dialog_id;
}
bool operator!=(const DialogNearby &other) const {
return !(*this == other);
}
};
struct RecommendedDialogs {
int32 total_count_ = 0;
vector<DialogId> dialog_ids_;
@ -1192,11 +1145,10 @@ class ContactsManager final : public Actor {
class ChannelLogEvent;
class SecretChatLogEvent;
static constexpr int32 MAX_GET_PROFILE_PHOTOS = 100; // server side limit
static constexpr size_t MAX_NAME_LENGTH = 64; // server side limit for first/last name
static constexpr size_t MAX_TITLE_LENGTH = 128; // server side limit for chat title
static constexpr size_t MAX_DESCRIPTION_LENGTH = 255; // server side limit for chat/channel description
static constexpr int32 MAX_GET_CHANNEL_PARTICIPANTS = 200; // server side limit
static constexpr int32 MAX_GET_PROFILE_PHOTOS = 100; // server side limit
static constexpr size_t MAX_NAME_LENGTH = 64; // server side limit for first/last name
static constexpr size_t MAX_TITLE_LENGTH = 128; // server side limit for chat title
static constexpr size_t MAX_DESCRIPTION_LENGTH = 255; // server side limit for chat/channel description
static constexpr int32 MAX_ACTIVE_STORY_ID_RELOAD_TIME = 3600; // some reasonable limit
static constexpr int32 CHANNEL_RECOMMENDATIONS_CACHE_TIME = 86400; // some reasonable limit
@ -1400,7 +1352,6 @@ 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);
@ -1415,9 +1366,6 @@ 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);
void on_set_emoji_status(EmojiStatus emoji_status, Promise<Unit> &&promise);
@ -1462,6 +1410,11 @@ class ContactsManager final : public Actor {
static void on_update_user_full_is_blocked(UserFull *user_full, UserId user_id, bool is_blocked,
bool is_blocked_for_stories);
static void on_update_user_full_common_chat_count(UserFull *user_full, UserId user_id, int32 common_chat_count);
static void on_update_user_full_location(UserFull *user_full, UserId user_id, DialogLocation &&location);
static void on_update_user_full_work_hours(UserFull *user_full, UserId user_id, BusinessWorkHours &&work_hours);
void on_update_user_full_away_message(UserFull *user_full, UserId user_id, BusinessAwayMessage &&away_message) const;
void on_update_user_full_greeting_message(UserFull *user_full, UserId user_id,
BusinessGreetingMessage &&greeting_message) const;
static void on_update_user_full_commands(UserFull *user_full, UserId user_id,
vector<tl_object_ptr<telegram_api::botCommand>> &&bot_commands);
static void on_update_user_full_menu_button(UserFull *user_full, UserId user_id,
@ -1522,8 +1475,6 @@ class ContactsManager final : public Actor {
StoryId max_read_story_id);
void on_update_channel_max_read_story_id(Channel *c, ChannelId channel_id, StoryId max_read_story_id);
void on_update_channel_bot_user_ids(ChannelId channel_id, vector<UserId> &&bot_user_ids);
void on_update_channel_full_photo(ChannelFull *channel_full, ChannelId channel_id, Photo photo);
void on_update_channel_full_invite_link(ChannelFull *channel_full,
tl_object_ptr<telegram_api::ExportedChatInvite> &&invite_link);
@ -1673,24 +1624,6 @@ class ContactsManager final : public Actor {
void on_clear_imported_contacts(vector<Contact> &&contacts, vector<size_t> contacts_unique_id,
std::pair<vector<size_t>, vector<Contact>> &&to_add, Promise<Unit> &&promise);
vector<td_api::object_ptr<td_api::chatNearby>> get_chats_nearby_object(
const vector<DialogNearby> &dialogs_nearby) const;
void send_update_users_nearby() const;
void on_get_dialogs_nearby(Result<tl_object_ptr<telegram_api::Updates>> result,
Promise<td_api::object_ptr<td_api::chatsNearby>> &&promise);
void try_send_set_location_visibility_query();
void on_set_location_visibility_expire_date(int32 set_expire_date, int32 error_code);
void set_location_visibility_expire_date(int32 expire_date);
void on_get_is_location_visible(Result<tl_object_ptr<telegram_api::Updates>> &&result, Promise<Unit> &&promise);
void update_is_location_visible();
bool is_suitable_recommended_channel(DialogId dialog_id) const;
bool is_suitable_recommended_channel(ChannelId channel_id) const;
@ -1735,16 +1668,8 @@ class ContactsManager final : public Actor {
vector<BotCommands> get_bot_commands(vector<tl_object_ptr<telegram_api::botInfo>> &&bot_infos,
const vector<DialogParticipant> *participants);
const DialogParticipant *get_chat_participant(ChatId chat_id, UserId user_id) const;
static const DialogParticipant *get_chat_full_participant(const ChatFull *chat_full, DialogId dialog_id);
std::pair<int32, vector<DialogId>> search_among_dialogs(const vector<DialogId> &dialog_ids, const string &query,
int32 limit) const;
DialogParticipants search_private_chat_participants(UserId my_user_id, UserId peer_user_id, const string &query,
int32 limit, DialogParticipantFilter filter) const;
void finish_get_chat_participant(ChatId chat_id, UserId user_id, Promise<DialogParticipant> &&promise);
void remove_dialog_suggested_action(SuggestedAction action);
@ -1763,6 +1688,10 @@ class ContactsManager final : public Actor {
tl_object_ptr<td_api::user> get_user_object(UserId user_id, const User *u) const;
tl_object_ptr<td_api::accessHash> get_user_access_hash_object(UserId user_id, const User *u) const;
tl_object_ptr<td_api::accessHash> get_channel_access_hash_object(ChannelId channel_id, const Channel *c) const;
tl_object_ptr<td_api::userFullInfo> get_user_full_info_object(UserId user_id, const UserFull *user_full) const;
td_api::object_ptr<td_api::updateBasicGroup> get_update_basic_group_object(ChatId chat_id, const Chat *c);
@ -1817,23 +1746,6 @@ class ContactsManager final : public Actor {
void update_dialogs_for_discussion(DialogId dialog_id, bool is_suitable);
void send_edit_chat_admin_query(ChatId chat_id, UserId user_id, bool is_administrator, Promise<Unit> &&promise);
void search_chat_participants(ChatId chat_id, const string &query, int32 limit, DialogParticipantFilter filter,
Promise<DialogParticipants> &&promise);
void do_search_chat_participants(ChatId chat_id, const string &query, int32 limit, DialogParticipantFilter filter,
Promise<DialogParticipants> &&promise);
void on_get_channel_participants(ChannelId channel_id, ChannelParticipantFilter &&filter, int32 offset, int32 limit,
string additional_query, int32 additional_limit,
tl_object_ptr<telegram_api::channels_channelParticipants> &&channel_participants,
Promise<DialogParticipants> &&promise);
void transfer_channel_ownership(ChannelId channel_id, UserId user_id,
tl_object_ptr<telegram_api::InputCheckPasswordSRP> input_check_password,
Promise<Unit> &&promise);
void get_channel_statistics_dc_id_impl(ChannelId channel_id, bool for_full_statistics, Promise<DcId> &&promise);
void on_get_support_user(UserId user_id, Promise<td_api::object_ptr<td_api::user>> &&promise);
@ -1846,8 +1758,6 @@ class ContactsManager final : public Actor {
static void on_channel_unban_timeout_callback(void *contacts_manager_ptr, int64 channel_id_long);
static void on_user_nearby_timeout_callback(void *contacts_manager_ptr, int64 user_id_long);
static void on_slow_mode_delay_timeout_callback(void *contacts_manager_ptr, int64 channel_id_long);
void on_user_online_timeout(UserId user_id);
@ -1858,12 +1768,8 @@ class ContactsManager final : public Actor {
void on_channel_unban_timeout(ChannelId channel_id);
void on_user_nearby_timeout(UserId user_id);
void on_slow_mode_delay_timeout(ChannelId channel_id);
void start_up() final;
void tear_down() final;
Td *td_;
@ -1981,8 +1887,6 @@ class ContactsManager final : public Actor {
FlatHashMap<int64, std::pair<vector<UserId>, vector<int32>>> imported_contacts_;
FlatHashMap<ChannelId, vector<DialogParticipant>, ChannelIdHash> cached_channel_participants_;
FlatHashMap<string, UserId> resolved_phone_numbers_;
FlatHashMap<UserId, FlatHashSet<MessageFullId, MessageFullIdHash>, UserIdHash> user_messages_;
@ -2005,15 +1909,6 @@ class ContactsManager final : public Actor {
bool are_imported_contacts_changing_ = false;
bool need_clear_imported_contacts_ = false;
vector<DialogNearby> users_nearby_;
vector<DialogNearby> channels_nearby_;
FlatHashSet<UserId, UserIdHash> all_users_nearby_;
int32 location_visibility_expire_date_ = 0;
int32 pending_location_visibility_expire_date_ = -1;
bool is_set_location_visibility_request_sent_ = false;
Location last_user_location_;
FlatHashMap<UserId, bool, UserIdHash> user_full_contact_require_premium_;
WaitFreeHashMap<ChannelId, ChannelId, ChannelIdHash> linked_channel_ids_;
@ -2032,7 +1927,6 @@ class ContactsManager final : public Actor {
MultiTimeout user_emoji_status_timeout_{"UserEmojiStatusTimeout"};
MultiTimeout channel_emoji_status_timeout_{"ChannelEmojiStatusTimeout"};
MultiTimeout channel_unban_timeout_{"ChannelUnbanTimeout"};
MultiTimeout user_nearby_timeout_{"UserNearbyTimeout"};
MultiTimeout slow_mode_delay_timeout_{"SlowModeDelayTimeout"};
};

View File

@ -610,4 +610,8 @@ FlatHashMap<string, unique_ptr<CountryInfoManager::CountryList>> CountryInfoMana
string CountryInfoManager::fragment_prefixes_str_;
vector<string> CountryInfoManager::fragment_prefixes_;
void CountryInfoManager::memory_stats(vector<string> &output) {
output.emplace_back("\"pending_load_country_queries_\":"); output.emplace_back(std::to_string(this->pending_load_country_queries_.size()));
}
} // namespace td

View File

@ -25,6 +25,7 @@ class Td;
class CountryInfoManager final : public Actor {
public:
void memory_stats(vector<string> &output);
CountryInfoManager(Td *td, ActorShared<> parent);
void get_countries(Promise<td_api::object_ptr<td_api::countries>> &&promise);

View File

@ -401,4 +401,10 @@ void DialogActionManager::clear_active_dialog_actions(DialogId dialog_id) {
}
}
void DialogActionManager::memory_stats(vector<string> &output) {
output.emplace_back("\"active_dialog_actions_\":"); output.emplace_back(std::to_string(this->active_dialog_actions_.size()));
output.emplace_back(",");
output.emplace_back("\"set_typing_query_\":"); output.emplace_back(std::to_string(this->set_typing_query_.size()));
}
} // namespace td

View File

@ -25,6 +25,7 @@ class Td;
class DialogActionManager final : public Actor {
public:
void memory_stats(vector<string> &output);
DialogActionManager(Td *td, ActorShared<> parent);
void on_dialog_action(DialogId dialog_id, MessageId top_thread_message_id, DialogId typing_dialog_id,

View File

@ -48,6 +48,7 @@ unique_ptr<DialogFilter> DialogFilter::get_dialog_filter(
dialog_filter->dialog_filter_id_ = dialog_filter_id;
dialog_filter->title_ = std::move(filter->title_);
dialog_filter->emoji_ = std::move(filter->emoticon_);
dialog_filter->color_id_ = (filter->flags_ & telegram_api::dialogFilter::COLOR_MASK) != 0 ? filter->color_ : -1;
dialog_filter->pinned_dialog_ids_ = InputDialogId::get_input_dialog_ids(filter->pinned_peers_, &added_dialog_ids);
dialog_filter->included_dialog_ids_ =
InputDialogId::get_input_dialog_ids(filter->include_peers_, &added_dialog_ids);
@ -62,6 +63,10 @@ unique_ptr<DialogFilter> DialogFilter::get_dialog_filter(
dialog_filter->include_bots_ = (flags & telegram_api::dialogFilter::BOTS_MASK) != 0;
dialog_filter->include_groups_ = (flags & telegram_api::dialogFilter::GROUPS_MASK) != 0;
dialog_filter->include_channels_ = (flags & telegram_api::dialogFilter::BROADCASTS_MASK) != 0;
if (!is_valid_color_id(dialog_filter->color_id_)) {
LOG(ERROR) << "Receive color " << dialog_filter->color_id_;
dialog_filter->color_id_ = -1;
}
return dialog_filter;
}
case telegram_api::dialogFilterChatlist::ID: {
@ -79,11 +84,17 @@ unique_ptr<DialogFilter> DialogFilter::get_dialog_filter(
dialog_filter->dialog_filter_id_ = dialog_filter_id;
dialog_filter->title_ = std::move(filter->title_);
dialog_filter->emoji_ = std::move(filter->emoticon_);
dialog_filter->color_id_ =
(filter->flags_ & telegram_api::dialogFilterChatlist::COLOR_MASK) != 0 ? filter->color_ : -1;
dialog_filter->pinned_dialog_ids_ = InputDialogId::get_input_dialog_ids(filter->pinned_peers_, &added_dialog_ids);
dialog_filter->included_dialog_ids_ =
InputDialogId::get_input_dialog_ids(filter->include_peers_, &added_dialog_ids);
dialog_filter->is_shareable_ = true;
dialog_filter->has_my_invites_ = filter->has_my_invites_;
if (!is_valid_color_id(dialog_filter->color_id_)) {
LOG(ERROR) << "Receive color " << dialog_filter->color_id_;
dialog_filter->color_id_ = -1;
}
return dialog_filter;
}
default:
@ -132,6 +143,10 @@ Result<unique_ptr<DialogFilter>> DialogFilter::create_dialog_filter(Td *td, Dial
if (dialog_filter->emoji_.empty() && !icon_name.empty()) {
return Status::Error(400, "Invalid icon name specified");
}
dialog_filter->color_id_ = filter->color_id_;
if (!is_valid_color_id(dialog_filter->color_id_)) {
return Status::Error(400, "Invalid color identifier specified");
}
dialog_filter->exclude_muted_ = filter->exclude_muted_;
dialog_filter->exclude_read_ = filter->exclude_read_;
dialog_filter->exclude_archived_ = filter->exclude_archived_;
@ -414,17 +429,23 @@ telegram_api::object_ptr<telegram_api::DialogFilter> DialogFilter::get_input_dia
if (!emoji_.empty()) {
flags |= telegram_api::dialogFilterChatlist::EMOTICON_MASK;
}
if (color_id_ != -1) {
flags |= telegram_api::dialogFilterChatlist::COLOR_MASK;
}
if (has_my_invites_) {
flags |= telegram_api::dialogFilterChatlist::HAS_MY_INVITES_MASK;
}
return telegram_api::make_object<telegram_api::dialogFilterChatlist>(
flags, false /*ignored*/, dialog_filter_id_.get(), title_, emoji_,
flags, false /*ignored*/, dialog_filter_id_.get(), title_, emoji_, color_id_,
InputDialogId::get_input_peers(pinned_dialog_ids_), InputDialogId::get_input_peers(included_dialog_ids_));
}
int32 flags = 0;
if (!emoji_.empty()) {
flags |= telegram_api::dialogFilter::EMOTICON_MASK;
}
if (color_id_ != -1) {
flags |= telegram_api::dialogFilter::COLOR_MASK;
}
if (exclude_muted_) {
flags |= telegram_api::dialogFilter::EXCLUDE_MUTED_MASK;
}
@ -452,7 +473,7 @@ telegram_api::object_ptr<telegram_api::DialogFilter> DialogFilter::get_input_dia
return telegram_api::make_object<telegram_api::dialogFilter>(
flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/,
false /*ignored*/, false /*ignored*/, false /*ignored*/, dialog_filter_id_.get(), title_, emoji_,
false /*ignored*/, false /*ignored*/, false /*ignored*/, dialog_filter_id_.get(), title_, emoji_, color_id_,
InputDialogId::get_input_peers(pinned_dialog_ids_), InputDialogId::get_input_peers(included_dialog_ids_),
InputDialogId::get_input_peers(excluded_dialog_ids_));
}
@ -477,15 +498,15 @@ td_api::object_ptr<td_api::chatFolder> DialogFilter::get_chat_folder_object(
icon = td_api::make_object<td_api::chatFolderIcon>(icon_name);
}
return td_api::make_object<td_api::chatFolder>(
title_, std::move(icon), is_shareable_, get_chat_ids(pinned_dialog_ids_), get_chat_ids(included_dialog_ids_),
get_chat_ids(excluded_dialog_ids_), exclude_muted_, exclude_read_, exclude_archived_, include_contacts_,
include_non_contacts_, include_bots_, include_groups_, include_channels_);
title_, std::move(icon), color_id_, is_shareable_, get_chat_ids(pinned_dialog_ids_),
get_chat_ids(included_dialog_ids_), get_chat_ids(excluded_dialog_ids_), exclude_muted_, exclude_read_,
exclude_archived_, include_contacts_, include_non_contacts_, include_bots_, include_groups_, include_channels_);
}
td_api::object_ptr<td_api::chatFolderInfo> DialogFilter::get_chat_folder_info_object() const {
return td_api::make_object<td_api::chatFolderInfo>(
dialog_filter_id_.get(), title_, td_api::make_object<td_api::chatFolderIcon>(get_chosen_or_default_icon_name()),
is_shareable_, has_my_invites_);
color_id_, is_shareable_, has_my_invites_);
}
void DialogFilter::for_each_dialog(std::function<void(const InputDialogId &)> callback) const {
@ -656,6 +677,7 @@ unique_ptr<DialogFilter> DialogFilter::merge_dialog_filter_changes(const DialogF
update_value(new_filter->title_, old_server_filter->title_, new_server_filter->title_);
update_value(new_filter->emoji_, old_server_filter->emoji_, new_server_filter->emoji_);
update_value(new_filter->color_id_, old_server_filter->color_id_, new_server_filter->color_id_);
LOG(INFO) << "Old local filter: " << *old_filter;
LOG(INFO) << "Old server filter: " << *old_server_filter;
@ -873,8 +895,8 @@ bool DialogFilter::are_similar(const DialogFilter &lhs, const DialogFilter &rhs)
}
bool DialogFilter::are_equivalent(const DialogFilter &lhs, const DialogFilter &rhs) {
return lhs.title_ == rhs.title_ && lhs.emoji_ == rhs.emoji_ && lhs.is_shareable_ == rhs.is_shareable_ &&
lhs.has_my_invites_ == rhs.has_my_invites_ &&
return lhs.title_ == rhs.title_ && lhs.emoji_ == rhs.emoji_ && lhs.color_id_ == rhs.color_id_ &&
lhs.is_shareable_ == rhs.is_shareable_ && lhs.has_my_invites_ == rhs.has_my_invites_ &&
InputDialogId::are_equivalent(lhs.pinned_dialog_ids_, rhs.pinned_dialog_ids_) &&
InputDialogId::are_equivalent(lhs.included_dialog_ids_, rhs.included_dialog_ids_) &&
InputDialogId::are_equivalent(lhs.excluded_dialog_ids_, rhs.excluded_dialog_ids_) && are_flags_equal(lhs, rhs);
@ -918,6 +940,10 @@ void DialogFilter::init_icon_names() {
CHECK(is_inited);
}
bool DialogFilter::is_valid_color_id(int32 color_id) {
return -1 <= color_id && color_id <= 6;
}
bool DialogFilter::are_flags_equal(const DialogFilter &lhs, const DialogFilter &rhs) {
return lhs.exclude_muted_ == rhs.exclude_muted_ && lhs.exclude_read_ == rhs.exclude_read_ &&
lhs.exclude_archived_ == rhs.exclude_archived_ && lhs.include_contacts_ == rhs.include_contacts_ &&

View File

@ -125,6 +125,7 @@ class DialogFilter {
vector<InputDialogId> pinned_dialog_ids_;
vector<InputDialogId> included_dialog_ids_;
vector<InputDialogId> excluded_dialog_ids_;
int32 color_id_ = -1;
bool exclude_muted_ = false;
bool exclude_read_ = false;
bool exclude_archived_ = false;
@ -139,6 +140,8 @@ class DialogFilter {
static FlatHashMap<string, string> emoji_to_icon_name_;
static FlatHashMap<string, string> icon_name_to_emoji_;
static bool is_valid_color_id(int32 color_id);
static bool are_flags_equal(const DialogFilter &lhs, const DialogFilter &rhs);
static void init_icon_names();
@ -152,9 +155,10 @@ class DialogFilter {
inline bool operator==(const DialogFilter &lhs, const DialogFilter &rhs) {
return lhs.dialog_filter_id_ == rhs.dialog_filter_id_ && lhs.title_ == rhs.title_ && lhs.emoji_ == rhs.emoji_ &&
lhs.is_shareable_ == rhs.is_shareable_ && lhs.has_my_invites_ == rhs.has_my_invites_ &&
lhs.pinned_dialog_ids_ == rhs.pinned_dialog_ids_ && lhs.included_dialog_ids_ == rhs.included_dialog_ids_ &&
lhs.excluded_dialog_ids_ == rhs.excluded_dialog_ids_ && DialogFilter::are_flags_equal(lhs, rhs);
lhs.color_id_ == rhs.color_id_ && lhs.is_shareable_ == rhs.is_shareable_ &&
lhs.has_my_invites_ == rhs.has_my_invites_ && lhs.pinned_dialog_ids_ == rhs.pinned_dialog_ids_ &&
lhs.included_dialog_ids_ == rhs.included_dialog_ids_ && lhs.excluded_dialog_ids_ == rhs.excluded_dialog_ids_ &&
DialogFilter::are_flags_equal(lhs, rhs);
}
inline bool operator!=(const DialogFilter &lhs, const DialogFilter &rhs) {

View File

@ -19,6 +19,7 @@ void DialogFilter::store(StorerT &storer) const {
bool has_pinned_dialog_ids = !pinned_dialog_ids_.empty();
bool has_included_dialog_ids = !included_dialog_ids_.empty();
bool has_excluded_dialog_ids = !excluded_dialog_ids_.empty();
bool has_color_id = color_id_ != -1;
BEGIN_STORE_FLAGS();
STORE_FLAG(exclude_muted_);
STORE_FLAG(exclude_read_);
@ -33,8 +34,8 @@ void DialogFilter::store(StorerT &storer) const {
STORE_FLAG(has_excluded_dialog_ids);
STORE_FLAG(is_shareable_);
STORE_FLAG(has_my_invites_);
STORE_FLAG(has_color_id);
END_STORE_FLAGS();
store(dialog_filter_id_, storer);
store(title_, storer);
store(emoji_, storer);
@ -47,6 +48,9 @@ void DialogFilter::store(StorerT &storer) const {
if (has_excluded_dialog_ids) {
store(excluded_dialog_ids_, storer);
}
if (has_color_id) {
store(color_id_, storer);
}
}
template <class ParserT>
@ -55,6 +59,7 @@ void DialogFilter::parse(ParserT &parser) {
bool has_pinned_dialog_ids;
bool has_included_dialog_ids;
bool has_excluded_dialog_ids;
bool has_color_id;
BEGIN_PARSE_FLAGS();
PARSE_FLAG(exclude_muted_);
PARSE_FLAG(exclude_read_);
@ -69,8 +74,8 @@ void DialogFilter::parse(ParserT &parser) {
PARSE_FLAG(has_excluded_dialog_ids);
PARSE_FLAG(is_shareable_);
PARSE_FLAG(has_my_invites_);
PARSE_FLAG(has_color_id);
END_PARSE_FLAGS();
parse(dialog_filter_id_, parser);
parse(title_, parser);
parse(emoji_, parser);
@ -83,6 +88,11 @@ void DialogFilter::parse(ParserT &parser) {
if (has_excluded_dialog_ids) {
parse(excluded_dialog_ids_, parser);
}
if (has_color_id) {
parse(color_id_, parser);
} else {
color_id_ = -1;
}
}
} // namespace td

View File

@ -40,10 +40,10 @@
namespace td {
class GetDialogFiltersQuery final : public Td::ResultHandler {
Promise<vector<tl_object_ptr<telegram_api::DialogFilter>>> promise_;
Promise<telegram_api::object_ptr<telegram_api::messages_dialogFilters>> promise_;
public:
explicit GetDialogFiltersQuery(Promise<vector<tl_object_ptr<telegram_api::DialogFilter>>> &&promise)
explicit GetDialogFiltersQuery(Promise<telegram_api::object_ptr<telegram_api::messages_dialogFilters>> &&promise)
: promise_(std::move(promise)) {
}
@ -127,6 +127,32 @@ class UpdateDialogFiltersOrderQuery final : public Td::ResultHandler {
}
};
class ToggleDialogFilterTagsQuery final : public Td::ResultHandler {
Promise<Unit> promise_;
public:
explicit ToggleDialogFilterTagsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
void send(bool are_tags_enabled) {
send_query(G()->net_query_creator().create(telegram_api::messages_toggleDialogFilterTags(are_tags_enabled)));
}
void on_result(BufferSlice packet) final {
auto result_ptr = fetch_result<telegram_api::messages_toggleDialogFilterTags>(packet);
if (result_ptr.is_error()) {
return on_error(result_ptr.move_as_error());
}
LOG(INFO) << "Receive result for ToggleDialogFilterTagsQuery: " << result_ptr.ok();
promise_.set_value(Unit());
}
void on_error(Status status) final {
promise_.set_error(std::move(status));
}
};
class ExportChatlistInviteQuery final : public Td::ResultHandler {
Promise<td_api::object_ptr<td_api::chatFolderInviteLink>> promise_;
@ -555,6 +581,8 @@ class DialogFilterManager::DialogFiltersLogEvent {
const vector<unique_ptr<DialogFilter>> *dialog_filters_in;
vector<unique_ptr<DialogFilter>> server_dialog_filters_out;
vector<unique_ptr<DialogFilter>> dialog_filters_out;
bool server_are_tags_enabled = false;
bool are_tags_enabled = false;
template <class StorerT>
void store(StorerT &storer) const {
@ -567,6 +595,8 @@ class DialogFilterManager::DialogFiltersLogEvent {
STORE_FLAG(has_dialog_filters);
STORE_FLAG(has_server_main_dialog_list_position);
STORE_FLAG(has_main_dialog_list_position);
STORE_FLAG(server_are_tags_enabled);
STORE_FLAG(are_tags_enabled);
END_STORE_FLAGS();
td::store(updated_date, storer);
if (has_server_dialog_filters) {
@ -595,6 +625,8 @@ class DialogFilterManager::DialogFiltersLogEvent {
PARSE_FLAG(has_dialog_filters);
PARSE_FLAG(has_server_main_dialog_list_position);
PARSE_FLAG(has_main_dialog_list_position);
PARSE_FLAG(server_are_tags_enabled);
PARSE_FLAG(are_tags_enabled);
END_PARSE_FLAGS();
}
td::parse(updated_date, parser);
@ -630,14 +662,22 @@ void DialogFilterManager::init() {
if (!dialog_filters.empty()) {
DialogFiltersLogEvent log_event;
if (log_event_parse(log_event, dialog_filters).is_ok()) {
server_are_tags_enabled_ = log_event.server_are_tags_enabled;
are_tags_enabled_ = log_event.are_tags_enabled;
server_main_dialog_list_position_ = log_event.server_main_dialog_list_position;
main_dialog_list_position_ = log_event.main_dialog_list_position;
if (!td_->option_manager_->get_option_boolean("is_premium") &&
(server_main_dialog_list_position_ != 0 || main_dialog_list_position_ != 0)) {
LOG(INFO) << "Ignore main chat list position " << server_main_dialog_list_position_ << '/'
<< main_dialog_list_position_;
server_main_dialog_list_position_ = 0;
main_dialog_list_position_ = 0;
if (!td_->option_manager_->get_option_boolean("is_premium")) {
if (server_main_dialog_list_position_ != 0 || main_dialog_list_position_ != 0) {
LOG(INFO) << "Ignore main chat list position " << server_main_dialog_list_position_ << '/'
<< main_dialog_list_position_;
server_main_dialog_list_position_ = 0;
main_dialog_list_position_ = 0;
}
if (server_are_tags_enabled_ || are_tags_enabled_) {
LOG(INFO) << "Ignore enabled tags " << server_are_tags_enabled_ << '/' << are_tags_enabled_;
server_are_tags_enabled_ = false;
are_tags_enabled_ = false;
}
}
dialog_filters_updated_date_ = td_->ignore_background_updates() ? 0 : log_event.updated_date;
@ -1134,7 +1174,7 @@ void DialogFilterManager::reload_dialog_filters() {
are_dialog_filters_being_reloaded_ = true;
need_dialog_filters_reload_ = false;
auto promise = PromiseCreator::lambda(
[actor_id = actor_id(this)](Result<vector<telegram_api::object_ptr<telegram_api::DialogFilter>>> r_filters) {
[actor_id = actor_id(this)](Result<telegram_api::object_ptr<telegram_api::messages_dialogFilters>> r_filters) {
send_closure(actor_id, &DialogFilterManager::on_get_dialog_filters, std::move(r_filters), false);
});
td_->create_handler<GetDialogFiltersQuery>(std::move(promise))->send();
@ -1187,7 +1227,7 @@ void DialogFilterManager::on_get_dialog_filter(telegram_api::object_ptr<telegram
}
void DialogFilterManager::on_get_dialog_filters(
Result<vector<telegram_api::object_ptr<telegram_api::DialogFilter>>> r_filters, bool dummy) {
Result<telegram_api::object_ptr<telegram_api::messages_dialogFilters>> r_filters, bool dummy) {
if (G()->close_flag()) {
return;
}
@ -1206,10 +1246,12 @@ void DialogFilterManager::on_get_dialog_filters(
return;
}
auto filters = r_filters.move_as_ok();
auto dialog_filters = r_filters.move_as_ok();
auto filters = std::move(dialog_filters->filters_);
vector<unique_ptr<DialogFilter>> new_server_dialog_filters;
LOG(INFO) << "Receive chat folders from server: " << to_string(filters);
std::unordered_set<DialogFilterId, DialogFilterIdHash> new_dialog_filter_ids;
bool server_are_tags_enabled = dialog_filters->tags_enabled_;
int32 server_main_dialog_list_position = -1;
int32 position = 0;
for (auto &filter : filters) {
@ -1242,6 +1284,10 @@ void DialogFilterManager::on_get_dialog_filters(
LOG(INFO) << "Ignore server main chat list position " << server_main_dialog_list_position;
server_main_dialog_list_position = 0;
}
if (server_are_tags_enabled && !td_->option_manager_->get_option_boolean("is_premium")) {
LOG(INFO) << "Ignore server enabled tags";
server_are_tags_enabled = false;
}
bool is_changed = false;
dialog_filters_updated_date_ = G()->unix_time();
@ -1363,6 +1409,15 @@ void DialogFilterManager::on_get_dialog_filters(
is_changed = true;
}
}
if (server_are_tags_enabled_ != server_are_tags_enabled) {
server_are_tags_enabled_ = server_are_tags_enabled;
if (server_are_tags_enabled != are_tags_enabled_) {
LOG(INFO) << "Change are_tags_enabled_ from " << are_tags_enabled_ << " to " << server_are_tags_enabled;
are_tags_enabled_ = server_are_tags_enabled;
is_changed = true;
}
}
if (is_changed || !is_update_chat_folders_sent_) {
send_update_chat_folders();
}
@ -1404,6 +1459,10 @@ bool DialogFilterManager::need_synchronize_dialog_filters() const {
// need reorder main chat list on server
return true;
}
if (are_tags_enabled_ != server_are_tags_enabled_) {
// need enable/disable tags
return true;
}
return false;
}
@ -1452,6 +1511,10 @@ void DialogFilterManager::synchronize_dialog_filters() {
return reorder_dialog_filters_on_server(std::move(dialog_filter_ids), server_main_dialog_list_position);
}
if (are_tags_enabled_ != server_are_tags_enabled_) {
return toggle_are_tags_enabled_on_server(are_tags_enabled_);
}
UNREACHABLE();
}
@ -1471,6 +1534,7 @@ td_api::object_ptr<td_api::updateChatFolders> DialogFilterManager::get_update_ch
update->chat_folders_.push_back(dialog_filter->get_chat_folder_info_object());
}
update->main_chat_list_position_ = main_dialog_list_position_;
update->are_tags_enabled_ = are_tags_enabled_;
return update;
}
@ -1779,6 +1843,50 @@ void DialogFilterManager::on_reorder_dialog_filters(vector<DialogFilterId> dialo
synchronize_dialog_filters();
}
void DialogFilterManager::toggle_dialog_filter_tags(bool are_tags_enabled, Promise<Unit> &&promise) {
if (!td_->option_manager_->get_option_boolean("is_premium")) {
if (!are_tags_enabled) {
return promise.set_value(Unit());
}
return promise.set_error(Status::Error(400, "Method not available"));
}
if (are_tags_enabled_ != are_tags_enabled) {
are_tags_enabled_ = are_tags_enabled;
save_dialog_filters();
send_update_chat_folders();
synchronize_dialog_filters();
}
promise.set_value(Unit());
}
void DialogFilterManager::toggle_are_tags_enabled_on_server(bool are_tags_enabled) {
CHECK(!td_->auth_manager_->is_bot());
are_dialog_filters_being_synchronized_ = true;
auto promise = PromiseCreator::lambda([actor_id = actor_id(this), are_tags_enabled](Result<Unit> result) mutable {
send_closure(actor_id, &DialogFilterManager::on_toggle_are_tags_enabled, are_tags_enabled,
result.is_error() ? result.move_as_error() : Status::OK());
});
td_->create_handler<ToggleDialogFilterTagsQuery>(std::move(promise))->send(are_tags_enabled);
}
void DialogFilterManager::on_toggle_are_tags_enabled(bool are_tags_enabled, Status result) {
CHECK(!td_->auth_manager_->is_bot());
if (result.is_error()) {
are_tags_enabled_ = !are_tags_enabled;
} else {
if (server_are_tags_enabled_ != are_tags_enabled) {
server_are_tags_enabled_ = are_tags_enabled;
save_dialog_filters();
}
}
are_dialog_filters_being_synchronized_ = false;
synchronize_dialog_filters();
}
void DialogFilterManager::add_dialog_filter(unique_ptr<DialogFilter> dialog_filter, bool at_beginning,
const char *source) {
if (td_->auth_manager_->is_bot()) {
@ -1846,6 +1954,8 @@ void DialogFilterManager::save_dialog_filters() {
}
DialogFiltersLogEvent log_event;
log_event.server_are_tags_enabled = server_are_tags_enabled_;
log_event.are_tags_enabled = are_tags_enabled_;
log_event.server_main_dialog_list_position = server_main_dialog_list_position_;
log_event.main_dialog_list_position = main_dialog_list_position_;
log_event.updated_date = dialog_filters_updated_date_;
@ -2009,7 +2119,7 @@ void DialogFilterManager::on_get_chatlist_invite(
icon_name = "Custom";
}
info = td_api::make_object<td_api::chatFolderInfo>(
0, invite->title_, td_api::make_object<td_api::chatFolderIcon>(icon_name), true, false);
0, invite->title_, td_api::make_object<td_api::chatFolderIcon>(icon_name), -1, true, false);
missing_peers = std::move(invite->peers_);
chats = std::move(invite->chats_);
users = std::move(invite->users_);
@ -2100,4 +2210,14 @@ void DialogFilterManager::get_current_state(vector<td_api::object_ptr<td_api::Up
}
}
void DialogFilterManager::memory_stats(vector<string> &output) {
output.emplace_back("\"server_dialog_filters_\":"); output.emplace_back(std::to_string(this->server_dialog_filters_.size()));
output.emplace_back(",");
output.emplace_back("\"dialog_filters_\":"); output.emplace_back(std::to_string(this->dialog_filters_.size()));
output.emplace_back(",");
output.emplace_back("\"dialog_filter_reload_queries_\":"); output.emplace_back(std::to_string(this->dialog_filter_reload_queries_.size()));
output.emplace_back(",");
output.emplace_back("\"recommended_dialog_filters_\":"); output.emplace_back(std::to_string(this->recommended_dialog_filters_.size()));
}
} // namespace td

View File

@ -28,6 +28,7 @@ class Td;
class DialogFilterManager final : public Actor {
public:
void memory_stats(vector<string> &output);
DialogFilterManager(Td *td, ActorShared<> parent);
DialogFilterManager(const DialogFilterManager &) = delete;
DialogFilterManager &operator=(const DialogFilterManager &) = delete;
@ -81,6 +82,8 @@ class DialogFilterManager final : public Actor {
void reorder_dialog_filters(vector<DialogFilterId> dialog_filter_ids, int32 main_dialog_list_position,
Promise<Unit> &&promise);
void toggle_dialog_filter_tags(bool are_tags_enabled, Promise<Unit> &&promise);
void get_dialogs_for_dialog_filter_invite_link(DialogFilterId dialog_filter_id,
Promise<td_api::object_ptr<td_api::chats>> promise);
@ -152,7 +155,7 @@ class DialogFilterManager final : public Actor {
void reload_dialog_filters();
void on_get_dialog_filters(Result<vector<telegram_api::object_ptr<telegram_api::DialogFilter>>> r_filters,
void on_get_dialog_filters(Result<telegram_api::object_ptr<telegram_api::messages_dialogFilters>> r_filters,
bool dummy);
bool need_synchronize_dialog_filters() const;
@ -186,6 +189,10 @@ class DialogFilterManager final : public Actor {
void on_reorder_dialog_filters(vector<DialogFilterId> dialog_filter_ids, int32 main_dialog_list_position,
Status result);
void toggle_are_tags_enabled_on_server(bool are_tags_enabled);
void on_toggle_are_tags_enabled(bool are_tags_enabled, Status result);
void save_dialog_filters();
void add_dialog_filter(unique_ptr<DialogFilter> dialog_filter, bool at_beginning, const char *source);
@ -227,6 +234,8 @@ class DialogFilterManager final : public Actor {
bool need_dialog_filters_reload_ = false;
bool disable_get_dialog_filter_ = false;
bool is_update_chat_folders_sent_ = false;
bool server_are_tags_enabled_ = false;
bool are_tags_enabled_ = false;
int32 dialog_filters_updated_date_ = 0;
vector<unique_ptr<DialogFilter>> server_dialog_filters_;
vector<unique_ptr<DialogFilter>> dialog_filters_;

View File

@ -1097,4 +1097,10 @@ void DialogInviteLinkManager::delete_all_revoked_dialog_invite_links(DialogId di
->send(dialog_id, std::move(input_user));
}
void DialogInviteLinkManager::memory_stats(vector<string> &output) {
output.emplace_back("\"invite_link_infos_\":"); output.emplace_back(std::to_string(this->invite_link_infos_.size()));
output.emplace_back(",");
output.emplace_back("\"dialog_access_by_invite_link_\":"); output.emplace_back(std::to_string(this->dialog_access_by_invite_link_.size()));
}
} // namespace td

View File

@ -28,6 +28,7 @@ class Td;
class DialogInviteLinkManager final : public Actor {
public:
void memory_stats(vector<string> &output);
DialogInviteLinkManager(Td *td, ActorShared<> parent);
DialogInviteLinkManager(const DialogInviteLinkManager &) = delete;
DialogInviteLinkManager &operator=(const DialogInviteLinkManager &) = delete;

View File

@ -18,6 +18,13 @@ DialogLocation::DialogLocation(Td *td, telegram_api::object_ptr<telegram_api::Ch
}
}
DialogLocation::DialogLocation(Td *td, telegram_api::object_ptr<telegram_api::businessLocation> &&business_location) {
if (business_location != nullptr) {
location_ = Location(td, business_location->geo_point_);
address_ = std::move(business_location->address_);
}
}
DialogLocation::DialogLocation(td_api::object_ptr<td_api::chatLocation> &&chat_location) {
if (chat_location != nullptr) {
location_ = Location(chat_location->location_);
@ -28,6 +35,16 @@ DialogLocation::DialogLocation(td_api::object_ptr<td_api::chatLocation> &&chat_l
}
}
DialogLocation::DialogLocation(td_api::object_ptr<td_api::businessLocation> &&business_location) {
if (business_location != nullptr) {
location_ = Location(business_location->location_);
address_ = std::move(business_location->address_);
if (!clean_input_string(address_)) {
address_.clear();
}
}
}
bool DialogLocation::empty() const {
return location_.empty();
}
@ -39,6 +56,13 @@ td_api::object_ptr<td_api::chatLocation> DialogLocation::get_chat_location_objec
return td_api::make_object<td_api::chatLocation>(location_.get_location_object(), address_);
}
td_api::object_ptr<td_api::businessLocation> DialogLocation::get_business_location_object() const {
if (empty() && address_.empty()) {
return nullptr;
}
return td_api::make_object<td_api::businessLocation>(location_.get_location_object(), address_);
}
telegram_api::object_ptr<telegram_api::InputGeoPoint> DialogLocation::get_input_geo_point() const {
return location_.get_input_geo_point();
}

View File

@ -32,12 +32,18 @@ class DialogLocation {
DialogLocation(Td *td, telegram_api::object_ptr<telegram_api::ChannelLocation> &&channel_location_ptr);
DialogLocation(Td *td, telegram_api::object_ptr<telegram_api::businessLocation> &&business_location);
explicit DialogLocation(td_api::object_ptr<td_api::chatLocation> &&chat_location);
explicit DialogLocation(td_api::object_ptr<td_api::businessLocation> &&business_location);
bool empty() const;
td_api::object_ptr<td_api::chatLocation> get_chat_location_object() const;
td_api::object_ptr<td_api::businessLocation> get_business_location_object() const;
telegram_api::object_ptr<telegram_api::InputGeoPoint> get_input_geo_point() const;
const string &get_address() const;

View File

@ -17,6 +17,7 @@
#include "td/telegram/Global.h"
#include "td/telegram/MessagesManager.h"
#include "td/telegram/misc.h"
#include "td/telegram/OptionManager.h"
#include "td/telegram/ReportReason.h"
#include "td/telegram/SecretChatId.h"
#include "td/telegram/SecretChatsManager.h"
@ -103,15 +104,13 @@ class CheckChannelUsernameQuery final : public Td::ResultHandler {
};
class ResolveUsernameQuery final : public Td::ResultHandler {
Promise<Unit> promise_;
string username_;
Promise<DialogId> promise_;
public:
explicit ResolveUsernameQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
explicit ResolveUsernameQuery(Promise<DialogId> &&promise) : promise_(std::move(promise)) {
}
void send(const string &username) {
username_ = username;
send_query(G()->net_query_creator().create(telegram_api::contacts_resolveUsername(username)));
}
@ -126,15 +125,10 @@ class ResolveUsernameQuery final : public Td::ResultHandler {
td_->contacts_manager_->on_get_users(std::move(ptr->users_), "ResolveUsernameQuery");
td_->contacts_manager_->on_get_chats(std::move(ptr->chats_), "ResolveUsernameQuery");
td_->dialog_manager_->on_resolved_username(username_, DialogId(ptr->peer_));
promise_.set_value(Unit());
promise_.set_value(DialogId(ptr->peer_));
}
void on_error(Status status) final {
if (status.message() == Slice("USERNAME_NOT_OCCUPIED")) {
td_->dialog_manager_->drop_username(username_);
}
promise_.set_error(std::move(status));
}
};
@ -689,6 +683,19 @@ bool DialogManager::have_dialog_info(DialogId dialog_id) const {
}
}
bool DialogManager::is_dialog_info_received_from_server(DialogId dialog_id) const {
switch (dialog_id.get_type()) {
case DialogType::User:
return td_->contacts_manager_->is_user_received_from_server(dialog_id.get_user_id());
case DialogType::Chat:
return td_->contacts_manager_->is_chat_received_from_server(dialog_id.get_chat_id());
case DialogType::Channel:
return td_->contacts_manager_->is_channel_received_from_server(dialog_id.get_channel_id());
default:
return false;
}
}
bool DialogManager::have_dialog_info_force(DialogId dialog_id, const char *source) const {
switch (dialog_id.get_type()) {
case DialogType::User: {
@ -1107,6 +1114,24 @@ string DialogManager::get_dialog_about(DialogId dialog_id) {
}
}
string DialogManager::get_dialog_search_text(DialogId dialog_id) const {
switch (dialog_id.get_type()) {
case DialogType::User:
return td_->contacts_manager_->get_user_search_text(dialog_id.get_user_id());
case DialogType::Chat:
return td_->contacts_manager_->get_chat_title(dialog_id.get_chat_id());
case DialogType::Channel:
return td_->contacts_manager_->get_channel_search_text(dialog_id.get_channel_id());
case DialogType::SecretChat:
return td_->contacts_manager_->get_user_search_text(
td_->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id()));
case DialogType::None:
default:
UNREACHABLE();
}
return string();
}
bool DialogManager::get_dialog_has_protected_content(DialogId dialog_id) const {
switch (dialog_id.get_type()) {
case DialogType::User:
@ -1607,6 +1632,24 @@ void DialogManager::set_dialog_description(DialogId dialog_id, const string &des
}
}
void DialogManager::set_dialog_location(DialogId dialog_id, const DialogLocation &location, Promise<Unit> &&promise) {
if (!have_dialog_force(dialog_id, "set_dialog_location")) {
return promise.set_error(Status::Error(400, "Chat not found"));
}
switch (dialog_id.get_type()) {
case DialogType::User:
case DialogType::Chat:
case DialogType::SecretChat:
return promise.set_error(Status::Error(400, "The chat can't have location"));
case DialogType::Channel:
return td_->contacts_manager_->set_channel_location(dialog_id.get_channel_id(), location, std::move(promise));
case DialogType::None:
default:
UNREACHABLE();
}
}
bool DialogManager::can_report_dialog(DialogId dialog_id) const {
// doesn't include possibility of report from action bar
switch (dialog_id.get_type()) {
@ -1730,6 +1773,21 @@ Status DialogManager::can_pin_messages(DialogId dialog_id) const {
return Status::OK();
}
bool DialogManager::can_use_premium_custom_emoji_in_dialog(DialogId dialog_id) const {
if (!td_->auth_manager_->is_bot()) {
if (dialog_id == get_my_dialog_id() || td_->option_manager_->get_option_boolean("is_premium")) {
return true;
}
if (dialog_id.get_type() == DialogType::Channel &&
td_->contacts_manager_->can_use_premium_custom_emoji_in_channel(dialog_id.get_channel_id())) {
return true;
}
return false;
}
auto user_id = td_->contacts_manager_->get_my_id();
return !td_->contacts_manager_->have_user(user_id) || td_->contacts_manager_->has_user_fragment_username(user_id);
}
bool DialogManager::is_dialog_removed_from_dialog_list(DialogId dialog_id) const {
switch (dialog_id.get_type()) {
case DialogType::User:
@ -1748,6 +1806,40 @@ bool DialogManager::is_dialog_removed_from_dialog_list(DialogId dialog_id) const
return false;
}
void DialogManager::on_update_dialog_bot_commands(
DialogId dialog_id, UserId bot_user_id, vector<telegram_api::object_ptr<telegram_api::botCommand>> &&bot_commands) {
if (!bot_user_id.is_valid()) {
LOG(ERROR) << "Receive updateBotCommands about invalid " << bot_user_id;
return;
}
if (!td_->contacts_manager_->have_user_force(bot_user_id, "on_update_dialog_bot_commands") ||
!td_->contacts_manager_->is_user_bot(bot_user_id)) {
return;
}
if (td_->auth_manager_->is_bot()) {
return;
}
switch (dialog_id.get_type()) {
case DialogType::User:
if (DialogId(bot_user_id) != dialog_id) {
LOG(ERROR) << "Receive commands of " << bot_user_id << " in " << dialog_id;
return;
}
return td_->contacts_manager_->on_update_user_commands(bot_user_id, std::move(bot_commands));
case DialogType::Chat:
return td_->contacts_manager_->on_update_chat_bot_commands(dialog_id.get_chat_id(),
BotCommands(bot_user_id, std::move(bot_commands)));
case DialogType::Channel:
return td_->contacts_manager_->on_update_channel_bot_commands(dialog_id.get_channel_id(),
BotCommands(bot_user_id, std::move(bot_commands)));
case DialogType::SecretChat:
default:
LOG(ERROR) << "Receive updateBotCommands in " << dialog_id;
break;
}
}
void DialogManager::on_dialog_usernames_updated(DialogId dialog_id, const Usernames &old_usernames,
const Usernames &new_usernames) {
LOG(INFO) << "Update usernames in " << dialog_id << " from " << old_usernames << " to " << new_usernames;
@ -1876,7 +1968,54 @@ td_api::object_ptr<td_api::CheckChatUsernameResult> DialogManager::get_check_cha
}
void DialogManager::send_resolve_dialog_username_query(const string &username, Promise<Unit> &&promise) {
td_->create_handler<ResolveUsernameQuery>(std::move(promise))->send(username);
CHECK(!username.empty());
auto &queries = resolve_dialog_username_queries_[username];
queries.push_back(std::move(promise));
if (queries.size() != 1u) {
return;
}
auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), username](Result<DialogId> r_dialog_id) {
send_closure(actor_id, &DialogManager::on_resolved_username, username, std::move(r_dialog_id));
});
td_->create_handler<ResolveUsernameQuery>(std::move(query_promise))->send(username);
}
void DialogManager::on_resolved_username(const string &username, Result<DialogId> r_dialog_id) {
G()->ignore_result_if_closing(r_dialog_id);
auto it = resolve_dialog_username_queries_.find(username);
CHECK(it != resolve_dialog_username_queries_.end());
auto promises = std::move(it->second);
CHECK(!promises.empty());
resolve_dialog_username_queries_.erase(it);
if (r_dialog_id.is_error()) {
auto error_message = r_dialog_id.error().message();
if (error_message == Slice("USERNAME_NOT_OCCUPIED") || error_message == Slice("USERNAME_INVALID")) {
drop_username(username);
}
return fail_promises(promises, r_dialog_id.move_as_error());
}
auto dialog_id = r_dialog_id.ok();
if (!dialog_id.is_valid()) {
LOG(ERROR) << "Resolve username \"" << username << "\" to invalid " << dialog_id;
return fail_promises(promises, Status::Error(500, "Chat not found"));
}
auto cleaned_username = clean_username(username);
if (cleaned_username.empty()) {
return fail_promises(promises, Status::Error(500, "Invalid username"));
}
auto resolved_username = resolved_usernames_.get(cleaned_username);
if (resolved_username.dialog_id.is_valid()) {
LOG_IF(ERROR, resolved_username.dialog_id != dialog_id)
<< "Resolve username \"" << username << "\" to " << dialog_id << ", but have it in "
<< resolved_username.dialog_id;
return set_promises(promises);
}
inaccessible_resolved_usernames_[cleaned_username] = dialog_id;
set_promises(promises);
}
void DialogManager::resolve_dialog(const string &username, ChannelId channel_id, Promise<DialogId> promise) {
@ -2002,28 +2141,6 @@ void DialogManager::reload_voice_chat_on_search(const string &username) {
}
}
void DialogManager::on_resolved_username(const string &username, DialogId dialog_id) {
if (!dialog_id.is_valid()) {
LOG(ERROR) << "Resolve username \"" << username << "\" to invalid " << dialog_id;
return;
}
auto cleaned_username = clean_username(username);
if (cleaned_username.empty()) {
return;
}
auto resolved_username = resolved_usernames_.get(cleaned_username);
if (resolved_username.dialog_id.is_valid()) {
LOG_IF(ERROR, resolved_username.dialog_id != dialog_id)
<< "Resolve username \"" << username << "\" to " << dialog_id << ", but have it in "
<< resolved_username.dialog_id;
return;
}
inaccessible_resolved_usernames_[cleaned_username] = dialog_id;
}
void DialogManager::drop_username(const string &username) {
auto cleaned_username = clean_username(username);
if (cleaned_username.empty()) {
@ -2044,4 +2161,16 @@ void DialogManager::drop_username(const string &username) {
}
}
void DialogManager::memory_stats(vector<string> &output) {
output.emplace_back("\"being_uploaded_dialog_photos_\":"); output.emplace_back(std::to_string(this->being_uploaded_dialog_photos_.size()));
output.emplace_back(",");
output.emplace_back("\"resolved_usernames_\":"); output.emplace_back(std::to_string(this->resolved_usernames_.calc_size()));
output.emplace_back(",");
output.emplace_back("\"inaccessible_resolved_usernames_\":"); output.emplace_back(std::to_string(this->inaccessible_resolved_usernames_.calc_size()));
output.emplace_back(",");
output.emplace_back("\"reload_voice_chat_on_search_usernames_\":"); output.emplace_back(std::to_string(this->reload_voice_chat_on_search_usernames_.size()));
output.emplace_back(",");
output.emplace_back("\"resolve_dialog_username_queries_\":"); output.emplace_back(std::to_string(this->resolve_dialog_username_queries_.size()));
}
} // namespace td

View File

@ -11,6 +11,7 @@
#include "td/telegram/ChannelId.h"
#include "td/telegram/CustomEmojiId.h"
#include "td/telegram/DialogId.h"
#include "td/telegram/DialogLocation.h"
#include "td/telegram/DialogParticipant.h"
#include "td/telegram/EmojiStatus.h"
#include "td/telegram/files/FileId.h"
@ -41,6 +42,7 @@ class Usernames;
class DialogManager final : public Actor {
public:
void memory_stats(vector<string> &output);
DialogManager(Td *td, ActorShared<> parent);
DialogManager(const DialogManager &) = delete;
DialogManager &operator=(const DialogManager &) = delete;
@ -84,6 +86,8 @@ class DialogManager final : public Actor {
void reload_dialog_info(DialogId dialog_id, Promise<Unit> &&promise);
bool is_dialog_info_received_from_server(DialogId dialog_id) const;
void get_dialog_info_full(DialogId dialog_id, Promise<Unit> &&promise, const char *source);
void reload_dialog_info_full(DialogId dialog_id, const char *source);
@ -134,6 +138,8 @@ class DialogManager final : public Actor {
string get_dialog_about(DialogId dialog_id);
string get_dialog_search_text(DialogId dialog_id) const;
bool get_dialog_has_protected_content(DialogId dialog_id) const;
bool is_dialog_action_unneeded(DialogId dialog_id) const;
@ -158,6 +164,8 @@ class DialogManager final : public Actor {
void set_dialog_description(DialogId dialog_id, const string &description, Promise<Unit> &&promise);
void set_dialog_location(DialogId dialog_id, const DialogLocation &location, Promise<Unit> &&promise);
bool can_report_dialog(DialogId dialog_id) const;
void report_dialog(DialogId dialog_id, const vector<MessageId> &message_ids, ReportReason &&reason,
@ -167,11 +175,16 @@ class DialogManager final : public Actor {
Status can_pin_messages(DialogId dialog_id) const;
bool can_use_premium_custom_emoji_in_dialog(DialogId dialog_id) const;
bool is_dialog_removed_from_dialog_list(DialogId dialog_id) const;
void upload_dialog_photo(DialogId dialog_id, FileId file_id, bool is_animation, double main_frame_timestamp,
bool is_reupload, Promise<Unit> &&promise, vector<int> bad_parts = {});
void on_update_dialog_bot_commands(DialogId dialog_id, UserId bot_user_id,
vector<telegram_api::object_ptr<telegram_api::botCommand>> &&bot_commands);
void on_dialog_usernames_updated(DialogId dialog_id, const Usernames &old_usernames, const Usernames &new_usernames);
void on_dialog_usernames_received(DialogId dialog_id, const Usernames &usernames, bool from_database);
@ -199,10 +212,6 @@ class DialogManager final : public Actor {
void reload_voice_chat_on_search(const string &username);
void on_resolved_username(const string &username, DialogId dialog_id);
void drop_username(const string &username);
private:
static constexpr size_t MAX_TITLE_LENGTH = 128; // server side limit for chat title
@ -220,6 +229,10 @@ class DialogManager final : public Actor {
void send_resolve_dialog_username_query(const string &username, Promise<Unit> &&promise);
void on_resolved_username(const string &username, Result<DialogId> r_dialog_id);
void drop_username(const string &username);
void on_resolve_dialog(const string &username, ChannelId channel_id, Promise<DialogId> &&promise);
class UploadDialogPhotoCallback;
@ -255,6 +268,8 @@ class DialogManager final : public Actor {
WaitFreeHashMap<string, DialogId> inaccessible_resolved_usernames_;
FlatHashSet<string> reload_voice_chat_on_search_usernames_;
FlatHashMap<string, vector<Promise<Unit>>> resolve_dialog_username_queries_;
Td *td_;
ActorShared<> parent_;
};

File diff suppressed because it is too large Load Diff

View File

@ -12,6 +12,7 @@
#include "td/telegram/DialogId.h"
#include "td/telegram/DialogInviteLink.h"
#include "td/telegram/DialogParticipant.h"
#include "td/telegram/DialogParticipantFilter.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/telegram/UserId.h"
@ -24,12 +25,17 @@
#include "td/utils/Promise.h"
#include "td/utils/Status.h"
#include <utility>
namespace td {
class ChannelParticipantFilter;
class Td;
class DialogParticipantManager final : public Actor {
public:
void memory_stats(vector<string> &output);
DialogParticipantManager(Td *td, ActorShared<> parent);
DialogParticipantManager(const DialogParticipantManager &) = delete;
DialogParticipantManager &operator=(const DialogParticipantManager &) = delete;
@ -44,6 +50,14 @@ class DialogParticipantManager final : public Actor {
void on_update_dialog_online_member_count(DialogId dialog_id, int32 online_member_count, bool is_from_server);
void add_cached_channel_participants(ChannelId channel_id, const vector<UserId> &added_user_ids,
UserId inviter_user_id, int32 date);
void delete_cached_channel_participant(ChannelId channel_id, UserId deleted_user_id);
void update_cached_channel_participant_status(ChannelId channel_id, UserId user_id,
const DialogParticipantStatus &status);
void on_dialog_opened(DialogId dialog_id);
void on_dialog_closed(DialogId dialog_id);
@ -89,6 +103,13 @@ class DialogParticipantManager final : public Actor {
void get_channel_participant(ChannelId channel_id, DialogId participant_dialog_id,
Promise<DialogParticipant> &&promise);
void get_channel_participants(ChannelId channel_id, td_api::object_ptr<td_api::SupergroupMembersFilter> &&filter,
string additional_query, int32 offset, int32 limit, int32 additional_limit,
Promise<DialogParticipants> &&promise);
void search_dialog_participants(DialogId dialog_id, const string &query, int32 limit, DialogParticipantFilter filter,
Promise<DialogParticipants> &&promise);
void add_dialog_participant(DialogId dialog_id, UserId user_id, int32 forward_limit, Promise<Unit> &&promise);
void add_dialog_participants(DialogId dialog_id, const vector<UserId> &user_ids, Promise<Unit> &&promise);
@ -114,6 +135,18 @@ class DialogParticipantManager final : public Actor {
void drop_channel_participant_cache(ChannelId channel_id);
struct CanTransferOwnershipResult {
enum class Type : uint8 { Ok, PasswordNeeded, PasswordTooFresh, SessionTooFresh };
Type type = Type::Ok;
int32 retry_after = 0;
};
void can_transfer_ownership(Promise<CanTransferOwnershipResult> &&promise);
static td_api::object_ptr<td_api::CanTransferOwnershipResult> get_can_transfer_ownership_result_object(
CanTransferOwnershipResult result);
void transfer_dialog_ownership(DialogId dialog_id, UserId user_id, const string &password, Promise<Unit> &&promise);
void get_current_state(vector<td_api::object_ptr<td_api::Update>> &updates) const;
private:
@ -123,6 +156,8 @@ class DialogParticipantManager final : public Actor {
static constexpr int32 CHANNEL_PARTICIPANT_CACHE_TIME = 1800; // some reasonable limit
static constexpr int32 MAX_GET_CHANNEL_PARTICIPANTS = 200; // server side limit
void tear_down() final;
static void on_update_dialog_online_member_count_timeout_callback(void *dialog_participant_manager_ptr,
@ -166,6 +201,33 @@ class DialogParticipantManager final : public Actor {
void finish_get_channel_participant(ChannelId channel_id, DialogParticipant &&dialog_participant,
Promise<DialogParticipant> &&promise);
std::pair<int32, vector<DialogId>> search_among_dialogs(const vector<DialogId> &dialog_ids, const string &query,
int32 limit) const;
DialogParticipants search_private_chat_participants(UserId peer_user_id, const string &query, int32 limit,
DialogParticipantFilter filter) const;
void search_chat_participants(ChatId chat_id, const string &query, int32 limit, DialogParticipantFilter filter,
Promise<DialogParticipants> &&promise);
void do_search_chat_participants(ChatId chat_id, const string &query, int32 limit, DialogParticipantFilter filter,
Promise<DialogParticipants> &&promise);
void on_get_channel_participants(
ChannelId channel_id, ChannelParticipantFilter &&filter, int32 offset, int32 limit, string additional_query,
int32 additional_limit,
telegram_api::object_ptr<telegram_api::channels_channelParticipants> &&channel_participants,
Promise<DialogParticipants> &&promise);
void set_chat_participant_status(ChatId chat_id, UserId user_id, DialogParticipantStatus status, bool is_recursive,
Promise<Unit> &&promise);
void add_chat_participant(ChatId chat_id, UserId user_id, int32 forward_limit, Promise<Unit> &&promise);
void send_edit_chat_admin_query(ChatId chat_id, UserId user_id, bool is_administrator, Promise<Unit> &&promise);
void delete_chat_participant(ChatId chat_id, UserId user_id, bool revoke_messages, Promise<Unit> &&promise);
void add_channel_participant(ChannelId channel_id, UserId user_id, const DialogParticipantStatus &old_status,
Promise<Unit> &&promise);
@ -201,6 +263,16 @@ class DialogParticipantManager final : public Actor {
void on_channel_participant_cache_timeout(ChannelId channel_id);
void set_cached_channel_participants(ChannelId channel_id, vector<DialogParticipant> participants);
void drop_cached_channel_participants(ChannelId channel_id);
void update_channel_online_member_count(ChannelId channel_id, bool is_from_server);
void transfer_channel_ownership(ChannelId channel_id, UserId user_id,
tl_object_ptr<telegram_api::InputCheckPasswordSRP> input_check_password,
Promise<Unit> &&promise);
struct OnlineMemberCountInfo {
int32 online_member_count = 0;
double update_time = 0;
@ -226,6 +298,8 @@ class DialogParticipantManager final : public Actor {
};
FlatHashMap<ChannelId, ChannelParticipants, ChannelIdHash> channel_participants_;
FlatHashMap<ChannelId, vector<DialogParticipant>, ChannelIdHash> cached_channel_participants_;
FlatHashMap<ChannelId, vector<Promise<Unit>>, ChannelIdHash> join_channel_queries_;
MultiTimeout update_dialog_online_member_count_timeout_{"UpdateDialogOnlineMemberCountTimeout"};

View File

@ -13,6 +13,7 @@
#include "td/telegram/Td.h"
#include "td/telegram/VideoNotesManager.h"
#include "td/telegram/VideosManager.h"
#include "td/telegram/Global.h"
#include "td/utils/algorithm.h"
@ -36,24 +37,26 @@ void Document::append_file_ids(const Td *td, vector<FileId> &file_ids) const {
file_ids.push_back(file_id);
FileId thumbnail_file_id = [&] {
switch (type) {
case Type::Animation:
return td->animations_manager_->get_animation_thumbnail_file_id(file_id);
case Type::Audio:
return td->audios_manager_->get_audio_thumbnail_file_id(file_id);
case Type::General:
return td->documents_manager_->get_document_thumbnail_file_id(file_id);
case Type::Video:
return td->videos_manager_->get_video_thumbnail_file_id(file_id);
case Type::VideoNote:
return td->video_notes_manager_->get_video_note_thumbnail_file_id(file_id);
default:
return FileId();
if (!G()->get_option_boolean("disable_minithumbnails")) {
FileId thumbnail_file_id = [&] {
switch (type) {
case Type::Animation:
return td->animations_manager_->get_animation_thumbnail_file_id(file_id);
case Type::Audio:
return td->audios_manager_->get_audio_thumbnail_file_id(file_id);
case Type::General:
return td->documents_manager_->get_document_thumbnail_file_id(file_id);
case Type::Video:
return td->videos_manager_->get_video_thumbnail_file_id(file_id);
case Type::VideoNote:
return td->video_notes_manager_->get_video_note_thumbnail_file_id(file_id);
default:
return FileId();
}
}();
if (thumbnail_file_id.is_valid()) {
file_ids.push_back(thumbnail_file_id);
}
}();
if (thumbnail_file_id.is_valid()) {
file_ids.push_back(thumbnail_file_id);
}
FileId animated_thumbnail_file_id = [&] {

View File

@ -757,6 +757,7 @@ void DocumentsManager::merge_documents(FileId new_id, FileId old_id) {
LOG_STATUS(td_->file_manager_->merge(new_id, old_id));
}
string DocumentsManager::get_document_search_text(FileId file_id) const {
auto document = get_document(file_id);
CHECK(document);
@ -778,4 +779,8 @@ string DocumentsManager::get_document_search_text(FileId file_id) const {
return sb.as_cslice().str();
}
void DocumentsManager::memory_stats(vector<string> &output) {
output.emplace_back("\"documents_\":"); output.emplace_back(std::to_string(this->documents_.calc_size()));
}
} // namespace td

Some files were not shown because too many files have changed in this diff Show More