diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 517bb81a8..3341e1dda 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -2066,6 +2066,9 @@ callStateDiscarded reason:CallDiscardReason need_rating:Bool need_debug_informat callStateError error:error = CallState; +//@description Describes a recently speaking user in a group call @user_id User identifier @is_speaking True, is the user has spoken recently +groupCallRecentSpeaker user_id:int32 is_speaking:Bool = GroupCallRecentSpeaker; + //@description Describes a group call //@id Group call identifier //@is_active True, if the call is active @@ -2075,11 +2078,11 @@ callStateError error:error = CallState; //@can_be_managed True, if the current user can manage the group call //@participant_count Number of participants in the group call //@loaded_all_participants True, if all group call participants are loaded -//@recent_speaker_user_ids Identifiers of recently speaking users in the group call +//@recent_speakers Recently speaking users in the group call //@mute_new_participants True, if only group call administrators can unmute new participants //@allowed_change_mute_new_participants True, if group call administrators can enable or disable mute_new_participants setting //@duration Call duration; for ended calls only -groupCall id:int32 is_active:Bool is_joined:Bool need_rejoin:Bool can_unmute_self:Bool can_be_managed:Bool participant_count:int32 loaded_all_participants:Bool recent_speaker_user_ids:vector mute_new_participants:Bool allowed_change_mute_new_participants:Bool duration:int32 = GroupCall; +groupCall id:int32 is_active:Bool is_joined:Bool need_rejoin:Bool can_unmute_self:Bool can_be_managed:Bool participant_count:int32 loaded_all_participants:Bool recent_speakers:vector mute_new_participants:Bool allowed_change_mute_new_participants:Bool duration:int32 = GroupCall; //@description Describes a payload fingerprint for interaction with tgcalls @hash Value of the field hash @setup Value of the field setup @fingerprint Value of the field fingerprint groupCallPayloadFingerprint hash:string setup:string fingerprint:string = GroupCallPayloadFingerprint; @@ -4398,9 +4401,6 @@ setGroupCallParticipantIsSpeaking group_call_id:int32 source:int32 is_speaking:B //@group_call_id Group call identifier @user_id User identifier @is_muted Pass true if the user must be muted and false otherwise toggleGroupCallParticipantIsMuted group_call_id:int32 user_id:int32 is_muted:Bool = Ok; -//@description Checks whether a group call is still joined. Should be called every 10 seconds when tgcalls notifies about lost connection with the server @group_call_id Group call identifier -checkGroupCallIsJoined group_call_id:int32 = Ok; - //@description Loads more group call participants. The loaded participants will be received through updates. Use the field groupCall.loaded_all_participants to check whether all participants has already been loaded //@group_call_id Group call identifier. The group call must be previously received through getGroupCall and must be joined or being joined //@limit Maximum number of participants to load diff --git a/td/generate/scheme/update-tlo.sh b/td/generate/scheme/update-tlo.sh deleted file mode 100755 index cfcb71f35..000000000 --- a/td/generate/scheme/update-tlo.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh -cd $(dirname $0) -tl-parser -e td_api.tlo td_api.tl -tl-parser -e telegram_api.tlo telegram_api.tl -tl-parser -e mtproto_api.tlo mtproto_api.tl -tl-parser -e secret_api.tlo secret_api.tl diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 610fbbb27..40fa1a1e8 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -8706,6 +8706,18 @@ void ContactsManager::on_load_channel_full_from_database(ChannelId channel_id, s auto photo = std::move(channel_full->photo); on_update_channel_full_photo(channel_full, channel_id, std::move(photo)); + if (channel_full->participant_count < channel_full->administrator_count) { + channel_full->participant_count = channel_full->administrator_count; + } + if (c->participant_count != channel_full->participant_count) { + channel_full->participant_count = c->participant_count; + + if (channel_full->participant_count < channel_full->administrator_count) { + channel_full->participant_count = channel_full->administrator_count; + channel_full->expires_at = 0.0; + } + } + update_channel_full(channel_full, channel_id, true); if (channel_full->expires_at == 0.0) { @@ -9110,9 +9122,7 @@ void ContactsManager::update_channel_full(ChannelFull *channel_full, ChannelId c CHECK(channel_full != nullptr); unavailable_channel_fulls_.erase(channel_id); // don't needed anymore - if (channel_full->participant_count < channel_full->administrator_count) { - channel_full->administrator_count = channel_full->participant_count; - } + CHECK(channel_full->participant_count >= channel_full->administrator_count); if (channel_full->is_slow_mode_next_send_date_changed) { auto now = G()->server_time(); @@ -9517,14 +9527,17 @@ void ContactsManager::on_get_chat_full(tl_object_ptr &&c ChannelFull *channel = add_channel_full(channel_id); bool have_participant_count = (channel_full->flags_ & CHANNEL_FULL_FLAG_HAS_PARTICIPANT_COUNT) != 0; - auto participant_count = have_participant_count ? channel_full->participants_count_ : 0; + auto participant_count = have_participant_count ? channel_full->participants_count_ : channel->participant_count; auto administrator_count = 0; if ((channel_full->flags_ & CHANNEL_FULL_FLAG_HAS_ADMINISTRATOR_COUNT) != 0) { administrator_count = channel_full->admins_count_; } else if (c->is_megagroup || c->status.is_administrator()) { - // in megagroups and administrated channels don't drop known number of administrators + // in megagroups and administered channels don't drop known number of administrators administrator_count = channel->administrator_count; } + if (participant_count < administrator_count) { + participant_count = administrator_count; + } auto restricted_count = (channel_full->flags_ & CHANNEL_FULL_FLAG_HAS_BANNED_COUNT) != 0 ? channel_full->banned_count_ : 0; auto banned_count = @@ -10699,11 +10712,20 @@ void ContactsManager::on_get_channel_participants_success( if (participant_count != -1 || administrator_count != -1) { auto channel_full = get_channel_full_force(channel_id, "on_get_channel_participants_success"); if (channel_full != nullptr) { - if (participant_count != -1 && channel_full->participant_count != participant_count) { + if (administrator_count == -1) { + administrator_count = channel_full->administrator_count; + } + if (participant_count == -1) { + participant_count = channel_full->participant_count; + } + if (participant_count < administrator_count) { + participant_count = administrator_count; + } + if (channel_full->participant_count != participant_count) { channel_full->participant_count = participant_count; channel_full->is_changed = true; } - if (administrator_count != -1 && channel_full->administrator_count != administrator_count) { + if (channel_full->administrator_count != administrator_count) { channel_full->administrator_count = administrator_count; channel_full->is_changed = true; } @@ -13683,6 +13705,18 @@ void ContactsManager::on_update_channel_administrator_count(ChannelId channel_id if (channel_full != nullptr && channel_full->administrator_count != administrator_count) { channel_full->administrator_count = administrator_count; channel_full->is_changed = true; + + if (channel_full->participant_count < channel_full->administrator_count) { + channel_full->participant_count = channel_full->administrator_count; + + auto c = get_channel(channel_id); + if (c != nullptr && c->participant_count != channel_full->participant_count) { + c->participant_count = channel_full->participant_count; + c->is_changed = true; + update_channel(c, channel_id); + } + } + update_channel_full(channel_full, channel_id); } } @@ -13908,6 +13942,13 @@ void ContactsManager::on_chat_update(telegram_api::channel &channel, const char int32 participant_count = (channel.flags_ & CHANNEL_FLAG_HAS_PARTICIPANT_COUNT) != 0 ? channel.participants_count_ : 0; + if (participant_count != 0) { + auto channel_full = get_channel_full_const(channel_id); + if (channel_full != nullptr && channel_full->administrator_count > participant_count) { + participant_count = channel_full->administrator_count; + } + } + { bool is_broadcast = (channel.flags_ & CHANNEL_FLAG_IS_BROADCAST) != 0; LOG_IF(ERROR, is_broadcast == is_megagroup) @@ -13999,6 +14040,13 @@ void ContactsManager::on_chat_update(telegram_api::channel &channel, const char if (participant_count != 0 && participant_count != c->participant_count) { c->participant_count = participant_count; c->is_changed = true; + + auto channel_full = get_channel_full(channel_id, "on_chat_update"); + if (channel_full != nullptr && channel_full->participant_count != participant_count) { + channel_full->participant_count = participant_count; + channel_full->is_changed = true; + update_channel_full(channel_full, channel_id); + } } bool need_invalidate_channel_full = false; @@ -14094,11 +14142,6 @@ void ContactsManager::on_chat_update(telegram_api::channelForbidden &channel, co sign_messages = true; } - if (c->participant_count != 0) { - c->participant_count = 0; - c->is_changed = true; - } - bool need_invalidate_channel_full = false; if (c->is_slow_mode_enabled != is_slow_mode_enabled || c->is_megagroup != is_megagroup || !c->restriction_reasons.empty() || c->is_scam != is_scam) { @@ -14119,6 +14162,19 @@ void ContactsManager::on_chat_update(telegram_api::channelForbidden &channel, co c->is_changed = true; } + if (c->participant_count != 0) { + c->participant_count = 0; + c->is_changed = true; + + auto channel_full = get_channel_full(channel_id, "on_chat_update"); + if (channel_full != nullptr && channel_full->participant_count != 0) { + channel_full->participant_count = 0; + channel_full->administrator_count = 0; + channel_full->is_changed = true; + update_channel_full(channel_full, channel_id); + } + } + if (c->cache_version != Channel::CACHE_VERSION) { c->cache_version = Channel::CACHE_VERSION; c->need_save_to_database = true; diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 320a6bb26..f1e8ccc32 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -431,7 +431,7 @@ struct GroupCallManager::GroupCallParticipants { struct GroupCallManager::GroupCallRecentSpeakers { vector> users; // user + time; sorted by time bool is_changed = false; - vector last_sent_user_ids; + vector> last_sent_users; }; struct GroupCallManager::PendingJoinRequest { @@ -442,6 +442,9 @@ struct GroupCallManager::PendingJoinRequest { }; GroupCallManager::GroupCallManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) { + check_group_call_is_joined_timeout_.set_callback(on_check_group_call_is_joined_timeout_callback); + check_group_call_is_joined_timeout_.set_callback_data(static_cast(this)); + pending_send_speaking_action_timeout_.set_callback(on_pending_send_speaking_action_timeout_callback); pending_send_speaking_action_timeout_.set_callback_data(static_cast(this)); @@ -486,6 +489,45 @@ void GroupCallManager::memory_stats(vector &output) { output.push_back("\"pending_join_requests_\":"); output.push_back(std::to_string(pending_join_requests_.size())); } +void GroupCallManager::on_check_group_call_is_joined_timeout_callback(void *group_call_manager_ptr, + int64 group_call_id_int) { + if (G()->close_flag()) { + return; + } + + auto group_call_manager = static_cast(group_call_manager_ptr); + send_closure_later(group_call_manager->actor_id(group_call_manager), + &GroupCallManager::on_check_group_call_is_joined_timeout, + GroupCallId(narrow_cast(group_call_id_int))); +} + +void GroupCallManager::on_check_group_call_is_joined_timeout(GroupCallId group_call_id) { + if (G()->close_flag()) { + return; + } + + LOG(INFO) << "Receive check group call is_joined timeout in " << group_call_id; + auto input_group_call_id = get_input_group_call_id(group_call_id).move_as_ok(); + + auto *group_call = get_group_call(input_group_call_id); + CHECK(group_call != nullptr && group_call->is_inited); + if (!group_call->is_joined || check_group_call_is_joined_timeout_.has_timeout(group_call_id.get())) { + return; + } + + auto source = group_call->source; + auto promise = + PromiseCreator::lambda([actor_id = actor_id(this), input_group_call_id, source](Result &&result) mutable { + if (result.is_error() && result.error().message() == "GROUP_CALL_JOIN_MISSING") { + send_closure(actor_id, &GroupCallManager::on_group_call_left, input_group_call_id, source, true); + result = Unit(); + } + send_closure(actor_id, &GroupCallManager::finish_check_group_call_is_joined, input_group_call_id, source, + std::move(result)); + }); + td_->create_handler(std::move(promise))->send(input_group_call_id, source); +} + void GroupCallManager::on_pending_send_speaking_action_timeout_callback(void *group_call_manager_ptr, int64 group_call_id_int) { if (G()->close_flag()) { @@ -540,8 +582,8 @@ void GroupCallManager::on_recent_speaker_update_timeout(GroupCallId group_call_i LOG(INFO) << "Receive recent speaker update timeout in " << group_call_id; auto input_group_call_id = get_input_group_call_id(group_call_id).move_as_ok(); - get_recent_speaker_user_ids(get_group_call(input_group_call_id), - false); // will update the list and send updateGroupCall if needed + get_recent_speakers(get_group_call(input_group_call_id), + false); // will update the list and send updateGroupCall if needed } void GroupCallManager::on_sync_participants_timeout_callback(void *group_call_manager_ptr, int64 group_call_id_int) { @@ -718,7 +760,7 @@ void GroupCallManager::get_group_call(GroupCallId group_call_id, auto group_call = get_group_call(input_group_call_id); if (group_call != nullptr && group_call->is_inited) { - return promise.set_value(get_group_call_object(group_call, get_recent_speaker_user_ids(group_call, false))); + return promise.set_value(get_group_call_object(group_call, get_recent_speakers(group_call, false))); } reload_group_call(input_group_call_id, std::move(promise)); @@ -804,11 +846,26 @@ void GroupCallManager::finish_get_group_call(InputGroupCallId input_group_call_i CHECK(group_call != nullptr && group_call->is_inited); for (auto &promise : promises) { if (promise) { - promise.set_value(get_group_call_object(group_call, get_recent_speaker_user_ids(group_call, false))); + promise.set_value(get_group_call_object(group_call, get_recent_speakers(group_call, false))); } } } +void GroupCallManager::finish_check_group_call_is_joined(InputGroupCallId input_group_call_id, int32 source, + Result &&result) { + LOG(INFO) << "Finish check group call is_joined for " << input_group_call_id; + + auto *group_call = get_group_call(input_group_call_id); + CHECK(group_call != nullptr && group_call->is_inited); + if (!group_call->is_joined || check_group_call_is_joined_timeout_.has_timeout(group_call->group_call_id.get()) || + group_call->source != source) { + return; + } + + int32 next_timeout = result.is_ok() ? CHECK_GROUP_CALL_IS_JOINED_TIMEOUT : 1; + check_group_call_is_joined_timeout_.set_timeout_in(group_call->group_call_id.get(), next_timeout); +} + bool GroupCallManager::need_group_call_participants(InputGroupCallId input_group_call_id) const { auto *group_call = get_group_call(input_group_call_id); if (group_call == nullptr || !group_call->is_inited || !group_call->is_active) { @@ -1616,6 +1673,8 @@ bool GroupCallManager::on_join_group_call_response(InputGroupCallId input_group_ group_call->joined_date = G()->unix_time(); group_call->source = it->second->source; it->second->promise.set_value(result.move_as_ok()); + check_group_call_is_joined_timeout_.set_timeout_in(group_call->group_call_id.get(), + CHECK_GROUP_CALL_IS_JOINED_TIMEOUT); need_update = true; } pending_join_requests_.erase(it); @@ -1691,6 +1750,10 @@ void GroupCallManager::set_group_call_participant_is_speaking(GroupCallId group_ } else { recursive = true; } + if (source != group_call->source && !recursive && is_speaking && + check_group_call_is_joined_timeout_.has_timeout(group_call_id.get())) { + check_group_call_is_joined_timeout_.set_timeout_in(group_call_id.get(), CHECK_GROUP_CALL_IS_JOINED_TIMEOUT); + } UserId user_id = set_group_call_participant_is_speaking_by_source(input_group_call_id, source, is_speaking, date); if (!user_id.is_valid()) { if (!recursive) { @@ -1755,29 +1818,6 @@ void GroupCallManager::toggle_group_call_participant_is_muted(GroupCallId group_ td_->create_handler(std::move(promise))->send(input_group_call_id, user_id, is_muted); } -void GroupCallManager::check_group_call_is_joined(GroupCallId group_call_id, Promise &&promise) { - TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id)); - - auto *group_call = get_group_call(input_group_call_id); - if (group_call == nullptr || !group_call->is_inited) { - return promise.set_error(Status::Error(400, "GROUP_CALL_JOIN_MISSING")); - } - if (!group_call->is_active || !group_call->is_joined || group_call->joined_date > G()->unix_time() - 8) { - return promise.set_value(Unit()); - } - auto source = group_call->source; - - auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), input_group_call_id, source, - promise = std::move(promise)](Result &&result) mutable { - if (result.is_error() && result.error().message() == "GROUP_CALL_JOIN_MISSING") { - send_closure(actor_id, &GroupCallManager::on_group_call_left, input_group_call_id, source, true); - result = Unit(); - } - promise.set_result(std::move(result)); - }); - td_->create_handler(std::move(query_promise))->send(input_group_call_id, source); -} - void GroupCallManager::load_group_call_participants(GroupCallId group_call_id, int32 limit, Promise &&promise) { if (limit <= 0) { return promise.set_error(Status::Error(400, "Parameter limit must be positive")); @@ -1846,6 +1886,7 @@ void GroupCallManager::on_group_call_left_impl(GroupCall *group_call, bool need_ group_call->source = 0; group_call->loaded_all_participants = false; group_call->version = -1; + check_group_call_is_joined_timeout_.cancel_timeout(group_call->group_call_id.get()); try_clear_group_call_participants(get_input_group_call_id(group_call->group_call_id).ok()); } @@ -2220,64 +2261,74 @@ void GroupCallManager::update_group_call_dialog(const GroupCall *group_call, con group_call->participant_count == 0, source); } -vector GroupCallManager::get_recent_speaker_user_ids(const GroupCall *group_call, bool for_update) { +vector> GroupCallManager::get_recent_speakers( + const GroupCall *group_call, bool for_update) { CHECK(group_call != nullptr && group_call->is_inited); - vector recent_speaker_user_ids; auto recent_speakers_it = group_call_recent_speakers_.find(group_call->group_call_id); if (recent_speakers_it == group_call_recent_speakers_.end()) { - return recent_speaker_user_ids; + return Auto(); } auto *recent_speakers = recent_speakers_it->second.get(); CHECK(recent_speakers != nullptr); LOG(INFO) << "Found " << recent_speakers->users.size() << " recent speakers in " << group_call->group_call_id << " from " << group_call->dialog_id; - while (!recent_speakers->users.empty() && - recent_speakers->users.back().second < G()->unix_time() - RECENT_SPEAKER_TIMEOUT) { + auto now = G()->unix_time(); + while (!recent_speakers->users.empty() && recent_speakers->users.back().second < now - RECENT_SPEAKER_TIMEOUT) { recent_speakers->users.pop_back(); } + vector> recent_speaker_users; for (auto &recent_speaker : recent_speakers->users) { - recent_speaker_user_ids.push_back(recent_speaker.first.get()); + recent_speaker_users.emplace_back(recent_speaker.first, recent_speaker.second > now - 5); } if (recent_speakers->is_changed) { recent_speakers->is_changed = false; recent_speaker_update_timeout_.cancel_timeout(group_call->group_call_id.get()); } - if (!recent_speakers->users.empty()) { - auto next_timeout = recent_speakers->users.back().second + RECENT_SPEAKER_TIMEOUT - G()->unix_time() + 1; + if (!recent_speaker_users.empty()) { + auto next_timeout = recent_speakers->users.back().second + RECENT_SPEAKER_TIMEOUT - now + 1; + if (recent_speaker_users[0].second) { // if someone is speaking, recheck in 1 second + next_timeout = 1; + } recent_speaker_update_timeout_.add_timeout_in(group_call->group_call_id.get(), next_timeout); } - if (recent_speakers->last_sent_user_ids != recent_speaker_user_ids) { - recent_speakers->last_sent_user_ids = recent_speaker_user_ids; + auto get_result = [recent_speaker_users] { + return transform(recent_speaker_users, [](const std::pair &recent_speaker_user) { + return td_api::make_object(recent_speaker_user.first.get(), + recent_speaker_user.second); + }); + }; + if (recent_speakers->last_sent_users != recent_speaker_users) { + recent_speakers->last_sent_users = std::move(recent_speaker_users); if (!for_update) { // the change must be received through update first - send_update_group_call(group_call, "get_recent_speaker_user_ids"); + send_closure(G()->td(), &Td::send_update, get_update_group_call_object(group_call, get_result())); } } - return recent_speaker_user_ids; + + return get_result(); } -tl_object_ptr GroupCallManager::get_group_call_object(const GroupCall *group_call, - vector recent_speaker_user_ids) const { +tl_object_ptr GroupCallManager::get_group_call_object( + const GroupCall *group_call, vector> recent_speakers) const { CHECK(group_call != nullptr); CHECK(group_call->is_inited); return td_api::make_object( group_call->group_call_id.get(), group_call->is_active, group_call->is_joined, group_call->need_rejoin, group_call->can_self_unmute, group_call->can_be_managed, group_call->participant_count, - group_call->loaded_all_participants, std::move(recent_speaker_user_ids), group_call->mute_new_participants, + group_call->loaded_all_participants, std::move(recent_speakers), group_call->mute_new_participants, group_call->allowed_change_mute_new_participants, group_call->duration); } tl_object_ptr GroupCallManager::get_update_group_call_object( - const GroupCall *group_call, vector recent_speaker_user_ids) const { - return td_api::make_object( - get_group_call_object(group_call, std::move(recent_speaker_user_ids))); + const GroupCall *group_call, vector> recent_speakers) const { + return td_api::make_object(get_group_call_object(group_call, std::move(recent_speakers))); } tl_object_ptr GroupCallManager::get_update_group_call_participant_object( @@ -2292,7 +2343,7 @@ void GroupCallManager::send_update_group_call(const GroupCall *group_call, const return; } send_closure(G()->td(), &Td::send_update, - get_update_group_call_object(group_call, get_recent_speaker_user_ids(group_call, true))); + get_update_group_call_object(group_call, get_recent_speakers(group_call, true))); } void GroupCallManager::send_update_group_call_participant(GroupCallId group_call_id, diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index 5faa283ea..9c97e7e4c 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -66,8 +66,6 @@ class GroupCallManager : public Actor { void toggle_group_call_participant_is_muted(GroupCallId group_call_id, UserId user_id, bool is_muted, Promise &&promise); - void check_group_call_is_joined(GroupCallId group_call_id, Promise &&promise); - void load_group_call_participants(GroupCallId group_call_id, int32 limit, Promise &&promise); void leave_group_call(GroupCallId group_call_id, Promise &&promise); @@ -96,9 +94,14 @@ class GroupCallManager : public Actor { struct PendingJoinRequest; static constexpr int32 RECENT_SPEAKER_TIMEOUT = 5 * 60; + static constexpr int32 CHECK_GROUP_CALL_IS_JOINED_TIMEOUT = 10; void tear_down() override; + static void on_check_group_call_is_joined_timeout_callback(void *group_call_manager_ptr, int64 group_call_id_int); + + void on_check_group_call_is_joined_timeout(GroupCallId group_call_id); + static void on_pending_send_speaking_action_timeout_callback(void *group_call_manager_ptr, int64 group_call_id_int); void on_send_speaking_action_timeout(GroupCallId group_call_id); @@ -129,6 +132,8 @@ class GroupCallManager : public Actor { void finish_get_group_call(InputGroupCallId input_group_call_id, Result> &&result); + void finish_check_group_call_is_joined(InputGroupCallId input_group_call_id, int32 source, Result &&result); + bool need_group_call_participants(InputGroupCallId input_group_call_id) const; bool process_pending_group_call_participant_updates(InputGroupCallId input_group_call_id); @@ -185,13 +190,14 @@ class GroupCallManager : public Actor { void update_group_call_dialog(const GroupCall *group_call, const char *source); - vector get_recent_speaker_user_ids(const GroupCall *group_call, bool for_update); + vector> get_recent_speakers(const GroupCall *group_call, + bool for_update); - tl_object_ptr get_update_group_call_object(const GroupCall *group_call, - vector recent_speaker_user_ids) const; + tl_object_ptr get_update_group_call_object( + const GroupCall *group_call, vector> recent_speakers) const; - tl_object_ptr get_group_call_object(const GroupCall *group_call, - vector recent_speaker_user_ids) const; + tl_object_ptr get_group_call_object( + const GroupCall *group_call, vector> recent_speakers) const; tl_object_ptr get_update_group_call_participant_object( GroupCallId group_call_id, const GroupCallParticipant &participant); @@ -223,6 +229,7 @@ class GroupCallManager : public Actor { std::unordered_map, InputGroupCallIdHash> pending_join_requests_; uint64 join_group_request_generation_ = 0; + MultiTimeout check_group_call_is_joined_timeout_{"CheckGroupCallIsJoinedTimeout"}; MultiTimeout pending_send_speaking_action_timeout_{"PendingSendSpeakingActionTimeout"}; MultiTimeout recent_speaker_update_timeout_{"RecentSpeakerUpdateTimeout"}; MultiTimeout sync_participants_timeout_{"SyncParticipantsTimeout"}; diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 01457e49d..f87cecd51 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -656,22 +656,24 @@ class UnpinAllMessagesQuery : public Td::ResultHandler { if (affected_history->pts_count_ > 0) { affected_history->pts_count_ = 0; // force receiving real updates from the server + auto promise = affected_history->offset_ > 0 ? Promise() : std::move(promise_); if (dialog_id_.get_type() == DialogType::Channel) { td->messages_manager_->add_pending_channel_update(dialog_id_, make_tl_object(), affected_history->pts_, affected_history->pts_count_, - "unpin all messages"); + std::move(promise), "unpin all messages"); } else { td->messages_manager_->add_pending_update(make_tl_object(), affected_history->pts_, - affected_history->pts_count_, false, "unpin all messages"); + affected_history->pts_count_, false, std::move(promise), + "unpin all messages"); } + } else if (affected_history->offset_ <= 0) { + promise_.set_value(Unit()); } if (affected_history->offset_ > 0) { send_request(); return; } - - promise_.set_value(Unit()); } void on_error(uint64 id, Status status) override { @@ -1566,7 +1568,8 @@ class ReadMessagesContentsQuery : public Td::ResultHandler { if (affected_messages->pts_count_ > 0) { td->messages_manager_->add_pending_update(make_tl_object(), affected_messages->pts_, - affected_messages->pts_count_, false, "read messages content query"); + affected_messages->pts_count_, false, Promise(), + "read messages content query"); } promise_.set_value(Unit()); @@ -1783,7 +1786,8 @@ class ReadHistoryQuery : public Td::ResultHandler { if (affected_messages->pts_count_ > 0) { td->messages_manager_->add_pending_update(make_tl_object(), affected_messages->pts_, - affected_messages->pts_count_, false, "read history query"); + affected_messages->pts_count_, false, Promise(), + "read history query"); } promise_.set_value(Unit()); @@ -2252,7 +2256,8 @@ class DeleteHistoryQuery : public Td::ResultHandler { if (affected_history->pts_count_ > 0) { td->messages_manager_->add_pending_update(make_tl_object(), affected_history->pts_, - affected_history->pts_count_, false, "delete history query"); + affected_history->pts_count_, false, Promise(), + "delete history query"); } if (affected_history->offset_ > 0) { @@ -2391,17 +2396,17 @@ class DeleteUserHistoryQuery : public Td::ResultHandler { CHECK(affected_history->get_id() == telegram_api::messages_affectedHistory::ID); if (affected_history->pts_count_ > 0) { - td->messages_manager_->add_pending_channel_update(DialogId(channel_id_), make_tl_object(), - affected_history->pts_, affected_history->pts_count_, - "delete user history query"); + td->messages_manager_->add_pending_channel_update( + DialogId(channel_id_), make_tl_object(), affected_history->pts_, affected_history->pts_count_, + affected_history->offset_ > 0 ? Promise() : std::move(promise_), "delete user history query"); + } else if (affected_history->offset_ <= 0) { + promise_.set_value(Unit()); } if (affected_history->offset_ > 0) { send_request(); return; } - - promise_.set_value(Unit()); } void on_error(uint64 id, Status status) override { @@ -2451,7 +2456,8 @@ class ReadAllMentionsQuery : public Td::ResultHandler { td->updates_manager_->get_difference("Wrong messages_readMentions result"); } else { td->messages_manager_->add_pending_update(make_tl_object(), affected_history->pts_, - affected_history->pts_count_, false, "read all mentions query"); + affected_history->pts_count_, false, Promise(), + "read all mentions query"); } } @@ -2581,13 +2587,13 @@ class SendMessageActor : public NetActorOnce { if (dialog_id_.get_type() == DialogType::Channel) { td->messages_manager_->add_pending_channel_update( dialog_id_, make_tl_object(random_id_, message_id, sent_message->date_), - sent_message->pts_, sent_message->pts_count_, "send message actor"); + sent_message->pts_, sent_message->pts_count_, Promise(), "send message actor"); return; } td->messages_manager_->add_pending_update( make_tl_object(random_id_, message_id, sent_message->date_), sent_message->pts_, - sent_message->pts_count_, false, "send message actor"); + sent_message->pts_count_, false, Promise(), "send message actor"); } void on_error(uint64 id, Status status) override { @@ -3038,11 +3044,20 @@ class SendScheduledMessageActor : public NetActorOnce { }; class EditMessageActor : public NetActorOnce { - Promise promise_; + Promise promise_; DialogId dialog_id_; public: - explicit EditMessageActor(Promise &&promise) : promise_(std::move(promise)) { + explicit EditMessageActor(Promise &&promise) { + promise_ = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + promise.set_value(Unit()); + } + }); + } + explicit EditMessageActor(Promise &&promise) : promise_(std::move(promise)) { } void send(int32 flags, DialogId dialog_id, MessageId message_id, const string &text, @@ -3101,13 +3116,16 @@ class EditMessageActor : public NetActorOnce { auto ptr = result_ptr.move_as_ok(); LOG(INFO) << "Receive result for EditMessageActor: " << to_string(ptr); - td->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_)); + auto pts = td->updates_manager_->get_update_edit_message_pts(ptr.get()); + auto promise = PromiseCreator::lambda( + [promise = std::move(promise_), pts](Result result) mutable { promise.set_value(std::move(pts)); }); + td->updates_manager_->on_get_updates(std::move(ptr), std::move(promise)); } void on_error(uint64 id, Status status) override { LOG(INFO) << "Receive error for EditMessageQuery: " << status; if (!td->auth_manager_->is_bot() && status.message() == "MESSAGE_NOT_MODIFIED") { - return promise_.set_value(Unit()); + return promise_.set_value(0); } td->messages_manager_->on_get_dialog_error(dialog_id_, status, "EditMessageActor"); promise_.set_error(std::move(status)); @@ -3596,7 +3614,8 @@ class DeleteMessagesQuery : public Td::ResultHandler { if (affected_messages->pts_count_ > 0) { td->messages_manager_->add_pending_update(make_tl_object(), affected_messages->pts_, - affected_messages->pts_count_, false, "delete messages query"); + affected_messages->pts_count_, false, Promise(), + "delete messages query"); } if (--query_count_ == 0) { promise_.set_value(Unit()); @@ -3661,7 +3680,7 @@ class DeleteChannelMessagesQuery : public Td::ResultHandler { if (affected_messages->pts_count_ > 0) { td->messages_manager_->add_pending_channel_update(DialogId(channel_id_), make_tl_object(), affected_messages->pts_, affected_messages->pts_count_, - "DeleteChannelMessagesQuery"); + Promise(), "DeleteChannelMessagesQuery"); } if (--query_count_ == 0) { promise_.set_value(Unit()); @@ -6246,7 +6265,7 @@ void MessagesManager::skip_old_pending_update(tl_object_ptr &&update, int32 new_pts, int32 pts_count, - bool force_apply, const char *source) { + bool force_apply, Promise &&promise, const char *source) { // do not try to run getDifference from this function CHECK(update != nullptr); CHECK(source != nullptr); @@ -6255,7 +6274,7 @@ void MessagesManager::add_pending_update(tl_object_ptr &&u if (pts_count < 0 || new_pts <= pts_count) { LOG(ERROR) << "Receive update with wrong pts = " << new_pts << " or pts_count = " << pts_count << " from " << source << ": " << oneline(to_string(update)); - return; + return promise.set_value(Unit()); } // TODO need to save all updates that can change result of running queries not associated with pts (for example @@ -6272,7 +6291,7 @@ void MessagesManager::add_pending_update(tl_object_ptr &&u auto update_new_message = static_cast(update.get()); DialogId dialog_id = get_message_dialog_id(update_new_message->message_); if (!check_update_dialog_id(update, dialog_id)) { - return; + return promise.set_value(Unit()); } break; } @@ -6280,7 +6299,7 @@ void MessagesManager::add_pending_update(tl_object_ptr &&u auto update_read_history_inbox = static_cast(update.get()); auto dialog_id = DialogId(update_read_history_inbox->peer_); if (!check_update_dialog_id(update, dialog_id)) { - return; + return promise.set_value(Unit()); } break; } @@ -6288,7 +6307,7 @@ void MessagesManager::add_pending_update(tl_object_ptr &&u auto update_read_history_outbox = static_cast(update.get()); auto dialog_id = DialogId(update_read_history_outbox->peer_); if (!check_update_dialog_id(update, dialog_id)) { - return; + return promise.set_value(Unit()); } break; } @@ -6296,7 +6315,7 @@ void MessagesManager::add_pending_update(tl_object_ptr &&u auto update_edit_message = static_cast(update.get()); DialogId dialog_id = get_message_dialog_id(update_edit_message->message_); if (!check_update_dialog_id(update, dialog_id)) { - return; + return promise.set_value(Unit()); } break; } @@ -6304,7 +6323,7 @@ void MessagesManager::add_pending_update(tl_object_ptr &&u auto update_pinned_messages = static_cast(update.get()); auto dialog_id = DialogId(update_pinned_messages->peer_); if (!check_update_dialog_id(update, dialog_id)) { - return; + return promise.set_value(Unit()); } break; } @@ -6314,17 +6333,18 @@ void MessagesManager::add_pending_update(tl_object_ptr &&u } if (force_apply) { - CHECK(pending_updates_.empty()); + CHECK(pending_pts_updates_.empty()); CHECK(accumulated_pts_ == -1); if (pts_count != 0) { LOG(ERROR) << "Receive forced update with pts_count = " << pts_count << " from " << source; } process_update(std::move(update)); - return; + return promise.set_value(Unit()); } if (DROP_UPDATES) { - return set_get_difference_timeout(1.0); + set_get_difference_timeout(1.0); + return promise.set_value(Unit()); } int32 old_pts = td_->updates_manager_->get_pts(); @@ -6350,15 +6370,13 @@ void MessagesManager::add_pending_update(tl_object_ptr &&u if (new_pts <= old_pts) { skip_old_pending_update(std::move(update), new_pts, old_pts, pts_count, source); - return; + return promise.set_value(Unit()); } - if (td_->updates_manager_->running_get_difference()) { + if (td_->updates_manager_->running_get_difference() || !postponed_pts_updates_.empty()) { LOG(INFO) << "Save pending update got while running getDifference from " << source; CHECK(update->get_id() == dummyUpdate::ID || update->get_id() == updateSentMessage::ID); - if (pts_count > 0) { - postponed_pts_updates_.emplace(new_pts, PendingPtsUpdate(std::move(update), new_pts, pts_count)); - } + postpone_pts_update(std::move(update), new_pts, pts_count, std::move(promise)); return; } @@ -6366,6 +6384,7 @@ void MessagesManager::add_pending_update(tl_object_ptr &&u LOG(WARNING) << "Have old_pts (= " << old_pts << ") + pts_count (= " << pts_count << ") > new_pts (= " << new_pts << "). Logged in " << G()->shared_config().get_option_integer("authorization_date") << ". Update from " << source << " = " << oneline(to_string(update)); + postpone_pts_update(std::move(update), new_pts, pts_count, std::move(promise)); set_get_difference_timeout(0.001); return; } @@ -6381,13 +6400,14 @@ void MessagesManager::add_pending_update(tl_object_ptr &&u << ", pts_count = " << pts_count << ". Logged in " << G()->shared_config().get_option_integer("authorization_date") << ". Update from " << source << " = " << oneline(to_string(update)); + postpone_pts_update(std::move(update), new_pts, pts_count, std::move(promise)); set_get_difference_timeout(0.001); return; } LOG_IF(INFO, pts_count == 0 && update->get_id() != dummyUpdate::ID) << "Skip useless update " << to_string(update); - if (pending_updates_.empty() && old_pts + accumulated_pts_count_ == accumulated_pts_ && + if (pending_pts_updates_.empty() && old_pts + accumulated_pts_count_ == accumulated_pts_ && !pts_gap_timeout_.has_timeout()) { if (pts_count > 0) { process_update(std::move(update)); @@ -6397,12 +6417,11 @@ void MessagesManager::add_pending_update(tl_object_ptr &&u accumulated_pts_count_ = 0; accumulated_pts_ = -1; } + promise.set_value(Unit()); return; } - if (pts_count > 0) { - pending_updates_.emplace(new_pts, PendingPtsUpdate(std::move(update), new_pts, pts_count)); - } + pending_pts_updates_.emplace(new_pts, PendingPtsUpdate(std::move(update), new_pts, pts_count, std::move(promise))); if (old_pts + accumulated_pts_count_ < accumulated_pts_) { set_get_difference_timeout(UpdatesManager::MAX_UNFILLED_GAP_TIME); @@ -6410,7 +6429,7 @@ void MessagesManager::add_pending_update(tl_object_ptr &&u } CHECK(old_pts + accumulated_pts_count_ == accumulated_pts_); - if (!pending_updates_.empty()) { + if (!pending_pts_updates_.empty()) { process_pending_updates(); } } @@ -6513,82 +6532,6 @@ void MessagesManager::on_update_service_notification(tl_object_ptr &&update) { - int new_pts = update->pts_; - int pts_count = update->pts_count_; - DialogId dialog_id = get_message_dialog_id(update->message_); - switch (dialog_id.get_type()) { - case DialogType::None: - return; - case DialogType::User: - case DialogType::Chat: - case DialogType::SecretChat: - LOG(ERROR) << "Receive updateNewChannelMessage in wrong " << dialog_id; - return; - case DialogType::Channel: { - auto channel_id = dialog_id.get_channel_id(); - if (!td_->contacts_manager_->have_channel(channel_id)) { - // if min channel was received - if (td_->contacts_manager_->have_min_channel(channel_id)) { - td_->updates_manager_->schedule_get_difference("on_update_new_channel_message"); - return; - } - } - // Ok - break; - } - default: - UNREACHABLE(); - return; - } - - if (pts_count < 0 || new_pts <= pts_count) { - LOG(ERROR) << "Receive new channel message with wrong pts = " << new_pts << " or pts_count = " << pts_count << ": " - << oneline(to_string(update)); - return; - } - - add_pending_channel_update(dialog_id, std::move(update), new_pts, pts_count, "on_update_new_channel_message"); -} - -void MessagesManager::on_update_edit_channel_message(tl_object_ptr &&update) { - int new_pts = update->pts_; - int pts_count = update->pts_count_; - DialogId dialog_id = get_message_dialog_id(update->message_); - switch (dialog_id.get_type()) { - case DialogType::None: - return; - case DialogType::User: - case DialogType::Chat: - case DialogType::SecretChat: - LOG(ERROR) << "Receive updateEditChannelMessage in wrong " << dialog_id; - return; - case DialogType::Channel: { - auto channel_id = dialog_id.get_channel_id(); - if (!td_->contacts_manager_->have_channel(channel_id)) { - // if min channel was received - if (td_->contacts_manager_->have_min_channel(channel_id)) { - td_->updates_manager_->schedule_get_difference("on_update_edit_channel_message"); - return; - } - } - // Ok - break; - } - default: - UNREACHABLE(); - return; - } - - if (pts_count < 0 || new_pts <= pts_count) { - LOG(ERROR) << "Receive edited channel message with wrong pts = " << new_pts << " or pts_count = " << pts_count - << ": " << oneline(to_string(update)); - return; - } - - add_pending_channel_update(dialog_id, std::move(update), new_pts, pts_count, "on_update_edit_channel_message"); -} - void MessagesManager::on_update_read_channel_inbox(tl_object_ptr &&update) { ChannelId channel_id(update->channel_id_); if (!channel_id.is_valid()) { @@ -6819,7 +6762,10 @@ bool MessagesManager::is_active_message_reply_info(DialogId dialog_id, const Mes bool MessagesManager::is_visible_message_reply_info(DialogId dialog_id, const Message *m) const { CHECK(m != nullptr); - if (!m->message_id.is_valid() || !m->message_id.is_server()) { + if (!m->message_id.is_valid()) { + return false; + } + if (!m->message_id.is_server() && !m->message_id.is_yet_unsent()) { return false; } if (is_broadcast_channel(dialog_id) && (m->had_reply_markup || m->reply_markup != nullptr)) { @@ -7248,28 +7194,41 @@ void MessagesManager::cancel_user_dialog_action(DialogId dialog_id, const Messag } void MessagesManager::add_pending_channel_update(DialogId dialog_id, tl_object_ptr &&update, - int32 new_pts, int32 pts_count, const char *source, - bool is_postponed_update) { + int32 new_pts, int32 pts_count, Promise &&promise, + const char *source, bool is_postponed_update) { LOG(INFO) << "Receive from " << source << " pending " << to_string(update); CHECK(update != nullptr); - CHECK(dialog_id.get_type() == DialogType::Channel); + if (dialog_id.get_type() != DialogType::Channel) { + LOG(ERROR) << "Receive channel update in invalid " << dialog_id << " from " << source << ": " + << oneline(to_string(update)); + promise.set_value(Unit()); + return; + } if (pts_count < 0 || new_pts <= pts_count) { LOG(ERROR) << "Receive channel update from " << source << " with wrong pts = " << new_pts << " or pts_count = " << pts_count << ": " << oneline(to_string(update)); + promise.set_value(Unit()); + return; + } + + auto channel_id = dialog_id.get_channel_id(); + if (!td_->contacts_manager_->have_channel(channel_id) && td_->contacts_manager_->have_min_channel(channel_id)) { + td_->updates_manager_->schedule_get_difference("on_update_new_channel_message"); + promise.set_value(Unit()); return; } // TODO need to save all updates that can change result of running queries not associated with pts (for example - // getHistory) and apply them to result of this queries + // getHistory) and apply them to result of these queries Dialog *d = get_dialog_force(dialog_id); if (d == nullptr) { auto pts = load_channel_pts(dialog_id); if (pts > 0) { - auto channel_id = dialog_id.get_channel_id(); if (!td_->contacts_manager_->have_channel(channel_id)) { // do not create dialog if there is no info about the channel LOG(INFO) << "There is no info about " << channel_id << ", so ignore " << oneline(to_string(update)); + promise.set_value(Unit()); return; } @@ -7286,6 +7245,7 @@ void MessagesManager::add_pending_channel_update(DialogId dialog_id, tl_object_p // if there is no dialog, it can be created by the update LOG(INFO) << "Receive pending update from " << source << " about unknown " << dialog_id; if (running_get_channel_difference(dialog_id)) { + promise.set_value(Unit()); return; } } else { @@ -7310,6 +7270,7 @@ void MessagesManager::add_pending_channel_update(DialogId dialog_id, tl_object_p // apply sent channel message on_get_message(std::move(update_new_channel_message->message_), true, true, false, true, true, "updateNewChannelMessage with an awaited message"); + promise.set_value(Unit()); return; } } @@ -7319,6 +7280,7 @@ void MessagesManager::add_pending_channel_update(DialogId dialog_id, tl_object_p // apply sent channel message on_send_message_success(update_sent_message->random_id_, update_sent_message->message_id_, update_sent_message->date_, FileId(), "process old updateSentChannelMessage"); + promise.set_value(Unit()); return; } } @@ -7326,14 +7288,14 @@ void MessagesManager::add_pending_channel_update(DialogId dialog_id, tl_object_p LOG_IF(WARNING, new_pts == old_pts && pts_count == 0) << "Receive from " << source << " useless channel update " << oneline(to_string(update)); LOG(INFO) << "Skip already applied channel update"; + promise.set_value(Unit()); return; } if (running_get_channel_difference(dialog_id)) { - if (pts_count > 0) { - d->postponed_channel_updates.emplace(new_pts, PendingPtsUpdate(std::move(update), new_pts, pts_count)); - } LOG(INFO) << "Postpone channel update, because getChannelDifference is run"; + d->postponed_channel_updates.emplace(new_pts, + PendingPtsUpdate(std::move(update), new_pts, pts_count, std::move(promise))); return; } @@ -7341,9 +7303,8 @@ void MessagesManager::add_pending_channel_update(DialogId dialog_id, tl_object_p LOG(INFO) << "Found a gap in the " << dialog_id << " with pts = " << old_pts << ". new_pts = " << new_pts << ", pts_count = " << pts_count << " in update from " << source; - if (pts_count > 0) { - d->postponed_channel_updates.emplace(new_pts, PendingPtsUpdate(std::move(update), new_pts, pts_count)); - } + d->postponed_channel_updates.emplace(new_pts, + PendingPtsUpdate(std::move(update), new_pts, pts_count, std::move(promise))); get_channel_difference(dialog_id, old_pts, true, "add_pending_channel_update pts mismatch"); return; @@ -7362,12 +7323,14 @@ void MessagesManager::add_pending_channel_update(DialogId dialog_id, tl_object_p d = get_dialog(dialog_id); if (d == nullptr) { LOG(INFO) << "Update didn't created " << dialog_id; + promise.set_value(Unit()); return; } } CHECK(new_pts > d->pts); set_channel_pts(d, new_pts, source); + promise.set_value(Unit()); } bool MessagesManager::is_old_channel_update(DialogId dialog_id, int32 new_pts) { @@ -7391,11 +7354,12 @@ void MessagesManager::process_update(tl_object_ptr &&updat case dummyUpdate::ID: LOG(INFO) << "Process dummyUpdate"; break; - case telegram_api::updateNewMessage::ID: + case telegram_api::updateNewMessage::ID: { + auto update_new_message = move_tl_object_as(update); LOG(INFO) << "Process updateNewMessage"; - on_get_message(std::move(move_tl_object_as(update)->message_), true, false, false, - true, true, "updateNewMessage"); + on_get_message(std::move(update_new_message->message_), true, false, false, true, true, "updateNewMessage"); break; + } case updateSentMessage::ID: { auto send_message_success_update = move_tl_object_as(update); LOG(INFO) << "Process updateSentMessage " << send_message_success_update->random_id_; @@ -7412,11 +7376,11 @@ void MessagesManager::process_update(tl_object_ptr &&updat break; } case telegram_api::updateEditMessage::ID: { - auto full_message_id = - on_get_message(std::move(move_tl_object_as(update)->message_), false, false, - false, false, false, "updateEditMessage"); + auto update_edit_message = move_tl_object_as(update); + auto full_message_id = on_get_message(std::move(update_edit_message->message_), false, false, false, false, false, + "updateEditMessage"); LOG(INFO) << "Process updateEditMessage"; - on_message_edited(full_message_id); + on_message_edited(full_message_id, update_edit_message->pts_); break; } case telegram_api::updateDeleteMessages::ID: { @@ -7477,11 +7441,13 @@ void MessagesManager::process_channel_update(tl_object_ptr send_message_success_update->date_, FileId(), "process updateSentChannelMessage"); break; } - case telegram_api::updateNewChannelMessage::ID: + case telegram_api::updateNewChannelMessage::ID: { + auto update_new_channel_message = move_tl_object_as(update); LOG(INFO) << "Process updateNewChannelMessage"; - on_get_message(std::move(move_tl_object_as(update)->message_), true, true, - false, true, true, "updateNewChannelMessage"); + on_get_message(std::move(update_new_channel_message->message_), true, true, false, true, true, + "updateNewChannelMessage"); break; + } case telegram_api::updateDeleteChannelMessages::ID: { auto delete_channel_messages_update = move_tl_object_as(update); LOG(INFO) << "Process updateDeleteChannelMessages"; @@ -7501,11 +7467,11 @@ void MessagesManager::process_channel_update(tl_object_ptr break; } case telegram_api::updateEditChannelMessage::ID: { + auto update_edit_channel_message = move_tl_object_as(update); LOG(INFO) << "Process updateEditChannelMessage"; - auto full_message_id = - on_get_message(std::move(move_tl_object_as(update)->message_), false, - true, false, false, false, "updateEditChannelMessage"); - on_message_edited(full_message_id); + auto full_message_id = on_get_message(std::move(update_edit_channel_message->message_), false, true, false, false, + false, "updateEditChannelMessage"); + on_message_edited(full_message_id, update_edit_channel_message->pts_); break; } case telegram_api::updatePinnedChannelMessages::ID: { @@ -7531,15 +7497,16 @@ void MessagesManager::process_channel_update(tl_object_ptr } } -void MessagesManager::on_message_edited(FullMessageId full_message_id) { +void MessagesManager::on_message_edited(FullMessageId full_message_id, int32 pts) { if (full_message_id == FullMessageId()) { return; } auto dialog_id = full_message_id.get_dialog_id(); Dialog *d = get_dialog(dialog_id); - const Message *m = get_message(d, full_message_id.get_message_id()); + Message *m = get_message(d, full_message_id.get_message_id()); CHECK(m != nullptr); + m->last_edit_pts = pts; if (td_->auth_manager_->is_bot()) { d->last_edited_message_id = m->message_id; send_update_message_edited(dialog_id, m); @@ -7548,8 +7515,9 @@ void MessagesManager::on_message_edited(FullMessageId full_message_id) { } void MessagesManager::process_pending_updates() { - for (auto &update : pending_updates_) { + for (auto &update : pending_pts_updates_) { process_update(std::move(update.second.update)); + update.second.promise.set_value(Unit()); } td_->updates_manager_->set_pts(accumulated_pts_, "process pending updates") @@ -7561,7 +7529,12 @@ void MessagesManager::drop_pending_updates() { accumulated_pts_count_ = 0; accumulated_pts_ = -1; pts_gap_timeout_.cancel_timeout(); - pending_updates_.clear(); + pending_pts_updates_.clear(); +} + +void MessagesManager::postpone_pts_update(tl_object_ptr &&update, int32 pts, int32 pts_count, + Promise &&promise) { + postponed_pts_updates_.emplace(pts, PendingPtsUpdate(std::move(update), pts, pts_count, std::move(promise))); } string MessagesManager::get_notification_settings_scope_database_key(NotificationSettingsScope scope) { @@ -8902,8 +8875,8 @@ void MessagesManager::before_get_difference() { // scheduled messages are not returned in getDifference, so we must always reget them after it scheduled_messages_sync_generation_++; - postponed_pts_updates_.insert(std::make_move_iterator(pending_updates_.begin()), - std::make_move_iterator(pending_updates_.end())); + postponed_pts_updates_.insert(std::make_move_iterator(pending_pts_updates_.begin()), + std::make_move_iterator(pending_pts_updates_.end())); drop_pending_updates(); } @@ -8919,9 +8892,10 @@ void MessagesManager::after_get_difference() { if (new_pts <= old_pts) { skip_old_pending_update(std::move(update.second.update), new_pts, old_pts, update.second.pts_count, "after get difference"); + update.second.promise.set_value(Unit()); } else { add_pending_update(std::move(update.second.update), update.second.pts, update.second.pts_count, false, - "after get difference"); + std::move(update.second.promise), "after get difference"); } CHECK(!td_->updates_manager_->running_get_difference()); } @@ -8994,13 +8968,13 @@ void MessagesManager::after_get_difference() { LOG(ERROR) << "Unknown dialog " << dialog_id; break; } - if (dialog_id.get_type() == DialogType::Channel || pending_updates_.empty() || message_id.is_scheduled() || + if (dialog_id.get_type() == DialogType::Channel || pending_pts_updates_.empty() || message_id.is_scheduled() || message_id <= d->last_new_message_id) { LOG(ERROR) << "Receive updateMessageId from " << it.second << " to " << full_message_id << " but not receive corresponding message, last_new_message_id = " << d->last_new_message_id; } if (dialog_id.get_type() != DialogType::Channel && - (pending_updates_.empty() || message_id.is_scheduled() || message_id <= d->last_new_message_id)) { + (pending_pts_updates_.empty() || message_id.is_scheduled() || message_id <= d->last_new_message_id)) { dump_debug_message_op(get_dialog(dialog_id)); } if (message_id.is_scheduled() || message_id <= d->last_new_message_id) { @@ -9322,12 +9296,10 @@ void MessagesManager::on_get_history(DialogId dialog_id, MessageId from_message_ set_dialog_last_new_message_id( d, last_added_message_id.is_valid() ? last_added_message_id : last_received_message_id, "on_get_history"); } - if (last_added_message_id.is_valid()) { - if (last_added_message_id > d->last_message_id) { - CHECK(d->last_new_message_id.is_valid()); - set_dialog_last_message_id(d, last_added_message_id, "on_get_history"); - send_update_chat_last_message(d, "on_get_history"); - } + if (last_added_message_id.is_valid() && last_added_message_id > d->last_message_id) { + CHECK(d->last_new_message_id.is_valid()); + set_dialog_last_message_id(d, last_added_message_id, "on_get_history"); + send_update_chat_last_message(d, "on_get_history"); } } @@ -13402,14 +13374,6 @@ FullMessageId MessagesManager::on_get_message(MessageInfo &&message_info, bool f return FullMessageId(); } - if (is_sent_message) { - try_add_active_live_location(dialog_id, m); - - // add_message_to_dialog will not update counts, because need_update == false - update_message_count_by_index(d, +1, m); - update_reply_count_by_message(d, +1, m); - } - auto pcc_it = pending_created_dialogs_.find(dialog_id); if (from_update && pcc_it != pending_created_dialogs_.end()) { pcc_it->second.set_value(Unit()); @@ -13421,6 +13385,18 @@ FullMessageId MessagesManager::on_get_message(MessageInfo &&message_info, bool f send_update_new_message(d, m); } + if (is_sent_message) { + try_add_active_live_location(dialog_id, m); + + // add_message_to_dialog will not update counts, because need_update == false + update_message_count_by_index(d, +1, m); + } + + if (is_sent_message || need_update) { + update_reply_count_by_message(d, +1, m); + update_forward_count(dialog_id, m); + } + if (dialog_id.get_type() == DialogType::Channel && !have_input_peer(dialog_id, AccessRights::Read)) { auto p = delete_message(d, message_id, false, &need_update_dialog_pos, "get a message in inaccessible chat"); CHECK(p.get() == m); @@ -16521,6 +16497,9 @@ Result MessagesManager::get_top_thread_full_message_id(DialogId d if (!is_visible_message_reply_info(dialog_id, m)) { return Status::Error(400, "Message has no comments"); } + if (m->message_id.is_yet_unsent()) { + return Status::Error(400, "Message is not sent yet"); + } return FullMessageId{DialogId(m->reply_info.channel_id), m->linked_top_thread_message_id}; } else { if (!m->top_thread_message_id.is_valid()) { @@ -17004,7 +16983,7 @@ Result> MessagesManager::get_message_link(FullMessageId return Status::Error(400, "Message not found"); } if (m->message_id.is_yet_unsent()) { - return Status::Error(400, "Message is yet unsent"); + return Status::Error(400, "Message is not sent yet"); } if (m->message_id.is_scheduled()) { return Status::Error(400, "Message is scheduled"); @@ -17103,7 +17082,7 @@ string MessagesManager::get_message_embedding_code(FullMessageId full_message_id return {}; } if (m->message_id.is_yet_unsent()) { - promise.set_error(Status::Error(400, "Message is yet unsent")); + promise.set_error(Status::Error(400, "Message is not sent yet")); return {}; } if (m->message_id.is_scheduled()) { @@ -23583,7 +23562,7 @@ void MessagesManager::on_message_media_uploaded(DialogId dialog_id, const Messag auto promise = PromiseCreator::lambda( [actor_id = actor_id(this), dialog_id, message_id, file_id, thumbnail_file_id, schedule_date, generation = m->edit_generation, was_uploaded, was_thumbnail_uploaded, - file_reference = FileManager::extract_file_reference(input_media)](Result result) mutable { + file_reference = FileManager::extract_file_reference(input_media)](Result result) mutable { send_closure(actor_id, &MessagesManager::on_message_media_edited, dialog_id, message_id, file_id, thumbnail_file_id, was_uploaded, was_thumbnail_uploaded, std::move(file_reference), schedule_date, generation, std::move(result)); @@ -24750,7 +24729,9 @@ void MessagesManager::cancel_edit_message_media(DialogId dialog_id, Message *m, void MessagesManager::on_message_media_edited(DialogId dialog_id, MessageId message_id, FileId file_id, FileId thumbnail_file_id, bool was_uploaded, bool was_thumbnail_uploaded, string file_reference, int32 schedule_date, uint64 generation, - Result &&result) { + Result &&result) { + // must not run getDifference + CHECK(message_id.is_any_server()); auto m = get_message({dialog_id, message_id}); if (m == nullptr || m->edit_generation != generation) { @@ -24761,15 +24742,20 @@ void MessagesManager::on_message_media_edited(DialogId dialog_id, MessageId mess CHECK(m->edited_content != nullptr); if (result.is_ok()) { // message content has already been replaced from updateEdit{Channel,}Message - // TODO check that it really was replaced // need only merge files from edited_content with their uploaded counterparts // updateMessageContent was already sent and needs to be sent again, // only if 'i' and 't' sizes from edited_content was added to the photo + auto pts = result.ok(); + LOG(INFO) << "Successfully edited " << message_id << " in " << dialog_id << " with pts = " << pts + << " and last edit pts = " << m->last_edit_pts; std::swap(m->content, m->edited_content); bool need_send_update_message_content = m->edited_content->get_type() == MessageContentType::Photo && m->content->get_type() == MessageContentType::Photo; - update_message_content(dialog_id, m, std::move(m->edited_content), need_send_update_message_content, true, true); + bool need_merge_files = pts != 0 && pts == m->last_edit_pts; + update_message_content(dialog_id, m, std::move(m->edited_content), need_send_update_message_content, + need_merge_files, true); } else { + LOG(INFO) << "Failed to edit " << message_id << " in " << dialog_id << ": " << result.error(); if (was_uploaded) { if (was_thumbnail_uploaded) { CHECK(thumbnail_file_id.is_valid()); @@ -28374,6 +28360,8 @@ FullMessageId MessagesManager::on_send_message_success(int64 random_id, MessageI send_update_chat_last_message(d, "on_send_message_success"); } try_add_active_live_location(dialog_id, m); + update_reply_count_by_message(d, +1, m); + update_forward_count(dialog_id, m); being_readded_message_id_ = FullMessageId(); return {dialog_id, new_message_id}; } @@ -29134,6 +29122,10 @@ void MessagesManager::on_update_dialog_last_pinned_message_id(DialogId dialog_id d->is_last_pinned_message_id_inited = true; on_dialog_updated(dialog_id, "on_update_dialog_last_pinned_message_id"); } + Message *m = get_message_force(d, pinned_message_id, "on_update_dialog_last_pinned_message_id"); + if (m != nullptr && update_message_is_pinned(d, m, true, "on_update_dialog_last_pinned_message_id")) { + on_message_changed(d, m, true, "on_update_dialog_last_pinned_message_id"); + } return; } @@ -29142,6 +29134,11 @@ void MessagesManager::on_update_dialog_last_pinned_message_id(DialogId dialog_id void MessagesManager::set_dialog_last_pinned_message_id(Dialog *d, MessageId pinned_message_id) { CHECK(d != nullptr); + Message *m = get_message_force(d, pinned_message_id, "set_dialog_last_pinned_message_id"); + if (m != nullptr && update_message_is_pinned(d, m, true, "set_dialog_last_pinned_message_id")) { + on_message_changed(d, m, true, "set_dialog_last_pinned_message_id"); + } + if (d->last_pinned_message_id == pinned_message_id) { return; } @@ -32145,7 +32142,6 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq } if (*need_update) { update_message_count_by_index(d, +1, message.get()); - update_reply_count_by_message(d, +1, message.get()); } if (auto_attach && message_id > d->last_message_id && message_id >= d->last_new_message_id) { set_dialog_last_message_id(d, message_id, "add_message_to_dialog"); @@ -32330,12 +32326,6 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq } } } - if (!td_->auth_manager_->is_bot() && from_update && m->forward_info != nullptr && - m->forward_info->sender_dialog_id.is_valid() && m->forward_info->message_id.is_valid() && - (!is_discussion_message(dialog_id, m) || m->forward_info->sender_dialog_id != m->forward_info->from_dialog_id || - m->forward_info->message_id != m->forward_info->from_message_id)) { - update_forward_count(m->forward_info->sender_dialog_id, m->forward_info->message_id, m->date); - } return result_message; } @@ -33287,6 +33277,7 @@ bool MessagesManager::update_message_content(DialogId dialog_id, Message *old_me "update_message_content"); } old_content = std::move(new_content); + old_message->last_edit_pts = 0; update_message_content_file_id_remote(old_content.get(), old_file_id); } else { update_message_content_file_id_remote(old_content.get(), get_message_content_any_file_id(new_content.get())); @@ -35490,31 +35481,42 @@ void MessagesManager::after_get_channel_difference(DialogId dialog_id, bool succ auto d = get_dialog(dialog_id); if (d != nullptr) { bool have_access = have_input_peer(dialog_id, AccessRights::Read); - if (!have_access) { - d->postponed_channel_updates.clear(); - } else if (!d->postponed_channel_updates.empty()) { + if (!d->postponed_channel_updates.empty()) { LOG(INFO) << "Begin to apply postponed channel updates"; while (!d->postponed_channel_updates.empty()) { auto it = d->postponed_channel_updates.begin(); auto update = std::move(it->second.update); auto update_pts = it->second.pts; auto update_pts_count = it->second.pts_count; + auto promise = std::move(it->second.promise); d->postponed_channel_updates.erase(it); + auto old_size = d->postponed_channel_updates.size(); auto update_id = update->get_id(); - add_pending_channel_update(dialog_id, std::move(update), update_pts, update_pts_count, - "apply postponed channel updates", true); + if (have_access) { + add_pending_channel_update(dialog_id, std::move(update), update_pts, update_pts_count, std::move(promise), + "apply postponed channel updates", true); + } else { + promise.set_value(Unit()); + } if (d->postponed_channel_updates.size() != old_size || running_get_channel_difference(dialog_id)) { if (success && update_pts < d->pts + 10000 && update_pts_count == 1) { // if getChannelDifference was successful and update pts is near channel pts, // we hope that the update eventually can be applied LOG(INFO) << "Can't apply postponed channel updates"; } else { - // otherwise we protecting from getChannelDifference repeating calls by dropping pending updates + // otherwise protect from getChannelDifference repeating calls by dropping postponed updates LOG(WARNING) << "Failed to apply postponed updates of type " << update_id << " in " << dialog_id << " with pts " << d->pts << ", update pts is " << update_pts << ", update pts count is " << update_pts_count; + vector> update_promises; + for (auto &postponed_update : d->postponed_channel_updates) { + update_promises.push_back(std::move(postponed_update.second.promise)); + } d->postponed_channel_updates.clear(); + for (auto &update_promise : update_promises) { + update_promise.set_value(Unit()); + } } break; } @@ -35679,6 +35681,15 @@ void MessagesManager::update_top_dialogs(DialogId dialog_id, const Message *m) { } } +void MessagesManager::update_forward_count(DialogId dialog_id, const Message *m) { + if (!td_->auth_manager_->is_bot() && m->forward_info != nullptr && m->forward_info->sender_dialog_id.is_valid() && + m->forward_info->message_id.is_valid() && + (!is_discussion_message(dialog_id, m) || m->forward_info->sender_dialog_id != m->forward_info->from_dialog_id || + m->forward_info->message_id != m->forward_info->from_message_id)) { + update_forward_count(m->forward_info->sender_dialog_id, m->forward_info->message_id, m->date); + } +} + void MessagesManager::update_forward_count(DialogId dialog_id, MessageId message_id, int32 update_date) { CHECK(!td_->auth_manager_->is_bot()); Dialog *d = get_dialog(dialog_id); diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index d4318c2b0..2c8ef53ac 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -347,10 +347,6 @@ class MessagesManager : public Actor { void on_update_service_notification(tl_object_ptr &&update, bool skip_new_entities, Promise &&promise); - void on_update_new_channel_message(tl_object_ptr &&update); - - void on_update_edit_channel_message(tl_object_ptr &&update); - void on_update_read_channel_inbox(tl_object_ptr &&update); void on_update_read_channel_outbox(tl_object_ptr &&update); @@ -797,10 +793,11 @@ class MessagesManager : public Actor { bool skip_not_found); void add_pending_update(tl_object_ptr &&update, int32 new_pts, int32 pts_count, - bool force_apply, const char *source); + bool force_apply, Promise &&promise, const char *source); void add_pending_channel_update(DialogId dialog_id, tl_object_ptr &&update, int32 new_pts, - int32 pts_count, const char *source, bool is_postponed_update = false); + int32 pts_count, Promise &&promise, const char *source, + bool is_postponed_update = false); bool is_old_channel_update(DialogId dialog_id, int32 new_pts); @@ -977,9 +974,10 @@ class MessagesManager : public Actor { tl_object_ptr update; int32 pts; int32 pts_count; + Promise promise; - PendingPtsUpdate(tl_object_ptr &&update, int32 pts, int32 pts_count) - : update(std::move(update)), pts(pts), pts_count(pts_count) { + PendingPtsUpdate(tl_object_ptr &&update, int32 pts, int32 pts_count, Promise &&promise) + : update(std::move(update)), pts(pts), pts_count(pts_count), promise(std::move(promise)) { } }; @@ -1144,6 +1142,8 @@ class MessagesManager : public Actor { uint64 edit_generation = 0; Promise edit_promise; + int32 last_edit_pts = 0; + unique_ptr left; unique_ptr right; @@ -1815,7 +1815,7 @@ class MessagesManager : public Actor { void on_message_media_edited(DialogId dialog_id, MessageId message_id, FileId file_id, FileId thumbnail_file_id, bool was_uploaded, bool was_thumbnail_uploaded, string file_reference, - int32 scheduled_date, uint64 generation, Result &&result); + int32 scheduled_date, uint64 generation, Result &&result); MessageId get_persistent_message_id(const Dialog *d, MessageId message_id) const; @@ -1834,7 +1834,7 @@ class MessagesManager : public Actor { void process_channel_update(tl_object_ptr &&update); - void on_message_edited(FullMessageId full_message_id); + void on_message_edited(FullMessageId full_message_id, int32 pts); void delete_messages_from_updates(const vector &message_ids); @@ -2800,6 +2800,9 @@ class MessagesManager : public Actor { void drop_pending_updates(); + void postpone_pts_update(tl_object_ptr &&update, int32 pts, int32 pts_count, + Promise &&promise); + static string get_channel_pts_key(DialogId dialog_id); int32 load_channel_pts(DialogId dialog_id) const; @@ -2917,6 +2920,8 @@ class MessagesManager : public Actor { void update_top_dialogs(DialogId dialog_id, const Message *m); + void update_forward_count(DialogId dialog_id, const Message *m); + void update_forward_count(DialogId dialog_id, MessageId message_id, int32 update_date); void try_hide_distance(DialogId dialog_id, const Message *m); @@ -3111,7 +3116,7 @@ class MessagesManager : public Actor { bool running_get_difference_ = false; // true after before_get_difference and false after after_get_difference std::unordered_map, DialogIdHash> dialogs_; - std::multimap pending_updates_; + std::multimap pending_pts_updates_; std::multimap postponed_pts_updates_; std::unordered_set diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index aa75a2abb..fd2b593d2 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -6114,12 +6114,6 @@ void Td::on_request(uint64 id, const td_api::toggleGroupCallParticipantIsMuted & GroupCallId(request.group_call_id_), UserId(request.user_id_), request.is_muted_, std::move(promise)); } -void Td::on_request(uint64 id, const td_api::checkGroupCallIsJoined &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - group_call_manager_->check_group_call_is_joined(GroupCallId(request.group_call_id_), std::move(promise)); -} - void Td::on_request(uint64 id, const td_api::loadGroupCallParticipants &request) { CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); diff --git a/td/telegram/Td.h b/td/telegram/Td.h index 5351ad44c..8b96fa28c 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -719,8 +719,6 @@ class Td final : public NetQueryCallback { void on_request(uint64 id, const td_api::toggleGroupCallParticipantIsMuted &request); - void on_request(uint64 id, const td_api::checkGroupCallIsJoined &request); - void on_request(uint64 id, const td_api::loadGroupCallParticipants &request); void on_request(uint64 id, const td_api::leaveGroupCall &request); diff --git a/td/telegram/UpdatesManager.cpp b/td/telegram/UpdatesManager.cpp index c0ffbe72d..536ae1a6f 100644 --- a/td/telegram/UpdatesManager.cpp +++ b/td/telegram/UpdatesManager.cpp @@ -1008,6 +1008,37 @@ vector UpdatesManager::get_chat_dialog_ids(const telegram_api::Updates return dialog_ids; } +int32 UpdatesManager::get_update_edit_message_pts(const telegram_api::Updates *updates_ptr) { + int32 pts = 0; + auto updates = get_updates(updates_ptr); + if (updates != nullptr) { + for (auto &update : *updates) { + int32 update_pts = [&] { + switch (update->get_id()) { + case telegram_api::updateEditMessage::ID: + return static_cast(update.get())->pts_; + case telegram_api::updateEditChannelMessage::ID: + return static_cast(update.get())->pts_; + default: + return 0; + } + }(); + if (update_pts != 0) { + if (pts == 0) { + pts = update_pts; + } else { + pts = -1; + } + } + } + } + if (pts == -1) { + LOG(ERROR) << "Receive multiple edit message updates in " << to_string(*updates_ptr); + pts = 0; + } + return pts; +} + void UpdatesManager::init_state() { if (!td_->auth_manager_->is_authorized()) { return; @@ -1695,14 +1726,17 @@ void UpdatesManager::on_update(tl_object_ptr upd Promise &&promise) { int new_pts = update->pts_; int pts_count = update->pts_count_; - td_->messages_manager_->add_pending_update(std::move(update), new_pts, pts_count, force_apply, "on_updateNewMessage"); - promise.set_value(Unit()); + td_->messages_manager_->add_pending_update(std::move(update), new_pts, pts_count, force_apply, std::move(promise), + "updateNewMessage"); } void UpdatesManager::on_update(tl_object_ptr update, bool /*force_apply*/, Promise &&promise) { - td_->messages_manager_->on_update_new_channel_message(std::move(update)); - promise.set_value(Unit()); + DialogId dialog_id = MessagesManager::get_message_dialog_id(update->message_); + int new_pts = update->pts_; + int pts_count = update->pts_count_; + td_->messages_manager_->add_pending_channel_update(dialog_id, std::move(update), new_pts, pts_count, + std::move(promise), "updateNewChannelMessage"); } void UpdatesManager::on_update(tl_object_ptr update, bool force_apply, @@ -1721,18 +1755,16 @@ void UpdatesManager::on_update(tl_object_ptr &&promise) { int new_pts = update->pts_; int pts_count = update->pts_count_; - td_->messages_manager_->add_pending_update(std::move(update), new_pts, pts_count, force_apply, - "on_updateReadMessagesContents"); - promise.set_value(Unit()); + td_->messages_manager_->add_pending_update(std::move(update), new_pts, pts_count, force_apply, std::move(promise), + "updateReadMessagesContents"); } void UpdatesManager::on_update(tl_object_ptr update, bool force_apply, Promise &&promise) { int new_pts = update->pts_; int pts_count = update->pts_count_; - td_->messages_manager_->add_pending_update(std::move(update), new_pts, pts_count, force_apply, - "on_updateEditMessage"); - promise.set_value(Unit()); + td_->messages_manager_->add_pending_update(std::move(update), new_pts, pts_count, force_apply, std::move(promise), + "updateEditMessage"); } void UpdatesManager::on_update(tl_object_ptr update, bool force_apply, @@ -1741,12 +1773,12 @@ void UpdatesManager::on_update(tl_object_ptr int pts_count = update->pts_count_; if (update->messages_.empty()) { td_->messages_manager_->add_pending_update(make_tl_object(), new_pts, pts_count, force_apply, - "on_updateDeleteMessages"); + Promise(), "updateDeleteMessages"); + promise.set_value(Unit()); } else { - td_->messages_manager_->add_pending_update(std::move(update), new_pts, pts_count, force_apply, - "on_updateDeleteMessages"); + td_->messages_manager_->add_pending_update(std::move(update), new_pts, pts_count, force_apply, std::move(promise), + "updateDeleteMessages"); } - promise.set_value(Unit()); } void UpdatesManager::on_update(tl_object_ptr update, bool force_apply, @@ -1756,18 +1788,16 @@ void UpdatesManager::on_update(tl_object_ptrstill_unread_count_ = -1; } - td_->messages_manager_->add_pending_update(std::move(update), new_pts, pts_count, force_apply, - "on_updateReadHistoryInbox"); - promise.set_value(Unit()); + td_->messages_manager_->add_pending_update(std::move(update), new_pts, pts_count, force_apply, std::move(promise), + "updateReadHistoryInbox"); } void UpdatesManager::on_update(tl_object_ptr update, bool force_apply, Promise &&promise) { int new_pts = update->pts_; int pts_count = update->pts_count_; - td_->messages_manager_->add_pending_update(std::move(update), new_pts, pts_count, force_apply, - "on_updateReadHistoryOutbox"); - promise.set_value(Unit()); + td_->messages_manager_->add_pending_update(std::move(update), new_pts, pts_count, force_apply, std::move(promise), + "updateReadHistoryOutbox"); } void UpdatesManager::on_update(tl_object_ptr update, bool /*force_apply*/, @@ -1816,23 +1846,20 @@ void UpdatesManager::on_update(tl_object_ptr update void UpdatesManager::on_update(tl_object_ptr update, bool /*force_apply*/, Promise &&promise) { - td_->messages_manager_->on_update_edit_channel_message(std::move(update)); - promise.set_value(Unit()); + DialogId dialog_id = MessagesManager::get_message_dialog_id(update->message_); + int new_pts = update->pts_; + int pts_count = update->pts_count_; + td_->messages_manager_->add_pending_channel_update(dialog_id, std::move(update), new_pts, pts_count, + std::move(promise), "updateEditChannelMessage"); } void UpdatesManager::on_update(tl_object_ptr update, bool /*force_apply*/, Promise &&promise) { - ChannelId channel_id(update->channel_id_); - if (!channel_id.is_valid()) { - LOG(ERROR) << "Receive invalid " << channel_id; - } else { - DialogId dialog_id(channel_id); - int new_pts = update->pts_; - int pts_count = update->pts_count_; - td_->messages_manager_->add_pending_channel_update(dialog_id, std::move(update), new_pts, pts_count, - "on_updateDeleteChannelMessages"); - } - promise.set_value(Unit()); + DialogId dialog_id(ChannelId(update->channel_id_)); + int new_pts = update->pts_; + int pts_count = update->pts_count_; + td_->messages_manager_->add_pending_channel_update(dialog_id, std::move(update), new_pts, pts_count, + std::move(promise), "updateDeleteChannelMessages"); } void UpdatesManager::on_update(tl_object_ptr update, bool /*force_apply*/, @@ -1893,24 +1920,17 @@ void UpdatesManager::on_update(tl_object_ptr Promise &&promise) { int new_pts = update->pts_; int pts_count = update->pts_count_; - td_->messages_manager_->add_pending_update(std::move(update), new_pts, pts_count, force_apply, - "on_updatePinnedMessages"); - promise.set_value(Unit()); + td_->messages_manager_->add_pending_update(std::move(update), new_pts, pts_count, force_apply, std::move(promise), + "updatePinnedMessages"); } void UpdatesManager::on_update(tl_object_ptr update, bool /*force_apply*/, Promise &&promise) { - ChannelId channel_id(update->channel_id_); - if (!channel_id.is_valid()) { - LOG(ERROR) << "Receive invalid " << channel_id; - } else { - DialogId dialog_id(channel_id); - int new_pts = update->pts_; - int pts_count = update->pts_count_; - td_->messages_manager_->add_pending_channel_update(dialog_id, std::move(update), new_pts, pts_count, - "on_updatePinnedChannelMessages"); - } - promise.set_value(Unit()); + DialogId dialog_id(ChannelId(update->channel_id_)); + int new_pts = update->pts_; + int pts_count = update->pts_count_; + td_->messages_manager_->add_pending_channel_update(dialog_id, std::move(update), new_pts, pts_count, + std::move(promise), "updatePinnedChannelMessages"); } void UpdatesManager::on_update(tl_object_ptr update, bool /*force_apply*/, @@ -1960,21 +1980,16 @@ void UpdatesManager::on_update(tl_object_ptr update Promise &&promise) { td_->web_pages_manager_->on_get_web_page(std::move(update->webpage_), DialogId()); td_->messages_manager_->add_pending_update(make_tl_object(), update->pts_, update->pts_count_, - force_apply, "on_updateWebPage"); + force_apply, Promise(), "updateWebPage"); promise.set_value(Unit()); } void UpdatesManager::on_update(tl_object_ptr update, bool /*force_apply*/, Promise &&promise) { td_->web_pages_manager_->on_get_web_page(std::move(update->webpage_), DialogId()); - ChannelId channel_id(update->channel_id_); - if (!channel_id.is_valid()) { - LOG(ERROR) << "Receive invalid " << channel_id; - } else { - DialogId dialog_id(channel_id); - td_->messages_manager_->add_pending_channel_update(dialog_id, make_tl_object(), update->pts_, - update->pts_count_, "on_updateChannelWebPage"); - } + DialogId dialog_id(ChannelId(update->channel_id_)); + td_->messages_manager_->add_pending_channel_update(dialog_id, make_tl_object(), update->pts_, + update->pts_count_, Promise(), "updateChannelWebPage"); promise.set_value(Unit()); } @@ -1987,7 +2002,7 @@ void UpdatesManager::on_update(tl_object_ptr up } td_->messages_manager_->add_pending_update(make_tl_object(), update->pts_, update->pts_count_, - force_apply, "on_updateFolderPeers"); + force_apply, Promise(), "updateFolderPeers"); promise.set_value(Unit()); } diff --git a/td/telegram/UpdatesManager.h b/td/telegram/UpdatesManager.h index c98a6737f..92f5a2cea 100644 --- a/td/telegram/UpdatesManager.h +++ b/td/telegram/UpdatesManager.h @@ -51,6 +51,8 @@ class UpdatesManager : public Actor { static vector get_chat_dialog_ids(const telegram_api::Updates *updates_ptr); + static int32 get_update_edit_message_pts(const telegram_api::Updates *updates_ptr); + void get_difference(const char *source); void schedule_get_difference(const char *source); diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index c85bb2b81..f0071f4a3 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -59,6 +59,7 @@ #include #include #include +#include #ifdef USE_READLINE /* Standard readline include files. */ @@ -318,9 +319,8 @@ class CliClient final : public Actor { if (!messages.messages_.empty()) { auto last_message_id = messages.messages_.back()->id_; LOG(ERROR) << (last_message_id >> 20); - send_request(td_api::make_object( - search_chat_id_, "", nullptr, last_message_id, 0, 100, - td_api::make_object(), 0)); + send_request(td_api::make_object(search_chat_id_, "", nullptr, last_message_id, 0, + 100, as_search_messages_filter("pvi"), 0)); } else { search_chat_id_ = 0; } @@ -524,6 +524,13 @@ class CliClient final : public Actor { return to_integer(trim(str)); } + static int32 as_limit(Slice str, int32 default_limit = 10) { + if (str.empty()) { + return default_limit; + } + return to_integer(trim(str)); + } + int32 as_user_id(Slice str) const { str = trim(str); if (str[0] == '@') { @@ -658,6 +665,50 @@ class CliClient final : public Actor { return transform(transform(full_split(ids_string, get_delimiter(ids_string)), trim), to_integer); } + static void get_args(string &args, string &arg) { + if (&args != &arg) { + arg = std::move(args); + } + } + + static void get_args(string &args, bool &arg) { + arg = as_bool(args); + } + + struct SearchQuery { + int32 limit; + string query; + }; + + static void get_args(string &args, SearchQuery &arg) { + string limit; + std::tie(limit, arg.query) = split(trim(args)); + auto r_limit = to_integer_safe(limit); + if (r_limit.is_ok() && r_limit.ok() > 0) { + arg.limit = r_limit.ok(); + } else { + arg.limit = 10; + arg.query = std::move(args); + } + args.clear(); + } + + static void get_args(string &args, int32 &arg) { + arg = to_integer(args); + } + + static void get_args(string &args, int64 &arg) { + arg = to_integer(args); + } + + template + static void get_args(string &args, FirstType &first_arg, SecondType &second_arg, Types &... other_args) { + string arg; + std::tie(arg, args) = split(args); + get_args(arg, first_arg); + get_args(args, second_arg, other_args...); + } + void on_result(uint64 generation, uint64 id, td_api::object_ptr result) { auto result_str = to_string(result); if (result != nullptr) { @@ -1027,9 +1078,30 @@ class CliClient final : public Actor { return nullptr; } - static td_api::object_ptr as_search_messages_filter(MutableSlice filter) { + td_api::object_ptr get_user_privacy_setting_rules(Slice allow, Slice ids) const { + td::vector> rules; + if (allow == "c" || allow == "contacts") { + rules.push_back(td_api::make_object()); + } else if (allow == "users") { + rules.push_back(td_api::make_object(as_user_ids(ids))); + } else if (allow == "chats") { + rules.push_back(td_api::make_object(as_chat_ids(ids))); + } else if (as_bool(allow.str())) { + rules.push_back(td_api::make_object()); + rules.push_back(td_api::make_object()); + } else { + rules.push_back(td_api::make_object()); + } + return td_api::make_object(std::move(rules)); + } + + static td_api::object_ptr as_search_messages_filter(Slice filter) { filter = trim(filter); - to_lower_inplace(filter); + string lowered_filter = to_lower(filter); + filter = lowered_filter; + if (begins_with(filter, "search")) { + filter.remove_prefix(6); + } if (filter == "an" || filter == "animation") { return td_api::make_object(); } @@ -1117,22 +1189,60 @@ class CliClient final : public Actor { return nullptr; } + static td_api::object_ptr get_supergroup_members_filter(MutableSlice filter, + string query, + Slice message_thread_id) { + filter = trim(filter); + to_lower_inplace(filter); + if (begins_with(filter, "get")) { + filter.remove_prefix(3); + } + if (begins_with(filter, "search")) { + filter.remove_prefix(6); + } + if (begins_with(filter, "supergroup")) { + filter.remove_prefix(10); + } + if (filter == "administrators") { + return td_api::make_object(); + } + if (filter == "banned") { + return td_api::make_object(query); + } + if (filter == "bots") { + return td_api::make_object(); + } + if (filter == "contacts") { + return td_api::make_object(query); + } + if (filter == "members") { + if (query.empty()) { + return td_api::make_object(); + } else { + return td_api::make_object(query); + } + } + if (filter == "restricted") { + return td_api::make_object(query); + } + if (filter == "nentions") { + return td_api::make_object(query, + as_message_thread_id(message_thread_id)); + } + return nullptr; + } + + static bool rand_bool() { + return Random::fast_bool(); + } + td_api::object_ptr as_chat_filter(string filter) const { string title; string icon_name; string pinned_chat_ids; string included_chat_ids; string excluded_chat_ids; - std::tie(title, filter) = split(filter); - std::tie(icon_name, filter) = split(filter); - std::tie(pinned_chat_ids, filter) = split(filter); - std::tie(included_chat_ids, filter) = split(filter); - std::tie(excluded_chat_ids, filter) = split(filter); - - auto rand_bool = [] { - return Random::fast_bool(); - }; - + get_args(filter, title, icon_name, pinned_chat_ids, included_chat_ids, excluded_chat_ids); return td_api::make_object( title, icon_name, as_chat_ids(pinned_chat_ids), as_chat_ids(included_chat_ids), as_chat_ids(excluded_chat_ids), rand_bool(), rand_bool(), rand_bool(), rand_bool(), rand_bool(), rand_bool(), rand_bool(), rand_bool()); @@ -1203,6 +1313,29 @@ class CliClient final : public Actor { return td_api::make_object(); } + static td_api::object_ptr get_chat_report_reason(MutableSlice reason) { + reason = trim(reason); + if (reason == "spam") { + return td_api::make_object(); + } + if (reason == "violence") { + return td_api::make_object(); + } + if (reason == "porno") { + return td_api::make_object(); + } + if (reason == "ca") { + return td_api::make_object(); + } + if (reason == "copyright") { + return td_api::make_object(); + } + if (reason == "geo" || reason == "location") { + return td_api::make_object(); + } + return td_api::make_object(reason.str()); + } + static td_api::object_ptr get_network_type(MutableSlice type) { type = trim(type); to_lower_inplace(type); @@ -1457,9 +1590,7 @@ class CliClient final : public Actor { } else if (op == "ru") { string first_name; string last_name; - - std::tie(first_name, last_name) = split(args); - + get_args(args, first_name, last_name); send_request(td_api::make_object(first_name, last_name)); } else if (op == "cap") { send_request(td_api::make_object(args)); @@ -1495,19 +1626,16 @@ class CliClient final : public Actor { string new_password; string new_hint; string recovery_email_address; - std::tie(password, args) = split(args); + get_args(args, password, new_password, new_hint, recovery_email_address); if (password == "#") { password = ""; } - std::tie(new_password, args) = split(args); if (new_password == "#") { new_password = ""; } - std::tie(new_hint, args) = split(args); if (new_hint == "#") { new_hint = ""; } - recovery_email_address = args; if (recovery_email_address == "#") { recovery_email_address = ""; } @@ -1551,23 +1679,20 @@ class CliClient final : public Actor { "P7d2+fuJMlkjtM7oAwf+tI8CAwEAAQ==\n" "-----END PUBLIC KEY-----"; string payload; - - std::tie(bot_id, args) = split(args); - std::tie(scope, payload) = split(args); + get_args(args, bot_id, scope, payload); send_request( td_api::make_object(as_user_id(bot_id), scope, public_key, payload)); } else if (op == "gpafae") { - string form_id; + int32 form_id; string password; - std::tie(form_id, password) = split(args); - send_request(td_api::make_object( - to_integer(form_id), password)); + get_args(args, form_id, password); + send_request(td_api::make_object(form_id, password)); } else if (op == "spaf") { - string form_id; + int32 form_id; string types; - std::tie(form_id, types) = split(args); - send_request(td_api::make_object(to_integer(form_id), - as_passport_element_types(types))); + get_args(args, form_id, types); + send_request( + td_api::make_object(form_id, as_passport_element_types(types))); } else if (op == "gpcl") { send_request(td_api::make_object(args)); } else if (op == "spnvc" || op == "SendPhoneNumberVerificationCode") { @@ -1585,7 +1710,7 @@ class CliClient final : public Actor { } else if (op == "srea" || op == "SetRecoveryEmailAddress") { string password; string recovery_email_address; - std::tie(password, recovery_email_address) = split(args); + get_args(args, password, recovery_email_address); send_request(td_api::make_object(password, recovery_email_address)); } else if (op == "grea" || op == "GetRecoveryEmailAddress") { send_request(td_api::make_object(args)); @@ -1610,7 +1735,7 @@ class CliClient final : public Actor { } else if (op == "gpe") { string password; string passport_element_type; - std::tie(password, passport_element_type) = split(args); + get_args(args, password, passport_element_type); send_request( td_api::make_object(as_passport_element_type(passport_element_type), password)); } else if (op == "gape") { @@ -1620,8 +1745,7 @@ class CliClient final : public Actor { string password; string passport_element_type; string arg; - std::tie(password, args) = split(args); - std::tie(passport_element_type, arg) = split(args); + get_args(args, password, passport_element_type, arg); send_request(td_api::make_object( as_input_passport_element(passport_element_type, arg, op == "spes"), password)); } else if (op == "dpe") { @@ -1643,15 +1767,13 @@ class CliClient final : public Actor { } else if (op == "rdt") { string token; string other_user_ids_str; - - std::tie(token, other_user_ids_str) = split(args); + get_args(args, token, other_user_ids_str); send_request(td_api::make_object(td_api::make_object(token), as_user_ids(other_user_ids_str))); } else if (op == "rdu") { string token; string other_user_ids_str; - - std::tie(token, other_user_ids_str) = split(args); + get_args(args, token, other_user_ids_str); send_request(td_api::make_object( td_api::make_object(token), as_user_ids(other_user_ids_str))); } else if (op == "rdw") { @@ -1659,10 +1781,7 @@ class CliClient final : public Actor { string key; string secret; string other_user_ids_str; - - std::tie(endpoint, args) = split(args); - std::tie(key, args) = split(args); - std::tie(secret, other_user_ids_str) = split(args); + get_args(args, endpoint, key, secret, other_user_ids_str); send_request(td_api::make_object( td_api::make_object(endpoint, key, secret), as_user_ids(other_user_ids_str))); } else if (op == "gbci") { @@ -1670,29 +1789,22 @@ class CliClient final : public Actor { } else if (op == "gpf") { string chat_id; string message_id; - - std::tie(chat_id, message_id) = split(args); + get_args(args, chat_id, message_id); send_request(td_api::make_object(as_chat_id(chat_id), as_message_id(message_id))); } else if (op == "voi") { string chat_id; string message_id; - string allow_save; - - std::tie(chat_id, args) = split(args); - std::tie(message_id, allow_save) = split(args); + bool allow_save; + get_args(args, chat_id, message_id, allow_save); send_request(td_api::make_object(as_chat_id(chat_id), as_message_id(message_id), - nullptr, as_bool(allow_save))); + nullptr, allow_save)); } else if (op == "spfs") { string chat_id; string message_id; string order_info_id; string shipping_option_id; string saved_credentials_id; - - std::tie(chat_id, args) = split(args); - std::tie(message_id, args) = split(args); - std::tie(order_info_id, args) = split(args); - std::tie(shipping_option_id, saved_credentials_id) = split(args); + get_args(args, chat_id, message_id, order_info_id, shipping_option_id, saved_credentials_id); send_request(td_api::make_object( as_chat_id(chat_id), as_message_id(message_id), order_info_id, shipping_option_id, td_api::make_object(saved_credentials_id))); @@ -1702,19 +1814,14 @@ class CliClient final : public Actor { string order_info_id; string shipping_option_id; string data; - - std::tie(chat_id, args) = split(args); - std::tie(message_id, args) = split(args); - std::tie(order_info_id, args) = split(args); - std::tie(shipping_option_id, data) = split(args); + get_args(args, chat_id, message_id, order_info_id, shipping_option_id, data); send_request(td_api::make_object( as_chat_id(chat_id), as_message_id(message_id), order_info_id, shipping_option_id, td_api::make_object(data, true))); } else if (op == "gpre") { string chat_id; string message_id; - - std::tie(chat_id, message_id) = split(args); + get_args(args, chat_id, message_id); send_request(td_api::make_object(as_chat_id(chat_id), as_message_id(message_id))); } else if (op == "gsoi") { send_request(td_api::make_object()); @@ -1732,24 +1839,9 @@ class CliClient final : public Actor { string setting; string allow; string ids; - std::tie(setting, args) = split(args); - std::tie(allow, ids) = split(args); - - std::vector> rules; - if (allow == "c" || allow == "contacts") { - rules.push_back(td_api::make_object()); - } else if (allow == "users") { - rules.push_back(td_api::make_object(as_user_ids(ids))); - } else if (allow == "chats") { - rules.push_back(td_api::make_object(as_chat_ids(ids))); - } else if (as_bool(allow)) { - rules.push_back(td_api::make_object()); - rules.push_back(td_api::make_object()); - } else { - rules.push_back(td_api::make_object()); - } - send_request(td_api::make_object( - get_user_privacy_setting(setting), td_api::make_object(std::move(rules)))); + get_args(args, setting, allow, ids); + send_request(td_api::make_object(get_user_privacy_setting(setting), + get_user_privacy_setting_rules(allow, ids))); } else if (op == "cp" || op == "ChangePhone") { send_request(td_api::make_object(args, nullptr)); } else if (op == "ccpc" || op == "CheckChangePhoneCode") { @@ -1760,21 +1852,17 @@ class CliClient final : public Actor { if (args.empty()) { send_request(td_api::make_object()); } else { - auto limit = to_integer(args); - send_request(td_api::make_object("", limit)); + send_request(td_api::make_object("", as_limit(args))); } } else if (op == "AddContact") { string user_id; string first_name; string last_name; - std::tie(user_id, args) = split(args); - std::tie(first_name, last_name) = split(args); - + get_args(args, user_id, first_name, last_name); send_request(td_api::make_object( td_api::make_object(string(), first_name, last_name, string(), as_user_id(user_id)), false)); } else if (op == "spn") { string user_id = args; - send_request(td_api::make_object(as_user_id(user_id))); } else if (op == "ImportContacts" || op == "cic") { vector contacts_str = full_split(args, ';'); @@ -1787,7 +1875,6 @@ class CliClient final : public Actor { std::tie(first_name, last_name) = split(c, ','); contacts.push_back(td_api::make_object(phone_number, first_name, last_name, string(), 0)); } - if (op == "cic") { send_request(td_api::make_object(std::move(contacts))); } else { @@ -1807,13 +1894,7 @@ class CliClient final : public Actor { string limit; string offset_order_string; string offset_chat_id; - - std::tie(limit, args) = split(args); - std::tie(offset_order_string, offset_chat_id) = split(args); - - if (limit.empty()) { - limit = "10000"; - } + get_args(args, limit, offset_order_string, offset_chat_id); int64 offset_order; if (offset_order_string.empty()) { offset_order = std::numeric_limits::max(); @@ -1821,7 +1902,7 @@ class CliClient final : public Actor { offset_order = to_integer(offset_order_string); } send_request(td_api::make_object(as_chat_list(op), offset_order, as_chat_id(offset_chat_id), - to_integer(limit))); + as_limit(limit, 10000))); } else if (op == "gctest") { send_request(td_api::make_object(nullptr, std::numeric_limits::max(), 0, 1)); send_request(td_api::make_object(nullptr, std::numeric_limits::max(), 0, 10)); @@ -1830,48 +1911,26 @@ class CliClient final : public Actor { string user_id; string offset_chat_id; string limit; - - std::tie(user_id, args) = split(args); - std::tie(offset_chat_id, limit) = split(args); - - if (limit.empty()) { - limit = "100"; - } + get_args(args, user_id, offset_chat_id, limit); send_request(td_api::make_object(as_user_id(user_id), as_chat_id(offset_chat_id), - to_integer(limit))); + as_limit(limit, 100))); } else if (op == "gh" || op == "GetHistory" || op == "ghl" || op == "gmth") { string chat_id; string thread_message_id; string from_message_id; - string offset; + int32 offset; string limit; - - std::tie(chat_id, args) = split(args); if (op == "gmth") { - std::tie(thread_message_id, args) = split(args); + get_args(args, thread_message_id, args); } - std::tie(from_message_id, args) = split(args); - if (from_message_id.empty()) { - from_message_id = "0"; - } - std::tie(offset, args) = split(args); - if (offset.empty()) { - offset = "0"; - } - std::tie(limit, args) = split(args); - if (limit.empty()) { - limit = "10"; - } - if (!args.empty()) { - LOG(ERROR) << "Wrong parameters to function getChatHistory specified"; - } else if (op == "gmth") { + get_args(args, chat_id, from_message_id, offset, limit); + if (op == "gmth") { send_request(td_api::make_object( - as_chat_id(chat_id), as_message_id(thread_message_id), as_message_id(from_message_id), - to_integer(offset), to_integer(limit))); + as_chat_id(chat_id), as_message_id(thread_message_id), as_message_id(from_message_id), offset, + as_limit(limit))); } else { send_request(td_api::make_object(as_chat_id(chat_id), as_message_id(from_message_id), - to_integer(offset), to_integer(limit), - op == "ghl")); + offset, as_limit(limit), op == "ghl")); } } else if (op == "gcsm") { string chat_id = args; @@ -1881,43 +1940,29 @@ class CliClient final : public Actor { string message_id; string offset; string limit; - - std::tie(chat_id, args) = split(args); - std::tie(message_id, args) = split(args); - std::tie(offset, limit) = split(args); - + get_args(args, chat_id, message_id, offset, limit); send_request(td_api::make_object(as_chat_id(chat_id), as_message_id(message_id), - offset, to_integer(limit))); + offset, as_limit(limit))); } else if (op == "ghf") { get_history_chat_id_ = as_chat_id(args); - send_request(td_api::make_object(get_history_chat_id_, std::numeric_limits::max(), 0, 100, false)); } else if (op == "replies") { string chat_id; string message_thread_id; - - std::tie(chat_id, message_thread_id) = split(args); + get_args(args, chat_id, message_thread_id); send_request(td_api::make_object(as_chat_id(chat_id), "", nullptr, 0, 0, 100, nullptr, as_message_thread_id(message_thread_id))); } else if (op == "spvf") { search_chat_id_ = as_chat_id(args); - - send_request(td_api::make_object( - search_chat_id_, "", nullptr, 0, 0, 100, td_api::make_object(), - 0)); + send_request(td_api::make_object(search_chat_id_, "", nullptr, 0, 0, 100, + as_search_messages_filter("pvi"), 0)); } else if (op == "Search" || op == "SearchA" || op == "SearchM") { - string from_date; - string limit; string query; + string limit; string filter; - - std::tie(query, args) = split(args); - std::tie(limit, args) = split(args); - std::tie(filter, from_date) = split(args); - if (from_date.empty()) { - from_date = "0"; - } + int32 from_date; + get_args(args, query, limit, filter, from_date); td_api::object_ptr chat_list; if (op == "SearchA") { chat_list = td_api::make_object(); @@ -1925,205 +1970,76 @@ class CliClient final : public Actor { if (op == "SearchM") { chat_list = td_api::make_object(); } - send_request(td_api::make_object( - std::move(chat_list), query, to_integer(from_date), 2147483647, 0, to_integer(limit), - as_search_messages_filter(filter), 1, 2147483647)); + send_request(td_api::make_object(std::move(chat_list), query, from_date, 2147483647, 0, + as_limit(limit), as_search_messages_filter(filter), 1, + 2147483647)); } else if (op == "SCM") { string chat_id; - string limit; - string query; - - std::tie(chat_id, args) = split(args); - std::tie(limit, query) = split(args); - if (limit.empty()) { - limit = "10"; - } - - send_request(td_api::make_object(as_chat_id(chat_id), query, nullptr, 0, 0, - to_integer(limit), nullptr, 0)); + SearchQuery query; + get_args(args, chat_id, query); + send_request(td_api::make_object(as_chat_id(chat_id), query.query, nullptr, 0, 0, + query.limit, nullptr, 0)); } else if (op == "SMME") { string chat_id; string limit; - - std::tie(chat_id, limit) = split(args); - if (limit.empty()) { - limit = "10"; - } - + get_args(args, chat_id, limit); send_request(td_api::make_object( - as_chat_id(chat_id), "", td_api::make_object(my_id_), 0, 0, - to_integer(limit), nullptr, 0)); + as_chat_id(chat_id), "", td_api::make_object(my_id_), 0, 0, as_limit(limit), + nullptr, 0)); } else if (op == "SMU" || op == "SMC") { string chat_id; string sender_id; string limit; - - std::tie(chat_id, args) = split(args); - std::tie(sender_id, limit) = split(args); - if (limit.empty()) { - limit = "10"; - } - + get_args(args, chat_id, sender_id, limit); send_request(td_api::make_object( - as_chat_id(chat_id), "", as_message_sender(sender_id), 0, 0, to_integer(limit), nullptr, 0)); + as_chat_id(chat_id), "", as_message_sender(sender_id), 0, 0, as_limit(limit), nullptr, 0)); } else if (op == "SM") { string chat_id; string filter; string limit; string offset_message_id; - string offset; - - std::tie(chat_id, args) = split(args); - std::tie(filter, args) = split(args); - std::tie(limit, args) = split(args); - std::tie(offset_message_id, offset) = split(args); - if (limit.empty()) { - limit = "10"; - } - if (offset_message_id.empty()) { - offset_message_id = "0"; - } - if (offset.empty()) { - offset = "0"; - } - + int32 offset; + get_args(args, chat_id, filter, limit, offset_message_id, offset); send_request(td_api::make_object( - as_chat_id(chat_id), "", nullptr, as_message_id(offset_message_id), to_integer(offset), - to_integer(limit), as_search_messages_filter(filter), 0)); + as_chat_id(chat_id), "", nullptr, as_message_id(offset_message_id), offset, as_limit(limit), + as_search_messages_filter(filter), 0)); } else if (op == "SC") { string limit; string offset_message_id; - string only_missed; - - std::tie(limit, args) = split(args); - std::tie(offset_message_id, only_missed) = split(args); - if (limit.empty()) { - limit = "10"; - } - if (offset_message_id.empty()) { - offset_message_id = "0"; - } - - send_request(td_api::make_object(as_message_id(offset_message_id), - to_integer(limit), as_bool(only_missed))); + bool only_missed; + get_args(args, limit, offset_message_id, only_missed); + send_request(td_api::make_object(as_message_id(offset_message_id), as_limit(limit), + only_missed)); } else if (op == "SCRLM") { string chat_id; string limit; - - std::tie(chat_id, limit) = split(args); - if (limit.empty()) { - limit = "10"; - } - - send_request( - td_api::make_object(as_chat_id(chat_id), to_integer(limit))); - } else if (op == "SearchAudio") { + get_args(args, chat_id, limit); + send_request(td_api::make_object(as_chat_id(chat_id), as_limit(limit))); + } else if (op == "SearchAudio" || op == "SearchDocument" || op == "SearchPhoto" || op == "SearchChatPhoto") { string chat_id; string offset_message_id; - string limit; - string query; - - std::tie(chat_id, args) = split(args); - std::tie(offset_message_id, args) = split(args); - if (offset_message_id.empty()) { - offset_message_id = "0"; - } - std::tie(limit, query) = split(args); - if (limit.empty()) { - limit = "10"; - } - send_request(td_api::make_object( - as_chat_id(chat_id), query, nullptr, as_message_id(offset_message_id), 0, to_integer(limit), - td_api::make_object(), 0)); - } else if (op == "SearchDocument") { - string chat_id; - string offset_message_id; - string limit; - string query; - - std::tie(chat_id, args) = split(args); - std::tie(offset_message_id, args) = split(args); - if (offset_message_id.empty()) { - offset_message_id = "0"; - } - std::tie(limit, query) = split(args); - if (limit.empty()) { - limit = "10"; - } - send_request(td_api::make_object( - as_chat_id(chat_id), query, nullptr, to_integer(offset_message_id), 0, to_integer(limit), - td_api::make_object(), 0)); - } else if (op == "SearchPhoto") { - string chat_id; - string offset_message_id; - string limit; - string query; - - std::tie(chat_id, args) = split(args); - std::tie(offset_message_id, args) = split(args); - if (offset_message_id.empty()) { - offset_message_id = "2000000000000000000"; - } - std::tie(limit, query) = split(args); - if (limit.empty()) { - limit = "10"; - } - send_request(td_api::make_object( - as_chat_id(chat_id), query, nullptr, as_message_id(offset_message_id), 0, to_integer(limit), - td_api::make_object(), 0)); - } else if (op == "SearchChatPhoto") { - string chat_id; - string offset_message_id; - string limit; - string query; - - std::tie(chat_id, args) = split(args); - std::tie(offset_message_id, args) = split(args); - if (offset_message_id.empty()) { - offset_message_id = "2000000000000000000"; - } - std::tie(limit, query) = split(args); - if (limit.empty()) { - limit = "10"; - } - send_request(td_api::make_object( - as_chat_id(chat_id), query, nullptr, as_message_id(offset_message_id), 0, to_integer(limit), - td_api::make_object(), 0)); + SearchQuery query; + get_args(args, chat_id, offset_message_id, query); + send_request(td_api::make_object(as_chat_id(chat_id), query.query, nullptr, + as_message_id(offset_message_id), 0, query.limit, + as_search_messages_filter(op), 0)); } else if (op == "gcmc") { string chat_id; string filter; - string return_local; - - std::tie(chat_id, args) = split(args); - std::tie(filter, return_local) = split(args); - - send_request(td_api::make_object( - as_chat_id(chat_id), as_search_messages_filter(filter), as_bool(return_local))); + bool return_local; + get_args(args, chat_id, filter, return_local); + send_request(td_api::make_object(as_chat_id(chat_id), + as_search_messages_filter(filter), return_local)); } else if (op == "gup" || op == "gupp") { string user_id; - string offset; + int32 offset; string limit; - - std::tie(user_id, args) = split(args); - std::tie(offset, args) = split(args); - if (offset.empty()) { - offset = "0"; - } - std::tie(limit, args) = split(args); - if (limit.empty()) { - limit = "10"; - } - if (!args.empty()) { - LOG(ERROR) << "Wrong parameters to function getUserProfilePhotos specified"; - } else { - send_request(td_api::make_object(as_user_id(user_id), to_integer(offset), - to_integer(limit))); - } + get_args(args, user_id, offset, limit); + send_request(td_api::make_object(as_user_id(user_id), offset, as_limit(limit))); } else if (op == "dcrm") { string chat_id; string message_id; - - std::tie(chat_id, message_id) = split(args); + get_args(args, chat_id, message_id); send_request(td_api::make_object(as_chat_id(chat_id), as_message_id(message_id))); } else if (op == "glti") { send_request(td_api::make_object(as_bool(args))); @@ -2132,18 +2048,14 @@ class CliClient final : public Actor { } else if (op == "glps") { string language_code; string keys; - - std::tie(language_code, keys) = split(args); + get_args(args, language_code, keys); send_request(td_api::make_object(language_code, full_split(keys))); } else if (op == "glpss") { string language_database_path; string language_pack; string language_code; string key; - - std::tie(language_database_path, args) = split(args); - std::tie(language_pack, args) = split(args); - std::tie(language_code, key) = split(args); + get_args(args, language_database_path, language_pack, language_code, key); send_request(td_api::make_object(language_database_path, language_pack, language_code, key)); } else if (op == "synclp") { @@ -2157,11 +2069,7 @@ class CliClient final : public Actor { string name; string native_name; string key; - - std::tie(language_code, args) = split(args); - std::tie(name, args) = split(args); - std::tie(native_name, key) = split(args); - + get_args(args, language_code, name, native_name, key); vector> strings; strings.push_back(td_api::make_object( key, td_api::make_object("Ordinary value"))); @@ -2170,27 +2078,20 @@ class CliClient final : public Actor { "Few", "Many", "Other"))); strings.push_back(td_api::make_object( "DELETED", td_api::make_object())); - send_request(td_api::make_object( as_language_pack_info(language_code, name, native_name), std::move(strings))); } else if (op == "eclpi") { string language_code; string name; string native_name; - - std::tie(language_code, args) = split(args); - std::tie(name, native_name) = split(args); - + get_args(args, language_code, name, native_name); send_request(td_api::make_object( as_language_pack_info(language_code, name, native_name))); } else if (op == "sclpsv" || op == "sclpsp" || op == "sclpsd") { string language_code; string key; string value; - - std::tie(language_code, args) = split(args); - std::tie(key, value) = split(args); - + get_args(args, language_code, key, value); td_api::object_ptr str = td_api::make_object(key, nullptr); if (op == "sclsv") { @@ -2201,7 +2102,6 @@ class CliClient final : public Actor { } else { str->value_ = td_api::make_object(); } - send_request(td_api::make_object(language_code, std::move(str))); } else if (op == "dlp") { send_request(td_api::make_object(args)); @@ -2209,26 +2109,22 @@ class CliClient final : public Actor { send_request(td_api::make_object(args)); } else if (op == "sob") { string name; - string value; - - std::tie(name, value) = split(args); - send_request(td_api::make_object( - name, td_api::make_object(as_bool(value)))); + bool value; + get_args(args, name, value); + send_request( + td_api::make_object(name, td_api::make_object(value))); } else if (op == "soe") { send_request(td_api::make_object(args, td_api::make_object())); } else if (op == "soi") { string name; - string value; - - std::tie(name, value) = split(args); - auto value_int = to_integer(value); + int64 value; + get_args(args, name, value); send_request( - td_api::make_object(name, td_api::make_object(value_int))); + td_api::make_object(name, td_api::make_object(value))); } else if (op == "sos") { string name; string value; - - std::tie(name, value) = split(args); + get_args(args, name, value); send_request(td_api::make_object(name, td_api::make_object(value))); } else if (op == "me") { send_request(td_api::make_object()); @@ -2293,10 +2189,10 @@ class CliClient final : public Actor { send_request(td_api::make_object(nullptr, get_solid_background(to_integer(args)), op == "sbgsd")); } else if (op == "sbgg" || op == "sbggd") { - string top_color; - string bottom_color; - std::tie(top_color, bottom_color) = split(args); - auto background_type = get_gradient_background(to_integer(top_color), to_integer(bottom_color)); + int32 top_color; + int32 bottom_color; + get_args(args, top_color, bottom_color); + auto background_type = get_gradient_background(top_color, bottom_color); send_request(td_api::make_object(nullptr, std::move(background_type), op == "sbggd")); } else if (op == "sbgwid" || op == "sbgwidd") { send_request(td_api::make_object( @@ -2325,61 +2221,42 @@ class CliClient final : public Actor { } else if (op == "tme") { send_request(td_api::make_object(args)); } else if (op == "gbms") { - string offset; + int32 offset; string limit; - - std::tie(offset, limit) = split(args); - if (offset.empty()) { - offset = "0"; - } - if (limit.empty()) { - limit = "10"; - } - send_request( - td_api::make_object(to_integer(offset), to_integer(limit))); + get_args(args, offset, limit); + send_request(td_api::make_object(offset, as_limit(limit))); } else if (op == "gu") { send_request(td_api::make_object(as_user_id(args))); } else if (op == "gsu") { send_request(td_api::make_object()); } else if (op == "gs") { - string limit; - string emoji; - std::tie(limit, emoji) = split(args); - send_request(td_api::make_object(emoji, to_integer(limit))); + SearchQuery query; + get_args(args, query); + send_request(td_api::make_object(query.query, query.limit)); } else if (op == "sst") { - string limit; - string emoji; - std::tie(limit, emoji) = split(args); - send_request(td_api::make_object(emoji, to_integer(limit))); + SearchQuery query; + get_args(args, query); + send_request(td_api::make_object(query.query, query.limit)); } else if (op == "gss") { send_request(td_api::make_object(to_integer(args))); } else if (op == "giss") { send_request(td_api::make_object(as_bool(args))); } else if (op == "gass") { - string is_masks; - string offset_sticker_set_id; + bool is_masks; + int64 offset_sticker_set_id; string limit; - - std::tie(is_masks, args) = split(args); - std::tie(offset_sticker_set_id, limit) = split(args); - - send_request(td_api::make_object( - as_bool(is_masks), to_integer(offset_sticker_set_id), to_integer(limit))); - } else if (op == "gtss") { - string offset; - string limit; - - std::tie(offset, limit) = split(args); - if (limit.empty()) { - limit = "1000"; - } + get_args(args, is_masks, offset_sticker_set_id, limit); send_request( - td_api::make_object(to_integer(offset), to_integer(limit))); + td_api::make_object(is_masks, offset_sticker_set_id, as_limit(limit))); + } else if (op == "gtss") { + int32 offset; + string limit; + get_args(args, offset, limit); + send_request(td_api::make_object(offset, as_limit(limit, 1000))); } else if (op == "gatss") { send_request(td_api::make_object(as_file_id(args))); } else if (op == "storage") { - auto chat_limit = to_integer(args); - send_request(td_api::make_object(chat_limit)); + send_request(td_api::make_object(as_limit(args))); } else if (op == "storage_fast") { send_request(td_api::make_object()); } else if (op == "database") { @@ -2389,12 +2266,11 @@ class CliClient final : public Actor { } else if (op == "optimize_storage" || op == "optimize_storage_all") { string chat_ids; string exclude_chat_ids; - string chat_ids_limit; - std::tie(chat_ids, args) = split(args); - std::tie(exclude_chat_ids, chat_ids_limit) = split(args); + int32 chat_ids_limit; + get_args(args, chat_ids, exclude_chat_ids, chat_ids_limit); send_request(td_api::make_object( 10000000, -1, -1, 0, std::vector>(), as_chat_ids(chat_ids), - as_chat_ids(exclude_chat_ids), op == "optimize_storage", to_integer(chat_ids_limit))); + as_chat_ids(exclude_chat_ids), op == "optimize_storage", chat_ids_limit)); } else if (op == "clean_storage_default") { send_request(td_api::make_object()); } else if (op == "clean_photos") { @@ -2433,34 +2309,29 @@ class CliClient final : public Actor { send_request(td_api::make_object( td_api::make_object(), get_network_type(args))); } else if (op == "ansc") { - string sent_bytes; - string received_bytes; + int32 sent_bytes; + int32 received_bytes; string duration; string network_type; - std::tie(sent_bytes, args) = split(args); - std::tie(received_bytes, args) = split(args); - std::tie(duration, network_type) = split(args); + get_args(args, sent_bytes, received_bytes, duration, network_type); send_request( td_api::make_object(td_api::make_object( - get_network_type(network_type), to_integer(sent_bytes), to_integer(received_bytes), - to_double(duration)))); + get_network_type(network_type), sent_bytes, received_bytes, to_double(duration)))); } else if (op == "ans") { - string sent_bytes; - string received_bytes; + int32 sent_bytes; + int32 received_bytes; string network_type; - std::tie(sent_bytes, args) = split(args); - std::tie(received_bytes, network_type) = split(args); + get_args(args, sent_bytes, received_bytes, network_type); send_request( td_api::make_object(td_api::make_object( - td_api::make_object(), get_network_type(network_type), - to_integer(sent_bytes), to_integer(received_bytes)))); + td_api::make_object(), get_network_type(network_type), sent_bytes, + received_bytes))); } else if (op == "top_chats") { send_request(td_api::make_object(get_top_chat_category(args), 50)); } else if (op == "rtc") { string chat_id; string category; - std::tie(chat_id, category) = split(args); - + get_args(args, chat_id, category); send_request(td_api::make_object(get_top_chat_category(category), as_chat_id(chat_id))); } else if (op == "sss") { send_request(td_api::make_object(args)); @@ -2469,42 +2340,30 @@ class CliClient final : public Actor { } else if (op == "ssss") { send_request(td_api::make_object(args)); } else if (op == "css") { - string set_id; - string is_installed; - string is_archived; - - std::tie(set_id, args) = split(args); - std::tie(is_installed, is_archived) = split(args); - - send_request(td_api::make_object(to_integer(set_id), as_bool(is_installed), - as_bool(is_archived))); + int64 set_id; + bool is_installed; + bool is_archived; + get_args(args, set_id, is_installed, is_archived); + send_request(td_api::make_object(set_id, is_installed, is_archived)); } else if (op == "vtss") { send_request(td_api::make_object(to_integers(args))); } else if (op == "riss") { - string is_masks; + bool is_masks; string new_order; - - std::tie(is_masks, new_order) = split(args); - - send_request( - td_api::make_object(as_bool(is_masks), to_integers(new_order))); + get_args(args, is_masks, new_order); + send_request(td_api::make_object(is_masks, to_integers(new_order))); } else if (op == "grs") { send_request(td_api::make_object(as_bool(args))); } else if (op == "ars") { - string is_attached; + bool is_attached; string sticker_id; - - std::tie(is_attached, sticker_id) = split(args); - - send_request(td_api::make_object(as_bool(is_attached), as_input_file_id(sticker_id))); + get_args(args, is_attached, sticker_id); + send_request(td_api::make_object(is_attached, as_input_file_id(sticker_id))); } else if (op == "rrs") { - string is_attached; + bool is_attached; string sticker_id; - - std::tie(is_attached, sticker_id) = split(args); - - send_request( - td_api::make_object(as_bool(is_attached), as_input_file_id(sticker_id))); + get_args(args, is_attached, sticker_id); + send_request(td_api::make_object(is_attached, as_input_file_id(sticker_id))); } else if (op == "gfs") { send_request(td_api::make_object()); } else if (op == "afs") { @@ -2547,20 +2406,15 @@ class CliClient final : public Actor { send_request(td_api::make_object(as_secret_chat_id(args))); } else if (op == "scm") { string chat_id; - string limit; - string query; string filter; - - std::tie(chat_id, args) = split(args); - std::tie(limit, args) = split(args); - std::tie(query, filter) = split(args); - send_request(td_api::make_object(as_chat_id(chat_id), query, to_integer(limit), + SearchQuery query; + get_args(args, chat_id, filter, query); + send_request(td_api::make_object(as_chat_id(chat_id), query.query, query.limit, get_chat_members_filter(filter))); } else if (op == "gcm") { string chat_id; string user_id; - - std::tie(chat_id, user_id) = split(args); + get_args(args, chat_id, user_id); send_request(td_api::make_object(as_chat_id(chat_id), as_user_id(user_id))); } else if (op == "GetChatAdministrators") { string chat_id = args; @@ -2569,47 +2423,16 @@ class CliClient final : public Actor { op == "GetSupergroupContacts" || op == "GetSupergroupMembers" || op == "GetSupergroupRestricted" || op == "SearchSupergroupMembers" || op == "SearchSupergroupMentions") { string supergroup_id; - string query; string message_thread_id; - string offset; - string limit; - - std::tie(supergroup_id, args) = split(args); - if (op == "GetSupergroupBanned" || op == "GetSupergroupContacts" || op == "GetSupergroupRestricted" || - op == "SearchSupergroupMembers" || op == "SearchSupergroupMentions") { - std::tie(query, args) = split(args); - } + int32 offset; + SearchQuery query; if (op == "SearchSupergroupMentions") { - std::tie(message_thread_id, args) = split(args); - } - std::tie(offset, limit) = split(args); - if (offset.empty()) { - offset = "0"; - } - if (limit.empty()) { - limit = "10"; - } - td_api::object_ptr filter; - if (op == "GetSupergroupAdministrators") { - filter = td_api::make_object(); - } else if (op == "GetSupergroupBanned") { - filter = td_api::make_object(query); - } else if (op == "GetSupergroupBots") { - filter = td_api::make_object(); - } else if (op == "GetSupergroupContacts") { - filter = td_api::make_object(query); - } else if (op == "GetSupergroupMembers") { - filter = td_api::make_object(); - } else if (op == "GetSupergroupRestricted") { - filter = td_api::make_object(query); - } else if (op == "SearchSupergroupMembers") { - filter = td_api::make_object(query); - } else if (op == "SearchSupergroupMentions") { - filter = - td_api::make_object(query, as_message_thread_id(message_thread_id)); + get_args(args, message_thread_id, args); } + get_args(args, supergroup_id, offset, query); send_request(td_api::make_object( - as_supergroup_id(supergroup_id), std::move(filter), to_integer(offset), to_integer(limit))); + as_supergroup_id(supergroup_id), get_supergroup_members_filter(op, query.query, message_thread_id), offset, + query.limit)); } else if (op == "gdialog" || op == "gd") { send_request(td_api::make_object(as_chat_id(args))); } else if (op == "open") { @@ -2619,32 +2442,30 @@ class CliClient final : public Actor { } else if (op == "gm") { string chat_id; string message_id; - std::tie(chat_id, message_id) = split(args); + get_args(args, chat_id, message_id); send_request(td_api::make_object(as_chat_id(chat_id), as_message_id(message_id))); } else if (op == "gmf") { string chat_id; - string from_message_id_str; - string to_message_id_str; - std::tie(chat_id, args) = split(args); - std::tie(from_message_id_str, to_message_id_str) = split(args); - auto to_message_id = to_integer(to_message_id_str); - for (auto message_id = to_integer(from_message_id_str); message_id <= to_message_id; message_id++) { + int64 from_message_id; + int64 to_message_id; + get_args(args, chat_id, from_message_id, to_message_id); + for (auto message_id = from_message_id; message_id <= to_message_id; message_id++) { send_request(td_api::make_object(as_chat_id(chat_id), message_id << 20)); } } else if (op == "gml") { string chat_id; string message_id; - std::tie(chat_id, message_id) = split(args); + get_args(args, chat_id, message_id); send_request(td_api::make_object(as_chat_id(chat_id), as_message_id(message_id))); } else if (op == "grm") { string chat_id; string message_id; - std::tie(chat_id, message_id) = split(args); + get_args(args, chat_id, message_id); send_request(td_api::make_object(as_chat_id(chat_id), as_message_id(message_id))); } else if (op == "gmt") { string chat_id; string message_id; - std::tie(chat_id, message_id) = split(args); + get_args(args, chat_id, message_id); send_request(td_api::make_object(as_chat_id(chat_id), as_message_id(message_id))); } else if (op == "gcpm") { string chat_id = args; @@ -2652,98 +2473,79 @@ class CliClient final : public Actor { } else if (op == "gms") { string chat_id; string message_ids; - std::tie(chat_id, message_ids) = split(args); + get_args(args, chat_id, message_ids); send_request(td_api::make_object(as_chat_id(chat_id), as_message_ids(message_ids))); } else if (op == "gmlink") { string chat_id; string message_id; - string for_album; - string for_comment; - std::tie(chat_id, args) = split(args); - std::tie(message_id, args) = split(args); - std::tie(for_album, for_comment) = split(args); + bool for_album; + bool for_comment; + get_args(args, chat_id, message_id, for_album, for_comment); send_request(td_api::make_object(as_chat_id(chat_id), as_message_id(message_id), - as_bool(for_album), as_bool(for_comment))); + for_album, for_comment)); } else if (op == "gmec") { string chat_id; string message_id; - string for_album; - std::tie(chat_id, args) = split(args); - std::tie(message_id, for_album) = split(args); + bool for_album; + get_args(args, chat_id, message_id, for_album); send_request(td_api::make_object(as_chat_id(chat_id), as_message_id(message_id), - as_bool(for_album))); + for_album)); } else if (op == "gmli") { send_request(td_api::make_object(args)); } else if (op == "gcmbd") { string chat_id; - string date; - std::tie(chat_id, date) = split(args); - send_request(td_api::make_object(as_chat_id(chat_id), to_integer(date))); + int32 date; + get_args(args, chat_id, date); + send_request(td_api::make_object(as_chat_id(chat_id), date)); } else if (op == "gf" || op == "GetFile") { send_request(td_api::make_object(as_file_id(args))); } else if (op == "gfdps") { string file_id; - string offset; - std::tie(file_id, offset) = split(args); - send_request( - td_api::make_object(as_file_id(file_id), to_integer(offset))); + int32 offset; + get_args(args, file_id, offset); + send_request(td_api::make_object(as_file_id(file_id), offset)); } else if (op == "rfp") { string file_id; - string offset; - string count; - std::tie(file_id, args) = split(args); - std::tie(offset, count) = split(args); - - send_request(td_api::make_object(as_file_id(file_id), to_integer(offset), - to_integer(count))); + int32 offset; + int32 count; + get_args(args, file_id, offset, count); + send_request(td_api::make_object(as_file_id(file_id), offset, count)); } else if (op == "grf") { send_request(td_api::make_object(args, nullptr)); } else if (op == "gmtf") { string latitude; string longitude; - string zoom; - string width; - string height; - string scale; + int32 zoom; + int32 width; + int32 height; + int32 scale; string chat_id; - std::tie(latitude, args) = split(args); - std::tie(longitude, args) = split(args); - std::tie(zoom, args) = split(args); - std::tie(width, args) = split(args); - std::tie(height, args) = split(args); - std::tie(scale, chat_id) = split(args); - - send_request(td_api::make_object( - as_location(latitude, longitude), to_integer(zoom), to_integer(width), - to_integer(height), to_integer(scale), as_chat_id(chat_id))); + get_args(args, latitude, longitude, zoom, width, height, scale, chat_id); + send_request(td_api::make_object(as_location(latitude, longitude), zoom, width, + height, scale, as_chat_id(chat_id))); } else if (op == "df" || op == "DownloadFile" || op == "dff" || op == "dfs") { string file_id; - string priority; - string offset; + int32 priority; + int32 offset; string limit; - std::tie(file_id, args) = split(args); - std::tie(offset, args) = split(args); - std::tie(limit, priority) = split(args); - if (priority.empty()) { - priority = "1"; + get_args(args, file_id, offset, limit, priority); + if (priority <= 0) { + priority = 1; } - int32 max_file_id = as_file_id(file_id); int32 min_file_id = (op == "dff" ? 1 : max_file_id); for (int32 i = min_file_id; i <= max_file_id; i++) { - send_request(td_api::make_object( - i, to_integer(priority), to_integer(offset), to_integer(limit), op == "dfs")); + send_request(td_api::make_object(i, priority, offset, as_limit(limit), op == "dfs")); } } else if (op == "cdf") { send_request(td_api::make_object(as_file_id(args), false)); } else if (op == "uf" || op == "ufs" || op == "ufse") { string file_path; - string priority; - std::tie(file_path, priority) = split(args); - if (priority.empty()) { - priority = "1"; + int32 priority; + get_args(args, file_path, priority); + if (priority <= 0) { + priority = 1; } - td_api::object_ptr type = td_api::make_object(); if (op == "ufs") { type = td_api::make_object(); @@ -2751,13 +2553,11 @@ class CliClient final : public Actor { if (op == "ufse") { type = td_api::make_object(); } - - send_request(td_api::make_object(as_input_file(file_path), std::move(type), - to_integer(priority))); + send_request(td_api::make_object(as_input_file(file_path), std::move(type), priority)); } else if (op == "ufg") { string file_path; string conversion; - std::tie(file_path, conversion) = split(args); + get_args(args, file_path, conversion); send_request(td_api::make_object(as_generated_file(file_path, conversion), td_api::make_object(), 1)); } else if (op == "cuf") { @@ -2768,26 +2568,22 @@ class CliClient final : public Actor { } else if (op == "dm" || op == "dmr") { string chat_id; string message_ids; - std::tie(chat_id, message_ids) = split(args); - + get_args(args, chat_id, message_ids); send_request( td_api::make_object(as_chat_id(chat_id), as_message_ids(message_ids), op == "dmr")); } else if (op == "fm" || op == "cm") { string chat_id; string from_chat_id; string message_ids; - std::tie(chat_id, args) = split(args); - std::tie(from_chat_id, message_ids) = split(args); - + get_args(args, chat_id, from_chat_id, message_ids); auto chat = as_chat_id(chat_id); - send_request(td_api::make_object( - chat, as_chat_id(from_chat_id), as_message_ids(message_ids), default_message_send_options(), op[0] == 'c', - Random::fast_bool())); + send_request( + td_api::make_object(chat, as_chat_id(from_chat_id), as_message_ids(message_ids), + default_message_send_options(), op[0] == 'c', rand_bool())); } else if (op == "resend") { string chat_id; string message_ids; - std::tie(chat_id, message_ids) = split(args); - + get_args(args, chat_id, message_ids); send_request(td_api::make_object(as_chat_id(chat_id), as_message_ids(message_ids))); } else if (op == "csc" || op == "CreateSecretChat") { send_request(td_api::make_object(as_secret_chat_id(args))); @@ -2797,16 +2593,15 @@ class CliClient final : public Actor { send_request(td_api::make_object(as_chat_id(args))); } else if (op == "sscttl" || op == "setSecretChatTtl") { string chat_id; - string ttl; - std::tie(chat_id, ttl) = split(args); - - send_request(td_api::make_object(as_chat_id(chat_id), to_integer(ttl))); + int32 ttl; + get_args(args, chat_id, ttl); + send_request(td_api::make_object(as_chat_id(chat_id), ttl)); } else if (op == "closeSC" || op == "cancelSC") { send_request(td_api::make_object(as_secret_chat_id(args))); } else if (op == "cc" || op == "CreateCall") { send_request(td_api::make_object( as_user_id(args), td_api::make_object(true, true, 65, 65, vector{"2.6", "3.0"}), - Random::fast_bool())); + rand_bool())); } else if (op == "ac" || op == "AcceptCall") { send_request(td_api::make_object( as_call_id(args), @@ -2815,16 +2610,13 @@ class CliClient final : public Actor { send_request(td_api::make_object(as_call_id(args), "abacaba")); } else if (op == "dc" || op == "DiscardCall") { string call_id; - string is_disconnected; - std::tie(call_id, is_disconnected) = split(args); - - send_request(td_api::make_object(as_call_id(call_id), as_bool(is_disconnected), 0, - Random::fast_bool(), 0)); + bool is_disconnected; + get_args(args, call_id, is_disconnected); + send_request(td_api::make_object(as_call_id(call_id), is_disconnected, 0, rand_bool(), 0)); } else if (op == "scr" || op == "SendCallRating") { string call_id; - string rating; - std::tie(call_id, rating) = split(args); - + int32 rating; + get_args(args, call_id, rating); vector> problems; problems.emplace_back(td_api::make_object()); problems.emplace_back(td_api::make_object()); @@ -2835,7 +2627,7 @@ class CliClient final : public Actor { problems.emplace_back(td_api::make_object()); problems.emplace_back(td_api::make_object()); send_request(td_api::make_object( - as_call_id(call_id), to_integer(rating), "Wow, such good call! (TDLib test)", std::move(problems))); + as_call_id(call_id), rating, "Wow, such good call! (TDLib test)", std::move(problems))); } else if (op == "scdi" || op == "SendCallDebugInformation") { send_request(td_api::make_object(as_call_id(args), "{}")); } else if (op == "cvc") { @@ -2857,34 +2649,30 @@ class CliClient final : public Actor { td_api::make_object(as_group_call_id(args), op == "tgcmnpe")); } else if (op == "sgcpis") { string group_call_id; - string source; - string is_speaking; - std::tie(group_call_id, args) = split(args); - std::tie(source, is_speaking) = split(args); - send_request(td_api::make_object( - as_group_call_id(group_call_id), to_integer(source), as_bool(is_speaking))); + int32 source; + bool is_speaking; + get_args(args, group_call_id, source, is_speaking); + send_request(td_api::make_object(as_group_call_id(group_call_id), + source, is_speaking)); } else if (op == "igcp") { string group_call_id; string user_ids; - std::tie(group_call_id, user_ids) = split(args); + get_args(args, group_call_id, user_ids); send_request(td_api::make_object(as_group_call_id(group_call_id), as_user_ids(user_ids))); } else if (op == "tgcpim") { string group_call_id; string user_id; - string is_muted; - std::tie(group_call_id, args) = split(args); - std::tie(user_id, is_muted) = split(args); - send_request(td_api::make_object( - as_group_call_id(group_call_id), as_user_id(user_id), as_bool(is_muted))); - } else if (op == "cgcij") { - send_request(td_api::make_object(as_group_call_id(args))); + bool is_muted; + get_args(args, group_call_id, user_id, is_muted); + send_request(td_api::make_object(as_group_call_id(group_call_id), + as_user_id(user_id), is_muted)); } else if (op == "lgcp") { string group_call_id; string limit; - std::tie(group_call_id, limit) = split(args); - send_request(td_api::make_object(as_group_call_id(group_call_id), - to_integer(limit))); + get_args(args, group_call_id, limit); + send_request( + td_api::make_object(as_group_call_id(group_call_id), as_limit(limit))); } else if (op == "lgc") { send_request(td_api::make_object(as_group_call_id(args))); } else if (op == "dgc") { @@ -2961,9 +2749,7 @@ class CliClient final : public Actor { string type; string chat_id; string json; - std::tie(type, args) = split(args); - std::tie(chat_id, json) = split(args); - + get_args(args, type, chat_id, json); auto result = execute(td_api::make_object(json)); if (result->get_id() == td_api::error::ID) { LOG(ERROR) << to_string(result); @@ -2980,17 +2766,15 @@ class CliClient final : public Actor { string message_thread_id; string reply_to_message_id; string message; - std::tie(chat_id, args) = split(args); if (op == "scdmt") { - std::tie(message_thread_id, args) = split(args); + get_args(args, message_thread_id, args); } - std::tie(reply_to_message_id, message) = split(args); + get_args(args, chat_id, reply_to_message_id, message); td_api::object_ptr draft_message; if (!reply_to_message_id.empty() || !message.empty()) { vector> entities; entities.push_back( td_api::make_object(0, 1, td_api::make_object())); - draft_message = td_api::make_object( as_message_id(reply_to_message_id), 0, td_api::make_object(as_formatted_text(message, std::move(entities)), true, @@ -3002,38 +2786,33 @@ class CliClient final : public Actor { send_request(td_api::make_object()); } else if (op == "tcip" || op == "tcipa" || begins_with(op, "tcip-")) { string chat_id; - string is_pinned; - std::tie(chat_id, is_pinned) = split(args); - send_request( - td_api::make_object(as_chat_list(op), as_chat_id(chat_id), as_bool(is_pinned))); + bool is_pinned; + get_args(args, chat_id, is_pinned); + send_request(td_api::make_object(as_chat_list(op), as_chat_id(chat_id), is_pinned)); } else if (op == "tcimau") { string chat_id; - string is_marked_as_read; - std::tie(chat_id, is_marked_as_read) = split(args); - send_request( - td_api::make_object(as_chat_id(chat_id), as_bool(is_marked_as_read))); + bool is_marked_as_read; + get_args(args, chat_id, is_marked_as_read); + send_request(td_api::make_object(as_chat_id(chat_id), is_marked_as_read)); } else if (op == "tmsib") { string chat_id; - string is_blocked; - std::tie(chat_id, is_blocked) = split(args); - send_request( - td_api::make_object(as_message_sender(chat_id), as_bool(is_blocked))); + bool is_blocked; + get_args(args, chat_id, is_blocked); + send_request(td_api::make_object(as_message_sender(chat_id), is_blocked)); } else if (op == "bmsfr") { string message_id; - string delete_message; - string delete_all_messages; - string report_spam; - std::tie(message_id, args) = split(args); - std::tie(delete_message, args) = split(args); - std::tie(delete_all_messages, report_spam) = split(args); - send_request(td_api::make_object( - as_message_id(message_id), as_bool(delete_message), as_bool(delete_all_messages), as_bool(report_spam))); + bool delete_message; + bool delete_all_messages; + bool report_spam; + get_args(args, message_id, delete_message, delete_all_messages, report_spam); + send_request(td_api::make_object(as_message_id(message_id), delete_message, + delete_all_messages, report_spam)); } else if (op == "tcddn") { string chat_id; - string default_disable_notification; - std::tie(chat_id, default_disable_notification) = split(args); - send_request(td_api::make_object( - as_chat_id(chat_id), as_bool(default_disable_notification))); + bool default_disable_notification; + get_args(args, chat_id, default_disable_notification); + send_request(td_api::make_object(as_chat_id(chat_id), + default_disable_notification)); } else if (op == "spchats" || op == "spchatsa" || begins_with(op, "spchats-")) { vector chat_ids_str = full_split(args, ' '); vector chat_ids; @@ -3045,8 +2824,7 @@ class CliClient final : public Actor { string chat_id; string message_thread_id; string action; - std::tie(chat_id, args) = split(args); - std::tie(message_thread_id, action) = split(args); + get_args(args, chat_id, message_thread_id, action); send_request(td_api::make_object( as_chat_id(chat_id), as_message_thread_id(message_thread_id), get_chat_action(action))); } else if (op == "smt" || op == "smtp" || op == "smtf" || op == "smtpf") { @@ -3065,18 +2843,12 @@ class CliClient final : public Actor { } } else if (op == "ssm") { string chat_id; - string offset; - string limit; string filter; - string query; - - std::tie(chat_id, args) = split(args); - std::tie(offset, args) = split(args); - std::tie(limit, args) = split(args); - std::tie(filter, query) = split(args); - - send_request(td_api::make_object( - as_chat_id(chat_id), query, offset, to_integer(limit), as_search_messages_filter(filter))); + string offset; + SearchQuery query; + get_args(args, chat_id, filter, offset, query); + send_request(td_api::make_object(as_chat_id(chat_id), query.query, offset, + query.limit, as_search_messages_filter(filter))); } else if (op == "ssd") { schedule_date_ = args; } else if (op == "smti") { @@ -3085,15 +2857,13 @@ class CliClient final : public Actor { string chat_id; string reply_to_message_id; string message; - - std::tie(chat_id, message) = split(args); + get_args(args, chat_id, message); if (op == "smr") { - std::tie(reply_to_message_id, message) = split(message); + get_args(message, reply_to_message_id, message); } if (op == "smf") { message = string(5097, 'a'); } - send_message(chat_id, td_api::make_object(as_formatted_text(message), false, true), op == "sms", false, as_message_id(reply_to_message_id)); } else if (op == "alm" || op == "almr") { @@ -3101,13 +2871,10 @@ class CliClient final : public Actor { string sender_id; string reply_to_message_id; string message; - - std::tie(chat_id, args) = split(args); - std::tie(sender_id, message) = split(args); + get_args(args, chat_id, sender_id, message); if (op == "almr") { - std::tie(reply_to_message_id, message) = split(message); + get_args(message, reply_to_message_id, message); } - send_request(td_api::make_object( as_chat_id(chat_id), as_message_sender(sender_id), as_message_id(reply_to_message_id), false, td_api::make_object(as_formatted_text(message), false, true))); @@ -3115,13 +2882,11 @@ class CliClient final : public Actor { string chat_id; string reply_to_message_id; vector photos; - - std::tie(chat_id, args) = split(args); + get_args(args, chat_id, args); if (op == "smapr") { - std::tie(reply_to_message_id, args) = split(args); + get_args(args, reply_to_message_id, args); } photos = full_split(args); - send_request(td_api::make_object( as_chat_id(chat_id), as_message_thread_id(message_thread_id_), as_message_id(reply_to_message_id), default_message_send_options(), transform(photos, [](const string &photo) { @@ -3132,10 +2897,8 @@ class CliClient final : public Actor { } else if (op == "smad") { string chat_id; vector documents; - - std::tie(chat_id, args) = split(args); + get_args(args, chat_id, args); documents = full_split(args); - send_request(td_api::make_object( as_chat_id(chat_id), as_message_thread_id(message_thread_id_), 0, default_message_send_options(), transform(documents, [](const string &document) { @@ -3147,8 +2910,7 @@ class CliClient final : public Actor { string chat_id; string message_id; string message; - std::tie(chat_id, args) = split(args); - std::tie(message_id, message) = split(args); + get_args(args, chat_id, message_id, message); send_request(td_api::make_object( as_chat_id(chat_id), as_message_id(message_id), nullptr, td_api::make_object(as_formatted_text(message), true, true))); @@ -3156,8 +2918,7 @@ class CliClient final : public Actor { string chat_id; string message_id; string animation; - std::tie(chat_id, args) = split(args); - std::tie(message_id, animation) = split(args); + get_args(args, chat_id, message_id, animation); send_request(td_api::make_object( as_chat_id(chat_id), as_message_id(message_id), nullptr, td_api::make_object(as_input_file(animation), nullptr, vector(), 0, 0, @@ -3166,47 +2927,32 @@ class CliClient final : public Actor { string chat_id; string message_id; string caption; - std::tie(chat_id, args) = split(args); - std::tie(message_id, caption) = split(args); + get_args(args, chat_id, message_id, caption); send_request(td_api::make_object(as_chat_id(chat_id), as_message_id(message_id), nullptr, as_caption(caption))); } else if (op == "emd") { string chat_id; string message_id; string document; - std::tie(chat_id, args) = split(args); - std::tie(message_id, document) = split(args); + get_args(args, chat_id, message_id, document); send_request(td_api::make_object( as_chat_id(chat_id), as_message_id(message_id), nullptr, td_api::make_object(as_input_file(document), nullptr, false, as_caption("")))); - } else if (op == "emp") { + } else if (op == "emp" || op == "empttl") { string chat_id; string message_id; string photo; - std::tie(chat_id, args) = split(args); - std::tie(message_id, photo) = split(args); + get_args(args, chat_id, message_id, photo); send_request(td_api::make_object( as_chat_id(chat_id), as_message_id(message_id), nullptr, td_api::make_object(as_input_file(photo), as_input_thumbnail(photo), Auto(), 0, 0, - as_caption(""), 0))); - } else if (op == "empttl") { - string chat_id; - string message_id; - string photo; - std::tie(chat_id, args) = split(args); - std::tie(message_id, photo) = split(args); - send_request(td_api::make_object( - as_chat_id(chat_id), as_message_id(message_id), nullptr, - td_api::make_object(as_input_file(photo), as_input_thumbnail(photo), Auto(), 0, 0, - as_caption(""), 10))); + as_caption(""), op == "empttl" ? 10 : 0))); } else if (op == "emvt") { string chat_id; string message_id; string video; string thumbnail; - std::tie(chat_id, args) = split(args); - std::tie(message_id, args) = split(args); - std::tie(video, thumbnail) = split(args); + get_args(args, chat_id, message_id, video, thumbnail); send_request(td_api::make_object( as_chat_id(chat_id), as_message_id(message_id), nullptr, td_api::make_object(as_input_file(video), as_input_thumbnail(thumbnail), Auto(), 1, @@ -3217,23 +2963,17 @@ class CliClient final : public Actor { string latitude; string longitude; string accuracy; - string heading; - string proximity_alert_radius; - std::tie(chat_id, args) = split(args); - std::tie(message_id, args) = split(args); - std::tie(latitude, args) = split(args); - std::tie(longitude, args) = split(args); - std::tie(accuracy, args) = split(args); - std::tie(heading, proximity_alert_radius) = split(args); + int32 heading; + int32 proximity_alert_radius; + get_args(args, chat_id, message_id, latitude, longitude, accuracy, heading, proximity_alert_radius); send_request(td_api::make_object( - as_chat_id(chat_id), as_message_id(message_id), nullptr, as_location(latitude, longitude, accuracy), - to_integer(heading), to_integer(proximity_alert_radius))); + as_chat_id(chat_id), as_message_id(message_id), nullptr, as_location(latitude, longitude, accuracy), heading, + proximity_alert_radius)); } else if (op == "emss") { string chat_id; string message_id; string date; - std::tie(chat_id, args) = split(args); - std::tie(message_id, date) = split(args); + get_args(args, chat_id, message_id, date); send_request(td_api::make_object( as_chat_id(chat_id), as_message_id(message_id), as_message_scheduling_state(date))); } else if (op == "gallm") { @@ -3242,45 +2982,40 @@ class CliClient final : public Actor { string bot_id; string chat_id; string parameter; - std::tie(bot_id, args) = split(args); - std::tie(chat_id, parameter) = split(args); + get_args(args, bot_id, chat_id, parameter); send_request( td_api::make_object(as_user_id(bot_id), as_chat_id(chat_id), parameter)); } else if (op == "giqr") { string bot_id; string query; - std::tie(bot_id, query) = split(args); + get_args(args, bot_id, query); send_request(td_api::make_object(as_user_id(bot_id), 0, nullptr, query, "")); } else if (op == "giqro") { string bot_id; string offset; string query; - std::tie(bot_id, args) = split(args); - std::tie(offset, query) = split(args); + get_args(args, bot_id, offset, query); send_request(td_api::make_object(as_user_id(bot_id), 0, nullptr, query, offset)); } else if (op == "giqrl") { string bot_id; string query; - std::tie(bot_id, query) = split(args); + get_args(args, bot_id, query); send_request(td_api::make_object(as_user_id(bot_id), 0, as_location("1.1", "2.2"), query, "")); } else if (op == "siqr" || op == "siqrh") { string chat_id; - string query_id; + int64 query_id; string result_id; - std::tie(chat_id, args) = split(args); - std::tie(query_id, result_id) = split(args); - + get_args(args, chat_id, query_id, result_id); auto chat = as_chat_id(chat_id); send_request(td_api::make_object( - chat, as_message_thread_id(message_thread_id_), 0, default_message_send_options(), - to_integer(query_id), result_id, op == "siqrh")); + chat, as_message_thread_id(message_thread_id_), 0, default_message_send_options(), query_id, result_id, + op == "siqrh")); } else if (op == "gcqa") { string chat_id; string message_id; string data; - std::tie(chat_id, args) = split(args); - std::tie(message_id, data) = split(args); + get_args(args, chat_id, message_id, data); send_request(td_api::make_object( as_chat_id(chat_id), as_message_id(message_id), td_api::make_object(data))); } else if (op == "gcpqa") { @@ -3288,81 +3023,66 @@ class CliClient final : public Actor { string message_id; string password; string data; - std::tie(chat_id, args) = split(args); - std::tie(message_id, args) = split(args); - std::tie(password, data) = split(args); + get_args(args, chat_id, message_id, password, data); send_request(td_api::make_object( as_chat_id(chat_id), as_message_id(message_id), td_api::make_object(password, data))); } else if (op == "gcgqa") { string chat_id; string message_id; - std::tie(chat_id, message_id) = split(args); + get_args(args, chat_id, message_id); send_request(td_api::make_object( as_chat_id(chat_id), as_message_id(message_id), td_api::make_object(""))); } else if (op == "san") { string chat_id; string animation_path; - string width; - string height; + int32 width; + int32 height; string caption; - std::tie(chat_id, args) = split(args); - std::tie(animation_path, args) = split(args); - std::tie(width, args) = split(args); - std::tie(height, caption) = split(args); - - send_message(chat_id, td_api::make_object( - as_input_file(animation_path), nullptr, vector(), 60, to_integer(width), - to_integer(height), as_caption(caption))); + get_args(args, chat_id, animation_path, width, height, caption); + send_message(chat_id, td_api::make_object(as_input_file(animation_path), nullptr, + vector(), 60, width, height, + as_caption(caption))); } else if (op == "sang") { string chat_id; string animation_path; string animation_conversion; - std::tie(chat_id, args) = split(args); - std::tie(animation_path, animation_conversion) = split(args); + get_args(args, chat_id, animation_path, animation_conversion); send_message(chat_id, td_api::make_object( as_generated_file(animation_path, animation_conversion), nullptr, vector(), 60, 0, 0, as_caption(""))); } else if (op == "sanid") { string chat_id; string file_id; - std::tie(chat_id, file_id) = split(args); - + get_args(args, chat_id, file_id); send_message(chat_id, td_api::make_object( as_input_file_id(file_id), nullptr, vector(), 0, 0, 0, as_caption(""))); } else if (op == "sanurl") { string chat_id; string url; - std::tie(chat_id, url) = split(args); - + get_args(args, chat_id, url); send_message(chat_id, td_api::make_object( as_generated_file(url, "#url#"), nullptr, vector(), 0, 0, 0, as_caption(""))); } else if (op == "sanurl2") { string chat_id; string url; - std::tie(chat_id, url) = split(args); - + get_args(args, chat_id, url); send_message(chat_id, td_api::make_object( as_remote_file(url), nullptr, vector(), 0, 0, 0, as_caption(""))); } else if (op == "sau") { string chat_id; string audio_path; - string duration; + int32 duration; string title; string performer; - std::tie(chat_id, args) = split(args); - std::tie(audio_path, args) = split(args); - std::tie(duration, args) = split(args); - std::tie(title, performer) = split(args); - - send_message(chat_id, td_api::make_object(as_input_file(audio_path), nullptr, - to_integer(duration), title, - performer, as_caption("audio caption"))); + get_args(args, chat_id, audio_path, duration, title, performer); + send_message(chat_id, + td_api::make_object(as_input_file(audio_path), nullptr, duration, title, + performer, as_caption("audio caption"))); } else if (op == "svoice") { string chat_id; string voice_path; - std::tie(chat_id, voice_path) = split(args); - + get_args(args, chat_id, voice_path); send_message(chat_id, td_api::make_object(as_input_file(voice_path), 0, "abacaba", as_caption("voice caption"))); } else if (op == "SendContact" || op == "scontact") { @@ -3371,38 +3091,30 @@ class CliClient final : public Actor { string first_name; string last_name; string user_id; - std::tie(chat_id, args) = split(args); - std::tie(phone_number, args) = split(args); - std::tie(first_name, args) = split(args); - std::tie(last_name, user_id) = split(args); - + get_args(args, chat_id, phone_number, first_name, last_name, user_id); send_message(chat_id, td_api::make_object(td_api::make_object( phone_number, first_name, last_name, string(), as_user_id(user_id)))); } else if (op == "sf" || op == "scopy") { string chat_id; string from_chat_id; string from_message_id; - std::tie(chat_id, args) = split(args); - std::tie(from_chat_id, from_message_id) = split(args); - + get_args(args, chat_id, from_chat_id, from_message_id); td_api::object_ptr copy_options; if (op == "scopy") { - copy_options = td_api::make_object(true, Random::fast_bool(), as_caption("_as_d")); + copy_options = td_api::make_object(true, rand_bool(), as_caption("_as_d")); } - send_message(chat_id, td_api::make_object( as_chat_id(from_chat_id), as_message_id(from_message_id), true, std::move(copy_options))); } else if (op == "sdice" || op == "sdicecd") { string chat_id; string emoji; - std::tie(chat_id, emoji) = split(args); - + get_args(args, chat_id, emoji); send_message(chat_id, td_api::make_object(emoji, op == "sdicecd")); } else if (op == "sd" || op == "sdf") { string chat_id; string document_path; - std::tie(chat_id, document_path) = split(args); + get_args(args, chat_id, document_path); send_message(chat_id, td_api::make_object( as_input_file(document_path), nullptr, op == "sdf", as_caption(u8"\u1680\u180Etest \u180E\n\u180E\n\u180E\n cap\ttion\u180E\u180E"))); @@ -3410,8 +3122,7 @@ class CliClient final : public Actor { string chat_id; string document_path; string thumbnail_path; - std::tie(chat_id, args) = split(args); - std::tie(document_path, thumbnail_path) = split(args); + get_args(args, chat_id, document_path, thumbnail_path); send_message(chat_id, td_api::make_object( as_input_file(document_path), as_input_thumbnail(thumbnail_path), op == "sdtf", as_caption("test caption"))); @@ -3419,8 +3130,7 @@ class CliClient final : public Actor { string chat_id; string document_path; string document_conversion; - std::tie(chat_id, args) = split(args); - std::tie(document_path, document_conversion) = split(args); + get_args(args, chat_id, document_path, document_conversion); if (op == "sdgu") { send_request( td_api::make_object(as_generated_file(document_path, document_conversion), nullptr, 1)); @@ -3433,9 +3143,7 @@ class CliClient final : public Actor { string document_path; string thumbnail_path; string thumbnail_conversion; - std::tie(chat_id, args) = split(args); - std::tie(document_path, args) = split(args); - std::tie(thumbnail_path, thumbnail_conversion) = split(args); + get_args(args, chat_id, document_path, thumbnail_path, thumbnail_conversion); send_message(chat_id, td_api::make_object( as_input_file(document_path), as_input_thumbnail(thumbnail_path, thumbnail_conversion), false, as_caption("test caption"))); @@ -3445,10 +3153,7 @@ class CliClient final : public Actor { string document_conversion; string thumbnail_path; string thumbnail_conversion; - std::tie(chat_id, args) = split(args); - std::tie(document_path, args) = split(args); - std::tie(document_conversion, args) = split(args); - std::tie(thumbnail_path, thumbnail_conversion) = split(args); + get_args(args, chat_id, document_path, document_conversion, thumbnail_path, thumbnail_conversion); send_message(chat_id, td_api::make_object( as_generated_file(document_path, document_conversion), @@ -3456,59 +3161,45 @@ class CliClient final : public Actor { } else if (op == "sdid") { string chat_id; string file_id; - std::tie(chat_id, file_id) = split(args); + get_args(args, chat_id, file_id); send_message(chat_id, td_api::make_object(as_input_file_id(file_id), nullptr, false, as_caption(""))); } else if (op == "sdurl") { string chat_id; string url; - std::tie(chat_id, url) = split(args); - + get_args(args, chat_id, url); send_message(chat_id, td_api::make_object(as_remote_file(url), nullptr, false, as_caption(""))); } else if (op == "sg") { string chat_id; string bot_user_id; string game_short_name; - std::tie(chat_id, args) = split(args); - std::tie(bot_user_id, game_short_name) = split(args); + get_args(args, chat_id, bot_user_id, game_short_name); send_message(chat_id, td_api::make_object(as_user_id(bot_user_id), game_short_name)); } else if (op == "sl") { string chat_id; string latitude; string longitude; string accuracy; - std::tie(chat_id, args) = split(args); - std::tie(latitude, args) = split(args); - std::tie(longitude, accuracy) = split(args); - + get_args(args, chat_id, latitude, longitude, accuracy); send_message(chat_id, td_api::make_object( as_location(latitude, longitude, accuracy), 0, 0, 0)); } else if (op == "sll") { string chat_id; - string period; + int32 period; string latitude; string longitude; string accuracy; - string heading; - string proximity_alert_radius; - std::tie(chat_id, args) = split(args); - std::tie(period, args) = split(args); - std::tie(latitude, args) = split(args); - std::tie(longitude, args) = split(args); - std::tie(accuracy, args) = split(args); - std::tie(heading, proximity_alert_radius) = split(args); - + int32 heading; + int32 proximity_alert_radius; + get_args(args, chat_id, period, latitude, longitude, accuracy, heading, proximity_alert_radius); send_message(chat_id, td_api::make_object( - as_location(latitude, longitude, accuracy), to_integer(period), - to_integer(heading), to_integer(proximity_alert_radius))); + as_location(latitude, longitude, accuracy), period, heading, proximity_alert_radius)); } else if (op == "spoll" || op == "spollm" || op == "spollp" || op == "squiz") { string chat_id; string question; - std::tie(chat_id, args) = split(args); - std::tie(question, args) = split(args); + get_args(args, chat_id, question, args); auto options = full_split(args); - td_api::object_ptr poll_type; if (op == "squiz") { poll_type = td_api::make_object(narrow_cast(options.size() - 1), @@ -3523,14 +3214,12 @@ class CliClient final : public Actor { string photo_path; string sticker_file_ids_str; vector sticker_file_ids; - std::tie(chat_id, args) = split(args); - std::tie(sticker_file_ids_str, photo_path) = split(args); + get_args(args, chat_id, sticker_file_ids_str, photo_path); if (trim(photo_path).empty()) { photo_path = sticker_file_ids_str; } else { sticker_file_ids = to_integers(sticker_file_ids_str); } - send_message(chat_id, td_api::make_object( as_input_file(photo_path), nullptr, std::move(sticker_file_ids), 0, 0, as_caption(op == "spcaption" ? "cap \n\n\n\n tion " : ""), op == "spttl" ? 10 : 0)); @@ -3538,21 +3227,16 @@ class CliClient final : public Actor { string chat_id; string photo_path; string conversion; - string expected_size; - std::tie(chat_id, args) = split(args); - std::tie(photo_path, args) = split(args); - std::tie(conversion, expected_size) = split(args); - + int32 expected_size; + get_args(args, chat_id, photo_path, conversion, expected_size); send_message(chat_id, td_api::make_object( - as_generated_file(photo_path, conversion, to_integer(expected_size)), nullptr, - vector(), 0, 0, as_caption(""), op == "spgttl" ? 10 : 0)); + as_generated_file(photo_path, conversion, expected_size), nullptr, vector(), 0, + 0, as_caption(""), op == "spgttl" ? 10 : 0)); } else if (op == "spt") { string chat_id; string photo_path; string thumbnail_path; - std::tie(chat_id, args) = split(args); - std::tie(photo_path, thumbnail_path) = split(args); - + get_args(args, chat_id, photo_path, thumbnail_path); send_message(chat_id, td_api::make_object(as_input_file(photo_path), as_input_thumbnail(thumbnail_path, 90, 89), vector(), 0, 0, as_caption(""), 0)); @@ -3561,10 +3245,7 @@ class CliClient final : public Actor { string photo_path; string thumbnail_path; string thumbnail_conversion; - std::tie(chat_id, args) = split(args); - std::tie(photo_path, args) = split(args); - std::tie(thumbnail_path, thumbnail_conversion) = split(args); - + get_args(args, chat_id, photo_path, thumbnail_path, thumbnail_conversion); send_message(chat_id, td_api::make_object( as_input_file(photo_path), as_input_thumbnail(thumbnail_path, thumbnail_conversion, 90, 89), @@ -3575,12 +3256,7 @@ class CliClient final : public Actor { string conversion; string thumbnail_path; string thumbnail_conversion; - - std::tie(chat_id, args) = split(args); - std::tie(photo_path, args) = split(args); - std::tie(conversion, args) = split(args); - std::tie(thumbnail_path, thumbnail_conversion) = split(args); - + get_args(args, chat_id, photo_path, conversion, thumbnail_path, thumbnail_conversion); send_message(chat_id, td_api::make_object( as_generated_file(photo_path, conversion), as_input_thumbnail(thumbnail_path, thumbnail_conversion, 90, 89), vector(), 0, 0, @@ -3588,32 +3264,27 @@ class CliClient final : public Actor { } else if (op == "spid") { string chat_id; string file_id; - std::tie(chat_id, file_id) = split(args); + get_args(args, chat_id, file_id); send_message(chat_id, td_api::make_object(as_input_file_id(file_id), nullptr, vector(), 0, 0, as_caption(""), 0)); } else if (op == "ss") { string chat_id; string sticker_path; - std::tie(chat_id, sticker_path) = split(args); - + get_args(args, chat_id, sticker_path); send_message(chat_id, td_api::make_object(as_input_file(sticker_path), nullptr, 0, 0, string())); } else if (op == "sstt") { string chat_id; string sticker_path; string thumbnail_path; - std::tie(chat_id, args) = split(args); - std::tie(sticker_path, thumbnail_path) = split(args); - + get_args(args, chat_id, sticker_path, thumbnail_path); send_message(chat_id, td_api::make_object( as_input_file(sticker_path), as_input_thumbnail(thumbnail_path), 0, 0, string())); } else if (op == "ssid") { string chat_id; string file_id; string emoji; - std::tie(chat_id, args) = split(args); - std::tie(file_id, emoji) = split(args); - + get_args(args, chat_id, file_id, emoji); send_message(chat_id, td_api::make_object(as_input_file_id(file_id), nullptr, 0, 0, emoji)); } else if (op == "sv" || op == "svttl") { @@ -3621,14 +3292,12 @@ class CliClient final : public Actor { string video_path; string sticker_file_ids_str; vector sticker_file_ids; - std::tie(chat_id, args) = split(args); - std::tie(sticker_file_ids_str, video_path) = split(args); + get_args(args, chat_id, sticker_file_ids_str, video_path); if (trim(video_path).empty()) { video_path = sticker_file_ids_str; } else { sticker_file_ids = to_integers(sticker_file_ids_str); } - send_message(chat_id, td_api::make_object(as_input_file(video_path), nullptr, std::move(sticker_file_ids), 1, 2, 3, true, as_caption(""), op == "svttl" ? 10 : 0)); @@ -3636,21 +3305,18 @@ class CliClient final : public Actor { string chat_id; string video; string thumbnail; - std::tie(chat_id, args) = split(args); - std::tie(video, thumbnail) = split(args); - + get_args(args, chat_id, video, thumbnail); send_message(chat_id, td_api::make_object( as_input_file(video), as_input_thumbnail(thumbnail), vector(), 0, 0, 0, true, as_caption(""), op == "svtttl" ? 10 : 0)); } else if (op == "svn") { string chat_id; string video_path; - std::tie(chat_id, video_path) = split(args); + get_args(args, chat_id, video_path); send_message(chat_id, td_api::make_object(as_input_file(video_path), nullptr, 1, 5)); } else if (op == "svenue") { string chat_id; - string latitude; string longitude; string accuracy; @@ -3659,15 +3325,7 @@ class CliClient final : public Actor { string provider; string venue_id; string venue_type; - std::tie(chat_id, args) = split(args); - std::tie(latitude, args) = split(args); - std::tie(longitude, args) = split(args); - std::tie(accuracy, args) = split(args); - std::tie(title, args) = split(args); - std::tie(address, args) = split(args); - std::tie(provider, args) = split(args); - std::tie(venue_id, venue_type) = split(args); - + get_args(args, chat_id, latitude, longitude, accuracy, title, address, provider, venue_id, venue_type); send_message(chat_id, td_api::make_object(td_api::make_object( as_location(latitude, longitude, accuracy), title, address, provider, venue_id, venue_type))); @@ -3677,22 +3335,20 @@ class CliClient final : public Actor { send_request(td_api::make_object(to_double(args))); } else if (op == "delete") { string chat_id; - string remove_from_the_chat_list; - string revoke; - std::tie(chat_id, args) = split(args); - std::tie(remove_from_the_chat_list, revoke) = split(args); - send_request(td_api::make_object(as_chat_id(chat_id), - as_bool(remove_from_the_chat_list), as_bool(revoke))); + bool remove_from_the_chat_list; + bool revoke; + get_args(args, chat_id, remove_from_the_chat_list, revoke); + send_request( + td_api::make_object(as_chat_id(chat_id), remove_from_the_chat_list, revoke)); } else if (op == "dmfu") { string chat_id; string user_id; - std::tie(chat_id, user_id) = split(args); + get_args(args, chat_id, user_id); send_request(td_api::make_object(as_chat_id(chat_id), as_user_id(user_id))); } else if (op == "cnbgc") { string user_ids_string; string title; - std::tie(user_ids_string, title) = split(args); - + get_args(args, user_ids_string, title); send_request(td_api::make_object(as_user_ids(user_ids_string), title)); } else if (op == "cnch") { send_request(td_api::make_object(args, true, "Description", nullptr)); @@ -3722,23 +3378,19 @@ class CliClient final : public Actor { send_request(td_api::make_object()); } else if (op == "cpc") { string user_id; - string force; - - std::tie(user_id, force) = split(args); - send_request(td_api::make_object(as_user_id(user_id), as_bool(force))); + bool force; + get_args(args, user_id, force); + send_request(td_api::make_object(as_user_id(user_id), force)); } else if (op == "cbgc") { string basic_group_id; - string force; - - std::tie(basic_group_id, force) = split(args); - send_request( - td_api::make_object(as_basic_group_id(basic_group_id), as_bool(force))); + bool force; + get_args(args, basic_group_id, force); + send_request(td_api::make_object(as_basic_group_id(basic_group_id), force)); } else if (op == "csgc" || op == "cchc") { string supergroup_id; - string force; - - std::tie(supergroup_id, force) = split(args); - send_request(td_api::make_object(as_supergroup_id(supergroup_id), as_bool(force))); + bool force; + get_args(args, supergroup_id, force); + send_request(td_api::make_object(as_supergroup_id(supergroup_id), force)); } else if (op == "gcltac") { string chat_id = args; send_request(td_api::make_object(as_chat_id(chat_id))); @@ -3757,8 +3409,7 @@ class CliClient final : public Actor { } else if (op == "ecf") { string chat_filter_id; string filter; - - std::tie(chat_filter_id, filter) = split(args); + get_args(args, chat_filter_id, filter); send_request( td_api::make_object(as_chat_filter_id(chat_filter_id), as_chat_filter(filter))); } else if (op == "dcf") { @@ -3772,42 +3423,35 @@ class CliClient final : public Actor { } else if (op == "sct") { string chat_id; string title; - - std::tie(chat_id, title) = split(args); + get_args(args, chat_id, title); send_request(td_api::make_object(as_chat_id(chat_id), title)); } else if (op == "scpe") { string chat_id = args; - send_request(td_api::make_object(as_chat_id(chat_id), nullptr)); } else if (op == "scpp") { string chat_id; - string photo_id; - - std::tie(chat_id, photo_id) = split(args); + int64 photo_id; + get_args(args, chat_id, photo_id); send_request(td_api::make_object( - as_chat_id(chat_id), td_api::make_object(to_integer(photo_id)))); + as_chat_id(chat_id), td_api::make_object(photo_id))); } else if (op == "scp") { string chat_id; string photo_path; - - std::tie(chat_id, photo_path) = split(args); + get_args(args, chat_id, photo_path); send_request(td_api::make_object( as_chat_id(chat_id), td_api::make_object(as_input_file(photo_path)))); } else if (op == "scpa" || op == "scpv") { string chat_id; string animation; string main_frame_timestamp; - - std::tie(chat_id, args) = split(args); - std::tie(animation, main_frame_timestamp) = split(args); + get_args(args, chat_id, animation, main_frame_timestamp); send_request(td_api::make_object( as_chat_id(chat_id), td_api::make_object(as_input_file(animation), to_double(main_frame_timestamp)))); } else if (op == "scperm") { string chat_id; string permissions; - - std::tie(chat_id, permissions) = split(args); + get_args(args, chat_id, permissions); if (permissions.size() == 8) { auto &s = permissions; send_request(td_api::make_object( @@ -3820,52 +3464,39 @@ class CliClient final : public Actor { } else if (op == "sccd") { string chat_id; string client_data; - - std::tie(chat_id, client_data) = split(args); + get_args(args, chat_id, client_data); send_request(td_api::make_object(as_chat_id(chat_id), client_data)); } else if (op == "acm") { string chat_id; string user_id; - string forward_limit; - - std::tie(chat_id, args) = split(args); - std::tie(user_id, forward_limit) = split(args); - send_request(td_api::make_object(as_chat_id(chat_id), as_user_id(user_id), - to_integer(forward_limit))); + int32 forward_limit; + get_args(args, chat_id, user_id, forward_limit); + send_request(td_api::make_object(as_chat_id(chat_id), as_user_id(user_id), forward_limit)); } else if (op == "acms") { string chat_id; string user_ids; - - std::tie(chat_id, user_ids) = split(args); + get_args(args, chat_id, user_ids); send_request(td_api::make_object(as_chat_id(chat_id), as_user_ids(user_ids))); } else if (op == "spolla") { string chat_id; string message_id; string option_ids; - - std::tie(chat_id, args) = split(args); - std::tie(message_id, option_ids) = split(args); + get_args(args, chat_id, message_id, option_ids); send_request(td_api::make_object(as_chat_id(chat_id), as_message_id(message_id), to_integers(option_ids))); } else if (op == "gpollv") { string chat_id; string message_id; - string option_id; - string offset; + int32 option_id; + int32 offset; string limit; - - std::tie(chat_id, args) = split(args); - std::tie(message_id, args) = split(args); - std::tie(option_id, args) = split(args); - std::tie(offset, limit) = split(args); - send_request(td_api::make_object(as_chat_id(chat_id), as_message_id(message_id), - to_integer(option_id), to_integer(offset), - to_integer(limit))); + get_args(args, chat_id, message_id, option_id, offset, limit); + send_request(td_api::make_object(as_chat_id(chat_id), as_message_id(message_id), option_id, + offset, as_limit(limit))); } else if (op == "stoppoll") { string chat_id; string message_id; - - std::tie(chat_id, message_id) = split(args); + get_args(args, chat_id, message_id); send_request(td_api::make_object(as_chat_id(chat_id), as_message_id(message_id), nullptr)); } else { op_not_found_count++; @@ -3876,9 +3507,7 @@ class CliClient final : public Actor { string user_id; string status_str; td_api::object_ptr status; - - std::tie(chat_id, args) = split(args); - std::tie(user_id, status_str) = split(args); + get_args(args, chat_id, user_id, status_str); if (status_str == "member") { status = td_api::make_object(); } else if (status_str == "left") { @@ -3945,18 +3574,15 @@ class CliClient final : public Actor { string chat_id; string user_id; string password; - - std::tie(chat_id, args) = split(args); - std::tie(user_id, password) = split(args); + get_args(args, chat_id, user_id, password); send_request( td_api::make_object(as_chat_id(chat_id), as_user_id(user_id), password)); } else if (op == "log") { string chat_id; string limit; - - std::tie(chat_id, limit) = split(args); - send_request(td_api::make_object(as_chat_id(chat_id), "", 0, to_integer(limit), - nullptr, vector())); + get_args(args, chat_id, limit); + send_request(td_api::make_object(as_chat_id(chat_id), "", 0, as_limit(limit), nullptr, + vector())); } else if (op == "join") { send_request(td_api::make_object(as_chat_id(args))); } else if (op == "leave") { @@ -3964,8 +3590,7 @@ class CliClient final : public Actor { } else if (op == "dcm") { string chat_id; string user_id_str; - - std::tie(chat_id, user_id_str) = split(args); + get_args(args, chat_id, user_id_str); auto user_id = as_user_id(user_id_str); td_api::object_ptr status = td_api::make_object(); if (user_id == my_id_) { @@ -3975,7 +3600,7 @@ class CliClient final : public Actor { } else if (op == "sn") { string first_name; string last_name; - std::tie(first_name, last_name) = split(args); + get_args(args, first_name, last_name); send_request(td_api::make_object(first_name, last_name)); } else if (op == "sb") { send_request(td_api::make_object("\n" + args + "\n" + args + "\n")); @@ -3984,76 +3609,63 @@ class CliClient final : public Actor { } else if (op == "ccun") { string chat_id; string username; - - std::tie(chat_id, username) = split(args); + get_args(args, chat_id, username); send_request(td_api::make_object(as_chat_id(chat_id), username)); } else if (op == "ssgun" || op == "schun") { string supergroup_id; string username; - - std::tie(supergroup_id, username) = split(args); + get_args(args, supergroup_id, username); send_request(td_api::make_object(as_supergroup_id(supergroup_id), username)); } else if (op == "ssgss") { string supergroup_id; - string sticker_set_id; - - std::tie(supergroup_id, sticker_set_id) = split(args); - send_request(td_api::make_object(as_supergroup_id(supergroup_id), - to_integer(sticker_set_id))); + int64 sticker_set_id; + get_args(args, supergroup_id, sticker_set_id); + send_request( + td_api::make_object(as_supergroup_id(supergroup_id), sticker_set_id)); } else if (op == "tsgp") { string supergroup_id; - string is_all_history_available; - - std::tie(supergroup_id, is_all_history_available) = split(args); - send_request(td_api::make_object( - as_supergroup_id(supergroup_id), as_bool(is_all_history_available))); + bool is_all_history_available; + get_args(args, supergroup_id, is_all_history_available); + send_request(td_api::make_object(as_supergroup_id(supergroup_id), + is_all_history_available)); } else if (op == "tsgsm") { string supergroup_id; - string sign_messages; - - std::tie(supergroup_id, sign_messages) = split(args); - send_request(td_api::make_object(as_supergroup_id(supergroup_id), - as_bool(sign_messages))); + bool sign_messages; + get_args(args, supergroup_id, sign_messages); + send_request( + td_api::make_object(as_supergroup_id(supergroup_id), sign_messages)); } else if (op == "scd") { string chat_id; string description; - - std::tie(chat_id, description) = split(args); + get_args(args, chat_id, description); send_request(td_api::make_object(as_chat_id(chat_id), description)); } else if (op == "scdg") { string chat_id; string group_chat_id; - - std::tie(chat_id, group_chat_id) = split(args); + get_args(args, chat_id, group_chat_id); send_request(td_api::make_object(as_chat_id(chat_id), as_chat_id(group_chat_id))); } else if (op == "scl") { string chat_id; string latitude; string longitude; - - std::tie(chat_id, args) = split(args); - std::tie(latitude, longitude) = split(args); + get_args(args, chat_id, latitude, longitude); send_request(td_api::make_object( as_chat_id(chat_id), td_api::make_object(as_location(latitude, longitude), "address"))); } else if (op == "scsmd") { string chat_id; - string slow_mode_delay; - - std::tie(chat_id, slow_mode_delay) = split(args); - send_request( - td_api::make_object(as_chat_id(chat_id), to_integer(slow_mode_delay))); + int32 slow_mode_delay; + get_args(args, chat_id, slow_mode_delay); + send_request(td_api::make_object(as_chat_id(chat_id), slow_mode_delay)); } else if (op == "pcm" || op == "pcms" || op == "pcmo") { string chat_id; string message_id; - - std::tie(chat_id, message_id) = split(args); + get_args(args, chat_id, message_id); send_request(td_api::make_object(as_chat_id(chat_id), as_message_id(message_id), op == "pcms", op == "pcmo")); } else if (op == "upcm") { string chat_id; string message_id; - - std::tie(chat_id, message_id) = split(args); + get_args(args, chat_id, message_id); send_request(td_api::make_object(as_chat_id(chat_id), as_message_id(message_id))); } else if (op == "uacm") { string chat_id = args; @@ -4065,32 +3677,27 @@ class CliClient final : public Actor { } else if (op == "spcs") { send_request(td_api::make_object(args)); } else if (op == "sc") { - string limit; - string query; - std::tie(limit, query) = split(args); - send_request(td_api::make_object(query, to_integer(limit))); + SearchQuery query; + get_args(args, query); + send_request(td_api::make_object(query.query, query.limit)); } else if (op == "scos") { - string limit; - string query; - std::tie(limit, query) = split(args); - send_request(td_api::make_object(query, to_integer(limit))); + SearchQuery query; + get_args(args, query); + send_request(td_api::make_object(query.query, query.limit)); } else if (op == "scn") { string latitude; string longitude; - - std::tie(latitude, longitude) = split(args); + get_args(args, latitude, longitude); send_request(td_api::make_object(as_location(latitude, longitude))); } else if (op == "sloc") { string latitude; string longitude; - - std::tie(latitude, longitude) = split(args); + get_args(args, latitude, longitude); send_request(td_api::make_object(as_location(latitude, longitude))); } else if (op == "sco") { - string limit; - string query; - std::tie(limit, query) = split(args); - send_request(td_api::make_object(query, to_integer(limit))); + SearchQuery query; + get_args(args, query); + send_request(td_api::make_object(query.query, query.limit)); } else if (op == "arfc") { send_request(td_api::make_object(as_chat_id(args))); } else if (op == "rrfc") { @@ -4101,10 +3708,9 @@ class CliClient final : public Actor { send_request(td_api::make_object(as_caption(args))); } else if (op == "gwpiv") { string url; - string force_full; - std::tie(url, force_full) = split(args); - - send_request(td_api::make_object(url, as_bool(force_full))); + bool force_full; + get_args(args, url, force_full); + send_request(td_api::make_object(url, force_full)); } else if (op == "sppp") { send_request(td_api::make_object( td_api::make_object(to_integer(args)))); @@ -4114,8 +3720,7 @@ class CliClient final : public Actor { } else if (op == "sppa" || op == "sppv") { string animation; string main_frame_timestamp; - std::tie(animation, main_frame_timestamp) = split(args); - + get_args(args, animation, main_frame_timestamp); send_request(td_api::make_object(td_api::make_object( as_input_file(animation), to_double(main_frame_timestamp)))); } else if (op == "sh") { @@ -4128,18 +3733,16 @@ class CliClient final : public Actor { string chat_id; string message_thread_id; string message_ids; - std::tie(chat_id, message_ids) = split(args); + get_args(args, chat_id, message_ids); if (op == "viewt") { - std::tie(message_thread_id, message_ids) = split(message_ids); + get_args(message_ids, message_thread_id, message_ids); } - send_request(td_api::make_object( as_chat_id(chat_id), as_message_thread_id(message_thread_id), as_message_ids(message_ids), true)); } else if (op == "omc") { string chat_id; string message_id; - std::tie(chat_id, message_id) = split(args); - + get_args(args, chat_id, message_id); send_request(td_api::make_object(as_chat_id(chat_id), as_message_id(message_id))); } else if (op == "racm") { string chat_id = args; @@ -4156,21 +3759,13 @@ class CliClient final : public Actor { send_request(td_api::make_object(get_notification_settings_scope(args))); } else if (op == "scns" || op == "ssns") { string chat_id_or_scope; - string settings; - - std::tie(chat_id_or_scope, settings) = split(args); - string mute_for; string sound; string show_preview; string disable_pinned_message_notifications; string disable_mention_notifications; - - std::tie(mute_for, settings) = split(settings, ','); - std::tie(sound, settings) = split(settings, ','); - std::tie(show_preview, settings) = split(settings, ','); - std::tie(disable_pinned_message_notifications, disable_mention_notifications) = split(settings, ','); - + get_args(args, chat_id_or_scope, mute_for, sound, show_preview, disable_pinned_message_notifications, + disable_mention_notifications); if (op == "scns") { send_request(td_api::make_object( as_chat_id(chat_id_or_scope), @@ -4189,88 +3784,58 @@ class CliClient final : public Actor { } else if (op == "rans") { send_request(td_api::make_object()); } else if (op == "rn") { - string group_id; + int32 group_id; string notification_ids; - std::tie(group_id, notification_ids) = split(args); + get_args(args, group_id, notification_ids); for (auto notification_id : to_integers(notification_ids)) { - send_request(td_api::make_object(to_integer(group_id), notification_id)); + send_request(td_api::make_object(group_id, notification_id)); } } else if (op == "rng") { - string group_id; - string max_notification_id; - std::tie(group_id, max_notification_id) = split(args); - send_request(td_api::make_object(to_integer(group_id), - to_integer(max_notification_id))); + int32 group_id; + int32 max_notification_id; + get_args(args, group_id, max_notification_id); + send_request(td_api::make_object(group_id, max_notification_id)); } else if (op == "rcab") { string chat_id = args; send_request(td_api::make_object(as_chat_id(chat_id))); } else if (op == "rc") { string chat_id; - string reason_str; + string reason; string message_ids; - std::tie(chat_id, args) = split(args); - std::tie(reason_str, message_ids) = split(args); - - td_api::object_ptr reason; - if (reason_str == "spam") { - reason = td_api::make_object(); - } else if (reason_str == "violence") { - reason = td_api::make_object(); - } else if (reason_str == "porno") { - reason = td_api::make_object(); - } else if (reason_str == "ca") { - reason = td_api::make_object(); - } else if (reason_str == "copyright") { - reason = td_api::make_object(); - } else if (reason_str == "geo" || reason_str == "location") { - reason = td_api::make_object(); - } else { - reason = td_api::make_object(reason_str); - } - - send_request( - td_api::make_object(as_chat_id(chat_id), std::move(reason), as_message_ids(message_ids))); + get_args(args, chat_id, reason, message_ids); + send_request(td_api::make_object(as_chat_id(chat_id), get_chat_report_reason(reason), + as_message_ids(message_ids))); } else if (op == "gcsu") { string chat_id; string parameters; - string is_dark; - std::tie(chat_id, args) = split(args); - std::tie(parameters, is_dark) = split(args); - - send_request( - td_api::make_object(as_chat_id(chat_id), parameters, as_bool(is_dark))); + bool is_dark; + get_args(args, chat_id, parameters, is_dark); + send_request(td_api::make_object(as_chat_id(chat_id), parameters, is_dark)); } else if (op == "gcst") { string chat_id; - string is_dark; - std::tie(chat_id, is_dark) = split(args); - - send_request(td_api::make_object(as_chat_id(chat_id), as_bool(is_dark))); + bool is_dark; + get_args(args, chat_id, is_dark); + send_request(td_api::make_object(as_chat_id(chat_id), is_dark)); } else if (op == "gmst") { string chat_id; string message_id; - string is_dark; - std::tie(chat_id, args) = split(args); - std::tie(message_id, is_dark) = split(args); - - send_request(td_api::make_object(as_chat_id(chat_id), as_message_id(message_id), - as_bool(is_dark))); + bool is_dark; + get_args(args, chat_id, message_id, is_dark); + send_request( + td_api::make_object(as_chat_id(chat_id), as_message_id(message_id), is_dark)); } else if (op == "gstg") { string chat_id; string token; - string x; - std::tie(chat_id, args) = split(args); - std::tie(token, x) = split(args); - - send_request(td_api::make_object(as_chat_id(chat_id), token, to_integer(x))); + int64 x; + get_args(args, chat_id, token, x); + send_request(td_api::make_object(as_chat_id(chat_id), token, x)); } else if (op == "hsa" || op == "glu" || op == "glua") { send_request(td_api::make_object(as_suggested_action(args))); } else if (op == "glui" || op == "glu" || op == "glua") { string chat_id; string message_id; string button_id; - std::tie(chat_id, args) = split(args); - std::tie(message_id, button_id) = split(args); - + get_args(args, chat_id, message_id, button_id); if (op == "glui") { send_request(td_api::make_object(as_chat_id(chat_id), as_message_id(message_id), as_button_id(button_id))); @@ -4282,9 +3847,7 @@ class CliClient final : public Actor { string supergroup_id; string user_id; string message_ids; - std::tie(supergroup_id, args) = split(args); - std::tie(user_id, message_ids) = split(args); - + get_args(args, supergroup_id, user_id, message_ids); send_request(td_api::make_object(as_supergroup_id(supergroup_id), as_user_id(user_id), as_message_ids(message_ids))); } else if (op == "gdiff") { @@ -4299,34 +3862,31 @@ class CliClient final : public Actor { op == "editeproxytcp" || op == "tproxy") { string proxy_id; string server; - string port; + int32 port; string user; string password; if (op[0] == 'e') { - std::tie(proxy_id, args) = split(args); + get_args(args, proxy_id, args); } - std::tie(server, args) = split(args); - std::tie(port, args) = split(args); - std::tie(user, password) = split(args); + get_args(args, server, port, user, password); bool enable = op != "aproxy" && op != "editproxy"; td_api::object_ptr type; if (!user.empty() && password.empty()) { type = td_api::make_object(user); } else { - if (port == "80" || port == "8080") { + if (port == 80 || port == 8080) { type = td_api::make_object(user, password, op.back() != 'p'); } else { type = td_api::make_object(user, password); } } - auto port_int = to_integer(port); if (op[0] == 'e') { send_request( - td_api::make_object(as_proxy_id(proxy_id), server, port_int, enable, std::move(type))); + td_api::make_object(as_proxy_id(proxy_id), server, port, enable, std::move(type))); } else if (op == "tproxy") { - send_request(td_api::make_object(server, port_int, std::move(type), 2, 10.0)); + send_request(td_api::make_object(server, port, std::move(type), 2, 10.0)); } else { - send_request(td_api::make_object(server, port_int, enable, std::move(type))); + send_request(td_api::make_object(server, port, enable, std::move(type))); } } else if (op == "gproxy" || op == "gproxies") { send_request(td_api::make_object()); @@ -4390,9 +3950,9 @@ class CliClient final : public Actor { execute(td_api::make_object()); } else if (op == "sltvl" || op == "sltvle" || op == "tag") { string tag; - string level; - std::tie(tag, level) = split(args); - auto request = td_api::make_object(tag, to_integer(level)); + int32 level; + get_args(args, tag, level); + auto request = td_api::make_object(tag, level); if (op == "sltvl") { send_request(std::move(request)); } else { @@ -4407,11 +3967,10 @@ class CliClient final : public Actor { execute(std::move(request)); } } else if (op == "alog" || op == "aloge") { - string level; + int32 level; string text; - std::tie(level, text) = split(args); - - auto request = td_api::make_object(to_integer(level), text); + get_args(args, level, text); + auto request = td_api::make_object(level, text); if (op == "alog") { send_request(std::move(request)); } else { @@ -4484,7 +4043,7 @@ class CliClient final : public Actor { } BufferSlice block(it->part_size); FileFd::open(it->source, FileFd::Flags::Read).move_as_ok().pread(block.as_slice(), it->local_size).ensure(); - if (Random::fast_bool()) { + if (rand_bool()) { auto open_flags = FileFd::Flags::Write | (it->local_size ? 0 : FileFd::Flags::Truncate | FileFd::Flags::Create); FileFd::open(it->destination, open_flags).move_as_ok().pwrite(block.as_slice(), it->local_size).ensure(); } else { @@ -4643,10 +4202,8 @@ void main(int argc, char **argv) { }); options.add_option('W', "", "Preload chat list", [&] { get_chat_list = true; }); options.add_option('n', "disable-network", "Disable network", [&] { disable_network = true; }); - options.add_option('\0', "api-id", "Set Telegram API ID", - [&](Slice parameter) { api_id = to_integer(parameter); }); - options.add_option('\0', "api_id", "Set Telegram API ID", - [&](Slice parameter) { api_id = to_integer(parameter); }); + options.add_checked_option('\0', "api-id", "Set Telegram API ID", OptionParser::parse_integer(api_id)); + options.add_checked_option('\0', "api_id", "Set Telegram API ID", OptionParser::parse_integer(api_id)); options.add_option('\0', "api-hash", "Set Telegram API hash", OptionParser::parse_string(api_hash)); options.add_option('\0', "api_hash", "Set Telegram API hash", OptionParser::parse_string(api_hash)); options.add_check([&] { diff --git a/tdutils/td/utils/misc.h b/tdutils/td/utils/misc.h index 32971b8cc..323d33626 100644 --- a/tdutils/td/utils/misc.h +++ b/tdutils/td/utils/misc.h @@ -320,7 +320,7 @@ template Result to_integer_safe(Slice str) { auto res = to_integer(str); if ((PSLICE() << res) != str) { - return Status::Error(PSLICE() << "Can't parse \"" << str << "\" as number"); + return Status::Error(PSLICE() << "Can't parse \"" << str << "\" as an integer"); } return res; }