static int connect_to_closest(Group_Chats *g_c, int groupnumber) { Group_c *g = get_group_c(g_c, groupnumber); if (!g) return -1; if (!g->changed) return 0; unsigned int i; for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { if (g->close[i].type == GROUPCHAT_CLOSE_NONE) continue; if (!g->close[i].closest) continue; uint8_t real_pk[crypto_box_PUBLICKEYBYTES]; uint8_t dht_temp_pk[crypto_box_PUBLICKEYBYTES]; get_friendcon_public_keys(real_pk, dht_temp_pk, g_c->fr_c, g->close[i].number); if (!pk_in_closest_peers(g, real_pk)) { g->close[i].type = GROUPCHAT_CLOSE_NONE; kill_friend_connection(g_c->fr_c, g->close[i].number); } } for (i = 0; i < DESIRED_CLOSE_CONNECTIONS; ++i) { if (!g->closest_peers[i].entry) continue; int friendcon_id = getfriend_conn_id_pk(g_c->fr_c, g->closest_peers[i].real_pk); if (friendcon_id == -1) { friendcon_id = new_friend_connection(g_c->fr_c, g->closest_peers[i].real_pk); if (friendcon_id == -1) { continue; } set_dht_temp_pk(g_c->fr_c, friendcon_id, g->closest_peers[i].temp_pk); } add_conn_to_groupchat(g_c, friendcon_id, groupnumber, 1); if (friend_con_connected(g_c->fr_c, friendcon_id) == FRIENDCONN_STATUS_CONNECTED) { send_packet_online(g_c->fr_c, friendcon_id, groupnumber, g->identifier); } } g->changed = 0; return 0; }
/* Join a group (you need to have been invited first.) * * returns group number on success * returns -1 on failure. */ int join_groupchat(Group_Chats *g_c, int32_t friendnumber, const uint8_t *data, uint16_t length) { if (length != sizeof(uint16_t) + GROUP_IDENTIFIER_LENGTH) return -1; int friendcon_id = getfriendcon_id(g_c->m, friendnumber); if (friendcon_id == -1) return -1; int groupnumber = create_group_chat(g_c); if (groupnumber == -1) return -1; Group_c *g = &g_c->chats[groupnumber]; uint16_t group_num = htons(groupnumber); g->status = GROUPCHAT_STATUS_VALID; g->number_joined = -1; memcpy(g->real_pk, g_c->m->net_crypto->self_public_key, crypto_box_PUBLICKEYBYTES); uint8_t response[INVITE_RESPONSE_PACKET_SIZE]; response[0] = INVITE_RESPONSE_ID; memcpy(response + 1, &group_num, sizeof(uint16_t)); memcpy(response + 1 + sizeof(uint16_t), data, sizeof(uint16_t) + GROUP_IDENTIFIER_LENGTH); if (send_group_invite_packet(g_c->m, friendnumber, response, sizeof(response))) { uint16_t other_groupnum; memcpy(&other_groupnum, data, sizeof(other_groupnum)); other_groupnum = ntohs(other_groupnum); memcpy(g->identifier, data + sizeof(uint16_t), GROUP_IDENTIFIER_LENGTH); int close_index = add_conn_to_groupchat(g_c, friendcon_id, groupnumber, 0, 1); if (close_index != -1) { g->close[close_index].group_number = other_groupnum; g->close[close_index].type = GROUPCHAT_CLOSE_ONLINE; g->number_joined = friendcon_id; } send_peer_query(g_c, friendcon_id, other_groupnum); return groupnumber; } else { g->status = GROUPCHAT_STATUS_NONE; return -1; } }
static void handle_friend_invite_packet(Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length) { Group_Chats *g_c = m->group_chat_object; if (length <= 1) return; const uint8_t *invite_data = data + 1; uint16_t invite_length = length - 1; switch (data[0]) { case INVITE_ID: { if (length != INVITE_PACKET_SIZE) return; int groupnumber = get_group_num(g_c, data + 1 + sizeof(uint16_t)); if (groupnumber == -1) { if (g_c->invite_callback) g_c->invite_callback(m, friendnumber, invite_data, invite_length, g_c->invite_callback_userdata); return; } break; } case INVITE_RESPONSE_ID: { if (length != INVITE_RESPONSE_PACKET_SIZE) return; uint16_t other_groupnum, groupnum; memcpy(&groupnum, data + 1 + sizeof(uint16_t), sizeof(uint16_t)); groupnum = ntohs(groupnum); Group_c *g = get_group_c(g_c, groupnum); if (!g) return; if (memcmp(data + 1 + sizeof(uint16_t) * 2, g->identifier, GROUP_IDENTIFIER_LENGTH) != 0) return; uint16_t peer_number = rand(); /* TODO: what if two people enter the group at the same time and are given the same peer_number by different nodes? */ unsigned int tries = 0; while (get_peer_index(g, peer_number) != -1) { peer_number = rand(); ++tries; if (tries > 32) return; } memcpy(&other_groupnum, data + 1, sizeof(uint16_t)); other_groupnum = ntohs(other_groupnum); int friendcon_id = getfriendcon_id(m, friendnumber); uint8_t real_pk[crypto_box_PUBLICKEYBYTES], temp_pk[crypto_box_PUBLICKEYBYTES]; get_friendcon_public_keys(real_pk, temp_pk, g_c->fr_c, friendcon_id); addpeer(g_c, groupnum, real_pk, temp_pk, peer_number); int close_index = add_conn_to_groupchat(g_c, friendcon_id, groupnum, 0, 1); if (close_index != -1) { g->close[close_index].group_number = other_groupnum; g->close[close_index].type = GROUPCHAT_CLOSE_ONLINE; } group_new_peer_send(g_c, groupnum, peer_number, real_pk, temp_pk); break; } default: return; } }