Skip to main content

rustigram_types/
message.rs

1use serde::{Deserialize, Serialize};
2
3use crate::chat::{Chat, Location, Venue};
4use crate::checklist::{Checklist, ChecklistTasksAdded, ChecklistTasksDone};
5use crate::direct_messages::{
6    DirectMessagePriceChanged, DirectMessagesTopic, PaidMessagePriceChanged,
7};
8use crate::file::{Animation, Audio, Document, PhotoSize, Video, VideoNote, Voice};
9use crate::keyboard::InlineKeyboardMarkup;
10use crate::managed_bot::ManagedBotCreated;
11use crate::poll::{Poll, PollOptionAdded, PollOptionDeleted};
12use crate::sticker::Sticker;
13use crate::suggested_post::{
14    SuggestedPostApprovalFailed, SuggestedPostApproved, SuggestedPostDeclined, SuggestedPostInfo,
15    SuggestedPostPaid, SuggestedPostRefunded,
16};
17use crate::user::User;
18
19/// A Telegram message.
20///
21/// Only fields that were actually sent will be `Some`. Consult the
22/// official Bot API documentation for field availability rules.
23#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct Message {
25    /// Unique message identifier inside this chat.
26    pub message_id: i64,
27
28    /// Optional — unique identifier of a message thread to which the message belongs.
29    #[serde(skip_serializing_if = "Option::is_none")]
30    pub message_thread_id: Option<i64>,
31
32    /// Information about the direct messages chat topic that contains the message.
33    #[serde(skip_serializing_if = "Option::is_none")]
34    pub direct_messages_topic: Option<DirectMessagesTopic>,
35
36    /// Sender of the message; empty for messages sent to channels.
37    #[serde(skip_serializing_if = "Option::is_none")]
38    pub from: Option<User>,
39
40    /// Sender of the message; empty for messages sent to channels or on behalf of a chat.
41    #[serde(skip_serializing_if = "Option::is_none")]
42    pub sender_chat: Option<Chat>,
43
44    /// For supergroup messages — boost count of the sender.
45    #[serde(skip_serializing_if = "Option::is_none")]
46    pub sender_boost_count: Option<u32>,
47
48    /// The bot that actually sent the message on behalf of the business account.
49    #[serde(skip_serializing_if = "Option::is_none")]
50    pub sender_business_bot: Option<User>,
51
52    /// Tag or custom title of the sender; for supergroups only (Bot API 9.5).
53    #[serde(skip_serializing_if = "Option::is_none")]
54    pub sender_tag: Option<String>,
55
56    /// Date the message was sent, as a Unix timestamp.
57    pub date: i64,
58
59    /// Unique identifier of the business connection from which the message was received.
60    #[serde(skip_serializing_if = "Option::is_none")]
61    pub business_connection_id: Option<String>,
62
63    /// Conversation the message belongs to.
64    pub chat: Chat,
65
66    /// Information about the original message for forwarded messages.
67    #[serde(skip_serializing_if = "Option::is_none")]
68    pub forward_origin: Option<MessageOrigin>,
69
70    /// `true` if the message is sent to a forum topic.
71    #[serde(skip_serializing_if = "Option::is_none")]
72    pub is_topic_message: Option<bool>,
73
74    /// `true` if the message is a channel post automatically forwarded to the
75    /// connected discussion group.
76    #[serde(skip_serializing_if = "Option::is_none")]
77    pub is_automatic_forward: Option<bool>,
78
79    /// For replies in the same chat and message thread, the original message.
80    #[serde(skip_serializing_if = "Option::is_none")]
81    pub reply_to_message: Option<Box<Message>>,
82
83    /// Information about the message that is being replied to from another chat or topic.
84    #[serde(skip_serializing_if = "Option::is_none")]
85    pub external_reply: Option<ExternalReplyInfo>,
86
87    /// For replies that quote part of the original message, the quoted part.
88    #[serde(skip_serializing_if = "Option::is_none")]
89    pub quote: Option<TextQuote>,
90
91    /// For replies to a story, the original story.
92    #[serde(skip_serializing_if = "Option::is_none")]
93    pub reply_to_story: Option<serde_json::Value>,
94
95    /// Identifier of the checklist task being replied to.
96    #[serde(skip_serializing_if = "Option::is_none")]
97    pub reply_to_checklist_task_id: Option<i64>,
98
99    /// Persistent identifier of the poll option being replied to.
100    #[serde(skip_serializing_if = "Option::is_none")]
101    pub reply_to_poll_option_id: Option<String>,
102
103    /// Bot through which the message was sent.
104    #[serde(skip_serializing_if = "Option::is_none")]
105    pub via_bot: Option<User>,
106
107    /// Date the message was last edited, as a Unix timestamp.
108    #[serde(skip_serializing_if = "Option::is_none")]
109    pub edit_date: Option<i64>,
110
111    /// `true` if the message can't be forwarded.
112    #[serde(skip_serializing_if = "Option::is_none")]
113    pub has_protected_content: Option<bool>,
114
115    /// `true` if the message was sent by an implicit action.
116    #[serde(skip_serializing_if = "Option::is_none")]
117    pub is_from_offline: Option<bool>,
118
119    /// `true` if the message is a paid post.
120    ///
121    /// Paid posts must not be deleted for 24 hours after sending and cannot be edited.
122    #[serde(skip_serializing_if = "Option::is_none")]
123    pub is_paid_post: Option<bool>,
124
125    /// The unique identifier of a media message group this message belongs to.
126    #[serde(skip_serializing_if = "Option::is_none")]
127    pub media_group_id: Option<String>,
128
129    /// Signature of the post author for messages in channels.
130    #[serde(skip_serializing_if = "Option::is_none")]
131    pub author_signature: Option<String>,
132
133    /// Number of Telegram Stars paid by the sender to send this message.
134    #[serde(skip_serializing_if = "Option::is_none")]
135    pub paid_star_count: Option<i64>,
136
137    /// Actual UTF-8 text of the message (0–4096 characters).
138    #[serde(skip_serializing_if = "Option::is_none")]
139    pub text: Option<String>,
140
141    /// Special entities like usernames, URLs, bot commands, etc.
142    #[serde(skip_serializing_if = "Option::is_none")]
143    pub entities: Option<Vec<MessageEntity>>,
144
145    /// Options used for link preview generation.
146    #[serde(skip_serializing_if = "Option::is_none")]
147    pub link_preview_options: Option<LinkPreviewOptions>,
148
149    /// Information about a suggested post; present when the message is a suggested
150    /// post in a channel direct messages chat.
151    #[serde(skip_serializing_if = "Option::is_none")]
152    pub suggested_post_info: Option<SuggestedPostInfo>,
153
154    /// Unique identifier of the message effect added to the message.
155    #[serde(skip_serializing_if = "Option::is_none")]
156    pub effect_id: Option<String>,
157
158    // Media fields
159    /// Animation attached to the message.
160    #[serde(skip_serializing_if = "Option::is_none")]
161    pub animation: Option<Animation>,
162    /// Audio file attached to the message.
163    #[serde(skip_serializing_if = "Option::is_none")]
164    pub audio: Option<Audio>,
165    /// Document attached to the message.
166    #[serde(skip_serializing_if = "Option::is_none")]
167    pub document: Option<Document>,
168    /// Paid media attached to the message.
169    #[serde(skip_serializing_if = "Option::is_none")]
170    pub paid_media: Option<serde_json::Value>,
171    /// Photo attached to the message (array of sizes).
172    #[serde(skip_serializing_if = "Option::is_none")]
173    pub photo: Option<Vec<PhotoSize>>,
174    /// Sticker attached to the message.
175    #[serde(skip_serializing_if = "Option::is_none")]
176    pub sticker: Option<Sticker>,
177    /// Story attached to the message.
178    #[serde(skip_serializing_if = "Option::is_none")]
179    pub story: Option<serde_json::Value>,
180    /// Video attached to the message.
181    #[serde(skip_serializing_if = "Option::is_none")]
182    pub video: Option<Video>,
183    /// Video note attached to the message.
184    #[serde(skip_serializing_if = "Option::is_none")]
185    pub video_note: Option<VideoNote>,
186    /// Voice note attached to the message.
187    #[serde(skip_serializing_if = "Option::is_none")]
188    pub voice: Option<Voice>,
189
190    /// Caption for the animation, audio, document, paid media, photo, video or voice.
191    #[serde(skip_serializing_if = "Option::is_none")]
192    pub caption: Option<String>,
193
194    /// Special entities in the caption.
195    #[serde(skip_serializing_if = "Option::is_none")]
196    pub caption_entities: Option<Vec<MessageEntity>>,
197
198    /// `true` if the caption must be shown above the message media.
199    #[serde(skip_serializing_if = "Option::is_none")]
200    pub show_caption_above_media: Option<bool>,
201
202    /// `true` if the message media is covered by a spoiler animation.
203    #[serde(skip_serializing_if = "Option::is_none")]
204    pub has_media_spoiler: Option<bool>,
205
206    /// Checklist attached to the message.
207    #[serde(skip_serializing_if = "Option::is_none")]
208    pub checklist: Option<Checklist>,
209
210    // Service message types
211    /// Contact shared in the message.
212    #[serde(skip_serializing_if = "Option::is_none")]
213    pub contact: Option<Contact>,
214    /// Dice result in the message.
215    #[serde(skip_serializing_if = "Option::is_none")]
216    pub dice: Option<Dice>,
217    /// Game in the message.
218    #[serde(skip_serializing_if = "Option::is_none")]
219    pub game: Option<serde_json::Value>,
220    /// Poll in the message.
221    #[serde(skip_serializing_if = "Option::is_none")]
222    pub poll: Option<Poll>,
223    /// Venue in the message.
224    #[serde(skip_serializing_if = "Option::is_none")]
225    pub venue: Option<Venue>,
226    /// Location in the message.
227    #[serde(skip_serializing_if = "Option::is_none")]
228    pub location: Option<Location>,
229
230    // Group events
231    /// New members that joined the group.
232    #[serde(skip_serializing_if = "Option::is_none")]
233    pub new_chat_members: Option<Vec<User>>,
234    /// A member that left the group.
235    #[serde(skip_serializing_if = "Option::is_none")]
236    pub left_chat_member: Option<User>,
237    /// Service message: chat owner has left.
238    #[serde(skip_serializing_if = "Option::is_none")]
239    pub chat_owner_left: Option<ChatOwnerLeft>,
240    /// Service message: chat owner has changed.
241    #[serde(skip_serializing_if = "Option::is_none")]
242    pub chat_owner_changed: Option<ChatOwnerChanged>,
243    /// New chat title (service message).
244    #[serde(skip_serializing_if = "Option::is_none")]
245    pub new_chat_title: Option<String>,
246    /// New chat photo (service message).
247    #[serde(skip_serializing_if = "Option::is_none")]
248    pub new_chat_photo: Option<Vec<PhotoSize>>,
249    /// `true` if the chat photo was deleted (service message).
250    #[serde(skip_serializing_if = "Option::is_none")]
251    pub delete_chat_photo: Option<bool>,
252    /// `true` if the group was created (service message).
253    #[serde(skip_serializing_if = "Option::is_none")]
254    pub group_chat_created: Option<bool>,
255    /// `true` if the supergroup was created (service message).
256    #[serde(skip_serializing_if = "Option::is_none")]
257    pub supergroup_chat_created: Option<bool>,
258    /// `true` if the channel was created (service message).
259    #[serde(skip_serializing_if = "Option::is_none")]
260    pub channel_chat_created: Option<bool>,
261    /// Auto-delete timer changed (service message).
262    #[serde(skip_serializing_if = "Option::is_none")]
263    pub message_auto_delete_timer_changed: Option<serde_json::Value>,
264    /// The group has been migrated to a supergroup with this ID.
265    #[serde(skip_serializing_if = "Option::is_none")]
266    pub migrate_to_chat_id: Option<i64>,
267    /// The supergroup has been migrated from a group with this ID.
268    #[serde(skip_serializing_if = "Option::is_none")]
269    pub migrate_from_chat_id: Option<i64>,
270    /// The pinned message (service message).
271    #[serde(skip_serializing_if = "Option::is_none")]
272    pub pinned_message: Option<Box<Message>>,
273
274    /// Inline keyboard attached to the message.
275    #[serde(skip_serializing_if = "Option::is_none")]
276    pub reply_markup: Option<InlineKeyboardMarkup>,
277
278    // Payment fields
279    /// Invoice for a payment (service message).
280    #[serde(skip_serializing_if = "Option::is_none")]
281    pub invoice: Option<serde_json::Value>,
282    /// Successful payment information (service message).
283    #[serde(skip_serializing_if = "Option::is_none")]
284    pub successful_payment: Option<serde_json::Value>,
285    /// Refunded payment information (service message).
286    #[serde(skip_serializing_if = "Option::is_none")]
287    pub refunded_payment: Option<serde_json::Value>,
288
289    // Web app
290    /// Data from the Web App.
291    #[serde(skip_serializing_if = "Option::is_none")]
292    pub web_app_data: Option<WebAppData>,
293
294    // Forum topic events
295    /// Forum topic created (service message).
296    #[serde(skip_serializing_if = "Option::is_none")]
297    pub forum_topic_created: Option<serde_json::Value>,
298    /// Forum topic edited (service message).
299    #[serde(skip_serializing_if = "Option::is_none")]
300    pub forum_topic_edited: Option<serde_json::Value>,
301    /// Forum topic closed (service message).
302    #[serde(skip_serializing_if = "Option::is_none")]
303    pub forum_topic_closed: Option<serde_json::Value>,
304    /// Forum topic reopened (service message).
305    #[serde(skip_serializing_if = "Option::is_none")]
306    pub forum_topic_reopened: Option<serde_json::Value>,
307    /// General forum topic hidden (service message).
308    #[serde(skip_serializing_if = "Option::is_none")]
309    pub general_forum_topic_hidden: Option<serde_json::Value>,
310    /// General forum topic unhidden (service message).
311    #[serde(skip_serializing_if = "Option::is_none")]
312    pub general_forum_topic_unhidden: Option<serde_json::Value>,
313
314    // Managed bot events
315    /// Service message: a new managed bot was created (Bot API 9.6).
316    #[serde(skip_serializing_if = "Option::is_none")]
317    pub managed_bot_created: Option<ManagedBotCreated>,
318
319    // Poll events
320    /// Service message: an option was added to a poll (Bot API 9.6).
321    #[serde(skip_serializing_if = "Option::is_none")]
322    pub poll_option_added: Option<PollOptionAdded>,
323    /// Service message: an option was deleted from a poll (Bot API 9.6).
324    #[serde(skip_serializing_if = "Option::is_none")]
325    pub poll_option_deleted: Option<PollOptionDeleted>,
326
327    // Checklist events
328    /// Service message: tasks in a checklist were marked done or not done.
329    #[serde(skip_serializing_if = "Option::is_none")]
330    pub checklist_tasks_done: Option<ChecklistTasksDone>,
331    /// Service message: tasks were added to a checklist.
332    #[serde(skip_serializing_if = "Option::is_none")]
333    pub checklist_tasks_added: Option<ChecklistTasksAdded>,
334
335    // Direct messages events
336    /// Service message: the price for paid messages in the direct messages chat changed.
337    #[serde(skip_serializing_if = "Option::is_none")]
338    pub direct_message_price_changed: Option<DirectMessagePriceChanged>,
339    /// Service message: the price for paid messages in the chat changed.
340    #[serde(skip_serializing_if = "Option::is_none")]
341    pub paid_message_price_changed: Option<PaidMessagePriceChanged>,
342
343    // Suggested post events
344    /// Service message: a suggested post was approved.
345    #[serde(skip_serializing_if = "Option::is_none")]
346    pub suggested_post_approved: Option<SuggestedPostApproved>,
347    /// Service message: approval of a suggested post has failed.
348    #[serde(skip_serializing_if = "Option::is_none")]
349    pub suggested_post_approval_failed: Option<SuggestedPostApprovalFailed>,
350    /// Service message: a suggested post was declined.
351    #[serde(skip_serializing_if = "Option::is_none")]
352    pub suggested_post_declined: Option<SuggestedPostDeclined>,
353    /// Service message: payment for a suggested post was received.
354    #[serde(skip_serializing_if = "Option::is_none")]
355    pub suggested_post_paid: Option<SuggestedPostPaid>,
356    /// Service message: payment for a suggested post was refunded.
357    #[serde(skip_serializing_if = "Option::is_none")]
358    pub suggested_post_refunded: Option<SuggestedPostRefunded>,
359}
360
361impl Message {
362    /// Returns the effective text of the message — `text` or `caption`.
363    #[must_use]
364    pub fn effective_text(&self) -> Option<&str> {
365        self.text.as_deref().or(self.caption.as_deref())
366    }
367
368    /// Returns `true` if the message is a command (text starts with `/`).
369    #[must_use]
370    pub fn is_command(&self) -> bool {
371        self.entities
372            .as_deref()
373            .unwrap_or_default()
374            .iter()
375            .any(|e| e.kind == MessageEntityKind::BotCommand && e.offset == 0)
376    }
377
378    /// Extracts the command string (e.g. `"start"` from `/start@bot`), if present.
379    #[must_use]
380    pub fn command(&self) -> Option<&str> {
381        let text = self.text.as_deref()?;
382        let entity = self
383            .entities
384            .as_deref()?
385            .iter()
386            .find(|e| e.kind == MessageEntityKind::BotCommand && e.offset == 0)?;
387        let raw = &text[..entity.length as usize];
388        // Strip the `@BotUsername` suffix if present.
389        Some(
390            raw.find('@')
391                .map_or(raw, |i| &raw[..i])
392                .trim_start_matches('/'),
393        )
394    }
395}
396
397/// Type of a message entity.
398#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
399#[serde(rename_all = "snake_case")]
400pub enum MessageEntityKind {
401    /// @username mention.
402    Mention,
403    /// #hashtag.
404    Hashtag,
405    /// $cashtag.
406    Cashtag,
407    /// /bot_command.
408    BotCommand,
409    /// Plain URL.
410    Url,
411    /// Email address.
412    Email,
413    /// Phone number.
414    PhoneNumber,
415    /// **Bold** text.
416    Bold,
417    /// _Italic_ text.
418    Italic,
419    /// Underlined text.
420    Underline,
421    /// ~~Strikethrough~~ text.
422    Strikethrough,
423    /// ||Spoiler|| text.
424    Spoiler,
425    /// Block quotation.
426    Blockquote,
427    /// An "expandable" block quotation that can be expanded to show the full text.
428    ExpandableBlockquote,
429    /// Monospaced text.
430    Code,
431    /// Monospaced block.
432    Pre,
433    /// A text link. The `url` field will contain the destination URL.
434    TextLink,
435    /// A text mention of a user. The `user` field will contain the mentioned user.
436    TextMention,
437    /// Custom emoji. The `custom_emoji_id` field will contain the identifier of the custom emoji.
438    CustomEmoji,
439    /// Date/time entity.
440    DateTime,
441}
442
443/// One special entity in a message text.
444#[derive(Debug, Clone, Serialize, Deserialize)]
445pub struct MessageEntity {
446    /// Type of the entity.
447    #[serde(rename = "type")]
448    pub kind: MessageEntityKind,
449    /// Offset in UTF-16 code units to the start of the entity.
450    pub offset: u32,
451    /// Length of the entity in UTF-16 code units.
452    pub length: u32,
453    /// For `TextLink` — URL.
454    #[serde(skip_serializing_if = "Option::is_none")]
455    pub url: Option<String>,
456    /// For `TextMention` — the mentioned user.
457    #[serde(skip_serializing_if = "Option::is_none")]
458    pub user: Option<User>,
459    /// For `Pre` — the programming language.
460    #[serde(skip_serializing_if = "Option::is_none")]
461    pub language: Option<String>,
462    /// For `CustomEmoji` — identifier of the custom emoji.
463    #[serde(skip_serializing_if = "Option::is_none")]
464    pub custom_emoji_id: Option<String>,
465    /// For `DateTime` — Unix timestamp associated with the entity.
466    #[serde(skip_serializing_if = "Option::is_none")]
467    pub unix_time: Option<i64>,
468    /// For `DateTime` — format string (`r|w?[dD]?[tT]?`).
469    #[serde(skip_serializing_if = "Option::is_none")]
470    pub date_time_format: Option<String>,
471}
472
473/// Origin of a forwarded message.
474#[derive(Debug, Clone, Serialize, Deserialize)]
475#[serde(tag = "type", rename_all = "snake_case")]
476pub enum MessageOrigin {
477    /// Forwarded from a user with a visible profile.
478    User {
479        /// Date the original message was sent, as a Unix timestamp.
480        date: i64,
481        /// The user who sent the original message.
482        sender_user: User,
483    },
484    /// Forwarded from a user with a hidden profile.
485    HiddenUser {
486        /// Date the original message was sent, as a Unix timestamp.
487        date: i64,
488        /// Name of the user who sent the original message.
489        sender_user_name: String,
490    },
491    /// Forwarded from a chat on behalf of the chat itself.
492    Chat {
493        /// Date the original message was sent, as a Unix timestamp.
494        date: i64,
495        /// The chat that sent the original message.
496        sender_chat: Chat,
497        /// Signature of the original post author.
498        #[serde(skip_serializing_if = "Option::is_none")]
499        author_signature: Option<String>,
500    },
501    /// Forwarded from a channel.
502    Channel {
503        /// Date the original message was sent, as a Unix timestamp.
504        date: i64,
505        /// The channel that sent the original message.
506        chat: Chat,
507        /// Identifier of the original message in the channel.
508        message_id: i64,
509        /// Signature of the original post author.
510        #[serde(skip_serializing_if = "Option::is_none")]
511        author_signature: Option<String>,
512    },
513}
514
515/// Parameters for replying to a message.
516#[derive(Debug, Clone, Serialize, Deserialize)]
517pub struct ReplyParameters {
518    /// Identifier of the message that will be replied to.
519    pub message_id: i64,
520    /// Chat containing the message.
521    #[serde(skip_serializing_if = "Option::is_none")]
522    pub chat_id: Option<crate::user::ChatId>,
523    /// `true` if the message should be sent even if the specified message is not found.
524    #[serde(skip_serializing_if = "Option::is_none")]
525    pub allow_sending_without_reply: Option<bool>,
526    /// Quoted part of the message to be replied to.
527    #[serde(skip_serializing_if = "Option::is_none")]
528    pub quote: Option<String>,
529    /// Parse mode for the quote.
530    #[serde(skip_serializing_if = "Option::is_none")]
531    pub quote_parse_mode: Option<ParseMode>,
532    /// Special entities in the quote.
533    #[serde(skip_serializing_if = "Option::is_none")]
534    pub quote_entities: Option<Vec<MessageEntity>>,
535    /// Position of the quote in the original message (UTF-16 offset).
536    #[serde(skip_serializing_if = "Option::is_none")]
537    pub quote_position: Option<u32>,
538    /// Identifier of the poll option being replied to.
539    #[serde(skip_serializing_if = "Option::is_none")]
540    pub poll_option_id: Option<String>,
541    /// Identifier of the checklist task being replied to.
542    #[serde(skip_serializing_if = "Option::is_none")]
543    pub checklist_task_id: Option<i64>,
544}
545
546/// Text parse mode for message formatting.
547#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
548pub enum ParseMode {
549    /// Markdown v2 — recommended.
550    MarkdownV2,
551    /// HTML formatting.
552    HTML,
553    /// Legacy Markdown — limited.
554    Markdown,
555}
556
557/// Reaction type on a message.
558#[derive(Debug, Clone, Serialize, Deserialize)]
559#[serde(tag = "type", rename_all = "snake_case")]
560pub enum ReactionType {
561    /// A standard emoji reaction.
562    Emoji {
563        /// The emoji character.
564        emoji: String,
565    },
566    /// A custom emoji reaction.
567    CustomEmoji {
568        /// Identifier of the custom emoji.
569        custom_emoji_id: String,
570    },
571    /// A paid star reaction.
572    Paid,
573}
574
575/// Options for controlling how links are previewed in messages.
576#[derive(Debug, Clone, Default, Serialize, Deserialize)]
577pub struct LinkPreviewOptions {
578    /// `true` if link preview is disabled.
579    #[serde(skip_serializing_if = "Option::is_none")]
580    pub is_disabled: Option<bool>,
581    /// URL to use for the link preview.
582    #[serde(skip_serializing_if = "Option::is_none")]
583    pub url: Option<String>,
584    /// `true` if the media in the link preview should be shrunk.
585    #[serde(skip_serializing_if = "Option::is_none")]
586    pub prefer_small_media: Option<bool>,
587    /// `true` if the media in the link preview should be enlarged.
588    #[serde(skip_serializing_if = "Option::is_none")]
589    pub prefer_large_media: Option<bool>,
590    /// `true` if the link preview should be shown above the message text.
591    #[serde(skip_serializing_if = "Option::is_none")]
592    pub show_above_text: Option<bool>,
593}
594
595/// Information about the quoted part of a message that is replied to.
596#[derive(Debug, Clone, Serialize, Deserialize)]
597pub struct TextQuote {
598    /// Text of the quoted part of the message.
599    pub text: String,
600    /// Special entities in the quote.
601    #[serde(skip_serializing_if = "Option::is_none")]
602    pub entities: Option<Vec<MessageEntity>>,
603    /// Approximate quote position in the original message (UTF-16 offset).
604    pub position: u32,
605    /// `true` if the quote was chosen manually by the message sender.
606    #[serde(skip_serializing_if = "Option::is_none")]
607    pub is_manual: Option<bool>,
608}
609
610/// Information about a message that is being replied to from outside the thread.
611#[derive(Debug, Clone, Serialize, Deserialize)]
612pub struct ExternalReplyInfo {
613    /// Origin of the message being replied to.
614    pub origin: MessageOrigin,
615    /// Chat the original message belongs to (if not the current chat).
616    #[serde(skip_serializing_if = "Option::is_none")]
617    pub chat: Option<Chat>,
618    /// Identifier of the original message in the original chat.
619    #[serde(skip_serializing_if = "Option::is_none")]
620    pub message_id: Option<i64>,
621    /// Options for link preview.
622    #[serde(skip_serializing_if = "Option::is_none")]
623    pub link_preview_options: Option<LinkPreviewOptions>,
624    /// Animation in the original message.
625    #[serde(skip_serializing_if = "Option::is_none")]
626    pub animation: Option<Animation>,
627    /// Audio in the original message.
628    #[serde(skip_serializing_if = "Option::is_none")]
629    pub audio: Option<Audio>,
630    /// Document in the original message.
631    #[serde(skip_serializing_if = "Option::is_none")]
632    pub document: Option<Document>,
633    /// Photo in the original message.
634    #[serde(skip_serializing_if = "Option::is_none")]
635    pub photo: Option<Vec<PhotoSize>>,
636    /// Sticker in the original message.
637    #[serde(skip_serializing_if = "Option::is_none")]
638    pub sticker: Option<Sticker>,
639    /// Video in the original message.
640    #[serde(skip_serializing_if = "Option::is_none")]
641    pub video: Option<Video>,
642    /// Video note in the original message.
643    #[serde(skip_serializing_if = "Option::is_none")]
644    pub video_note: Option<VideoNote>,
645    /// Voice note in the original message.
646    #[serde(skip_serializing_if = "Option::is_none")]
647    pub voice: Option<Voice>,
648    /// `true` if the media is covered by a spoiler animation.
649    #[serde(skip_serializing_if = "Option::is_none")]
650    pub has_media_spoiler: Option<bool>,
651    /// Checklist in the original message.
652    #[serde(skip_serializing_if = "Option::is_none")]
653    pub checklist: Option<Checklist>,
654    /// Contact in the original message.
655    #[serde(skip_serializing_if = "Option::is_none")]
656    pub contact: Option<Contact>,
657    /// Dice in the original message.
658    #[serde(skip_serializing_if = "Option::is_none")]
659    pub dice: Option<Dice>,
660    /// Location in the original message.
661    #[serde(skip_serializing_if = "Option::is_none")]
662    pub location: Option<Location>,
663    /// Venue in the original message.
664    #[serde(skip_serializing_if = "Option::is_none")]
665    pub venue: Option<Venue>,
666    /// Poll in the original message.
667    #[serde(skip_serializing_if = "Option::is_none")]
668    pub poll: Option<Poll>,
669}
670
671/// Phone contact.
672#[derive(Debug, Clone, Serialize, Deserialize)]
673pub struct Contact {
674    /// Contact's phone number.
675    pub phone_number: String,
676    /// Contact's first name.
677    pub first_name: String,
678    /// Contact's last name.
679    #[serde(skip_serializing_if = "Option::is_none")]
680    pub last_name: Option<String>,
681    /// Contact's Telegram user ID.
682    #[serde(skip_serializing_if = "Option::is_none")]
683    pub user_id: Option<i64>,
684    /// Contact's vCard.
685    #[serde(skip_serializing_if = "Option::is_none")]
686    pub vcard: Option<String>,
687}
688
689/// Animated dice with a random value.
690#[derive(Debug, Clone, Serialize, Deserialize)]
691pub struct Dice {
692    /// Emoji on which the dice throw animation is based.
693    pub emoji: String,
694    /// Value of the dice (1–6 for 🎲🎯🎳; 1–5 for 🏀⚽; 1–64 for 🎰).
695    pub value: u8,
696}
697
698/// Data sent from a Web App.
699#[derive(Debug, Clone, Serialize, Deserialize)]
700pub struct WebAppData {
701    /// Data sent by the Web App.
702    pub data: String,
703    /// Text of the button that opened the Web App.
704    pub button_text: String,
705}
706
707/// Information about a Web App.
708#[derive(Debug, Clone, Serialize, Deserialize)]
709pub struct WebAppInfo {
710    /// HTTPS URL of the Web App.
711    pub url: String,
712}
713
714/// Lightweight message identifier returned by `copyMessage`.
715#[derive(Debug, Clone, Serialize, Deserialize)]
716pub struct MessageId {
717    /// Identifier of the message.
718    pub message_id: i64,
719}
720
721/// Service message: the chat owner left the chat (Bot API 9.4).
722#[derive(Debug, Clone, Serialize, Deserialize)]
723pub struct ChatOwnerLeft {
724    /// The user who will become the new owner if the previous owner does not return.
725    #[serde(skip_serializing_if = "Option::is_none")]
726    pub new_owner: Option<User>,
727}
728
729/// Service message: ownership of the chat changed (Bot API 9.4).
730#[derive(Debug, Clone, Serialize, Deserialize)]
731pub struct ChatOwnerChanged {
732    /// The new owner of the chat.
733    pub new_owner: User,
734}