Merge remote-tracking branch 'td/master'

This commit is contained in:
Andrea Cavalli 2022-05-04 17:49:23 +02:00
commit 4cd31ceb93
50 changed files with 1058 additions and 674 deletions

View File

@ -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.');

View File

@ -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

View File

@ -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>;

View File

@ -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 {

View File

@ -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) {
LOG(ERROR) << "Receive wrong attachment menu bot icon \"" << name << "\" for " << user_id;
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;

View File

@ -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());
}
call_state_.need_rating = false;
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());
}
call_state_.need_debug_information = false;
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_;

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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,20 +4662,26 @@ tl_object_ptr<telegram_api::inputEncryptedChat> ContactsManager::get_input_encry
return make_tl_object<telegram_api::inputEncryptedChat>(secret_chat_id.get(), sc->access_hash);
}
void ContactsManager::apply_pending_user_photo(User *u, UserId user_id) {
if (u == nullptr || u->is_photo_inited) {
return;
}
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");
pending_user_photos_.erase(it);
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;
}
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");
pending_user_photos_.erase(it);
update_user(u, user_id);
}
}
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));
on_update_chat_photo(c, get_dialog_photo(td_->file_manager_.get(), DialogId(chat_id), 0, std::move(chat_photo_ptr)));
}
void ContactsManager::on_update_chat_photo(Chat *c, DialogPhoto &&photo) {
if (td_->auth_manager_->is_bot()) {
new_chat_photo.minithumbnail.clear();
photo.minithumbnail.clear();
}
if (new_chat_photo != c->photo) {
c->photo = new_chat_photo;
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));
on_update_channel_photo(
c, get_dialog_photo(td_->file_manager_.get(), DialogId(channel_id), c->access_hash, std::move(chat_photo_ptr)));
}
void ContactsManager::on_update_channel_photo(Channel *c, DialogPhoto &&photo) {
if (td_->auth_manager_->is_bot()) {
new_chat_photo.minithumbnail.clear();
photo.minithumbnail.clear();
}
if (new_chat_photo != c->photo) {
c->photo = new_chat_photo;
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) {

View File

@ -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);

View File

@ -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);

View File

@ -2435,36 +2435,30 @@ 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: {
vector<tl_object_ptr<telegram_api::DocumentAttribute>> attributes;
auto file_path = file_view.suggested_path();
const PathView path_view(file_path);
Slice file_name = path_view.file_name();
if (!file_name.empty()) {
attributes.push_back(make_tl_object<telegram_api::documentAttributeFilename>(file_name.str()));
}
string mime_type = MimeType::from_extension(path_view.extension());
int32 flags = 0;
if (file_type == FileType::Video) {
flags |= telegram_api::inputMediaUploadedDocument::NOSOUND_VIDEO_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);
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);
Slice file_name = path_view.file_name();
if (!file_name.empty()) {
attributes.push_back(make_tl_object<telegram_api::documentAttributeFilename>(file_name.str()));
}
case FileType::Photo:
return make_tl_object<telegram_api::inputMediaUploadedPhoto>(
0, std::move(input_file), vector<tl_object_ptr<telegram_api::InputDocument>>(), 0);
default:
UNREACHABLE();
string mime_type = MimeType::from_extension(path_view.extension());
int32 flags = 0;
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);
} 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);
}
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();
}

View File

@ -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);

View File

@ -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) {

View File

@ -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);

View File

@ -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;
return;
}
break;
}
case DialogType::Channel:
// the message will be added after get_channel_difference_if_needed
break;
case DialogType::SecretChat:
default:
UNREACHABLE();
break;
const Dialog *d = get_dialog(dialog_id);
if (d == nullptr) {
LOG(INFO) << "Ignore updateMessageReaction in unknown " << dialog_id;
return;
}
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");
// 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;
}
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:
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"));
}
} else {
if (is_broadcast_channel(dialog_id)) {
return promise.set_error(Status::Error(400, "Can't delete chat history in a channel"));
}
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"));
}
auto can_delete = can_delete_dialog(d);
if (revoke) {
if (!can_delete.for_all_users_) {
if (!can_delete.for_self_) {
return promise.set_error(Status::Error(400, "Chat history can't be deleted"));
}
break;
case DialogType::SecretChat:
// ok
break;
case DialogType::None:
default:
UNREACHABLE();
break;
LOG(INFO) << "Can't delete history of " << dialog_id << " for everyone; delete it only for self";
revoke = false;
}
} else {
if (!can_delete.for_self_) {
return promise.set_error(
Status::Error(400, PSLICE() << "Can't delete history of " << dialog_id << " only for self"));
}
}
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;
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();
auto dialog_id = ContactsManager::get_dialog_id(chat);
if (!dialog_id.is_valid()) {
LOG(ERROR) << "Receive invalid " << to_string(chat);
continue;
}
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) {

View File

@ -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_

View File

@ -204,7 +204,7 @@ void NotificationManager::start_up() {
}
void NotificationManager::init() {
if (is_disabled()) {
if (is_disabled() || is_inited_) {
return;
}

View File

@ -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) {

View File

@ -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);

View File

@ -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;

View File

@ -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,

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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();

View File

@ -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);

View File

@ -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 =

View File

@ -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_);

View File

@ -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);

View File

@ -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,19 +1194,12 @@ 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 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));
}
auto channel_id = ContactsManager::get_channel_id(chat);
if (channel_id.is_valid()) {
dialog_ids.push_back(DialogId(channel_id));
continue;
}
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));
}

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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();

View File

@ -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) {

View File

@ -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;

View File

@ -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();

View File

@ -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

View File

@ -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

View File

@ -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());
}
}

View File

@ -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) {

View File

@ -129,7 +129,7 @@ void HttpConnectionBase::loop() {
live_event();
state_ = State::Write;
if (res.error().code() == 500) {
LOG(WARNING) << "Failed to process an HTTP query:" << res.error();
LOG(WARNING) << "Failed to process an HTTP query: " << res.error();
} else {
LOG(INFO) << res.error();
}

View File

@ -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_;

View File

@ -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 {

View File

@ -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);

View File

@ -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();