Skip to main content

simploxide_api_types/
commands.rs

1use {crate::utils::CommandSyntax, crate::*};
2
3use std::fmt::Write;
4/// ### Address commands
5///
6/// Bots can use these commands to automatically check and create address when initialized
7///
8/// ----
9///
10/// Create bot address.
11///
12/// *Network usage*: interactive.
13///
14/// *Syntax:*
15///
16/// ```
17/// /_address <userId>
18/// ```
19#[derive(Debug, Clone, PartialEq)]
20#[cfg_attr(feature = "bon", derive(::bon::Builder))]
21pub struct ApiCreateMyAddress {
22    pub user_id: i64,
23}
24
25impl CommandSyntax for ApiCreateMyAddress {
26    const COMMAND_BUF_SIZE: usize = 64;
27
28    fn append_command_syntax(&self, buf: &mut String) {
29        buf.push_str("/_address ");
30        write!(buf, "{}", self.user_id).unwrap();
31    }
32}
33
34/// ### Address commands
35///
36/// Bots can use these commands to automatically check and create address when initialized
37///
38/// ----
39///
40/// Delete bot address.
41///
42/// *Network usage*: background.
43///
44/// *Syntax:*
45///
46/// ```
47/// /_delete_address <userId>
48/// ```
49#[derive(Debug, Clone, PartialEq)]
50#[cfg_attr(feature = "bon", derive(::bon::Builder))]
51pub struct ApiDeleteMyAddress {
52    pub user_id: i64,
53}
54
55impl CommandSyntax for ApiDeleteMyAddress {
56    const COMMAND_BUF_SIZE: usize = 64;
57
58    fn append_command_syntax(&self, buf: &mut String) {
59        buf.push_str("/_delete_address ");
60        write!(buf, "{}", self.user_id).unwrap();
61    }
62}
63
64/// ### Address commands
65///
66/// Bots can use these commands to automatically check and create address when initialized
67///
68/// ----
69///
70/// Get bot address and settings.
71///
72/// *Network usage*: no.
73///
74/// *Syntax:*
75///
76/// ```
77/// /_show_address <userId>
78/// ```
79#[derive(Debug, Clone, PartialEq)]
80#[cfg_attr(feature = "bon", derive(::bon::Builder))]
81pub struct ApiShowMyAddress {
82    pub user_id: i64,
83}
84
85impl CommandSyntax for ApiShowMyAddress {
86    const COMMAND_BUF_SIZE: usize = 64;
87
88    fn append_command_syntax(&self, buf: &mut String) {
89        buf.push_str("/_show_address ");
90        write!(buf, "{}", self.user_id).unwrap();
91    }
92}
93
94/// ### Address commands
95///
96/// Bots can use these commands to automatically check and create address when initialized
97///
98/// ----
99///
100/// Add address to bot profile.
101///
102/// *Network usage*: interactive.
103///
104/// *Syntax:*
105///
106/// ```
107/// /_profile_address <userId> on|off
108/// ```
109#[derive(Debug, Clone, PartialEq)]
110#[cfg_attr(feature = "bon", derive(::bon::Builder))]
111pub struct ApiSetProfileAddress {
112    pub user_id: i64,
113    pub enable: bool,
114}
115
116impl ApiSetProfileAddress {
117    /// Creates a command with all `Option` parameters set to `None` and all `bool` parameters set to false
118    pub fn new(user_id: i64) -> Self {
119        Self {
120            user_id,
121            enable: false,
122        }
123    }
124}
125
126impl CommandSyntax for ApiSetProfileAddress {
127    const COMMAND_BUF_SIZE: usize = 64;
128
129    fn append_command_syntax(&self, buf: &mut String) {
130        buf.push_str("/_profile_address ");
131        write!(buf, "{}", self.user_id).unwrap();
132        buf.push(' ');
133        if self.enable {
134            buf.push_str("on");
135        } else {
136            buf.push_str("off");
137        }
138    }
139}
140
141/// ### Address commands
142///
143/// Bots can use these commands to automatically check and create address when initialized
144///
145/// ----
146///
147/// Set bot address settings.
148///
149/// *Network usage*: interactive.
150///
151/// *Syntax:*
152///
153/// ```
154/// /_address_settings <userId> <json(settings)>
155/// ```
156#[derive(Debug, Clone, PartialEq)]
157#[cfg_attr(feature = "bon", derive(::bon::Builder))]
158pub struct ApiSetAddressSettings {
159    pub user_id: i64,
160    pub settings: AddressSettings,
161}
162
163impl CommandSyntax for ApiSetAddressSettings {
164    const COMMAND_BUF_SIZE: usize = 1024;
165
166    fn append_command_syntax(&self, buf: &mut String) {
167        buf.push_str("/_address_settings ");
168        write!(buf, "{}", self.user_id).unwrap();
169        buf.push(' ');
170        // SAFETY: serde_json guarantees to produce valid UTF-8 sequences
171        unsafe {
172            serde_json::to_writer(buf.as_mut_vec(), &self.settings).unwrap();
173        }
174    }
175}
176
177/// ### Message commands
178///
179/// Commands to send, update, delete, moderate messages and set message reactions
180///
181/// ----
182///
183/// Send messages.
184///
185/// *Network usage*: background.
186///
187/// *Syntax:*
188///
189/// ```
190/// /_send <str(sendRef)>[ live=on][ ttl=<ttl>][ sign=on] json <json(composedMessages)>
191/// ```
192#[derive(Debug, Clone, PartialEq)]
193#[cfg_attr(feature = "bon", derive(::bon::Builder))]
194pub struct ApiSendMessages {
195    pub send_ref: ChatRef,
196    pub live_message: bool,
197    pub ttl: Option<i32>,
198    pub sign_messages: bool,
199    pub composed_messages: Vec<ComposedMessage>,
200}
201
202impl ApiSendMessages {
203    /// Creates a command with all `Option` parameters set to `None` and all `bool` parameters set to false
204    pub fn new(send_ref: ChatRef, composed_messages: Vec<ComposedMessage>) -> Self {
205        Self {
206            send_ref,
207            live_message: false,
208            ttl: None,
209            sign_messages: false,
210            composed_messages,
211        }
212    }
213}
214
215impl CommandSyntax for ApiSendMessages {
216    const COMMAND_BUF_SIZE: usize = 1024;
217
218    fn append_command_syntax(&self, buf: &mut String) {
219        buf.push_str("/_send ");
220        self.send_ref.append_command_syntax(buf);
221        if self.live_message {
222            buf.push(' ');
223            buf.push_str("live=");
224            buf.push_str("on");
225        }
226        if let Some(ttl) = &self.ttl {
227            buf.push(' ');
228            buf.push_str("ttl=");
229            write!(buf, "{}", ttl).unwrap();
230        }
231        if self.sign_messages {
232            buf.push(' ');
233            buf.push_str("sign=");
234            buf.push_str("on");
235        }
236        buf.push(' ');
237        buf.push_str("json ");
238        // SAFETY: serde_json guarantees to produce valid UTF-8 sequences
239        unsafe {
240            serde_json::to_writer(buf.as_mut_vec(), &self.composed_messages).unwrap();
241        }
242    }
243}
244
245/// ### Message commands
246///
247/// Commands to send, update, delete, moderate messages and set message reactions
248///
249/// ----
250///
251/// Update message.
252///
253/// *Network usage*: background.
254///
255/// *Syntax:*
256///
257/// ```
258/// /_update item <str(chatRef)> <chatItemId>[ live=on] json <json(updatedMessage)>
259/// ```
260#[derive(Debug, Clone, PartialEq)]
261#[cfg_attr(feature = "bon", derive(::bon::Builder))]
262pub struct ApiUpdateChatItem {
263    pub chat_ref: ChatRef,
264    pub chat_item_id: i64,
265    pub live_message: bool,
266    pub updated_message: UpdatedMessage,
267}
268
269impl ApiUpdateChatItem {
270    /// Creates a command with all `Option` parameters set to `None` and all `bool` parameters set to false
271    pub fn new(chat_ref: ChatRef, chat_item_id: i64, updated_message: UpdatedMessage) -> Self {
272        Self {
273            chat_ref,
274            chat_item_id,
275            live_message: false,
276            updated_message,
277        }
278    }
279}
280
281impl CommandSyntax for ApiUpdateChatItem {
282    const COMMAND_BUF_SIZE: usize = 1024;
283
284    fn append_command_syntax(&self, buf: &mut String) {
285        buf.push_str("/_update ");
286        buf.push_str("item ");
287        self.chat_ref.append_command_syntax(buf);
288        buf.push(' ');
289        write!(buf, "{}", self.chat_item_id).unwrap();
290        if self.live_message {
291            buf.push(' ');
292            buf.push_str("live=");
293            buf.push_str("on");
294        }
295        buf.push(' ');
296        buf.push_str("json ");
297        // SAFETY: serde_json guarantees to produce valid UTF-8 sequences
298        unsafe {
299            serde_json::to_writer(buf.as_mut_vec(), &self.updated_message).unwrap();
300        }
301    }
302}
303
304/// ### Message commands
305///
306/// Commands to send, update, delete, moderate messages and set message reactions
307///
308/// ----
309///
310/// Delete message.
311///
312/// *Network usage*: background.
313///
314/// *Syntax:*
315///
316/// ```
317/// /_delete item <str(chatRef)> <chatItemIds[0]>[,<chatItemIds[1]>...] broadcast|internal|internalMark|history
318/// ```
319#[derive(Debug, Clone, PartialEq)]
320#[cfg_attr(feature = "bon", derive(::bon::Builder))]
321pub struct ApiDeleteChatItem {
322    pub chat_ref: ChatRef,
323    pub chat_item_ids: Vec<i64>,
324    pub delete_mode: CIDeleteMode,
325}
326
327impl CommandSyntax for ApiDeleteChatItem {
328    const COMMAND_BUF_SIZE: usize = 256;
329
330    fn append_command_syntax(&self, buf: &mut String) {
331        buf.push_str("/_delete ");
332        buf.push_str("item ");
333        self.chat_ref.append_command_syntax(buf);
334        buf.push(' ');
335        let mut iter = self.chat_item_ids.iter();
336        if let Some(el) = iter.next() {
337            write!(buf, "{el}").unwrap();
338        }
339        for el in iter {
340            buf.push(',');
341            write!(buf, "{el}").unwrap();
342        }
343        buf.push(' ');
344        match self.delete_mode {
345            CIDeleteMode::Broadcast => {
346                buf.push_str("broadcast");
347            }
348            CIDeleteMode::Internal => {
349                buf.push_str("internal");
350            }
351            CIDeleteMode::InternalMark => {
352                buf.push_str("internalMark");
353            }
354            CIDeleteMode::History => {
355                buf.push_str("history");
356            }
357        }
358    }
359}
360
361/// ### Message commands
362///
363/// Commands to send, update, delete, moderate messages and set message reactions
364///
365/// ----
366///
367/// Moderate message. Requires Moderator role (and higher than message author's).
368///
369/// *Network usage*: background.
370///
371/// *Syntax:*
372///
373/// ```
374/// /_delete member item #<groupId> <chatItemIds[0]>[,<chatItemIds[1]>...]
375/// ```
376#[derive(Debug, Clone, PartialEq)]
377#[cfg_attr(feature = "bon", derive(::bon::Builder))]
378pub struct ApiDeleteMemberChatItem {
379    pub group_id: i64,
380    pub chat_item_ids: Vec<i64>,
381}
382
383impl CommandSyntax for ApiDeleteMemberChatItem {
384    const COMMAND_BUF_SIZE: usize = 256;
385
386    fn append_command_syntax(&self, buf: &mut String) {
387        buf.push_str("/_delete ");
388        buf.push_str("member ");
389        buf.push_str("item ");
390        buf.push('#');
391        write!(buf, "{}", self.group_id).unwrap();
392        buf.push(' ');
393        let mut iter = self.chat_item_ids.iter();
394        if let Some(el) = iter.next() {
395            write!(buf, "{el}").unwrap();
396        }
397        for el in iter {
398            buf.push(',');
399            write!(buf, "{el}").unwrap();
400        }
401    }
402}
403
404/// ### Message commands
405///
406/// Commands to send, update, delete, moderate messages and set message reactions
407///
408/// ----
409///
410/// Add/remove message reaction.
411///
412/// *Network usage*: background.
413///
414/// *Syntax:*
415///
416/// ```
417/// /_reaction <str(chatRef)> <chatItemId> on|off <json(reaction)>
418/// ```
419#[derive(Debug, Clone, PartialEq)]
420#[cfg_attr(feature = "bon", derive(::bon::Builder))]
421pub struct ApiChatItemReaction {
422    pub chat_ref: ChatRef,
423    pub chat_item_id: i64,
424    pub add: bool,
425    pub reaction: MsgReaction,
426}
427
428impl ApiChatItemReaction {
429    /// Creates a command with all `Option` parameters set to `None` and all `bool` parameters set to false
430    pub fn new(chat_ref: ChatRef, chat_item_id: i64, reaction: MsgReaction) -> Self {
431        Self {
432            chat_ref,
433            chat_item_id,
434            add: false,
435            reaction,
436        }
437    }
438}
439
440impl CommandSyntax for ApiChatItemReaction {
441    const COMMAND_BUF_SIZE: usize = 1024;
442
443    fn append_command_syntax(&self, buf: &mut String) {
444        buf.push_str("/_reaction ");
445        self.chat_ref.append_command_syntax(buf);
446        buf.push(' ');
447        write!(buf, "{}", self.chat_item_id).unwrap();
448        buf.push(' ');
449        if self.add {
450            buf.push_str("on");
451        } else {
452            buf.push_str("off");
453        }
454        buf.push(' ');
455        // SAFETY: serde_json guarantees to produce valid UTF-8 sequences
456        unsafe {
457            serde_json::to_writer(buf.as_mut_vec(), &self.reaction).unwrap();
458        }
459    }
460}
461
462/// ### File commands
463///
464/// Commands to receive and to cancel files. Files are sent as part of the message, there are no separate commands to send files.
465///
466/// ----
467///
468/// Receive file.
469///
470/// *Network usage*: no.
471///
472/// *Syntax:*
473///
474/// ```
475/// /freceive <fileId>[ approved_relays=on][ encrypt=on|off][ inline=on|off][ <filePath>]
476/// ```
477#[derive(Debug, Clone, PartialEq)]
478#[cfg_attr(feature = "bon", derive(::bon::Builder))]
479pub struct ReceiveFile {
480    pub file_id: i64,
481    pub user_approved_relays: bool,
482    pub store_encrypted: Option<bool>,
483    pub file_inline: Option<bool>,
484    pub file_path: Option<String>,
485}
486
487impl ReceiveFile {
488    /// Creates a command with all `Option` parameters set to `None` and all `bool` parameters set to false
489    pub fn new(file_id: i64) -> Self {
490        Self {
491            file_id,
492            user_approved_relays: false,
493            store_encrypted: None,
494            file_inline: None,
495            file_path: None,
496        }
497    }
498}
499
500impl CommandSyntax for ReceiveFile {
501    const COMMAND_BUF_SIZE: usize = 256;
502
503    fn append_command_syntax(&self, buf: &mut String) {
504        buf.push_str("/freceive ");
505        write!(buf, "{}", self.file_id).unwrap();
506        if self.user_approved_relays {
507            buf.push(' ');
508            buf.push_str("approved_relays=");
509            buf.push_str("on");
510        }
511        if let Some(store_encrypted) = &self.store_encrypted {
512            buf.push(' ');
513            buf.push_str("encrypt=");
514            if *store_encrypted {
515                buf.push_str("on");
516            } else {
517                buf.push_str("off");
518            }
519        }
520        if let Some(file_inline) = &self.file_inline {
521            buf.push(' ');
522            buf.push_str("inline=");
523            if *file_inline {
524                buf.push_str("on");
525            } else {
526                buf.push_str("off");
527            }
528        }
529        if let Some(file_path) = &self.file_path {
530            buf.push(' ');
531            write!(buf, "{}", file_path).unwrap();
532        }
533    }
534}
535
536/// ### File commands
537///
538/// Commands to receive and to cancel files. Files are sent as part of the message, there are no separate commands to send files.
539///
540/// ----
541///
542/// Cancel file.
543///
544/// *Network usage*: background.
545///
546/// *Syntax:*
547///
548/// ```
549/// /fcancel <fileId>
550/// ```
551#[derive(Debug, Clone, PartialEq)]
552#[cfg_attr(feature = "bon", derive(::bon::Builder))]
553pub struct CancelFile {
554    pub file_id: i64,
555}
556
557impl CommandSyntax for CancelFile {
558    const COMMAND_BUF_SIZE: usize = 64;
559
560    fn append_command_syntax(&self, buf: &mut String) {
561        buf.push_str("/fcancel ");
562        write!(buf, "{}", self.file_id).unwrap();
563    }
564}
565
566/// ### Group commands
567///
568/// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
569///
570/// ----
571///
572/// Add contact to group. Requires bot to have Admin role.
573///
574/// *Network usage*: interactive.
575///
576/// *Syntax:*
577///
578/// ```
579/// /_add #<groupId> <contactId> relay|observer|author|member|moderator|admin|owner
580/// ```
581#[derive(Debug, Clone, PartialEq)]
582#[cfg_attr(feature = "bon", derive(::bon::Builder))]
583pub struct ApiAddMember {
584    pub group_id: i64,
585    pub contact_id: i64,
586    pub member_role: GroupMemberRole,
587}
588
589impl CommandSyntax for ApiAddMember {
590    const COMMAND_BUF_SIZE: usize = 256;
591
592    fn append_command_syntax(&self, buf: &mut String) {
593        buf.push_str("/_add ");
594        buf.push('#');
595        write!(buf, "{}", self.group_id).unwrap();
596        buf.push(' ');
597        write!(buf, "{}", self.contact_id).unwrap();
598        buf.push(' ');
599        match self.member_role {
600            GroupMemberRole::Relay => {
601                buf.push_str("relay");
602            }
603            GroupMemberRole::Observer => {
604                buf.push_str("observer");
605            }
606            GroupMemberRole::Author => {
607                buf.push_str("author");
608            }
609            GroupMemberRole::Member => {
610                buf.push_str("member");
611            }
612            GroupMemberRole::Moderator => {
613                buf.push_str("moderator");
614            }
615            GroupMemberRole::Admin => {
616                buf.push_str("admin");
617            }
618            GroupMemberRole::Owner => {
619                buf.push_str("owner");
620            }
621        }
622    }
623}
624
625/// ### Group commands
626///
627/// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
628///
629/// ----
630///
631/// Join group.
632///
633/// *Network usage*: interactive.
634///
635/// *Syntax:*
636///
637/// ```
638/// /_join #<groupId>
639/// ```
640#[derive(Debug, Clone, PartialEq)]
641#[cfg_attr(feature = "bon", derive(::bon::Builder))]
642pub struct ApiJoinGroup {
643    pub group_id: i64,
644}
645
646impl CommandSyntax for ApiJoinGroup {
647    const COMMAND_BUF_SIZE: usize = 64;
648
649    fn append_command_syntax(&self, buf: &mut String) {
650        buf.push_str("/_join ");
651        buf.push('#');
652        write!(buf, "{}", self.group_id).unwrap();
653    }
654}
655
656/// ### Group commands
657///
658/// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
659///
660/// ----
661///
662/// Accept group member. Requires Admin role.
663///
664/// *Network usage*: background.
665///
666/// *Syntax:*
667///
668/// ```
669/// /_accept member #<groupId> <groupMemberId> relay|observer|author|member|moderator|admin|owner
670/// ```
671#[derive(Debug, Clone, PartialEq)]
672#[cfg_attr(feature = "bon", derive(::bon::Builder))]
673pub struct ApiAcceptMember {
674    pub group_id: i64,
675    pub group_member_id: i64,
676    pub member_role: GroupMemberRole,
677}
678
679impl CommandSyntax for ApiAcceptMember {
680    const COMMAND_BUF_SIZE: usize = 256;
681
682    fn append_command_syntax(&self, buf: &mut String) {
683        buf.push_str("/_accept ");
684        buf.push_str("member ");
685        buf.push('#');
686        write!(buf, "{}", self.group_id).unwrap();
687        buf.push(' ');
688        write!(buf, "{}", self.group_member_id).unwrap();
689        buf.push(' ');
690        match self.member_role {
691            GroupMemberRole::Relay => {
692                buf.push_str("relay");
693            }
694            GroupMemberRole::Observer => {
695                buf.push_str("observer");
696            }
697            GroupMemberRole::Author => {
698                buf.push_str("author");
699            }
700            GroupMemberRole::Member => {
701                buf.push_str("member");
702            }
703            GroupMemberRole::Moderator => {
704                buf.push_str("moderator");
705            }
706            GroupMemberRole::Admin => {
707                buf.push_str("admin");
708            }
709            GroupMemberRole::Owner => {
710                buf.push_str("owner");
711            }
712        }
713    }
714}
715
716/// ### Group commands
717///
718/// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
719///
720/// ----
721///
722/// Set members role. Requires Admin role.
723///
724/// *Network usage*: background.
725///
726/// *Syntax:*
727///
728/// ```
729/// /_member role #<groupId> <groupMemberIds[0]>[,<groupMemberIds[1]>...] relay|observer|author|member|moderator|admin|owner
730/// ```
731#[derive(Debug, Clone, PartialEq)]
732#[cfg_attr(feature = "bon", derive(::bon::Builder))]
733pub struct ApiMembersRole {
734    pub group_id: i64,
735    pub group_member_ids: Vec<i64>,
736    pub member_role: GroupMemberRole,
737}
738
739impl CommandSyntax for ApiMembersRole {
740    const COMMAND_BUF_SIZE: usize = 256;
741
742    fn append_command_syntax(&self, buf: &mut String) {
743        buf.push_str("/_member ");
744        buf.push_str("role ");
745        buf.push('#');
746        write!(buf, "{}", self.group_id).unwrap();
747        buf.push(' ');
748        let mut iter = self.group_member_ids.iter();
749        if let Some(el) = iter.next() {
750            write!(buf, "{el}").unwrap();
751        }
752        for el in iter {
753            buf.push(',');
754            write!(buf, "{el}").unwrap();
755        }
756        buf.push(' ');
757        match self.member_role {
758            GroupMemberRole::Relay => {
759                buf.push_str("relay");
760            }
761            GroupMemberRole::Observer => {
762                buf.push_str("observer");
763            }
764            GroupMemberRole::Author => {
765                buf.push_str("author");
766            }
767            GroupMemberRole::Member => {
768                buf.push_str("member");
769            }
770            GroupMemberRole::Moderator => {
771                buf.push_str("moderator");
772            }
773            GroupMemberRole::Admin => {
774                buf.push_str("admin");
775            }
776            GroupMemberRole::Owner => {
777                buf.push_str("owner");
778            }
779        }
780    }
781}
782
783/// ### Group commands
784///
785/// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
786///
787/// ----
788///
789/// Block members. Requires Moderator role.
790///
791/// *Network usage*: background.
792///
793/// *Syntax:*
794///
795/// ```
796/// /_block #<groupId> <groupMemberIds[0]>[,<groupMemberIds[1]>...] blocked=on|off
797/// ```
798#[derive(Debug, Clone, PartialEq)]
799#[cfg_attr(feature = "bon", derive(::bon::Builder))]
800pub struct ApiBlockMembersForAll {
801    pub group_id: i64,
802    pub group_member_ids: Vec<i64>,
803    pub blocked: bool,
804}
805
806impl ApiBlockMembersForAll {
807    /// Creates a command with all `Option` parameters set to `None` and all `bool` parameters set to false
808    pub fn new(group_id: i64, group_member_ids: Vec<i64>) -> Self {
809        Self {
810            group_id,
811            group_member_ids,
812            blocked: false,
813        }
814    }
815}
816
817impl CommandSyntax for ApiBlockMembersForAll {
818    const COMMAND_BUF_SIZE: usize = 256;
819
820    fn append_command_syntax(&self, buf: &mut String) {
821        buf.push_str("/_block ");
822        buf.push('#');
823        write!(buf, "{}", self.group_id).unwrap();
824        buf.push(' ');
825        let mut iter = self.group_member_ids.iter();
826        if let Some(el) = iter.next() {
827            write!(buf, "{el}").unwrap();
828        }
829        for el in iter {
830            buf.push(',');
831            write!(buf, "{el}").unwrap();
832        }
833        buf.push(' ');
834        buf.push_str("blocked=");
835        if self.blocked {
836            buf.push_str("on");
837        } else {
838            buf.push_str("off");
839        }
840    }
841}
842
843/// ### Group commands
844///
845/// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
846///
847/// ----
848///
849/// Remove members. Requires Admin role.
850///
851/// *Network usage*: background.
852///
853/// *Syntax:*
854///
855/// ```
856/// /_remove #<groupId> <groupMemberIds[0]>[,<groupMemberIds[1]>...][ messages=on]
857/// ```
858#[derive(Debug, Clone, PartialEq)]
859#[cfg_attr(feature = "bon", derive(::bon::Builder))]
860pub struct ApiRemoveMembers {
861    pub group_id: i64,
862    pub group_member_ids: Vec<i64>,
863    pub with_messages: bool,
864}
865
866impl ApiRemoveMembers {
867    /// Creates a command with all `Option` parameters set to `None` and all `bool` parameters set to false
868    pub fn new(group_id: i64, group_member_ids: Vec<i64>) -> Self {
869        Self {
870            group_id,
871            group_member_ids,
872            with_messages: false,
873        }
874    }
875}
876
877impl CommandSyntax for ApiRemoveMembers {
878    const COMMAND_BUF_SIZE: usize = 256;
879
880    fn append_command_syntax(&self, buf: &mut String) {
881        buf.push_str("/_remove ");
882        buf.push('#');
883        write!(buf, "{}", self.group_id).unwrap();
884        buf.push(' ');
885        let mut iter = self.group_member_ids.iter();
886        if let Some(el) = iter.next() {
887            write!(buf, "{el}").unwrap();
888        }
889        for el in iter {
890            buf.push(',');
891            write!(buf, "{el}").unwrap();
892        }
893        if self.with_messages {
894            buf.push(' ');
895            buf.push_str("messages=");
896            buf.push_str("on");
897        }
898    }
899}
900
901/// ### Group commands
902///
903/// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
904///
905/// ----
906///
907/// Leave group.
908///
909/// *Network usage*: background.
910///
911/// *Syntax:*
912///
913/// ```
914/// /_leave #<groupId>
915/// ```
916#[derive(Debug, Clone, PartialEq)]
917#[cfg_attr(feature = "bon", derive(::bon::Builder))]
918pub struct ApiLeaveGroup {
919    pub group_id: i64,
920}
921
922impl CommandSyntax for ApiLeaveGroup {
923    const COMMAND_BUF_SIZE: usize = 64;
924
925    fn append_command_syntax(&self, buf: &mut String) {
926        buf.push_str("/_leave ");
927        buf.push('#');
928        write!(buf, "{}", self.group_id).unwrap();
929    }
930}
931
932/// ### Group commands
933///
934/// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
935///
936/// ----
937///
938/// Get group members.
939///
940/// *Network usage*: no.
941///
942/// *Syntax:*
943///
944/// ```
945/// /_members #<groupId>
946/// ```
947#[derive(Debug, Clone, PartialEq)]
948#[cfg_attr(feature = "bon", derive(::bon::Builder))]
949pub struct ApiListMembers {
950    pub group_id: i64,
951}
952
953impl CommandSyntax for ApiListMembers {
954    const COMMAND_BUF_SIZE: usize = 64;
955
956    fn append_command_syntax(&self, buf: &mut String) {
957        buf.push_str("/_members ");
958        buf.push('#');
959        write!(buf, "{}", self.group_id).unwrap();
960    }
961}
962
963/// ### Group commands
964///
965/// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
966///
967/// ----
968///
969/// Create group.
970///
971/// *Network usage*: no.
972///
973/// *Syntax:*
974///
975/// ```
976/// /_group <userId>[ incognito=on] <json(groupProfile)>
977/// ```
978#[derive(Debug, Clone, PartialEq)]
979#[cfg_attr(feature = "bon", derive(::bon::Builder))]
980pub struct ApiNewGroup {
981    pub user_id: i64,
982    pub incognito: bool,
983    pub group_profile: GroupProfile,
984}
985
986impl ApiNewGroup {
987    /// Creates a command with all `Option` parameters set to `None` and all `bool` parameters set to false
988    pub fn new(user_id: i64, group_profile: GroupProfile) -> Self {
989        Self {
990            user_id,
991            incognito: false,
992            group_profile,
993        }
994    }
995}
996
997impl CommandSyntax for ApiNewGroup {
998    const COMMAND_BUF_SIZE: usize = 1024;
999
1000    fn append_command_syntax(&self, buf: &mut String) {
1001        buf.push_str("/_group ");
1002        write!(buf, "{}", self.user_id).unwrap();
1003        if self.incognito {
1004            buf.push(' ');
1005            buf.push_str("incognito=");
1006            buf.push_str("on");
1007        }
1008        buf.push(' ');
1009        // SAFETY: serde_json guarantees to produce valid UTF-8 sequences
1010        unsafe {
1011            serde_json::to_writer(buf.as_mut_vec(), &self.group_profile).unwrap();
1012        }
1013    }
1014}
1015
1016/// ### Group commands
1017///
1018/// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
1019///
1020/// ----
1021///
1022/// Create public group.
1023///
1024/// *Network usage*: interactive.
1025///
1026/// *Syntax:*
1027///
1028/// ```
1029/// /_public group <userId>[ incognito=on] <relayIds[0]>[,<relayIds[1]>...] <json(groupProfile)>
1030/// ```
1031#[derive(Debug, Clone, PartialEq)]
1032#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1033pub struct ApiNewPublicGroup {
1034    pub user_id: i64,
1035    pub incognito: bool,
1036    pub relay_ids: Vec<i64>,
1037    pub group_profile: GroupProfile,
1038}
1039
1040impl ApiNewPublicGroup {
1041    /// Creates a command with all `Option` parameters set to `None` and all `bool` parameters set to false
1042    pub fn new(user_id: i64, relay_ids: Vec<i64>, group_profile: GroupProfile) -> Self {
1043        Self {
1044            user_id,
1045            incognito: false,
1046            relay_ids,
1047            group_profile,
1048        }
1049    }
1050}
1051
1052impl CommandSyntax for ApiNewPublicGroup {
1053    const COMMAND_BUF_SIZE: usize = 1024;
1054
1055    fn append_command_syntax(&self, buf: &mut String) {
1056        buf.push_str("/_public ");
1057        buf.push_str("group ");
1058        write!(buf, "{}", self.user_id).unwrap();
1059        if self.incognito {
1060            buf.push(' ');
1061            buf.push_str("incognito=");
1062            buf.push_str("on");
1063        }
1064        buf.push(' ');
1065        let mut iter = self.relay_ids.iter();
1066        if let Some(el) = iter.next() {
1067            write!(buf, "{el}").unwrap();
1068        }
1069        for el in iter {
1070            buf.push(',');
1071            write!(buf, "{el}").unwrap();
1072        }
1073        buf.push(' ');
1074        // SAFETY: serde_json guarantees to produce valid UTF-8 sequences
1075        unsafe {
1076            serde_json::to_writer(buf.as_mut_vec(), &self.group_profile).unwrap();
1077        }
1078    }
1079}
1080
1081/// ### Group commands
1082///
1083/// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
1084///
1085/// ----
1086///
1087/// Get group relays.
1088///
1089/// *Network usage*: no.
1090///
1091/// *Syntax:*
1092///
1093/// ```
1094/// /_get relays #<groupId>
1095/// ```
1096#[derive(Debug, Clone, PartialEq)]
1097#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1098pub struct ApiGetGroupRelays {
1099    pub group_id: i64,
1100}
1101
1102impl CommandSyntax for ApiGetGroupRelays {
1103    const COMMAND_BUF_SIZE: usize = 64;
1104
1105    fn append_command_syntax(&self, buf: &mut String) {
1106        buf.push_str("/_get ");
1107        buf.push_str("relays ");
1108        buf.push('#');
1109        write!(buf, "{}", self.group_id).unwrap();
1110    }
1111}
1112
1113/// ### Group commands
1114///
1115/// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
1116///
1117/// ----
1118///
1119/// Add relays to group.
1120///
1121/// *Network usage*: interactive.
1122///
1123/// *Syntax:*
1124///
1125/// ```
1126/// /_add relays #<groupId> <relayIds[0]>[,<relayIds[1]>...]
1127/// ```
1128#[derive(Debug, Clone, PartialEq)]
1129#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1130pub struct ApiAddGroupRelays {
1131    pub group_id: i64,
1132    pub relay_ids: Vec<i64>,
1133}
1134
1135impl CommandSyntax for ApiAddGroupRelays {
1136    const COMMAND_BUF_SIZE: usize = 256;
1137
1138    fn append_command_syntax(&self, buf: &mut String) {
1139        buf.push_str("/_add ");
1140        buf.push_str("relays ");
1141        buf.push('#');
1142        write!(buf, "{}", self.group_id).unwrap();
1143        buf.push(' ');
1144        let mut iter = self.relay_ids.iter();
1145        if let Some(el) = iter.next() {
1146            write!(buf, "{el}").unwrap();
1147        }
1148        for el in iter {
1149            buf.push(',');
1150            write!(buf, "{el}").unwrap();
1151        }
1152    }
1153}
1154
1155/// ### Group commands
1156///
1157/// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
1158///
1159/// ----
1160///
1161/// Clear relay rejection for a channel (relay operator).
1162///
1163/// *Network usage*: background.
1164///
1165/// *Syntax:*
1166///
1167/// ```
1168/// /_relay allow #<groupId>
1169/// ```
1170#[derive(Debug, Clone, PartialEq)]
1171#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1172pub struct ApiAllowRelayGroup {
1173    pub group_id: i64,
1174}
1175
1176impl CommandSyntax for ApiAllowRelayGroup {
1177    const COMMAND_BUF_SIZE: usize = 64;
1178
1179    fn append_command_syntax(&self, buf: &mut String) {
1180        buf.push_str("/_relay ");
1181        buf.push_str("allow ");
1182        buf.push('#');
1183        write!(buf, "{}", self.group_id).unwrap();
1184    }
1185}
1186
1187/// ### Group commands
1188///
1189/// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
1190///
1191/// ----
1192///
1193/// Update group profile.
1194///
1195/// *Network usage*: background.
1196///
1197/// *Syntax:*
1198///
1199/// ```
1200/// /_group_profile #<groupId> <json(groupProfile)>
1201/// ```
1202#[derive(Debug, Clone, PartialEq)]
1203#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1204pub struct ApiUpdateGroupProfile {
1205    pub group_id: i64,
1206    pub group_profile: GroupProfile,
1207}
1208
1209impl CommandSyntax for ApiUpdateGroupProfile {
1210    const COMMAND_BUF_SIZE: usize = 1024;
1211
1212    fn append_command_syntax(&self, buf: &mut String) {
1213        buf.push_str("/_group_profile ");
1214        buf.push('#');
1215        write!(buf, "{}", self.group_id).unwrap();
1216        buf.push(' ');
1217        // SAFETY: serde_json guarantees to produce valid UTF-8 sequences
1218        unsafe {
1219            serde_json::to_writer(buf.as_mut_vec(), &self.group_profile).unwrap();
1220        }
1221    }
1222}
1223
1224/// ### Group link commands
1225///
1226/// These commands can be used by bots that manage multiple public groups
1227///
1228/// ----
1229///
1230/// Create group link.
1231///
1232/// *Network usage*: interactive.
1233///
1234/// *Syntax:*
1235///
1236/// ```
1237/// /_create link #<groupId> relay|observer|author|member|moderator|admin|owner
1238/// ```
1239#[derive(Debug, Clone, PartialEq)]
1240#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1241pub struct ApiCreateGroupLink {
1242    pub group_id: i64,
1243    pub member_role: GroupMemberRole,
1244}
1245
1246impl CommandSyntax for ApiCreateGroupLink {
1247    const COMMAND_BUF_SIZE: usize = 64;
1248
1249    fn append_command_syntax(&self, buf: &mut String) {
1250        buf.push_str("/_create ");
1251        buf.push_str("link ");
1252        buf.push('#');
1253        write!(buf, "{}", self.group_id).unwrap();
1254        buf.push(' ');
1255        match self.member_role {
1256            GroupMemberRole::Relay => {
1257                buf.push_str("relay");
1258            }
1259            GroupMemberRole::Observer => {
1260                buf.push_str("observer");
1261            }
1262            GroupMemberRole::Author => {
1263                buf.push_str("author");
1264            }
1265            GroupMemberRole::Member => {
1266                buf.push_str("member");
1267            }
1268            GroupMemberRole::Moderator => {
1269                buf.push_str("moderator");
1270            }
1271            GroupMemberRole::Admin => {
1272                buf.push_str("admin");
1273            }
1274            GroupMemberRole::Owner => {
1275                buf.push_str("owner");
1276            }
1277        }
1278    }
1279}
1280
1281/// ### Group link commands
1282///
1283/// These commands can be used by bots that manage multiple public groups
1284///
1285/// ----
1286///
1287/// Set member role for group link.
1288///
1289/// *Network usage*: no.
1290///
1291/// *Syntax:*
1292///
1293/// ```
1294/// /_set link role #<groupId> relay|observer|author|member|moderator|admin|owner
1295/// ```
1296#[derive(Debug, Clone, PartialEq)]
1297#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1298pub struct ApiGroupLinkMemberRole {
1299    pub group_id: i64,
1300    pub member_role: GroupMemberRole,
1301}
1302
1303impl CommandSyntax for ApiGroupLinkMemberRole {
1304    const COMMAND_BUF_SIZE: usize = 64;
1305
1306    fn append_command_syntax(&self, buf: &mut String) {
1307        buf.push_str("/_set ");
1308        buf.push_str("link ");
1309        buf.push_str("role ");
1310        buf.push('#');
1311        write!(buf, "{}", self.group_id).unwrap();
1312        buf.push(' ');
1313        match self.member_role {
1314            GroupMemberRole::Relay => {
1315                buf.push_str("relay");
1316            }
1317            GroupMemberRole::Observer => {
1318                buf.push_str("observer");
1319            }
1320            GroupMemberRole::Author => {
1321                buf.push_str("author");
1322            }
1323            GroupMemberRole::Member => {
1324                buf.push_str("member");
1325            }
1326            GroupMemberRole::Moderator => {
1327                buf.push_str("moderator");
1328            }
1329            GroupMemberRole::Admin => {
1330                buf.push_str("admin");
1331            }
1332            GroupMemberRole::Owner => {
1333                buf.push_str("owner");
1334            }
1335        }
1336    }
1337}
1338
1339/// ### Group link commands
1340///
1341/// These commands can be used by bots that manage multiple public groups
1342///
1343/// ----
1344///
1345/// Delete group link.
1346///
1347/// *Network usage*: background.
1348///
1349/// *Syntax:*
1350///
1351/// ```
1352/// /_delete link #<groupId>
1353/// ```
1354#[derive(Debug, Clone, PartialEq)]
1355#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1356pub struct ApiDeleteGroupLink {
1357    pub group_id: i64,
1358}
1359
1360impl CommandSyntax for ApiDeleteGroupLink {
1361    const COMMAND_BUF_SIZE: usize = 64;
1362
1363    fn append_command_syntax(&self, buf: &mut String) {
1364        buf.push_str("/_delete ");
1365        buf.push_str("link ");
1366        buf.push('#');
1367        write!(buf, "{}", self.group_id).unwrap();
1368    }
1369}
1370
1371/// ### Group link commands
1372///
1373/// These commands can be used by bots that manage multiple public groups
1374///
1375/// ----
1376///
1377/// Get group link.
1378///
1379/// *Network usage*: no.
1380///
1381/// *Syntax:*
1382///
1383/// ```
1384/// /_get link #<groupId>
1385/// ```
1386#[derive(Debug, Clone, PartialEq)]
1387#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1388pub struct ApiGetGroupLink {
1389    pub group_id: i64,
1390}
1391
1392impl CommandSyntax for ApiGetGroupLink {
1393    const COMMAND_BUF_SIZE: usize = 64;
1394
1395    fn append_command_syntax(&self, buf: &mut String) {
1396        buf.push_str("/_get ");
1397        buf.push_str("link ");
1398        buf.push('#');
1399        write!(buf, "{}", self.group_id).unwrap();
1400    }
1401}
1402
1403/// ### Connection commands
1404///
1405/// These commands may be used to create connections. Most bots do not need to use them - bot users will connect via bot address with auto-accept enabled.
1406///
1407/// ----
1408///
1409/// Create 1-time invitation link.
1410///
1411/// *Network usage*: interactive.
1412///
1413/// *Syntax:*
1414///
1415/// ```
1416/// /_connect <userId>[ incognito=on]
1417/// ```
1418#[derive(Debug, Clone, PartialEq)]
1419#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1420pub struct ApiAddContact {
1421    pub user_id: i64,
1422    pub incognito: bool,
1423}
1424
1425impl ApiAddContact {
1426    /// Creates a command with all `Option` parameters set to `None` and all `bool` parameters set to false
1427    pub fn new(user_id: i64) -> Self {
1428        Self {
1429            user_id,
1430            incognito: false,
1431        }
1432    }
1433}
1434
1435impl CommandSyntax for ApiAddContact {
1436    const COMMAND_BUF_SIZE: usize = 64;
1437
1438    fn append_command_syntax(&self, buf: &mut String) {
1439        buf.push_str("/_connect ");
1440        write!(buf, "{}", self.user_id).unwrap();
1441        if self.incognito {
1442            buf.push(' ');
1443            buf.push_str("incognito=");
1444            buf.push_str("on");
1445        }
1446    }
1447}
1448
1449/// ### Connection commands
1450///
1451/// These commands may be used to create connections. Most bots do not need to use them - bot users will connect via bot address with auto-accept enabled.
1452///
1453/// ----
1454///
1455/// Determine SimpleX link type and if the bot is already connected via this link or name.
1456///
1457/// *Network usage*: interactive.
1458///
1459/// *Syntax:*
1460///
1461/// ```
1462/// /_connect plan <userId> <connectTarget>
1463/// ```
1464#[derive(Debug, Clone, PartialEq)]
1465#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1466pub struct ApiConnectPlan {
1467    pub user_id: i64,
1468    pub connect_target: Option<String>,
1469    pub resolve_mode: PlanResolveMode,
1470    pub link_owner_sig: Option<LinkOwnerSig>,
1471}
1472
1473impl ApiConnectPlan {
1474    /// Creates a command with all `Option` parameters set to `None` and all `bool` parameters set to false
1475    pub fn new(user_id: i64, resolve_mode: PlanResolveMode) -> Self {
1476        Self {
1477            user_id,
1478            connect_target: None,
1479            resolve_mode,
1480            link_owner_sig: None,
1481        }
1482    }
1483}
1484
1485impl CommandSyntax for ApiConnectPlan {
1486    const COMMAND_BUF_SIZE: usize = 256;
1487
1488    fn append_command_syntax(&self, buf: &mut String) {
1489        buf.push_str("/_connect ");
1490        buf.push_str("plan ");
1491        write!(buf, "{}", self.user_id).unwrap();
1492        buf.push(' ');
1493        write!(
1494            buf,
1495            "{}",
1496            self.connect_target.as_deref().unwrap_or_default()
1497        )
1498        .unwrap();
1499    }
1500}
1501
1502/// ### Connection commands
1503///
1504/// These commands may be used to create connections. Most bots do not need to use them - bot users will connect via bot address with auto-accept enabled.
1505///
1506/// ----
1507///
1508/// Connect via prepared SimpleX link. The link can be 1-time invitation link, contact address or group link.
1509///
1510/// *Network usage*: interactive.
1511///
1512/// *Syntax:*
1513///
1514/// ```
1515/// /_connect <userId>[ <str(preparedLink_)>]
1516/// ```
1517#[derive(Debug, Clone, PartialEq)]
1518#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1519pub struct ApiConnect {
1520    pub user_id: i64,
1521    pub incognito: bool,
1522    pub prepared_link: Option<CreatedConnLink>,
1523}
1524
1525impl ApiConnect {
1526    /// Creates a command with all `Option` parameters set to `None` and all `bool` parameters set to false
1527    pub fn new(user_id: i64) -> Self {
1528        Self {
1529            user_id,
1530            incognito: false,
1531            prepared_link: None,
1532        }
1533    }
1534}
1535
1536impl CommandSyntax for ApiConnect {
1537    const COMMAND_BUF_SIZE: usize = 256;
1538
1539    fn append_command_syntax(&self, buf: &mut String) {
1540        buf.push_str("/_connect ");
1541        write!(buf, "{}", self.user_id).unwrap();
1542        if let Some(prepared_link) = &self.prepared_link {
1543            buf.push(' ');
1544            prepared_link.append_command_syntax(buf);
1545        }
1546    }
1547}
1548
1549/// ### Connection commands
1550///
1551/// These commands may be used to create connections. Most bots do not need to use them - bot users will connect via bot address with auto-accept enabled.
1552///
1553/// ----
1554///
1555/// Connect via SimpleX link or name as string in the active user profile.
1556///
1557/// *Network usage*: interactive.
1558///
1559/// *Syntax:*
1560///
1561/// ```
1562/// /connect[ <connTarget_>]
1563/// ```
1564#[derive(Debug, Clone, PartialEq)]
1565#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1566pub struct Connect {
1567    pub incognito: bool,
1568    pub conn_target: Option<String>,
1569}
1570
1571impl Connect {
1572    /// Creates a command with all `Option` parameters set to `None` and all `bool` parameters set to false
1573    pub fn new() -> Self {
1574        Self {
1575            incognito: false,
1576            conn_target: None,
1577        }
1578    }
1579}
1580
1581impl CommandSyntax for Connect {
1582    const COMMAND_BUF_SIZE: usize = 64;
1583
1584    fn append_command_syntax(&self, buf: &mut String) {
1585        buf.push_str("/connect");
1586        if let Some(conn_target) = &self.conn_target {
1587            buf.push(' ');
1588            write!(buf, "{}", conn_target).unwrap();
1589        }
1590    }
1591}
1592
1593/// ### Connection commands
1594///
1595/// These commands may be used to create connections. Most bots do not need to use them - bot users will connect via bot address with auto-accept enabled.
1596///
1597/// ----
1598///
1599/// Accept contact request.
1600///
1601/// *Network usage*: interactive.
1602///
1603/// *Syntax:*
1604///
1605/// ```
1606/// /_accept <contactReqId>
1607/// ```
1608#[derive(Debug, Clone, PartialEq)]
1609#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1610pub struct ApiAcceptContact {
1611    pub contact_req_id: i64,
1612}
1613
1614impl CommandSyntax for ApiAcceptContact {
1615    const COMMAND_BUF_SIZE: usize = 64;
1616
1617    fn append_command_syntax(&self, buf: &mut String) {
1618        buf.push_str("/_accept ");
1619        write!(buf, "{}", self.contact_req_id).unwrap();
1620    }
1621}
1622
1623/// ### Connection commands
1624///
1625/// These commands may be used to create connections. Most bots do not need to use them - bot users will connect via bot address with auto-accept enabled.
1626///
1627/// ----
1628///
1629/// Reject contact request. The user who sent the request is **not notified**.
1630///
1631/// *Network usage*: no.
1632///
1633/// *Syntax:*
1634///
1635/// ```
1636/// /_reject <contactReqId>
1637/// ```
1638#[derive(Debug, Clone, PartialEq)]
1639#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1640pub struct ApiRejectContact {
1641    pub contact_req_id: i64,
1642}
1643
1644impl CommandSyntax for ApiRejectContact {
1645    const COMMAND_BUF_SIZE: usize = 64;
1646
1647    fn append_command_syntax(&self, buf: &mut String) {
1648        buf.push_str("/_reject ");
1649        write!(buf, "{}", self.contact_req_id).unwrap();
1650    }
1651}
1652
1653/// ### Chat commands
1654///
1655/// Commands to list and delete conversations.
1656///
1657/// ----
1658///
1659/// Get contacts.
1660///
1661/// *Network usage*: no.
1662///
1663/// *Syntax:*
1664///
1665/// ```
1666/// /_contacts <userId>
1667/// ```
1668#[derive(Debug, Clone, PartialEq)]
1669#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1670pub struct ApiListContacts {
1671    pub user_id: i64,
1672}
1673
1674impl CommandSyntax for ApiListContacts {
1675    const COMMAND_BUF_SIZE: usize = 64;
1676
1677    fn append_command_syntax(&self, buf: &mut String) {
1678        buf.push_str("/_contacts ");
1679        write!(buf, "{}", self.user_id).unwrap();
1680    }
1681}
1682
1683/// ### Chat commands
1684///
1685/// Commands to list and delete conversations.
1686///
1687/// ----
1688///
1689/// Get groups.
1690///
1691/// *Network usage*: no.
1692///
1693/// *Syntax:*
1694///
1695/// ```
1696/// /_groups <userId>[ @<contactId_>][ <search>]
1697/// ```
1698#[derive(Debug, Clone, PartialEq)]
1699#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1700pub struct ApiListGroups {
1701    pub user_id: i64,
1702    pub contact_id: Option<i64>,
1703    pub search: Option<String>,
1704}
1705
1706impl ApiListGroups {
1707    /// Creates a command with all `Option` parameters set to `None` and all `bool` parameters set to false
1708    pub fn new(user_id: i64) -> Self {
1709        Self {
1710            user_id,
1711            contact_id: None,
1712            search: None,
1713        }
1714    }
1715}
1716
1717impl CommandSyntax for ApiListGroups {
1718    const COMMAND_BUF_SIZE: usize = 256;
1719
1720    fn append_command_syntax(&self, buf: &mut String) {
1721        buf.push_str("/_groups ");
1722        write!(buf, "{}", self.user_id).unwrap();
1723        if let Some(contact_id) = &self.contact_id {
1724            buf.push(' ');
1725            buf.push('@');
1726            write!(buf, "{}", contact_id).unwrap();
1727        }
1728        if let Some(search) = &self.search {
1729            buf.push(' ');
1730            write!(buf, "{}", search).unwrap();
1731        }
1732    }
1733}
1734
1735/// ### Chat commands
1736///
1737/// Commands to list and delete conversations.
1738///
1739/// ----
1740///
1741/// Get chat previews. Supports time-based pagination — use this instead of APIListContacts / APIListGroups when scanning at scale (those load every record into memory and fail on large databases).
1742///
1743/// *Network usage*: no.
1744///
1745/// *Syntax:*
1746///
1747/// ```
1748/// /_get chats <userId>[ pcc=on] <str(pagination)> <json(query)>
1749/// ```
1750#[derive(Debug, Clone, PartialEq)]
1751#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1752pub struct ApiGetChats {
1753    pub user_id: i64,
1754    pub pending_connections: bool,
1755    pub pagination: PaginationByTime,
1756    pub query: ChatListQuery,
1757}
1758
1759impl ApiGetChats {
1760    /// Creates a command with all `Option` parameters set to `None` and all `bool` parameters set to false
1761    pub fn new(user_id: i64, pagination: PaginationByTime, query: ChatListQuery) -> Self {
1762        Self {
1763            user_id,
1764            pending_connections: false,
1765            pagination,
1766            query,
1767        }
1768    }
1769}
1770
1771impl CommandSyntax for ApiGetChats {
1772    const COMMAND_BUF_SIZE: usize = 1024;
1773
1774    fn append_command_syntax(&self, buf: &mut String) {
1775        buf.push_str("/_get ");
1776        buf.push_str("chats ");
1777        write!(buf, "{}", self.user_id).unwrap();
1778        if self.pending_connections {
1779            buf.push(' ');
1780            buf.push_str("pcc=");
1781            buf.push_str("on");
1782        }
1783        buf.push(' ');
1784        self.pagination.append_command_syntax(buf);
1785        buf.push(' ');
1786        // SAFETY: serde_json guarantees to produce valid UTF-8 sequences
1787        unsafe {
1788            serde_json::to_writer(buf.as_mut_vec(), &self.query).unwrap();
1789        }
1790    }
1791}
1792
1793/// ### Chat commands
1794///
1795/// Commands to list and delete conversations.
1796///
1797/// ----
1798///
1799/// Delete chat.
1800///
1801/// *Network usage*: background.
1802///
1803/// *Syntax:*
1804///
1805/// ```
1806/// /_delete <str(chatRef)> <str(chatDeleteMode)>
1807/// ```
1808#[derive(Debug, Clone, PartialEq)]
1809#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1810pub struct ApiDeleteChat {
1811    pub chat_ref: ChatRef,
1812    pub chat_delete_mode: ChatDeleteMode,
1813}
1814
1815impl CommandSyntax for ApiDeleteChat {
1816    const COMMAND_BUF_SIZE: usize = 64;
1817
1818    fn append_command_syntax(&self, buf: &mut String) {
1819        buf.push_str("/_delete ");
1820        self.chat_ref.append_command_syntax(buf);
1821        buf.push(' ');
1822        self.chat_delete_mode.append_command_syntax(buf);
1823    }
1824}
1825
1826/// ### Chat commands
1827///
1828/// Commands to list and delete conversations.
1829///
1830/// ----
1831///
1832/// Set group custom data.
1833///
1834/// *Network usage*: no.
1835///
1836/// *Syntax:*
1837///
1838/// ```
1839/// /_set custom #<groupId>[ <json(customData)>]
1840/// ```
1841#[derive(Debug, Clone, PartialEq)]
1842#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1843pub struct ApiSetGroupCustomData {
1844    pub group_id: i64,
1845    pub custom_data: Option<JsonObject>,
1846}
1847
1848impl ApiSetGroupCustomData {
1849    /// Creates a command with all `Option` parameters set to `None` and all `bool` parameters set to false
1850    pub fn new(group_id: i64) -> Self {
1851        Self {
1852            group_id,
1853            custom_data: None,
1854        }
1855    }
1856}
1857
1858impl CommandSyntax for ApiSetGroupCustomData {
1859    const COMMAND_BUF_SIZE: usize = 1024;
1860
1861    fn append_command_syntax(&self, buf: &mut String) {
1862        buf.push_str("/_set ");
1863        buf.push_str("custom ");
1864        buf.push('#');
1865        write!(buf, "{}", self.group_id).unwrap();
1866        if let Some(custom_data) = &self.custom_data {
1867            buf.push(' ');
1868            // SAFETY: serde_json guarantees to produce valid UTF-8 sequences
1869            unsafe {
1870                serde_json::to_writer(buf.as_mut_vec(), &custom_data).unwrap();
1871            }
1872        }
1873    }
1874}
1875
1876/// ### Chat commands
1877///
1878/// Commands to list and delete conversations.
1879///
1880/// ----
1881///
1882/// Set contact custom data.
1883///
1884/// *Network usage*: no.
1885///
1886/// *Syntax:*
1887///
1888/// ```
1889/// /_set custom @<contactId>[ <json(customData)>]
1890/// ```
1891#[derive(Debug, Clone, PartialEq)]
1892#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1893pub struct ApiSetContactCustomData {
1894    pub contact_id: i64,
1895    pub custom_data: Option<JsonObject>,
1896}
1897
1898impl ApiSetContactCustomData {
1899    /// Creates a command with all `Option` parameters set to `None` and all `bool` parameters set to false
1900    pub fn new(contact_id: i64) -> Self {
1901        Self {
1902            contact_id,
1903            custom_data: None,
1904        }
1905    }
1906}
1907
1908impl CommandSyntax for ApiSetContactCustomData {
1909    const COMMAND_BUF_SIZE: usize = 1024;
1910
1911    fn append_command_syntax(&self, buf: &mut String) {
1912        buf.push_str("/_set ");
1913        buf.push_str("custom ");
1914        buf.push('@');
1915        write!(buf, "{}", self.contact_id).unwrap();
1916        if let Some(custom_data) = &self.custom_data {
1917            buf.push(' ');
1918            // SAFETY: serde_json guarantees to produce valid UTF-8 sequences
1919            unsafe {
1920                serde_json::to_writer(buf.as_mut_vec(), &custom_data).unwrap();
1921            }
1922        }
1923    }
1924}
1925
1926/// ### Chat commands
1927///
1928/// Commands to list and delete conversations.
1929///
1930/// ----
1931///
1932/// Set auto-accept member contacts.
1933///
1934/// *Network usage*: no.
1935///
1936/// *Syntax:*
1937///
1938/// ```
1939/// /_set accept member contacts <userId> on|off
1940/// ```
1941#[derive(Debug, Clone, PartialEq)]
1942#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1943pub struct ApiSetUserAutoAcceptMemberContacts {
1944    pub user_id: i64,
1945    pub on_off: bool,
1946}
1947
1948impl ApiSetUserAutoAcceptMemberContacts {
1949    /// Creates a command with all `Option` parameters set to `None` and all `bool` parameters set to false
1950    pub fn new(user_id: i64) -> Self {
1951        Self {
1952            user_id,
1953            on_off: false,
1954        }
1955    }
1956}
1957
1958impl CommandSyntax for ApiSetUserAutoAcceptMemberContacts {
1959    const COMMAND_BUF_SIZE: usize = 64;
1960
1961    fn append_command_syntax(&self, buf: &mut String) {
1962        buf.push_str("/_set ");
1963        buf.push_str("accept ");
1964        buf.push_str("member ");
1965        buf.push_str("contacts ");
1966        write!(buf, "{}", self.user_id).unwrap();
1967        buf.push(' ');
1968        if self.on_off {
1969            buf.push_str("on");
1970        } else {
1971            buf.push_str("off");
1972        }
1973    }
1974}
1975
1976/// ### User profile commands
1977///
1978/// Most bots don't need to use these commands, as bot profile can be configured manually via CLI or desktop client. These commands can be used by bots that need to manage multiple user profiles (e.g., the profiles of support agents).
1979///
1980/// ----
1981///
1982/// Get active user profile.
1983///
1984/// *Network usage*: no.
1985///
1986/// *Syntax:*
1987///
1988/// ```
1989/// /user
1990/// ```
1991#[derive(Debug, Clone, PartialEq)]
1992#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1993pub struct ShowActiveUser {}
1994
1995impl CommandSyntax for ShowActiveUser {
1996    const COMMAND_BUF_SIZE: usize = 0;
1997
1998    fn append_command_syntax(&self, buf: &mut String) {
1999        buf.push_str("/user");
2000    }
2001}
2002
2003/// ### User profile commands
2004///
2005/// Most bots don't need to use these commands, as bot profile can be configured manually via CLI or desktop client. These commands can be used by bots that need to manage multiple user profiles (e.g., the profiles of support agents).
2006///
2007/// ----
2008///
2009/// Create new user profile.
2010///
2011/// *Network usage*: no.
2012///
2013/// *Syntax:*
2014///
2015/// ```
2016/// /_create user <json(newUser)>
2017/// ```
2018#[derive(Debug, Clone, PartialEq)]
2019#[cfg_attr(feature = "bon", derive(::bon::Builder))]
2020pub struct CreateActiveUser {
2021    pub new_user: NewUser,
2022}
2023
2024impl CommandSyntax for CreateActiveUser {
2025    const COMMAND_BUF_SIZE: usize = 1024;
2026
2027    fn append_command_syntax(&self, buf: &mut String) {
2028        buf.push_str("/_create ");
2029        buf.push_str("user ");
2030        // SAFETY: serde_json guarantees to produce valid UTF-8 sequences
2031        unsafe {
2032            serde_json::to_writer(buf.as_mut_vec(), &self.new_user).unwrap();
2033        }
2034    }
2035}
2036
2037/// ### User profile commands
2038///
2039/// Most bots don't need to use these commands, as bot profile can be configured manually via CLI or desktop client. These commands can be used by bots that need to manage multiple user profiles (e.g., the profiles of support agents).
2040///
2041/// ----
2042///
2043/// Get all user profiles.
2044///
2045/// *Network usage*: no.
2046///
2047/// *Syntax:*
2048///
2049/// ```
2050/// /users
2051/// ```
2052#[derive(Debug, Clone, PartialEq)]
2053#[cfg_attr(feature = "bon", derive(::bon::Builder))]
2054pub struct ListUsers {}
2055
2056impl CommandSyntax for ListUsers {
2057    const COMMAND_BUF_SIZE: usize = 0;
2058
2059    fn append_command_syntax(&self, buf: &mut String) {
2060        buf.push_str("/users");
2061    }
2062}
2063
2064/// ### User profile commands
2065///
2066/// Most bots don't need to use these commands, as bot profile can be configured manually via CLI or desktop client. These commands can be used by bots that need to manage multiple user profiles (e.g., the profiles of support agents).
2067///
2068/// ----
2069///
2070/// Set active user profile.
2071///
2072/// *Network usage*: no.
2073///
2074/// *Syntax:*
2075///
2076/// ```
2077/// /_user <userId>[ <json(viewPwd)>]
2078/// ```
2079#[derive(Debug, Clone, PartialEq)]
2080#[cfg_attr(feature = "bon", derive(::bon::Builder))]
2081pub struct ApiSetActiveUser {
2082    pub user_id: i64,
2083    pub view_pwd: Option<String>,
2084}
2085
2086impl ApiSetActiveUser {
2087    /// Creates a command with all `Option` parameters set to `None` and all `bool` parameters set to false
2088    pub fn new(user_id: i64) -> Self {
2089        Self {
2090            user_id,
2091            view_pwd: None,
2092        }
2093    }
2094}
2095
2096impl CommandSyntax for ApiSetActiveUser {
2097    const COMMAND_BUF_SIZE: usize = 1024;
2098
2099    fn append_command_syntax(&self, buf: &mut String) {
2100        buf.push_str("/_user ");
2101        write!(buf, "{}", self.user_id).unwrap();
2102        if let Some(view_pwd) = &self.view_pwd {
2103            buf.push(' ');
2104            // SAFETY: serde_json guarantees to produce valid UTF-8 sequences
2105            unsafe {
2106                serde_json::to_writer(buf.as_mut_vec(), &view_pwd).unwrap();
2107            }
2108        }
2109    }
2110}
2111
2112/// ### User profile commands
2113///
2114/// Most bots don't need to use these commands, as bot profile can be configured manually via CLI or desktop client. These commands can be used by bots that need to manage multiple user profiles (e.g., the profiles of support agents).
2115///
2116/// ----
2117///
2118/// Delete user profile.
2119///
2120/// *Network usage*: background.
2121///
2122/// *Syntax:*
2123///
2124/// ```
2125/// /_delete user <userId> del_smp=on|off[ <json(viewPwd)>]
2126/// ```
2127#[derive(Debug, Clone, PartialEq)]
2128#[cfg_attr(feature = "bon", derive(::bon::Builder))]
2129pub struct ApiDeleteUser {
2130    pub user_id: i64,
2131    pub del_smp_queues: bool,
2132    pub view_pwd: Option<String>,
2133}
2134
2135impl ApiDeleteUser {
2136    /// Creates a command with all `Option` parameters set to `None` and all `bool` parameters set to false
2137    pub fn new(user_id: i64) -> Self {
2138        Self {
2139            user_id,
2140            del_smp_queues: false,
2141            view_pwd: None,
2142        }
2143    }
2144}
2145
2146impl CommandSyntax for ApiDeleteUser {
2147    const COMMAND_BUF_SIZE: usize = 1024;
2148
2149    fn append_command_syntax(&self, buf: &mut String) {
2150        buf.push_str("/_delete ");
2151        buf.push_str("user ");
2152        write!(buf, "{}", self.user_id).unwrap();
2153        buf.push(' ');
2154        buf.push_str("del_smp=");
2155        if self.del_smp_queues {
2156            buf.push_str("on");
2157        } else {
2158            buf.push_str("off");
2159        }
2160        if let Some(view_pwd) = &self.view_pwd {
2161            buf.push(' ');
2162            // SAFETY: serde_json guarantees to produce valid UTF-8 sequences
2163            unsafe {
2164                serde_json::to_writer(buf.as_mut_vec(), &view_pwd).unwrap();
2165            }
2166        }
2167    }
2168}
2169
2170/// ### User profile commands
2171///
2172/// Most bots don't need to use these commands, as bot profile can be configured manually via CLI or desktop client. These commands can be used by bots that need to manage multiple user profiles (e.g., the profiles of support agents).
2173///
2174/// ----
2175///
2176/// Update user profile.
2177///
2178/// *Network usage*: background.
2179///
2180/// *Syntax:*
2181///
2182/// ```
2183/// /_profile <userId> <json(profile)>
2184/// ```
2185#[derive(Debug, Clone, PartialEq)]
2186#[cfg_attr(feature = "bon", derive(::bon::Builder))]
2187pub struct ApiUpdateProfile {
2188    pub user_id: i64,
2189    pub profile: Profile,
2190}
2191
2192impl CommandSyntax for ApiUpdateProfile {
2193    const COMMAND_BUF_SIZE: usize = 1024;
2194
2195    fn append_command_syntax(&self, buf: &mut String) {
2196        buf.push_str("/_profile ");
2197        write!(buf, "{}", self.user_id).unwrap();
2198        buf.push(' ');
2199        // SAFETY: serde_json guarantees to produce valid UTF-8 sequences
2200        unsafe {
2201            serde_json::to_writer(buf.as_mut_vec(), &self.profile).unwrap();
2202        }
2203    }
2204}
2205
2206/// ### User profile commands
2207///
2208/// Most bots don't need to use these commands, as bot profile can be configured manually via CLI or desktop client. These commands can be used by bots that need to manage multiple user profiles (e.g., the profiles of support agents).
2209///
2210/// ----
2211///
2212/// Configure chat preference overrides for the contact.
2213///
2214/// *Network usage*: background.
2215///
2216/// *Syntax:*
2217///
2218/// ```
2219/// /_set prefs @<contactId> <json(preferences)>
2220/// ```
2221#[derive(Debug, Clone, PartialEq)]
2222#[cfg_attr(feature = "bon", derive(::bon::Builder))]
2223pub struct ApiSetContactPrefs {
2224    pub contact_id: i64,
2225    pub preferences: Preferences,
2226}
2227
2228impl CommandSyntax for ApiSetContactPrefs {
2229    const COMMAND_BUF_SIZE: usize = 1024;
2230
2231    fn append_command_syntax(&self, buf: &mut String) {
2232        buf.push_str("/_set ");
2233        buf.push_str("prefs ");
2234        buf.push('@');
2235        write!(buf, "{}", self.contact_id).unwrap();
2236        buf.push(' ');
2237        // SAFETY: serde_json guarantees to produce valid UTF-8 sequences
2238        unsafe {
2239            serde_json::to_writer(buf.as_mut_vec(), &self.preferences).unwrap();
2240        }
2241    }
2242}
2243
2244/// ### Chat management
2245///
2246/// These commands should not be used with CLI-based bots
2247///
2248/// ----
2249///
2250/// Start chat controller.
2251///
2252/// *Network usage*: no.
2253///
2254/// *Syntax:*
2255///
2256/// ```
2257/// /_start
2258/// ```
2259#[derive(Debug, Clone, PartialEq)]
2260#[cfg_attr(feature = "bon", derive(::bon::Builder))]
2261pub struct StartChat {
2262    pub main_app: bool,
2263    pub enable_snd_files: bool,
2264}
2265
2266impl StartChat {
2267    /// Creates a command with all `Option` parameters set to `None` and all `bool` parameters set to false
2268    pub fn new() -> Self {
2269        Self {
2270            main_app: false,
2271            enable_snd_files: false,
2272        }
2273    }
2274}
2275
2276impl CommandSyntax for StartChat {
2277    const COMMAND_BUF_SIZE: usize = 64;
2278
2279    fn append_command_syntax(&self, buf: &mut String) {
2280        buf.push_str("/_start");
2281    }
2282}
2283
2284/// ### Chat management
2285///
2286/// These commands should not be used with CLI-based bots
2287///
2288/// ----
2289///
2290/// Stop chat controller.
2291///
2292/// *Network usage*: no.
2293///
2294/// *Syntax:*
2295///
2296/// ```
2297/// /_stop
2298/// ```
2299#[derive(Debug, Clone, PartialEq)]
2300#[cfg_attr(feature = "bon", derive(::bon::Builder))]
2301pub struct ApiStopChat {}
2302
2303impl CommandSyntax for ApiStopChat {
2304    const COMMAND_BUF_SIZE: usize = 0;
2305
2306    fn append_command_syntax(&self, buf: &mut String) {
2307        buf.push_str("/_stop");
2308    }
2309}