#![cfg_attr(docsrs, feature(doc_cfg))]
#![deny(unsafe_code)]
pub mod builder;
mod client;
mod dialog;
mod envelope;
mod errors;
mod input_message;
pub mod media;
pub use media::DownloadIter;
pub mod message_box;
mod mini_app;
#[cfg(feature = "parsers")]
pub mod parsers;
pub mod participants;
mod peer_cache;
pub mod persist;
mod quick_connect;
mod restart;
mod retry;
mod session;
mod two_factor_auth;
pub mod update;
pub mod cdn_download;
pub mod conversation;
pub mod dc_pool;
pub mod dns_resolver;
pub mod filters;
pub mod inline_iter;
pub mod keyboard;
pub mod search;
pub mod session_backend;
pub mod socks5;
pub mod special_config;
pub use ferogram_connect::{
FullTransport, IntermediateTransport, ObfuscatedFraming, ObfuscatedStream,
PaddedIntermediateTransport,
};
pub mod types;
pub mod typing_guard;
#[macro_use]
pub mod macros;
pub mod guest_chat;
pub mod peer_ext;
pub mod peer_ref;
pub mod poll;
pub mod reactions;
pub mod dc_migration;
pub mod proxy;
pub mod file_info;
#[cfg(feature = "fsm")]
pub mod fsm;
pub mod middleware;
#[cfg(feature = "experimental")]
pub mod resume;
pub mod transfer;
pub mod update_config;
pub mod util;
pub(crate) mod builder_util;
pub mod string_session {
pub use ferogram_session::string_session::{
FullSession, Session, StringSession, StringSessionError,
};
}
#[cfg(feature = "fsm")]
pub use fsm::FsmState;
#[cfg(feature = "derive")]
#[cfg_attr(docsrs, doc(cfg(feature = "derive")))]
pub use ferogram_derive::FsmState;
pub use builder::{BuilderError, ClientBuilder};
pub use client::Client;
pub use client::{Config, ShutdownToken, UpdateStream};
pub use dialog::{Dialog, DialogIter, MessageIter};
pub use errors::{
ErrorKind, InvocationError, InvocationErrorExt, LoginToken, PasswordToken, RpcError,
SignInError,
};
pub use ferogram_connect::TransportKind;
pub use ferogram_connect::random_i64 as random_i64_pub;
pub use file_info::{FileInfo, detect_mime, file_info, file_info_from_path};
pub use guest_chat::GuestChatQuery;
pub use input_message::{ForwardOptions, InputMessage, InvoiceOptions, LinkKind};
pub use keyboard::{Button, InlineKeyboard, ReplyKeyboard};
pub use media::{Document, Downloadable, Photo, Sticker, UploadedFile};
pub use mini_app::{MiniApp, MiniAppSession};
pub use participants::{Participant, ParticipantStatus, ProfilePhotoIter};
pub use peer_cache::{ExperimentalFeatures, PeerCache, PeerType};
pub use peer_ext::{OptionPeerExt, PeerExt};
pub use peer_ref::PeerRef;
pub use poll::PollBuilder;
pub use proxy::{MtProxyConfig, parse_proxy_link};
pub use quick_connect::QuickConnectError;
pub use restart::{ConnectionRestartPolicy, ExponentialBackoff, FixedInterval, NeverRestart};
pub use retry::{AutoSleep, CircuitBreaker, NoRetries, RetryContext, RetryPolicy};
pub use search::{GlobalSearchBuilder, SearchBuilder};
pub use session::{DcEntry, DcFlags};
#[cfg(feature = "libsql-session")]
#[cfg_attr(docsrs, doc(cfg(feature = "libsql-session")))]
pub use session_backend::LibSqlBackend;
#[cfg(feature = "sqlite-session")]
#[cfg_attr(docsrs, doc(cfg(feature = "sqlite-session")))]
pub use session_backend::SqliteBackend;
pub use session_backend::{
BinaryFileBackend, InMemoryBackend, SessionBackend, StringSessionBackend, UpdateStateChange,
};
pub use socks5::Socks5Config;
pub use transfer::{TransferError, TransferHandle, TransferProgress};
pub use types::{Channel, ChannelKind, Chat, Group, User};
pub use typing_guard::TypingGuard;
pub use update::{BotStoppedUpdate, MessageReactionUpdate, PollVoteUpdate};
pub use update::{ButtonFilter, Update};
pub use update::{ChatActionUpdate, JoinRequestUpdate, ParticipantUpdate, UserStatusUpdate};
pub use update::{ChatBoostUpdate, PreCheckoutQueryUpdate, ShippingQueryUpdate};
pub use update_config::{OverflowStrategy, UpdateConfig};
pub use ferogram_tl_types as tl;
pub use ferogram_mtproto as mtproto;
pub use ferogram_crypto as crypto;
#[cfg(feature = "parser")]
pub use ferogram_tl_parser as parser;
#[cfg(feature = "codegen")]
pub use ferogram_tl_gen as codegen;
pub use ferogram_crypto::AuthKey;
pub use ferogram_mtproto::authentication::{self, Finished, finish, step1, step2, step3};
pub use ferogram_tl_types::{Identifiable, LAYER, Serializable};
pub enum ChannelStats {
Broadcast(tl::enums::stats::BroadcastStats),
Megagroup(tl::enums::stats::MegagroupStats),
}
pub struct SetProfileBuilder {
client: Client,
peer: PeerRef,
first_name: Option<String>,
last_name: Option<String>,
bio: Option<String>,
emoji_status: Option<(Option<i64>, Option<i32>)>,
title: Option<String>,
about: Option<String>,
chat_photo: Option<tl::enums::InputChatPhoto>,
username: Option<String>,
photo: Option<media::UploadedFile>,
photo_path: Option<std::path::PathBuf>,
}
impl SetProfileBuilder {
#[doc(hidden)]
pub fn new(client: Client, peer: PeerRef) -> Self {
Self {
client,
peer,
first_name: None,
last_name: None,
bio: None,
emoji_status: None,
title: None,
about: None,
chat_photo: None,
username: None,
photo: None,
photo_path: None,
}
}
pub fn name(mut self, first: impl Into<String>, last: impl Into<String>) -> Self {
self.first_name = Some(first.into());
self.last_name = Some(last.into());
self
}
pub fn bio(mut self, bio: impl Into<String>) -> Self {
self.bio = Some(bio.into());
self
}
pub fn username(mut self, u: impl Into<String>) -> Self {
self.username = Some(u.into());
self
}
pub fn photo(mut self, file: media::UploadedFile) -> Self {
self.photo = Some(file);
self
}
pub fn photo_path(mut self, path: impl Into<std::path::PathBuf>) -> Self {
self.photo_path = Some(path.into());
self
}
pub fn emoji_status(mut self, document_id: Option<i64>, until: Option<i32>) -> Self {
self.emoji_status = Some((document_id, until));
self
}
pub fn title(mut self, t: impl Into<String>) -> Self {
self.title = Some(t.into());
self
}
pub fn about(mut self, a: impl Into<String>) -> Self {
self.about = Some(a.into());
self
}
pub fn chat_photo(mut self, p: tl::enums::InputChatPhoto) -> Self {
self.chat_photo = Some(p);
self
}
pub async fn send(mut self) -> Result<(), InvocationError> {
use ferogram_tl_types as tl;
if let Some(path) = self.photo_path.take() {
let uploaded = self.client.upload_file(path).await?;
self.photo = Some(uploaded);
}
let peer = self.peer.resolve(&self.client).await?;
let input_peer = self
.client
.inner
.peer_cache
.read()
.await
.peer_to_input(&peer)?;
let is_channel_or_chat = matches!(
&input_peer,
tl::enums::InputPeer::Channel(_) | tl::enums::InputPeer::Chat(_)
);
if is_channel_or_chat {
let effective_title = self.title.or(self.first_name);
if let Some(t) = effective_title {
match &input_peer {
tl::enums::InputPeer::Channel(c) => {
let req = tl::functions::channels::EditTitle {
channel: tl::enums::InputChannel::InputChannel(
tl::types::InputChannel {
channel_id: c.channel_id,
access_hash: c.access_hash,
},
),
title: t,
};
self.client.rpc_write(&req).await?;
}
tl::enums::InputPeer::Chat(c) => {
let req = tl::functions::messages::EditChatTitle {
chat_id: c.chat_id,
title: t,
};
self.client.rpc_write(&req).await?;
}
_ => {}
}
}
let effective_about = self.about.or(self.bio);
if let Some(a) = effective_about {
let req = tl::functions::messages::EditChatAbout {
peer: input_peer.clone(),
about: a,
};
self.client.rpc_write(&req).await?;
}
if let Some(u) = self.username {
let req = tl::functions::account::UpdateUsername { username: u };
self.client.rpc_write(&req).await?;
}
if let Some(file) = self.photo {
if let Some(chat_photo) = self.chat_photo {
match &input_peer {
tl::enums::InputPeer::Channel(c) => {
let req = tl::functions::channels::EditPhoto {
channel: tl::enums::InputChannel::InputChannel(
tl::types::InputChannel {
channel_id: c.channel_id,
access_hash: c.access_hash,
},
),
photo: chat_photo,
};
self.client.rpc_write(&req).await?;
}
tl::enums::InputPeer::Chat(c) => {
let req = tl::functions::messages::EditChatPhoto {
chat_id: c.chat_id,
photo: chat_photo,
};
self.client.rpc_write(&req).await?;
}
_ => {}
}
} else {
let chat_photo = tl::enums::InputChatPhoto::InputChatUploadedPhoto(
tl::types::InputChatUploadedPhoto {
video: None,
file: Some(file.inner),
video_start_ts: None,
video_emoji_markup: None,
},
);
match &input_peer {
tl::enums::InputPeer::Channel(c) => {
let req = tl::functions::channels::EditPhoto {
channel: tl::enums::InputChannel::InputChannel(
tl::types::InputChannel {
channel_id: c.channel_id,
access_hash: c.access_hash,
},
),
photo: chat_photo,
};
self.client.rpc_write(&req).await?;
}
tl::enums::InputPeer::Chat(c) => {
let req = tl::functions::messages::EditChatPhoto {
chat_id: c.chat_id,
photo: chat_photo,
};
self.client.rpc_write(&req).await?;
}
_ => {}
}
}
} else if let Some(chat_photo) = self.chat_photo {
match &input_peer {
tl::enums::InputPeer::Channel(c) => {
let req = tl::functions::channels::EditPhoto {
channel: tl::enums::InputChannel::InputChannel(
tl::types::InputChannel {
channel_id: c.channel_id,
access_hash: c.access_hash,
},
),
photo: chat_photo,
};
self.client.rpc_write(&req).await?;
}
tl::enums::InputPeer::Chat(c) => {
let req = tl::functions::messages::EditChatPhoto {
chat_id: c.chat_id,
photo: chat_photo,
};
self.client.rpc_write(&req).await?;
}
_ => {}
}
}
} else {
if self.first_name.is_some() || self.last_name.is_some() || self.bio.is_some() {
let req = tl::functions::account::UpdateProfile {
first_name: self.first_name,
last_name: self.last_name,
about: self.bio,
};
self.client.rpc_write(&req).await?;
}
if let Some(u) = self.username {
let req = tl::functions::account::UpdateUsername { username: u };
self.client.rpc_write(&req).await?;
}
if let Some(file) = self.photo {
let req = tl::functions::photos::UploadProfilePhoto {
fallback: false,
bot: None,
file: Some(file.inner),
video: None,
video_start_ts: None,
video_emoji_markup: None,
};
self.client.rpc_write(&req).await?;
}
if let Some((doc_id, until)) = self.emoji_status {
let emoji_status = match doc_id {
None => tl::enums::EmojiStatus::Empty,
Some(id) => tl::enums::EmojiStatus::EmojiStatus(tl::types::EmojiStatus {
document_id: id,
until,
}),
};
let req = tl::functions::account::UpdateEmojiStatus { emoji_status };
self.client.rpc_write(&req).await?;
}
}
Ok(())
}
}