5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2002 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, 1, &tmp_len);
287 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
291 /* Find Client entry and if not found query it */
292 client_entry = silc_client_get_client_by_id(client, conn, client_id);
294 silc_client_notify_by_server_resolve(client, conn, packet,
295 SILC_ID_CLIENT, client_id);
299 /* If nickname or username hasn't been resolved, do so */
300 if (!client_entry->nickname || !client_entry->username) {
301 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
302 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
305 silc_client_notify_by_server_resolve(client, conn, packet,
306 SILC_ID_CLIENT, client_id);
307 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
308 client_entry->resolve_cmd_ident = conn->cmd_ident;
311 if (client_entry != conn->local_entry)
312 silc_client_nickname_format(client, conn, client_entry);
316 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
320 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
324 /* Get channel entry */
325 channel = silc_client_get_channel_by_id(client, conn, channel_id);
329 /* Join the client to channel */
330 if (!silc_client_on_channel(channel, client_entry)) {
331 chu = silc_calloc(1, sizeof(*chu));
332 chu->client = client_entry;
333 chu->channel = channel;
334 silc_hash_table_add(channel->user_list, client_entry, chu);
335 silc_hash_table_add(client_entry->channels, channel, chu);
338 /* Notify application. The channel entry is sent last as this notify
339 is for channel but application don't know it from the arguments
341 client->internal->ops->notify(client, conn, type, client_entry, channel);
344 case SILC_NOTIFY_TYPE_LEAVE:
346 * Someone has left a channel. We will remove it from the channel but
347 * we'll keep it in the cache in case we'll need it later.
350 SILC_LOG_DEBUG(("Notify: LEAVE"));
353 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
357 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
361 /* Find Client entry */
363 silc_client_get_client_by_id(client, conn, client_id);
367 /* Get channel entry */
368 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
372 channel = silc_client_get_channel_by_id(client, conn, channel_id);
376 /* Remove client from channel */
377 chu = silc_client_on_channel(channel, client_entry);
379 silc_hash_table_del(client_entry->channels, channel);
380 silc_hash_table_del(channel->user_list, client_entry);
384 /* Some client implementations actually quit network by first doing
385 LEAVE and then immediately SIGNOFF. We'll check for this by doing
386 check for the client after 5 - 34 seconds. If it is not valid after
387 that we'll remove the client from cache. */
388 if (!silc_hash_table_count(client_entry->channels)) {
389 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
390 res->context = client;
391 res->sock = silc_socket_dup(conn->sock);
392 res->packet = silc_id_dup(client_id, SILC_ID_CLIENT);
393 silc_schedule_task_add(client->schedule, conn->sock->sock,
394 silc_client_notify_check_client, res,
395 (5 + (silc_rng_get_rn16(client->rng) % 29)),
396 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
399 /* Notify application. The channel entry is sent last as this notify
400 is for channel but application don't know it from the arguments
402 client->internal->ops->notify(client, conn, type, client_entry, channel);
405 case SILC_NOTIFY_TYPE_SIGNOFF:
407 * Someone left SILC. We'll remove it from all channels and from cache.
410 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
413 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
417 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
421 /* Find Client entry */
423 silc_client_get_client_by_id(client, conn, client_id);
427 /* Remove from all channels */
428 silc_client_remove_from_channels(client, conn, client_entry);
430 /* Remove from cache */
431 silc_idcache_del_by_context(conn->internal->client_cache, client_entry);
433 /* Get signoff message */
434 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
438 /* Notify application */
439 client->internal->ops->notify(client, conn, type, client_entry, tmp);
442 silc_client_del_client_entry(client, conn, client_entry);
445 case SILC_NOTIFY_TYPE_TOPIC_SET:
447 * Someone set the topic on a channel.
450 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
452 /* Get channel entry */
453 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
457 channel = silc_client_get_channel_by_id(client, conn, channel_id);
462 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
465 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
469 /* Find Client entry */
470 if (id_type == SILC_ID_CLIENT) {
471 /* Find Client entry */
473 client_entry = silc_client_get_client_by_id(client, conn, client_id);
475 silc_client_channel_set_wait(client, conn, channel,
476 conn->cmd_ident + 1);
477 silc_client_notify_by_server_resolve(client, conn, packet,
478 SILC_ID_CLIENT, client_id);
481 } else if (id_type == SILC_ID_SERVER) {
482 /* Find Server entry */
484 server = silc_client_get_server_by_id(client, conn, server_id);
486 silc_client_channel_set_wait(client, conn, channel,
487 conn->cmd_ident + 1);
488 silc_client_notify_by_server_resolve(client, conn, packet,
489 SILC_ID_SERVER, server_id);
490 server = silc_client_add_server(client, conn, NULL, NULL, server_id);
494 server->resolve_cmd_ident = conn->cmd_ident;
499 /* If entry being resoled, wait for it before processing this notify */
500 if (server->resolve_cmd_ident) {
501 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
502 res->packet = silc_packet_context_dup(packet);
503 res->context = client;
504 res->sock = silc_socket_dup(conn->sock);
505 silc_client_command_pending(conn, SILC_COMMAND_NONE,
506 server->resolve_cmd_ident,
507 silc_client_notify_by_server_pending, res);
511 /* Save the pointer to the client_entry pointer */
512 client_entry = (SilcClientEntry)server;
514 /* Find Channel entry */
515 silc_free(channel_id);
517 client_entry = (SilcClientEntry)
518 silc_client_get_channel_by_id(client, conn, channel_id);
520 silc_client_channel_set_wait(client, conn, channel,
521 conn->cmd_ident + 1);
522 silc_client_notify_by_server_resolve(client, conn, packet,
523 SILC_ID_CHANNEL, channel_id);
529 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
533 /* If information is being resolved for this channel, wait for it */
534 if (channel->resolve_cmd_ident) {
535 silc_client_channel_wait(client, conn, channel, packet);
539 /* Notify application. The channel entry is sent last as this notify
540 is for channel but application don't know it from the arguments
542 client->internal->ops->notify(client, conn, type, id_type,
543 client_entry, tmp, channel);
547 case SILC_NOTIFY_TYPE_NICK_CHANGE:
549 * Someone changed their nickname. If we don't have entry for the new
550 * ID we will query it and return here after it's done. After we've
551 * returned we fetch the old entry and free it and notify the
555 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
557 /* Get old Client ID */
558 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
562 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
567 if (conn->local_id && SILC_ID_CLIENT_COMPARE(client_id, conn->local_id))
570 /* Find old Client entry */
571 client_entry = silc_client_get_client_by_id(client, conn, client_id);
574 silc_free(client_id);
577 /* Wait for resolving if necessary */
578 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
579 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
580 res->packet = silc_packet_context_dup(packet);
581 res->context = client;
582 res->sock = silc_socket_dup(conn->sock);
583 silc_client_command_pending(conn, SILC_COMMAND_NONE,
584 client_entry->resolve_cmd_ident,
585 silc_client_notify_by_server_pending, res);
589 client_entry->valid = FALSE;
591 /* Get new Client ID */
592 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
596 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
600 /* Take the nickname */
601 tmp = silc_argument_get_arg_type(args, 3, NULL);
605 /* Check whether nickname changed at all. It is possible that nick
606 change notify is received but nickname didn't changed, only the
607 ID changes. Check whether the hashes in the Client ID match, if
608 they do nickname didn't change. */
609 if (SILC_ID_COMPARE_HASH(client_entry->id, client_id)) {
610 /* Nickname didn't change. Update only the ID */
611 silc_idcache_del_by_context(conn->internal->client_cache,
613 silc_free(client_entry->id);
614 client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
615 silc_idcache_add(conn->internal->client_cache, strdup(tmp),
616 client_entry->id, client_entry, 0, NULL);
618 /* Notify application */
619 client->internal->ops->notify(client, conn, type,
620 client_entry, client_entry);
624 /* Create new client entry, and save all old information with the
625 new nickname and client ID */
626 client_entry2 = silc_client_add_client(client, conn, NULL, NULL,
627 client_entry->realname,
628 silc_id_dup(client_id,
633 if (client_entry->server)
634 client_entry2->server = strdup(client_entry->server);
635 if (client_entry->username)
636 client_entry2->username = strdup(client_entry->username);
637 if (client_entry->hostname)
638 client_entry2->hostname = strdup(client_entry->hostname);
639 client_entry2->fingerprint = client_entry->fingerprint;
640 client_entry2->fingerprint_len = client_entry->fingerprint_len;
641 client_entry->fingerprint = NULL;
642 client_entry->fingerprint_len = NULL;
643 silc_client_update_client(client, conn, client_entry2, tmp, NULL, NULL,
646 /* Remove the old from cache */
647 silc_idcache_del_by_context(conn->internal->client_cache, client_entry);
649 /* Replace old ID entry with new one on all channels. */
650 silc_client_replace_from_channels(client, conn, client_entry,
653 /* Notify application */
654 client->internal->ops->notify(client, conn, type,
655 client_entry, client_entry2);
657 /* Free old client entry */
658 silc_client_del_client_entry(client, conn, client_entry);
662 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
664 * Someone changed a channel mode
667 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
669 /* Get channel entry */
670 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
674 channel = silc_client_get_channel_by_id(client, conn, channel_id);
679 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
682 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
686 /* Find Client entry */
687 if (id_type == SILC_ID_CLIENT) {
688 /* Find Client entry */
690 client_entry = silc_client_get_client_by_id(client, conn, client_id);
692 silc_client_channel_set_wait(client, conn, channel,
693 conn->cmd_ident + 1);
694 silc_client_notify_by_server_resolve(client, conn, packet,
695 SILC_ID_CLIENT, client_id);
699 if (!client_entry->nickname) {
700 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
701 /* Attach to existing resolving */
702 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
703 res->packet = silc_packet_context_dup(packet);
704 res->context = client;
705 res->sock = silc_socket_dup(conn->sock);
706 silc_client_command_pending(conn, SILC_COMMAND_NONE,
707 client_entry->resolve_cmd_ident,
708 silc_client_notify_by_server_pending,
713 /* Do new resolving */
714 silc_client_channel_set_wait(client, conn, channel,
715 conn->cmd_ident + 1);
716 silc_client_notify_by_server_resolve(client, conn, packet,
717 SILC_ID_CLIENT, client_id);
720 } else if (id_type == SILC_ID_SERVER) {
721 /* Find Server entry */
723 server = silc_client_get_server_by_id(client, conn, server_id);
725 silc_client_channel_set_wait(client, conn, channel,
726 conn->cmd_ident + 1);
727 silc_client_notify_by_server_resolve(client, conn, packet,
728 SILC_ID_SERVER, server_id);
729 server = silc_client_add_server(client, conn, NULL, NULL, server_id);
733 server->resolve_cmd_ident = conn->cmd_ident;
738 /* If entry being resoled, wait for it before processing this notify */
739 if (server->resolve_cmd_ident) {
740 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
741 res->packet = silc_packet_context_dup(packet);
742 res->context = client;
743 res->sock = silc_socket_dup(conn->sock);
744 silc_client_command_pending(conn, SILC_COMMAND_NONE,
745 server->resolve_cmd_ident,
746 silc_client_notify_by_server_pending, res);
750 /* Save the pointer to the client_entry pointer */
751 client_entry = (SilcClientEntry)server;
753 /* Find Channel entry */
754 silc_free(channel_id);
756 client_entry = (SilcClientEntry)
757 silc_client_get_channel_by_id(client, conn, channel_id);
759 silc_client_channel_set_wait(client, conn, channel,
760 conn->cmd_ident + 1);
761 silc_client_notify_by_server_resolve(client, conn, packet,
762 SILC_ID_CHANNEL, channel_id);
768 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
772 SILC_GET32_MSB(mode, tmp);
774 /* If information is being resolved for this channel, wait for it */
775 if (channel->resolve_cmd_ident) {
776 silc_client_channel_wait(client, conn, channel, packet);
780 /* Save the new mode */
781 channel->mode = mode;
784 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
786 unsigned char hash[32];
789 silc_hmac_free(channel->hmac);
790 if (!silc_hmac_alloc(tmp, NULL, &channel->hmac))
793 silc_hash_make(silc_hmac_get_hash(channel->hmac),
794 channel->key, channel->key_len / 8,
796 silc_hmac_set_key(channel->hmac, hash,
797 silc_hash_len(silc_hmac_get_hash(channel->hmac)));
798 memset(hash, 0, sizeof(hash));
801 /* Notify application. The channel entry is sent last as this notify
802 is for channel but application don't know it from the arguments
804 client->internal->ops->notify(client, conn, type, id_type,
805 client_entry, mode, NULL, tmp, channel);
808 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
810 * Someone changed user's mode on a channel
813 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
815 /* Get channel entry */
816 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
820 channel = silc_client_get_channel_by_id(client, conn, channel_id);
825 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
828 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
832 /* Find Client entry */
833 if (id_type == SILC_ID_CLIENT) {
834 /* Find Client entry */
836 client_entry = silc_client_get_client_by_id(client, conn, client_id);
838 silc_client_channel_set_wait(client, conn, channel,
839 conn->cmd_ident + 1);
840 silc_client_notify_by_server_resolve(client, conn, packet,
841 SILC_ID_CLIENT, client_id);
845 if (!client_entry->nickname) {
846 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
847 /* Attach to existing resolving */
848 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
849 res->packet = silc_packet_context_dup(packet);
850 res->context = client;
851 res->sock = silc_socket_dup(conn->sock);
852 silc_client_command_pending(conn, SILC_COMMAND_NONE,
853 client_entry->resolve_cmd_ident,
854 silc_client_notify_by_server_pending,
859 /* Do new resolving */
860 silc_client_channel_set_wait(client, conn, channel,
861 conn->cmd_ident + 1);
862 silc_client_notify_by_server_resolve(client, conn, packet,
863 SILC_ID_CLIENT, client_id);
866 } else if (id_type == SILC_ID_SERVER) {
867 /* Find Server entry */
869 server = silc_client_get_server_by_id(client, conn, server_id);
871 silc_client_channel_set_wait(client, conn, channel,
872 conn->cmd_ident + 1);
873 silc_client_notify_by_server_resolve(client, conn, packet,
874 SILC_ID_SERVER, server_id);
875 server = silc_client_add_server(client, conn, NULL, NULL, server_id);
879 server->resolve_cmd_ident = conn->cmd_ident;
884 /* If entry being resoled, wait for it before processing this notify */
885 if (server->resolve_cmd_ident) {
886 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
887 res->packet = silc_packet_context_dup(packet);
888 res->context = client;
889 res->sock = silc_socket_dup(conn->sock);
890 silc_client_command_pending(conn, SILC_COMMAND_NONE,
891 server->resolve_cmd_ident,
892 silc_client_notify_by_server_pending, res);
896 /* Save the pointer to the client_entry pointer */
897 client_entry = (SilcClientEntry)server;
899 /* Find Channel entry */
900 silc_free(channel_id);
902 client_entry = (SilcClientEntry)
903 silc_client_get_channel_by_id(client, conn, channel_id);
905 silc_client_channel_set_wait(client, conn, channel,
906 conn->cmd_ident + 1);
907 silc_client_notify_by_server_resolve(client, conn, packet,
908 SILC_ID_CHANNEL, channel_id);
914 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
918 SILC_GET32_MSB(mode, tmp);
920 /* If information is being resolved for this channel, wait for it */
921 if (channel->resolve_cmd_ident) {
922 silc_client_channel_wait(client, conn, channel, packet);
926 /* Get target Client ID */
927 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
931 silc_free(client_id);
932 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
936 /* Find target Client entry */
938 silc_client_get_client_by_id(client, conn, client_id);
939 if (!client_entry2) {
940 silc_client_notify_by_server_resolve(client, conn, packet,
941 SILC_ID_CLIENT, client_id);
946 chu = silc_client_on_channel(channel, client_entry2);
950 /* Notify application. The channel entry is sent last as this notify
951 is for channel but application don't know it from the arguments
953 client->internal->ops->notify(client, conn, type,
954 id_type, client_entry, mode,
955 client_entry2, channel);
958 case SILC_NOTIFY_TYPE_MOTD:
960 * Received Message of the day
963 SILC_LOG_DEBUG(("Notify: MOTD"));
966 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
970 /* Notify application */
971 client->internal->ops->notify(client, conn, type, tmp);
974 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
976 * Router has enforced a new ID to a channel. Let's change the old
977 * ID to the one provided here.
980 SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
983 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
986 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
990 /* Get the channel entry */
991 channel = silc_client_get_channel_by_id(client, conn, channel_id);
995 silc_free(channel_id);
999 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1002 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1006 /* Replace the Channel ID */
1007 if (silc_client_replace_channel_id(client, conn, channel, channel_id))
1010 /* Notify application */
1011 client->internal->ops->notify(client, conn, type, channel, channel);
1014 case SILC_NOTIFY_TYPE_KICKED:
1016 * A client (maybe me) was kicked from a channel
1019 SILC_LOG_DEBUG(("Notify: KICKED"));
1022 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1026 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1030 /* Find Client entry */
1031 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1035 /* Get channel entry */
1036 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
1040 channel = silc_client_get_channel_by_id(client, conn, channel_id);
1044 /* From protocol version 1.1 we get the kicker's client ID as well */
1045 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1047 silc_free(client_id);
1048 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1052 /* Find kicker's client entry and if not found resolve it */
1053 client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
1054 if (!client_entry2) {
1055 silc_client_notify_by_server_resolve(client, conn, packet,
1056 SILC_ID_CLIENT, client_id);
1059 if (client_entry2 != conn->local_entry)
1060 silc_client_nickname_format(client, conn, client_entry2);
1065 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1067 /* Notify application. The channel entry is sent last as this notify
1068 is for channel but application don't know it from the arguments
1070 client->internal->ops->notify(client, conn, type, client_entry, tmp,
1071 client_entry2, channel);
1073 /* Remove kicked client from channel */
1074 if (client_entry == conn->local_entry) {
1075 /* If I was kicked from channel, remove the channel */
1076 if (conn->current_channel == channel)
1077 conn->current_channel = NULL;
1078 silc_client_del_channel(client, conn, channel);
1080 chu = silc_client_on_channel(channel, client_entry);
1082 silc_hash_table_del(client_entry->channels, channel);
1083 silc_hash_table_del(channel->user_list, client_entry);
1087 if (!silc_hash_table_count(client_entry->channels)) {
1088 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1089 res->context = client;
1090 res->sock = silc_socket_dup(conn->sock);
1091 res->packet = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1092 silc_schedule_task_add(client->schedule, conn->sock->sock,
1093 silc_client_notify_check_client, res,
1094 (5 + (silc_rng_get_rn16(client->rng) % 529)),
1095 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1100 case SILC_NOTIFY_TYPE_KILLED:
1103 * A client (maybe me) was killed from the network.
1106 SilcUInt32 comment_len;
1108 SILC_LOG_DEBUG(("Notify: KILLED"));
1111 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1115 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1119 /* Find Client entry */
1120 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1125 comment = silc_argument_get_arg_type(args, 2, &comment_len);
1127 /* From protocol version 1.1 we get killer's client ID as well */
1128 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1130 silc_free(client_id);
1132 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
1136 /* Find Client entry */
1137 if (id_type == SILC_ID_CLIENT) {
1138 /* Find Client entry */
1140 client_entry2 = silc_client_get_client_by_id(client, conn,
1142 if (!client_entry) {
1143 silc_client_notify_by_server_resolve(client, conn, packet,
1144 SILC_ID_CLIENT, client_id);
1147 } else if (id_type == SILC_ID_SERVER) {
1148 /* Find Server entry */
1150 server = silc_client_get_server_by_id(client, conn, server_id);
1152 silc_client_notify_by_server_resolve(client, conn, packet,
1153 SILC_ID_SERVER, server_id);
1154 server = silc_client_add_server(client, conn, NULL, NULL,
1159 server->resolve_cmd_ident = conn->cmd_ident;
1164 if (server->resolve_cmd_ident) {
1165 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1166 res->packet = silc_packet_context_dup(packet);
1167 res->context = client;
1168 res->sock = silc_socket_dup(conn->sock);
1169 silc_client_command_pending(conn, SILC_COMMAND_NONE,
1170 server->resolve_cmd_ident,
1171 silc_client_notify_by_server_pending,
1176 /* Save the pointer to the client_entry pointer */
1177 client_entry2 = (SilcClientEntry)server;
1179 /* Find Channel entry */
1181 channel = silc_client_get_channel_by_id(client, conn, channel_id);
1183 silc_client_notify_by_server_resolve(client, conn, packet,
1184 SILC_ID_CHANNEL, channel_id);
1188 /* Save the pointer to the client_entry pointer */
1189 client_entry2 = (SilcClientEntry)channel;
1190 silc_free(channel_id);
1195 /* Notify application. */
1196 client->internal->ops->notify(client, conn, type, client_entry,
1197 comment, id_type, client_entry2);
1199 if (client_entry != conn->local_entry)
1200 /* Remove the client from all channels and free it */
1201 silc_client_del_client(client, conn, client_entry);
1205 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
1208 * A server quit the SILC network and some clients must be removed
1209 * from channels as they quit as well.
1211 SilcClientEntry *clients = NULL;
1212 SilcUInt32 clients_count = 0;
1215 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
1217 for (i = 1; i < silc_argument_get_arg_num(args); i++) {
1219 tmp = silc_argument_get_arg_type(args, i + 1, &tmp_len);
1221 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1225 /* Get the client entry */
1226 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1228 clients = silc_realloc(clients, sizeof(*clients) *
1229 (clients_count + 1));
1230 clients[clients_count] = client_entry;
1233 silc_free(client_id);
1238 /* Notify application. We don't keep server entries so the server
1239 entry is returned as NULL. The client's are returned as array
1240 of SilcClientEntry pointers. */
1241 client->internal->ops->notify(client, conn, type, NULL,
1242 clients, clients_count);
1244 for (i = 0; i < clients_count; i++) {
1245 /* Remove client from all channels */
1246 client_entry = clients[i];
1247 if (client_entry == conn->local_entry)
1250 /* Remove the client from all channels and free it */
1251 silc_client_del_client(client, conn, client_entry);
1258 case SILC_NOTIFY_TYPE_ERROR:
1261 * Some has occurred and server is notifying us about it.
1265 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1266 if (!tmp && tmp_len != 1)
1268 error = (SilcStatus)tmp[0];
1270 SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1272 if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1273 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1275 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1278 client_entry = silc_client_get_client_by_id(client, conn,
1281 silc_client_del_client(client, conn, client_entry);
1285 /* Notify application. */
1286 client->internal->ops->notify(client, conn, type, error);
1290 case SILC_NOTIFY_TYPE_WATCH:
1293 * Received notify about some client we are watching
1295 SilcNotifyType notify = 0;
1296 bool del_client = FALSE;
1298 SILC_LOG_DEBUG(("Notify: WATCH"));
1300 /* Get sender Client ID */
1301 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1304 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1308 /* Find Client entry and if not found query it */
1309 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1310 if (!client_entry) {
1311 silc_client_notify_by_server_resolve(client, conn, packet,
1312 SILC_ID_CLIENT, client_id);
1317 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1318 if (!tmp || tmp_len != 4)
1320 SILC_GET32_MSB(mode, tmp);
1322 /* Get notify type */
1323 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1324 if (tmp && tmp_len != 2)
1327 SILC_GET16_MSB(notify, tmp);
1330 tmp = silc_argument_get_arg_type(args, 2, NULL);
1332 char *tmp_nick = NULL;
1334 if (client->internal->params->nickname_parse)
1335 client->internal->params->nickname_parse(client_entry->nickname,
1338 tmp_nick = strdup(tmp);
1340 /* If same nick, the client was new to us and has become "present"
1341 to network. Send NULL as nick to application. */
1342 if (tmp_nick && !strcmp(tmp, tmp_nick))
1345 silc_free(tmp_nick);
1348 /* Notify application. */
1349 client->internal->ops->notify(client, conn, type, client_entry,
1352 client_entry->mode = mode;
1354 /* If nickname was changed, remove the client entry unless the
1355 client is on some channel */
1356 if (tmp && notify == SILC_NOTIFY_TYPE_NICK_CHANGE &&
1357 !silc_hash_table_count(client_entry->channels))
1359 else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1360 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
1361 notify == SILC_NOTIFY_TYPE_KILLED)
1365 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1366 res->context = client;
1367 res->sock = silc_socket_dup(conn->sock);
1368 res->packet = client_id;
1370 silc_schedule_task_add(client->schedule, conn->sock->sock,
1371 silc_client_notify_del_client_cb, res,
1372 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1382 silc_notify_payload_free(payload);
1383 silc_free(client_id);
1384 silc_free(channel_id);
1385 silc_free(server_id);