diff --git a/toxav/groupav.c b/toxav/groupav.c index 55a5fe5501..4c16d1de9c 100644 --- a/toxav/groupav.c +++ b/toxav/groupav.c @@ -473,7 +473,7 @@ int add_av_groupchat(const Logger *log, Tox *tox, Group_Chats *g_c, audio_data_c } if (groupchat_enable_av(log, tox, g_c, groupnumber, audio_callback, userdata) == -1) { - del_groupchat(g_c, groupnumber); + del_groupchat(g_c, groupnumber, true); return -1; } @@ -495,7 +495,7 @@ int join_av_groupchat(const Logger *log, Tox *tox, Group_Chats *g_c, uint32_t fr } if (groupchat_enable_av(log, tox, g_c, groupnumber, audio_callback, userdata) == -1) { - del_groupchat(g_c, groupnumber); + del_groupchat(g_c, groupnumber, true); return -1; } diff --git a/toxcore/group.c b/toxcore/group.c index 99f7233670..b345a01c12 100644 --- a/toxcore/group.c +++ b/toxcore/group.c @@ -271,6 +271,7 @@ typedef enum Groupchat_Closest { static int add_to_closest(Group_Chats *g_c, uint32_t groupnumber, const uint8_t *real_pk, const uint8_t *temp_pk) { + // TODO(zugz): this can be const. Similarly throughout the file. Group_c *g = get_group_c(g_c, groupnumber); if (!g) { @@ -1033,12 +1034,15 @@ int add_groupchat(Group_Chats *g_c, uint8_t type) return groupnumber; } -/* Delete a groupchat from the chats array. +static int group_leave(const Group_Chats *g_c, uint32_t groupnumber); + +/* Delete a groupchat from the chats array, informing the group first as + * appropriate. * * return 0 on success. * return -1 if groupnumber is invalid. */ -int del_groupchat(Group_Chats *g_c, uint32_t groupnumber) +int del_groupchat(Group_Chats *g_c, uint32_t groupnumber, bool leave_permanently) { Group_c *g = get_group_c(g_c, groupnumber); @@ -1046,6 +1050,10 @@ int del_groupchat(Group_Chats *g_c, uint32_t groupnumber) return -1; } + if (leave_permanently) { + group_leave(g_c, groupnumber); + } + for (uint32_t i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { if (g->close[i].type == GROUPCHAT_CLOSE_NONE) { continue; @@ -1071,14 +1079,14 @@ int del_groupchat(Group_Chats *g_c, uint32_t groupnumber) return wipe_group_chat(g_c, groupnumber); } -/* Copy the public key of peernumber who is in groupnumber to pk. - * pk must be CRYPTO_PUBLIC_KEY_SIZE long. +/* Copy the public key of (frozen, if frozen is true) peernumber who is in + * groupnumber to pk. pk must be CRYPTO_PUBLIC_KEY_SIZE long. * * return 0 on success * return -1 if groupnumber is invalid. * return -2 if peernumber is invalid. */ -int group_peer_pubkey(const Group_Chats *g_c, uint32_t groupnumber, int peernumber, uint8_t *pk) +int group_peer_pubkey(const Group_Chats *g_c, uint32_t groupnumber, int peernumber, uint8_t *pk, bool frozen) { Group_c *g = get_group_c(g_c, groupnumber); @@ -1086,21 +1094,24 @@ int group_peer_pubkey(const Group_Chats *g_c, uint32_t groupnumber, int peernumb return -1; } - if ((uint32_t)peernumber >= g->numpeers) { + const Group_Peer *list = frozen ? g->frozen : g->group; + const uint32_t num = frozen ? g->numfrozen : g->numpeers; + + if ((uint32_t)peernumber >= num) { return -2; } - memcpy(pk, g->group[peernumber].real_pk, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(pk, list[peernumber].real_pk, CRYPTO_PUBLIC_KEY_SIZE); return 0; } /* - * Return the size of peernumber's name. + * Return the size of (frozen, if frozen is true) peernumber's name. * * return -1 if groupnumber is invalid. * return -2 if peernumber is invalid. */ -int group_peername_size(const Group_Chats *g_c, uint32_t groupnumber, int peernumber) +int group_peername_size(const Group_Chats *g_c, uint32_t groupnumber, int peernumber, bool frozen) { Group_c *g = get_group_c(g_c, groupnumber); @@ -1108,25 +1119,28 @@ int group_peername_size(const Group_Chats *g_c, uint32_t groupnumber, int peernu return -1; } - if ((uint32_t)peernumber >= g->numpeers) { + const Group_Peer *list = frozen ? g->frozen : g->group; + const uint32_t num = frozen ? g->numfrozen : g->numpeers; + + if ((uint32_t)peernumber >= num) { return -2; } - if (g->group[peernumber].nick_len == 0) { + if (list[peernumber].nick_len == 0) { return 0; } - return g->group[peernumber].nick_len; + return list[peernumber].nick_len; } -/* Copy the name of peernumber who is in groupnumber to name. - * name must be at least MAX_NAME_LENGTH long. +/* Copy the name of (frozen, if frozen is true) peernumber who is in + * groupnumber to name. name must be at least MAX_NAME_LENGTH long. * * return length of name if success * return -1 if groupnumber is invalid. * return -2 if peernumber is invalid. */ -int group_peername(const Group_Chats *g_c, uint32_t groupnumber, int peernumber, uint8_t *name) +int group_peername(const Group_Chats *g_c, uint32_t groupnumber, int peernumber, uint8_t *name, bool frozen) { Group_c *g = get_group_c(g_c, groupnumber); @@ -1134,19 +1148,46 @@ int group_peername(const Group_Chats *g_c, uint32_t groupnumber, int peernumber, return -1; } - if ((uint32_t)peernumber >= g->numpeers) { + const Group_Peer *list = frozen ? g->frozen : g->group; + const uint32_t num = frozen ? g->numfrozen : g->numpeers; + + if ((uint32_t)peernumber >= num) { return -2; } - if (g->group[peernumber].nick_len == 0) { + if (list[peernumber].nick_len == 0) { return 0; } - memcpy(name, g->group[peernumber].nick, g->group[peernumber].nick_len); - return g->group[peernumber].nick_len; + memcpy(name, list[peernumber].nick, list[peernumber].nick_len); + return list[peernumber].nick_len; } -/* List all the peers in the group chat. +/* Copy last active timestamp of frozennumber who is in groupnumber to + * last_active. + * + * return 0 on success. + * return -1 if groupnumber is invalid. + * return -2 if frozennumber is invalid. + */ +int group_frozen_last_active(const Group_Chats *g_c, uint32_t groupnumber, int peernumber, + uint64_t *last_active) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + if ((uint32_t)peernumber >= g->numfrozen) { + return -2; + } + + *last_active = g->frozen[peernumber].last_active; + return 0; +} + +/* List all the (frozen, if frozen is true) peers in the group chat. * * Copies the names of the peers to the name[length][MAX_NAME_LENGTH] array. * @@ -1157,7 +1198,7 @@ int group_peername(const Group_Chats *g_c, uint32_t groupnumber, int peernumber, * return -1 on failure. */ int group_names(const Group_Chats *g_c, uint32_t groupnumber, uint8_t names[][MAX_NAME_LENGTH], uint16_t lengths[], - uint16_t length) + uint16_t length, bool frozen) { Group_c *g = get_group_c(g_c, groupnumber); @@ -1165,19 +1206,22 @@ int group_names(const Group_Chats *g_c, uint32_t groupnumber, uint8_t names[][MA return -1; } + const uint32_t num = frozen ? g->numfrozen : g->numpeers; + unsigned int i; - for (i = 0; i < g->numpeers && i < length; ++i) { - lengths[i] = group_peername(g_c, groupnumber, i, names[i]); + for (i = 0; i < num && i < length; ++i) { + lengths[i] = group_peername(g_c, groupnumber, i, names[i], frozen); } return i; } -/* Return the number of peers in the group chat on success. +/* Return the number of (frozen, if frozen is true) peers in the group chat on + * success. * return -1 if groupnumber is invalid. */ -int group_number_peers(const Group_Chats *g_c, uint32_t groupnumber) +int group_number_peers(const Group_Chats *g_c, uint32_t groupnumber, bool frozen) { Group_c *g = get_group_c(g_c, groupnumber); @@ -1185,7 +1229,7 @@ int group_number_peers(const Group_Chats *g_c, uint32_t groupnumber) return -1; } - return g->numpeers; + return frozen ? g->numfrozen : g->numpeers; } /* return 1 if the peernumber corresponds to ours. @@ -1597,18 +1641,18 @@ static int group_name_send(const Group_Chats *g_c, uint32_t groupnumber, const u } /* send message to announce leaving group - * return true on success - * return false on failure + * return 0 on success + * return -1 on failure */ -bool group_leave(const Group_Chats *g_c, uint32_t groupnumber) +static int group_leave(const Group_Chats *g_c, uint32_t groupnumber) { Group_c *g = get_group_c(g_c, groupnumber); if (!g) { - return false; + return -1; } - return group_kill_peer_send(g_c, groupnumber, g->peer_number) == 0; + return group_kill_peer_send(g_c, groupnumber, g->peer_number); } @@ -2900,7 +2944,7 @@ void send_name_all_groups(Group_Chats *g_c) } } -#define SAVED_PEER_SIZE_CONSTANT (2 * CRYPTO_PUBLIC_KEY_SIZE + 2 + 1) +#define SAVED_PEER_SIZE_CONSTANT (2 * CRYPTO_PUBLIC_KEY_SIZE + sizeof(uint16_t) + sizeof(uint64_t) + 1) static uint32_t saved_peer_size(const Group_Peer *peer) { @@ -2918,6 +2962,9 @@ static uint8_t *save_peer(const Group_Peer *peer, uint8_t *data) host_to_lendian_bytes16(data, peer->peer_number); data += sizeof(uint16_t); + host_to_lendian_bytes64(data, peer->last_active); + data += sizeof(uint64_t); + *data = peer->nick_len; ++data; @@ -3098,6 +3145,9 @@ static State_Load_Status load_conferences(Group_Chats *g_c, const uint8_t *data, lendian_bytes_to_host16(&peer->peer_number, data); data += sizeof(uint16_t); + lendian_bytes_to_host64(&peer->last_active, data); + data += sizeof(uint64_t); + peer->nick_len = *data; ++data; @@ -3189,7 +3239,7 @@ void do_groupchats(Group_Chats *g_c, void *userdata) void kill_groupchats(Group_Chats *g_c) { for (uint16_t i = 0; i < g_c->num_chats; ++i) { - del_groupchat(g_c, i); + del_groupchat(g_c, i, false); } m_callback_conference_invite(g_c->m, nullptr); diff --git a/toxcore/group.h b/toxcore/group.h index 148de0c1e4..83015273b3 100644 --- a/toxcore/group.h +++ b/toxcore/group.h @@ -238,38 +238,51 @@ void g_callback_peer_list_changed(Group_Chats *g_c, peer_list_changed_cb *functi */ int add_groupchat(Group_Chats *g_c, uint8_t type); -/* Delete a groupchat from the chats array. +/* Delete a groupchat from the chats array, informing the group first as + * appropriate. * * return 0 on success. * return -1 if groupnumber is invalid. */ -int del_groupchat(Group_Chats *g_c, uint32_t groupnumber); +int del_groupchat(Group_Chats *g_c, uint32_t groupnumber, bool leave_permanently); -/* Copy the public key of peernumber who is in groupnumber to pk. +/* Copy the public key of (frozen, if frozen is true) peernumber who is in + * groupnumber to pk. * pk must be CRYPTO_PUBLIC_KEY_SIZE long. * * return 0 on success * return -1 if groupnumber is invalid. * return -2 if peernumber is invalid. */ -int group_peer_pubkey(const Group_Chats *g_c, uint32_t groupnumber, int peernumber, uint8_t *pk); +int group_peer_pubkey(const Group_Chats *g_c, uint32_t groupnumber, int peernumber, uint8_t *pk, bool frozen); /* - * Return the size of peernumber's name. + * Return the size of (frozen, if frozen is true) peernumber's name. * * return -1 if groupnumber is invalid. * return -2 if peernumber is invalid. */ -int group_peername_size(const Group_Chats *g_c, uint32_t groupnumber, int32_t peernumber); +int group_peername_size(const Group_Chats *g_c, uint32_t groupnumber, int32_t peernumber, bool frozen); -/* Copy the name of peernumber who is in groupnumber to name. +/* Copy the name of (frozen, if frozen is true) peernumber who is in + * groupnumber to name. * name must be at least MAX_NAME_LENGTH long. * * return length of name if success * return -1 if groupnumber is invalid. * return -2 if peernumber is invalid. */ -int group_peername(const Group_Chats *g_c, uint32_t groupnumber, int peernumber, uint8_t *name); +int group_peername(const Group_Chats *g_c, uint32_t groupnumber, int peernumber, uint8_t *name, bool frozen); + +/* Copy last active timestamp of frozen peernumber who is in groupnumber to + * last_active. + * + * return 0 on success. + * return -1 if groupnumber is invalid. + * return -2 if peernumber is invalid. + */ +int group_frozen_last_active(const Group_Chats *g_c, uint32_t groupnumber, int peernumber, + uint64_t *last_active); /* invite friendnumber to groupnumber * @@ -306,12 +319,6 @@ int group_message_send(const Group_Chats *g_c, uint32_t groupnumber, const uint8 */ int group_action_send(const Group_Chats *g_c, uint32_t groupnumber, const uint8_t *action, uint16_t length); -/* send message to announce leaving group - * return true on success - * return false on failure - */ -bool group_leave(const Group_Chats *g_c, uint32_t groupnumber); - /* set the group's title, limited to MAX_NAME_LENGTH * return 0 on success * return -1 if groupnumber is invalid. @@ -336,10 +343,11 @@ int group_title_get_size(const Group_Chats *g_c, uint32_t groupnumber); */ int group_title_get(const Group_Chats *g_c, uint32_t groupnumber, uint8_t *title); -/* Return the number of peers in the group chat on success. +/* Return the number of (frozen, if frozen is true) peers in the group chat on + * success. * return -1 if groupnumber is invalid. */ -int group_number_peers(const Group_Chats *g_c, uint32_t groupnumber); +int group_number_peers(const Group_Chats *g_c, uint32_t groupnumber, bool frozen); /* return 1 if the peernumber corresponds to ours. * return 0 if the peernumber is not ours. @@ -349,7 +357,7 @@ int group_number_peers(const Group_Chats *g_c, uint32_t groupnumber); */ int group_peernumber_is_ours(const Group_Chats *g_c, uint32_t groupnumber, int peernumber); -/* List all the peers in the group chat. +/* List all the (frozen, if frozen is true) peers in the group chat. * * Copies the names of the peers to the name[length][MAX_NAME_LENGTH] array. * @@ -360,7 +368,7 @@ int group_peernumber_is_ours(const Group_Chats *g_c, uint32_t groupnumber, int p * return -1 on failure. */ int group_names(const Group_Chats *g_c, uint32_t groupnumber, uint8_t names[][MAX_NAME_LENGTH], uint16_t lengths[], - uint16_t length); + uint16_t length, bool frozen); /* Set handlers for custom lossy packets. */ void group_lossy_packet_registerhandler(Group_Chats *g_c, uint8_t byte, lossy_packet_cb *function); diff --git a/toxcore/state.c b/toxcore/state.c index 919c2e8c7e..bca7a1512d 100644 --- a/toxcore/state.c +++ b/toxcore/state.c @@ -84,6 +84,28 @@ uint16_t host_to_lendian16(uint16_t host) return lendian_to_host16(host); } +void host_to_lendian_bytes64(uint8_t *dest, uint64_t num) +{ +#ifdef WORDS_BIGENDIAN + num = ((num << 8) & 0xFF00FF00FF00FF00) | ((num >> 8) & 0xFF00FF00FF00FF); + num = ((num << 16) & 0xFFFF0000FFFF0000) | ((num >> 16) & 0xFFFF0000FFFF); + num = (num << 32) | (num >> 32); +#endif + memcpy(dest, &num, sizeof(uint64_t)); +} + +void lendian_bytes_to_host64(uint64_t *dest, const uint8_t *lendian) +{ + uint64_t d; + memcpy(&d, lendian, sizeof(uint64_t)); +#ifdef WORDS_BIGENDIAN + d = ((d << 8) & 0xFF00FF00FF00FF00) | ((d >> 8) & 0xFF00FF00FF00FF); + d = ((d << 16) & 0xFFFF0000FFFF0000) | ((d >> 16) & 0xFFFF0000FFFF); + d = (d << 32) | (d >> 32); +#endif + *dest = d; +} + void host_to_lendian_bytes32(uint8_t *dest, uint32_t num) { #ifdef WORDS_BIGENDIAN diff --git a/toxcore/state.h b/toxcore/state.h index 6e3c897eae..829036d8dd 100644 --- a/toxcore/state.h +++ b/toxcore/state.h @@ -58,6 +58,9 @@ uint8_t *state_write_section_header(uint8_t *data, uint16_t cookie_type, uint32_ uint16_t lendian_to_host16(uint16_t lendian); uint16_t host_to_lendian16(uint16_t host); +void host_to_lendian_bytes64(uint8_t *dest, uint64_t num); +void lendian_bytes_to_host64(uint64_t *dest, const uint8_t *lendian); + void host_to_lendian_bytes32(uint8_t *dest, uint32_t num); void lendian_bytes_to_host32(uint32_t *dest, const uint8_t *lendian); diff --git a/toxcore/tox.api.h b/toxcore/tox.api.h index 5378847358..ba1932f454 100644 --- a/toxcore/tox.api.h +++ b/toxcore/tox.api.h @@ -2257,32 +2257,32 @@ namespace conference { CONFERENCE_NOT_FOUND, } - - namespace peer { - + /** + * Error codes for peer info queries. + */ + error for peer_query { /** - * Error codes for peer info queries. + * The conference number passed did not designate a valid conference. */ - error for query { - /** - * The conference number passed did not designate a valid conference. - */ - CONFERENCE_NOT_FOUND, - /** - * The peer number passed did not designate a valid peer. - */ - PEER_NOT_FOUND, - /** - * The client is not connected to the conference. - */ - NO_CONNECTION, - } + CONFERENCE_NOT_FOUND, + /** + * The peer number passed did not designate a valid peer. + */ + PEER_NOT_FOUND, + /** + * The client is not connected to the conference. + */ + NO_CONNECTION, + } + + + namespace peer { /** * Return the number of peers in the conference. Return value is unspecified on failure. */ const uint32_t count(uint32_t conference_number) - with error for query; + with error for peer_query; uint8_t[size] name { @@ -2290,7 +2290,7 @@ namespace conference { * Return the length of the peer's name. Return value is unspecified on failure. */ size(uint32_t conference_number, uint32_t peer_number) - with error for query; + with error for peer_query; /** * Copy the name of peer_number who is in conference_number to name. @@ -2299,7 +2299,7 @@ namespace conference { * @return true on success. */ get(uint32_t conference_number, uint32_t peer_number) - with error for query; + with error for peer_query; } /** @@ -2310,17 +2310,63 @@ namespace conference { */ uint8_t[PUBLIC_KEY_SIZE] public_key { get(uint32_t conference_number, uint32_t peer_number) - with error for query; + with error for peer_query; } /** * Return true if passed peer_number corresponds to our own. */ const bool number_is_ours(uint32_t conference_number, uint32_t peer_number) - with error for query; + with error for peer_query; } + namespace offline_peer { + + /** + * Return the number of offline peers in the conference. Return value is unspecified on failure. + */ + const uint32_t count(uint32_t conference_number) + with error for peer_query; + + uint8_t[size] name { + + /** + * Return the length of the offline peer's name. Return value is unspecified on failure. + */ + size(uint32_t conference_number, uint32_t offline_peer_number) + with error for peer_query; + + /** + * Copy the name of offline_peer_number who is in conference_number to name. + * name must be at least $MAX_NAME_LENGTH long. + * + * @return true on success. + */ + get(uint32_t conference_number, uint32_t offline_peer_number) + with error for peer_query; + } + + /** + * Copy the public key of offline_peer_number who is in conference_number to public_key. + * public_key must be $PUBLIC_KEY_SIZE long. + * + * @return true on success. + */ + uint8_t[PUBLIC_KEY_SIZE] public_key { + get(uint32_t conference_number, uint32_t offline_peer_number) + with error for peer_query; + } + + /** + * Return a unix-time timestamp of the last time offline_peer_number was seen to be active. + */ + uint64_t last_active { + get(uint32_t conference_number, uint32_t offline_peer_number) + with error for peer_query; + } + + } /** * Invites a friend to a conference. diff --git a/toxcore/tox.c b/toxcore/tox.c index 88a9bd50a1..d848102e5a 100644 --- a/toxcore/tox.c +++ b/toxcore/tox.c @@ -713,6 +713,7 @@ Tox_Connection tox_self_get_connection_status(const Tox *tox) { const Messenger *m = tox->m; + // TODO(zugz): this can be const. Similarly throughout the file. unsigned int ret = onion_connection_status(m->onion_c); if (ret == 2) { @@ -1533,8 +1534,7 @@ uint32_t tox_conference_new(Tox *tox, Tox_Err_Conference_New *error) bool tox_conference_delete(Tox *tox, uint32_t conference_number, Tox_Err_Conference_Delete *error) { Messenger *m = tox->m; - group_leave(m->conferences_object, conference_number); - int ret = del_groupchat(m->conferences_object, conference_number); + int ret = del_groupchat(m->conferences_object, conference_number, true); if (ret == -1) { SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_DELETE_CONFERENCE_NOT_FOUND); @@ -1548,7 +1548,7 @@ bool tox_conference_delete(Tox *tox, uint32_t conference_number, Tox_Err_Confere uint32_t tox_conference_peer_count(const Tox *tox, uint32_t conference_number, Tox_Err_Conference_Peer_Query *error) { const Messenger *m = tox->m; - int ret = group_number_peers(m->conferences_object, conference_number); + int ret = group_number_peers(m->conferences_object, conference_number, false); if (ret == -1) { SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND); @@ -1563,7 +1563,7 @@ size_t tox_conference_peer_get_name_size(const Tox *tox, uint32_t conference_num Tox_Err_Conference_Peer_Query *error) { const Messenger *m = tox->m; - int ret = group_peername_size(m->conferences_object, conference_number, peer_number); + int ret = group_peername_size(m->conferences_object, conference_number, peer_number, false); switch (ret) { case -1: @@ -1583,7 +1583,7 @@ bool tox_conference_peer_get_name(const Tox *tox, uint32_t conference_number, ui Tox_Err_Conference_Peer_Query *error) { const Messenger *m = tox->m; - int ret = group_peername(m->conferences_object, conference_number, peer_number, name); + int ret = group_peername(m->conferences_object, conference_number, peer_number, name, false); switch (ret) { case -1: @@ -1603,7 +1603,7 @@ bool tox_conference_peer_get_public_key(const Tox *tox, uint32_t conference_numb uint8_t *public_key, Tox_Err_Conference_Peer_Query *error) { const Messenger *m = tox->m; - int ret = group_peer_pubkey(m->conferences_object, conference_number, peer_number, public_key); + int ret = group_peer_pubkey(m->conferences_object, conference_number, peer_number, public_key, false); switch (ret) { case -1: @@ -1643,6 +1643,106 @@ bool tox_conference_peer_number_is_ours(const Tox *tox, uint32_t conference_numb return ret; } +uint32_t tox_conference_offline_peer_count(const Tox *tox, uint32_t conference_number, + Tox_Err_Conference_Peer_Query *error) +{ + const Messenger *m = tox->m; + int ret = group_number_peers(m->conferences_object, conference_number, true); + + if (ret == -1) { + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND); + return UINT32_MAX; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK); + return ret; +} + +size_t tox_conference_offline_peer_get_name_size(const Tox *tox, uint32_t conference_number, + uint32_t offline_peer_number, + Tox_Err_Conference_Peer_Query *error) +{ + const Messenger *m = tox->m; + int ret = group_peername_size(m->conferences_object, conference_number, offline_peer_number, true); + + switch (ret) { + case -1: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND); + return -1; + + case -2: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_PEER_NOT_FOUND); + return -1; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK); + return ret; +} + +bool tox_conference_offline_peer_get_name(const Tox *tox, uint32_t conference_number, uint32_t offline_peer_number, + uint8_t *name, + Tox_Err_Conference_Peer_Query *error) +{ + const Messenger *m = tox->m; + int ret = group_peername(m->conferences_object, conference_number, offline_peer_number, name, true); + + switch (ret) { + case -1: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND); + return false; + + case -2: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_PEER_NOT_FOUND); + return false; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK); + return true; +} + +bool tox_conference_offline_peer_get_public_key(const Tox *tox, uint32_t conference_number, + uint32_t offline_peer_number, + uint8_t *public_key, Tox_Err_Conference_Peer_Query *error) +{ + const Messenger *m = tox->m; + int ret = group_peer_pubkey(m->conferences_object, conference_number, offline_peer_number, public_key, true); + + switch (ret) { + case -1: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND); + return false; + + case -2: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_PEER_NOT_FOUND); + return false; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK); + return true; +} + +uint64_t tox_conference_offline_peer_get_last_active(const Tox *tox, uint32_t conference_number, + uint32_t offline_peer_number, + Tox_Err_Conference_Peer_Query *error) +{ + const Messenger *m = tox->m; + uint64_t last_active = UINT64_MAX; + int ret = group_frozen_last_active(m->conferences_object, conference_number, offline_peer_number, &last_active); + + switch (ret) { + case -1: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND); + return UINT64_MAX; + + case -2: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_PEER_NOT_FOUND); + return UINT64_MAX; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK); + return last_active; +} + bool tox_conference_invite(Tox *tox, uint32_t friend_number, uint32_t conference_number, Tox_Err_Conference_Invite *error) { diff --git a/toxcore/tox.h b/toxcore/tox.h index ee8a01cc7d..94ffd32a6d 100644 --- a/toxcore/tox.h +++ b/toxcore/tox.h @@ -2631,6 +2631,42 @@ bool tox_conference_peer_get_public_key(const Tox *tox, uint32_t conference_numb bool tox_conference_peer_number_is_ours(const Tox *tox, uint32_t conference_number, uint32_t peer_number, TOX_ERR_CONFERENCE_PEER_QUERY *error); +/** + * Return the number of offline peers in the conference. Return value is unspecified on failure. + */ +uint32_t tox_conference_offline_peer_count(const Tox *tox, uint32_t conference_number, + TOX_ERR_CONFERENCE_PEER_QUERY *error); + +/** + * Return the length of the offline peer's name. Return value is unspecified on failure. + */ +size_t tox_conference_offline_peer_get_name_size(const Tox *tox, uint32_t conference_number, + uint32_t offline_peer_number, TOX_ERR_CONFERENCE_PEER_QUERY *error); + +/** + * Copy the name of offline_peer_number who is in conference_number to name. + * name must be at least TOX_MAX_NAME_LENGTH long. + * + * @return true on success. + */ +bool tox_conference_offline_peer_get_name(const Tox *tox, uint32_t conference_number, uint32_t offline_peer_number, + uint8_t *name, TOX_ERR_CONFERENCE_PEER_QUERY *error); + +/** + * Copy the public key of offline_peer_number who is in conference_number to public_key. + * public_key must be TOX_PUBLIC_KEY_SIZE long. + * + * @return true on success. + */ +bool tox_conference_offline_peer_get_public_key(const Tox *tox, uint32_t conference_number, + uint32_t offline_peer_number, uint8_t *public_key, TOX_ERR_CONFERENCE_PEER_QUERY *error); + +/** + * Return a unix-time timestamp of the last time offline_peer_number was seen to be active. + */ +uint64_t tox_conference_offline_peer_get_last_active(const Tox *tox, uint32_t conference_number, + uint32_t offline_peer_number, TOX_ERR_CONFERENCE_PEER_QUERY *error); + typedef enum TOX_ERR_CONFERENCE_INVITE { /**