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