Merge remote-tracking branch 'td/master'
This commit is contained in:
commit
4cd31ceb93
@ -734,7 +734,7 @@ function onOptionsChanged() {
|
||||
pre_text.push('Install Git, ' + compiler + ', make, CMake >= 3.0.2, OpenSSL-dev, zlib-dev, gperf, PHP' + jdk + ' using your package manager.');
|
||||
}
|
||||
if (os_linux && os.includes('Node.js')) {
|
||||
pre_text.push('Note that for Node.js ≤ 9.11.2 you must build TDLight with OpenSSL 1.0.* and for Node.js ≥ 10 with OpenSSL 1.1.* instead, so you may need to modify the following commands to install a proper OpenSSL version.');
|
||||
pre_text.push('Note that for Node.js ≥ 17 you must build TDLib with OpenSSL 3.0.*, for Node.js ≥ 10 with OpenSSL 1.1.*, and for Node.js < 10 with OpenSSL 1.0.*, so you may need to modify the following commands to install a proper OpenSSL version.');
|
||||
}
|
||||
if (os_freebsd) {
|
||||
pre_text.push('Note that the following instruction is for FreeBSD 11.');
|
||||
|
@ -2353,8 +2353,8 @@ callStateReady protocol:callProtocol servers:vector<callServer> config:string en
|
||||
//@description The call is hanging up after discardCall has been called
|
||||
callStateHangingUp = CallState;
|
||||
|
||||
//@description The call has ended successfully @reason The reason, why the call has ended @need_rating True, if the call rating must be sent to the server @need_debug_information True, if the call debug information must be sent to the server
|
||||
callStateDiscarded reason:CallDiscardReason need_rating:Bool need_debug_information:Bool = CallState;
|
||||
//@description The call has ended successfully @reason The reason, why the call has ended @need_rating True, if the call rating must be sent to the server @need_debug_information True, if the call debug information must be sent to the server @need_log True, if the call log must be sent to the server
|
||||
callStateDiscarded reason:CallDiscardReason need_rating:Bool need_debug_information:Bool need_log:Bool = CallState;
|
||||
|
||||
//@description The call has ended with an error @error Error. An error with the code 4005000 will be returned if an outgoing call is missed because of an expired timeout
|
||||
callStateError error:error = CallState;
|
||||
@ -3295,18 +3295,73 @@ userPrivacySettingAllowFindingByPhoneNumber = UserPrivacySetting;
|
||||
accountTtl days:int32 = AccountTtl;
|
||||
|
||||
|
||||
//@class SessionType @description Represents the type of a session
|
||||
|
||||
//@description The session is running on an Android device
|
||||
sessionTypeAndroid = SessionType;
|
||||
|
||||
//@description The session is running on a generic Apple device
|
||||
sessionTypeApple = SessionType;
|
||||
|
||||
//@description The session is running on the Brave browser
|
||||
sessionTypeBrave = SessionType;
|
||||
|
||||
//@description The session is running on the Chrome browser
|
||||
sessionTypeChrome = SessionType;
|
||||
|
||||
//@description The session is running on the Edge browser
|
||||
sessionTypeEdge = SessionType;
|
||||
|
||||
//@description The session is running on the Firefox browser
|
||||
sessionTypeFirefox = SessionType;
|
||||
|
||||
//@description The session is running on an iPad device
|
||||
sessionTypeIpad = SessionType;
|
||||
|
||||
//@description The session is running on an iPhone device
|
||||
sessionTypeIphone = SessionType;
|
||||
|
||||
//@description The session is running on a Linux device
|
||||
sessionTypeLinux = SessionType;
|
||||
|
||||
//@description The session is running on a Mac device
|
||||
sessionTypeMac = SessionType;
|
||||
|
||||
//@description The session is running on the Opera browser
|
||||
sessionTypeOpera = SessionType;
|
||||
|
||||
//@description The session is running on the Safari browser
|
||||
sessionTypeSafari = SessionType;
|
||||
|
||||
//@description The session is running on an Ubuntu device
|
||||
sessionTypeUbuntu = SessionType;
|
||||
|
||||
//@description The session is running on an unknown type of device
|
||||
sessionTypeUnknown = SessionType;
|
||||
|
||||
//@description The session is running on the Vivaldi browser
|
||||
sessionTypeVivaldi = SessionType;
|
||||
|
||||
//@description The session is running on a Windows device
|
||||
sessionTypeWindows = SessionType;
|
||||
|
||||
//@description The session is running on an Xbox console
|
||||
sessionTypeXbox = SessionType;
|
||||
|
||||
|
||||
//@description Contains information about one session in a Telegram application used by the current user. Sessions must be shown to the user in the returned order
|
||||
//@id Session identifier @is_current True, if this session is the current session
|
||||
//@is_password_pending True, if a password is needed to complete authorization of the session
|
||||
//@can_accept_secret_chats True, if incoming secret chats can be accepted by the session
|
||||
//@can_accept_calls True, if incoming calls can be accepted by the session
|
||||
//@type Session type based on the system and application version, which can be used to display a corresponding icon
|
||||
//@api_id Telegram API identifier, as provided by the application @application_name Name of the application, as provided by the application
|
||||
//@application_version The version of the application, as provided by the application @is_official_application True, if the application is an official application or uses the api_id of an official application
|
||||
//@device_model Model of the device the application has been run or is running on, as provided by the application @platform Operating system the application has been run or is running on, as provided by the application
|
||||
//@system_version Version of the operating system the application has been run or is running on, as provided by the application @log_in_date Point in time (Unix timestamp) when the user has logged in
|
||||
//@last_active_date Point in time (Unix timestamp) when the session was last used @ip IP address from which the session was created, in human-readable format
|
||||
//@country A two-letter country code for the country from which the session was created, based on the IP address @region Region code from which the session was created, based on the IP address
|
||||
session id:int64 is_current:Bool is_password_pending:Bool can_accept_secret_chats:Bool can_accept_calls:Bool api_id:int32 application_name:string application_version:string is_official_application:Bool device_model:string platform:string system_version:string log_in_date:int32 last_active_date:int32 ip:string country:string region:string = Session;
|
||||
session id:int64 is_current:Bool is_password_pending:Bool can_accept_secret_chats:Bool can_accept_calls:Bool type:SessionType api_id:int32 application_name:string application_version:string is_official_application:Bool device_model:string platform:string system_version:string log_in_date:int32 last_active_date:int32 ip:string country:string region:string = Session;
|
||||
|
||||
//@description Contains a list of sessions @sessions List of sessions @inactive_session_ttl_days Number of days of inactivity before sessions will automatically be terminated; 1-366 days
|
||||
sessions sessions:vector<session> inactive_session_ttl_days:int32 = Sessions;
|
||||
@ -5442,9 +5497,12 @@ discardCall call_id:int32 is_disconnected:Bool duration:int32 is_video:Bool conn
|
||||
//@description Sends a call rating @call_id Call identifier @rating Call rating; 1-5 @comment An optional user comment if the rating is less than 5 @problems List of the exact types of problems with the call, specified by the user
|
||||
sendCallRating call_id:int32 rating:int32 comment:string problems:vector<CallProblem> = Ok;
|
||||
|
||||
//@description Sends debug information for a call @call_id Call identifier @debug_information Debug information in application-specific format
|
||||
//@description Sends debug information for a call to Telegram servers @call_id Call identifier @debug_information Debug information in application-specific format
|
||||
sendCallDebugInformation call_id:int32 debug_information:string = Ok;
|
||||
|
||||
//@description Sends log file for a call to Telegram servers @call_id Call identifier @log_file Call log file. Only inputFileLocal and inputFileGenerated are supported
|
||||
sendCallLog call_id:int32 log_file:InputFile = Ok;
|
||||
|
||||
|
||||
//@description Returns list of participant identifiers, on whose behalf a video chat in the chat can be joined @chat_id Chat identifier
|
||||
getVideoChatAvailableParticipants chat_id:int53 = MessageSenders;
|
||||
@ -5610,7 +5668,7 @@ changeImportedContacts contacts:vector<contact> = ImportedContacts;
|
||||
clearImportedContacts = Ok;
|
||||
|
||||
|
||||
//@description Searches a user by their phone number @phone_number Phone number to search for
|
||||
//@description Searches a user by their phone number. Returns a 404 error if the user can't be found @phone_number Phone number to search for
|
||||
searchUserByPhoneNumber phone_number:string = User;
|
||||
|
||||
//@description Shares the phone number of the current user with a mutual contact. Supposed to be called when the user clicks on chatActionBarSharePhoneNumber @user_id Identifier of the user with whom to share the phone number. The user must be a mutual contact
|
||||
|
@ -1797,6 +1797,7 @@ phone.joinGroupCallPresentation#cbea6bc4 call:InputGroupCall params:DataJSON = U
|
||||
phone.leaveGroupCallPresentation#1c50d144 call:InputGroupCall = Updates;
|
||||
phone.getGroupCallStreamChannels#1ab21940 call:InputGroupCall = phone.GroupCallStreamChannels;
|
||||
phone.getGroupCallStreamRtmpUrl#deb3abbf peer:InputPeer revoke:Bool = phone.GroupCallStreamRtmpUrl;
|
||||
phone.saveCallLog#41248786 peer:InputPhoneCall file:InputFile = Bool;
|
||||
|
||||
langpack.getLangPack#f2f2330a lang_pack:string lang_code:string = LangPackDifference;
|
||||
langpack.getStrings#efea3803 lang_pack:string lang_code:string keys:Vector<string> = Vector<LangPackString>;
|
||||
|
@ -28,15 +28,85 @@
|
||||
|
||||
namespace td {
|
||||
|
||||
static td_api::object_ptr<td_api::SessionType> get_session_type_object(
|
||||
const tl_object_ptr<telegram_api::authorization> &authorization) {
|
||||
auto contains = [](const string &str, const char *substr) {
|
||||
return str.find(substr) != string::npos;
|
||||
};
|
||||
|
||||
const string &app_name = authorization->app_name_;
|
||||
auto device_model = to_lower(authorization->device_model_);
|
||||
auto platform = to_lower(authorization->platform_);
|
||||
auto system_version = to_lower(authorization->system_version_);
|
||||
|
||||
if (device_model.find("xbox") != string::npos) {
|
||||
return td_api::make_object<td_api::sessionTypeXbox>();
|
||||
}
|
||||
|
||||
bool is_web = [&] {
|
||||
CSlice web_name("Web");
|
||||
auto pos = app_name.find(web_name.c_str());
|
||||
if (pos == string::npos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto next_character = app_name[pos + web_name.size()];
|
||||
return !('a' <= next_character && next_character <= 'z');
|
||||
}();
|
||||
|
||||
if (is_web) {
|
||||
if (contains(device_model, "brave")) {
|
||||
return td_api::make_object<td_api::sessionTypeBrave>();
|
||||
} else if (contains(device_model, "vivaldi")) {
|
||||
return td_api::make_object<td_api::sessionTypeVivaldi>();
|
||||
} else if (contains(device_model, "opera") || contains(device_model, "opr")) {
|
||||
return td_api::make_object<td_api::sessionTypeOpera>();
|
||||
} else if (contains(device_model, "edg")) {
|
||||
return td_api::make_object<td_api::sessionTypeEdge>();
|
||||
} else if (contains(device_model, "chrome")) {
|
||||
return td_api::make_object<td_api::sessionTypeChrome>();
|
||||
} else if (contains(device_model, "firefox") || contains(device_model, "fxios")) {
|
||||
return td_api::make_object<td_api::sessionTypeFirefox>();
|
||||
} else if (contains(device_model, "safari")) {
|
||||
return td_api::make_object<td_api::sessionTypeSafari>();
|
||||
}
|
||||
}
|
||||
|
||||
if (begins_with(platform, "android") || contains(system_version, "android")) {
|
||||
return td_api::make_object<td_api::sessionTypeAndroid>();
|
||||
} else if (begins_with(platform, "windows") || contains(system_version, "windows")) {
|
||||
return td_api::make_object<td_api::sessionTypeWindows>();
|
||||
} else if (begins_with(platform, "ubuntu") || contains(system_version, "ubuntu")) {
|
||||
return td_api::make_object<td_api::sessionTypeUbuntu>();
|
||||
} else if (begins_with(platform, "linux") || contains(system_version, "linux")) {
|
||||
return td_api::make_object<td_api::sessionTypeLinux>();
|
||||
}
|
||||
|
||||
auto is_ios = begins_with(platform, "ios") || contains(system_version, "ios");
|
||||
auto is_macos = begins_with(platform, "macos") || contains(system_version, "macos");
|
||||
if (is_ios && contains(device_model, "iphone")) {
|
||||
return td_api::make_object<td_api::sessionTypeIphone>();
|
||||
} else if (is_ios && contains(device_model, "ipad")) {
|
||||
return td_api::make_object<td_api::sessionTypeIpad>();
|
||||
} else if (is_macos && contains(device_model, "mac")) {
|
||||
return td_api::make_object<td_api::sessionTypeMac>();
|
||||
} else if (is_ios || is_macos) {
|
||||
return td_api::make_object<td_api::sessionTypeApple>();
|
||||
}
|
||||
|
||||
return td_api::make_object<td_api::sessionTypeUnknown>();
|
||||
}
|
||||
|
||||
static td_api::object_ptr<td_api::session> convert_authorization_object(
|
||||
tl_object_ptr<telegram_api::authorization> &&authorization) {
|
||||
CHECK(authorization != nullptr);
|
||||
return td_api::make_object<td_api::session>(
|
||||
authorization->hash_, authorization->current_, authorization->password_pending_,
|
||||
!authorization->encrypted_requests_disabled_, !authorization->call_requests_disabled_, authorization->api_id_,
|
||||
authorization->app_name_, authorization->app_version_, authorization->official_app_, authorization->device_model_,
|
||||
authorization->platform_, authorization->system_version_, authorization->date_created_,
|
||||
authorization->date_active_, authorization->ip_, authorization->country_, authorization->region_);
|
||||
!authorization->encrypted_requests_disabled_, !authorization->call_requests_disabled_,
|
||||
get_session_type_object(authorization), authorization->api_id_, authorization->app_name_,
|
||||
authorization->app_version_, authorization->official_app_, authorization->device_model_, authorization->platform_,
|
||||
authorization->system_version_, authorization->date_created_, authorization->date_active_, authorization->ip_,
|
||||
authorization->country_, authorization->region_);
|
||||
}
|
||||
|
||||
class SetAccountTtlQuery final : public Td::ResultHandler {
|
||||
|
@ -598,7 +598,9 @@ Result<AttachMenuManager::AttachMenuBot> AttachMenuManager::get_attach_menu_bot(
|
||||
auto parsed_document =
|
||||
td_->documents_manager_->on_get_document(move_tl_object_as<telegram_api::document>(icon->icon_), DialogId());
|
||||
if (parsed_document.type != expected_document_type) {
|
||||
if (user_id != UserId(5000860301) || !G()->is_test_dc() || name != "macos_animated") {
|
||||
LOG(ERROR) << "Receive wrong attachment menu bot icon \"" << name << "\" for " << user_id;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
bool expect_colors = false;
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "td/telegram/ContactsManager.h"
|
||||
#include "td/telegram/DhCache.h"
|
||||
#include "td/telegram/DialogId.h"
|
||||
#include "td/telegram/files/FileManager.h"
|
||||
#include "td/telegram/Global.h"
|
||||
#include "td/telegram/misc.h"
|
||||
#include "td/telegram/net/NetQueryCreator.h"
|
||||
@ -128,7 +129,7 @@ tl_object_ptr<td_api::CallState> CallState::get_call_state_object() const {
|
||||
return make_tl_object<td_api::callStateHangingUp>();
|
||||
case Type::Discarded:
|
||||
return make_tl_object<td_api::callStateDiscarded>(get_call_discard_reason_object(discard_reason), need_rating,
|
||||
need_debug_information);
|
||||
need_debug_information, need_log);
|
||||
case Type::Error:
|
||||
CHECK(error.is_error());
|
||||
return make_tl_object<td_api::callStateError>(make_tl_object<td_api::error>(error.code(), error.message().str()));
|
||||
@ -159,7 +160,7 @@ void CallActor::create_call(UserId user_id, tl_object_ptr<telegram_api::InputUse
|
||||
promise.set_value(CallId(local_call_id_));
|
||||
}
|
||||
|
||||
void CallActor::accept_call(CallProtocol &&protocol, Promise<> promise) {
|
||||
void CallActor::accept_call(CallProtocol &&protocol, Promise<Unit> promise) {
|
||||
if (state_ != State::SendAcceptQuery) {
|
||||
return promise.set_error(Status::Error(400, "Unexpected acceptCall"));
|
||||
}
|
||||
@ -180,7 +181,7 @@ void CallActor::update_call_signaling_data(string data) {
|
||||
send_closure(G()->td(), &Td::send_update, std::move(update));
|
||||
}
|
||||
|
||||
void CallActor::send_call_signaling_data(string &&data, Promise<> promise) {
|
||||
void CallActor::send_call_signaling_data(string &&data, Promise<Unit> promise) {
|
||||
if (call_state_.type != CallState::Type::Ready) {
|
||||
return promise.set_error(Status::Error(400, "Call is not active"));
|
||||
}
|
||||
@ -199,7 +200,7 @@ void CallActor::send_call_signaling_data(string &&data, Promise<> promise) {
|
||||
}
|
||||
|
||||
void CallActor::discard_call(bool is_disconnected, int32 duration, bool is_video, int64 connection_id,
|
||||
Promise<> promise) {
|
||||
Promise<Unit> promise) {
|
||||
promise.set_value(Unit());
|
||||
if (state_ == State::Discarded || state_ == State::WaitDiscardResult || state_ == State::SendDiscardQuery) {
|
||||
return;
|
||||
@ -244,7 +245,7 @@ void CallActor::discard_call(bool is_disconnected, int32 duration, bool is_video
|
||||
}
|
||||
|
||||
void CallActor::rate_call(int32 rating, string comment, vector<td_api::object_ptr<td_api::CallProblem>> &&problems,
|
||||
Promise<> promise) {
|
||||
Promise<Unit> promise) {
|
||||
if (!call_state_.need_rating) {
|
||||
return promise.set_error(Status::Error(400, "Unexpected sendCallRating"));
|
||||
}
|
||||
@ -309,11 +310,15 @@ void CallActor::on_set_rating_query_result(Result<NetQueryPtr> r_net_query) {
|
||||
if (res.is_error()) {
|
||||
return on_error(res.move_as_error());
|
||||
}
|
||||
if (call_state_.need_rating) {
|
||||
call_state_.need_rating = false;
|
||||
call_state_need_flush_ = true;
|
||||
loop();
|
||||
}
|
||||
send_closure(G()->updates_manager(), &UpdatesManager::on_get_updates, res.move_as_ok(), Promise<Unit>());
|
||||
}
|
||||
|
||||
void CallActor::send_call_debug_information(string data, Promise<> promise) {
|
||||
void CallActor::send_call_debug_information(string data, Promise<Unit> promise) {
|
||||
if (!call_state_.need_debug_information) {
|
||||
return promise.set_error(Status::Error(400, "Unexpected sendCallDebugInformation"));
|
||||
}
|
||||
@ -323,17 +328,148 @@ void CallActor::send_call_debug_information(string data, Promise<> promise) {
|
||||
auto query = G()->net_query_creator().create(tl_query);
|
||||
send_with_promise(std::move(query),
|
||||
PromiseCreator::lambda([actor_id = actor_id(this)](Result<NetQueryPtr> r_net_query) {
|
||||
send_closure(actor_id, &CallActor::on_set_debug_query_result, std::move(r_net_query));
|
||||
send_closure(actor_id, &CallActor::on_save_debug_query_result, std::move(r_net_query));
|
||||
}));
|
||||
loop();
|
||||
}
|
||||
|
||||
void CallActor::on_set_debug_query_result(Result<NetQueryPtr> r_net_query) {
|
||||
void CallActor::on_save_debug_query_result(Result<NetQueryPtr> r_net_query) {
|
||||
auto res = fetch_result<telegram_api::phone_saveCallDebug>(std::move(r_net_query));
|
||||
if (res.is_error()) {
|
||||
return on_error(res.move_as_error());
|
||||
}
|
||||
if (!res.ok() && !call_state_.need_log) {
|
||||
call_state_.need_log = true;
|
||||
call_state_need_flush_ = true;
|
||||
}
|
||||
if (call_state_.need_debug_information) {
|
||||
call_state_.need_debug_information = false;
|
||||
call_state_need_flush_ = true;
|
||||
}
|
||||
loop();
|
||||
}
|
||||
|
||||
void CallActor::send_call_log(td_api::object_ptr<td_api::InputFile> log_file, Promise<Unit> promise) {
|
||||
if (!call_state_.need_log) {
|
||||
return promise.set_error(Status::Error(400, "Unexpected sendCallLog"));
|
||||
}
|
||||
TRY_STATUS_PROMISE(promise, G()->close_status());
|
||||
|
||||
auto *file_manager = G()->td().get_actor_unsafe()->file_manager_.get();
|
||||
auto r_file_id = file_manager->get_input_file_id(FileType::CallLog, log_file, DialogId(), false, false);
|
||||
if (r_file_id.is_error()) {
|
||||
return promise.set_error(Status::Error(400, r_file_id.error().message()));
|
||||
}
|
||||
auto file_id = r_file_id.move_as_ok();
|
||||
|
||||
FileView file_view = file_manager->get_file_view(file_id);
|
||||
if (file_view.is_encrypted()) {
|
||||
return promise.set_error(Status::Error(400, "Can't use encrypted file"));
|
||||
}
|
||||
if (!file_view.has_local_location() && !file_view.has_generate_location()) {
|
||||
return promise.set_error(Status::Error(400, "Need local or generate location to upload call log"));
|
||||
}
|
||||
|
||||
upload_log_file(file_id, std::move(promise));
|
||||
}
|
||||
|
||||
void CallActor::upload_log_file(FileId file_id, Promise<Unit> &&promise) {
|
||||
auto *file_manager = G()->td().get_actor_unsafe()->file_manager_.get();
|
||||
auto upload_file_id = file_manager->dup_file_id(file_id);
|
||||
LOG(INFO) << "Ask to upload call log file " << upload_file_id;
|
||||
|
||||
class UploadLogFileCallback final : public FileManager::UploadCallback {
|
||||
ActorId<CallActor> actor_id_;
|
||||
FileId file_id_;
|
||||
Promise<Unit> promise_;
|
||||
|
||||
public:
|
||||
UploadLogFileCallback(ActorId<CallActor> actor_id, FileId file_id, Promise<Unit> &&promise)
|
||||
: actor_id_(actor_id), file_id_(file_id), promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
void on_upload_ok(FileId file_id, tl_object_ptr<telegram_api::InputFile> input_file) final {
|
||||
CHECK(file_id == file_id_);
|
||||
send_closure_later(actor_id_, &CallActor::on_upload_log_file, file_id, std::move(promise_),
|
||||
std::move(input_file));
|
||||
}
|
||||
|
||||
void on_upload_encrypted_ok(FileId file_id, tl_object_ptr<telegram_api::InputEncryptedFile> input_file) final {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void on_upload_secure_ok(FileId file_id, tl_object_ptr<telegram_api::InputSecureFile> input_file) final {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void on_upload_error(FileId file_id, Status error) final {
|
||||
CHECK(file_id == file_id_);
|
||||
send_closure_later(actor_id_, &CallActor::on_upload_log_file_error, file_id, std::move(promise_),
|
||||
std::move(error));
|
||||
}
|
||||
};
|
||||
|
||||
file_manager->upload(upload_file_id,
|
||||
std::make_shared<UploadLogFileCallback>(actor_id(this), upload_file_id, std::move(promise)), 1,
|
||||
0);
|
||||
}
|
||||
|
||||
void CallActor::on_upload_log_file(FileId file_id, Promise<Unit> &&promise,
|
||||
tl_object_ptr<telegram_api::InputFile> input_file) {
|
||||
LOG(INFO) << "Log file " << file_id << " has been uploaded";
|
||||
TRY_STATUS_PROMISE(promise, G()->close_status());
|
||||
|
||||
do_upload_log_file(file_id, std::move(input_file), std::move(promise));
|
||||
}
|
||||
|
||||
void CallActor::on_upload_log_file_error(FileId file_id, Promise<Unit> &&promise, Status status) {
|
||||
LOG(WARNING) << "Log file " << file_id << " has upload error " << status;
|
||||
CHECK(status.is_error());
|
||||
|
||||
TRY_STATUS_PROMISE(promise, G()->close_status());
|
||||
|
||||
promise.set_error(Status::Error(status.code() > 0 ? status.code() : 500,
|
||||
status.message())); // TODO CHECK that status has always a code
|
||||
}
|
||||
|
||||
void CallActor::do_upload_log_file(FileId file_id, tl_object_ptr<telegram_api::InputFile> &&input_file,
|
||||
Promise<Unit> &&promise) {
|
||||
if (input_file == nullptr) {
|
||||
return promise.set_error(Status::Error(500, "Failed to reupload call log"));
|
||||
}
|
||||
|
||||
auto tl_query = telegram_api::phone_saveCallLog(get_input_phone_call("do_upload_log_file"), std::move(input_file));
|
||||
send_with_promise(G()->net_query_creator().create(tl_query),
|
||||
PromiseCreator::lambda([actor_id = actor_id(this), file_id,
|
||||
promise = std::move(promise)](Result<NetQueryPtr> r_net_query) mutable {
|
||||
send_closure(actor_id, &CallActor::on_save_log_query_result, file_id, std::move(promise),
|
||||
std::move(r_net_query));
|
||||
}));
|
||||
loop();
|
||||
}
|
||||
|
||||
void CallActor::on_save_log_query_result(FileId file_id, Promise<Unit> promise, Result<NetQueryPtr> r_net_query) {
|
||||
TRY_STATUS_PROMISE(promise, G()->close_status());
|
||||
|
||||
auto *file_manager = G()->td().get_actor_unsafe()->file_manager_.get();
|
||||
file_manager->delete_partial_remote_location(file_id);
|
||||
file_manager->cancel_upload(file_id);
|
||||
|
||||
auto res = fetch_result<telegram_api::phone_saveCallLog>(std::move(r_net_query));
|
||||
if (res.is_error()) {
|
||||
auto error = res.move_as_error();
|
||||
if (begins_with(error.message(), "FILE_PART_") && ends_with(error.message(), "_MISSING")) {
|
||||
// TODO on_upload_log_file_part_missing(file_id, to_integer<int32>(error.message().substr(10)));
|
||||
// return;
|
||||
}
|
||||
return promise.set_error(std::move(error));
|
||||
}
|
||||
if (call_state_.need_log) {
|
||||
call_state_.need_log = false;
|
||||
call_state_need_flush_ = true;
|
||||
}
|
||||
loop();
|
||||
promise.set_value(Unit());
|
||||
}
|
||||
|
||||
// Requests
|
||||
@ -810,7 +946,7 @@ void CallActor::loop() {
|
||||
break;
|
||||
case State::Discarded: {
|
||||
if (call_state_.type == CallState::Type::Discarded &&
|
||||
(call_state_.need_rating || call_state_.need_debug_information)) {
|
||||
(call_state_.need_rating || call_state_.need_debug_information || call_state_.need_log)) {
|
||||
break;
|
||||
}
|
||||
LOG(INFO) << "Close " << local_call_id_;
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "td/telegram/CallDiscardReason.h"
|
||||
#include "td/telegram/CallId.h"
|
||||
#include "td/telegram/DhConfig.h"
|
||||
#include "td/telegram/files/FileId.h"
|
||||
#include "td/telegram/net/NetQuery.h"
|
||||
#include "td/telegram/td_api.h"
|
||||
#include "td/telegram/telegram_api.h"
|
||||
@ -76,6 +77,7 @@ struct CallState {
|
||||
bool is_received{false};
|
||||
bool need_debug_information{false};
|
||||
bool need_rating{false};
|
||||
bool need_log{false};
|
||||
|
||||
int64 key_fingerprint{0};
|
||||
string key;
|
||||
@ -94,13 +96,14 @@ class CallActor final : public NetQueryCallback {
|
||||
|
||||
void create_call(UserId user_id, tl_object_ptr<telegram_api::InputUser> &&input_user, CallProtocol &&protocol,
|
||||
bool is_video, Promise<CallId> &&promise);
|
||||
void accept_call(CallProtocol &&protocol, Promise<> promise);
|
||||
void accept_call(CallProtocol &&protocol, Promise<Unit> promise);
|
||||
void update_call_signaling_data(string data);
|
||||
void send_call_signaling_data(string &&data, Promise<> promise);
|
||||
void discard_call(bool is_disconnected, int32 duration, bool is_video, int64 connection_id, Promise<> promise);
|
||||
void send_call_signaling_data(string &&data, Promise<Unit> promise);
|
||||
void discard_call(bool is_disconnected, int32 duration, bool is_video, int64 connection_id, Promise<Unit> promise);
|
||||
void rate_call(int32 rating, string comment, vector<td_api::object_ptr<td_api::CallProblem>> &&problems,
|
||||
Promise<> promise);
|
||||
void send_call_debug_information(string data, Promise<> promise);
|
||||
Promise<Unit> promise);
|
||||
void send_call_debug_information(string data, Promise<Unit> promise);
|
||||
void send_call_log(td_api::object_ptr<td_api::InputFile> log_file, Promise<Unit> promise);
|
||||
|
||||
void update_call(tl_object_ptr<telegram_api::PhoneCall> call);
|
||||
|
||||
@ -182,7 +185,18 @@ class CallActor final : public NetQueryCallback {
|
||||
void on_call_discarded(CallDiscardReason reason, bool need_rating, bool need_debug, bool is_video);
|
||||
|
||||
void on_set_rating_query_result(Result<NetQueryPtr> r_net_query);
|
||||
void on_set_debug_query_result(Result<NetQueryPtr> r_net_query);
|
||||
|
||||
void on_save_debug_query_result(Result<NetQueryPtr> r_net_query);
|
||||
|
||||
void upload_log_file(FileId file_id, Promise<Unit> &&promise);
|
||||
|
||||
void on_upload_log_file(FileId file_id, Promise<Unit> &&promise, tl_object_ptr<telegram_api::InputFile> input_file);
|
||||
|
||||
void on_upload_log_file_error(FileId file_id, Promise<Unit> &&promise, Status status);
|
||||
|
||||
void do_upload_log_file(FileId file_id, tl_object_ptr<telegram_api::InputFile> &&input_file, Promise<Unit> &&promise);
|
||||
|
||||
void on_save_log_query_result(FileId file_id, Promise<Unit> promise, Result<NetQueryPtr> r_net_query);
|
||||
|
||||
void on_get_call_config_result(Result<NetQueryPtr> r_net_query);
|
||||
|
||||
|
@ -70,7 +70,7 @@ void CallManager::create_call(UserId user_id, tl_object_ptr<telegram_api::InputU
|
||||
std::move(promise));
|
||||
}
|
||||
|
||||
void CallManager::accept_call(CallId call_id, CallProtocol &&protocol, Promise<> promise) {
|
||||
void CallManager::accept_call(CallId call_id, CallProtocol &&protocol, Promise<Unit> promise) {
|
||||
auto actor = get_call_actor(call_id);
|
||||
if (actor.empty()) {
|
||||
return promise.set_error(Status::Error(400, "Call not found"));
|
||||
@ -78,7 +78,7 @@ void CallManager::accept_call(CallId call_id, CallProtocol &&protocol, Promise<>
|
||||
send_closure(actor, &CallActor::accept_call, std::move(protocol), std::move(promise));
|
||||
}
|
||||
|
||||
void CallManager::send_call_signaling_data(CallId call_id, string &&data, Promise<> promise) {
|
||||
void CallManager::send_call_signaling_data(CallId call_id, string &&data, Promise<Unit> promise) {
|
||||
auto actor = get_call_actor(call_id);
|
||||
if (actor.empty()) {
|
||||
return promise.set_error(Status::Error(400, "Call not found"));
|
||||
@ -87,7 +87,7 @@ void CallManager::send_call_signaling_data(CallId call_id, string &&data, Promis
|
||||
}
|
||||
|
||||
void CallManager::discard_call(CallId call_id, bool is_disconnected, int32 duration, bool is_video, int64 connection_id,
|
||||
Promise<> promise) {
|
||||
Promise<Unit> promise) {
|
||||
auto actor = get_call_actor(call_id);
|
||||
if (actor.empty()) {
|
||||
return promise.set_error(Status::Error(400, "Call not found"));
|
||||
@ -96,7 +96,7 @@ void CallManager::discard_call(CallId call_id, bool is_disconnected, int32 durat
|
||||
}
|
||||
|
||||
void CallManager::rate_call(CallId call_id, int32 rating, string comment,
|
||||
vector<td_api::object_ptr<td_api::CallProblem>> &&problems, Promise<> promise) {
|
||||
vector<td_api::object_ptr<td_api::CallProblem>> &&problems, Promise<Unit> promise) {
|
||||
auto actor = get_call_actor(call_id);
|
||||
if (actor.empty()) {
|
||||
return promise.set_error(Status::Error(400, "Call not found"));
|
||||
@ -104,7 +104,7 @@ void CallManager::rate_call(CallId call_id, int32 rating, string comment,
|
||||
send_closure(actor, &CallActor::rate_call, rating, std::move(comment), std::move(problems), std::move(promise));
|
||||
}
|
||||
|
||||
void CallManager::send_call_debug_information(CallId call_id, string data, Promise<> promise) {
|
||||
void CallManager::send_call_debug_information(CallId call_id, string data, Promise<Unit> promise) {
|
||||
auto actor = get_call_actor(call_id);
|
||||
if (actor.empty()) {
|
||||
return promise.set_error(Status::Error(400, "Call not found"));
|
||||
@ -112,6 +112,14 @@ void CallManager::send_call_debug_information(CallId call_id, string data, Promi
|
||||
send_closure(actor, &CallActor::send_call_debug_information, std::move(data), std::move(promise));
|
||||
}
|
||||
|
||||
void CallManager::send_call_log(CallId call_id, td_api::object_ptr<td_api::InputFile> log_file, Promise<Unit> promise) {
|
||||
auto actor = get_call_actor(call_id);
|
||||
if (actor.empty()) {
|
||||
return promise.set_error(Status::Error(400, "Call not found"));
|
||||
}
|
||||
send_closure(actor, &CallActor::send_call_log, std::move(log_file), std::move(promise));
|
||||
}
|
||||
|
||||
CallId CallManager::create_call_actor() {
|
||||
if (next_call_id_ == std::numeric_limits<int32>::max()) {
|
||||
next_call_id_ = 1;
|
||||
|
@ -29,13 +29,20 @@ class CallManager final : public Actor {
|
||||
|
||||
void create_call(UserId user_id, tl_object_ptr<telegram_api::InputUser> &&input_user, CallProtocol &&protocol,
|
||||
bool is_video, Promise<CallId> promise);
|
||||
void accept_call(CallId call_id, CallProtocol &&protocol, Promise<> promise);
|
||||
void send_call_signaling_data(CallId call_id, string &&data, Promise<> promise);
|
||||
|
||||
void accept_call(CallId call_id, CallProtocol &&protocol, Promise<Unit> promise);
|
||||
|
||||
void send_call_signaling_data(CallId call_id, string &&data, Promise<Unit> promise);
|
||||
|
||||
void discard_call(CallId call_id, bool is_disconnected, int32 duration, bool is_video, int64 connection_id,
|
||||
Promise<> promise);
|
||||
Promise<Unit> promise);
|
||||
|
||||
void rate_call(CallId call_id, int32 rating, string comment,
|
||||
vector<td_api::object_ptr<td_api::CallProblem>> &&problems, Promise<> promise);
|
||||
void send_call_debug_information(CallId call_id, string data, Promise<> promise);
|
||||
vector<td_api::object_ptr<td_api::CallProblem>> &&problems, Promise<Unit> promise);
|
||||
|
||||
void send_call_debug_information(CallId call_id, string data, Promise<Unit> promise);
|
||||
|
||||
void send_call_log(CallId call_id, td_api::object_ptr<td_api::InputFile> log_file, Promise<Unit> promise);
|
||||
|
||||
private:
|
||||
bool close_flag_ = false;
|
||||
|
@ -3318,6 +3318,11 @@ ContactsManager::~ContactsManager() = default;
|
||||
|
||||
void ContactsManager::tear_down() {
|
||||
parent_.reset();
|
||||
|
||||
LOG(DEBUG) << "Have " << users_.size() << " users, " << chats_.size() << " basic groups, " << channels_.size()
|
||||
<< " supergroups and " << secret_chats_.size() << " secret chats to free";
|
||||
LOG(DEBUG) << "Have " << users_full_.size() << " full users, " << chats_full_.size() << " full basic groups and "
|
||||
<< channels_full_.size() << " full supergroups to free";
|
||||
}
|
||||
|
||||
UserId ContactsManager::load_my_id() {
|
||||
@ -4657,13 +4662,11 @@ tl_object_ptr<telegram_api::inputEncryptedChat> ContactsManager::get_input_encry
|
||||
return make_tl_object<telegram_api::inputEncryptedChat>(secret_chat_id.get(), sc->access_hash);
|
||||
}
|
||||
|
||||
const DialogPhoto *ContactsManager::get_user_dialog_photo(UserId user_id) {
|
||||
auto u = get_user(user_id);
|
||||
if (u == nullptr) {
|
||||
return nullptr;
|
||||
void ContactsManager::apply_pending_user_photo(User *u, UserId user_id) {
|
||||
if (u == nullptr || u->is_photo_inited) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!u->is_photo_inited) {
|
||||
auto it = pending_user_photos_.find(user_id);
|
||||
if (it != pending_user_photos_.end()) {
|
||||
do_update_user_photo(u, user_id, std::move(it->second), "get_user_dialog_photo");
|
||||
@ -4671,6 +4674,14 @@ const DialogPhoto *ContactsManager::get_user_dialog_photo(UserId user_id) {
|
||||
update_user(u, user_id);
|
||||
}
|
||||
}
|
||||
|
||||
const DialogPhoto *ContactsManager::get_user_dialog_photo(UserId user_id) {
|
||||
auto u = get_user(user_id);
|
||||
if (u == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
apply_pending_user_photo(u, user_id);
|
||||
return &u->photo;
|
||||
}
|
||||
|
||||
@ -5287,7 +5298,7 @@ std::pair<vector<UserId>, vector<int32>> ContactsManager::import_contacts(const
|
||||
|
||||
do {
|
||||
random_id = Random::secure_int64();
|
||||
} while (random_id == 0 || imported_contacts_.find(random_id) != imported_contacts_.end());
|
||||
} while (random_id == 0 || imported_contacts_.count(random_id) > 0);
|
||||
imported_contacts_[random_id]; // reserve place for result
|
||||
|
||||
do_import_contacts(contacts, random_id, std::move(promise));
|
||||
@ -8378,6 +8389,14 @@ ChannelId ContactsManager::get_channel_id(const tl_object_ptr<telegram_api::Chat
|
||||
}
|
||||
}
|
||||
|
||||
DialogId ContactsManager::get_dialog_id(const tl_object_ptr<telegram_api::Chat> &chat) {
|
||||
auto channel_id = get_channel_id(chat);
|
||||
if (channel_id.is_valid()) {
|
||||
return DialogId(channel_id);
|
||||
}
|
||||
return DialogId(get_chat_id(chat));
|
||||
}
|
||||
|
||||
void ContactsManager::on_get_user(tl_object_ptr<telegram_api::User> &&user_ptr, const char *source, bool is_me,
|
||||
bool expect_support) {
|
||||
LOG(DEBUG) << "Receive from " << source << ' ' << to_string(user_ptr);
|
||||
@ -9808,18 +9827,18 @@ void ContactsManager::on_load_chat_full_from_database(ChatId chat_id, string val
|
||||
}
|
||||
}
|
||||
|
||||
if (td_->file_manager_->get_file_view(c->photo.small_file_id).get_unique_file_id() !=
|
||||
td_->file_manager_->get_file_view(as_fake_dialog_photo(chat_full->photo, DialogId(chat_id)).small_file_id)
|
||||
.get_unique_file_id()) {
|
||||
if (!is_same_dialog_photo(td_->file_manager_.get(), DialogId(chat_id), chat_full->photo, c->photo)) {
|
||||
chat_full->photo = Photo();
|
||||
if (c->photo.small_file_id.is_valid()) {
|
||||
reload_chat_full(chat_id, Auto());
|
||||
}
|
||||
}
|
||||
|
||||
td_->group_call_manager_->on_update_dialog_about(DialogId(chat_id), chat_full->description, false);
|
||||
auto photo = std::move(chat_full->photo);
|
||||
chat_full->photo = Photo();
|
||||
on_update_chat_full_photo(chat_full, chat_id, std::move(photo));
|
||||
|
||||
on_update_chat_full_photo(chat_full, chat_id, std::move(chat_full->photo));
|
||||
td_->group_call_manager_->on_update_dialog_about(DialogId(chat_id), chat_full->description, false);
|
||||
|
||||
chat_full->is_update_chat_full_sent = true;
|
||||
update_chat_full(chat_full, chat_id, "on_load_chat_full_from_database", true);
|
||||
@ -9919,15 +9938,14 @@ void ContactsManager::on_load_channel_full_from_database(ChannelId channel_id, s
|
||||
}
|
||||
}
|
||||
|
||||
if (td_->file_manager_->get_file_view(c->photo.small_file_id).get_unique_file_id() !=
|
||||
td_->file_manager_->get_file_view(as_fake_dialog_photo(channel_full->photo, DialogId(channel_id)).small_file_id)
|
||||
.get_unique_file_id()) {
|
||||
if (!is_same_dialog_photo(td_->file_manager_.get(), DialogId(channel_id), channel_full->photo, c->photo)) {
|
||||
channel_full->photo = Photo();
|
||||
if (c->photo.small_file_id.is_valid()) {
|
||||
channel_full->expires_at = 0.0;
|
||||
}
|
||||
}
|
||||
auto photo = std::move(channel_full->photo);
|
||||
channel_full->photo = Photo();
|
||||
on_update_channel_full_photo(channel_full, channel_id, std::move(photo));
|
||||
|
||||
if (channel_full->participant_count < channel_full->administrator_count) {
|
||||
@ -10113,10 +10131,20 @@ void ContactsManager::update_user(User *u, UserId user_id, bool from_binlog, boo
|
||||
|
||||
void ContactsManager::update_chat(Chat *c, ChatId chat_id, bool from_binlog, bool from_database) {
|
||||
CHECK(c != nullptr);
|
||||
bool need_update_chat_full = false;
|
||||
if (c->is_photo_changed) {
|
||||
td_->messages_manager_->on_dialog_photo_updated(DialogId(chat_id));
|
||||
drop_chat_photos(chat_id, !c->photo.small_file_id.is_valid(), true, "update_chat");
|
||||
c->is_photo_changed = false;
|
||||
|
||||
auto chat_full = get_chat_full(chat_id); // must not load ChatFull
|
||||
if (chat_full != nullptr &&
|
||||
!is_same_dialog_photo(td_->file_manager_.get(), DialogId(chat_id), chat_full->photo, c->photo)) {
|
||||
on_update_chat_full_photo(chat_full, chat_id, Photo());
|
||||
need_update_chat_full = true;
|
||||
if (c->photo.small_file_id.is_valid()) {
|
||||
reload_chat_full(chat_id, Auto());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (c->is_title_changed) {
|
||||
td_->messages_manager_->on_dialog_title_updated(DialogId(chat_id));
|
||||
@ -10168,14 +10196,34 @@ void ContactsManager::update_chat(Chat *c, ChatId chat_id, bool from_binlog, boo
|
||||
LOG(INFO) << "Repairing cache of " << chat_id;
|
||||
reload_chat(chat_id, Promise<Unit>());
|
||||
}
|
||||
|
||||
if (need_update_chat_full) {
|
||||
auto chat_full = get_chat_full(chat_id);
|
||||
CHECK(chat_full != nullptr);
|
||||
update_chat_full(chat_full, chat_id, "drop_chat_photos");
|
||||
}
|
||||
}
|
||||
|
||||
void ContactsManager::update_channel(Channel *c, ChannelId channel_id, bool from_binlog, bool from_database) {
|
||||
CHECK(c != nullptr);
|
||||
bool need_update_channel_full = false;
|
||||
if (c->is_photo_changed) {
|
||||
td_->messages_manager_->on_dialog_photo_updated(DialogId(channel_id));
|
||||
drop_channel_photos(channel_id, !c->photo.small_file_id.is_valid(), true, "update_channel");
|
||||
c->is_photo_changed = false;
|
||||
|
||||
auto channel_full = get_channel_full(channel_id, true, "update_channel");
|
||||
if (channel_full != nullptr &&
|
||||
!is_same_dialog_photo(td_->file_manager_.get(), DialogId(channel_id), channel_full->photo, c->photo)) {
|
||||
on_update_channel_full_photo(channel_full, channel_id, Photo());
|
||||
need_update_channel_full = true;
|
||||
if (c->photo.small_file_id.is_valid()) {
|
||||
if (channel_full->expires_at > 0.0) {
|
||||
channel_full->expires_at = 0.0;
|
||||
channel_full->need_save_to_database = true;
|
||||
}
|
||||
send_get_channel_full_query(channel_full, channel_id, Auto(), "update_channel");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (c->is_title_changed) {
|
||||
td_->messages_manager_->on_dialog_title_updated(DialogId(channel_id));
|
||||
@ -10283,6 +10331,12 @@ void ContactsManager::update_channel(Channel *c, ChannelId channel_id, bool from
|
||||
LOG(INFO) << "Repairing cache of " << channel_id;
|
||||
reload_channel(channel_id, Promise<Unit>());
|
||||
}
|
||||
|
||||
if (need_update_channel_full) {
|
||||
auto channel_full = get_channel_full(channel_id, true, "update_channel");
|
||||
CHECK(channel_full != nullptr);
|
||||
update_channel_full(channel_full, channel_id, "update_channel");
|
||||
}
|
||||
}
|
||||
|
||||
void ContactsManager::update_secret_chat(SecretChat *c, SecretChatId secret_chat_id, bool from_binlog,
|
||||
@ -10494,6 +10548,8 @@ void ContactsManager::on_get_user_full(tl_object_ptr<telegram_api::userFull> &&u
|
||||
return;
|
||||
}
|
||||
|
||||
apply_pending_user_photo(u, user_id);
|
||||
|
||||
td_->messages_manager_->on_update_dialog_notify_settings(DialogId(user_id), std::move(user->notify_settings_),
|
||||
"on_get_user_full");
|
||||
|
||||
@ -10753,16 +10809,17 @@ void ContactsManager::on_get_chat_full(tl_object_ptr<telegram_api::ChatFull> &&c
|
||||
return promise.set_value(Unit());
|
||||
}
|
||||
|
||||
Chat *c = get_chat(chat_id);
|
||||
if (c == nullptr) {
|
||||
LOG(ERROR) << "Can't find " << chat_id;
|
||||
return promise.set_value(Unit());
|
||||
}
|
||||
{
|
||||
MessageId pinned_message_id;
|
||||
if ((chat->flags_ & CHAT_FULL_FLAG_HAS_PINNED_MESSAGE) != 0) {
|
||||
pinned_message_id = MessageId(ServerMessageId(chat->pinned_msg_id_));
|
||||
}
|
||||
Chat *c = get_chat(chat_id);
|
||||
if (c == nullptr) {
|
||||
LOG(ERROR) << "Can't find " << chat_id;
|
||||
return promise.set_value(Unit());
|
||||
} else if (c->version >= c->pinned_message_version) {
|
||||
if (c->version >= c->pinned_message_version) {
|
||||
LOG(INFO) << "Receive pinned " << pinned_message_id << " in " << chat_id << " with version " << c->version
|
||||
<< ". Current version is " << c->pinned_message_version;
|
||||
td_->messages_manager_->on_update_dialog_last_pinned_message_id(DialogId(chat_id), pinned_message_id);
|
||||
@ -10809,8 +10866,10 @@ void ContactsManager::on_get_chat_full(tl_object_ptr<telegram_api::ChatFull> &&c
|
||||
|
||||
ChatFull *chat_full = add_chat_full(chat_id);
|
||||
on_update_chat_full_invite_link(chat_full, std::move(chat->exported_invite_));
|
||||
on_update_chat_full_photo(chat_full, chat_id,
|
||||
get_photo(td_->file_manager_.get(), std::move(chat->chat_photo_), DialogId(chat_id)));
|
||||
auto photo = get_photo(td_->file_manager_.get(), std::move(chat->chat_photo_), DialogId(chat_id));
|
||||
// on_update_chat_photo should be a no-op if server sent consistent data
|
||||
on_update_chat_photo(c, as_dialog_photo(td_->file_manager_.get(), DialogId(chat_id), 0, photo));
|
||||
on_update_chat_full_photo(chat_full, chat_id, std::move(photo));
|
||||
if (chat_full->description != chat->about_) {
|
||||
chat_full->description = std::move(chat->about_);
|
||||
chat_full->is_changed = true;
|
||||
@ -10840,6 +10899,7 @@ void ContactsManager::on_get_chat_full(tl_object_ptr<telegram_api::ChatFull> &&c
|
||||
}
|
||||
|
||||
chat_full->is_update_chat_full_sent = true;
|
||||
update_chat(c, chat_id);
|
||||
update_chat_full(chat_full, chat_id, "on_get_chat_full");
|
||||
} else {
|
||||
CHECK(chat_full_ptr->get_id() == telegram_api::channelFull::ID);
|
||||
@ -10975,9 +11035,10 @@ void ContactsManager::on_get_chat_full(tl_object_ptr<telegram_api::ChatFull> &&c
|
||||
channel_full->need_save_to_database = true;
|
||||
}
|
||||
|
||||
on_update_channel_full_photo(
|
||||
channel_full, channel_id,
|
||||
get_photo(td_->file_manager_.get(), std::move(channel->chat_photo_), DialogId(channel_id)));
|
||||
auto photo = get_photo(td_->file_manager_.get(), std::move(channel->chat_photo_), DialogId(channel_id));
|
||||
// on_update_channel_photo should be a no-op if server sent consistent data
|
||||
on_update_channel_photo(c, as_dialog_photo(td_->file_manager_.get(), DialogId(channel_id), c->access_hash, photo));
|
||||
on_update_channel_full_photo(channel_full, channel_id, std::move(photo));
|
||||
|
||||
td_->messages_manager_->on_read_channel_outbox(channel_id,
|
||||
MessageId(ServerMessageId(channel->read_outbox_max_id_)));
|
||||
@ -11108,6 +11169,7 @@ void ContactsManager::on_get_chat_full(tl_object_ptr<telegram_api::ChatFull> &&c
|
||||
}
|
||||
|
||||
channel_full->is_update_channel_full_sent = true;
|
||||
update_channel(c, channel_id);
|
||||
update_channel_full(channel_full, channel_id, "on_get_channel_full");
|
||||
|
||||
if (linked_channel_id.is_valid()) {
|
||||
@ -11296,7 +11358,7 @@ void ContactsManager::do_update_user_photo(User *u, UserId user_id,
|
||||
void ContactsManager::do_update_user_photo(User *u, UserId user_id, ProfilePhoto &&new_photo,
|
||||
bool invalidate_photo_cache, const char *source) {
|
||||
u->is_photo_inited = true;
|
||||
if (new_photo != u->photo) {
|
||||
if (need_update_profile_photo(u->photo, new_photo)) {
|
||||
LOG_IF(ERROR, u->access_hash == -1 && new_photo.small_file_id.is_valid())
|
||||
<< "Update profile photo of " << user_id << " without access hash from " << source;
|
||||
u->photo = new_photo;
|
||||
@ -12579,26 +12641,6 @@ void ContactsManager::speculative_add_channel_user(ChannelId channel_id, UserId
|
||||
update_channel_full(channel_full, channel_id, "speculative_add_channel_user");
|
||||
}
|
||||
|
||||
void ContactsManager::drop_channel_photos(ChannelId channel_id, bool is_empty, bool drop_channel_full_photo,
|
||||
const char *source) {
|
||||
if (drop_channel_full_photo) {
|
||||
auto channel_full = get_channel_full(channel_id, true, "drop_channel_photos"); // must not load ChannelFull
|
||||
if (channel_full == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
on_update_channel_full_photo(channel_full, channel_id, Photo());
|
||||
if (!is_empty) {
|
||||
if (channel_full->expires_at > 0.0) {
|
||||
channel_full->expires_at = 0.0;
|
||||
channel_full->need_save_to_database = true;
|
||||
}
|
||||
send_get_channel_full_query(channel_full, channel_id, Auto(), "drop_channel_photos");
|
||||
}
|
||||
update_channel_full(channel_full, channel_id, "drop_channel_photos");
|
||||
}
|
||||
}
|
||||
|
||||
void ContactsManager::invalidate_channel_full(ChannelId channel_id, bool need_drop_slow_mode_delay) {
|
||||
LOG(INFO) << "Invalidate supergroup full for " << channel_id;
|
||||
auto channel_full = get_channel_full(channel_id, true, "invalidate_channel_full"); // must not load ChannelFull
|
||||
@ -12632,9 +12674,6 @@ void ContactsManager::on_update_chat_full_photo(ChatFull *chat_full, ChatId chat
|
||||
chat_full->photo = std::move(photo);
|
||||
chat_full->is_changed = true;
|
||||
}
|
||||
if (chat_full->photo.is_empty()) {
|
||||
drop_chat_photos(chat_id, true, false, "on_update_chat_full_photo");
|
||||
}
|
||||
|
||||
auto photo_file_ids = photo_get_file_ids(chat_full->photo);
|
||||
if (chat_full->registered_photo_file_ids == photo_file_ids) {
|
||||
@ -12669,9 +12708,6 @@ void ContactsManager::on_update_channel_full_photo(ChannelFull *channel_full, Ch
|
||||
channel_full->photo = std::move(photo);
|
||||
channel_full->is_changed = true;
|
||||
}
|
||||
if (channel_full->photo.is_empty()) {
|
||||
drop_channel_photos(channel_id, true, false, "on_update_channel_full_photo");
|
||||
}
|
||||
|
||||
auto photo_file_ids = photo_get_file_ids(channel_full->photo);
|
||||
if (channel_full->registered_photo_file_ids == photo_file_ids) {
|
||||
@ -12950,7 +12986,7 @@ void ContactsManager::on_get_dialog_invite_link_info(const string &invite_link,
|
||||
LOG(ERROR) << "Receive invalid " << channel_id;
|
||||
channel_id = ChannelId();
|
||||
}
|
||||
if (!channel_id.is_valid() || accessible_before < 0) {
|
||||
if (accessible_before != 0 && (!channel_id.is_valid() || accessible_before < 0)) {
|
||||
LOG(ERROR) << "Receive expires = " << accessible_before << " for invite link " << invite_link << " to "
|
||||
<< to_string(chat);
|
||||
accessible_before = 0;
|
||||
@ -13449,14 +13485,16 @@ void ContactsManager::on_update_chat_participant_count(Chat *c, ChatId chat_id,
|
||||
|
||||
void ContactsManager::on_update_chat_photo(Chat *c, ChatId chat_id,
|
||||
tl_object_ptr<telegram_api::ChatPhoto> &&chat_photo_ptr) {
|
||||
DialogPhoto new_chat_photo =
|
||||
get_dialog_photo(td_->file_manager_.get(), DialogId(chat_id), 0, std::move(chat_photo_ptr));
|
||||
if (td_->auth_manager_->is_bot()) {
|
||||
new_chat_photo.minithumbnail.clear();
|
||||
on_update_chat_photo(c, get_dialog_photo(td_->file_manager_.get(), DialogId(chat_id), 0, std::move(chat_photo_ptr)));
|
||||
}
|
||||
|
||||
if (new_chat_photo != c->photo) {
|
||||
c->photo = new_chat_photo;
|
||||
void ContactsManager::on_update_chat_photo(Chat *c, DialogPhoto &&photo) {
|
||||
if (td_->auth_manager_->is_bot()) {
|
||||
photo.minithumbnail.clear();
|
||||
}
|
||||
|
||||
if (need_update_dialog_photo(c->photo, photo)) {
|
||||
c->photo = std::move(photo);
|
||||
c->is_photo_changed = true;
|
||||
c->need_save_to_database = true;
|
||||
}
|
||||
@ -13555,25 +13593,9 @@ void ContactsManager::on_update_chat_full_participants(ChatFull *chat_full, Chat
|
||||
update_chat_online_member_count(chat_full, chat_id, true);
|
||||
}
|
||||
|
||||
void ContactsManager::drop_chat_photos(ChatId chat_id, bool is_empty, bool drop_chat_full_photo, const char *source) {
|
||||
if (drop_chat_full_photo) {
|
||||
auto chat_full = get_chat_full(chat_id); // must not load ChatFull
|
||||
if (chat_full == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
on_update_chat_full_photo(chat_full, chat_id, Photo());
|
||||
if (!is_empty) {
|
||||
reload_chat_full(chat_id, Auto());
|
||||
}
|
||||
update_chat_full(chat_full, chat_id, "drop_chat_photos");
|
||||
}
|
||||
}
|
||||
|
||||
void ContactsManager::drop_chat_full(ChatId chat_id) {
|
||||
ChatFull *chat_full = get_chat_full_force(chat_id, "drop_chat_full");
|
||||
if (chat_full == nullptr) {
|
||||
drop_chat_photos(chat_id, false, false, "drop_chat_full");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -13591,14 +13613,17 @@ void ContactsManager::drop_chat_full(ChatId chat_id) {
|
||||
|
||||
void ContactsManager::on_update_channel_photo(Channel *c, ChannelId channel_id,
|
||||
tl_object_ptr<telegram_api::ChatPhoto> &&chat_photo_ptr) {
|
||||
DialogPhoto new_chat_photo =
|
||||
get_dialog_photo(td_->file_manager_.get(), DialogId(channel_id), c->access_hash, std::move(chat_photo_ptr));
|
||||
if (td_->auth_manager_->is_bot()) {
|
||||
new_chat_photo.minithumbnail.clear();
|
||||
on_update_channel_photo(
|
||||
c, get_dialog_photo(td_->file_manager_.get(), DialogId(channel_id), c->access_hash, std::move(chat_photo_ptr)));
|
||||
}
|
||||
|
||||
if (new_chat_photo != c->photo) {
|
||||
c->photo = new_chat_photo;
|
||||
void ContactsManager::on_update_channel_photo(Channel *c, DialogPhoto &&photo) {
|
||||
if (td_->auth_manager_->is_bot()) {
|
||||
photo.minithumbnail.clear();
|
||||
}
|
||||
|
||||
if (need_update_dialog_photo(c->photo, photo)) {
|
||||
c->photo = std::move(photo);
|
||||
c->is_photo_changed = true;
|
||||
c->need_save_to_database = true;
|
||||
}
|
||||
@ -14358,7 +14383,7 @@ std::pair<int32, vector<const Photo *>> ContactsManager::get_user_profile_photos
|
||||
return result;
|
||||
}
|
||||
|
||||
get_user_dialog_photo(user_id); // apply pending user photo
|
||||
apply_pending_user_photo(get_user(user_id), user_id);
|
||||
|
||||
auto user_photos = &user_photos_[user_id];
|
||||
if (user_photos->getting_now) {
|
||||
|
@ -80,6 +80,7 @@ class ContactsManager final : public Actor {
|
||||
static UserId get_user_id(const tl_object_ptr<telegram_api::User> &user);
|
||||
static ChatId get_chat_id(const tl_object_ptr<telegram_api::Chat> &chat);
|
||||
static ChannelId get_channel_id(const tl_object_ptr<telegram_api::Chat> &chat);
|
||||
static DialogId get_dialog_id(const tl_object_ptr<telegram_api::Chat> &chat);
|
||||
|
||||
Result<tl_object_ptr<telegram_api::InputUser>> get_input_user(UserId user_id) const;
|
||||
|
||||
@ -1229,6 +1230,7 @@ class ContactsManager final : public Actor {
|
||||
const char *source);
|
||||
void do_update_user_photo(User *u, UserId user_id, ProfilePhoto &&new_photo, bool invalidate_photo_cache,
|
||||
const char *source);
|
||||
void apply_pending_user_photo(User *u, UserId user_id);
|
||||
|
||||
void upload_profile_photo(FileId file_id, bool is_animation, double main_frame_timestamp, Promise<Unit> &&promise,
|
||||
int reupload_count = 0, vector<int> bad_parts = {});
|
||||
@ -1258,6 +1260,7 @@ class ContactsManager final : public Actor {
|
||||
void on_update_chat_participant_count(Chat *c, ChatId chat_id, int32 participant_count, int32 version,
|
||||
const string &debug_str);
|
||||
void on_update_chat_photo(Chat *c, ChatId chat_id, tl_object_ptr<telegram_api::ChatPhoto> &&chat_photo_ptr);
|
||||
void on_update_chat_photo(Chat *c, DialogPhoto &&photo);
|
||||
static void on_update_chat_title(Chat *c, ChatId chat_id, string &&title);
|
||||
static void on_update_chat_active(Chat *c, ChatId chat_id, bool is_active);
|
||||
static void on_update_chat_migrated_to_channel_id(Chat *c, ChatId chat_id, ChannelId migrated_to_channel_id);
|
||||
@ -1272,6 +1275,7 @@ class ContactsManager final : public Actor {
|
||||
|
||||
void on_update_channel_photo(Channel *c, ChannelId channel_id,
|
||||
tl_object_ptr<telegram_api::ChatPhoto> &&chat_photo_ptr);
|
||||
void on_update_channel_photo(Channel *c, DialogPhoto &&photo);
|
||||
static void on_update_channel_title(Channel *c, ChannelId channel_id, string &&title);
|
||||
void on_update_channel_username(Channel *c, ChannelId channel_id, string &&username);
|
||||
void on_update_channel_status(Channel *c, ChannelId channel_id, DialogParticipantStatus &&status);
|
||||
@ -1310,11 +1314,8 @@ class ContactsManager final : public Actor {
|
||||
void speculative_add_channel_user(ChannelId channel_id, UserId user_id, const DialogParticipantStatus &new_status,
|
||||
const DialogParticipantStatus &old_status);
|
||||
|
||||
void drop_chat_photos(ChatId chat_id, bool is_empty, bool drop_chat_full_photo, const char *source);
|
||||
void drop_chat_full(ChatId chat_id);
|
||||
|
||||
void drop_channel_photos(ChannelId channel_id, bool is_empty, bool drop_channel_full_photo, const char *source);
|
||||
|
||||
void do_invalidate_channel_full(ChannelFull *channel_full, ChannelId channel_id, bool need_drop_slow_mode_delay);
|
||||
|
||||
void update_user_online_member_count(User *u);
|
||||
|
@ -50,9 +50,9 @@ void DialogFilter::store(StorerT &storer) const {
|
||||
template <class ParserT>
|
||||
void DialogFilter::parse(ParserT &parser) {
|
||||
using td::parse;
|
||||
bool has_pinned_dialog_ids = !pinned_dialog_ids.empty();
|
||||
bool has_included_dialog_ids = !included_dialog_ids.empty();
|
||||
bool has_excluded_dialog_ids = !excluded_dialog_ids.empty();
|
||||
bool has_pinned_dialog_ids;
|
||||
bool has_included_dialog_ids;
|
||||
bool has_excluded_dialog_ids;
|
||||
BEGIN_PARSE_FLAGS();
|
||||
PARSE_FLAG(exclude_muted);
|
||||
PARSE_FLAG(exclude_read);
|
||||
|
@ -2435,13 +2435,7 @@ tl_object_ptr<telegram_api::InputMedia> get_fake_input_media(Td *td, tl_object_p
|
||||
FileId file_id) {
|
||||
FileView file_view = td->file_manager_->get_file_view(file_id);
|
||||
auto file_type = file_view.get_type();
|
||||
switch (file_type) {
|
||||
case FileType::Animation:
|
||||
case FileType::Audio:
|
||||
case FileType::Document:
|
||||
case FileType::Sticker:
|
||||
case FileType::Video:
|
||||
case FileType::VoiceNote: {
|
||||
if (is_document_file_type(file_type)) {
|
||||
vector<tl_object_ptr<telegram_api::DocumentAttribute>> attributes;
|
||||
auto file_path = file_view.suggested_path();
|
||||
const PathView path_view(file_path);
|
||||
@ -2454,17 +2448,17 @@ tl_object_ptr<telegram_api::InputMedia> get_fake_input_media(Td *td, tl_object_p
|
||||
if (file_type == FileType::Video) {
|
||||
flags |= telegram_api::inputMediaUploadedDocument::NOSOUND_VIDEO_MASK;
|
||||
}
|
||||
if (file_type == FileType::DocumentAsFile) {
|
||||
flags |= telegram_api::inputMediaUploadedDocument::FORCE_FILE_MASK;
|
||||
}
|
||||
return make_tl_object<telegram_api::inputMediaUploadedDocument>(
|
||||
flags, false /*ignored*/, false /*ignored*/, std::move(input_file), nullptr, mime_type, std::move(attributes),
|
||||
vector<tl_object_ptr<telegram_api::InputDocument>>(), 0);
|
||||
}
|
||||
case FileType::Photo:
|
||||
} else {
|
||||
CHECK(file_type == FileType::Photo);
|
||||
return make_tl_object<telegram_api::inputMediaUploadedPhoto>(
|
||||
0, std::move(input_file), vector<tl_object_ptr<telegram_api::InputDocument>>(), 0);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void delete_message_content_thumbnail(MessageContent *content, Td *td) {
|
||||
@ -5769,10 +5763,6 @@ bool is_unsent_animated_emoji_click(Td *td, DialogId dialog_id, const DialogActi
|
||||
return !td->stickers_manager_->is_sent_animated_emoji_click(dialog_id, remove_emoji_modifiers(emoji));
|
||||
}
|
||||
|
||||
bool is_active_reaction(Td *td, const string &reaction) {
|
||||
return td->stickers_manager_->is_active_reaction(reaction);
|
||||
}
|
||||
|
||||
void init_stickers_manager(Td *td) {
|
||||
td->stickers_manager_->init();
|
||||
}
|
||||
|
@ -248,8 +248,6 @@ void on_sent_message_content(Td *td, const MessageContent *content);
|
||||
|
||||
bool is_unsent_animated_emoji_click(Td *td, DialogId dialog_id, const DialogAction &action);
|
||||
|
||||
bool is_active_reaction(Td *td, const string &reaction);
|
||||
|
||||
void init_stickers_manager(Td *td);
|
||||
|
||||
void on_dialog_used(TopDialogCategory category, DialogId dialog_id, int32 date);
|
||||
|
@ -217,6 +217,17 @@ class GetMessageReactionsListQuery final : public Td::ResultHandler {
|
||||
}
|
||||
};
|
||||
|
||||
void MessageReaction::add_recent_chooser_dialog_id(DialogId dialog_id) {
|
||||
recent_chooser_dialog_ids_.insert(recent_chooser_dialog_ids_.begin(), dialog_id);
|
||||
if (recent_chooser_dialog_ids_.size() > MAX_RECENT_CHOOSERS) {
|
||||
recent_chooser_dialog_ids_.resize(MAX_RECENT_CHOOSERS);
|
||||
}
|
||||
}
|
||||
|
||||
bool MessageReaction::remove_recent_chooser_dialog_id(DialogId dialog_id) {
|
||||
return td::remove(recent_chooser_dialog_ids_, dialog_id);
|
||||
}
|
||||
|
||||
void MessageReaction::set_is_chosen(bool is_chosen, DialogId chooser_dialog_id, bool can_get_added_reactions) {
|
||||
if (is_chosen_ == is_chosen) {
|
||||
return;
|
||||
@ -227,12 +238,9 @@ void MessageReaction::set_is_chosen(bool is_chosen, DialogId chooser_dialog_id,
|
||||
if (chooser_dialog_id.is_valid()) {
|
||||
choose_count_ += is_chosen_ ? 1 : -1;
|
||||
if (can_get_added_reactions) {
|
||||
td::remove(recent_chooser_dialog_ids_, chooser_dialog_id);
|
||||
remove_recent_chooser_dialog_id(chooser_dialog_id);
|
||||
if (is_chosen_) {
|
||||
recent_chooser_dialog_ids_.insert(recent_chooser_dialog_ids_.begin(), chooser_dialog_id);
|
||||
if (recent_chooser_dialog_ids_.size() > MAX_RECENT_CHOOSERS) {
|
||||
recent_chooser_dialog_ids_.resize(MAX_RECENT_CHOOSERS);
|
||||
}
|
||||
add_recent_chooser_dialog_id(chooser_dialog_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -410,6 +418,24 @@ void MessageReactions::sort_reactions(const FlatHashMap<string, size_t> &active_
|
||||
});
|
||||
}
|
||||
|
||||
void MessageReactions::fix_chosen_reaction(DialogId my_dialog_id) {
|
||||
bool need_fix = false;
|
||||
for (auto &reaction : reactions_) {
|
||||
if (!reaction.is_chosen() && reaction.remove_recent_chooser_dialog_id(my_dialog_id)) {
|
||||
LOG(WARNING) << "Fix recent chosen reaction in " << *this;
|
||||
need_fix = true;
|
||||
}
|
||||
}
|
||||
if (!need_fix) {
|
||||
return;
|
||||
}
|
||||
for (auto &reaction : reactions_) {
|
||||
if (reaction.is_chosen() && !td::contains(reaction.get_recent_chooser_dialog_ids(), my_dialog_id)) {
|
||||
reaction.add_recent_chooser_dialog_id(my_dialog_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool MessageReactions::need_update_message_reactions(const MessageReactions *old_reactions,
|
||||
const MessageReactions *new_reactions) {
|
||||
if (old_reactions == nullptr) {
|
||||
|
@ -78,6 +78,10 @@ class MessageReaction {
|
||||
return recent_chooser_min_channels_;
|
||||
}
|
||||
|
||||
void add_recent_chooser_dialog_id(DialogId dialog_id);
|
||||
|
||||
bool remove_recent_chooser_dialog_id(DialogId dialog_id);
|
||||
|
||||
td_api::object_ptr<td_api::messageReaction> get_message_reaction_object(Td *td) const;
|
||||
|
||||
template <class StorerT>
|
||||
@ -149,6 +153,8 @@ struct MessageReactions {
|
||||
|
||||
void sort_reactions(const FlatHashMap<string, size_t> &active_reaction_pos);
|
||||
|
||||
void fix_chosen_reaction(DialogId my_dialog_id);
|
||||
|
||||
static bool need_update_message_reactions(const MessageReactions *old_reactions,
|
||||
const MessageReactions *new_reactions);
|
||||
|
||||
|
@ -6455,7 +6455,7 @@ void MessagesManager::skip_old_pending_pts_update(tl_object_ptr<telegram_api::Up
|
||||
if (update->get_id() == telegram_api::updateNewMessage::ID) {
|
||||
auto update_new_message = static_cast<telegram_api::updateNewMessage *>(update.get());
|
||||
auto full_message_id = get_full_message_id(update_new_message->message_, false);
|
||||
if (update_message_ids_.find(full_message_id) != update_message_ids_.end()) {
|
||||
if (update_message_ids_.count(full_message_id) > 0) {
|
||||
if (new_pts == old_pts) { // otherwise message can be already deleted
|
||||
// apply sent message anyway
|
||||
on_get_message(std::move(update_new_message->message_), true, false, false, true, true,
|
||||
@ -6716,41 +6716,28 @@ void MessagesManager::on_update_message_reactions(FullMessageId full_message_id,
|
||||
Promise<Unit> &&promise) {
|
||||
TRY_STATUS_PROMISE(promise, G()->close_status());
|
||||
|
||||
auto new_reactions = MessageReactions::get_message_reactions(td_, std::move(reactions), td_->auth_manager_->is_bot());
|
||||
if (!have_message_force(full_message_id, "on_update_message_reactions")) {
|
||||
auto dialog_id = full_message_id.get_dialog_id();
|
||||
if (!have_input_peer(dialog_id, AccessRights::Read)) {
|
||||
LOG(INFO) << "Ignore updateMessageReaction in inaccessible " << full_message_id;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (dialog_id.get_type()) {
|
||||
case DialogType::User:
|
||||
case DialogType::Chat: {
|
||||
const Dialog *d = get_dialog(dialog_id);
|
||||
if (d == nullptr) {
|
||||
LOG(INFO) << "Ignore updateMessageReaction in unknown " << dialog_id;
|
||||
return;
|
||||
}
|
||||
if (d->last_new_message_id != MessageId() && full_message_id.get_message_id() > d->last_new_message_id) {
|
||||
LOG(INFO) << "Ignore updateMessageReaction about too new " << full_message_id << ", last known is "
|
||||
<< d->last_new_message_id;
|
||||
|
||||
// there is no message, so the update can be ignored
|
||||
if ((new_reactions != nullptr && !new_reactions->unread_reactions_.empty()) || d->unread_reaction_count > 0) {
|
||||
// but if there are unread reactions or the chat has unread reactions,
|
||||
// then number of unread reactions could have been changed, so reload the number of unread reactions
|
||||
send_get_dialog_query(dialog_id, std::move(promise), 0, "on_update_message_reactions");
|
||||
}
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DialogType::Channel:
|
||||
// the message will be added after get_channel_difference_if_needed
|
||||
break;
|
||||
case DialogType::SecretChat:
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
LOG(INFO) << "Need to load " << full_message_id << " to process updateMessageReaction";
|
||||
return get_message_from_server(full_message_id, std::move(promise), "on_update_message_reactions");
|
||||
}
|
||||
|
||||
auto new_reactions = MessageReactions::get_message_reactions(td_, std::move(reactions), td_->auth_manager_->is_bot());
|
||||
update_message_interaction_info(full_message_id, -1, -1, false, nullptr, true, std::move(new_reactions));
|
||||
promise.set_value(Unit());
|
||||
}
|
||||
@ -7063,6 +7050,11 @@ bool MessagesManager::update_message_interaction_info(Dialog *d, Message *m, int
|
||||
reactions->update_from(*m->reactions);
|
||||
}
|
||||
reactions->sort_reactions(active_reaction_pos_);
|
||||
reactions->fix_chosen_reaction(get_my_dialog_id());
|
||||
if (d->default_send_message_as_dialog_id.is_valid()) {
|
||||
// the reaction could be set by previous owner of the broadcast
|
||||
// reactions->fix_chosen_reaction(d->default_send_message_as_dialog_id);
|
||||
}
|
||||
}
|
||||
bool need_update_reactions =
|
||||
has_reactions && MessageReactions::need_update_message_reactions(m->reactions.get(), reactions.get());
|
||||
@ -7679,7 +7671,7 @@ void MessagesManager::add_pending_channel_update(DialogId dialog_id, tl_object_p
|
||||
auto update_new_channel_message = static_cast<telegram_api::updateNewChannelMessage *>(update.get());
|
||||
auto message_id = get_message_id(update_new_channel_message->message_, false);
|
||||
FullMessageId full_message_id(dialog_id, message_id);
|
||||
if (update_message_ids_.find(full_message_id) != update_message_ids_.end()) {
|
||||
if (update_message_ids_.count(full_message_id) > 0) {
|
||||
// apply sent channel message
|
||||
on_get_message(std::move(update_new_channel_message->message_), true, true, false, true, true,
|
||||
"updateNewChannelMessage with an awaited message");
|
||||
@ -7755,79 +7747,78 @@ bool MessagesManager::is_old_channel_update(DialogId dialog_id, int32 new_pts) {
|
||||
return new_pts <= (d == nullptr ? load_channel_pts(dialog_id) : d->pts);
|
||||
}
|
||||
|
||||
void MessagesManager::process_pts_update(tl_object_ptr<telegram_api::Update> &&update) {
|
||||
switch (update->get_id()) {
|
||||
void MessagesManager::process_pts_update(tl_object_ptr<telegram_api::Update> &&update_ptr) {
|
||||
switch (update_ptr->get_id()) {
|
||||
case dummyUpdate::ID:
|
||||
LOG(INFO) << "Process dummyUpdate";
|
||||
break;
|
||||
case telegram_api::updateNewMessage::ID: {
|
||||
auto update_new_message = move_tl_object_as<telegram_api::updateNewMessage>(update);
|
||||
auto update = move_tl_object_as<telegram_api::updateNewMessage>(update_ptr);
|
||||
LOG(INFO) << "Process updateNewMessage";
|
||||
on_get_message(std::move(update_new_message->message_), true, false, false, true, true, "updateNewMessage");
|
||||
on_get_message(std::move(update->message_), true, false, false, true, true, "updateNewMessage");
|
||||
break;
|
||||
}
|
||||
case updateSentMessage::ID: {
|
||||
auto update_sent_message = move_tl_object_as<updateSentMessage>(update);
|
||||
LOG(INFO) << "Process updateSentMessage " << update_sent_message->random_id_;
|
||||
on_send_message_success(update_sent_message->random_id_, update_sent_message->message_id_,
|
||||
update_sent_message->date_, update_sent_message->ttl_period_, FileId(),
|
||||
auto update = move_tl_object_as<updateSentMessage>(update_ptr);
|
||||
LOG(INFO) << "Process updateSentMessage " << update->random_id_;
|
||||
on_send_message_success(update->random_id_, update->message_id_, update->date_, update->ttl_period_, FileId(),
|
||||
"process updateSentMessage");
|
||||
break;
|
||||
}
|
||||
case telegram_api::updateReadMessagesContents::ID: {
|
||||
auto read_contents_update = move_tl_object_as<telegram_api::updateReadMessagesContents>(update);
|
||||
auto update = move_tl_object_as<telegram_api::updateReadMessagesContents>(update_ptr);
|
||||
LOG(INFO) << "Process updateReadMessageContents";
|
||||
for (auto &message_id : read_contents_update->messages_) {
|
||||
for (auto &message_id : update->messages_) {
|
||||
read_message_content_from_updates(MessageId(ServerMessageId(message_id)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case telegram_api::updateEditMessage::ID: {
|
||||
auto update_edit_message = move_tl_object_as<telegram_api::updateEditMessage>(update);
|
||||
auto full_message_id = on_get_message(std::move(update_edit_message->message_), false, false, false, false, false,
|
||||
"updateEditMessage");
|
||||
auto update = move_tl_object_as<telegram_api::updateEditMessage>(update_ptr);
|
||||
LOG(INFO) << "Process updateEditMessage";
|
||||
on_message_edited(full_message_id, update_edit_message->pts_);
|
||||
bool had_message = have_message_force(get_full_message_id(update->message_, false), "updateEditMessage");
|
||||
auto full_message_id =
|
||||
on_get_message(std::move(update->message_), false, false, false, false, false, "updateEditMessage");
|
||||
on_message_edited(full_message_id, update->pts_, had_message);
|
||||
break;
|
||||
}
|
||||
case telegram_api::updateDeleteMessages::ID: {
|
||||
auto delete_update = move_tl_object_as<telegram_api::updateDeleteMessages>(update);
|
||||
auto update = move_tl_object_as<telegram_api::updateDeleteMessages>(update_ptr);
|
||||
LOG(INFO) << "Process updateDeleteMessages";
|
||||
vector<MessageId> message_ids;
|
||||
for (auto message : delete_update->messages_) {
|
||||
for (auto message : update->messages_) {
|
||||
message_ids.push_back(MessageId(ServerMessageId(message)));
|
||||
}
|
||||
delete_messages_from_updates(message_ids);
|
||||
break;
|
||||
}
|
||||
case telegram_api::updateReadHistoryInbox::ID: {
|
||||
auto read_update = move_tl_object_as<telegram_api::updateReadHistoryInbox>(update);
|
||||
auto update = move_tl_object_as<telegram_api::updateReadHistoryInbox>(update_ptr);
|
||||
LOG(INFO) << "Process updateReadHistoryInbox";
|
||||
DialogId dialog_id(read_update->peer_);
|
||||
DialogId dialog_id(update->peer_);
|
||||
FolderId folder_id;
|
||||
if ((read_update->flags_ & telegram_api::updateReadHistoryInbox::FOLDER_ID_MASK) != 0) {
|
||||
folder_id = FolderId(read_update->folder_id_);
|
||||
if ((update->flags_ & telegram_api::updateReadHistoryInbox::FOLDER_ID_MASK) != 0) {
|
||||
folder_id = FolderId(update->folder_id_);
|
||||
}
|
||||
on_update_dialog_folder_id(dialog_id, folder_id);
|
||||
read_history_inbox(dialog_id, MessageId(ServerMessageId(read_update->max_id_)),
|
||||
-1 /*read_update->still_unread_count*/, "updateReadHistoryInbox");
|
||||
read_history_inbox(dialog_id, MessageId(ServerMessageId(update->max_id_)), -1 /*update->still_unread_count*/,
|
||||
"updateReadHistoryInbox");
|
||||
break;
|
||||
}
|
||||
case telegram_api::updateReadHistoryOutbox::ID: {
|
||||
auto read_update = move_tl_object_as<telegram_api::updateReadHistoryOutbox>(update);
|
||||
auto update = move_tl_object_as<telegram_api::updateReadHistoryOutbox>(update_ptr);
|
||||
LOG(INFO) << "Process updateReadHistoryOutbox";
|
||||
read_history_outbox(DialogId(read_update->peer_), MessageId(ServerMessageId(read_update->max_id_)));
|
||||
read_history_outbox(DialogId(update->peer_), MessageId(ServerMessageId(update->max_id_)));
|
||||
break;
|
||||
}
|
||||
case telegram_api::updatePinnedMessages::ID: {
|
||||
auto pinned_messages_update = move_tl_object_as<telegram_api::updatePinnedMessages>(update);
|
||||
auto update = move_tl_object_as<telegram_api::updatePinnedMessages>(update_ptr);
|
||||
LOG(INFO) << "Process updatePinnedMessages";
|
||||
vector<MessageId> message_ids;
|
||||
for (auto message : pinned_messages_update->messages_) {
|
||||
for (auto message : update->messages_) {
|
||||
message_ids.push_back(MessageId(ServerMessageId(message)));
|
||||
}
|
||||
update_dialog_pinned_messages_from_updates(DialogId(pinned_messages_update->peer_), message_ids,
|
||||
pinned_messages_update->pinned_);
|
||||
update_dialog_pinned_messages_from_updates(DialogId(update->peer_), message_ids, update->pinned_);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -7836,37 +7827,35 @@ void MessagesManager::process_pts_update(tl_object_ptr<telegram_api::Update> &&u
|
||||
CHECK(!td_->updates_manager_->running_get_difference());
|
||||
}
|
||||
|
||||
void MessagesManager::process_channel_update(tl_object_ptr<telegram_api::Update> &&update) {
|
||||
switch (update->get_id()) {
|
||||
void MessagesManager::process_channel_update(tl_object_ptr<telegram_api::Update> &&update_ptr) {
|
||||
switch (update_ptr->get_id()) {
|
||||
case dummyUpdate::ID:
|
||||
LOG(INFO) << "Process dummyUpdate";
|
||||
break;
|
||||
case updateSentMessage::ID: {
|
||||
auto update_sent_message = move_tl_object_as<updateSentMessage>(update);
|
||||
LOG(INFO) << "Process updateSentMessage " << update_sent_message->random_id_;
|
||||
on_send_message_success(update_sent_message->random_id_, update_sent_message->message_id_,
|
||||
update_sent_message->date_, update_sent_message->ttl_period_, FileId(),
|
||||
auto update = move_tl_object_as<updateSentMessage>(update_ptr);
|
||||
LOG(INFO) << "Process updateSentMessage " << update->random_id_;
|
||||
on_send_message_success(update->random_id_, update->message_id_, update->date_, update->ttl_period_, FileId(),
|
||||
"process updateSentChannelMessage");
|
||||
break;
|
||||
}
|
||||
case telegram_api::updateNewChannelMessage::ID: {
|
||||
auto update_new_channel_message = move_tl_object_as<telegram_api::updateNewChannelMessage>(update);
|
||||
auto update = move_tl_object_as<telegram_api::updateNewChannelMessage>(update_ptr);
|
||||
LOG(INFO) << "Process updateNewChannelMessage";
|
||||
on_get_message(std::move(update_new_channel_message->message_), true, true, false, true, true,
|
||||
"updateNewChannelMessage");
|
||||
on_get_message(std::move(update->message_), true, true, false, true, true, "updateNewChannelMessage");
|
||||
break;
|
||||
}
|
||||
case telegram_api::updateDeleteChannelMessages::ID: {
|
||||
auto delete_channel_messages_update = move_tl_object_as<telegram_api::updateDeleteChannelMessages>(update);
|
||||
auto update = move_tl_object_as<telegram_api::updateDeleteChannelMessages>(update_ptr);
|
||||
LOG(INFO) << "Process updateDeleteChannelMessages";
|
||||
ChannelId channel_id(delete_channel_messages_update->channel_id_);
|
||||
ChannelId channel_id(update->channel_id_);
|
||||
if (!channel_id.is_valid()) {
|
||||
LOG(ERROR) << "Receive invalid " << channel_id;
|
||||
break;
|
||||
}
|
||||
|
||||
vector<MessageId> message_ids;
|
||||
for (auto &message : delete_channel_messages_update->messages_) {
|
||||
for (auto &message : update->messages_) {
|
||||
message_ids.push_back(MessageId(ServerMessageId(message)));
|
||||
}
|
||||
|
||||
@ -7875,29 +7864,29 @@ void MessagesManager::process_channel_update(tl_object_ptr<telegram_api::Update>
|
||||
break;
|
||||
}
|
||||
case telegram_api::updateEditChannelMessage::ID: {
|
||||
auto update_edit_channel_message = move_tl_object_as<telegram_api::updateEditChannelMessage>(update);
|
||||
auto update = move_tl_object_as<telegram_api::updateEditChannelMessage>(update_ptr);
|
||||
LOG(INFO) << "Process updateEditChannelMessage";
|
||||
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_);
|
||||
bool had_message = have_message_force(get_full_message_id(update->message_, false), "updateEditChannelMessage");
|
||||
auto full_message_id =
|
||||
on_get_message(std::move(update->message_), false, true, false, false, false, "updateEditChannelMessage");
|
||||
on_message_edited(full_message_id, update->pts_, had_message);
|
||||
break;
|
||||
}
|
||||
case telegram_api::updatePinnedChannelMessages::ID: {
|
||||
auto pinned_channel_messages_update = move_tl_object_as<telegram_api::updatePinnedChannelMessages>(update);
|
||||
auto update = move_tl_object_as<telegram_api::updatePinnedChannelMessages>(update_ptr);
|
||||
LOG(INFO) << "Process updatePinnedChannelMessages";
|
||||
ChannelId channel_id(pinned_channel_messages_update->channel_id_);
|
||||
ChannelId channel_id(update->channel_id_);
|
||||
if (!channel_id.is_valid()) {
|
||||
LOG(ERROR) << "Receive invalid " << channel_id;
|
||||
break;
|
||||
}
|
||||
|
||||
vector<MessageId> message_ids;
|
||||
for (auto &message : pinned_channel_messages_update->messages_) {
|
||||
for (auto &message : update->messages_) {
|
||||
message_ids.push_back(MessageId(ServerMessageId(message)));
|
||||
}
|
||||
|
||||
update_dialog_pinned_messages_from_updates(DialogId(channel_id), message_ids,
|
||||
pinned_channel_messages_update->pinned_);
|
||||
update_dialog_pinned_messages_from_updates(DialogId(channel_id), message_ids, update->pinned_);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -7905,7 +7894,7 @@ void MessagesManager::process_channel_update(tl_object_ptr<telegram_api::Update>
|
||||
}
|
||||
}
|
||||
|
||||
void MessagesManager::on_message_edited(FullMessageId full_message_id, int32 pts) {
|
||||
void MessagesManager::on_message_edited(FullMessageId full_message_id, int32 pts, bool had_message) {
|
||||
if (full_message_id == FullMessageId()) {
|
||||
return;
|
||||
}
|
||||
@ -7920,6 +7909,13 @@ void MessagesManager::on_message_edited(FullMessageId full_message_id, int32 pts
|
||||
send_update_message_edited(dialog_id, m);
|
||||
}
|
||||
update_used_hashtags(dialog_id, m);
|
||||
|
||||
if (!had_message &&
|
||||
((m->reactions != nullptr && !m->reactions->unread_reactions_.empty()) || d->unread_reaction_count > 0)) {
|
||||
// if new message with unread reactions was added or the chat has unread reactions,
|
||||
// then number of unread reactions could have been changed, so reload the number of unread reactions
|
||||
send_get_dialog_query(dialog_id, Promise<Unit>(), 0, "on_message_edited");
|
||||
}
|
||||
}
|
||||
|
||||
bool MessagesManager::update_dialog_notification_settings(DialogId dialog_id,
|
||||
@ -10214,7 +10210,7 @@ void MessagesManager::on_get_dialog_messages_search_result(
|
||||
if (filter == MessageSearchFilter::UnreadReaction) {
|
||||
d->unread_reaction_count = old_message_count;
|
||||
// update_dialog_mention_notification_count(d);
|
||||
send_update_chat_unread_reaction_count(d);
|
||||
send_update_chat_unread_reaction_count(d, "on_get_dialog_messages_search_result");
|
||||
}
|
||||
update_dialog = true;
|
||||
}
|
||||
@ -11084,6 +11080,52 @@ void MessagesManager::on_failed_scheduled_message_deletion(DialogId dialog_id, c
|
||||
load_dialog_scheduled_messages(dialog_id, false, 0, Promise<Unit>());
|
||||
}
|
||||
|
||||
MessagesManager::CanDeleteDialog MessagesManager::can_delete_dialog(const Dialog *d) const {
|
||||
auto chat_source = sponsored_dialog_source_.get_chat_source_object();
|
||||
if (chat_source != nullptr) {
|
||||
switch (chat_source->get_id()) {
|
||||
case td_api::chatSourcePublicServiceAnnouncement::ID:
|
||||
// can delete for self (but only while removing from dialog list)
|
||||
return {true, false};
|
||||
default:
|
||||
return {false, false};
|
||||
}
|
||||
}
|
||||
if (td_->auth_manager_->is_bot() || !have_input_peer(d->dialog_id, AccessRights::Read)) {
|
||||
return {false, false};
|
||||
}
|
||||
|
||||
switch (d->dialog_id.get_type()) {
|
||||
case DialogType::User:
|
||||
if (d->dialog_id == get_my_dialog_id() || td_->contacts_manager_->is_user_deleted(d->dialog_id.get_user_id()) ||
|
||||
td_->contacts_manager_->is_user_bot(d->dialog_id.get_user_id())) {
|
||||
return {true, false};
|
||||
}
|
||||
return {true, G()->shared_config().get_option_boolean("revoke_pm_inbox", true)};
|
||||
case DialogType::Chat:
|
||||
// chats can be deleted only for self and can be deleted for everyone by their creator
|
||||
return {true, td_->contacts_manager_->get_chat_status(d->dialog_id.get_chat_id()).is_creator()};
|
||||
case DialogType::Channel:
|
||||
// private supergroups can be deleted for self
|
||||
return {!is_broadcast_channel(d->dialog_id) &&
|
||||
!td_->contacts_manager_->is_channel_public(d->dialog_id.get_channel_id()),
|
||||
td_->contacts_manager_->get_channel_can_be_deleted(d->dialog_id.get_channel_id())};
|
||||
case DialogType::SecretChat:
|
||||
if (td_->contacts_manager_->get_secret_chat_state(d->dialog_id.get_secret_chat_id()) == SecretChatState::Closed) {
|
||||
// in a closed secret chats there is no way to delete messages for both users
|
||||
return {true, false};
|
||||
} else {
|
||||
// active secret chats can be deleted only for both users
|
||||
return {false, true};
|
||||
}
|
||||
break;
|
||||
case DialogType::None:
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return {false, false};
|
||||
}
|
||||
}
|
||||
|
||||
void MessagesManager::delete_dialog_history(DialogId dialog_id, bool remove_from_dialog_list, bool revoke,
|
||||
Promise<Unit> &&promise) {
|
||||
LOG(INFO) << "Receive deleteChatHistory request to delete all messages in " << dialog_id
|
||||
@ -11104,8 +11146,7 @@ void MessagesManager::delete_dialog_history(DialogId dialog_id, bool remove_from
|
||||
return promise.set_error(Status::Error(400, "Can't delete the chat"));
|
||||
}
|
||||
if (!remove_from_dialog_list) {
|
||||
return promise.set_error(
|
||||
Status::Error(400, "Can't delete only chat history without removing the chat from the chat list"));
|
||||
return promise.set_error(Status::Error(400, "Can't delete chat history without removing the chat"));
|
||||
}
|
||||
|
||||
removed_sponsored_dialog_id_ = dialog_id;
|
||||
@ -11116,37 +11157,25 @@ void MessagesManager::delete_dialog_history(DialogId dialog_id, bool remove_from
|
||||
return;
|
||||
}
|
||||
|
||||
auto dialog_type = dialog_id.get_type();
|
||||
switch (dialog_type) {
|
||||
case DialogType::User:
|
||||
case DialogType::Chat:
|
||||
// ok
|
||||
break;
|
||||
case DialogType::Channel:
|
||||
auto can_delete = can_delete_dialog(d);
|
||||
if (revoke) {
|
||||
if (!td_->contacts_manager_->get_channel_can_be_deleted(d->dialog_id.get_channel_id())) {
|
||||
return promise.set_error(Status::Error(400, "Can't delete chat history for all chat members"));
|
||||
if (!can_delete.for_all_users_) {
|
||||
if (!can_delete.for_self_) {
|
||||
return promise.set_error(Status::Error(400, "Chat history can't be deleted"));
|
||||
}
|
||||
|
||||
LOG(INFO) << "Can't delete history of " << dialog_id << " for everyone; delete it only for self";
|
||||
revoke = false;
|
||||
}
|
||||
} else {
|
||||
if (is_broadcast_channel(dialog_id)) {
|
||||
return promise.set_error(Status::Error(400, "Can't delete chat history in a channel"));
|
||||
if (!can_delete.for_self_) {
|
||||
return promise.set_error(
|
||||
Status::Error(400, PSLICE() << "Can't delete history of " << dialog_id << " only for self"));
|
||||
}
|
||||
if (td_->contacts_manager_->is_channel_public(dialog_id.get_channel_id())) {
|
||||
return promise.set_error(Status::Error(400, "Can't delete chat history in a public supergroup"));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DialogType::SecretChat:
|
||||
// ok
|
||||
break;
|
||||
case DialogType::None:
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
|
||||
auto last_new_message_id = d->last_new_message_id;
|
||||
if (dialog_type != DialogType::SecretChat && last_new_message_id == MessageId()) {
|
||||
if (dialog_id.get_type() != DialogType::SecretChat && last_new_message_id == MessageId()) {
|
||||
// TODO get dialog from the server and delete history from last message identifier
|
||||
}
|
||||
|
||||
@ -11697,7 +11726,7 @@ void MessagesManager::delete_all_dialog_messages(Dialog *d, bool remove_from_dia
|
||||
}
|
||||
if (d->unread_reaction_count > 0) {
|
||||
set_dialog_unread_reaction_count(d, 0);
|
||||
send_update_chat_unread_reaction_count(d);
|
||||
send_update_chat_unread_reaction_count(d, "delete_all_dialog_messages");
|
||||
}
|
||||
|
||||
bool has_last_message_id = d->last_message_id != MessageId();
|
||||
@ -11919,7 +11948,7 @@ void MessagesManager::read_all_dialog_reactions(DialogId dialog_id, Promise<Unit
|
||||
if (d->unread_reaction_count != 0) {
|
||||
set_dialog_unread_reaction_count(d, 0);
|
||||
if (!is_update_sent) {
|
||||
send_update_chat_unread_reaction_count(d);
|
||||
send_update_chat_unread_reaction_count(d, "read_all_dialog_reactions");
|
||||
} else {
|
||||
LOG(INFO) << "Update unread reaction message count in " << dialog_id << " to " << d->unread_reaction_count;
|
||||
on_dialog_updated(dialog_id, "read_all_dialog_reactions");
|
||||
@ -13117,6 +13146,8 @@ class MessagesManager::DialogFiltersLogEvent {
|
||||
|
||||
void MessagesManager::tear_down() {
|
||||
parent_.reset();
|
||||
|
||||
LOG(DEBUG) << "Have " << dialogs_.size() << " chats with " << added_message_count_ << " messages to free";
|
||||
}
|
||||
|
||||
void MessagesManager::hangup() {
|
||||
@ -14853,7 +14884,7 @@ void MessagesManager::set_dialog_is_empty(Dialog *d, const char *source) {
|
||||
}
|
||||
if (d->unread_reaction_count > 0) {
|
||||
set_dialog_unread_reaction_count(d, 0);
|
||||
send_update_chat_unread_reaction_count(d);
|
||||
send_update_chat_unread_reaction_count(d, "set_dialog_is_empty");
|
||||
}
|
||||
if (d->reply_markup_message_id != MessageId()) {
|
||||
set_dialog_reply_markup(d, MessageId());
|
||||
@ -15569,7 +15600,7 @@ void MessagesManager::on_get_dialogs(FolderId folder_id, vector<tl_object_ptr<te
|
||||
if (d->unread_reaction_count != dialog->unread_reactions_count_) {
|
||||
set_dialog_unread_reaction_count(d, dialog->unread_reactions_count_);
|
||||
// update_dialog_mention_notification_count(d);
|
||||
send_update_chat_unread_reaction_count(d);
|
||||
send_update_chat_unread_reaction_count(d, "on_get_dialogs");
|
||||
}
|
||||
}
|
||||
|
||||
@ -16183,7 +16214,7 @@ unique_ptr<MessagesManager::Message> MessagesManager::do_delete_message(Dialog *
|
||||
}
|
||||
} else {
|
||||
set_dialog_unread_reaction_count(d, d->unread_reaction_count - 1);
|
||||
send_update_chat_unread_reaction_count(d);
|
||||
send_update_chat_unread_reaction_count(d, "do_delete_message");
|
||||
}
|
||||
}
|
||||
|
||||
@ -16251,6 +16282,8 @@ void MessagesManager::on_message_deleted(Dialog *d, Message *m, bool is_permanen
|
||||
if (m->notification_id.is_valid()) {
|
||||
delete_notification_id_to_message_id_correspondence(d, m->notification_id, m->message_id);
|
||||
}
|
||||
|
||||
added_message_count_--;
|
||||
}
|
||||
|
||||
unique_ptr<MessagesManager::Message> MessagesManager::do_delete_scheduled_message(Dialog *d, MessageId message_id,
|
||||
@ -17558,62 +17591,11 @@ void MessagesManager::on_get_common_dialogs(UserId user_id, int64 offset_chat_id
|
||||
}
|
||||
bool is_last = chats.empty() && offset_chat_id == 0;
|
||||
for (auto &chat : chats) {
|
||||
DialogId dialog_id;
|
||||
switch (chat->get_id()) {
|
||||
case telegram_api::chatEmpty::ID: {
|
||||
auto c = static_cast<const telegram_api::chatEmpty *>(chat.get());
|
||||
ChatId chat_id(c->id_);
|
||||
if (!chat_id.is_valid()) {
|
||||
LOG(ERROR) << "Receive invalid " << chat_id;
|
||||
auto dialog_id = ContactsManager::get_dialog_id(chat);
|
||||
if (!dialog_id.is_valid()) {
|
||||
LOG(ERROR) << "Receive invalid " << to_string(chat);
|
||||
continue;
|
||||
}
|
||||
dialog_id = DialogId(chat_id);
|
||||
break;
|
||||
}
|
||||
case telegram_api::chat::ID: {
|
||||
auto c = static_cast<const telegram_api::chat *>(chat.get());
|
||||
ChatId chat_id(c->id_);
|
||||
if (!chat_id.is_valid()) {
|
||||
LOG(ERROR) << "Receive invalid " << chat_id;
|
||||
continue;
|
||||
}
|
||||
dialog_id = DialogId(chat_id);
|
||||
break;
|
||||
}
|
||||
case telegram_api::chatForbidden::ID: {
|
||||
auto c = static_cast<const telegram_api::chatForbidden *>(chat.get());
|
||||
ChatId chat_id(c->id_);
|
||||
if (!chat_id.is_valid()) {
|
||||
LOG(ERROR) << "Receive invalid " << chat_id;
|
||||
continue;
|
||||
}
|
||||
dialog_id = DialogId(chat_id);
|
||||
break;
|
||||
}
|
||||
case telegram_api::channel::ID: {
|
||||
auto c = static_cast<const telegram_api::channel *>(chat.get());
|
||||
ChannelId channel_id(c->id_);
|
||||
if (!channel_id.is_valid()) {
|
||||
LOG(ERROR) << "Receive invalid " << channel_id;
|
||||
continue;
|
||||
}
|
||||
dialog_id = DialogId(channel_id);
|
||||
break;
|
||||
}
|
||||
case telegram_api::channelForbidden::ID: {
|
||||
auto c = static_cast<const telegram_api::channelForbidden *>(chat.get());
|
||||
ChannelId channel_id(c->id_);
|
||||
if (!channel_id.is_valid()) {
|
||||
LOG(ERROR) << "Receive invalid " << channel_id;
|
||||
continue;
|
||||
}
|
||||
dialog_id = DialogId(channel_id);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
CHECK(dialog_id.is_valid());
|
||||
td_->contacts_manager_->on_get_chat(std::move(chat), "on_get_common_dialogs");
|
||||
|
||||
if (!td::contains(result, dialog_id)) {
|
||||
@ -19256,7 +19238,7 @@ void MessagesManager::add_dialog_filter(unique_ptr<DialogFilter> dialog_filter,
|
||||
}
|
||||
|
||||
auto dialog_list_id = DialogListId(dialog_filter_id);
|
||||
CHECK(dialog_lists_.find(dialog_list_id) == dialog_lists_.end());
|
||||
CHECK(dialog_lists_.count(dialog_list_id) == 0);
|
||||
|
||||
auto &list = add_dialog_list(dialog_list_id);
|
||||
auto folder_ids = get_dialog_list_folder_ids(list);
|
||||
@ -20407,7 +20389,7 @@ DialogId MessagesManager::create_new_group_chat(const vector<UserId> &user_ids,
|
||||
|
||||
do {
|
||||
random_id = Random::secure_int64();
|
||||
} while (random_id == 0 || created_dialogs_.find(random_id) != created_dialogs_.end());
|
||||
} while (random_id == 0 || created_dialogs_.count(random_id) > 0);
|
||||
created_dialogs_[random_id]; // reserve place for result
|
||||
|
||||
td_->create_handler<CreateChatQuery>(std::move(promise))->send(std::move(input_users), new_title, random_id);
|
||||
@ -20445,7 +20427,7 @@ DialogId MessagesManager::create_new_channel_chat(const string &title, bool is_m
|
||||
|
||||
do {
|
||||
random_id = Random::secure_int64();
|
||||
} while (random_id == 0 || created_dialogs_.find(random_id) != created_dialogs_.end());
|
||||
} while (random_id == 0 || created_dialogs_.count(random_id) > 0);
|
||||
created_dialogs_[random_id]; // reserve place for result
|
||||
|
||||
td_->create_handler<CreateChannelQuery>(std::move(promise))
|
||||
@ -21156,65 +21138,9 @@ td_api::object_ptr<td_api::chat> MessagesManager::get_chat_object(const Dialog *
|
||||
CHECK(d != nullptr);
|
||||
|
||||
auto chat_source = is_dialog_sponsored(d) ? sponsored_dialog_source_.get_chat_source_object() : nullptr;
|
||||
|
||||
bool can_delete_for_self = false;
|
||||
bool can_delete_for_all_users = false;
|
||||
if (chat_source != nullptr) {
|
||||
switch (chat_source->get_id()) {
|
||||
case td_api::chatSourcePublicServiceAnnouncement::ID:
|
||||
// can delete for self (but only while removing from dialog list)
|
||||
can_delete_for_self = true;
|
||||
break;
|
||||
default:
|
||||
// can't delete
|
||||
break;
|
||||
}
|
||||
} else if (!td_->auth_manager_->is_bot() && have_input_peer(d->dialog_id, AccessRights::Read)) {
|
||||
switch (d->dialog_id.get_type()) {
|
||||
case DialogType::User:
|
||||
can_delete_for_self = true;
|
||||
can_delete_for_all_users = G()->shared_config().get_option_boolean("revoke_pm_inbox", true);
|
||||
if (d->dialog_id == get_my_dialog_id() || td_->contacts_manager_->is_user_deleted(d->dialog_id.get_user_id()) ||
|
||||
td_->contacts_manager_->is_user_bot(d->dialog_id.get_user_id())) {
|
||||
can_delete_for_all_users = false;
|
||||
}
|
||||
break;
|
||||
case DialogType::Chat:
|
||||
// chats can be deleted only for self with deleteChatHistory and for everyone by their creator
|
||||
can_delete_for_self = true;
|
||||
can_delete_for_all_users = td_->contacts_manager_->get_chat_status(d->dialog_id.get_chat_id()).is_creator();
|
||||
break;
|
||||
case DialogType::Channel:
|
||||
if (is_broadcast_channel(d->dialog_id) ||
|
||||
td_->contacts_manager_->is_channel_public(d->dialog_id.get_channel_id())) {
|
||||
// deleteChatHistory can't be used in channels and public supergroups to delete messages for self
|
||||
} else {
|
||||
// private supergroups can be deleted for self
|
||||
can_delete_for_self = true;
|
||||
}
|
||||
if (td_->contacts_manager_->get_channel_can_be_deleted(d->dialog_id.get_channel_id())) {
|
||||
can_delete_for_all_users = true;
|
||||
}
|
||||
break;
|
||||
case DialogType::SecretChat:
|
||||
if (td_->contacts_manager_->get_secret_chat_state(d->dialog_id.get_secret_chat_id()) ==
|
||||
SecretChatState::Closed) {
|
||||
// in a closed secret chats there is no way to delete messages for both users
|
||||
can_delete_for_self = true;
|
||||
} else {
|
||||
// active secret chats can be deleted only for both users
|
||||
can_delete_for_all_users = true;
|
||||
}
|
||||
break;
|
||||
case DialogType::None:
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
auto can_delete = can_delete_dialog(d);
|
||||
// TODO hide/show draft message when can_send_message(dialog_id) changes
|
||||
auto draft_message = can_send_message(d->dialog_id).is_ok() ? get_draft_message_object(d->draft_message) : nullptr;
|
||||
|
||||
return make_tl_object<td_api::chat>(
|
||||
d->dialog_id.get(), get_chat_type_object(d->dialog_id), get_dialog_title(d->dialog_id),
|
||||
get_chat_photo_info_object(td_->file_manager_.get(), get_dialog_photo(d->dialog_id)),
|
||||
@ -21222,7 +21148,7 @@ td_api::object_ptr<td_api::chat> MessagesManager::get_chat_object(const Dialog *
|
||||
get_message_object(d->dialog_id, get_message(d, d->last_message_id), "get_chat_object"),
|
||||
get_chat_positions_object(d), get_default_message_sender_object(d),
|
||||
get_dialog_has_protected_content(d->dialog_id), d->is_marked_as_unread, d->is_blocked,
|
||||
get_dialog_has_scheduled_messages(d), can_delete_for_self, can_delete_for_all_users,
|
||||
get_dialog_has_scheduled_messages(d), can_delete.for_self_, can_delete.for_all_users_,
|
||||
can_report_dialog(d->dialog_id), d->notification_settings.silent_send_message,
|
||||
d->server_unread_count + d->local_unread_count, d->last_read_inbox_message_id.get(),
|
||||
d->last_read_outbox_message_id.get(), d->unread_mention_count, d->unread_reaction_count,
|
||||
@ -22054,7 +21980,7 @@ std::pair<DialogId, vector<MessageId>> MessagesManager::get_message_thread_histo
|
||||
|
||||
do {
|
||||
random_id = Random::secure_int64();
|
||||
} while (random_id == 0 || found_dialog_messages_.find(random_id) != found_dialog_messages_.end());
|
||||
} while (random_id == 0 || found_dialog_messages_.count(random_id) > 0);
|
||||
found_dialog_messages_[random_id]; // reserve place for result
|
||||
|
||||
td_->create_handler<SearchMessagesQuery>(std::move(promise))
|
||||
@ -22103,7 +22029,7 @@ td_api::object_ptr<td_api::messageCalendar> MessagesManager::get_dialog_message_
|
||||
|
||||
do {
|
||||
random_id = Random::secure_int64();
|
||||
} while (random_id == 0 || found_dialog_message_calendars_.find(random_id) != found_dialog_message_calendars_.end());
|
||||
} while (random_id == 0 || found_dialog_message_calendars_.count(random_id) > 0);
|
||||
found_dialog_message_calendars_[random_id]; // reserve place for result
|
||||
|
||||
CHECK(filter != MessageSearchFilter::Call && filter != MessageSearchFilter::MissedCall);
|
||||
@ -22317,7 +22243,7 @@ std::pair<int32, vector<MessageId>> MessagesManager::search_dialog_messages(
|
||||
|
||||
do {
|
||||
random_id = Random::secure_int64();
|
||||
} while (random_id == 0 || found_dialog_messages_.find(random_id) != found_dialog_messages_.end());
|
||||
} while (random_id == 0 || found_dialog_messages_.count(random_id) > 0);
|
||||
found_dialog_messages_[random_id]; // reserve place for result
|
||||
|
||||
if (filter == MessageSearchFilter::UnreadMention || filter == MessageSearchFilter::UnreadReaction) {
|
||||
@ -22437,7 +22363,7 @@ std::pair<int32, vector<FullMessageId>> MessagesManager::search_call_messages(Me
|
||||
|
||||
do {
|
||||
random_id = Random::secure_int64();
|
||||
} while (random_id == 0 || found_call_messages_.find(random_id) != found_call_messages_.end());
|
||||
} while (random_id == 0 || found_call_messages_.count(random_id) > 0);
|
||||
found_call_messages_[random_id]; // reserve place for result
|
||||
|
||||
auto filter = only_missed ? MessageSearchFilter::MissedCall : MessageSearchFilter::Call;
|
||||
@ -22947,7 +22873,7 @@ void MessagesManager::on_search_dialog_messages_db_result(int64 random_id, Dialo
|
||||
if (filter == MessageSearchFilter::UnreadReaction) {
|
||||
d->unread_reaction_count = message_count;
|
||||
// update_dialog_mention_notification_count(d);
|
||||
send_update_chat_unread_reaction_count(d);
|
||||
send_update_chat_unread_reaction_count(d, "on_search_dialog_messages_db_result");
|
||||
}
|
||||
on_dialog_updated(dialog_id, "on_search_dialog_messages_db_result");
|
||||
}
|
||||
@ -23030,7 +22956,7 @@ MessagesManager::FoundMessages MessagesManager::offline_search_messages(DialogId
|
||||
|
||||
do {
|
||||
random_id = Random::secure_int64();
|
||||
} while (random_id == 0 || found_fts_messages_.find(random_id) != found_fts_messages_.end());
|
||||
} while (random_id == 0 || found_fts_messages_.count(random_id) > 0);
|
||||
found_fts_messages_[random_id]; // reserve place for result
|
||||
|
||||
G()->td_db()->get_messages_db_async()->get_messages_fts(
|
||||
@ -23163,7 +23089,7 @@ std::pair<int32, vector<FullMessageId>> MessagesManager::search_messages(
|
||||
|
||||
do {
|
||||
random_id = Random::secure_int64();
|
||||
} while (random_id == 0 || found_messages_.find(random_id) != found_messages_.end());
|
||||
} while (random_id == 0 || found_messages_.count(random_id) > 0);
|
||||
found_messages_[random_id]; // reserve place for result
|
||||
|
||||
LOG(DEBUG) << "Search all messages filtered by " << filter << " with query = \"" << query << "\" from date "
|
||||
@ -23194,8 +23120,7 @@ int64 MessagesManager::get_dialog_message_by_date(DialogId dialog_id, int32 date
|
||||
int64 random_id = 0;
|
||||
do {
|
||||
random_id = Random::secure_int64();
|
||||
} while (random_id == 0 ||
|
||||
get_dialog_message_by_date_results_.find(random_id) != get_dialog_message_by_date_results_.end());
|
||||
} while (random_id == 0 || get_dialog_message_by_date_results_.count(random_id) > 0);
|
||||
get_dialog_message_by_date_results_[random_id]; // reserve place for result
|
||||
|
||||
auto message_id = find_message_by_date(d->messages.get(), date);
|
||||
@ -23511,9 +23436,14 @@ void MessagesManager::get_dialog_message_count(DialogId dialog_id, MessageSearch
|
||||
return promise.set_value(std::move(message_count));
|
||||
}
|
||||
|
||||
get_dialog_message_count_from_server(dialog_id, filter, std::move(promise));
|
||||
}
|
||||
|
||||
void MessagesManager::get_dialog_message_count_from_server(DialogId dialog_id, MessageSearchFilter filter,
|
||||
Promise<int32> &&promise) {
|
||||
LOG(INFO) << "Get number of messages in " << dialog_id << " filtered by " << filter << " from the server";
|
||||
|
||||
switch (dialog_type) {
|
||||
switch (dialog_id.get_type()) {
|
||||
case DialogType::User:
|
||||
case DialogType::Chat:
|
||||
case DialogType::Channel:
|
||||
@ -24238,7 +24168,8 @@ void MessagesManager::set_message_reaction(FullMessageId full_message_id, string
|
||||
return promise.set_error(Status::Error(400, "The reaction isn't available for the message"));
|
||||
}
|
||||
|
||||
bool can_get_added_reactions = !is_broadcast_channel(dialog_id) && dialog_id.get_type() != DialogType::User;
|
||||
bool can_get_added_reactions = !is_broadcast_channel(dialog_id) && dialog_id.get_type() != DialogType::User &&
|
||||
!is_discussion_message(dialog_id, m);
|
||||
if (m->reactions == nullptr) {
|
||||
if (reaction.empty()) {
|
||||
return promise.set_value(Unit());
|
||||
@ -24638,7 +24569,7 @@ int64 MessagesManager::generate_new_random_id() {
|
||||
int64 random_id;
|
||||
do {
|
||||
random_id = Random::secure_int64();
|
||||
} while (random_id == 0 || being_sent_messages_.find(random_id) != being_sent_messages_.end());
|
||||
} while (random_id == 0 || being_sent_messages_.count(random_id) > 0);
|
||||
return random_id;
|
||||
}
|
||||
|
||||
@ -27849,6 +27780,7 @@ void MessagesManager::do_forward_messages(DialogId to_dialog_id, DialogId from_d
|
||||
}
|
||||
|
||||
auto schedule_date = get_message_schedule_date(messages[0]);
|
||||
auto as_input_peer = get_send_message_as_input_peer(messages[0]);
|
||||
|
||||
int32 flags = 0;
|
||||
if (messages[0]->disable_notification) {
|
||||
@ -27863,7 +27795,7 @@ void MessagesManager::do_forward_messages(DialogId to_dialog_id, DialogId from_d
|
||||
if (schedule_date != 0) {
|
||||
flags |= SEND_MESSAGE_FLAG_HAS_SCHEDULE_DATE;
|
||||
}
|
||||
if (messages[0]->has_explicit_sender) {
|
||||
if (as_input_peer != nullptr) {
|
||||
flags |= SEND_MESSAGE_FLAG_HAS_SEND_AS;
|
||||
}
|
||||
if (messages[0]->noforwards) {
|
||||
@ -27873,8 +27805,8 @@ void MessagesManager::do_forward_messages(DialogId to_dialog_id, DialogId from_d
|
||||
vector<int64> random_ids =
|
||||
transform(messages, [this, to_dialog_id](const Message *m) { return begin_send_message(to_dialog_id, m); });
|
||||
td_->create_handler<ForwardMessagesQuery>(get_erase_log_event_promise(log_event_id))
|
||||
->send(flags, to_dialog_id, from_dialog_id, get_send_message_as_input_peer(messages[0]), message_ids,
|
||||
std::move(random_ids), schedule_date);
|
||||
->send(flags, to_dialog_id, from_dialog_id, std::move(as_input_peer), message_ids, std::move(random_ids),
|
||||
schedule_date);
|
||||
}
|
||||
|
||||
Result<td_api::object_ptr<td_api::message>> MessagesManager::forward_message(
|
||||
@ -28737,7 +28669,7 @@ void MessagesManager::start_import_messages(DialogId dialog_id, int64 import_id,
|
||||
int64 random_id;
|
||||
do {
|
||||
random_id = Random::secure_int64();
|
||||
} while (random_id == 0 || pending_message_imports_.find(random_id) != pending_message_imports_.end());
|
||||
} while (random_id == 0 || pending_message_imports_.count(random_id) > 0);
|
||||
pending_message_imports_[random_id] = std::move(pending_message_import);
|
||||
|
||||
multipromise.add_promise(PromiseCreator::lambda([actor_id = actor_id(this), random_id](Result<Unit> result) {
|
||||
@ -30494,17 +30426,20 @@ void MessagesManager::send_update_chat_unread_mention_count(const Dialog *d) {
|
||||
make_tl_object<td_api::updateChatUnreadMentionCount>(d->dialog_id.get(), d->unread_mention_count));
|
||||
}
|
||||
|
||||
void MessagesManager::send_update_chat_unread_reaction_count(const Dialog *d) {
|
||||
void MessagesManager::send_update_chat_unread_reaction_count(const Dialog *d, const char *source) {
|
||||
if (td_->auth_manager_->is_bot()) {
|
||||
return;
|
||||
}
|
||||
|
||||
CHECK(d != nullptr);
|
||||
LOG_CHECK(d->is_update_new_chat_sent) << "Wrong " << d->dialog_id << " in send_update_chat_unread_reaction_count";
|
||||
LOG(INFO) << "Update unread reaction message count in " << d->dialog_id << " to " << d->unread_reaction_count;
|
||||
LOG_CHECK(d->is_update_new_chat_sent) << "Wrong " << d->dialog_id
|
||||
<< " in send_update_chat_unread_reaction_count from " << source;
|
||||
LOG(INFO) << "Update unread reaction message count in " << d->dialog_id << " to " << d->unread_reaction_count
|
||||
<< " from " << source;
|
||||
on_dialog_updated(d->dialog_id, "send_update_chat_unread_reaction_count");
|
||||
send_closure(G()->td(), &Td::send_update,
|
||||
make_tl_object<td_api::updateChatUnreadReactionCount>(d->dialog_id.get(), d->unread_reaction_count));
|
||||
send_closure(
|
||||
G()->td(), &Td::send_update,
|
||||
td_api::make_object<td_api::updateChatUnreadReactionCount>(d->dialog_id.get(), d->unread_reaction_count));
|
||||
}
|
||||
|
||||
void MessagesManager::send_update_chat_position(DialogListId dialog_list_id, const Dialog *d,
|
||||
@ -32128,10 +32063,10 @@ void MessagesManager::on_create_new_dialog_success(int64 random_id, tl_object_pt
|
||||
return promise.set_value(Unit());
|
||||
}
|
||||
|
||||
if (pending_created_dialogs_.find(dialog_id) == pending_created_dialogs_.end()) {
|
||||
if (pending_created_dialogs_.count(dialog_id) == 0) {
|
||||
pending_created_dialogs_.emplace(dialog_id, std::move(promise));
|
||||
} else {
|
||||
LOG(ERROR) << dialog_id << " returned twice as result of chat creation";
|
||||
LOG(ERROR) << "Receive twice " << dialog_id << " as result of chat creation";
|
||||
return on_create_new_dialog_fail(random_id, Status::Error(500, "Chat was created earlier"), std::move(promise));
|
||||
}
|
||||
|
||||
@ -34456,7 +34391,7 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq
|
||||
}
|
||||
if (*need_update && has_unread_message_reactions(dialog_id, message.get())) {
|
||||
set_dialog_unread_reaction_count(d, d->unread_reaction_count + 1);
|
||||
send_update_chat_unread_reaction_count(d);
|
||||
send_update_chat_unread_reaction_count(d, "add_message_to_dialog");
|
||||
}
|
||||
if (*need_update) {
|
||||
update_message_count_by_index(d, +1, message.get());
|
||||
@ -34684,6 +34619,8 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq
|
||||
}
|
||||
}
|
||||
|
||||
added_message_count_++;
|
||||
|
||||
return result_message;
|
||||
}
|
||||
|
||||
@ -35715,21 +35652,6 @@ bool MessagesManager::update_message_content(DialogId dialog_id, Message *old_me
|
||||
old_file_view.size() == new_file_view.size()) {
|
||||
auto old_file_type = old_file_view.get_type();
|
||||
auto new_file_type = new_file_view.get_type();
|
||||
auto is_document_file_type = [](FileType file_type) {
|
||||
switch (file_type) {
|
||||
case FileType::Animation:
|
||||
case FileType::Audio:
|
||||
case FileType::Document:
|
||||
case FileType::DocumentAsFile:
|
||||
case FileType::Sticker:
|
||||
case FileType::Video:
|
||||
case FileType::VideoNote:
|
||||
case FileType::VoiceNote:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
if (is_document_file_type(old_file_type) && is_document_file_type(new_file_type)) {
|
||||
auto &old_location = old_file_view.local_location();
|
||||
@ -37466,7 +37388,7 @@ MessagesManager::DialogList &MessagesManager::add_dialog_list(DialogListId dialo
|
||||
if (dialog_list_id.is_folder() && dialog_list_id.get_folder_id() != FolderId::archive()) {
|
||||
dialog_list_id = DialogListId(FolderId::main());
|
||||
}
|
||||
if (dialog_lists_.find(dialog_list_id) == dialog_lists_.end()) {
|
||||
if (dialog_lists_.count(dialog_list_id) == 0) {
|
||||
LOG(INFO) << "Create " << dialog_list_id;
|
||||
}
|
||||
auto &list = dialog_lists_[dialog_list_id];
|
||||
@ -37840,8 +37762,7 @@ void MessagesManager::process_get_channel_difference_updates(
|
||||
auto update_new_channel_message = static_cast<telegram_api::updateNewChannelMessage *>(update.get());
|
||||
auto message_id = get_message_id(update_new_channel_message->message_, false);
|
||||
FullMessageId full_message_id(dialog_id, message_id);
|
||||
if (update_message_ids_.find(full_message_id) != update_message_ids_.end() &&
|
||||
changed_message_ids.find(message_id) != changed_message_ids.end()) {
|
||||
if (update_message_ids_.count(full_message_id) > 0 && changed_message_ids.count(message_id) > 0) {
|
||||
changed_message_ids.erase(message_id);
|
||||
AwaitedMessage awaited_message;
|
||||
awaited_message.message = std::move(update_new_channel_message->message_);
|
||||
@ -38015,7 +37936,7 @@ void MessagesManager::on_get_channel_dialog(DialogId dialog_id, MessageId last_m
|
||||
if (d->unread_reaction_count != unread_reaction_count) {
|
||||
set_dialog_unread_reaction_count(d, unread_reaction_count);
|
||||
// update_dialog_mention_notification_count(d);
|
||||
send_update_chat_unread_reaction_count(d);
|
||||
send_update_chat_unread_reaction_count(d, "on_get_channel_dialog 60");
|
||||
}
|
||||
|
||||
if (d->last_read_outbox_message_id != read_outbox_max_message_id) {
|
||||
|
@ -820,7 +820,7 @@ class MessagesManager final : public Actor {
|
||||
tl_object_ptr<td_api::messages> get_messages_object(int32 total_count, const vector<FullMessageId> &full_message_ids,
|
||||
bool skip_not_found, const char *source);
|
||||
|
||||
void process_pts_update(tl_object_ptr<telegram_api::Update> &&update);
|
||||
void process_pts_update(tl_object_ptr<telegram_api::Update> &&update_ptr);
|
||||
|
||||
void skip_old_pending_pts_update(tl_object_ptr<telegram_api::Update> &&update, int32 new_pts, int32 old_pts,
|
||||
int32 pts_count, const char *source);
|
||||
@ -1844,6 +1844,8 @@ class MessagesManager final : public Actor {
|
||||
|
||||
void delete_update_message_id(DialogId dialog_id, MessageId message_id);
|
||||
|
||||
void get_dialog_message_count_from_server(DialogId dialog_id, MessageSearchFilter filter, Promise<int32> &&promise);
|
||||
|
||||
FullMessageId on_get_message(MessageInfo &&message_info, bool from_update, bool is_channel_message,
|
||||
bool have_previous, bool have_next, const char *source);
|
||||
|
||||
@ -1917,9 +1919,9 @@ class MessagesManager final : public Actor {
|
||||
void add_postponed_channel_update(DialogId dialog_id, tl_object_ptr<telegram_api::Update> &&update, int32 new_pts,
|
||||
int32 pts_count, Promise<Unit> &&promise);
|
||||
|
||||
void process_channel_update(tl_object_ptr<telegram_api::Update> &&update);
|
||||
void process_channel_update(tl_object_ptr<telegram_api::Update> &&update_ptr);
|
||||
|
||||
void on_message_edited(FullMessageId full_message_id, int32 pts);
|
||||
void on_message_edited(FullMessageId full_message_id, int32 pts, bool had_message);
|
||||
|
||||
void delete_messages_from_updates(const vector<MessageId> &message_ids);
|
||||
|
||||
@ -2031,6 +2033,15 @@ class MessagesManager final : public Actor {
|
||||
|
||||
bool can_get_message_statistics(DialogId dialog_id, const Message *m) const;
|
||||
|
||||
struct CanDeleteDialog {
|
||||
bool for_self_;
|
||||
bool for_all_users_;
|
||||
|
||||
CanDeleteDialog(bool for_self, bool for_all_users) : for_self_(for_self), for_all_users_(for_all_users) {
|
||||
}
|
||||
};
|
||||
CanDeleteDialog can_delete_dialog(const Dialog *d) const;
|
||||
|
||||
static bool can_delete_channel_message(const DialogParticipantStatus &status, const Message *m, bool is_bot);
|
||||
|
||||
bool can_delete_message(DialogId dialog_id, const Message *m) const;
|
||||
@ -2449,7 +2460,7 @@ class MessagesManager final : public Actor {
|
||||
|
||||
void send_update_chat_unread_mention_count(const Dialog *d);
|
||||
|
||||
void send_update_chat_unread_reaction_count(const Dialog *d);
|
||||
void send_update_chat_unread_reaction_count(const Dialog *d, const char *source);
|
||||
|
||||
void send_update_chat_position(DialogListId dialog_list_id, const Dialog *d, const char *source) const;
|
||||
|
||||
@ -3419,6 +3430,7 @@ class MessagesManager final : public Actor {
|
||||
bool running_get_difference_ = false; // true after before_get_difference and false after after_get_difference
|
||||
|
||||
FlatHashMap<DialogId, unique_ptr<Dialog>, DialogIdHash> dialogs_;
|
||||
int64 added_message_count_ = 0;
|
||||
|
||||
FlatHashSet<DialogId, DialogIdHash> loaded_dialogs_; // dialogs loaded from database, but not added to dialogs_
|
||||
|
||||
|
@ -204,7 +204,7 @@ void NotificationManager::start_up() {
|
||||
}
|
||||
|
||||
void NotificationManager::init() {
|
||||
if (is_disabled()) {
|
||||
if (is_disabled() || is_inited_) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -70,18 +70,8 @@ tl_object_ptr<td_api::profilePhoto> get_profile_photo_object(FileManager *file_m
|
||||
profile_photo.has_animation);
|
||||
}
|
||||
|
||||
bool operator==(const ProfilePhoto &lhs, const ProfilePhoto &rhs) {
|
||||
bool location_differs = lhs.small_file_id != rhs.small_file_id || lhs.big_file_id != rhs.big_file_id;
|
||||
bool id_differs = lhs.id != rhs.id;
|
||||
|
||||
if (location_differs) {
|
||||
return false;
|
||||
}
|
||||
return lhs.has_animation == rhs.has_animation && lhs.minithumbnail == rhs.minithumbnail && !id_differs;
|
||||
}
|
||||
|
||||
bool operator!=(const ProfilePhoto &lhs, const ProfilePhoto &rhs) {
|
||||
return !(lhs == rhs);
|
||||
bool need_update_profile_photo(const ProfilePhoto &from, const ProfilePhoto &to) {
|
||||
return from.id != to.id || need_update_dialog_photo(from, to);
|
||||
}
|
||||
|
||||
StringBuilder &operator<<(StringBuilder &string_builder, const ProfilePhoto &profile_photo) {
|
||||
@ -163,9 +153,10 @@ DialogPhoto as_fake_dialog_photo(const Photo &photo, DialogId dialog_id) {
|
||||
return result;
|
||||
}
|
||||
|
||||
ProfilePhoto as_profile_photo(FileManager *file_manager, UserId user_id, int64 user_access_hash, const Photo &photo) {
|
||||
ProfilePhoto result;
|
||||
static_cast<DialogPhoto &>(result) = as_fake_dialog_photo(photo, DialogId(user_id));
|
||||
DialogPhoto as_dialog_photo(FileManager *file_manager, DialogId dialog_id, int64 dialog_access_hash,
|
||||
const Photo &photo) {
|
||||
DialogPhoto result;
|
||||
static_cast<DialogPhoto &>(result) = as_fake_dialog_photo(photo, dialog_id);
|
||||
if (!result.small_file_id.is_valid()) {
|
||||
return result;
|
||||
}
|
||||
@ -176,25 +167,40 @@ ProfilePhoto as_profile_photo(FileManager *file_manager, UserId user_id, int64 u
|
||||
auto remote = file_view.remote_location();
|
||||
CHECK(remote.is_photo());
|
||||
CHECK(!remote.is_web());
|
||||
remote.set_source(PhotoSizeSource::dialog_photo(DialogId(user_id), user_access_hash, is_big));
|
||||
return file_manager->register_remote(std::move(remote), FileLocationSource::FromServer, DialogId(),
|
||||
file_view.size(), file_view.expected_size(), file_view.remote_name());
|
||||
remote.set_source(PhotoSizeSource::dialog_photo(dialog_id, dialog_access_hash, is_big));
|
||||
return file_manager->register_remote(std::move(remote), FileLocationSource::FromServer, DialogId(), 0, 0,
|
||||
file_view.remote_name());
|
||||
};
|
||||
|
||||
result.id = photo.id.get();
|
||||
result.small_file_id = reregister_photo(false, result.small_file_id);
|
||||
result.big_file_id = reregister_photo(true, result.big_file_id);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool operator==(const DialogPhoto &lhs, const DialogPhoto &rhs) {
|
||||
return lhs.small_file_id == rhs.small_file_id && lhs.big_file_id == rhs.big_file_id &&
|
||||
lhs.minithumbnail == rhs.minithumbnail && lhs.has_animation == rhs.has_animation;
|
||||
ProfilePhoto as_profile_photo(FileManager *file_manager, UserId user_id, int64 user_access_hash, const Photo &photo) {
|
||||
ProfilePhoto result;
|
||||
static_cast<DialogPhoto &>(result) = as_dialog_photo(file_manager, DialogId(user_id), user_access_hash, photo);
|
||||
if (result.small_file_id.is_valid()) {
|
||||
result.id = photo.id.get();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool operator!=(const DialogPhoto &lhs, const DialogPhoto &rhs) {
|
||||
return !(lhs == rhs);
|
||||
bool is_same_dialog_photo(FileManager *file_manager, DialogId dialog_id, const Photo &photo,
|
||||
const DialogPhoto &dialog_photo) {
|
||||
auto get_unique_file_id = [file_manager](FileId file_id) {
|
||||
return file_manager->get_file_view(file_id).get_unique_file_id();
|
||||
};
|
||||
auto fake_photo = as_fake_dialog_photo(photo, dialog_id);
|
||||
return get_unique_file_id(fake_photo.small_file_id) == get_unique_file_id(dialog_photo.small_file_id) &&
|
||||
get_unique_file_id(fake_photo.big_file_id) == get_unique_file_id(dialog_photo.big_file_id);
|
||||
}
|
||||
|
||||
bool need_update_dialog_photo(const DialogPhoto &from, const DialogPhoto &to) {
|
||||
return from.small_file_id != to.small_file_id || from.big_file_id != to.big_file_id ||
|
||||
from.has_animation != to.has_animation ||
|
||||
need_update_dialog_photo_minithumbnail(from.minithumbnail, to.minithumbnail);
|
||||
}
|
||||
|
||||
StringBuilder &operator<<(StringBuilder &string_builder, const DialogPhoto &dialog_photo) {
|
||||
|
@ -57,8 +57,7 @@ ProfilePhoto get_profile_photo(FileManager *file_manager, UserId user_id, int64
|
||||
tl_object_ptr<td_api::profilePhoto> get_profile_photo_object(FileManager *file_manager,
|
||||
const ProfilePhoto &profile_photo);
|
||||
|
||||
bool operator==(const ProfilePhoto &lhs, const ProfilePhoto &rhs);
|
||||
bool operator!=(const ProfilePhoto &lhs, const ProfilePhoto &rhs);
|
||||
bool need_update_profile_photo(const ProfilePhoto &from, const ProfilePhoto &to);
|
||||
|
||||
StringBuilder &operator<<(StringBuilder &string_builder, const ProfilePhoto &profile_photo);
|
||||
|
||||
@ -69,12 +68,17 @@ tl_object_ptr<td_api::chatPhotoInfo> get_chat_photo_info_object(FileManager *fil
|
||||
|
||||
DialogPhoto as_fake_dialog_photo(const Photo &photo, DialogId dialog_id);
|
||||
|
||||
DialogPhoto as_dialog_photo(FileManager *file_manager, DialogId dialog_id, int64 dialog_access_hash,
|
||||
const Photo &photo);
|
||||
|
||||
ProfilePhoto as_profile_photo(FileManager *file_manager, UserId user_id, int64 user_access_hash, const Photo &photo);
|
||||
|
||||
bool is_same_dialog_photo(FileManager *file_manager, DialogId dialog_id, const Photo &photo,
|
||||
const DialogPhoto &dialog_photo);
|
||||
|
||||
vector<FileId> dialog_photo_get_file_ids(const DialogPhoto &dialog_photo);
|
||||
|
||||
bool operator==(const DialogPhoto &lhs, const DialogPhoto &rhs);
|
||||
bool operator!=(const DialogPhoto &lhs, const DialogPhoto &rhs);
|
||||
bool need_update_dialog_photo(const DialogPhoto &from, const DialogPhoto &to);
|
||||
|
||||
StringBuilder &operator<<(StringBuilder &string_builder, const DialogPhoto &dialog_photo);
|
||||
|
||||
|
@ -57,6 +57,27 @@ StringBuilder &operator<<(StringBuilder &string_builder, const Dimensions &dimen
|
||||
return string_builder << "(" << dimensions.width << ", " << dimensions.height << ")";
|
||||
}
|
||||
|
||||
static int32 get_minithumbnail_size(const string &packed) {
|
||||
if (packed.size() < 3) {
|
||||
return 0;
|
||||
}
|
||||
if (packed[0] == '\x01') {
|
||||
return max(static_cast<unsigned char>(packed[1]), static_cast<unsigned char>(packed[2]));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool need_update_dialog_photo_minithumbnail(const string &from, const string &to) {
|
||||
if (from == to) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto from_size = get_minithumbnail_size(from);
|
||||
auto to_size = get_minithumbnail_size(to);
|
||||
// dialog photo minithumbnail is expected to be 8x8
|
||||
return to_size != 0 && (to_size <= 8 || from_size > 8);
|
||||
}
|
||||
|
||||
td_api::object_ptr<td_api::minithumbnail> get_minithumbnail_object(const string &packed) {
|
||||
if (packed.size() < 3) {
|
||||
return nullptr;
|
||||
|
@ -48,6 +48,8 @@ bool operator!=(const Dimensions &lhs, const Dimensions &rhs);
|
||||
|
||||
StringBuilder &operator<<(StringBuilder &string_builder, const Dimensions &dimensions);
|
||||
|
||||
bool need_update_dialog_photo_minithumbnail(const string &from, const string &to);
|
||||
|
||||
td_api::object_ptr<td_api::minithumbnail> get_minithumbnail_object(const string &packed);
|
||||
|
||||
FileId register_photo_size(FileManager *file_manager, const PhotoSizeSource &source, int64 id, int64 access_hash,
|
||||
|
@ -1172,7 +1172,7 @@ void PollManager::on_update_poll_timeout(PollId poll_id) {
|
||||
if (poll->is_closed && poll->is_updated_after_close) {
|
||||
return;
|
||||
}
|
||||
if (pending_answers_.find(poll_id) != pending_answers_.end()) {
|
||||
if (pending_answers_.count(poll_id) > 0) {
|
||||
LOG(INFO) << "Skip fetching results of " << poll_id << ", because it is being voted now";
|
||||
return;
|
||||
}
|
||||
|
@ -548,7 +548,7 @@ void SecretChatActor::run_fill_gaps() {
|
||||
auto message = std::move(begin->second);
|
||||
pending_inbound_messages_.erase(begin);
|
||||
check_status(do_inbound_message_decrypted_unchecked(std::move(message), -1));
|
||||
CHECK(pending_inbound_messages_.find(next_seq_no) == pending_inbound_messages_.end());
|
||||
CHECK(pending_inbound_messages_.count(next_seq_no) == 0);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
@ -548,7 +548,7 @@ void SetSecureValue::start_upload(FileManager *file_manager, FileId &file_id, Se
|
||||
auto download_file_id = file_manager->dup_file_id(file_id);
|
||||
file_id =
|
||||
file_manager
|
||||
->register_generate(FileType::Secure, FileLocationSource::FromServer, file_view.suggested_path(),
|
||||
->register_generate(FileType::SecureEncrypted, FileLocationSource::FromServer, file_view.suggested_path(),
|
||||
PSTRING() << "#file_id#" << download_file_id.get(), DialogId(), file_view.size())
|
||||
.ok();
|
||||
}
|
||||
|
@ -354,9 +354,9 @@ EncryptedSecureFile get_encrypted_secure_file(FileManager *file_manager,
|
||||
break;
|
||||
}
|
||||
result.file.file_id = file_manager->register_remote(
|
||||
FullRemoteFileLocation(FileType::Secure, secure_file->id_, secure_file->access_hash_, DcId::internal(dc_id),
|
||||
""),
|
||||
FileLocationSource::FromServer, DialogId(), 0, secure_file->size_, PSTRING() << secure_file->id_ << ".jpg");
|
||||
FullRemoteFileLocation(FileType::SecureEncrypted, secure_file->id_, secure_file->access_hash_,
|
||||
DcId::internal(dc_id), ""),
|
||||
FileLocationSource::FromServer, DialogId(), secure_file->size_, 0, PSTRING() << secure_file->id_ << ".jpg");
|
||||
result.file.date = secure_file->date_;
|
||||
if (result.file.date < 0) {
|
||||
LOG(ERROR) << "Receive wrong date " << result.file.date;
|
||||
@ -427,12 +427,16 @@ static td_api::object_ptr<td_api::datedFile> get_dated_file_object(FileManager *
|
||||
LOG(ERROR) << "Have wrong file in get_dated_file_object";
|
||||
return nullptr;
|
||||
}
|
||||
dated_file.file_id =
|
||||
file_manager->register_remote(FullRemoteFileLocation(FileType::SecureRaw, file_view.remote_location().get_id(),
|
||||
file_view.remote_location().get_access_hash(),
|
||||
file_view.remote_location().get_dc_id(), ""),
|
||||
FileLocationSource::FromServer, DialogId(), file_view.size(),
|
||||
file_view.expected_size(), file_view.suggested_path());
|
||||
if (file_view.get_type() != FileType::SecureEncrypted) {
|
||||
LOG(ERROR) << "Have file of a wrong type in get_dated_file_object";
|
||||
} else if (file_view.encryption_key().empty()) {
|
||||
return get_dated_file_object(file_manager, dated_file);
|
||||
}
|
||||
dated_file.file_id = file_manager->register_remote(
|
||||
FullRemoteFileLocation(FileType::SecureDecrypted, file_view.remote_location().get_id(),
|
||||
file_view.remote_location().get_access_hash(), file_view.remote_location().get_dc_id(),
|
||||
""),
|
||||
FileLocationSource::FromServer, DialogId(), 0, file_view.expected_size(), file_view.suggested_path());
|
||||
return get_dated_file_object(file_manager, dated_file);
|
||||
}
|
||||
|
||||
@ -843,7 +847,8 @@ static Status check_document_number(string &number) {
|
||||
}
|
||||
|
||||
static Result<DatedFile> get_secure_file(FileManager *file_manager, td_api::object_ptr<td_api::InputFile> &&file) {
|
||||
TRY_RESULT(file_id, file_manager->get_input_file_id(FileType::Secure, file, DialogId(), false, false, false, true));
|
||||
TRY_RESULT(file_id,
|
||||
file_manager->get_input_file_id(FileType::SecureEncrypted, file, DialogId(), false, false, false, true));
|
||||
DatedFile result;
|
||||
result.file_id = file_id;
|
||||
result.date = G()->unix_time();
|
||||
|
@ -41,9 +41,9 @@ void SendCodeHelper::store(StorerT &storer) const {
|
||||
|
||||
template <class ParserT>
|
||||
void SendCodeHelper::parse(ParserT &parser) {
|
||||
bool legacy_is_registered = false;
|
||||
using td::parse;
|
||||
parse(phone_number_, parser);
|
||||
bool legacy_is_registered;
|
||||
parse(legacy_is_registered, parser);
|
||||
parse(phone_code_hash_, parser);
|
||||
parse(sent_code_info_, parser);
|
||||
|
@ -1295,7 +1295,7 @@ void StickersManager::start_up() {
|
||||
}
|
||||
|
||||
void StickersManager::init() {
|
||||
if (!td_->auth_manager_->is_authorized() || td_->auth_manager_->is_bot() || G()->close_flag()) {
|
||||
if (is_inited_ || !td_->auth_manager_->is_authorized() || td_->auth_manager_->is_bot() || G()->close_flag()) {
|
||||
return;
|
||||
}
|
||||
LOG(INFO) << "Init StickersManager";
|
||||
@ -5867,7 +5867,7 @@ void StickersManager::create_new_sticker_set(UserId user_id, string &title, stri
|
||||
int64 random_id;
|
||||
do {
|
||||
random_id = Random::secure_int64();
|
||||
} while (random_id == 0 || pending_new_sticker_sets_.find(random_id) != pending_new_sticker_sets_.end());
|
||||
} while (random_id == 0 || pending_new_sticker_sets_.count(random_id) > 0);
|
||||
pending_new_sticker_sets_[random_id] = std::move(pending_new_sticker_set);
|
||||
|
||||
multipromise.add_promise(PromiseCreator::lambda([actor_id = actor_id(this), random_id](Result<Unit> result) {
|
||||
@ -6066,7 +6066,7 @@ void StickersManager::add_sticker_to_set(UserId user_id, string &short_name,
|
||||
int64 random_id;
|
||||
do {
|
||||
random_id = Random::secure_int64();
|
||||
} while (random_id == 0 || pending_add_sticker_to_sets_.find(random_id) != pending_add_sticker_to_sets_.end());
|
||||
} while (random_id == 0 || pending_add_sticker_to_sets_.count(random_id) > 0);
|
||||
pending_add_sticker_to_sets_[random_id] = std::move(pending_add_sticker_to_set);
|
||||
|
||||
auto on_upload_promise = PromiseCreator::lambda([random_id](Result<Unit> result) {
|
||||
@ -6162,8 +6162,7 @@ void StickersManager::do_set_sticker_set_thumbnail(UserId user_id, string short_
|
||||
int64 random_id;
|
||||
do {
|
||||
random_id = Random::secure_int64();
|
||||
} while (random_id == 0 ||
|
||||
pending_set_sticker_set_thumbnails_.find(random_id) != pending_set_sticker_set_thumbnails_.end());
|
||||
} while (random_id == 0 || pending_set_sticker_set_thumbnails_.count(random_id) > 0);
|
||||
pending_set_sticker_set_thumbnails_[random_id] = std::move(pending_set_sticker_set_thumbnail);
|
||||
|
||||
auto on_upload_promise = PromiseCreator::lambda([random_id](Result<Unit> result) {
|
||||
@ -7590,7 +7589,7 @@ int64 StickersManager::get_emoji_suggestions_url(const string &language_code, Pr
|
||||
int64 random_id = 0;
|
||||
do {
|
||||
random_id = Random::secure_int64();
|
||||
} while (random_id == 0 || emoji_suggestions_urls_.find(random_id) != emoji_suggestions_urls_.end());
|
||||
} while (random_id == 0 || emoji_suggestions_urls_.count(random_id) > 0);
|
||||
emoji_suggestions_urls_[random_id]; // reserve place for result
|
||||
|
||||
auto query_promise =
|
||||
|
@ -5809,6 +5809,13 @@ void Td::on_request(uint64 id, td_api::sendCallDebugInformation &request) {
|
||||
std::move(request.debug_information_), std::move(promise));
|
||||
}
|
||||
|
||||
void Td::on_request(uint64 id, td_api::sendCallLog &request) {
|
||||
CHECK_IS_USER();
|
||||
CREATE_OK_REQUEST_PROMISE();
|
||||
send_closure(G()->call_manager(), &CallManager::send_call_log, CallId(request.call_id_), std::move(request.log_file_),
|
||||
std::move(promise));
|
||||
}
|
||||
|
||||
void Td::on_request(uint64 id, const td_api::getVideoChatAvailableParticipants &request) {
|
||||
CHECK_IS_USER();
|
||||
CREATE_REQUEST_PROMISE();
|
||||
@ -6613,7 +6620,7 @@ void Td::on_request(uint64 id, td_api::uploadFile &request) {
|
||||
|
||||
auto file_type = request.file_type_ == nullptr ? FileType::Temp : get_file_type(*request.file_type_);
|
||||
bool is_secret = file_type == FileType::Encrypted || file_type == FileType::EncryptedThumbnail;
|
||||
bool is_secure = file_type == FileType::Secure;
|
||||
bool is_secure = file_type == FileType::SecureEncrypted;
|
||||
auto r_file_id = file_manager_->get_input_file_id(file_type, request.file_, DialogId(), false, is_secret,
|
||||
!is_secure && !is_secret, is_secure);
|
||||
if (r_file_id.is_error()) {
|
||||
@ -8102,6 +8109,9 @@ td_api::object_ptr<td_api::Object> Td::do_static_request(td_api::parseTextEntiti
|
||||
}
|
||||
|
||||
auto r_entities = [&]() -> Result<vector<MessageEntity>> {
|
||||
if (utf8_length(request.text_) > 65536) {
|
||||
return Status::Error("Text is too long");
|
||||
}
|
||||
switch (request.parse_mode_->get_id()) {
|
||||
case td_api::textParseModeHTML::ID:
|
||||
return parse_html(request.text_);
|
||||
|
@ -755,6 +755,8 @@ class Td final : public Actor {
|
||||
|
||||
void on_request(uint64 id, td_api::sendCallDebugInformation &request);
|
||||
|
||||
void on_request(uint64 id, td_api::sendCallLog &request);
|
||||
|
||||
void on_request(uint64 id, const td_api::getVideoChatAvailableParticipants &request);
|
||||
|
||||
void on_request(uint64 id, const td_api::setVideoChatDefaultParticipant &request);
|
||||
|
@ -177,6 +177,8 @@ UpdatesManager::UpdatesManager(Td *td, ActorShared<> parent) : td_(td), parent_(
|
||||
|
||||
void UpdatesManager::tear_down() {
|
||||
parent_.reset();
|
||||
|
||||
LOG(DEBUG) << "Have " << being_processed_updates_ << " unprocessed updates to apply";
|
||||
}
|
||||
|
||||
void UpdatesManager::hangup_shared() {
|
||||
@ -1192,20 +1194,13 @@ vector<DialogId> UpdatesManager::get_chat_dialog_ids(const telegram_api::Updates
|
||||
vector<DialogId> dialog_ids;
|
||||
dialog_ids.reserve(chats->size());
|
||||
for (const auto &chat : *chats) {
|
||||
auto chat_id = ContactsManager::get_chat_id(chat);
|
||||
if (chat_id.is_valid()) {
|
||||
dialog_ids.push_back(DialogId(chat_id));
|
||||
continue;
|
||||
}
|
||||
|
||||
auto channel_id = ContactsManager::get_channel_id(chat);
|
||||
if (channel_id.is_valid()) {
|
||||
dialog_ids.push_back(DialogId(channel_id));
|
||||
continue;
|
||||
}
|
||||
|
||||
auto dialog_id = ContactsManager::get_dialog_id(chat);
|
||||
if (dialog_id.is_valid()) {
|
||||
dialog_ids.push_back(dialog_id);
|
||||
} else {
|
||||
LOG(ERROR) << "Can't find identifier of " << oneline(to_string(chat));
|
||||
}
|
||||
}
|
||||
return dialog_ids;
|
||||
}
|
||||
|
||||
@ -1709,6 +1704,7 @@ void UpdatesManager::on_pending_updates(vector<tl_object_ptr<telegram_api::Updat
|
||||
}
|
||||
|
||||
MultiPromiseActorSafe mpas{"OnPendingUpdatesMultiPromiseActor"};
|
||||
being_processed_updates_++;
|
||||
mpas.add_promise([actor_id = create_reference(), promise = std::move(promise)](Result<Unit> &&result) mutable {
|
||||
send_closure(actor_id, &UpdatesManager::on_pending_updates_processed, std::move(result), std::move(promise));
|
||||
});
|
||||
@ -1821,7 +1817,7 @@ void UpdatesManager::on_pending_updates(vector<tl_object_ptr<telegram_api::Updat
|
||||
|
||||
LOG(INFO) << "Gap in seq has found. Receive " << updates.size() << " updates [" << seq_begin << ", " << seq_end
|
||||
<< "] from " << source << ", but seq = " << seq_;
|
||||
LOG_IF(WARNING, pending_seq_updates_.find(seq_begin) != pending_seq_updates_.end())
|
||||
LOG_IF(WARNING, pending_seq_updates_.count(seq_begin) > 0)
|
||||
<< "Already have pending updates with seq = " << seq_begin << ", but receive it again from " << source;
|
||||
|
||||
pending_seq_updates_.emplace(
|
||||
@ -1831,6 +1827,7 @@ void UpdatesManager::on_pending_updates(vector<tl_object_ptr<telegram_api::Updat
|
||||
}
|
||||
|
||||
void UpdatesManager::on_pending_updates_processed(Result<Unit> result, Promise<Unit> promise) {
|
||||
being_processed_updates_--;
|
||||
promise.set_result(std::move(result));
|
||||
}
|
||||
|
||||
|
@ -195,6 +195,8 @@ class UpdatesManager final : public Actor {
|
||||
int32 pending_pts_ = 0;
|
||||
int32 pending_qts_ = 0;
|
||||
|
||||
int64 being_processed_updates_ = 0;
|
||||
|
||||
int32 short_update_date_ = 0;
|
||||
|
||||
int32 accumulated_pts_count_ = 0;
|
||||
|
@ -413,6 +413,8 @@ WebPagesManager::WebPagesManager(Td *td, ActorShared<> parent) : td_(td), parent
|
||||
|
||||
void WebPagesManager::tear_down() {
|
||||
parent_.reset();
|
||||
|
||||
LOG(DEBUG) << "Have " << web_pages_.size() << " web pages to free";
|
||||
}
|
||||
|
||||
WebPagesManager::~WebPagesManager() = default;
|
||||
|
@ -673,12 +673,28 @@ class CliClient final : public Actor {
|
||||
return as_input_thumbnail(as_generated_file(original_path, conversion), width, height);
|
||||
}
|
||||
|
||||
static int32 as_call_id(string str) {
|
||||
return to_integer<int32>(trim(std::move(str)));
|
||||
struct CallId {
|
||||
int32 call_id = 0;
|
||||
|
||||
operator int32() const {
|
||||
return call_id;
|
||||
}
|
||||
};
|
||||
|
||||
void get_args(string &args, CallId &arg) const {
|
||||
arg.call_id = to_integer<int32>(trim(args));
|
||||
}
|
||||
|
||||
static int32 as_group_call_id(string str) {
|
||||
return to_integer<int32>(trim(std::move(str)));
|
||||
struct GroupCallId {
|
||||
int32 group_call_id = 0;
|
||||
|
||||
operator int32() const {
|
||||
return group_call_id;
|
||||
}
|
||||
};
|
||||
|
||||
void get_args(string &args, GroupCallId &arg) const {
|
||||
arg.group_call_id = to_integer<int32>(trim(args));
|
||||
}
|
||||
|
||||
static int32 as_proxy_id(string str) {
|
||||
@ -2994,18 +3010,21 @@ class CliClient final : public Actor {
|
||||
user_id, td_api::make_object<td_api::callProtocol>(true, true, 65, 65, vector<string>{"2.6", "3.0"}),
|
||||
rand_bool()));
|
||||
} else if (op == "ac" || op == "AcceptCall") {
|
||||
CallId call_id;
|
||||
get_args(args, call_id);
|
||||
send_request(td_api::make_object<td_api::acceptCall>(
|
||||
as_call_id(args),
|
||||
td_api::make_object<td_api::callProtocol>(true, true, 65, 65, vector<string>{"2.6", "3.0"})));
|
||||
call_id, td_api::make_object<td_api::callProtocol>(true, true, 65, 65, vector<string>{"2.6", "3.0"})));
|
||||
} else if (op == "scsd") {
|
||||
send_request(td_api::make_object<td_api::sendCallSignalingData>(as_call_id(args), "abacaba"));
|
||||
CallId call_id;
|
||||
get_args(args, call_id);
|
||||
send_request(td_api::make_object<td_api::sendCallSignalingData>(call_id, "abacaba"));
|
||||
} else if (op == "dc" || op == "DiscardCall") {
|
||||
string call_id;
|
||||
CallId call_id;
|
||||
bool is_disconnected;
|
||||
get_args(args, call_id, is_disconnected);
|
||||
send_request(td_api::make_object<td_api::discardCall>(as_call_id(call_id), is_disconnected, 0, rand_bool(), 0));
|
||||
send_request(td_api::make_object<td_api::discardCall>(call_id, is_disconnected, 0, rand_bool(), 0));
|
||||
} else if (op == "scr" || op == "SendCallRating") {
|
||||
string call_id;
|
||||
CallId call_id;
|
||||
int32 rating;
|
||||
get_args(args, call_id, rating);
|
||||
vector<td_api::object_ptr<td_api::CallProblem>> problems;
|
||||
@ -3017,10 +3036,17 @@ class CliClient final : public Actor {
|
||||
problems.emplace_back(td_api::make_object<td_api::callProblemEcho>());
|
||||
problems.emplace_back(td_api::make_object<td_api::callProblemPixelatedVideo>());
|
||||
problems.emplace_back(td_api::make_object<td_api::callProblemDistortedSpeech>());
|
||||
send_request(td_api::make_object<td_api::sendCallRating>(
|
||||
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<td_api::sendCallDebugInformation>(as_call_id(args), "{}"));
|
||||
send_request(td_api::make_object<td_api::sendCallRating>(call_id, rating, "Wow, such good call! (TDLib test)",
|
||||
std::move(problems)));
|
||||
} else if (op == "scdi") {
|
||||
CallId call_id;
|
||||
get_args(args, call_id);
|
||||
send_request(td_api::make_object<td_api::sendCallDebugInformation>(call_id, "{}"));
|
||||
} else if (op == "sclog") {
|
||||
CallId call_id;
|
||||
string log_file;
|
||||
get_args(args, call_id, log_file);
|
||||
send_request(td_api::make_object<td_api::sendCallLog>(call_id, as_input_file(log_file)));
|
||||
} else if (op == "gvcap") {
|
||||
ChatId chat_id;
|
||||
get_args(args, chat_id);
|
||||
@ -3047,24 +3073,30 @@ class CliClient final : public Actor {
|
||||
get_args(args, chat_id);
|
||||
send_request(td_api::make_object<td_api::replaceVideoChatRtmpUrl>(chat_id));
|
||||
} else if (op == "ggc") {
|
||||
send_request(td_api::make_object<td_api::getGroupCall>(as_group_call_id(args)));
|
||||
} else if (op == "ggcs") {
|
||||
string group_call_id;
|
||||
GroupCallId group_call_id;
|
||||
get_args(args, group_call_id);
|
||||
send_request(td_api::make_object<td_api::getGroupCallStreams>(as_group_call_id(group_call_id)));
|
||||
send_request(td_api::make_object<td_api::getGroupCall>(group_call_id));
|
||||
} else if (op == "ggcs") {
|
||||
GroupCallId group_call_id;
|
||||
get_args(args, group_call_id);
|
||||
send_request(td_api::make_object<td_api::getGroupCallStreams>(group_call_id));
|
||||
} else if (op == "ggcss") {
|
||||
string group_call_id;
|
||||
GroupCallId group_call_id;
|
||||
int32 channel_id;
|
||||
get_args(args, group_call_id, channel_id);
|
||||
send_request(td_api::make_object<td_api::getGroupCallStreamSegment>(
|
||||
as_group_call_id(group_call_id), (std::time(nullptr) - 5) * 1000, 0, channel_id, nullptr));
|
||||
group_call_id, (std::time(nullptr) - 5) * 1000, 0, channel_id, nullptr));
|
||||
} else if (op == "ssgc") {
|
||||
send_request(td_api::make_object<td_api::startScheduledGroupCall>(as_group_call_id(args)));
|
||||
GroupCallId group_call_id;
|
||||
get_args(args, group_call_id);
|
||||
send_request(td_api::make_object<td_api::startScheduledGroupCall>(group_call_id));
|
||||
} else if (op == "tgcesn" || op == "tgcesne") {
|
||||
send_request(td_api::make_object<td_api::toggleGroupCallEnabledStartNotification>(as_group_call_id(args),
|
||||
op == "tgcesne"));
|
||||
GroupCallId group_call_id;
|
||||
get_args(args, group_call_id);
|
||||
send_request(
|
||||
td_api::make_object<td_api::toggleGroupCallEnabledStartNotification>(group_call_id, op == "tgcesne"));
|
||||
} else if (op == "jgc" || op == "jgcv" || op == "sgcss") {
|
||||
string group_call_id;
|
||||
GroupCallId group_call_id;
|
||||
string participant_id;
|
||||
string invite_hash;
|
||||
get_args(args, group_call_id, participant_id, invite_hash);
|
||||
@ -3090,106 +3122,108 @@ class CliClient final : public Actor {
|
||||
sim_sources + ",\"semantics\":\"SIM\"},{\"sources\":" + fid_sources + ",\"semantics\":\"FID\"}]}";
|
||||
}
|
||||
if (op == "sgcss") {
|
||||
send_request(td_api::make_object<td_api::startGroupCallScreenSharing>(
|
||||
as_group_call_id(group_call_id), group_call_source_ + 1, std::move(payload)));
|
||||
send_request(td_api::make_object<td_api::startGroupCallScreenSharing>(group_call_id, group_call_source_ + 1,
|
||||
std::move(payload)));
|
||||
} else {
|
||||
send_request(td_api::make_object<td_api::joinGroupCall>(as_group_call_id(group_call_id),
|
||||
as_message_sender(participant_id), group_call_source_,
|
||||
std::move(payload), true, true, invite_hash));
|
||||
send_request(td_api::make_object<td_api::joinGroupCall>(group_call_id, as_message_sender(participant_id),
|
||||
group_call_source_, std::move(payload), true, true,
|
||||
invite_hash));
|
||||
}
|
||||
} else if (op == "tgcssip") {
|
||||
string group_call_id;
|
||||
GroupCallId group_call_id;
|
||||
bool is_paused;
|
||||
get_args(args, group_call_id, is_paused);
|
||||
send_request(td_api::make_object<td_api::toggleGroupCallScreenSharingIsPaused>(as_group_call_id(group_call_id),
|
||||
is_paused));
|
||||
send_request(td_api::make_object<td_api::toggleGroupCallScreenSharingIsPaused>(group_call_id, is_paused));
|
||||
} else if (op == "egcss") {
|
||||
const string &group_call_id = args;
|
||||
send_request(td_api::make_object<td_api::endGroupCallScreenSharing>(as_group_call_id(group_call_id)));
|
||||
GroupCallId group_call_id;
|
||||
get_args(args, group_call_id);
|
||||
send_request(td_api::make_object<td_api::endGroupCallScreenSharing>(group_call_id));
|
||||
} else if (op == "sgct") {
|
||||
string group_call_id;
|
||||
GroupCallId group_call_id;
|
||||
string title;
|
||||
get_args(args, group_call_id, title);
|
||||
send_request(td_api::make_object<td_api::setGroupCallTitle>(as_group_call_id(group_call_id), title));
|
||||
send_request(td_api::make_object<td_api::setGroupCallTitle>(group_call_id, title));
|
||||
} else if (op == "tgcmnp" || op == "tgcmnpe") {
|
||||
send_request(
|
||||
td_api::make_object<td_api::toggleGroupCallMuteNewParticipants>(as_group_call_id(args), op == "tgcmnpe"));
|
||||
GroupCallId group_call_id;
|
||||
get_args(args, group_call_id);
|
||||
send_request(td_api::make_object<td_api::toggleGroupCallMuteNewParticipants>(group_call_id, op == "tgcmnpe"));
|
||||
} else if (op == "rgcil") {
|
||||
send_request(td_api::make_object<td_api::revokeGroupCallInviteLink>(as_group_call_id(args)));
|
||||
GroupCallId group_call_id;
|
||||
get_args(args, group_call_id);
|
||||
send_request(td_api::make_object<td_api::revokeGroupCallInviteLink>(group_call_id));
|
||||
} else if (op == "tgcimvp") {
|
||||
string group_call_id;
|
||||
GroupCallId group_call_id;
|
||||
bool is_my_video_paused;
|
||||
get_args(args, group_call_id, is_my_video_paused);
|
||||
send_request(td_api::make_object<td_api::toggleGroupCallIsMyVideoPaused>(as_group_call_id(group_call_id),
|
||||
is_my_video_paused));
|
||||
send_request(td_api::make_object<td_api::toggleGroupCallIsMyVideoPaused>(group_call_id, is_my_video_paused));
|
||||
} else if (op == "tgcimve") {
|
||||
string group_call_id;
|
||||
GroupCallId group_call_id;
|
||||
bool is_my_video_enabled;
|
||||
get_args(args, group_call_id, is_my_video_enabled);
|
||||
send_request(td_api::make_object<td_api::toggleGroupCallIsMyVideoEnabled>(as_group_call_id(group_call_id),
|
||||
is_my_video_enabled));
|
||||
send_request(td_api::make_object<td_api::toggleGroupCallIsMyVideoEnabled>(group_call_id, is_my_video_enabled));
|
||||
} else if (op == "sgcpis") {
|
||||
string group_call_id;
|
||||
GroupCallId group_call_id;
|
||||
int32 source_id;
|
||||
bool is_speaking;
|
||||
get_args(args, group_call_id, source_id, is_speaking);
|
||||
send_request(td_api::make_object<td_api::setGroupCallParticipantIsSpeaking>(as_group_call_id(group_call_id),
|
||||
source_id, is_speaking));
|
||||
send_request(
|
||||
td_api::make_object<td_api::setGroupCallParticipantIsSpeaking>(group_call_id, source_id, is_speaking));
|
||||
} else if (op == "igcp") {
|
||||
string group_call_id;
|
||||
GroupCallId group_call_id;
|
||||
string user_ids;
|
||||
get_args(args, group_call_id, user_ids);
|
||||
send_request(td_api::make_object<td_api::inviteGroupCallParticipants>(as_group_call_id(group_call_id),
|
||||
as_user_ids(user_ids)));
|
||||
send_request(td_api::make_object<td_api::inviteGroupCallParticipants>(group_call_id, as_user_ids(user_ids)));
|
||||
} else if (op == "ggcil") {
|
||||
string group_call_id;
|
||||
GroupCallId group_call_id;
|
||||
bool can_self_unmute;
|
||||
get_args(args, group_call_id, can_self_unmute);
|
||||
send_request(
|
||||
td_api::make_object<td_api::getGroupCallInviteLink>(as_group_call_id(group_call_id), can_self_unmute));
|
||||
send_request(td_api::make_object<td_api::getGroupCallInviteLink>(group_call_id, can_self_unmute));
|
||||
} else if (op == "sgcr") {
|
||||
string group_call_id;
|
||||
GroupCallId group_call_id;
|
||||
string title;
|
||||
bool record_video;
|
||||
bool use_portrait_orientation;
|
||||
get_args(args, group_call_id, title, record_video, use_portrait_orientation);
|
||||
send_request(td_api::make_object<td_api::startGroupCallRecording>(as_group_call_id(group_call_id), title,
|
||||
record_video, use_portrait_orientation));
|
||||
send_request(td_api::make_object<td_api::startGroupCallRecording>(group_call_id, title, record_video,
|
||||
use_portrait_orientation));
|
||||
} else if (op == "egcr") {
|
||||
string group_call_id;
|
||||
GroupCallId group_call_id;
|
||||
get_args(args, group_call_id);
|
||||
send_request(td_api::make_object<td_api::endGroupCallRecording>(as_group_call_id(group_call_id)));
|
||||
send_request(td_api::make_object<td_api::endGroupCallRecording>(group_call_id));
|
||||
} else if (op == "tgcpim") {
|
||||
string group_call_id;
|
||||
GroupCallId group_call_id;
|
||||
string participant_id;
|
||||
bool is_muted;
|
||||
get_args(args, group_call_id, participant_id, is_muted);
|
||||
send_request(td_api::make_object<td_api::toggleGroupCallParticipantIsMuted>(
|
||||
as_group_call_id(group_call_id), as_message_sender(participant_id), is_muted));
|
||||
group_call_id, as_message_sender(participant_id), is_muted));
|
||||
} else if (op == "sgcpvl") {
|
||||
string group_call_id;
|
||||
GroupCallId group_call_id;
|
||||
string participant_id;
|
||||
int32 volume_level;
|
||||
get_args(args, group_call_id, participant_id, volume_level);
|
||||
send_request(td_api::make_object<td_api::setGroupCallParticipantVolumeLevel>(
|
||||
as_group_call_id(group_call_id), as_message_sender(participant_id), volume_level));
|
||||
group_call_id, as_message_sender(participant_id), volume_level));
|
||||
} else if (op == "tgcpihr") {
|
||||
string group_call_id;
|
||||
GroupCallId group_call_id;
|
||||
string participant_id;
|
||||
bool is_hand_raised;
|
||||
get_args(args, group_call_id, participant_id, is_hand_raised);
|
||||
send_request(td_api::make_object<td_api::toggleGroupCallParticipantIsHandRaised>(
|
||||
as_group_call_id(group_call_id), as_message_sender(participant_id), is_hand_raised));
|
||||
group_call_id, as_message_sender(participant_id), is_hand_raised));
|
||||
} else if (op == "lgcp") {
|
||||
string group_call_id;
|
||||
GroupCallId group_call_id;
|
||||
string limit;
|
||||
get_args(args, group_call_id, limit);
|
||||
send_request(
|
||||
td_api::make_object<td_api::loadGroupCallParticipants>(as_group_call_id(group_call_id), as_limit(limit)));
|
||||
send_request(td_api::make_object<td_api::loadGroupCallParticipants>(group_call_id, as_limit(limit)));
|
||||
} else if (op == "lgc") {
|
||||
send_request(td_api::make_object<td_api::leaveGroupCall>(as_group_call_id(args)));
|
||||
GroupCallId group_call_id;
|
||||
get_args(args, group_call_id);
|
||||
send_request(td_api::make_object<td_api::leaveGroupCall>(group_call_id));
|
||||
} else if (op == "egc") {
|
||||
send_request(td_api::make_object<td_api::endGroupCall>(as_group_call_id(args)));
|
||||
GroupCallId group_call_id;
|
||||
get_args(args, group_call_id);
|
||||
send_request(td_api::make_object<td_api::endGroupCall>(group_call_id));
|
||||
} else if (op == "rpcil") {
|
||||
ChatId chat_id;
|
||||
get_args(args, chat_id);
|
||||
|
@ -63,7 +63,7 @@ Result<FileLoader::FileInfo> FileDownloader::init() {
|
||||
if (encryption_key_.is_secure() && !encryption_key_.has_value_hash()) {
|
||||
LOG(ERROR) << "Can't download Secure file with unknown value_hash";
|
||||
}
|
||||
if (remote_.file_type_ == FileType::Secure) {
|
||||
if (remote_.file_type_ == FileType::SecureEncrypted) {
|
||||
size_ = 0;
|
||||
}
|
||||
int32 part_size = 0;
|
||||
|
@ -45,7 +45,7 @@ void FileLoadManager::download(QueryId id, const FullRemoteFileLocation &remote_
|
||||
if (stop_flag_) {
|
||||
return;
|
||||
}
|
||||
CHECK(query_id_to_node_id_.find(id) == query_id_to_node_id_.end());
|
||||
CHECK(query_id_to_node_id_.count(id) == 0);
|
||||
NodeId node_id = nodes_container_.create(Node());
|
||||
Node *node = nodes_container_.get(node_id);
|
||||
CHECK(node);
|
||||
@ -68,7 +68,7 @@ void FileLoadManager::upload(QueryId id, const LocalFileLocation &local_location
|
||||
if (stop_flag_) {
|
||||
return;
|
||||
}
|
||||
CHECK(query_id_to_node_id_.find(id) == query_id_to_node_id_.end());
|
||||
CHECK(query_id_to_node_id_.count(id) == 0);
|
||||
NodeId node_id = nodes_container_.create(Node());
|
||||
Node *node = nodes_container_.get(node_id);
|
||||
CHECK(node);
|
||||
@ -86,7 +86,7 @@ void FileLoadManager::upload_by_hash(QueryId id, const FullLocalFileLocation &lo
|
||||
if (stop_flag_) {
|
||||
return;
|
||||
}
|
||||
CHECK(query_id_to_node_id_.find(id) == query_id_to_node_id_.end());
|
||||
CHECK(query_id_to_node_id_.count(id) == 0);
|
||||
NodeId node_id = nodes_container_.create(Node());
|
||||
Node *node = nodes_container_.get(node_id);
|
||||
CHECK(node);
|
||||
@ -117,7 +117,7 @@ void FileLoadManager::from_bytes(QueryId id, FileType type, BufferSlice bytes, s
|
||||
if (stop_flag_) {
|
||||
return;
|
||||
}
|
||||
CHECK(query_id_to_node_id_.find(id) == query_id_to_node_id_.end());
|
||||
CHECK(query_id_to_node_id_.count(id) == 0);
|
||||
NodeId node_id = nodes_container_.create(Node());
|
||||
Node *node = nodes_container_.get(node_id);
|
||||
CHECK(node);
|
||||
|
@ -192,32 +192,17 @@ class FullRemoteFileLocation {
|
||||
if (is_web()) {
|
||||
return LocationType::Web;
|
||||
}
|
||||
switch (file_type_) {
|
||||
case FileType::Photo:
|
||||
case FileType::ProfilePhoto:
|
||||
case FileType::Thumbnail:
|
||||
case FileType::EncryptedThumbnail:
|
||||
case FileType::Wallpaper:
|
||||
switch (get_file_type_class(file_type_)) {
|
||||
case FileTypeClass::Photo:
|
||||
return LocationType::Photo;
|
||||
case FileType::Video:
|
||||
case FileType::VoiceNote:
|
||||
case FileType::Document:
|
||||
case FileType::Sticker:
|
||||
case FileType::Audio:
|
||||
case FileType::Animation:
|
||||
case FileType::Encrypted:
|
||||
case FileType::VideoNote:
|
||||
case FileType::SecureRaw:
|
||||
case FileType::Secure:
|
||||
case FileType::Background:
|
||||
case FileType::DocumentAsFile:
|
||||
case FileType::Ringtone:
|
||||
case FileTypeClass::Document:
|
||||
case FileTypeClass::Secure:
|
||||
case FileTypeClass::Encrypted:
|
||||
return LocationType::Common;
|
||||
case FileType::None:
|
||||
case FileType::Size:
|
||||
case FileTypeClass::Temp:
|
||||
return LocationType::None;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
case FileType::Temp:
|
||||
return LocationType::None;
|
||||
}
|
||||
}
|
||||
@ -376,13 +361,13 @@ class FullRemoteFileLocation {
|
||||
return file_type_ == FileType::Encrypted;
|
||||
}
|
||||
bool is_encrypted_secure() const {
|
||||
return file_type_ == FileType::Secure;
|
||||
return file_type_ == FileType::SecureEncrypted;
|
||||
}
|
||||
bool is_encrypted_any() const {
|
||||
return is_encrypted_secret() || is_encrypted_secure();
|
||||
}
|
||||
bool is_secure() const {
|
||||
return file_type_ == FileType::SecureRaw || file_type_ == FileType::Secure;
|
||||
return file_type_ == FileType::SecureDecrypted || file_type_ == FileType::SecureEncrypted;
|
||||
}
|
||||
bool is_document() const {
|
||||
return is_common() && !is_secure() && !is_encrypted_secret();
|
||||
|
@ -289,37 +289,7 @@ void FullRemoteFileLocation::AsUnique::store(StorerT &storer) const {
|
||||
if (key->is_web()) {
|
||||
return 0;
|
||||
}
|
||||
switch (key->file_type_) {
|
||||
case FileType::Photo:
|
||||
case FileType::ProfilePhoto:
|
||||
case FileType::Thumbnail:
|
||||
case FileType::EncryptedThumbnail:
|
||||
case FileType::Wallpaper:
|
||||
return 1;
|
||||
case FileType::Video:
|
||||
case FileType::VoiceNote:
|
||||
case FileType::Document:
|
||||
case FileType::Sticker:
|
||||
case FileType::Audio:
|
||||
case FileType::Animation:
|
||||
case FileType::VideoNote:
|
||||
case FileType::Background:
|
||||
case FileType::DocumentAsFile:
|
||||
case FileType::Ringtone:
|
||||
return 2;
|
||||
case FileType::SecureRaw:
|
||||
case FileType::Secure:
|
||||
return 3;
|
||||
case FileType::Encrypted:
|
||||
return 4;
|
||||
case FileType::Temp:
|
||||
return 5;
|
||||
case FileType::None:
|
||||
case FileType::Size:
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return -1;
|
||||
}
|
||||
return static_cast<int32>(get_file_type_class(key->file_type_)) + 1;
|
||||
}();
|
||||
store(type, storer);
|
||||
key.variant_.visit([&](auto &&value) {
|
||||
|
@ -924,9 +924,10 @@ string FileManager::get_file_name(FileType file_type, Slice path) {
|
||||
case FileType::Encrypted:
|
||||
case FileType::Temp:
|
||||
case FileType::EncryptedThumbnail:
|
||||
case FileType::Secure:
|
||||
case FileType::SecureRaw:
|
||||
case FileType::SecureEncrypted:
|
||||
case FileType::SecureDecrypted:
|
||||
case FileType::DocumentAsFile:
|
||||
case FileType::CallLog:
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
@ -2559,8 +2560,7 @@ void FileManager::resume_upload(FileId file_id, std::vector<int> bad_parts, std:
|
||||
node->set_upload_pause(FileId());
|
||||
}
|
||||
FileView file_view(node);
|
||||
if (file_view.has_active_upload_remote_location() && file_view.get_type() != FileType::Thumbnail &&
|
||||
file_view.get_type() != FileType::EncryptedThumbnail && file_view.get_type() != FileType::Background) {
|
||||
if (file_view.has_active_upload_remote_location() && can_reuse_remote_file(file_view.get_type())) {
|
||||
LOG(INFO) << "File " << file_id << " is already uploaded";
|
||||
if (callback) {
|
||||
callback->on_upload_ok(file_id, nullptr);
|
||||
@ -2797,7 +2797,7 @@ void FileManager::run_upload(FileNodePtr node, std::vector<int> bad_parts) {
|
||||
<< ", generate_id = " << node->generate_id_ << ", generate_was_update = " << node->generate_was_update_;
|
||||
return;
|
||||
}
|
||||
if (file_view.has_generate_location() && file_view.generate_location().file_type_ == FileType::Secure) {
|
||||
if (file_view.has_generate_location() && file_view.generate_location().file_type_ == FileType::SecureEncrypted) {
|
||||
// Can't upload secure file before its size is known
|
||||
LOG(INFO) << "Can't upload secure file " << node->main_file_id_ << " before it's size is known";
|
||||
return;
|
||||
@ -2816,7 +2816,7 @@ void FileManager::run_upload(FileNodePtr node, std::vector<int> bad_parts) {
|
||||
}
|
||||
|
||||
// create encryption key if necessary
|
||||
if (file_view.has_local_location() && file_view.local_location().file_type_ == FileType::Secure &&
|
||||
if (file_view.has_local_location() && file_view.local_location().file_type_ == FileType::SecureEncrypted &&
|
||||
file_view.encryption_key().empty()) {
|
||||
CHECK(!node->file_ids_.empty());
|
||||
bool success = set_encryption_key(node->file_ids_[0], FileEncryptionKey::create_secure_key());
|
||||
@ -2832,8 +2832,7 @@ void FileManager::run_upload(FileNodePtr node, std::vector<int> bad_parts) {
|
||||
|
||||
CHECK(node->upload_id_ == 0);
|
||||
if (file_view.has_alive_remote_location() && !file_view.has_active_upload_remote_location() &&
|
||||
file_view.get_type() != FileType::Thumbnail && file_view.get_type() != FileType::EncryptedThumbnail &&
|
||||
file_view.get_type() != FileType::Background) {
|
||||
can_reuse_remote_file(file_view.get_type())) {
|
||||
QueryId id = queries_container_.create(Query{file_id, Query::Type::UploadWaitFileReference});
|
||||
node->upload_id_ = id;
|
||||
if (node->upload_was_update_file_reference_) {
|
||||
@ -2884,12 +2883,6 @@ void FileManager::cancel_upload(FileId file_id) {
|
||||
return resume_upload(file_id, std::vector<int>(), nullptr, 0, 0);
|
||||
}
|
||||
|
||||
static bool is_document_type(FileType type) {
|
||||
return type == FileType::Document || type == FileType::Sticker || type == FileType::Audio ||
|
||||
type == FileType::Animation || type == FileType::VoiceNote || type == FileType::Background ||
|
||||
type == FileType::DocumentAsFile || type == FileType::Ringtone;
|
||||
}
|
||||
|
||||
static bool is_background_type(FileType type) {
|
||||
return type == FileType::Wallpaper || type == FileType::Background;
|
||||
}
|
||||
@ -2963,7 +2956,7 @@ Result<FileId> FileManager::from_persistent_id_v23(Slice binary, FileType file_t
|
||||
return Status::Error(400, "Wrong remote file identifier specified: can't unserialize it");
|
||||
}
|
||||
auto &real_file_type = remote_location.file_type_;
|
||||
if (is_document_type(real_file_type) && is_document_type(file_type)) {
|
||||
if (is_document_file_type(real_file_type) && is_document_file_type(file_type)) {
|
||||
real_file_type = file_type;
|
||||
} else if (is_background_type(real_file_type) && is_background_type(file_type)) {
|
||||
// type of file matches, but real type is in the stored remote location
|
||||
@ -3083,7 +3076,7 @@ Result<FileId> FileManager::check_input_file_id(FileType type, Result<FileId> re
|
||||
LOG(INFO) << "Checking file " << file_id << " of type " << type << "/" << real_type;
|
||||
if (!is_encrypted && !is_secure) {
|
||||
if (real_type != type && !(real_type == FileType::Temp && file_view.has_url()) &&
|
||||
!(is_document_type(real_type) && is_document_type(type)) &&
|
||||
!(is_document_file_type(real_type) && is_document_file_type(type)) &&
|
||||
!(is_background_type(real_type) && is_background_type(type)) &&
|
||||
!(file_view.is_encrypted() && type == FileType::Ringtone)) {
|
||||
// TODO: send encrypted file to unencrypted chat
|
||||
@ -3156,7 +3149,7 @@ Result<FileId> FileManager::get_input_file_id(FileType type, const tl_object_ptr
|
||||
get_by_hash = false;
|
||||
}
|
||||
|
||||
auto new_type = is_encrypted ? FileType::Encrypted : (is_secure ? FileType::Secure : type);
|
||||
auto new_type = is_encrypted ? FileType::Encrypted : (is_secure ? FileType::SecureEncrypted : type);
|
||||
|
||||
auto r_file_id = [&]() -> Result<FileId> {
|
||||
switch (file->get_id()) {
|
||||
@ -3393,13 +3386,14 @@ FileId FileManager::next_file_id() {
|
||||
empty_file_ids_.pop_back();
|
||||
return FileId{res, 0};
|
||||
}
|
||||
CHECK(file_id_info_.size() <= static_cast<size_t>(std::numeric_limits<int32>::max()));
|
||||
FileId res(static_cast<int32>(file_id_info_.size()), 0);
|
||||
// LOG(ERROR) << "NEXT file_id " << res;
|
||||
file_id_info_.push_back({});
|
||||
return res;
|
||||
}
|
||||
|
||||
FileManager::FileNodeId FileManager::next_file_node_id() {
|
||||
CHECK(file_nodes_.size() <= static_cast<size_t>(std::numeric_limits<FileNodeId>::max()));
|
||||
auto res = static_cast<FileNodeId>(file_nodes_.size());
|
||||
file_nodes_.emplace_back(nullptr);
|
||||
return res;
|
||||
@ -3937,6 +3931,10 @@ void FileManager::memory_stats(vector<string> &output) {
|
||||
|
||||
void FileManager::tear_down() {
|
||||
parent_.reset();
|
||||
|
||||
LOG(DEBUG) << "Have " << file_id_info_.size() << " files with " << file_nodes_.size() << " file nodes, "
|
||||
<< local_location_to_file_id_.size() << " local locations and " << remote_location_info_.size()
|
||||
<< " remote locations to free";
|
||||
}
|
||||
|
||||
constexpr int64 FileManager::KEEP_DOWNLOAD_LIMIT;
|
||||
|
@ -305,10 +305,10 @@ class FileView {
|
||||
return get_type() == FileType::Encrypted;
|
||||
}
|
||||
bool is_encrypted_secure() const {
|
||||
return get_type() == FileType::Secure;
|
||||
return get_type() == FileType::SecureEncrypted;
|
||||
}
|
||||
bool is_secure() const {
|
||||
return get_type() == FileType::Secure || get_type() == FileType::SecureRaw;
|
||||
return get_type() == FileType::SecureEncrypted || get_type() == FileType::SecureDecrypted;
|
||||
}
|
||||
bool is_encrypted_any() const {
|
||||
return is_encrypted_secret() || is_encrypted_secure();
|
||||
|
@ -39,7 +39,7 @@ FileType get_file_type(const td_api::FileType &file_type) {
|
||||
case td_api::fileTypeVideoNote::ID:
|
||||
return FileType::VideoNote;
|
||||
case td_api::fileTypeSecure::ID:
|
||||
return FileType::Secure;
|
||||
return FileType::SecureEncrypted;
|
||||
case td_api::fileTypeNotificationSound::ID:
|
||||
return FileType::Ringtone;
|
||||
case td_api::fileTypeNone::ID:
|
||||
@ -80,9 +80,9 @@ tl_object_ptr<td_api::FileType> get_file_type_object(FileType file_type) {
|
||||
return make_tl_object<td_api::fileTypeWallpaper>();
|
||||
case FileType::VideoNote:
|
||||
return make_tl_object<td_api::fileTypeVideoNote>();
|
||||
case FileType::Secure:
|
||||
case FileType::SecureEncrypted:
|
||||
return make_tl_object<td_api::fileTypeSecure>();
|
||||
case FileType::SecureRaw:
|
||||
case FileType::SecureDecrypted:
|
||||
UNREACHABLE();
|
||||
return make_tl_object<td_api::fileTypeSecure>();
|
||||
case FileType::Background:
|
||||
@ -91,6 +91,8 @@ tl_object_ptr<td_api::FileType> get_file_type_object(FileType file_type) {
|
||||
return make_tl_object<td_api::fileTypeDocument>();
|
||||
case FileType::Ringtone:
|
||||
return make_tl_object<td_api::fileTypeNotificationSound>();
|
||||
case FileType::CallLog:
|
||||
return make_tl_object<td_api::fileTypeDocument>();
|
||||
case FileType::None:
|
||||
return make_tl_object<td_api::fileTypeNone>();
|
||||
default:
|
||||
@ -103,10 +105,12 @@ FileType get_main_file_type(FileType file_type) {
|
||||
switch (file_type) {
|
||||
case FileType::Wallpaper:
|
||||
return FileType::Background;
|
||||
case FileType::SecureRaw:
|
||||
return FileType::Secure;
|
||||
case FileType::SecureDecrypted:
|
||||
return FileType::SecureEncrypted;
|
||||
case FileType::DocumentAsFile:
|
||||
return FileType::Document;
|
||||
case FileType::CallLog:
|
||||
return FileType::Document;
|
||||
default:
|
||||
return file_type;
|
||||
}
|
||||
@ -142,9 +146,9 @@ CSlice get_file_type_name(FileType file_type) {
|
||||
return CSlice("wallpapers");
|
||||
case FileType::VideoNote:
|
||||
return CSlice("video_notes");
|
||||
case FileType::SecureRaw:
|
||||
case FileType::SecureDecrypted:
|
||||
return CSlice("passport");
|
||||
case FileType::Secure:
|
||||
case FileType::SecureEncrypted:
|
||||
return CSlice("passport");
|
||||
case FileType::Background:
|
||||
return CSlice("wallpapers");
|
||||
@ -152,6 +156,8 @@ CSlice get_file_type_name(FileType file_type) {
|
||||
return CSlice("documents");
|
||||
case FileType::Ringtone:
|
||||
return CSlice("notification_sounds");
|
||||
case FileType::CallLog:
|
||||
return CSlice("documents");
|
||||
case FileType::Size:
|
||||
case FileType::None:
|
||||
default:
|
||||
@ -160,6 +166,45 @@ CSlice get_file_type_name(FileType file_type) {
|
||||
}
|
||||
}
|
||||
|
||||
FileTypeClass get_file_type_class(FileType file_type) {
|
||||
switch (file_type) {
|
||||
case FileType::Photo:
|
||||
case FileType::ProfilePhoto:
|
||||
case FileType::Thumbnail:
|
||||
case FileType::EncryptedThumbnail:
|
||||
case FileType::Wallpaper:
|
||||
return FileTypeClass::Photo;
|
||||
case FileType::Video:
|
||||
case FileType::VoiceNote:
|
||||
case FileType::Document:
|
||||
case FileType::Sticker:
|
||||
case FileType::Audio:
|
||||
case FileType::Animation:
|
||||
case FileType::VideoNote:
|
||||
case FileType::Background:
|
||||
case FileType::DocumentAsFile:
|
||||
case FileType::Ringtone:
|
||||
case FileType::CallLog:
|
||||
return FileTypeClass::Document;
|
||||
case FileType::SecureDecrypted:
|
||||
case FileType::SecureEncrypted:
|
||||
return FileTypeClass::Secure;
|
||||
case FileType::Encrypted:
|
||||
return FileTypeClass::Encrypted;
|
||||
case FileType::Temp:
|
||||
return FileTypeClass::Temp;
|
||||
case FileType::None:
|
||||
case FileType::Size:
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return FileTypeClass::Temp;
|
||||
}
|
||||
}
|
||||
|
||||
bool is_document_file_type(FileType file_type) {
|
||||
return get_file_type_class(file_type) == FileTypeClass::Document;
|
||||
}
|
||||
|
||||
StringBuilder &operator<<(StringBuilder &string_builder, FileType file_type) {
|
||||
return string_builder << get_file_type_name(file_type);
|
||||
}
|
||||
@ -173,8 +218,8 @@ FileDirType get_file_dir_type(FileType file_type) {
|
||||
case FileType::Temp:
|
||||
case FileType::Wallpaper:
|
||||
case FileType::EncryptedThumbnail:
|
||||
case FileType::Secure:
|
||||
case FileType::SecureRaw:
|
||||
case FileType::SecureEncrypted:
|
||||
case FileType::SecureDecrypted:
|
||||
case FileType::Background:
|
||||
case FileType::Ringtone:
|
||||
return FileDirType::Secure;
|
||||
@ -191,6 +236,7 @@ bool is_file_big(FileType file_type, int64 expected_size) {
|
||||
case FileType::EncryptedThumbnail:
|
||||
case FileType::VideoNote:
|
||||
case FileType::Ringtone:
|
||||
case FileType::CallLog:
|
||||
return false;
|
||||
default:
|
||||
break;
|
||||
@ -200,4 +246,16 @@ bool is_file_big(FileType file_type, int64 expected_size) {
|
||||
return expected_size > SMALL_FILE_MAX_SIZE;
|
||||
}
|
||||
|
||||
bool can_reuse_remote_file(FileType file_type) {
|
||||
switch (file_type) {
|
||||
case FileType::Thumbnail:
|
||||
case FileType::EncryptedThumbnail:
|
||||
case FileType::Background:
|
||||
case FileType::CallLog:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace td
|
||||
|
@ -29,11 +29,12 @@ enum class FileType : int32 {
|
||||
EncryptedThumbnail,
|
||||
Wallpaper,
|
||||
VideoNote,
|
||||
SecureRaw,
|
||||
Secure,
|
||||
SecureDecrypted,
|
||||
SecureEncrypted,
|
||||
Background,
|
||||
DocumentAsFile,
|
||||
Ringtone,
|
||||
CallLog,
|
||||
Size,
|
||||
None
|
||||
};
|
||||
@ -50,10 +51,18 @@ FileType get_main_file_type(FileType file_type);
|
||||
|
||||
CSlice get_file_type_name(FileType file_type);
|
||||
|
||||
enum class FileTypeClass : int32 { Photo, Document, Secure, Encrypted, Temp };
|
||||
|
||||
FileTypeClass get_file_type_class(FileType file_type);
|
||||
|
||||
bool is_document_file_type(FileType file_type);
|
||||
|
||||
StringBuilder &operator<<(StringBuilder &string_builder, FileType file_type);
|
||||
|
||||
FileDirType get_file_dir_type(FileType file_type);
|
||||
|
||||
bool is_file_big(FileType file_type, int64 expected_size);
|
||||
|
||||
bool can_reuse_remote_file(FileType file_type);
|
||||
|
||||
} // namespace td
|
||||
|
@ -52,7 +52,7 @@ struct NetworkStats {
|
||||
result->since_date_ = since;
|
||||
result->entries_.reserve(entries.size());
|
||||
for (const auto &entry : entries) {
|
||||
if ((entry.rx != 0 || entry.tx != 0) && entry.file_type != FileType::SecureRaw) {
|
||||
if ((entry.rx != 0 || entry.tx != 0) && entry.file_type != FileType::SecureDecrypted) {
|
||||
result->entries_.push_back(entry.get_network_statistics_entry_object());
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@
|
||||
namespace td {
|
||||
|
||||
bool MultiTimeout::has_timeout(int64 key) const {
|
||||
return items_.find(Item(key)) != items_.end();
|
||||
return items_.count(Item(key)) > 0;
|
||||
}
|
||||
|
||||
void MultiTimeout::set_timeout_at(int64 key, double timeout) {
|
||||
|
@ -37,6 +37,11 @@ class Enumerator {
|
||||
return *arr_[pos];
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
CHECK(map_.size() == arr_.size());
|
||||
return arr_.size();
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<ValueT, int32> map_;
|
||||
std::vector<const ValueT *> arr_;
|
||||
|
@ -211,7 +211,7 @@ std::pair<size_t, vector<Hints::KeyT>> Hints::search(Slice query, int32 limit, b
|
||||
}
|
||||
|
||||
bool Hints::has_key(KeyT key) const {
|
||||
return key_to_name_.find(key) != key_to_name_.end();
|
||||
return key_to_name_.count(key) > 0;
|
||||
}
|
||||
|
||||
string Hints::key_to_string(KeyT key) const {
|
||||
|
@ -159,8 +159,8 @@ string clean_filename(CSlice name) {
|
||||
}
|
||||
|
||||
PathView path_view(name);
|
||||
auto filename = clean_filename_part(path_view.file_stem(), 60);
|
||||
auto extension = clean_filename_part(path_view.extension(), 20);
|
||||
auto filename = clean_filename_part(path_view.file_stem(), 64);
|
||||
auto extension = clean_filename_part(path_view.extension(), 16);
|
||||
if (!extension.empty()) {
|
||||
if (filename.empty()) {
|
||||
filename = std::move(extension);
|
||||
|
@ -391,7 +391,7 @@ static Status create_local_lock(const string &path, int32 &max_tries) {
|
||||
while (true) {
|
||||
{ // mutex lock scope
|
||||
std::lock_guard<std::mutex> lock(in_process_lock_mutex);
|
||||
if (!path.empty() && locked_files.find(path) == locked_files.end()) {
|
||||
if (!path.empty() && locked_files.count(path) == 0) {
|
||||
VLOG(fd) << "Lock file \"" << path << '"';
|
||||
locked_files.insert(path);
|
||||
return Status::OK();
|
||||
|
Loading…
Reference in New Issue
Block a user