5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2003 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. */
24 #include "silcincludes.h"
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 /* Remove from all channels */
448 silc_client_remove_from_channels(client, conn, client_entry);
450 /* Remove from cache */
451 silc_idcache_del_by_context(conn->internal->client_cache, client_entry);
453 /* Get signoff message */
454 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
458 /* Notify application */
459 client->internal->ops->notify(client, conn, type, client_entry, tmp);
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);
559 /* Notify application. The channel entry is sent last as this notify
560 is for channel but application don't know it from the arguments
562 client->internal->ops->notify(client, conn, type, id_type,
563 client_entry, tmp, channel);
567 case SILC_NOTIFY_TYPE_NICK_CHANGE:
569 * Someone changed their nickname. If we don't have entry for the new
570 * ID we will query it and return here after it's done. After we've
571 * returned we fetch the old entry and free it and notify the
575 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
577 /* Get old Client ID */
578 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
582 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
587 if (conn->local_id && SILC_ID_CLIENT_COMPARE(client_id, conn->local_id))
590 /* Find old Client entry */
591 client_entry = silc_client_get_client_by_id(client, conn, client_id);
594 silc_free(client_id);
597 /* Wait for resolving if necessary */
598 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
599 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
600 res->packet = silc_packet_context_dup(packet);
601 res->context = client;
602 res->sock = silc_socket_dup(conn->sock);
603 silc_client_command_pending(conn, SILC_COMMAND_NONE,
604 client_entry->resolve_cmd_ident,
605 silc_client_notify_by_server_pending, res);
609 client_entry->valid = FALSE;
611 /* Get new Client ID */
612 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
616 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
620 /* Take the nickname */
621 tmp = silc_argument_get_arg_type(args, 3, NULL);
625 /* Check whether nickname changed at all. It is possible that nick
626 change notify is received but nickname didn't change, only the
627 ID changes. Check whether the hashes in the Client ID match, if
628 they do nickname didn't change. */
629 if (SILC_ID_COMPARE_HASH(client_entry->id, client_id) &&
630 !strcmp(tmp, client_entry->nickname)) {
631 /* Nickname didn't change. Update only Client ID. */
632 silc_idcache_del_by_context(conn->internal->client_cache,
634 silc_free(client_entry->id);
635 client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
636 silc_idcache_add(conn->internal->client_cache, strdup(tmp),
637 client_entry->id, client_entry, 0, NULL);
639 /* Notify application */
640 client->internal->ops->notify(client, conn, type,
641 client_entry, client_entry);
645 /* Create new client entry, and save all old information with the
646 new nickname and client ID */
647 client_entry2 = silc_client_add_client(client, conn, NULL, NULL,
648 client_entry->realname,
649 silc_id_dup(client_id,
654 if (client_entry->server)
655 client_entry2->server = strdup(client_entry->server);
656 if (client_entry->username)
657 client_entry2->username = strdup(client_entry->username);
658 if (client_entry->hostname)
659 client_entry2->hostname = strdup(client_entry->hostname);
660 client_entry2->fingerprint = client_entry->fingerprint;
661 client_entry2->fingerprint_len = client_entry->fingerprint_len;
662 client_entry->fingerprint = NULL;
663 client_entry->fingerprint_len = 0;
664 silc_client_update_client(client, conn, client_entry2, tmp, NULL, NULL,
667 /* Remove the old from cache */
668 silc_idcache_del_by_context(conn->internal->client_cache, client_entry);
670 /* Replace old ID entry with new one on all channels. */
671 silc_client_replace_from_channels(client, conn, client_entry,
674 /* Notify application */
675 client->internal->ops->notify(client, conn, type,
676 client_entry, client_entry2);
678 /* Free old client entry */
679 silc_client_del_client_entry(client, conn, client_entry);
683 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
686 * Someone changed a channel mode
688 char *passphrase, *cipher, *hmac;
689 SilcPublicKey founder_key = NULL;
690 SilcBufferStruct chpks;
692 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
694 /* Get channel entry */
695 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
699 channel = silc_client_get_channel_by_id(client, conn, channel_id);
704 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
707 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
711 /* Find Client entry */
712 if (id_type == SILC_ID_CLIENT) {
713 /* Find Client entry */
715 client_entry = silc_client_get_client_by_id(client, conn, client_id);
717 silc_client_channel_set_wait(client, conn, channel,
718 conn->cmd_ident + 1);
719 silc_client_notify_by_server_resolve(client, conn, packet,
720 SILC_ID_CLIENT, client_id);
724 if (!client_entry->nickname) {
725 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
726 /* Attach to existing resolving */
727 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
728 res->packet = silc_packet_context_dup(packet);
729 res->context = client;
730 res->sock = silc_socket_dup(conn->sock);
731 silc_client_command_pending(conn, SILC_COMMAND_NONE,
732 client_entry->resolve_cmd_ident,
733 silc_client_notify_by_server_pending,
738 /* Do new resolving */
739 silc_client_channel_set_wait(client, conn, channel,
740 conn->cmd_ident + 1);
741 silc_client_notify_by_server_resolve(client, conn, packet,
742 SILC_ID_CLIENT, client_id);
743 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
744 client_entry->resolve_cmd_ident = conn->cmd_ident;
747 } else if (id_type == SILC_ID_SERVER) {
748 /* Find Server entry */
750 server = silc_client_get_server_by_id(client, conn, server_id);
752 silc_client_channel_set_wait(client, conn, channel,
753 conn->cmd_ident + 1);
754 silc_client_notify_by_server_resolve(client, conn, packet,
755 SILC_ID_SERVER, server_id);
756 server = silc_client_add_server(client, conn, NULL, NULL, server_id);
760 server->resolve_cmd_ident = conn->cmd_ident;
765 /* If entry being resoled, wait for it before processing this notify */
766 if (server->resolve_cmd_ident) {
767 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
768 res->packet = silc_packet_context_dup(packet);
769 res->context = client;
770 res->sock = silc_socket_dup(conn->sock);
771 silc_client_command_pending(conn, SILC_COMMAND_NONE,
772 server->resolve_cmd_ident,
773 silc_client_notify_by_server_pending,
778 /* Save the pointer to the client_entry pointer */
779 client_entry = (SilcClientEntry)server;
781 /* Find Channel entry */
782 silc_free(channel_id);
784 client_entry = (SilcClientEntry)
785 silc_client_get_channel_by_id(client, conn, channel_id);
787 silc_client_channel_set_wait(client, conn, channel,
788 conn->cmd_ident + 1);
789 silc_client_notify_by_server_resolve(client, conn, packet,
790 SILC_ID_CHANNEL, channel_id);
796 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
800 SILC_GET32_MSB(mode, tmp);
802 /* If information is being resolved for this channel, wait for it */
803 if (channel->resolve_cmd_ident) {
804 silc_client_channel_wait(client, conn, channel, packet);
808 /* Save the new mode */
809 channel->mode = mode;
812 cipher = silc_argument_get_arg_type(args, 3, &tmp_len);
815 hmac = silc_argument_get_arg_type(args, 4, &tmp_len);
817 unsigned char hash[32];
820 silc_hmac_free(channel->hmac);
821 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac))
824 silc_hash_make(silc_hmac_get_hash(channel->hmac),
825 channel->key, channel->key_len / 8,
827 silc_hmac_set_key(channel->hmac, hash,
828 silc_hash_len(silc_hmac_get_hash(channel->hmac)));
829 memset(hash, 0, sizeof(hash));
832 /* Get the passphrase if it was set */
833 passphrase = silc_argument_get_arg_type(args, 5, &tmp_len);
835 /* Get the channel founder key if it was set */
836 tmp = silc_argument_get_arg_type(args, 6, &tmp_len);
838 if (!silc_pkcs_public_key_payload_decode(tmp, tmp_len, &founder_key))
842 /* Get the channel public key that was added or removed */
843 tmp = silc_argument_get_arg_type(args, 7, &tmp_len);
845 silc_buffer_set(&chpks, tmp, tmp_len);
847 /* Notify application. The channel entry is sent last as this notify
848 is for channel but application don't know it from the arguments
850 client->internal->ops->notify(client, conn, type, id_type,
851 client_entry, mode, cipher, hmac,
852 passphrase, founder_key,
853 tmp ? &chpks : NULL, channel);
856 silc_pkcs_public_key_free(founder_key);
860 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
862 * Someone changed user's mode on a channel
865 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
867 /* Get channel entry */
868 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
872 channel = silc_client_get_channel_by_id(client, conn, channel_id);
877 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
880 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
884 /* Find Client entry */
885 if (id_type == SILC_ID_CLIENT) {
886 /* Find Client entry */
888 client_entry = silc_client_get_client_by_id(client, conn, client_id);
890 silc_client_channel_set_wait(client, conn, channel,
891 conn->cmd_ident + 1);
892 silc_client_notify_by_server_resolve(client, conn, packet,
893 SILC_ID_CLIENT, client_id);
897 if (!client_entry->nickname) {
898 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
899 /* Attach to existing resolving */
900 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
901 res->packet = silc_packet_context_dup(packet);
902 res->context = client;
903 res->sock = silc_socket_dup(conn->sock);
904 silc_client_command_pending(conn, SILC_COMMAND_NONE,
905 client_entry->resolve_cmd_ident,
906 silc_client_notify_by_server_pending,
911 /* Do new resolving */
912 silc_client_channel_set_wait(client, conn, channel,
913 conn->cmd_ident + 1);
914 silc_client_notify_by_server_resolve(client, conn, packet,
915 SILC_ID_CLIENT, client_id);
916 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
917 client_entry->resolve_cmd_ident = conn->cmd_ident;
920 } else if (id_type == SILC_ID_SERVER) {
921 /* Find Server entry */
923 server = silc_client_get_server_by_id(client, conn, server_id);
925 silc_client_channel_set_wait(client, conn, channel,
926 conn->cmd_ident + 1);
927 silc_client_notify_by_server_resolve(client, conn, packet,
928 SILC_ID_SERVER, server_id);
929 server = silc_client_add_server(client, conn, NULL, NULL, server_id);
933 server->resolve_cmd_ident = conn->cmd_ident;
938 /* If entry being resoled, wait for it before processing this notify */
939 if (server->resolve_cmd_ident) {
940 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
941 res->packet = silc_packet_context_dup(packet);
942 res->context = client;
943 res->sock = silc_socket_dup(conn->sock);
944 silc_client_command_pending(conn, SILC_COMMAND_NONE,
945 server->resolve_cmd_ident,
946 silc_client_notify_by_server_pending, res);
950 /* Save the pointer to the client_entry pointer */
951 client_entry = (SilcClientEntry)server;
953 /* Find Channel entry */
954 silc_free(channel_id);
956 client_entry = (SilcClientEntry)
957 silc_client_get_channel_by_id(client, conn, channel_id);
959 silc_client_channel_set_wait(client, conn, channel,
960 conn->cmd_ident + 1);
961 silc_client_notify_by_server_resolve(client, conn, packet,
962 SILC_ID_CHANNEL, channel_id);
968 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
972 SILC_GET32_MSB(mode, tmp);
974 /* If information is being resolved for this channel, wait for it */
975 if (channel->resolve_cmd_ident) {
976 silc_client_channel_wait(client, conn, channel, packet);
980 /* Get target Client ID */
981 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
985 silc_free(client_id);
986 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
990 /* Find target Client entry */
992 silc_client_get_client_by_id(client, conn, client_id);
993 if (!client_entry2) {
994 silc_client_notify_by_server_resolve(client, conn, packet,
995 SILC_ID_CLIENT, client_id);
1000 chu = silc_client_on_channel(channel, client_entry2);
1004 /* Notify application. The channel entry is sent last as this notify
1005 is for channel but application don't know it from the arguments
1007 client->internal->ops->notify(client, conn, type,
1008 id_type, client_entry, mode,
1009 client_entry2, channel);
1012 case SILC_NOTIFY_TYPE_MOTD:
1014 * Received Message of the day
1017 SILC_LOG_DEBUG(("Notify: MOTD"));
1020 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1024 /* Notify application */
1025 client->internal->ops->notify(client, conn, type, tmp);
1028 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
1030 * Router has enforced a new ID to a channel. Let's change the old
1031 * ID to the one provided here.
1034 SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
1036 /* Get the old ID */
1037 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1040 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1044 /* Get the channel entry */
1045 channel = silc_client_get_channel_by_id(client, conn, channel_id);
1049 silc_free(channel_id);
1052 /* Get the new ID */
1053 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1056 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1060 /* Replace the Channel ID */
1061 if (silc_client_replace_channel_id(client, conn, channel, channel_id))
1064 /* Notify application */
1065 client->internal->ops->notify(client, conn, type, channel, channel);
1068 case SILC_NOTIFY_TYPE_KICKED:
1070 * A client (maybe me) was kicked from a channel
1073 SILC_LOG_DEBUG(("Notify: KICKED"));
1076 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1080 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1084 /* Find Client entry */
1085 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1089 /* Get channel entry */
1090 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
1094 channel = silc_client_get_channel_by_id(client, conn, channel_id);
1098 /* From protocol version 1.1 we get the kicker's client ID as well */
1099 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1101 silc_free(client_id);
1102 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1106 /* Find kicker's client entry and if not found resolve it */
1107 client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
1108 if (!client_entry2) {
1109 silc_client_notify_by_server_resolve(client, conn, packet,
1110 SILC_ID_CLIENT, client_id);
1113 if (client_entry2 != conn->local_entry)
1114 silc_client_nickname_format(client, conn, client_entry2);
1119 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1121 /* Notify application. The channel entry is sent last as this notify
1122 is for channel but application don't know it from the arguments
1124 client->internal->ops->notify(client, conn, type, client_entry, tmp,
1125 client_entry2, channel);
1127 /* Remove kicked client from channel */
1128 if (client_entry == conn->local_entry) {
1129 /* If I was kicked from channel, remove the channel */
1130 if (conn->current_channel == channel)
1131 conn->current_channel = NULL;
1132 silc_client_del_channel(client, conn, channel);
1134 chu = silc_client_on_channel(channel, client_entry);
1136 silc_hash_table_del(client_entry->channels, channel);
1137 silc_hash_table_del(channel->user_list, client_entry);
1141 if (!silc_hash_table_count(client_entry->channels)) {
1142 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1143 res->context = client;
1144 res->sock = silc_socket_dup(conn->sock);
1145 res->packet = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1146 silc_schedule_task_add(client->schedule, conn->sock->sock,
1147 silc_client_notify_check_client, res,
1148 (5 + (silc_rng_get_rn16(client->rng) % 529)),
1149 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1154 case SILC_NOTIFY_TYPE_KILLED:
1157 * A client (maybe me) was killed from the network.
1160 SilcUInt32 comment_len;
1162 SILC_LOG_DEBUG(("Notify: KILLED"));
1165 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1169 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1173 /* Find Client entry */
1174 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1179 comment = silc_argument_get_arg_type(args, 2, &comment_len);
1181 /* From protocol version 1.1 we get killer's client ID as well */
1182 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1184 silc_free(client_id);
1186 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
1190 /* Find Client entry */
1191 if (id_type == SILC_ID_CLIENT) {
1192 /* Find Client entry */
1194 client_entry2 = silc_client_get_client_by_id(client, conn,
1196 if (!client_entry) {
1197 silc_client_notify_by_server_resolve(client, conn, packet,
1198 SILC_ID_CLIENT, client_id);
1201 } else if (id_type == SILC_ID_SERVER) {
1202 /* Find Server entry */
1204 server = silc_client_get_server_by_id(client, conn, server_id);
1206 silc_client_notify_by_server_resolve(client, conn, packet,
1207 SILC_ID_SERVER, server_id);
1208 server = silc_client_add_server(client, conn, NULL, NULL,
1213 server->resolve_cmd_ident = conn->cmd_ident;
1218 if (server->resolve_cmd_ident) {
1219 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1220 res->packet = silc_packet_context_dup(packet);
1221 res->context = client;
1222 res->sock = silc_socket_dup(conn->sock);
1223 silc_client_command_pending(conn, SILC_COMMAND_NONE,
1224 server->resolve_cmd_ident,
1225 silc_client_notify_by_server_pending,
1230 /* Save the pointer to the client_entry pointer */
1231 client_entry2 = (SilcClientEntry)server;
1233 /* Find Channel entry */
1235 channel = silc_client_get_channel_by_id(client, conn, channel_id);
1237 silc_client_notify_by_server_resolve(client, conn, packet,
1238 SILC_ID_CHANNEL, channel_id);
1242 /* Save the pointer to the client_entry pointer */
1243 client_entry2 = (SilcClientEntry)channel;
1244 silc_free(channel_id);
1249 /* Notify application. */
1250 client->internal->ops->notify(client, conn, type, client_entry,
1251 comment, id_type, client_entry2);
1253 if (client_entry != conn->local_entry)
1254 /* Remove the client from all channels and free it */
1255 silc_client_del_client(client, conn, client_entry);
1259 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
1262 * A server quit the SILC network and some clients must be removed
1263 * from channels as they quit as well.
1265 SilcClientEntry *clients = NULL;
1266 SilcUInt32 clients_count = 0;
1269 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
1271 for (i = 1; i < silc_argument_get_arg_num(args); i++) {
1273 tmp = silc_argument_get_arg_type(args, i + 1, &tmp_len);
1275 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1279 /* Get the client entry */
1280 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1282 clients = silc_realloc(clients, sizeof(*clients) *
1283 (clients_count + 1));
1284 clients[clients_count] = client_entry;
1287 silc_free(client_id);
1292 /* Notify application. We don't keep server entries so the server
1293 entry is returned as NULL. The client's are returned as array
1294 of SilcClientEntry pointers. */
1295 client->internal->ops->notify(client, conn, type, NULL,
1296 clients, clients_count);
1298 for (i = 0; i < clients_count; i++) {
1299 /* Remove client from all channels */
1300 client_entry = clients[i];
1301 if (client_entry == conn->local_entry)
1304 /* Remove the client from all channels and free it */
1305 silc_client_del_client(client, conn, client_entry);
1312 case SILC_NOTIFY_TYPE_ERROR:
1315 * Some has occurred and server is notifying us about it.
1319 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1320 if (!tmp && tmp_len != 1)
1322 error = (SilcStatus)tmp[0];
1324 SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1326 if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1327 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1329 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1332 client_entry = silc_client_get_client_by_id(client, conn,
1335 silc_client_del_client(client, conn, client_entry);
1339 /* Notify application. */
1340 client->internal->ops->notify(client, conn, type, error);
1344 case SILC_NOTIFY_TYPE_WATCH:
1347 * Received notify about some client we are watching
1349 SilcNotifyType notify = 0;
1350 bool del_client = FALSE;
1352 SILC_LOG_DEBUG(("Notify: WATCH"));
1354 /* Get sender Client ID */
1355 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1358 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1362 /* Find Client entry and if not found query it */
1363 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1364 if (!client_entry) {
1365 silc_client_notify_by_server_resolve(client, conn, packet,
1366 SILC_ID_CLIENT, client_id);
1371 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1372 if (!tmp || tmp_len != 4)
1374 SILC_GET32_MSB(mode, tmp);
1376 /* Get notify type */
1377 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1378 if (tmp && tmp_len != 2)
1381 SILC_GET16_MSB(notify, tmp);
1384 tmp = silc_argument_get_arg_type(args, 2, NULL);
1386 char *tmp_nick = NULL;
1388 if (client->internal->params->nickname_parse)
1389 client->internal->params->nickname_parse(client_entry->nickname,
1392 tmp_nick = strdup(tmp);
1394 /* If same nick, the client was new to us and has become "present"
1395 to network. Send NULL as nick to application. */
1396 if (tmp_nick && !strcmp(tmp, tmp_nick))
1399 silc_free(tmp_nick);
1402 /* Notify application. */
1403 client->internal->ops->notify(client, conn, type, client_entry,
1406 client_entry->mode = mode;
1408 /* If nickname was changed, remove the client entry unless the
1409 client is on some channel */
1410 if (tmp && notify == SILC_NOTIFY_TYPE_NICK_CHANGE &&
1411 !silc_hash_table_count(client_entry->channels))
1413 else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1414 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
1415 notify == SILC_NOTIFY_TYPE_KILLED)
1419 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1420 res->context = client;
1421 res->sock = silc_socket_dup(conn->sock);
1422 res->packet = client_id;
1424 silc_schedule_task_add(client->schedule, conn->sock->sock,
1425 silc_client_notify_del_client_cb, res,
1426 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1436 silc_notify_payload_free(payload);
1437 silc_free(client_id);
1438 silc_free(channel_id);
1439 silc_free(server_id);