- case SILC_NOTIFY_TYPE_CMODE_CHANGE:
- {
- /*
- * Someone changed a channel mode
- */
- char *passphrase, *cipher, *hmac;
- SilcPublicKey founder_key = NULL;
- SilcBufferStruct chpks;
-
- SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
-
- /* Get channel entry */
- channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
- SILC_ID_CHANNEL);
- if (!channel_id)
- goto out;
- channel = silc_client_get_channel_by_id(client, conn, channel_id);
- if (!channel)
- goto out;
-
- /* Get ID */
- tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
- if (!tmp)
- goto out;
- id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
- if (!id)
- goto out;
-
- /* Find Client entry */
- if (id_type == SILC_ID_CLIENT) {
- /* Find Client entry */
- client_id = id;
- client_entry = silc_client_get_client_by_id(client, conn, client_id);
- if (!client_entry) {
- silc_client_channel_set_wait(client, conn, channel,
- conn->cmd_ident + 1);
- silc_client_notify_by_server_resolve(client, conn, packet,
- SILC_ID_CLIENT, client_id);
- goto out;
- }
-
- if (!client_entry->nickname) {
- if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
- /* Attach to existing resolving */
- SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
- res->packet = silc_packet_context_dup(packet);
- res->context = client;
- res->sock = silc_socket_dup(conn->sock);
- silc_client_command_pending(conn, SILC_COMMAND_NONE,
- client_entry->resolve_cmd_ident,
- silc_client_notify_by_server_pending,
- res);
- goto out;
- }
-
- /* Do new resolving */
- silc_client_channel_set_wait(client, conn, channel,
- conn->cmd_ident + 1);
- silc_client_notify_by_server_resolve(client, conn, packet,
- SILC_ID_CLIENT, client_id);
- client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
- client_entry->resolve_cmd_ident = conn->cmd_ident;
- goto out;
- }
- } else if (id_type == SILC_ID_SERVER) {
- /* Find Server entry */
- server_id = id;
- server = silc_client_get_server_by_id(client, conn, server_id);
- if (!server) {
- silc_client_channel_set_wait(client, conn, channel,
- conn->cmd_ident + 1);
- silc_client_notify_by_server_resolve(client, conn, packet,
- SILC_ID_SERVER, server_id);
- server = silc_client_add_server(client, conn, NULL, NULL, server_id);
- if (!server)
- goto out;
-
- server->resolve_cmd_ident = conn->cmd_ident;
- server_id = NULL;
- goto out;
- }
-
- /* If entry being resoled, wait for it before processing this notify */
- if (server->resolve_cmd_ident) {
- SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
- res->packet = silc_packet_context_dup(packet);
- res->context = client;
- res->sock = silc_socket_dup(conn->sock);
- silc_client_command_pending(conn, SILC_COMMAND_NONE,
- server->resolve_cmd_ident,
- silc_client_notify_by_server_pending,
- res);
- goto out;
- }
-
- /* Save the pointer to the client_entry pointer */
- client_entry = (SilcClientEntry)server;
- } else {
- /* Find Channel entry */
- silc_free(channel_id);
- channel_id = id;
- client_entry = (SilcClientEntry)
- silc_client_get_channel_by_id(client, conn, channel_id);
- if (!client_entry) {
- silc_client_channel_set_wait(client, conn, channel,
- conn->cmd_ident + 1);
- silc_client_notify_by_server_resolve(client, conn, packet,
- SILC_ID_CHANNEL, channel_id);
- goto out;
- }
- }
-
- /* Get the mode */
- tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
- if (!tmp)
- goto out;
-
- SILC_GET32_MSB(mode, tmp);
-
- /* If information is being resolved for this channel, wait for it */
- if (channel->resolve_cmd_ident) {
- silc_client_channel_wait(client, conn, channel, packet);
- goto out;
- }
-
- /* Save the new mode */
- channel->mode = mode;
-
- /* Get the cipher */
- cipher = silc_argument_get_arg_type(args, 3, &tmp_len);
-
- /* Get the hmac */
- hmac = silc_argument_get_arg_type(args, 4, &tmp_len);
- if (hmac) {
- unsigned char hash[SILC_HASH_MAXLEN];
-
- if (channel->hmac)
- silc_hmac_free(channel->hmac);
- if (!silc_hmac_alloc(hmac, NULL, &channel->hmac))
- goto out;
-
- silc_hash_make(silc_hmac_get_hash(channel->hmac),
- channel->key, channel->key_len / 8,
- hash);
- silc_hmac_set_key(channel->hmac, hash,
- silc_hash_len(silc_hmac_get_hash(channel->hmac)));
- memset(hash, 0, sizeof(hash));
- }
-
- /* Get the passphrase if it was set */
- passphrase = silc_argument_get_arg_type(args, 5, &tmp_len);
-
- /* Get the channel founder key if it was set */
- tmp = silc_argument_get_arg_type(args, 6, &tmp_len);
- if (tmp) {
- if (!silc_pkcs_public_key_payload_decode(tmp, tmp_len, &founder_key))
- founder_key = NULL;
- }
-
- /* Get user limit */
- tmp = silc_argument_get_arg_type(args, 8, &tmp_len);
- if (tmp && tmp_len == 4)
- SILC_GET32_MSB(channel->user_limit, tmp);
- if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
- channel->user_limit = 0;
-
- /* Get the channel public key that was added or removed */
- tmp = silc_argument_get_arg_type(args, 7, &tmp_len);
- if (tmp)
- silc_buffer_set(&chpks, tmp, tmp_len);
-
- /* Notify application. The channel entry is sent last as this notify
- is for channel but application don't know it from the arguments
- sent by server. */
- client->internal->ops->notify(client, conn, type, id_type,
- client_entry, mode, cipher, hmac,
- passphrase, founder_key,
- tmp ? &chpks : NULL, channel);
-
- if (founder_key)
- silc_pkcs_public_key_free(founder_key);
- }
- break;