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/// Update group profile.
1155///
1156/// *Network usage*: background.
1157///
1158/// *Syntax:*
1159///
1160/// ```
1161/// /_group_profile #<groupId> <json(groupProfile)>
1162/// ```
1163#[derive(Debug, Clone, PartialEq)]
1164#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1165pub struct ApiUpdateGroupProfile {
1166    pub group_id: i64,
1167    pub group_profile: GroupProfile,
1168}
1169
1170impl CommandSyntax for ApiUpdateGroupProfile {
1171    const COMMAND_BUF_SIZE: usize = 1024;
1172
1173    fn append_command_syntax(&self, buf: &mut String) {
1174        buf.push_str("/_group_profile ");
1175        buf.push('#');
1176        write!(buf, "{}", self.group_id).unwrap();
1177        buf.push(' ');
1178        // SAFETY: serde_json guarantees to produce valid UTF-8 sequences
1179        unsafe {
1180            serde_json::to_writer(buf.as_mut_vec(), &self.group_profile).unwrap();
1181        }
1182    }
1183}
1184
1185/// ### Group link commands
1186///
1187/// These commands can be used by bots that manage multiple public groups
1188///
1189/// ----
1190///
1191/// Create group link.
1192///
1193/// *Network usage*: interactive.
1194///
1195/// *Syntax:*
1196///
1197/// ```
1198/// /_create link #<groupId> relay|observer|author|member|moderator|admin|owner
1199/// ```
1200#[derive(Debug, Clone, PartialEq)]
1201#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1202pub struct ApiCreateGroupLink {
1203    pub group_id: i64,
1204    pub member_role: GroupMemberRole,
1205}
1206
1207impl CommandSyntax for ApiCreateGroupLink {
1208    const COMMAND_BUF_SIZE: usize = 64;
1209
1210    fn append_command_syntax(&self, buf: &mut String) {
1211        buf.push_str("/_create ");
1212        buf.push_str("link ");
1213        buf.push('#');
1214        write!(buf, "{}", self.group_id).unwrap();
1215        buf.push(' ');
1216        match self.member_role {
1217            GroupMemberRole::Relay => {
1218                buf.push_str("relay");
1219            }
1220            GroupMemberRole::Observer => {
1221                buf.push_str("observer");
1222            }
1223            GroupMemberRole::Author => {
1224                buf.push_str("author");
1225            }
1226            GroupMemberRole::Member => {
1227                buf.push_str("member");
1228            }
1229            GroupMemberRole::Moderator => {
1230                buf.push_str("moderator");
1231            }
1232            GroupMemberRole::Admin => {
1233                buf.push_str("admin");
1234            }
1235            GroupMemberRole::Owner => {
1236                buf.push_str("owner");
1237            }
1238        }
1239    }
1240}
1241
1242/// ### Group link commands
1243///
1244/// These commands can be used by bots that manage multiple public groups
1245///
1246/// ----
1247///
1248/// Set member role for group link.
1249///
1250/// *Network usage*: no.
1251///
1252/// *Syntax:*
1253///
1254/// ```
1255/// /_set link role #<groupId> relay|observer|author|member|moderator|admin|owner
1256/// ```
1257#[derive(Debug, Clone, PartialEq)]
1258#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1259pub struct ApiGroupLinkMemberRole {
1260    pub group_id: i64,
1261    pub member_role: GroupMemberRole,
1262}
1263
1264impl CommandSyntax for ApiGroupLinkMemberRole {
1265    const COMMAND_BUF_SIZE: usize = 64;
1266
1267    fn append_command_syntax(&self, buf: &mut String) {
1268        buf.push_str("/_set ");
1269        buf.push_str("link ");
1270        buf.push_str("role ");
1271        buf.push('#');
1272        write!(buf, "{}", self.group_id).unwrap();
1273        buf.push(' ');
1274        match self.member_role {
1275            GroupMemberRole::Relay => {
1276                buf.push_str("relay");
1277            }
1278            GroupMemberRole::Observer => {
1279                buf.push_str("observer");
1280            }
1281            GroupMemberRole::Author => {
1282                buf.push_str("author");
1283            }
1284            GroupMemberRole::Member => {
1285                buf.push_str("member");
1286            }
1287            GroupMemberRole::Moderator => {
1288                buf.push_str("moderator");
1289            }
1290            GroupMemberRole::Admin => {
1291                buf.push_str("admin");
1292            }
1293            GroupMemberRole::Owner => {
1294                buf.push_str("owner");
1295            }
1296        }
1297    }
1298}
1299
1300/// ### Group link commands
1301///
1302/// These commands can be used by bots that manage multiple public groups
1303///
1304/// ----
1305///
1306/// Delete group link.
1307///
1308/// *Network usage*: background.
1309///
1310/// *Syntax:*
1311///
1312/// ```
1313/// /_delete link #<groupId>
1314/// ```
1315#[derive(Debug, Clone, PartialEq)]
1316#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1317pub struct ApiDeleteGroupLink {
1318    pub group_id: i64,
1319}
1320
1321impl CommandSyntax for ApiDeleteGroupLink {
1322    const COMMAND_BUF_SIZE: usize = 64;
1323
1324    fn append_command_syntax(&self, buf: &mut String) {
1325        buf.push_str("/_delete ");
1326        buf.push_str("link ");
1327        buf.push('#');
1328        write!(buf, "{}", self.group_id).unwrap();
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/// Get group link.
1339///
1340/// *Network usage*: no.
1341///
1342/// *Syntax:*
1343///
1344/// ```
1345/// /_get link #<groupId>
1346/// ```
1347#[derive(Debug, Clone, PartialEq)]
1348#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1349pub struct ApiGetGroupLink {
1350    pub group_id: i64,
1351}
1352
1353impl CommandSyntax for ApiGetGroupLink {
1354    const COMMAND_BUF_SIZE: usize = 64;
1355
1356    fn append_command_syntax(&self, buf: &mut String) {
1357        buf.push_str("/_get ");
1358        buf.push_str("link ");
1359        buf.push('#');
1360        write!(buf, "{}", self.group_id).unwrap();
1361    }
1362}
1363
1364/// ### Connection commands
1365///
1366/// 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.
1367///
1368/// ----
1369///
1370/// Create 1-time invitation link.
1371///
1372/// *Network usage*: interactive.
1373///
1374/// *Syntax:*
1375///
1376/// ```
1377/// /_connect <userId>[ incognito=on]
1378/// ```
1379#[derive(Debug, Clone, PartialEq)]
1380#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1381pub struct ApiAddContact {
1382    pub user_id: i64,
1383    pub incognito: bool,
1384}
1385
1386impl ApiAddContact {
1387    /// Creates a command with all `Option` parameters set to `None` and all `bool` parameters set to false
1388    pub fn new(user_id: i64) -> Self {
1389        Self {
1390            user_id,
1391            incognito: false,
1392        }
1393    }
1394}
1395
1396impl CommandSyntax for ApiAddContact {
1397    const COMMAND_BUF_SIZE: usize = 64;
1398
1399    fn append_command_syntax(&self, buf: &mut String) {
1400        buf.push_str("/_connect ");
1401        write!(buf, "{}", self.user_id).unwrap();
1402        if self.incognito {
1403            buf.push(' ');
1404            buf.push_str("incognito=");
1405            buf.push_str("on");
1406        }
1407    }
1408}
1409
1410/// ### Connection commands
1411///
1412/// 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.
1413///
1414/// ----
1415///
1416/// Determine SimpleX link type and if the bot is already connected via this link.
1417///
1418/// *Network usage*: interactive.
1419///
1420/// *Syntax:*
1421///
1422/// ```
1423/// /_connect plan <userId> <connectionLink>
1424/// ```
1425#[derive(Debug, Clone, PartialEq)]
1426#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1427pub struct ApiConnectPlan {
1428    pub user_id: i64,
1429    pub connection_link: Option<String>,
1430    pub resolve_known: bool,
1431    pub link_owner_sig: Option<LinkOwnerSig>,
1432}
1433
1434impl ApiConnectPlan {
1435    /// Creates a command with all `Option` parameters set to `None` and all `bool` parameters set to false
1436    pub fn new(user_id: i64) -> Self {
1437        Self {
1438            user_id,
1439            connection_link: None,
1440            resolve_known: false,
1441            link_owner_sig: None,
1442        }
1443    }
1444}
1445
1446impl CommandSyntax for ApiConnectPlan {
1447    const COMMAND_BUF_SIZE: usize = 256;
1448
1449    fn append_command_syntax(&self, buf: &mut String) {
1450        buf.push_str("/_connect ");
1451        buf.push_str("plan ");
1452        write!(buf, "{}", self.user_id).unwrap();
1453        buf.push(' ');
1454        write!(
1455            buf,
1456            "{}",
1457            self.connection_link.as_deref().unwrap_or_default()
1458        )
1459        .unwrap();
1460    }
1461}
1462
1463/// ### Connection commands
1464///
1465/// 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.
1466///
1467/// ----
1468///
1469/// Connect via prepared SimpleX link. The link can be 1-time invitation link, contact address or group link.
1470///
1471/// *Network usage*: interactive.
1472///
1473/// *Syntax:*
1474///
1475/// ```
1476/// /_connect <userId>[ <str(preparedLink_)>]
1477/// ```
1478#[derive(Debug, Clone, PartialEq)]
1479#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1480pub struct ApiConnect {
1481    pub user_id: i64,
1482    pub incognito: bool,
1483    pub prepared_link: Option<CreatedConnLink>,
1484}
1485
1486impl ApiConnect {
1487    /// Creates a command with all `Option` parameters set to `None` and all `bool` parameters set to false
1488    pub fn new(user_id: i64) -> Self {
1489        Self {
1490            user_id,
1491            incognito: false,
1492            prepared_link: None,
1493        }
1494    }
1495}
1496
1497impl CommandSyntax for ApiConnect {
1498    const COMMAND_BUF_SIZE: usize = 256;
1499
1500    fn append_command_syntax(&self, buf: &mut String) {
1501        buf.push_str("/_connect ");
1502        write!(buf, "{}", self.user_id).unwrap();
1503        if let Some(prepared_link) = &self.prepared_link {
1504            buf.push(' ');
1505            prepared_link.append_command_syntax(buf);
1506        }
1507    }
1508}
1509
1510/// ### Connection commands
1511///
1512/// 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.
1513///
1514/// ----
1515///
1516/// Connect via SimpleX link as string in the active user profile.
1517///
1518/// *Network usage*: interactive.
1519///
1520/// *Syntax:*
1521///
1522/// ```
1523/// /connect[ <connLink_>]
1524/// ```
1525#[derive(Debug, Clone, PartialEq)]
1526#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1527pub struct Connect {
1528    pub incognito: bool,
1529    pub conn_link: Option<String>,
1530}
1531
1532impl Connect {
1533    /// Creates a command with all `Option` parameters set to `None` and all `bool` parameters set to false
1534    pub fn new() -> Self {
1535        Self {
1536            incognito: false,
1537            conn_link: None,
1538        }
1539    }
1540}
1541
1542impl CommandSyntax for Connect {
1543    const COMMAND_BUF_SIZE: usize = 64;
1544
1545    fn append_command_syntax(&self, buf: &mut String) {
1546        buf.push_str("/connect");
1547        if let Some(conn_link) = &self.conn_link {
1548            buf.push(' ');
1549            write!(buf, "{}", conn_link).unwrap();
1550        }
1551    }
1552}
1553
1554/// ### Connection commands
1555///
1556/// 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.
1557///
1558/// ----
1559///
1560/// Accept contact request.
1561///
1562/// *Network usage*: interactive.
1563///
1564/// *Syntax:*
1565///
1566/// ```
1567/// /_accept <contactReqId>
1568/// ```
1569#[derive(Debug, Clone, PartialEq)]
1570#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1571pub struct ApiAcceptContact {
1572    pub contact_req_id: i64,
1573}
1574
1575impl CommandSyntax for ApiAcceptContact {
1576    const COMMAND_BUF_SIZE: usize = 64;
1577
1578    fn append_command_syntax(&self, buf: &mut String) {
1579        buf.push_str("/_accept ");
1580        write!(buf, "{}", self.contact_req_id).unwrap();
1581    }
1582}
1583
1584/// ### Connection commands
1585///
1586/// 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.
1587///
1588/// ----
1589///
1590/// Reject contact request. The user who sent the request is **not notified**.
1591///
1592/// *Network usage*: no.
1593///
1594/// *Syntax:*
1595///
1596/// ```
1597/// /_reject <contactReqId>
1598/// ```
1599#[derive(Debug, Clone, PartialEq)]
1600#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1601pub struct ApiRejectContact {
1602    pub contact_req_id: i64,
1603}
1604
1605impl CommandSyntax for ApiRejectContact {
1606    const COMMAND_BUF_SIZE: usize = 64;
1607
1608    fn append_command_syntax(&self, buf: &mut String) {
1609        buf.push_str("/_reject ");
1610        write!(buf, "{}", self.contact_req_id).unwrap();
1611    }
1612}
1613
1614/// ### Chat commands
1615///
1616/// Commands to list and delete conversations.
1617///
1618/// ----
1619///
1620/// Get contacts.
1621///
1622/// *Network usage*: no.
1623///
1624/// *Syntax:*
1625///
1626/// ```
1627/// /_contacts <userId>
1628/// ```
1629#[derive(Debug, Clone, PartialEq)]
1630#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1631pub struct ApiListContacts {
1632    pub user_id: i64,
1633}
1634
1635impl CommandSyntax for ApiListContacts {
1636    const COMMAND_BUF_SIZE: usize = 64;
1637
1638    fn append_command_syntax(&self, buf: &mut String) {
1639        buf.push_str("/_contacts ");
1640        write!(buf, "{}", self.user_id).unwrap();
1641    }
1642}
1643
1644/// ### Chat commands
1645///
1646/// Commands to list and delete conversations.
1647///
1648/// ----
1649///
1650/// Get groups.
1651///
1652/// *Network usage*: no.
1653///
1654/// *Syntax:*
1655///
1656/// ```
1657/// /_groups <userId>[ @<contactId_>][ <search>]
1658/// ```
1659#[derive(Debug, Clone, PartialEq)]
1660#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1661pub struct ApiListGroups {
1662    pub user_id: i64,
1663    pub contact_id: Option<i64>,
1664    pub search: Option<String>,
1665}
1666
1667impl ApiListGroups {
1668    /// Creates a command with all `Option` parameters set to `None` and all `bool` parameters set to false
1669    pub fn new(user_id: i64) -> Self {
1670        Self {
1671            user_id,
1672            contact_id: None,
1673            search: None,
1674        }
1675    }
1676}
1677
1678impl CommandSyntax for ApiListGroups {
1679    const COMMAND_BUF_SIZE: usize = 256;
1680
1681    fn append_command_syntax(&self, buf: &mut String) {
1682        buf.push_str("/_groups ");
1683        write!(buf, "{}", self.user_id).unwrap();
1684        if let Some(contact_id) = &self.contact_id {
1685            buf.push(' ');
1686            buf.push('@');
1687            write!(buf, "{}", contact_id).unwrap();
1688        }
1689        if let Some(search) = &self.search {
1690            buf.push(' ');
1691            write!(buf, "{}", search).unwrap();
1692        }
1693    }
1694}
1695
1696/// ### Chat commands
1697///
1698/// Commands to list and delete conversations.
1699///
1700/// ----
1701///
1702/// 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).
1703///
1704/// *Network usage*: no.
1705///
1706/// *Syntax:*
1707///
1708/// ```
1709/// /_get chats <userId>[ pcc=on] <str(pagination)> <json(query)>
1710/// ```
1711#[derive(Debug, Clone, PartialEq)]
1712#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1713pub struct ApiGetChats {
1714    pub user_id: i64,
1715    pub pending_connections: bool,
1716    pub pagination: PaginationByTime,
1717    pub query: ChatListQuery,
1718}
1719
1720impl ApiGetChats {
1721    /// Creates a command with all `Option` parameters set to `None` and all `bool` parameters set to false
1722    pub fn new(user_id: i64, pagination: PaginationByTime, query: ChatListQuery) -> Self {
1723        Self {
1724            user_id,
1725            pending_connections: false,
1726            pagination,
1727            query,
1728        }
1729    }
1730}
1731
1732impl CommandSyntax for ApiGetChats {
1733    const COMMAND_BUF_SIZE: usize = 1024;
1734
1735    fn append_command_syntax(&self, buf: &mut String) {
1736        buf.push_str("/_get ");
1737        buf.push_str("chats ");
1738        write!(buf, "{}", self.user_id).unwrap();
1739        if self.pending_connections {
1740            buf.push(' ');
1741            buf.push_str("pcc=");
1742            buf.push_str("on");
1743        }
1744        buf.push(' ');
1745        self.pagination.append_command_syntax(buf);
1746        buf.push(' ');
1747        // SAFETY: serde_json guarantees to produce valid UTF-8 sequences
1748        unsafe {
1749            serde_json::to_writer(buf.as_mut_vec(), &self.query).unwrap();
1750        }
1751    }
1752}
1753
1754/// ### Chat commands
1755///
1756/// Commands to list and delete conversations.
1757///
1758/// ----
1759///
1760/// Delete chat.
1761///
1762/// *Network usage*: background.
1763///
1764/// *Syntax:*
1765///
1766/// ```
1767/// /_delete <str(chatRef)> <str(chatDeleteMode)>
1768/// ```
1769#[derive(Debug, Clone, PartialEq)]
1770#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1771pub struct ApiDeleteChat {
1772    pub chat_ref: ChatRef,
1773    pub chat_delete_mode: ChatDeleteMode,
1774}
1775
1776impl CommandSyntax for ApiDeleteChat {
1777    const COMMAND_BUF_SIZE: usize = 64;
1778
1779    fn append_command_syntax(&self, buf: &mut String) {
1780        buf.push_str("/_delete ");
1781        self.chat_ref.append_command_syntax(buf);
1782        buf.push(' ');
1783        self.chat_delete_mode.append_command_syntax(buf);
1784    }
1785}
1786
1787/// ### Chat commands
1788///
1789/// Commands to list and delete conversations.
1790///
1791/// ----
1792///
1793/// Set group custom data.
1794///
1795/// *Network usage*: no.
1796///
1797/// *Syntax:*
1798///
1799/// ```
1800/// /_set custom #<groupId>[ <json(customData)>]
1801/// ```
1802#[derive(Debug, Clone, PartialEq)]
1803#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1804pub struct ApiSetGroupCustomData {
1805    pub group_id: i64,
1806    pub custom_data: Option<JsonObject>,
1807}
1808
1809impl ApiSetGroupCustomData {
1810    /// Creates a command with all `Option` parameters set to `None` and all `bool` parameters set to false
1811    pub fn new(group_id: i64) -> Self {
1812        Self {
1813            group_id,
1814            custom_data: None,
1815        }
1816    }
1817}
1818
1819impl CommandSyntax for ApiSetGroupCustomData {
1820    const COMMAND_BUF_SIZE: usize = 1024;
1821
1822    fn append_command_syntax(&self, buf: &mut String) {
1823        buf.push_str("/_set ");
1824        buf.push_str("custom ");
1825        buf.push('#');
1826        write!(buf, "{}", self.group_id).unwrap();
1827        if let Some(custom_data) = &self.custom_data {
1828            buf.push(' ');
1829            // SAFETY: serde_json guarantees to produce valid UTF-8 sequences
1830            unsafe {
1831                serde_json::to_writer(buf.as_mut_vec(), &custom_data).unwrap();
1832            }
1833        }
1834    }
1835}
1836
1837/// ### Chat commands
1838///
1839/// Commands to list and delete conversations.
1840///
1841/// ----
1842///
1843/// Set contact custom data.
1844///
1845/// *Network usage*: no.
1846///
1847/// *Syntax:*
1848///
1849/// ```
1850/// /_set custom @<contactId>[ <json(customData)>]
1851/// ```
1852#[derive(Debug, Clone, PartialEq)]
1853#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1854pub struct ApiSetContactCustomData {
1855    pub contact_id: i64,
1856    pub custom_data: Option<JsonObject>,
1857}
1858
1859impl ApiSetContactCustomData {
1860    /// Creates a command with all `Option` parameters set to `None` and all `bool` parameters set to false
1861    pub fn new(contact_id: i64) -> Self {
1862        Self {
1863            contact_id,
1864            custom_data: None,
1865        }
1866    }
1867}
1868
1869impl CommandSyntax for ApiSetContactCustomData {
1870    const COMMAND_BUF_SIZE: usize = 1024;
1871
1872    fn append_command_syntax(&self, buf: &mut String) {
1873        buf.push_str("/_set ");
1874        buf.push_str("custom ");
1875        buf.push('@');
1876        write!(buf, "{}", self.contact_id).unwrap();
1877        if let Some(custom_data) = &self.custom_data {
1878            buf.push(' ');
1879            // SAFETY: serde_json guarantees to produce valid UTF-8 sequences
1880            unsafe {
1881                serde_json::to_writer(buf.as_mut_vec(), &custom_data).unwrap();
1882            }
1883        }
1884    }
1885}
1886
1887/// ### Chat commands
1888///
1889/// Commands to list and delete conversations.
1890///
1891/// ----
1892///
1893/// Set auto-accept member contacts.
1894///
1895/// *Network usage*: no.
1896///
1897/// *Syntax:*
1898///
1899/// ```
1900/// /_set accept member contacts <userId> on|off
1901/// ```
1902#[derive(Debug, Clone, PartialEq)]
1903#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1904pub struct ApiSetUserAutoAcceptMemberContacts {
1905    pub user_id: i64,
1906    pub on_off: bool,
1907}
1908
1909impl ApiSetUserAutoAcceptMemberContacts {
1910    /// Creates a command with all `Option` parameters set to `None` and all `bool` parameters set to false
1911    pub fn new(user_id: i64) -> Self {
1912        Self {
1913            user_id,
1914            on_off: false,
1915        }
1916    }
1917}
1918
1919impl CommandSyntax for ApiSetUserAutoAcceptMemberContacts {
1920    const COMMAND_BUF_SIZE: usize = 64;
1921
1922    fn append_command_syntax(&self, buf: &mut String) {
1923        buf.push_str("/_set ");
1924        buf.push_str("accept ");
1925        buf.push_str("member ");
1926        buf.push_str("contacts ");
1927        write!(buf, "{}", self.user_id).unwrap();
1928        buf.push(' ');
1929        if self.on_off {
1930            buf.push_str("on");
1931        } else {
1932            buf.push_str("off");
1933        }
1934    }
1935}
1936
1937/// ### User profile commands
1938///
1939/// 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).
1940///
1941/// ----
1942///
1943/// Get active user profile.
1944///
1945/// *Network usage*: no.
1946///
1947/// *Syntax:*
1948///
1949/// ```
1950/// /user
1951/// ```
1952#[derive(Debug, Clone, PartialEq)]
1953#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1954pub struct ShowActiveUser {}
1955
1956impl CommandSyntax for ShowActiveUser {
1957    const COMMAND_BUF_SIZE: usize = 0;
1958
1959    fn append_command_syntax(&self, buf: &mut String) {
1960        buf.push_str("/user");
1961    }
1962}
1963
1964/// ### User profile commands
1965///
1966/// 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).
1967///
1968/// ----
1969///
1970/// Create new user profile.
1971///
1972/// *Network usage*: no.
1973///
1974/// *Syntax:*
1975///
1976/// ```
1977/// /_create user <json(newUser)>
1978/// ```
1979#[derive(Debug, Clone, PartialEq)]
1980#[cfg_attr(feature = "bon", derive(::bon::Builder))]
1981pub struct CreateActiveUser {
1982    pub new_user: NewUser,
1983}
1984
1985impl CommandSyntax for CreateActiveUser {
1986    const COMMAND_BUF_SIZE: usize = 1024;
1987
1988    fn append_command_syntax(&self, buf: &mut String) {
1989        buf.push_str("/_create ");
1990        buf.push_str("user ");
1991        // SAFETY: serde_json guarantees to produce valid UTF-8 sequences
1992        unsafe {
1993            serde_json::to_writer(buf.as_mut_vec(), &self.new_user).unwrap();
1994        }
1995    }
1996}
1997
1998/// ### User profile commands
1999///
2000/// 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).
2001///
2002/// ----
2003///
2004/// Get all user profiles.
2005///
2006/// *Network usage*: no.
2007///
2008/// *Syntax:*
2009///
2010/// ```
2011/// /users
2012/// ```
2013#[derive(Debug, Clone, PartialEq)]
2014#[cfg_attr(feature = "bon", derive(::bon::Builder))]
2015pub struct ListUsers {}
2016
2017impl CommandSyntax for ListUsers {
2018    const COMMAND_BUF_SIZE: usize = 0;
2019
2020    fn append_command_syntax(&self, buf: &mut String) {
2021        buf.push_str("/users");
2022    }
2023}
2024
2025/// ### User profile commands
2026///
2027/// 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).
2028///
2029/// ----
2030///
2031/// Set active user profile.
2032///
2033/// *Network usage*: no.
2034///
2035/// *Syntax:*
2036///
2037/// ```
2038/// /_user <userId>[ <json(viewPwd)>]
2039/// ```
2040#[derive(Debug, Clone, PartialEq)]
2041#[cfg_attr(feature = "bon", derive(::bon::Builder))]
2042pub struct ApiSetActiveUser {
2043    pub user_id: i64,
2044    pub view_pwd: Option<String>,
2045}
2046
2047impl ApiSetActiveUser {
2048    /// Creates a command with all `Option` parameters set to `None` and all `bool` parameters set to false
2049    pub fn new(user_id: i64) -> Self {
2050        Self {
2051            user_id,
2052            view_pwd: None,
2053        }
2054    }
2055}
2056
2057impl CommandSyntax for ApiSetActiveUser {
2058    const COMMAND_BUF_SIZE: usize = 1024;
2059
2060    fn append_command_syntax(&self, buf: &mut String) {
2061        buf.push_str("/_user ");
2062        write!(buf, "{}", self.user_id).unwrap();
2063        if let Some(view_pwd) = &self.view_pwd {
2064            buf.push(' ');
2065            // SAFETY: serde_json guarantees to produce valid UTF-8 sequences
2066            unsafe {
2067                serde_json::to_writer(buf.as_mut_vec(), &view_pwd).unwrap();
2068            }
2069        }
2070    }
2071}
2072
2073/// ### User profile commands
2074///
2075/// 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).
2076///
2077/// ----
2078///
2079/// Delete user profile.
2080///
2081/// *Network usage*: background.
2082///
2083/// *Syntax:*
2084///
2085/// ```
2086/// /_delete user <userId> del_smp=on|off[ <json(viewPwd)>]
2087/// ```
2088#[derive(Debug, Clone, PartialEq)]
2089#[cfg_attr(feature = "bon", derive(::bon::Builder))]
2090pub struct ApiDeleteUser {
2091    pub user_id: i64,
2092    pub del_smp_queues: bool,
2093    pub view_pwd: Option<String>,
2094}
2095
2096impl ApiDeleteUser {
2097    /// Creates a command with all `Option` parameters set to `None` and all `bool` parameters set to false
2098    pub fn new(user_id: i64) -> Self {
2099        Self {
2100            user_id,
2101            del_smp_queues: false,
2102            view_pwd: None,
2103        }
2104    }
2105}
2106
2107impl CommandSyntax for ApiDeleteUser {
2108    const COMMAND_BUF_SIZE: usize = 1024;
2109
2110    fn append_command_syntax(&self, buf: &mut String) {
2111        buf.push_str("/_delete ");
2112        buf.push_str("user ");
2113        write!(buf, "{}", self.user_id).unwrap();
2114        buf.push(' ');
2115        buf.push_str("del_smp=");
2116        if self.del_smp_queues {
2117            buf.push_str("on");
2118        } else {
2119            buf.push_str("off");
2120        }
2121        if let Some(view_pwd) = &self.view_pwd {
2122            buf.push(' ');
2123            // SAFETY: serde_json guarantees to produce valid UTF-8 sequences
2124            unsafe {
2125                serde_json::to_writer(buf.as_mut_vec(), &view_pwd).unwrap();
2126            }
2127        }
2128    }
2129}
2130
2131/// ### User profile commands
2132///
2133/// 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).
2134///
2135/// ----
2136///
2137/// Update user profile.
2138///
2139/// *Network usage*: background.
2140///
2141/// *Syntax:*
2142///
2143/// ```
2144/// /_profile <userId> <json(profile)>
2145/// ```
2146#[derive(Debug, Clone, PartialEq)]
2147#[cfg_attr(feature = "bon", derive(::bon::Builder))]
2148pub struct ApiUpdateProfile {
2149    pub user_id: i64,
2150    pub profile: Profile,
2151}
2152
2153impl CommandSyntax for ApiUpdateProfile {
2154    const COMMAND_BUF_SIZE: usize = 1024;
2155
2156    fn append_command_syntax(&self, buf: &mut String) {
2157        buf.push_str("/_profile ");
2158        write!(buf, "{}", self.user_id).unwrap();
2159        buf.push(' ');
2160        // SAFETY: serde_json guarantees to produce valid UTF-8 sequences
2161        unsafe {
2162            serde_json::to_writer(buf.as_mut_vec(), &self.profile).unwrap();
2163        }
2164    }
2165}
2166
2167/// ### User profile commands
2168///
2169/// 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).
2170///
2171/// ----
2172///
2173/// Configure chat preference overrides for the contact.
2174///
2175/// *Network usage*: background.
2176///
2177/// *Syntax:*
2178///
2179/// ```
2180/// /_set prefs @<contactId> <json(preferences)>
2181/// ```
2182#[derive(Debug, Clone, PartialEq)]
2183#[cfg_attr(feature = "bon", derive(::bon::Builder))]
2184pub struct ApiSetContactPrefs {
2185    pub contact_id: i64,
2186    pub preferences: Preferences,
2187}
2188
2189impl CommandSyntax for ApiSetContactPrefs {
2190    const COMMAND_BUF_SIZE: usize = 1024;
2191
2192    fn append_command_syntax(&self, buf: &mut String) {
2193        buf.push_str("/_set ");
2194        buf.push_str("prefs ");
2195        buf.push('@');
2196        write!(buf, "{}", self.contact_id).unwrap();
2197        buf.push(' ');
2198        // SAFETY: serde_json guarantees to produce valid UTF-8 sequences
2199        unsafe {
2200            serde_json::to_writer(buf.as_mut_vec(), &self.preferences).unwrap();
2201        }
2202    }
2203}
2204
2205/// ### Chat management
2206///
2207/// These commands should not be used with CLI-based bots
2208///
2209/// ----
2210///
2211/// Start chat controller.
2212///
2213/// *Network usage*: no.
2214///
2215/// *Syntax:*
2216///
2217/// ```
2218/// /_start
2219/// ```
2220#[derive(Debug, Clone, PartialEq)]
2221#[cfg_attr(feature = "bon", derive(::bon::Builder))]
2222pub struct StartChat {
2223    pub main_app: bool,
2224    pub enable_snd_files: bool,
2225}
2226
2227impl StartChat {
2228    /// Creates a command with all `Option` parameters set to `None` and all `bool` parameters set to false
2229    pub fn new() -> Self {
2230        Self {
2231            main_app: false,
2232            enable_snd_files: false,
2233        }
2234    }
2235}
2236
2237impl CommandSyntax for StartChat {
2238    const COMMAND_BUF_SIZE: usize = 64;
2239
2240    fn append_command_syntax(&self, buf: &mut String) {
2241        buf.push_str("/_start");
2242    }
2243}
2244
2245/// ### Chat management
2246///
2247/// These commands should not be used with CLI-based bots
2248///
2249/// ----
2250///
2251/// Stop chat controller.
2252///
2253/// *Network usage*: no.
2254///
2255/// *Syntax:*
2256///
2257/// ```
2258/// /_stop
2259/// ```
2260#[derive(Debug, Clone, PartialEq)]
2261#[cfg_attr(feature = "bon", derive(::bon::Builder))]
2262pub struct ApiStopChat {}
2263
2264impl CommandSyntax for ApiStopChat {
2265    const COMMAND_BUF_SIZE: usize = 0;
2266
2267    fn append_command_syntax(&self, buf: &mut String) {
2268        buf.push_str("/_stop");
2269    }
2270}