1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
|
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2016-2026 The TokTok team.
* Copyright © 2014 Tox project.
*/
/**
* Slightly better groupchats implementation.
*/
#ifndef C_TOXCORE_TOXCORE_GROUP_H
#define C_TOXCORE_TOXCORE_GROUP_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "Messenger.h"
#include "attributes.h"
#include "crypto_core.h"
#include "mem.h"
#include "mono_time.h"
#include "state.h"
typedef enum Groupchat_Type {
GROUPCHAT_TYPE_TEXT,
GROUPCHAT_TYPE_AV,
} Groupchat_Type;
typedef void peer_on_join_cb(void *_Nullable object, uint32_t conference_number, uint32_t peer_number);
typedef void peer_on_leave_cb(void *_Nullable object, uint32_t conference_number, void *_Nullable peer_object);
typedef void group_on_delete_cb(void *_Nullable object, uint32_t conference_number);
/** @brief Callback for group invites.
*
* data of length is what needs to be passed to `join_groupchat()`.
*/
typedef void g_conference_invite_cb(Messenger *_Nonnull m, uint32_t friend_number, int type, const uint8_t *_Nonnull cookie,
size_t length, void *_Nullable user_data);
/** Callback for group connection. */
typedef void g_conference_connected_cb(Messenger *_Nonnull m, uint32_t conference_number, void *_Nullable user_data);
/** Callback for group messages. */
typedef void g_conference_message_cb(Messenger *_Nonnull m, uint32_t conference_number, uint32_t peer_number, int type,
const uint8_t *_Nonnull message, size_t length, void *_Nullable user_data);
/** Callback for peer nickname changes. */
typedef void peer_name_cb(Messenger *_Nonnull m, uint32_t conference_number, uint32_t peer_number, const uint8_t *_Nonnull name,
size_t length, void *_Nullable user_data);
/** Set callback function for peer list changes. */
typedef void peer_list_changed_cb(Messenger *_Nonnull m, uint32_t conference_number, void *_Nullable user_data);
/** @brief Callback for title changes.
*
* If peer_number == -1, then author is unknown (e.g. initial joining the group).
*/
typedef void title_cb(Messenger *_Nonnull m, uint32_t conference_number, uint32_t peer_number, const uint8_t *_Nonnull title,
size_t length, void *_Nullable user_data);
/** @brief Callback for lossy packets.
*
* NOTE: Handler must return 0 if packet is to be relayed, -1 if the packet should not be relayed.
*/
typedef int lossy_packet_cb(void *_Nullable object, uint32_t conference_number, uint32_t peer_number, void *_Nullable peer_object,
const uint8_t *_Nonnull packet, uint16_t length);
typedef struct Group_Chats Group_Chats;
const Mono_Time *_Nonnull g_mono_time(const Group_Chats *_Nonnull g_c);
/** Set the callback for group invites. */
void g_callback_group_invite(Group_Chats *_Nonnull g_c, g_conference_invite_cb *_Nonnull function);
/** Set the callback for group connection. */
void g_callback_group_connected(Group_Chats *_Nonnull g_c, g_conference_connected_cb *_Nonnull function);
/** Set the callback for group messages. */
void g_callback_group_message(Group_Chats *_Nonnull g_c, g_conference_message_cb *_Nonnull function);
/** Set callback function for title changes. */
void g_callback_group_title(Group_Chats *_Nonnull g_c, title_cb *_Nonnull function);
/** @brief Set callback function for peer nickname changes.
*
* It gets called every time a peer changes their nickname.
*/
void g_callback_peer_name(Group_Chats *_Nonnull g_c, peer_name_cb *_Nonnull function);
/** @brief Set callback function for peer list changes.
*
* It gets called every time the name list changes(new peer, deleted peer)
*/
void g_callback_peer_list_changed(Group_Chats *_Nonnull g_c, peer_list_changed_cb *_Nonnull function);
/** @brief Creates a new groupchat and puts it in the chats array.
*
* @param rng Random number generator used for generating the group ID.
* @param type is one of `GROUPCHAT_TYPE_*`
*
* @return group number on success.
* @retval -1 on failure.
*/
int add_groupchat(Group_Chats *_Nonnull g_c, const Random *_Nonnull rng, uint8_t type);
/** @brief Delete a groupchat from the chats array, informing the group first as
* appropriate.
*
* @retval true on success.
* @retval false if groupnumber is invalid.
*/
bool del_groupchat(Group_Chats *_Nonnull g_c, uint32_t groupnumber, bool leave_permanently);
/**
* @brief Copy the public key of (frozen, if frozen is true) peernumber who is in
* groupnumber to pk.
*
* @param pk must be CRYPTO_PUBLIC_KEY_SIZE long.
*
* @retval 0 on success
* @retval -1 if groupnumber is invalid.
* @retval -2 if peernumber is invalid.
*/
int group_peer_pubkey(const Group_Chats *_Nonnull g_c, uint32_t groupnumber, uint32_t peernumber, uint8_t *_Nonnull pk, bool frozen);
/**
* @brief Return the size of (frozen, if frozen is true) peernumber's name.
*
* @retval -1 if groupnumber is invalid.
* @retval -2 if peernumber is invalid.
*/
int group_peername_size(const Group_Chats *_Nonnull g_c, uint32_t groupnumber, uint32_t peernumber, bool frozen);
/**
* @brief Copy the name of (frozen, if frozen is true) peernumber who is in
* groupnumber to name.
*
* @param name must be at least MAX_NAME_LENGTH long.
*
* @return length of name if success
* @retval -1 if groupnumber is invalid.
* @retval -2 if peernumber is invalid.
*/
int group_peername(const Group_Chats *_Nonnull g_c, uint32_t groupnumber, uint32_t peernumber, uint8_t *_Nonnull name, bool frozen);
/**
* @brief Copy last active timestamp of frozen peernumber who is in groupnumber to
* last_active.
*
* @retval 0 on success.
* @retval -1 if groupnumber is invalid.
* @retval -2 if peernumber is invalid.
*/
int group_frozen_last_active(const Group_Chats *_Nonnull g_c, uint32_t groupnumber, uint32_t peernumber, uint64_t *_Nonnull last_active);
/** @brief Set maximum number of frozen peers.
*
* @retval 0 on success.
* @retval -1 if groupnumber is invalid.
*/
int group_set_max_frozen(const Group_Chats *_Nonnull g_c, uint32_t groupnumber, uint32_t maxfrozen);
/** @brief invite friendnumber to groupnumber.
*
* @retval 0 on success.
* @retval -1 if groupnumber is invalid.
* @retval -2 if invite packet failed to send.
* @retval -3 if we are not connected to the group chat.
*/
int invite_friend(const Group_Chats *_Nonnull g_c, uint32_t friendnumber, uint32_t groupnumber);
/** @brief Join a group (we need to have been invited first).
*
* @param expected_type is the groupchat type we expect the chat we are joining
* to have.
*
* @return group number on success.
* @retval -1 if data length is invalid.
* @retval -2 if group is not the expected type.
* @retval -3 if friendnumber is invalid.
* @retval -4 if client is already in this group.
* @retval -5 if group instance failed to initialize.
* @retval -6 if join packet fails to send.
*/
int join_groupchat(Group_Chats *_Nonnull g_c, uint32_t friendnumber, uint8_t expected_type, const uint8_t *_Nonnull data, uint16_t length);
/** @brief send a group message
* @retval 0 on success
* @see send_message_group for error codes.
*/
int group_message_send(const Group_Chats *_Nonnull g_c, uint32_t groupnumber, const uint8_t *_Nonnull message, uint16_t length);
/** @brief send a group action
* @retval 0 on success
* @see send_message_group for error codes.
*/
int group_action_send(const Group_Chats *_Nonnull g_c, uint32_t groupnumber, const uint8_t *_Nonnull action, uint16_t length);
/** @brief set the group's title, limited to MAX_NAME_LENGTH.
* @retval 0 on success
* @retval -1 if groupnumber is invalid.
* @retval -2 if title is too long or empty.
* @retval -3 if packet fails to send.
*/
int group_title_send(const Group_Chats *_Nonnull g_c, uint32_t groupnumber, const uint8_t *_Nonnull title, uint8_t title_len);
/** @brief return the group's title size.
* @retval -1 of groupnumber is invalid.
* @retval -2 if title is too long or empty.
*/
int group_title_get_size(const Group_Chats *_Nonnull g_c, uint32_t groupnumber);
/** @brief Get group title from groupnumber and put it in title.
*
* Title needs to be a valid memory location with a size of at least MAX_NAME_LENGTH (128) bytes.
*
* @return length of copied title if success.
* @retval -1 if groupnumber is invalid.
* @retval -2 if title is too long or empty.
*/
int group_title_get(const Group_Chats *_Nonnull g_c, uint32_t groupnumber, uint8_t *_Nonnull title);
/**
* @return the number of (frozen, if frozen is true) peers in the group chat on success.
* @retval -1 if groupnumber is invalid.
*/
int group_number_peers(const Group_Chats *_Nonnull g_c, uint32_t groupnumber, bool frozen);
/**
* @retval 1 if the peernumber corresponds to ours.
* @retval 0 if the peernumber is not ours.
* @retval -1 if groupnumber is invalid.
* @retval -2 if peernumber is invalid.
* @retval -3 if we are not connected to the group chat.
*/
int group_peernumber_is_ours(const Group_Chats *_Nonnull g_c, uint32_t groupnumber, uint32_t peernumber);
/** Set handlers for custom lossy packets. */
void group_lossy_packet_registerhandler(Group_Chats *_Nonnull g_c, uint8_t byte, lossy_packet_cb *_Nonnull function);
/** @brief High level function to send custom lossy packets.
*
* @retval -1 on failure.
* @retval 0 on success.
*/
int send_group_lossy_packet(const Group_Chats *_Nonnull g_c, uint32_t groupnumber, const uint8_t *_Nonnull data, uint16_t length);
/**
* @brief Return the number of chats in the instance m.
*
* You should use this to determine how much memory to allocate
* for copy_chatlist.
*/
uint32_t count_chatlist(const Group_Chats *_Nonnull g_c);
/** @brief Copy a list of valid chat IDs into the array out_list.
*
* If out_list is NULL, returns 0.
* Otherwise, returns the number of elements copied.
* If the array was too small, the contents
* of out_list will be truncated to list_size.
*/
uint32_t copy_chatlist(const Group_Chats *_Nonnull g_c, uint32_t *_Nonnull out_list, uint32_t list_size);
/** @brief return the type of groupchat (GROUPCHAT_TYPE_) that groupnumber is.
*
* @retval -1 on failure.
* @return type on success.
*/
int group_get_type(const Group_Chats *_Nonnull g_c, uint32_t groupnumber);
/** @brief Copies the unique id of `group_chat[groupnumber]` into `id`.
*
* @retval false on failure.
* @retval true on success.
*/
bool conference_get_id(const Group_Chats *_Nonnull g_c, uint32_t groupnumber, uint8_t *_Nonnull id);
int32_t conference_by_id(const Group_Chats *_Nonnull g_c, const uint8_t *_Nonnull id);
/** Send current name (set in messenger) to all online groups. */
void send_name_all_groups(const Group_Chats *_Nonnull g_c);
/** @brief Set the object that is tied to the group chat.
*
* @retval 0 on success.
* @retval -1 on failure
*/
int group_set_object(const Group_Chats *_Nonnull g_c, uint32_t groupnumber, void *_Nullable object);
/** @brief Set the object that is tied to the group peer.
*
* @retval 0 on success.
* @retval -1 on failure
*/
int group_peer_set_object(const Group_Chats *_Nonnull g_c, uint32_t groupnumber, uint32_t peernumber, void *_Nullable object);
/** @brief Return the object tied to the group chat previously set by group_set_object.
*
* @retval NULL on failure.
* @return object on success.
*/
void *_Nullable group_get_object(const Group_Chats *_Nonnull g_c, uint32_t groupnumber);
/** @brief Return the object tied to the group chat peer previously set by group_peer_set_object.
*
* @retval NULL on failure.
* @return object on success.
*/
void *_Nullable group_peer_get_object(const Group_Chats *_Nonnull g_c, uint32_t groupnumber, uint32_t peernumber);
/** @brief Set a function to be called when a new peer joins a group chat.
*
* @retval 0 on success.
* @retval -1 on failure.
*/
int callback_groupchat_peer_new(const Group_Chats *_Nonnull g_c, uint32_t groupnumber, peer_on_join_cb *_Nullable function);
/** @brief Set a function to be called when a peer leaves a group chat.
*
* @retval 0 on success.
* @retval -1 on failure.
*/
int callback_groupchat_peer_delete(const Group_Chats *_Nonnull g_c, uint32_t groupnumber, peer_on_leave_cb *_Nullable function);
/** @brief Set a function to be called when the group chat is deleted.
*
* @retval 0 on success.
* @retval -1 on failure.
*/
int callback_groupchat_delete(const Group_Chats *_Nonnull g_c, uint32_t groupnumber, group_on_delete_cb *_Nullable function);
/** Return size of the conferences data (for saving). */
uint32_t conferences_size(const Group_Chats *_Nonnull g_c);
/** Save the conferences in data (must be allocated memory of size at least `conferences_size()`). */
uint8_t *_Nonnull conferences_save(const Group_Chats *_Nonnull g_c, uint8_t *_Nonnull data);
/**
* Load a state section.
*
* @param data Data to load
* @param length Length of data
* @param type Type of section (`STATE_TYPE_*`)
* @param status Result of loading section is stored here if the section is handled.
* @return true iff section handled.
*/
bool conferences_load_state_section(Group_Chats *_Nonnull g_c, const uint8_t *_Nonnull data, uint32_t length, uint16_t type, State_Load_Status *_Nonnull status);
/** Create new groupchat instance. */
Group_Chats *_Nullable new_groupchats(const Mono_Time *_Nonnull mono_time, const Memory *_Nonnull mem, Messenger *_Nonnull m);
/** main groupchats loop. */
void do_groupchats(Group_Chats *_Nonnull g_c, void *_Nullable userdata);
/** Free everything related with group chats. */
void kill_groupchats(Group_Chats *_Nullable g_c);
#endif /* C_TOXCORE_TOXCORE_GROUP_H */
|