5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2005 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
20 /* This file includes the Notify packet handling. Notify packets are
21 important packets sent by the server. They tell different things to the
22 client such as nick changes, mode changes etc. */
25 #include "silcclient.h"
26 #include "client_internal.h"
28 /* Context used for resolving client, channel and server info. */
32 SilcSocketConnection sock;
33 } *SilcClientNotifyResolve;
35 SILC_TASK_CALLBACK(silc_client_notify_check_client)
37 SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
38 SilcClient client = res->context;
39 SilcClientConnection conn = res->sock->user_data;
40 SilcClientID *client_id = res->packet;
41 silc_client_get_client_by_id_resolve(client, conn, client_id,
44 silc_socket_free(res->sock);
48 SILC_TASK_CALLBACK(silc_client_notify_del_client_cb)
50 SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
51 SilcClient client = res->context;
52 SilcClientConnection conn = res->sock->user_data;
53 SilcClientID *client_id = res->packet;
54 SilcClientEntry client_entry;
55 client_entry = silc_client_get_client_by_id(client, conn, client_id);
57 silc_client_del_client(client, conn, client_entry);
59 silc_socket_free(res->sock);
63 /* Called when notify is received and some async operation (such as command)
64 is required before processing the notify message. This calls again the
65 silc_client_notify_by_server and reprocesses the original notify packet. */
67 static void silc_client_notify_by_server_pending(void *context, void *context2)
69 SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
70 SilcClientCommandReplyContext reply =
71 (SilcClientCommandReplyContext)context2;
73 SILC_LOG_DEBUG(("Start"));
75 if (reply && !silc_command_get_status(reply->payload, NULL, NULL))
78 silc_client_notify_by_server(res->context, res->sock, res->packet);
81 silc_socket_free(res->sock);
82 silc_packet_context_free(res->packet);
86 /* Resets the channel entry's resolve_cmd_ident after whatever-thing
87 was resolved is completed. */
89 static void silc_client_channel_cond(void *context, void *context2)
91 SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
92 SilcClient client = res->context;
93 SilcClientConnection conn = res->sock->user_data;
94 SilcChannelID *channel_id = res->packet;
95 SilcChannelEntry channel;
96 channel = silc_client_get_channel_by_id(client, conn, channel_id);
98 channel->resolve_cmd_ident = 0;
99 silc_free(channel_id);
100 silc_socket_free(res->sock);
104 /* Function that starts waiting for the `cmd_ident' to arrive and
105 marks the channel info being resolved. */
107 static void silc_client_channel_set_wait(SilcClient client,
108 SilcClientConnection conn,
109 SilcChannelEntry channel,
110 SilcUInt16 cmd_ident)
112 SilcClientNotifyResolve res;
114 if (!channel->resolve_cmd_ident) {
115 res = silc_calloc(1, sizeof(*res));
116 res->context = client;
117 res->sock = silc_socket_dup(conn->sock);
118 res->packet = silc_id_dup(channel->id, SILC_ID_CHANNEL);
119 silc_client_command_pending(conn, SILC_COMMAND_NONE, cmd_ident,
120 silc_client_channel_cond, res);
121 channel->resolve_cmd_ident = cmd_ident;
125 /* Attaches to the channel's resolving cmd ident and calls the
126 notify handling with `packet' after it's received. */
128 static void silc_client_channel_wait(SilcClient client,
129 SilcClientConnection conn,
130 SilcChannelEntry channel,
131 SilcPacketContext *packet)
133 SilcClientNotifyResolve res;
135 if (!channel->resolve_cmd_ident)
138 res = silc_calloc(1, sizeof(*res));
139 res->packet = silc_packet_context_dup(packet);
140 res->context = client;
141 res->sock = silc_socket_dup(conn->sock);
143 silc_client_command_pending(conn, SILC_COMMAND_NONE,
144 channel->resolve_cmd_ident,
145 silc_client_notify_by_server_pending, res);
148 /* Resolve client, channel or server information. */
150 static void silc_client_notify_by_server_resolve(SilcClient client,
151 SilcClientConnection conn,
152 SilcPacketContext *packet,
156 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
157 SilcBuffer idp = silc_id_payload_encode(id, id_type);
159 res->packet = silc_packet_context_dup(packet);
160 res->context = client;
161 res->sock = silc_socket_dup(conn->sock);
163 /* For client resolving use WHOIS, and otherwise use IDENTIFY */
164 if (id_type == SILC_ID_CLIENT) {
165 silc_client_command_register(client, SILC_COMMAND_WHOIS, NULL, NULL,
166 silc_client_command_reply_whois_i, 0,
168 silc_client_command_send(client, conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
169 1, 4, idp->data, idp->len);
170 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
171 silc_client_notify_by_server_pending, res);
173 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
174 silc_client_command_reply_identify_i, 0,
176 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
177 conn->cmd_ident, 1, 5, idp->data, idp->len);
178 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
179 silc_client_notify_by_server_pending, res);
181 silc_buffer_free(idp);
184 /* Received notify message from server */
186 void silc_client_notify_by_server(SilcClient client,
187 SilcSocketConnection sock,
188 SilcPacketContext *packet)
190 SilcBuffer buffer = packet->buffer;
191 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
192 SilcNotifyPayload payload;
194 SilcArgumentPayload args;
198 SilcClientID *client_id = NULL;
199 SilcChannelID *channel_id = NULL;
200 SilcServerID *server_id = NULL;
201 SilcClientEntry client_entry = NULL;
202 SilcClientEntry client_entry2 = NULL;
203 SilcChannelEntry channel;
205 SilcServerEntry server;
207 SilcUInt32 tmp_len, mode;
209 SILC_LOG_DEBUG(("Start"));
211 payload = silc_notify_payload_parse(buffer->data, buffer->len);
215 type = silc_notify_get_type(payload);
216 args = silc_notify_get_args(payload);
221 case SILC_NOTIFY_TYPE_NONE:
222 /* Notify application */
223 client->internal->ops->notify(client, conn, type,
224 silc_argument_get_arg_type(args, 1, NULL));
227 case SILC_NOTIFY_TYPE_INVITE:
229 * Someone invited me to a channel. Find Client and Channel entries
230 * for the application.
233 SILC_LOG_DEBUG(("Notify: INVITE"));
236 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
240 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
244 /* Get the channel entry */
245 channel = silc_client_get_channel_by_id(client, conn, channel_id);
247 /* Get sender Client ID */
248 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
252 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
256 /* Find Client entry and if not found query it */
257 client_entry = silc_client_get_client_by_id(client, conn, client_id);
259 silc_client_notify_by_server_resolve(client, conn, packet,
260 SILC_ID_CLIENT, client_id);
264 /* Get the channel name */
265 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
269 /* Notify application */
270 client->internal->ops->notify(client, conn, type, channel, tmp,
274 case SILC_NOTIFY_TYPE_JOIN:
276 * Someone has joined to a channel. Get their ID and nickname and
277 * cache them for later use.
280 SILC_LOG_DEBUG(("Notify: JOIN"));
283 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
287 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
291 /* Get channel entry */
292 channel = silc_client_get_channel_by_id(client, conn, channel_id);
297 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
301 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
305 /* Find Client entry and if not found query it */
306 client_entry = silc_client_get_client_by_id(client, conn, client_id);
308 silc_client_channel_set_wait(client, conn, channel,
309 conn->cmd_ident + 1);
310 silc_client_notify_by_server_resolve(client, conn, packet,
311 SILC_ID_CLIENT, client_id);
315 /* If nickname or username hasn't been resolved, do so */
316 if (!client_entry->nickname || !client_entry->username) {
317 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
318 /* Attach to existing resolving */
319 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
320 res->packet = silc_packet_context_dup(packet);
321 res->context = client;
322 res->sock = silc_socket_dup(conn->sock);
323 silc_client_command_pending(conn, SILC_COMMAND_NONE,
324 client_entry->resolve_cmd_ident,
325 silc_client_notify_by_server_pending,
330 /* Do new resolving */
331 silc_client_channel_set_wait(client, conn, channel,
332 conn->cmd_ident + 1);
333 silc_client_notify_by_server_resolve(client, conn, packet,
334 SILC_ID_CLIENT, client_id);
335 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
336 client_entry->resolve_cmd_ident = conn->cmd_ident;
339 if (client_entry != conn->local_entry)
340 silc_client_nickname_format(client, conn, client_entry);
343 /* If information is being resolved for this channel, wait for it */
344 if (channel->resolve_cmd_ident) {
345 silc_client_channel_wait(client, conn, channel, packet);
349 /* Join the client to channel */
350 if (!silc_client_on_channel(channel, client_entry)) {
351 chu = silc_calloc(1, sizeof(*chu));
352 chu->client = client_entry;
353 chu->channel = channel;
354 silc_hash_table_add(channel->user_list, client_entry, chu);
355 silc_hash_table_add(client_entry->channels, channel, chu);
358 /* Notify application. The channel entry is sent last as this notify
359 is for channel but application don't know it from the arguments
361 client->internal->ops->notify(client, conn, type, client_entry, channel);
364 case SILC_NOTIFY_TYPE_LEAVE:
366 * Someone has left a channel. We will remove it from the channel but
367 * we'll keep it in the cache in case we'll need it later.
370 SILC_LOG_DEBUG(("Notify: LEAVE"));
373 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
377 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
381 /* Find Client entry */
383 silc_client_get_client_by_id(client, conn, client_id);
387 /* Get channel entry */
388 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
392 channel = silc_client_get_channel_by_id(client, conn, channel_id);
396 /* Remove client from channel */
397 chu = silc_client_on_channel(channel, client_entry);
399 silc_hash_table_del(client_entry->channels, channel);
400 silc_hash_table_del(channel->user_list, client_entry);
404 /* Some client implementations actually quit network by first doing
405 LEAVE and then immediately SIGNOFF. We'll check for this by doing
406 check for the client after 5 - 34 seconds. If it is not valid after
407 that we'll remove the client from cache. */
408 if (!silc_hash_table_count(client_entry->channels)) {
409 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
410 res->context = client;
411 res->sock = silc_socket_dup(conn->sock);
412 res->packet = silc_id_dup(client_id, SILC_ID_CLIENT);
413 silc_schedule_task_add(client->schedule, conn->sock->sock,
414 silc_client_notify_check_client, res,
415 (5 + (silc_rng_get_rn16(client->rng) % 29)),
416 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
419 /* Notify application. The channel entry is sent last as this notify
420 is for channel but application don't know it from the arguments
422 client->internal->ops->notify(client, conn, type, client_entry, channel);
425 case SILC_NOTIFY_TYPE_SIGNOFF:
427 * Someone left SILC. We'll remove it from all channels and from cache.
430 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
433 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
437 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
441 /* Find Client entry */
443 silc_client_get_client_by_id(client, conn, client_id);
447 /* Get signoff message */
448 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
452 /* Notify application */
453 client->internal->ops->notify(client, conn, type, client_entry, tmp);
455 /* Remove from all channels */
456 silc_client_remove_from_channels(client, conn, client_entry);
458 /* Remove from cache */
459 silc_idcache_del_by_context(conn->internal->client_cache, client_entry);
462 silc_client_del_client_entry(client, conn, client_entry);
465 case SILC_NOTIFY_TYPE_TOPIC_SET:
467 * Someone set the topic on a channel.
470 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
472 /* Get channel entry */
473 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
477 channel = silc_client_get_channel_by_id(client, conn, channel_id);
482 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
485 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
489 /* Find Client entry */
490 if (id_type == SILC_ID_CLIENT) {
491 /* Find Client entry */
493 client_entry = silc_client_get_client_by_id(client, conn, client_id);
495 silc_client_channel_set_wait(client, conn, channel,
496 conn->cmd_ident + 1);
497 silc_client_notify_by_server_resolve(client, conn, packet,
498 SILC_ID_CLIENT, client_id);
501 } else if (id_type == SILC_ID_SERVER) {
502 /* Find Server entry */
504 server = silc_client_get_server_by_id(client, conn, server_id);
506 silc_client_channel_set_wait(client, conn, channel,
507 conn->cmd_ident + 1);
508 silc_client_notify_by_server_resolve(client, conn, packet,
509 SILC_ID_SERVER, server_id);
510 server = silc_client_add_server(client, conn, NULL, NULL, server_id);
514 server->resolve_cmd_ident = conn->cmd_ident;
519 /* If entry being resoled, wait for it before processing this notify */
520 if (server->resolve_cmd_ident) {
521 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
522 res->packet = silc_packet_context_dup(packet);
523 res->context = client;
524 res->sock = silc_socket_dup(conn->sock);
525 silc_client_command_pending(conn, SILC_COMMAND_NONE,
526 server->resolve_cmd_ident,
527 silc_client_notify_by_server_pending, res);
531 /* Save the pointer to the client_entry pointer */
532 client_entry = (SilcClientEntry)server;
534 /* Find Channel entry */
535 silc_free(channel_id);
537 client_entry = (SilcClientEntry)
538 silc_client_get_channel_by_id(client, conn, channel_id);
540 silc_client_channel_set_wait(client, conn, channel,
541 conn->cmd_ident + 1);
542 silc_client_notify_by_server_resolve(client, conn, packet,
543 SILC_ID_CHANNEL, channel_id);
549 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
553 /* If information is being resolved for this channel, wait for it */
554 if (channel->resolve_cmd_ident) {
555 silc_client_channel_wait(client, conn, channel, packet);
560 silc_free(channel->topic);
561 channel->topic = silc_memdup(tmp, strlen(tmp));
564 /* Notify application. The channel entry is sent last as this notify
565 is for channel but application don't know it from the arguments
567 client->internal->ops->notify(client, conn, type, id_type,
568 client_entry, tmp, channel);
572 case SILC_NOTIFY_TYPE_NICK_CHANGE:
574 * Someone changed their nickname. If we don't have entry for the new
575 * ID we will query it and return here after it's done. After we've
576 * returned we fetch the old entry and free it and notify the
580 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
582 /* Get old Client ID */
583 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
587 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
592 if (conn->local_id && SILC_ID_CLIENT_COMPARE(client_id, conn->local_id))
595 /* Find old Client entry */
596 client_entry = silc_client_get_client_by_id(client, conn, client_id);
599 silc_free(client_id);
602 /* Wait for resolving if necessary */
603 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
604 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
605 res->packet = silc_packet_context_dup(packet);
606 res->context = client;
607 res->sock = silc_socket_dup(conn->sock);
608 silc_client_command_pending(conn, SILC_COMMAND_NONE,
609 client_entry->resolve_cmd_ident,
610 silc_client_notify_by_server_pending, res);
614 client_entry->valid = FALSE;
616 /* Get new Client ID */
617 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
621 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
625 /* Take the nickname */
626 tmp = silc_argument_get_arg_type(args, 3, NULL);
630 /* Check whether nickname changed at all. It is possible that nick
631 change notify is received but nickname didn't change, only the
632 ID changes. Check whether the hashes in the Client ID match, if
633 they do nickname didn't change. */
634 if (SILC_ID_COMPARE_HASH(client_entry->id, client_id) &&
635 silc_utf8_strcasecmp(tmp, client_entry->nickname)) {
636 /* Nickname didn't change. Update only Client ID. */
638 /* Normalize nickname */
639 tmp = silc_identifier_check(tmp, strlen(tmp),
640 SILC_STRING_UTF8, 128, NULL);
644 silc_idcache_del_by_context(conn->internal->client_cache,
646 silc_free(client_entry->id);
647 client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
648 silc_idcache_add(conn->internal->client_cache, tmp,
649 client_entry->id, client_entry, 0, NULL);
651 /* Notify application */
652 client->internal->ops->notify(client, conn, type,
653 client_entry, client_entry);
657 /* Create new client entry, and save all old information with the
658 new nickname and client ID */
659 client_entry2 = silc_client_add_client(client, conn, NULL, NULL,
660 client_entry->realname,
661 silc_id_dup(client_id,
666 if (client_entry->server)
667 client_entry2->server = strdup(client_entry->server);
668 if (client_entry->username)
669 client_entry2->username = strdup(client_entry->username);
670 if (client_entry->hostname)
671 client_entry2->hostname = strdup(client_entry->hostname);
672 client_entry2->fingerprint = client_entry->fingerprint;
673 client_entry2->fingerprint_len = client_entry->fingerprint_len;
674 client_entry->fingerprint = NULL;
675 client_entry->fingerprint_len = 0;
676 silc_client_update_client(client, conn, client_entry2, tmp, NULL, NULL,
679 /* Remove the old from cache */
680 silc_idcache_del_by_context(conn->internal->client_cache, client_entry);
682 /* Replace old ID entry with new one on all channels. */
683 silc_client_replace_from_channels(client, conn, client_entry,
686 /* Notify application */
687 client->internal->ops->notify(client, conn, type,
688 client_entry, client_entry2);
690 /* Free old client entry */
691 silc_client_del_client_entry(client, conn, client_entry);
695 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
698 * Someone changed a channel mode
700 char *passphrase, *cipher, *hmac;
701 SilcPublicKey founder_key = NULL;
702 SilcBufferStruct chpks;
704 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
706 /* Get channel entry */
707 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
711 channel = silc_client_get_channel_by_id(client, conn, channel_id);
716 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
719 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
723 /* Find Client entry */
724 if (id_type == SILC_ID_CLIENT) {
725 /* Find Client entry */
727 client_entry = silc_client_get_client_by_id(client, conn, client_id);
729 silc_client_channel_set_wait(client, conn, channel,
730 conn->cmd_ident + 1);
731 silc_client_notify_by_server_resolve(client, conn, packet,
732 SILC_ID_CLIENT, client_id);
736 if (!client_entry->nickname) {
737 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
738 /* Attach to existing resolving */
739 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
740 res->packet = silc_packet_context_dup(packet);
741 res->context = client;
742 res->sock = silc_socket_dup(conn->sock);
743 silc_client_command_pending(conn, SILC_COMMAND_NONE,
744 client_entry->resolve_cmd_ident,
745 silc_client_notify_by_server_pending,
750 /* Do new resolving */
751 silc_client_channel_set_wait(client, conn, channel,
752 conn->cmd_ident + 1);
753 silc_client_notify_by_server_resolve(client, conn, packet,
754 SILC_ID_CLIENT, client_id);
755 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
756 client_entry->resolve_cmd_ident = conn->cmd_ident;
759 } else if (id_type == SILC_ID_SERVER) {
760 /* Find Server entry */
762 server = silc_client_get_server_by_id(client, conn, server_id);
764 silc_client_channel_set_wait(client, conn, channel,
765 conn->cmd_ident + 1);
766 silc_client_notify_by_server_resolve(client, conn, packet,
767 SILC_ID_SERVER, server_id);
768 server = silc_client_add_server(client, conn, NULL, NULL, server_id);
772 server->resolve_cmd_ident = conn->cmd_ident;
777 /* If entry being resoled, wait for it before processing this notify */
778 if (server->resolve_cmd_ident) {
779 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
780 res->packet = silc_packet_context_dup(packet);
781 res->context = client;
782 res->sock = silc_socket_dup(conn->sock);
783 silc_client_command_pending(conn, SILC_COMMAND_NONE,
784 server->resolve_cmd_ident,
785 silc_client_notify_by_server_pending,
790 /* Save the pointer to the client_entry pointer */
791 client_entry = (SilcClientEntry)server;
793 /* Find Channel entry */
794 silc_free(channel_id);
796 client_entry = (SilcClientEntry)
797 silc_client_get_channel_by_id(client, conn, channel_id);
799 silc_client_channel_set_wait(client, conn, channel,
800 conn->cmd_ident + 1);
801 silc_client_notify_by_server_resolve(client, conn, packet,
802 SILC_ID_CHANNEL, channel_id);
808 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
812 SILC_GET32_MSB(mode, tmp);
814 /* If information is being resolved for this channel, wait for it */
815 if (channel->resolve_cmd_ident) {
816 silc_client_channel_wait(client, conn, channel, packet);
820 /* Save the new mode */
821 channel->mode = mode;
824 cipher = silc_argument_get_arg_type(args, 3, &tmp_len);
827 hmac = silc_argument_get_arg_type(args, 4, &tmp_len);
829 unsigned char hash[SILC_HASH_MAXLEN];
832 silc_hmac_free(channel->hmac);
833 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac))
836 silc_hash_make(silc_hmac_get_hash(channel->hmac),
837 channel->key, channel->key_len / 8,
839 silc_hmac_set_key(channel->hmac, hash,
840 silc_hash_len(silc_hmac_get_hash(channel->hmac)));
841 memset(hash, 0, sizeof(hash));
844 /* Get the passphrase if it was set */
845 passphrase = silc_argument_get_arg_type(args, 5, &tmp_len);
847 /* Get the channel founder key if it was set */
848 tmp = silc_argument_get_arg_type(args, 6, &tmp_len);
850 if (!silc_pkcs_public_key_payload_decode(tmp, tmp_len, &founder_key))
855 tmp = silc_argument_get_arg_type(args, 8, &tmp_len);
856 if (tmp && tmp_len == 4)
857 SILC_GET32_MSB(channel->user_limit, tmp);
858 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
859 channel->user_limit = 0;
861 /* Get the channel public key that was added or removed */
862 tmp = silc_argument_get_arg_type(args, 7, &tmp_len);
864 silc_buffer_set(&chpks, tmp, tmp_len);
866 /* Notify application. The channel entry is sent last as this notify
867 is for channel but application don't know it from the arguments
869 client->internal->ops->notify(client, conn, type, id_type,
870 client_entry, mode, cipher, hmac,
871 passphrase, founder_key,
872 tmp ? &chpks : NULL, channel);
875 silc_pkcs_public_key_free(founder_key);
879 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
881 * Someone changed user's mode on a channel
884 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
886 /* Get channel entry */
887 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
891 channel = silc_client_get_channel_by_id(client, conn, channel_id);
896 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
899 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
903 /* Find Client entry */
904 if (id_type == SILC_ID_CLIENT) {
905 /* Find Client entry */
907 client_entry = silc_client_get_client_by_id(client, conn, client_id);
909 silc_client_channel_set_wait(client, conn, channel,
910 conn->cmd_ident + 1);
911 silc_client_notify_by_server_resolve(client, conn, packet,
912 SILC_ID_CLIENT, client_id);
916 if (!client_entry->nickname) {
917 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
918 /* Attach to existing resolving */
919 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
920 res->packet = silc_packet_context_dup(packet);
921 res->context = client;
922 res->sock = silc_socket_dup(conn->sock);
923 silc_client_command_pending(conn, SILC_COMMAND_NONE,
924 client_entry->resolve_cmd_ident,
925 silc_client_notify_by_server_pending,
930 /* Do new resolving */
931 silc_client_channel_set_wait(client, conn, channel,
932 conn->cmd_ident + 1);
933 silc_client_notify_by_server_resolve(client, conn, packet,
934 SILC_ID_CLIENT, client_id);
935 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
936 client_entry->resolve_cmd_ident = conn->cmd_ident;
939 } else if (id_type == SILC_ID_SERVER) {
940 /* Find Server entry */
942 server = silc_client_get_server_by_id(client, conn, server_id);
944 silc_client_channel_set_wait(client, conn, channel,
945 conn->cmd_ident + 1);
946 silc_client_notify_by_server_resolve(client, conn, packet,
947 SILC_ID_SERVER, server_id);
948 server = silc_client_add_server(client, conn, NULL, NULL, server_id);
952 server->resolve_cmd_ident = conn->cmd_ident;
957 /* If entry being resoled, wait for it before processing this notify */
958 if (server->resolve_cmd_ident) {
959 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
960 res->packet = silc_packet_context_dup(packet);
961 res->context = client;
962 res->sock = silc_socket_dup(conn->sock);
963 silc_client_command_pending(conn, SILC_COMMAND_NONE,
964 server->resolve_cmd_ident,
965 silc_client_notify_by_server_pending, res);
969 /* Save the pointer to the client_entry pointer */
970 client_entry = (SilcClientEntry)server;
972 /* Find Channel entry */
973 silc_free(channel_id);
975 client_entry = (SilcClientEntry)
976 silc_client_get_channel_by_id(client, conn, channel_id);
978 silc_client_channel_set_wait(client, conn, channel,
979 conn->cmd_ident + 1);
980 silc_client_notify_by_server_resolve(client, conn, packet,
981 SILC_ID_CHANNEL, channel_id);
987 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
991 SILC_GET32_MSB(mode, tmp);
993 /* If information is being resolved for this channel, wait for it */
994 if (channel->resolve_cmd_ident) {
995 silc_client_channel_wait(client, conn, channel, packet);
999 /* Get target Client ID */
1000 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1004 silc_free(client_id);
1005 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1009 /* Find target Client entry */
1011 silc_client_get_client_by_id(client, conn, client_id);
1012 if (!client_entry2) {
1013 silc_client_notify_by_server_resolve(client, conn, packet,
1014 SILC_ID_CLIENT, client_id);
1019 chu = silc_client_on_channel(channel, client_entry2);
1023 /* Notify application. The channel entry is sent last as this notify
1024 is for channel but application don't know it from the arguments
1026 client->internal->ops->notify(client, conn, type,
1027 id_type, client_entry, mode,
1028 client_entry2, channel);
1031 case SILC_NOTIFY_TYPE_MOTD:
1033 * Received Message of the day
1036 SILC_LOG_DEBUG(("Notify: MOTD"));
1039 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1043 /* Notify application */
1044 client->internal->ops->notify(client, conn, type, tmp);
1047 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
1049 * Router has enforced a new ID to a channel. Let's change the old
1050 * ID to the one provided here.
1053 SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
1055 /* Get the old ID */
1056 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1059 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1063 /* Get the channel entry */
1064 channel = silc_client_get_channel_by_id(client, conn, channel_id);
1068 silc_free(channel_id);
1071 /* Get the new ID */
1072 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1075 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1079 /* Replace the Channel ID */
1080 if (silc_client_replace_channel_id(client, conn, channel, channel_id))
1083 /* Notify application */
1084 client->internal->ops->notify(client, conn, type, channel, channel);
1087 case SILC_NOTIFY_TYPE_KICKED:
1089 * A client (maybe me) was kicked from a channel
1092 SILC_LOG_DEBUG(("Notify: KICKED"));
1095 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1099 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1103 /* Find Client entry */
1104 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1108 /* Get channel entry */
1109 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
1113 channel = silc_client_get_channel_by_id(client, conn, channel_id);
1117 /* From protocol version 1.1 we get the kicker's client ID as well */
1118 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1120 silc_free(client_id);
1121 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1125 /* Find kicker's client entry and if not found resolve it */
1126 client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
1127 if (!client_entry2) {
1128 silc_client_notify_by_server_resolve(client, conn, packet,
1129 SILC_ID_CLIENT, client_id);
1132 if (client_entry2 != conn->local_entry)
1133 silc_client_nickname_format(client, conn, client_entry2);
1138 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1140 /* Remove kicked client from channel */
1141 if (client_entry != conn->local_entry) {
1142 chu = silc_client_on_channel(channel, client_entry);
1144 silc_hash_table_del(client_entry->channels, channel);
1145 silc_hash_table_del(channel->user_list, client_entry);
1150 /* Notify application. The channel entry is sent last as this notify
1151 is for channel but application don't know it from the arguments
1153 client->internal->ops->notify(client, conn, type, client_entry, tmp,
1154 client_entry2, channel);
1156 /* Remove kicked client (us) from channel */
1157 if (client_entry == conn->local_entry) {
1158 /* If I was kicked from channel, remove the channel */
1159 if (conn->current_channel == channel)
1160 conn->current_channel = NULL;
1161 silc_client_del_channel(client, conn, channel);
1163 if (!silc_hash_table_count(client_entry->channels)) {
1164 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1165 res->context = client;
1166 res->sock = silc_socket_dup(conn->sock);
1167 res->packet = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1168 silc_schedule_task_add(client->schedule, conn->sock->sock,
1169 silc_client_notify_check_client, res,
1170 (5 + (silc_rng_get_rn16(client->rng) % 529)),
1171 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1176 case SILC_NOTIFY_TYPE_KILLED:
1179 * A client (maybe me) was killed from the network.
1182 SilcUInt32 comment_len;
1184 SILC_LOG_DEBUG(("Notify: KILLED"));
1187 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1191 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1195 /* Find Client entry */
1196 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1201 comment = silc_argument_get_arg_type(args, 2, &comment_len);
1203 /* From protocol version 1.1 we get killer's client ID as well */
1204 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1206 silc_free(client_id);
1208 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
1212 /* Find Client entry */
1213 if (id_type == SILC_ID_CLIENT) {
1214 /* Find Client entry */
1216 client_entry2 = silc_client_get_client_by_id(client, conn,
1218 if (!client_entry) {
1219 silc_client_notify_by_server_resolve(client, conn, packet,
1220 SILC_ID_CLIENT, client_id);
1223 } else if (id_type == SILC_ID_SERVER) {
1224 /* Find Server entry */
1226 server = silc_client_get_server_by_id(client, conn, server_id);
1228 silc_client_notify_by_server_resolve(client, conn, packet,
1229 SILC_ID_SERVER, server_id);
1230 server = silc_client_add_server(client, conn, NULL, NULL,
1235 server->resolve_cmd_ident = conn->cmd_ident;
1240 if (server->resolve_cmd_ident) {
1241 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1242 res->packet = silc_packet_context_dup(packet);
1243 res->context = client;
1244 res->sock = silc_socket_dup(conn->sock);
1245 silc_client_command_pending(conn, SILC_COMMAND_NONE,
1246 server->resolve_cmd_ident,
1247 silc_client_notify_by_server_pending,
1252 /* Save the pointer to the client_entry pointer */
1253 client_entry2 = (SilcClientEntry)server;
1255 /* Find Channel entry */
1257 channel = silc_client_get_channel_by_id(client, conn, channel_id);
1259 silc_client_notify_by_server_resolve(client, conn, packet,
1260 SILC_ID_CHANNEL, channel_id);
1264 /* Save the pointer to the client_entry pointer */
1265 client_entry2 = (SilcClientEntry)channel;
1266 silc_free(channel_id);
1271 /* Notify application. */
1272 client->internal->ops->notify(client, conn, type, client_entry,
1273 comment, id_type, client_entry2);
1275 if (client_entry != conn->local_entry)
1276 /* Remove the client from all channels and free it */
1277 silc_client_del_client(client, conn, client_entry);
1281 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
1284 * A server quit the SILC network and some clients must be removed
1285 * from channels as they quit as well.
1287 SilcClientEntry *clients = NULL;
1288 SilcUInt32 clients_count = 0;
1291 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
1293 for (i = 1; i < silc_argument_get_arg_num(args); i++) {
1295 tmp = silc_argument_get_arg_type(args, i + 1, &tmp_len);
1297 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1301 /* Get the client entry */
1302 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1304 clients = silc_realloc(clients, sizeof(*clients) *
1305 (clients_count + 1));
1306 clients[clients_count] = client_entry;
1309 silc_free(client_id);
1314 /* Notify application. We don't keep server entries so the server
1315 entry is returned as NULL. The client's are returned as array
1316 of SilcClientEntry pointers. */
1317 client->internal->ops->notify(client, conn, type, NULL,
1318 clients, clients_count);
1320 for (i = 0; i < clients_count; i++) {
1321 /* Remove client from all channels */
1322 client_entry = clients[i];
1323 if (client_entry == conn->local_entry)
1326 /* Remove the client from all channels and free it */
1327 silc_client_del_client(client, conn, client_entry);
1334 case SILC_NOTIFY_TYPE_ERROR:
1337 * Some has occurred and server is notifying us about it.
1341 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1342 if (!tmp && tmp_len != 1)
1344 error = (SilcStatus)tmp[0];
1346 SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1348 if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1349 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1351 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1354 client_entry = silc_client_get_client_by_id(client, conn,
1357 silc_client_del_client(client, conn, client_entry);
1361 /* Notify application. */
1362 client->internal->ops->notify(client, conn, type, error);
1366 case SILC_NOTIFY_TYPE_WATCH:
1369 * Received notify about some client we are watching
1371 SilcNotifyType notify = 0;
1372 SilcBool del_client = FALSE;
1375 SilcPublicKey public_key = NULL;
1377 SILC_LOG_DEBUG(("Notify: WATCH"));
1379 /* Get sender Client ID */
1380 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1383 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1387 /* Find Client entry and if not found query it */
1388 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1389 if (!client_entry) {
1390 silc_client_notify_by_server_resolve(client, conn, packet,
1391 SILC_ID_CLIENT, client_id);
1396 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1397 if (!tmp || tmp_len != 4)
1399 SILC_GET32_MSB(mode, tmp);
1401 /* Get notify type */
1402 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1403 if (tmp && tmp_len != 2)
1406 SILC_GET16_MSB(notify, tmp);
1409 tmp = silc_argument_get_arg_type(args, 2, NULL);
1411 char *tmp_nick = NULL;
1413 if (client->internal->params->nickname_parse)
1414 client->internal->params->nickname_parse(client_entry->nickname,
1417 tmp_nick = strdup(tmp);
1419 /* If same nick, the client was new to us and has become "present"
1420 to network. Send NULL as nick to application. */
1421 if (tmp_nick && silc_utf8_strcasecmp(tmp, tmp_nick))
1424 silc_free(tmp_nick);
1427 /* Get public key, if present */
1428 pk = silc_argument_get_arg_type(args, 5, &pk_len);
1429 if (pk && !client_entry->public_key) {
1430 if (silc_pkcs_public_key_payload_decode(pk, pk_len, &public_key)) {
1431 client_entry->public_key = public_key;
1436 /* Notify application. */
1437 client->internal->ops->notify(client, conn, type, client_entry,
1439 client_entry->public_key);
1441 client_entry->mode = mode;
1443 /* If nickname was changed, remove the client entry unless the
1444 client is on some channel */
1445 if (tmp && notify == SILC_NOTIFY_TYPE_NICK_CHANGE &&
1446 !silc_hash_table_count(client_entry->channels))
1448 else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1449 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
1450 notify == SILC_NOTIFY_TYPE_KILLED)
1454 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1455 res->context = client;
1456 res->sock = silc_socket_dup(conn->sock);
1457 res->packet = client_id;
1459 silc_schedule_task_add(client->schedule, conn->sock->sock,
1460 silc_client_notify_del_client_cb, res,
1461 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1464 silc_pkcs_public_key_free(public_key);
1473 silc_notify_payload_free(payload);
1474 silc_free(client_id);
1475 silc_free(channel_id);
1476 silc_free(server_id);