1 /* SPDX-License-Identifier: GPL-3.0-or-later
2  * Copyright © 2016-2018 The TokTok team.
3  * Copyright © 2014 Tox project.
4  */
5 
6 /*
7  * Slightly better groupchats implementation.
8  */
9 #ifndef C_TOXCORE_TOXCORE_GROUP_H
10 #define C_TOXCORE_TOXCORE_GROUP_H
11 
12 #include "Messenger.h"
13 
14 typedef enum Groupchat_Status {
15     GROUPCHAT_STATUS_NONE,
16     GROUPCHAT_STATUS_VALID,
17     GROUPCHAT_STATUS_CONNECTED,
18 } Groupchat_Status;
19 
20 typedef enum Groupchat_Type {
21     GROUPCHAT_TYPE_TEXT,
22     GROUPCHAT_TYPE_AV,
23 } Groupchat_Type;
24 
25 #define MAX_LOSSY_COUNT 256
26 
27 typedef struct Message_Info {
28     uint32_t message_number;
29     uint8_t  message_id;
30 } Message_Info;
31 
32 #define MAX_LAST_MESSAGE_INFOS 8
33 
34 typedef struct Group_Peer {
35     uint8_t     real_pk[CRYPTO_PUBLIC_KEY_SIZE];
36     uint8_t     temp_pk[CRYPTO_PUBLIC_KEY_SIZE];
37     bool        temp_pk_updated;
38     bool        is_friend;
39 
40     uint64_t    last_active;
41 
42     Message_Info
43     last_message_infos[MAX_LAST_MESSAGE_INFOS]; /* received messages, strictly decreasing in message_number */
44     uint8_t     num_last_message_infos;
45 
46     uint8_t     nick[MAX_NAME_LENGTH];
47     uint8_t     nick_len;
48     bool        nick_updated;
49 
50     uint16_t peer_number;
51 
52     uint8_t  recv_lossy[MAX_LOSSY_COUNT];
53     uint16_t bottom_lossy_number;
54     uint16_t top_lossy_number;
55 
56     void *object;
57 } Group_Peer;
58 
59 #define DESIRED_CLOSEST 4
60 #define MAX_GROUP_CONNECTIONS 16
61 #define GROUP_ID_LENGTH CRYPTO_SYMMETRIC_KEY_SIZE
62 
63 typedef enum Groupchat_Connection_Type {
64     GROUPCHAT_CONNECTION_NONE,
65     GROUPCHAT_CONNECTION_CONNECTING,
66     GROUPCHAT_CONNECTION_ONLINE,
67 } Groupchat_Connection_Type;
68 
69 /* Connection is to one of the closest DESIRED_CLOSEST peers */
70 #define GROUPCHAT_CONNECTION_REASON_CLOSEST     (1 << 0)
71 
72 /* Connection is to a peer we are introducing to the conference */
73 #define GROUPCHAT_CONNECTION_REASON_INTRODUCING (1 << 1)
74 
75 /* Connection is to a peer who is introducing us to the conference */
76 #define GROUPCHAT_CONNECTION_REASON_INTRODUCER  (1 << 2)
77 
78 typedef struct Groupchat_Connection {
79     uint8_t type; /* `GROUPCHAT_CONNECTION_*` */
80     uint8_t reasons; /* bit field with flags `GROUPCHAT_CONNECTION_REASON_*` */
81     uint32_t number;
82     uint16_t group_number;
83 } Groupchat_Connection;
84 
85 typedef struct Groupchat_Closest {
86     uint8_t entry;
87     uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE];
88     uint8_t temp_pk[CRYPTO_PUBLIC_KEY_SIZE];
89 } Groupchat_Closest;
90 
91 typedef void peer_on_join_cb(void *object, uint32_t conference_number, uint32_t peer_number);
92 typedef void peer_on_leave_cb(void *object, uint32_t conference_number, void *peer_object);
93 typedef void group_on_delete_cb(void *object, uint32_t conference_number);
94 
95 // maximum number of frozen peers to store; group_set_max_frozen() overrides.
96 #define MAX_FROZEN_DEFAULT 128
97 
98 typedef struct Group_c {
99     uint8_t status;
100 
101     bool need_send_name;
102     bool title_fresh;
103 
104     Group_Peer *group;
105     uint32_t numpeers;
106 
107     Group_Peer *frozen;
108     uint32_t numfrozen;
109 
110     uint32_t maxfrozen;
111 
112     Groupchat_Connection connections[MAX_GROUP_CONNECTIONS];
113 
114     uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE];
115     Groupchat_Closest closest_peers[DESIRED_CLOSEST];
116     uint8_t changed;
117 
118     uint8_t type;
119     uint8_t id[GROUP_ID_LENGTH];
120 
121     uint8_t title[MAX_NAME_LENGTH];
122     uint8_t title_len;
123 
124     uint32_t message_number;
125     uint16_t lossy_message_number;
126     uint16_t peer_number;
127 
128     uint64_t last_sent_ping;
129 
130     uint32_t num_introducer_connections;
131 
132     void *object;
133 
134     peer_on_join_cb *peer_on_join;
135     peer_on_leave_cb *peer_on_leave;
136     group_on_delete_cb *group_on_delete;
137 } Group_c;
138 
139 /* Callback for group invites.
140  *
141  * data of length is what needs to be passed to join_groupchat().
142  */
143 typedef void g_conference_invite_cb(Messenger *m, uint32_t friend_number, int type, const uint8_t *cookie,
144                                     size_t length, void *user_data);
145 
146 /* Callback for group connection. */
147 typedef void g_conference_connected_cb(Messenger *m, uint32_t conference_number, void *user_data);
148 
149 /* Callback for group messages. */
150 typedef void g_conference_message_cb(Messenger *m, uint32_t conference_number, uint32_t peer_number, int type,
151                                      const uint8_t *message, size_t length, void *user_data);
152 
153 /* Callback for peer nickname changes. */
154 typedef void peer_name_cb(Messenger *m, uint32_t conference_number, uint32_t peer_number, const uint8_t *name,
155                           size_t length, void *user_data);
156 
157 /* Set callback function for peer list changes. */
158 typedef void peer_list_changed_cb(Messenger *m, uint32_t conference_number, void *user_data);
159 
160 /* Callback for title changes.
161  *
162  * If peer_number == -1, then author is unknown (e.g. initial joining the group).
163  */
164 typedef void title_cb(Messenger *m, uint32_t conference_number, uint32_t peer_number, const uint8_t *title,
165                       size_t length, void *user_data);
166 
167 /* Callback for lossy packets.
168  *
169  * NOTE: Handler must return 0 if packet is to be relayed, -1 if the packet should not be relayed.
170  */
171 typedef int lossy_packet_cb(void *object, uint32_t conference_number, uint32_t peer_number, void *peer_object,
172                             const uint8_t *packet, uint16_t length);
173 
174 typedef struct Group_Lossy_Handler {
175     lossy_packet_cb *function;
176 } Group_Lossy_Handler;
177 
178 typedef struct Group_Chats {
179     const Mono_Time *mono_time;
180 
181     Messenger *m;
182     Friend_Connections *fr_c;
183 
184     Group_c *chats;
185     uint16_t num_chats;
186 
187     g_conference_invite_cb *invite_callback;
188     g_conference_connected_cb *connected_callback;
189     g_conference_message_cb *message_callback;
190     peer_name_cb *peer_name_callback;
191     peer_list_changed_cb *peer_list_changed_callback;
192     title_cb *title_callback;
193 
194     Group_Lossy_Handler lossy_packethandlers[256];
195 } Group_Chats;
196 
197 /* Set the callback for group invites. */
198 void g_callback_group_invite(Group_Chats *g_c, g_conference_invite_cb *function);
199 
200 /* Set the callback for group connection. */
201 void g_callback_group_connected(Group_Chats *g_c, g_conference_connected_cb *function);
202 
203 /* Set the callback for group messages. */
204 void g_callback_group_message(Group_Chats *g_c, g_conference_message_cb *function);
205 
206 
207 /* Set callback function for title changes. */
208 void g_callback_group_title(Group_Chats *g_c, title_cb *function);
209 
210 /* Set callback function for peer nickname changes.
211  *
212  * It gets called every time a peer changes their nickname.
213  */
214 void g_callback_peer_name(Group_Chats *g_c, peer_name_cb *function);
215 
216 /* Set callback function for peer list changes.
217  *
218  * It gets called every time the name list changes(new peer, deleted peer)
219  */
220 void g_callback_peer_list_changed(Group_Chats *g_c, peer_list_changed_cb *function);
221 
222 /* Creates a new groupchat and puts it in the chats array.
223  *
224  * type is one of `GROUPCHAT_TYPE_*`
225  *
226  * return group number on success.
227  * return -1 on failure.
228  */
229 int add_groupchat(Group_Chats *g_c, uint8_t type);
230 
231 /* Delete a groupchat from the chats array, informing the group first as
232  * appropriate.
233  *
234  * return 0 on success.
235  * return -1 if groupnumber is invalid.
236  */
237 int del_groupchat(Group_Chats *g_c, uint32_t groupnumber, bool leave_permanently);
238 
239 /* Copy the public key of (frozen, if frozen is true) peernumber who is in
240  * groupnumber to pk.
241  * pk must be CRYPTO_PUBLIC_KEY_SIZE long.
242  *
243  * return 0 on success
244  * return -1 if groupnumber is invalid.
245  * return -2 if peernumber is invalid.
246  */
247 int group_peer_pubkey(const Group_Chats *g_c, uint32_t groupnumber, uint32_t peernumber, uint8_t *pk, bool frozen);
248 
249 /*
250  * Return the size of (frozen, if frozen is true) peernumber's name.
251  *
252  * return -1 if groupnumber is invalid.
253  * return -2 if peernumber is invalid.
254  */
255 int group_peername_size(const Group_Chats *g_c, uint32_t groupnumber, uint32_t peernumber, bool frozen);
256 
257 /* Copy the name of (frozen, if frozen is true) peernumber who is in
258  * groupnumber to name.
259  * name must be at least MAX_NAME_LENGTH long.
260  *
261  * return length of name if success
262  * return -1 if groupnumber is invalid.
263  * return -2 if peernumber is invalid.
264  */
265 int group_peername(const Group_Chats *g_c, uint32_t groupnumber, uint32_t peernumber, uint8_t *name, bool frozen);
266 
267 /* Copy last active timestamp of frozen peernumber who is in groupnumber to
268  * last_active.
269  *
270  * return 0 on success.
271  * return -1 if groupnumber is invalid.
272  * return -2 if peernumber is invalid.
273  */
274 int group_frozen_last_active(const Group_Chats *g_c, uint32_t groupnumber, uint32_t peernumber,
275                              uint64_t *last_active);
276 
277 /* Set maximum number of frozen peers.
278  *
279  * return 0 on success.
280  * return -1 if groupnumber is invalid.
281  */
282 int group_set_max_frozen(const Group_Chats *g_c, uint32_t groupnumber, uint32_t maxfrozen);
283 
284 /* invite friendnumber to groupnumber
285  *
286  * return 0 on success.
287  * return -1 if groupnumber is invalid.
288  * return -2 if invite packet failed to send.
289  */
290 int invite_friend(Group_Chats *g_c, uint32_t friendnumber, uint32_t groupnumber);
291 
292 /* Join a group (you need to have been invited first.)
293  *
294  * expected_type is the groupchat type we expect the chat we are joining to
295  * have.
296  *
297  * return group number on success.
298  * return -1 if data length is invalid.
299  * return -2 if group is not the expected type.
300  * return -3 if friendnumber is invalid.
301  * return -4 if client is already in this group.
302  * return -5 if group instance failed to initialize.
303  * return -6 if join packet fails to send.
304  */
305 int join_groupchat(Group_Chats *g_c, uint32_t friendnumber, uint8_t expected_type, const uint8_t *data,
306                    uint16_t length);
307 
308 /* send a group message
309  * return 0 on success
310  * see: send_message_group() for error codes.
311  */
312 int group_message_send(const Group_Chats *g_c, uint32_t groupnumber, const uint8_t *message, uint16_t length);
313 
314 /* send a group action
315  * return 0 on success
316  * see: send_message_group() for error codes.
317  */
318 int group_action_send(const Group_Chats *g_c, uint32_t groupnumber, const uint8_t *action, uint16_t length);
319 
320 /* set the group's title, limited to MAX_NAME_LENGTH
321  * return 0 on success
322  * return -1 if groupnumber is invalid.
323  * return -2 if title is too long or empty.
324  * return -3 if packet fails to send.
325  */
326 int group_title_send(const Group_Chats *g_c, uint32_t groupnumber, const uint8_t *title, uint8_t title_len);
327 
328 
329 /* return the group's title size.
330  * return -1 of groupnumber is invalid.
331  * return -2 if title is too long or empty.
332  */
333 int group_title_get_size(const Group_Chats *g_c, uint32_t groupnumber);
334 
335 /* Get group title from groupnumber and put it in title.
336  * Title needs to be a valid memory location with a size of at least MAX_NAME_LENGTH (128) bytes.
337  *
338  * return length of copied title if success.
339  * return -1 if groupnumber is invalid.
340  * return -2 if title is too long or empty.
341  */
342 int group_title_get(const Group_Chats *g_c, uint32_t groupnumber, uint8_t *title);
343 
344 /* Return the number of (frozen, if frozen is true) peers in the group chat on
345  * success.
346  * return -1 if groupnumber is invalid.
347  */
348 int group_number_peers(const Group_Chats *g_c, uint32_t groupnumber, bool frozen);
349 
350 /* return 1 if the peernumber corresponds to ours.
351  * return 0 if the peernumber is not ours.
352  * return -1 if groupnumber is invalid.
353  * return -2 if peernumber is invalid.
354  * return -3 if we are not connected to the group chat.
355  */
356 int group_peernumber_is_ours(const Group_Chats *g_c, uint32_t groupnumber, uint32_t peernumber);
357 
358 /* Set handlers for custom lossy packets. */
359 void group_lossy_packet_registerhandler(Group_Chats *g_c, uint8_t byte, lossy_packet_cb *function);
360 
361 /* High level function to send custom lossy packets.
362  *
363  * return -1 on failure.
364  * return 0 on success.
365  */
366 int send_group_lossy_packet(const Group_Chats *g_c, uint32_t groupnumber, const uint8_t *data, uint16_t length);
367 
368 /* Return the number of chats in the instance m.
369  * You should use this to determine how much memory to allocate
370  * for copy_chatlist.
371  */
372 uint32_t count_chatlist(const Group_Chats *g_c);
373 
374 /* Copy a list of valid chat IDs into the array out_list.
375  * If out_list is NULL, returns 0.
376  * Otherwise, returns the number of elements copied.
377  * If the array was too small, the contents
378  * of out_list will be truncated to list_size. */
379 uint32_t copy_chatlist(const Group_Chats *g_c, uint32_t *out_list, uint32_t list_size);
380 
381 /* return the type of groupchat (GROUPCHAT_TYPE_) that groupnumber is.
382  *
383  * return -1 on failure.
384  * return type on success.
385  */
386 int group_get_type(const Group_Chats *g_c, uint32_t groupnumber);
387 
388 /* Copies the unique id of `group_chat[groupnumber]` into id.
389  *
390  * return false on failure.
391  * return true on success.
392  */
393 bool conference_get_id(const Group_Chats *g_c, uint32_t groupnumber, uint8_t *id);
394 
395 int32_t conference_by_id(const Group_Chats *g_c, const uint8_t *id);
396 
397 /* Send current name (set in messenger) to all online groups.
398  */
399 void send_name_all_groups(Group_Chats *g_c);
400 
401 /* Set the object that is tied to the group chat.
402  *
403  * return 0 on success.
404  * return -1 on failure
405  */
406 int group_set_object(const Group_Chats *g_c, uint32_t groupnumber, void *object);
407 
408 /* Set the object that is tied to the group peer.
409  *
410  * return 0 on success.
411  * return -1 on failure
412  */
413 int group_peer_set_object(const Group_Chats *g_c, uint32_t groupnumber, uint32_t peernumber, void *object);
414 
415 /* Return the object tied to the group chat previously set by group_set_object.
416  *
417  * return NULL on failure.
418  * return object on success.
419  */
420 void *group_get_object(const Group_Chats *g_c, uint32_t groupnumber);
421 
422 /* Return the object tied to the group chat peer previously set by group_peer_set_object.
423  *
424  * return NULL on failure.
425  * return object on success.
426  */
427 void *group_peer_get_object(const Group_Chats *g_c, uint32_t groupnumber, uint32_t peernumber);
428 
429 /* Set a function to be called when a new peer joins a group chat.
430  *
431  * return 0 on success.
432  * return -1 on failure.
433  */
434 int callback_groupchat_peer_new(const Group_Chats *g_c, uint32_t groupnumber, peer_on_join_cb *function);
435 
436 /* Set a function to be called when a peer leaves a group chat.
437  *
438  * return 0 on success.
439  * return -1 on failure.
440  */
441 int callback_groupchat_peer_delete(Group_Chats *g_c, uint32_t groupnumber, peer_on_leave_cb *function);
442 
443 /* Set a function to be called when the group chat is deleted.
444  *
445  * return 0 on success.
446  * return -1 on failure.
447  */
448 int callback_groupchat_delete(Group_Chats *g_c, uint32_t groupnumber, group_on_delete_cb *function);
449 
450 /* Return size of the conferences data (for saving). */
451 uint32_t conferences_size(const Group_Chats *g_c);
452 
453 /* Save the conferences in data (must be allocated memory of size at least conferences_size()) */
454 uint8_t *conferences_save(const Group_Chats *g_c, uint8_t *data);
455 
456 /**
457  * Load a state section.
458  *
459  * @param data Data to load
460  * @param length Length of data
461  * @param type Type of section (`STATE_TYPE_*`)
462  * @param status Result of loading section is stored here if the section is handled.
463  * @return true iff section handled.
464  */
465 bool conferences_load_state_section(Group_Chats *g_c, const uint8_t *data, uint32_t length, uint16_t type,
466                                     State_Load_Status *status);
467 
468 /* Create new groupchat instance. */
469 Group_Chats *new_groupchats(Mono_Time *mono_time, Messenger *m);
470 
471 /* main groupchats loop. */
472 void do_groupchats(Group_Chats *g_c, void *userdata);
473 
474 /* Free everything related with group chats. */
475 void kill_groupchats(Group_Chats *g_c);
476 
477 #endif
478