- /* Join the client to the channel by adding it to channel's user list.
- Add also the channel to client entry's channels list for fast cross-
- referencing. */
- chl = silc_calloc(1, sizeof(*chl));
- chl->mode = umode;
- chl->client = client;
- chl->channel = channel;
- silc_hash_table_add(channel->user_list, client, chl);
- silc_hash_table_add(client->channels, channel, chl);
- channel->user_count++;
-
- /* Get users on the channel */
- silc_server_get_users_on_channel(server, channel, &user_list, &mode_list,
- &user_count);
-
- /* Encode Client ID Payload of the original client who wants to join */
- clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
-
- /* Encode command reply packet */
- chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
- SILC_PUT32_MSB(channel->mode, mode);
- SILC_PUT32_MSB(created, tmp2);
- SILC_PUT32_MSB(user_count, tmp3);
-
- if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
- tmp = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
- keyp = silc_channel_key_payload_encode(SILC_ID_CHANNEL_LEN, tmp,
- strlen(channel->channel_key->
- cipher->name),
- channel->channel_key->cipher->name,
- channel->key_len / 8, channel->key);
- silc_free(tmp);
- }
-
- reply =
- silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
- SILC_STATUS_OK, ident, 13,
- 2, channel->channel_name,
- strlen(channel->channel_name),
- 3, chidp->data, chidp->len,
- 4, clidp->data, clidp->len,
- 5, mode, 4,
- 6, tmp2, 4,
- 7, keyp ? keyp->data : NULL,
- keyp ? keyp->len : 0,
- 8, channel->ban_list,
- channel->ban_list ?
- strlen(channel->ban_list) : 0,
- 9, channel->invite_list,
- channel->invite_list ?
- strlen(channel->invite_list) : 0,
- 10, channel->topic,
- channel->topic ?
- strlen(channel->topic) : 0,
- 11, silc_hmac_get_name(channel->hmac),
- strlen(silc_hmac_get_name(channel->
- hmac)),
- 12, tmp3, 4,
- 13, user_list->data, user_list->len,
- 14, mode_list->data,
- mode_list->len);
-
- /* Send command reply */
- silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
- reply->data, reply->len, FALSE);
-
- /* Send JOIN notify to locally connected clients on the channel. If
- we are normal server then router will send or have sent JOIN notify
- already. However since we've added the client already to our channel
- we'll ignore it (in packet_receive.c) so we must send it here. If
- we are router then this will send it to local clients and local
- servers. */
- silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
- SILC_NOTIFY_TYPE_JOIN, 2,
- clidp->data, clidp->len,
- chidp->data, chidp->len);
-
- if (!cmd->pending) {
- /* Send JOIN notify packet to our primary router */
- if (!server->standalone)
- silc_server_send_notify_join(server, server->router->connection,
- server->server_type == SILC_ROUTER ?
- TRUE : FALSE, channel, client->id);
-
- if (keyp)
- /* Distribute the channel key to all backup routers. */
- silc_server_backup_send(server, NULL, SILC_PACKET_CHANNEL_KEY, 0,
- keyp->data, keyp->len, FALSE, TRUE);
- }
-
- /* If client became founder by providing correct founder auth data
- notify the mode change to the channel. */
- if (founder) {
- SILC_PUT32_MSB(chl->mode, mode);
- silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
- SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3,
- clidp->data, clidp->len,
- mode, 4, clidp->data, clidp->len);
-
- /* Set CUMODE notify type to network */
- if (!server->standalone)
- silc_server_send_notify_cumode(server, server->router->connection,
- server->server_type == SILC_ROUTER ?
- TRUE : FALSE, channel,
- chl->mode, client->id, SILC_ID_CLIENT,
- client->id);
- }
-
- silc_buffer_free(reply);
- silc_buffer_free(clidp);
- silc_buffer_free(chidp);
- silc_buffer_free(keyp);
- silc_buffer_free(user_list);
- silc_buffer_free(mode_list);
-
- out:
- silc_free(passphrase);
-}
-
-/* Server side of command JOIN. Joins client into requested channel. If
- the channel does not exist it will be created. */
-
-SILC_SERVER_CMD_FUNC(join)
-{
- SilcServerCommandContext cmd = (SilcServerCommandContext)context;
- SilcServer server = cmd->server;
- unsigned char *auth;
- SilcUInt32 tmp_len, auth_len;
- char *tmp, *channel_name = NULL, *cipher, *hmac;
- SilcChannelEntry channel;
- SilcUInt32 umode = 0;
- bool created = FALSE, create_key = TRUE;
- SilcClientID *client_id;
-
- SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_JOIN, cmd, 2, 6);
-
- /* Get channel name */
- tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
- if (!tmp) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
- channel_name = tmp;
-
- if (tmp_len > 256)
- channel_name[255] = '\0';
-
- if (silc_server_name_bad_chars(channel_name, tmp_len) == TRUE) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
- SILC_STATUS_ERR_BAD_CHANNEL);
- goto out;
- }
-
- /* Get Client ID of the client who is joining to the channel */
- tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
- if (!tmp) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
- client_id = silc_id_payload_parse_id(tmp, tmp_len);
- if (!client_id) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
-
- /* Get cipher, hmac name and auth payload */
- cipher = silc_argument_get_arg_type(cmd->args, 4, NULL);
- hmac = silc_argument_get_arg_type(cmd->args, 5, NULL);
- auth = silc_argument_get_arg_type(cmd->args, 6, &auth_len);
-
- /* See if the channel exists */
- channel = silc_idlist_find_channel_by_name(server->local_list,
- channel_name, NULL);
-
- if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
- SilcClientEntry entry = (SilcClientEntry)cmd->sock->user_data;
- client_id = silc_id_dup(entry->id, SILC_ID_CLIENT);
-
- if (!channel || channel->disabled) {
- /* Channel not found */
-
- /* If we are standalone server we don't have a router, we just create
- the channel by ourselves. */
- if (server->standalone) {
- channel = silc_server_create_new_channel(server, server->id, cipher,
- hmac, channel_name, TRUE);
- if (!channel) {
- silc_server_command_send_status_reply(
- cmd, SILC_COMMAND_JOIN,
- SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
- goto out;
- }
-
- umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
- created = TRUE;
- create_key = FALSE;
-
- } else {
-
- /* The channel does not exist on our server. If we are normal server
- we will send JOIN command to our router which will handle the
- joining procedure (either creates the channel if it doesn't exist
- or joins the client to it). */
- if (server->server_type != SILC_ROUTER) {
- SilcBuffer tmpbuf;
- SilcUInt16 old_ident;
-
- /* If this is pending command callback then we've resolved
- it and it didn't work, return since we've notified the
- client already in the command reply callback. */
- if (cmd->pending)
- goto out;
-
- old_ident = silc_command_get_ident(cmd->payload);
- silc_command_set_ident(cmd->payload, ++server->cmd_ident);
- tmpbuf = silc_command_payload_encode_payload(cmd->payload);
-
- /* Send JOIN command to our router */
- silc_server_packet_send(server, (SilcSocketConnection)
- server->router->connection,
- SILC_PACKET_COMMAND, cmd->packet->flags,
- tmpbuf->data, tmpbuf->len, TRUE);
-
- /* Reprocess this packet after received reply from router */
- silc_server_command_pending(server, SILC_COMMAND_JOIN,
- silc_command_get_ident(cmd->payload),
- silc_server_command_join,
- silc_server_command_dup(cmd));
- cmd->pending = TRUE;
- silc_command_set_ident(cmd->payload, old_ident);
- silc_buffer_free(tmpbuf);
- goto out;
- }
-
- /* We are router and the channel does not seem exist so we will check
- our global list as well for the channel. */
- channel = silc_idlist_find_channel_by_name(server->global_list,
- channel_name, NULL);
- if (!channel) {
- /* Channel really does not exist, create it */
- channel = silc_server_create_new_channel(server, server->id, cipher,
- hmac, channel_name, TRUE);
- if (!channel) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
- SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
- goto out;
- }
-
- umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
- created = TRUE;
- create_key = FALSE;
- }
- }
- }
- } else {
- if (!channel) {
- /* Channel not found */