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 /* 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);
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 /* Remove kicked client from channel */
1122 if (client_entry != conn->local_entry) {
1123 chu = silc_client_on_channel(channel, client_entry);
1125 silc_hash_table_del(client_entry->channels, channel);
1126 silc_hash_table_del(channel->user_list, client_entry);
1131 /* Notify application. The channel entry is sent last as this notify
1132 is for channel but application don't know it from the arguments
1134 client->internal->ops->notify(client, conn, type, client_entry, tmp,
1135 client_entry2, channel);
1137 /* Remove kicked client (us) from channel */
1138 if (client_entry == conn->local_entry) {
1139 /* If I was kicked from channel, remove the channel */
1140 if (conn->current_channel == channel)
1141 conn->current_channel = NULL;
1142 silc_client_del_channel(client, conn, channel);
1144 if (!silc_hash_table_count(client_entry->channels)) {
1145 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1146 res->context = client;
1147 res->sock = silc_socket_dup(conn->sock);
1148 res->packet = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1149 silc_schedule_task_add(client->schedule, conn->sock->sock,
1150 silc_client_notify_check_client, res,
1151 (5 + (silc_rng_get_rn16(client->rng) % 529)),
1152 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1157 case SILC_NOTIFY_TYPE_KILLED:
1160 * A client (maybe me) was killed from the network.
1163 SilcUInt32 comment_len;
1165 SILC_LOG_DEBUG(("Notify: KILLED"));
1168 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1172 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1176 /* Find Client entry */
1177 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1182 comment = silc_argument_get_arg_type(args, 2, &comment_len);
1184 /* From protocol version 1.1 we get killer's client ID as well */
1185 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1187 silc_free(client_id);
1189 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
1193 /* Find Client entry */
1194 if (id_type == SILC_ID_CLIENT) {
1195 /* Find Client entry */
1197 client_entry2 = silc_client_get_client_by_id(client, conn,
1199 if (!client_entry) {
1200 silc_client_notify_by_server_resolve(client, conn, packet,
1201 SILC_ID_CLIENT, client_id);
1204 } else if (id_type == SILC_ID_SERVER) {
1205 /* Find Server entry */
1207 server = silc_client_get_server_by_id(client, conn, server_id);
1209 silc_client_notify_by_server_resolve(client, conn, packet,
1210 SILC_ID_SERVER, server_id);
1211 server = silc_client_add_server(client, conn, NULL, NULL,
1216 server->resolve_cmd_ident = conn->cmd_ident;
1221 if (server->resolve_cmd_ident) {
1222 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1223 res->packet = silc_packet_context_dup(packet);
1224 res->context = client;
1225 res->sock = silc_socket_dup(conn->sock);
1226 silc_client_command_pending(conn, SILC_COMMAND_NONE,
1227 server->resolve_cmd_ident,
1228 silc_client_notify_by_server_pending,
1233 /* Save the pointer to the client_entry pointer */
1234 client_entry2 = (SilcClientEntry)server;
1236 /* Find Channel entry */
1238 channel = silc_client_get_channel_by_id(client, conn, channel_id);
1240 silc_client_notify_by_server_resolve(client, conn, packet,
1241 SILC_ID_CHANNEL, channel_id);
1245 /* Save the pointer to the client_entry pointer */
1246 client_entry2 = (SilcClientEntry)channel;
1247 silc_free(channel_id);
1252 /* Notify application. */
1253 client->internal->ops->notify(client, conn, type, client_entry,
1254 comment, id_type, client_entry2);
1256 if (client_entry != conn->local_entry)
1257 /* Remove the client from all channels and free it */
1258 silc_client_del_client(client, conn, client_entry);
1262 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
1265 * A server quit the SILC network and some clients must be removed
1266 * from channels as they quit as well.
1268 SilcClientEntry *clients = NULL;
1269 SilcUInt32 clients_count = 0;
1272 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
1274 for (i = 1; i < silc_argument_get_arg_num(args); i++) {
1276 tmp = silc_argument_get_arg_type(args, i + 1, &tmp_len);
1278 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1282 /* Get the client entry */
1283 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1285 clients = silc_realloc(clients, sizeof(*clients) *
1286 (clients_count + 1));
1287 clients[clients_count] = client_entry;
1290 silc_free(client_id);
1295 /* Notify application. We don't keep server entries so the server
1296 entry is returned as NULL. The client's are returned as array
1297 of SilcClientEntry pointers. */
1298 client->internal->ops->notify(client, conn, type, NULL,
1299 clients, clients_count);
1301 for (i = 0; i < clients_count; i++) {
1302 /* Remove client from all channels */
1303 client_entry = clients[i];
1304 if (client_entry == conn->local_entry)
1307 /* Remove the client from all channels and free it */
1308 silc_client_del_client(client, conn, client_entry);
1315 case SILC_NOTIFY_TYPE_ERROR:
1318 * Some has occurred and server is notifying us about it.
1322 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1323 if (!tmp && tmp_len != 1)
1325 error = (SilcStatus)tmp[0];
1327 SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1329 if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1330 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1332 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1335 client_entry = silc_client_get_client_by_id(client, conn,
1338 silc_client_del_client(client, conn, client_entry);
1342 /* Notify application. */
1343 client->internal->ops->notify(client, conn, type, error);
1347 case SILC_NOTIFY_TYPE_WATCH:
1350 * Received notify about some client we are watching
1352 SilcNotifyType notify = 0;
1353 bool del_client = FALSE;
1355 SILC_LOG_DEBUG(("Notify: WATCH"));
1357 /* Get sender Client ID */
1358 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1361 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1365 /* Find Client entry and if not found query it */
1366 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1367 if (!client_entry) {
1368 silc_client_notify_by_server_resolve(client, conn, packet,
1369 SILC_ID_CLIENT, client_id);
1374 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1375 if (!tmp || tmp_len != 4)
1377 SILC_GET32_MSB(mode, tmp);
1379 /* Get notify type */
1380 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1381 if (tmp && tmp_len != 2)
1384 SILC_GET16_MSB(notify, tmp);
1387 tmp = silc_argument_get_arg_type(args, 2, NULL);
1389 char *tmp_nick = NULL;
1391 if (client->internal->params->nickname_parse)
1392 client->internal->params->nickname_parse(client_entry->nickname,
1395 tmp_nick = strdup(tmp);
1397 /* If same nick, the client was new to us and has become "present"
1398 to network. Send NULL as nick to application. */
1399 if (tmp_nick && !strcmp(tmp, tmp_nick))
1402 silc_free(tmp_nick);
1405 /* Notify application. */
1406 client->internal->ops->notify(client, conn, type, client_entry,
1409 client_entry->mode = mode;
1411 /* If nickname was changed, remove the client entry unless the
1412 client is on some channel */
1413 if (tmp && notify == SILC_NOTIFY_TYPE_NICK_CHANGE &&
1414 !silc_hash_table_count(client_entry->channels))
1416 else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1417 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
1418 notify == SILC_NOTIFY_TYPE_KILLED)
1422 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1423 res->context = client;
1424 res->sock = silc_socket_dup(conn->sock);
1425 res->packet = client_id;
1427 silc_schedule_task_add(client->schedule, conn->sock->sock,
1428 silc_client_notify_del_client_cb, res,
1429 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1439 silc_notify_payload_free(payload);
1440 silc_free(client_id);
1441 silc_free(channel_id);
1442 silc_free(server_id);