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, NULL, NULL);
43 silc_socket_free(res->sock);
47 SILC_TASK_CALLBACK(silc_client_notify_del_client_cb)
49 SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
50 SilcClient client = res->context;
51 SilcClientConnection conn = res->sock->user_data;
52 SilcClientID *client_id = res->packet;
53 SilcClientEntry client_entry;
54 client_entry = silc_client_get_client_by_id(client, conn, client_id);
56 silc_client_del_client(client, conn, client_entry);
58 silc_socket_free(res->sock);
62 /* Called when notify is received and some async operation (such as command)
63 is required before processing the notify message. This calls again the
64 silc_client_notify_by_server and reprocesses the original notify packet. */
66 static void silc_client_notify_by_server_pending(void *context, void *context2)
68 SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
69 SilcClientCommandReplyContext reply =
70 (SilcClientCommandReplyContext)context2;
72 SILC_LOG_DEBUG(("Start"));
74 if (reply && !silc_command_get_status(reply->payload, NULL, NULL))
77 silc_client_notify_by_server(res->context, res->sock, res->packet);
80 silc_socket_free(res->sock);
81 silc_packet_context_free(res->packet);
85 /* Resets the channel entry's resolve_cmd_ident after whatever-thing
86 was resolved is completed. */
88 static void silc_client_channel_cond(void *context, void *context2)
90 SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
91 SilcClient client = res->context;
92 SilcClientConnection conn = res->sock->user_data;
93 SilcChannelID *channel_id = res->packet;
94 SilcChannelEntry channel;
95 channel = silc_client_get_channel_by_id(client, conn, channel_id);
97 channel->resolve_cmd_ident = 0;
98 silc_free(channel_id);
99 silc_socket_free(res->sock);
103 /* Function that starts waiting for the `cmd_ident' to arrive and
104 marks the channel info being resolved. */
106 static void silc_client_channel_set_wait(SilcClient client,
107 SilcClientConnection conn,
108 SilcChannelEntry channel,
109 SilcUInt16 cmd_ident)
111 SilcClientNotifyResolve res;
113 if (!channel->resolve_cmd_ident) {
114 res = silc_calloc(1, sizeof(*res));
115 res->context = client;
116 res->sock = silc_socket_dup(conn->sock);
117 res->packet = silc_id_dup(channel->id, SILC_ID_CHANNEL);
118 silc_client_command_pending(conn, SILC_COMMAND_NONE, cmd_ident,
119 silc_client_channel_cond, res);
120 channel->resolve_cmd_ident = cmd_ident;
124 /* Attaches to the channel's resolving cmd ident and calls the
125 notify handling with `packet' after it's received. */
127 static void silc_client_channel_wait(SilcClient client,
128 SilcClientConnection conn,
129 SilcChannelEntry channel,
130 SilcPacketContext *packet)
132 SilcClientNotifyResolve res;
134 if (!channel->resolve_cmd_ident)
137 res = silc_calloc(1, sizeof(*res));
138 res->packet = silc_packet_context_dup(packet);
139 res->context = client;
140 res->sock = silc_socket_dup(conn->sock);
142 silc_client_command_pending(conn, SILC_COMMAND_NONE,
143 channel->resolve_cmd_ident,
144 silc_client_notify_by_server_pending, res);
147 /* Resolve client, channel or server information. */
149 static void silc_client_notify_by_server_resolve(SilcClient client,
150 SilcClientConnection conn,
151 SilcPacketContext *packet,
155 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
156 SilcBuffer idp = silc_id_payload_encode(id, id_type);
158 res->packet = silc_packet_context_dup(packet);
159 res->context = client;
160 res->sock = silc_socket_dup(conn->sock);
162 /* For client resolving use WHOIS, and otherwise use IDENTIFY */
163 if (id_type == SILC_ID_CLIENT) {
164 silc_client_command_register(client, SILC_COMMAND_WHOIS, NULL, NULL,
165 silc_client_command_reply_whois_i, 0,
167 silc_client_command_send(client, conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
168 1, 4, idp->data, idp->len);
169 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
170 silc_client_notify_by_server_pending, res);
172 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
173 silc_client_command_reply_identify_i, 0,
175 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
176 conn->cmd_ident, 1, 5, idp->data, idp->len);
177 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
178 silc_client_notify_by_server_pending, res);
180 silc_buffer_free(idp);
183 /* Received notify message from server */
185 void silc_client_notify_by_server(SilcClient client,
186 SilcSocketConnection sock,
187 SilcPacketContext *packet)
189 SilcBuffer buffer = packet->buffer;
190 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
191 SilcNotifyPayload payload;
193 SilcArgumentPayload args;
197 SilcClientID *client_id = NULL;
198 SilcChannelID *channel_id = NULL;
199 SilcServerID *server_id = NULL;
200 SilcClientEntry client_entry = NULL;
201 SilcClientEntry client_entry2 = NULL;
202 SilcChannelEntry channel;
204 SilcServerEntry server;
206 SilcUInt32 tmp_len, mode;
208 SILC_LOG_DEBUG(("Start"));
210 payload = silc_notify_payload_parse(buffer->data, buffer->len);
214 type = silc_notify_get_type(payload);
215 args = silc_notify_get_args(payload);
220 case SILC_NOTIFY_TYPE_NONE:
221 /* Notify application */
222 client->internal->ops->notify(client, conn, type,
223 silc_argument_get_arg_type(args, 1, NULL));
226 case SILC_NOTIFY_TYPE_INVITE:
228 * Someone invited me to a channel. Find Client and Channel entries
229 * for the application.
232 SILC_LOG_DEBUG(("Notify: INVITE"));
235 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
239 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
243 /* Get the channel entry */
244 channel = silc_client_get_channel_by_id(client, conn, channel_id);
246 /* Get sender Client ID */
247 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
251 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
255 /* Find Client entry and if not found query it */
256 client_entry = silc_client_get_client_by_id(client, conn, client_id);
258 silc_client_notify_by_server_resolve(client, conn, packet,
259 SILC_ID_CLIENT, client_id);
263 /* Get the channel name */
264 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
268 /* Notify application */
269 client->internal->ops->notify(client, conn, type, channel, tmp,
273 case SILC_NOTIFY_TYPE_JOIN:
275 * Someone has joined to a channel. Get their ID and nickname and
276 * cache them for later use.
279 SILC_LOG_DEBUG(("Notify: JOIN"));
282 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
286 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
290 /* Find Client entry and if not found query it */
291 client_entry = silc_client_get_client_by_id(client, conn, client_id);
293 silc_client_notify_by_server_resolve(client, conn, packet,
294 SILC_ID_CLIENT, client_id);
298 /* If nickname or username hasn't been resolved, do so */
299 if (!client_entry->nickname || !client_entry->username) {
300 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
301 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
304 silc_client_notify_by_server_resolve(client, conn, packet,
305 SILC_ID_CLIENT, client_id);
306 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
307 client_entry->resolve_cmd_ident = conn->cmd_ident;
310 if (client_entry != conn->local_entry)
311 silc_client_nickname_format(client, conn, client_entry);
315 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
319 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
323 /* Get channel entry */
324 channel = silc_client_get_channel_by_id(client, conn, channel_id);
328 /* Join the client to channel */
329 if (!silc_client_on_channel(channel, client_entry)) {
330 chu = silc_calloc(1, sizeof(*chu));
331 chu->client = client_entry;
332 chu->channel = channel;
333 silc_hash_table_add(channel->user_list, client_entry, chu);
334 silc_hash_table_add(client_entry->channels, channel, chu);
337 /* Notify application. The channel entry is sent last as this notify
338 is for channel but application don't know it from the arguments
340 client->internal->ops->notify(client, conn, type, client_entry, channel);
343 case SILC_NOTIFY_TYPE_LEAVE:
345 * Someone has left a channel. We will remove it from the channel but
346 * we'll keep it in the cache in case we'll need it later.
349 SILC_LOG_DEBUG(("Notify: LEAVE"));
352 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
356 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
360 /* Find Client entry */
362 silc_client_get_client_by_id(client, conn, client_id);
366 /* Get channel entry */
367 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
371 channel = silc_client_get_channel_by_id(client, conn, channel_id);
375 /* Remove client from channel */
376 chu = silc_client_on_channel(channel, client_entry);
378 silc_hash_table_del(client_entry->channels, channel);
379 silc_hash_table_del(channel->user_list, client_entry);
383 /* Some client implementations actually quit network by first doing
384 LEAVE and then immediately SIGNOFF. We'll check for this by doing
385 check for the client after 5 - 34 seconds. If it is not valid after
386 that we'll remove the client from cache. */
387 if (!silc_hash_table_count(client_entry->channels)) {
388 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
389 res->context = client;
390 res->sock = silc_socket_dup(conn->sock);
391 res->packet = silc_id_dup(client_id, SILC_ID_CLIENT);
392 silc_schedule_task_add(client->schedule, conn->sock->sock,
393 silc_client_notify_check_client, res,
394 (5 + (silc_rng_get_rn16(client->rng) % 29)),
395 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
398 /* Notify application. The channel entry is sent last as this notify
399 is for channel but application don't know it from the arguments
401 client->internal->ops->notify(client, conn, type, client_entry, channel);
404 case SILC_NOTIFY_TYPE_SIGNOFF:
406 * Someone left SILC. We'll remove it from all channels and from cache.
409 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
412 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
416 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
420 /* Find Client entry */
422 silc_client_get_client_by_id(client, conn, client_id);
426 /* Remove from all channels */
427 silc_client_remove_from_channels(client, conn, client_entry);
429 /* Remove from cache */
430 silc_idcache_del_by_context(conn->client_cache, client_entry);
432 /* Get signoff message */
433 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
437 /* Notify application */
438 client->internal->ops->notify(client, conn, type, client_entry, tmp);
441 silc_client_del_client_entry(client, conn, client_entry);
444 case SILC_NOTIFY_TYPE_TOPIC_SET:
446 * Someone set the topic on a channel.
449 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
451 /* Get channel entry */
452 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
456 channel = silc_client_get_channel_by_id(client, conn, channel_id);
461 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
464 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
468 /* Find Client entry */
469 if (id_type == SILC_ID_CLIENT) {
470 /* Find Client entry */
472 client_entry = silc_client_get_client_by_id(client, conn, client_id);
474 silc_client_channel_set_wait(client, conn, channel,
475 conn->cmd_ident + 1);
476 silc_client_notify_by_server_resolve(client, conn, packet,
477 SILC_ID_CLIENT, client_id);
480 } else if (id_type == SILC_ID_SERVER) {
481 /* Find Server entry */
483 server = silc_client_get_server_by_id(client, conn, server_id);
485 silc_client_channel_set_wait(client, conn, channel,
486 conn->cmd_ident + 1);
487 silc_client_notify_by_server_resolve(client, conn, packet,
488 SILC_ID_SERVER, server_id);
489 server = silc_client_add_server(client, conn, NULL, NULL, server_id);
493 server->resolve_cmd_ident = conn->cmd_ident;
498 /* If entry being resoled, wait for it before processing this notify */
499 if (server->resolve_cmd_ident) {
500 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
501 res->packet = silc_packet_context_dup(packet);
502 res->context = client;
503 res->sock = silc_socket_dup(conn->sock);
504 silc_client_command_pending(conn, SILC_COMMAND_NONE,
505 server->resolve_cmd_ident,
506 silc_client_notify_by_server_pending, res);
510 /* Save the pointer to the client_entry pointer */
511 client_entry = (SilcClientEntry)server;
513 /* Find Channel entry */
514 silc_free(channel_id);
516 client_entry = (SilcClientEntry)
517 silc_client_get_channel_by_id(client, conn, channel_id);
519 silc_client_channel_set_wait(client, conn, channel,
520 conn->cmd_ident + 1);
521 silc_client_notify_by_server_resolve(client, conn, packet,
522 SILC_ID_CHANNEL, channel_id);
528 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
532 /* If information is being resolved for this channel, wait for it */
533 if (channel->resolve_cmd_ident) {
534 silc_client_channel_wait(client, conn, channel, packet);
538 /* Notify application. The channel entry is sent last as this notify
539 is for channel but application don't know it from the arguments
541 client->internal->ops->notify(client, conn, type, id_type,
542 client_entry, tmp, channel);
546 case SILC_NOTIFY_TYPE_NICK_CHANGE:
548 * Someone changed their nickname. If we don't have entry for the new
549 * ID we will query it and return here after it's done. After we've
550 * returned we fetch the old entry and free it and notify the
554 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
556 /* Get old Client ID */
557 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
561 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
566 if (conn->local_id && SILC_ID_CLIENT_COMPARE(client_id, conn->local_id))
569 /* Find old Client entry */
570 client_entry = silc_client_get_client_by_id(client, conn, client_id);
573 silc_free(client_id);
575 client_entry->valid = FALSE;
577 /* Get new Client ID */
578 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
582 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
586 /* From protocol version 1.1 we get the new nickname in notify as well,
587 so we don't have to resolve it. Do it the hard way if server doesn't
589 tmp = silc_argument_get_arg_type(args, 3, NULL);
591 /* Protocol version 1.1 */
592 char *tmp_nick = NULL;
594 /* Check whether nickname changed at all. It is possible that nick
595 change notify is received but nickname didn't changed, only the
597 if (client->internal->params->nickname_parse)
598 client->internal->params->nickname_parse(client_entry->nickname,
601 tmp_nick = strdup(tmp);
603 if (tmp_nick && !strcmp(tmp, tmp_nick)) {
604 /* Nickname didn't change. Update only the ID */
605 silc_idcache_del_by_context(conn->client_cache, client_entry);
606 silc_free(client_entry->id);
607 client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
608 silc_idcache_add(conn->client_cache, strdup(tmp),
609 client_entry->id, client_entry, 0, NULL);
611 /* Notify application */
612 client->internal->ops->notify(client, conn, type,
613 client_entry, client_entry);
618 /* Create new client entry, and save all old information with the
619 new nickname and client ID */
620 client_entry2 = silc_client_add_client(client, conn, NULL, NULL,
621 client_entry->realname,
622 silc_id_dup(client_id,
627 if (client_entry->server)
628 client_entry2->server = strdup(client_entry->server);
629 if (client_entry->username)
630 client_entry2->username = strdup(client_entry->username);
631 if (client_entry->hostname)
632 client_entry2->hostname = strdup(client_entry->hostname);
633 silc_client_update_client(client, conn, client_entry2, tmp, NULL, NULL,
636 /* Protocol version 1.0 */
638 /* Find client entry and if not found resolve it */
639 client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
640 if (!client_entry2) {
641 /* Resolve the entry information */
642 silc_client_notify_by_server_resolve(client, conn, packet,
643 SILC_ID_CLIENT, client_id);
645 /* Add the new entry even though we resolved it. This is because we
646 want to replace the old entry with the new entry here right now. */
648 silc_client_add_client(client, conn, NULL, NULL, NULL,
649 silc_id_dup(client_id, SILC_ID_CLIENT),
652 /* Replace old ID entry with new one on all channels. */
653 silc_client_replace_from_channels(client, conn, client_entry,
658 if (client_entry2 != conn->local_entry)
659 silc_client_nickname_format(client, conn, client_entry2);
662 /* Remove the old from cache */
663 silc_idcache_del_by_context(conn->client_cache, client_entry);
665 /* Replace old ID entry with new one on all channels. */
666 silc_client_replace_from_channels(client, conn, client_entry,
669 /* Notify application */
670 client->internal->ops->notify(client, conn, type,
671 client_entry, client_entry2);
673 /* Free old client entry */
674 silc_client_del_client_entry(client, conn, client_entry);
678 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
680 * Someone changed a channel mode
683 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
685 /* Get channel entry */
686 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
690 channel = silc_client_get_channel_by_id(client, conn, channel_id);
695 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
698 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
702 /* Find Client entry */
703 if (id_type == SILC_ID_CLIENT) {
704 /* Find Client entry */
706 client_entry = silc_client_get_client_by_id(client, conn, client_id);
708 silc_client_channel_set_wait(client, conn, channel,
709 conn->cmd_ident + 1);
710 silc_client_notify_by_server_resolve(client, conn, packet,
711 SILC_ID_CLIENT, client_id);
714 } else if (id_type == SILC_ID_SERVER) {
715 /* Find Server entry */
717 server = silc_client_get_server_by_id(client, conn, server_id);
719 silc_client_channel_set_wait(client, conn, channel,
720 conn->cmd_ident + 1);
721 silc_client_notify_by_server_resolve(client, conn, packet,
722 SILC_ID_SERVER, server_id);
723 server = silc_client_add_server(client, conn, NULL, NULL, server_id);
727 server->resolve_cmd_ident = conn->cmd_ident;
732 /* If entry being resoled, wait for it before processing this notify */
733 if (server->resolve_cmd_ident) {
734 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
735 res->packet = silc_packet_context_dup(packet);
736 res->context = client;
737 res->sock = silc_socket_dup(conn->sock);
738 silc_client_command_pending(conn, SILC_COMMAND_NONE,
739 server->resolve_cmd_ident,
740 silc_client_notify_by_server_pending, res);
744 /* Save the pointer to the client_entry pointer */
745 client_entry = (SilcClientEntry)server;
747 /* Find Channel entry */
748 silc_free(channel_id);
750 client_entry = (SilcClientEntry)
751 silc_client_get_channel_by_id(client, conn, channel_id);
753 silc_client_channel_set_wait(client, conn, channel,
754 conn->cmd_ident + 1);
755 silc_client_notify_by_server_resolve(client, conn, packet,
756 SILC_ID_CHANNEL, channel_id);
762 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
766 SILC_GET32_MSB(mode, tmp);
768 /* If information is being resolved for this channel, wait for it */
769 if (channel->resolve_cmd_ident) {
770 silc_client_channel_wait(client, conn, channel, packet);
774 /* Save the new mode */
775 channel->mode = mode;
778 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
780 unsigned char hash[32];
783 silc_hmac_free(channel->hmac);
784 if (!silc_hmac_alloc(tmp, NULL, &channel->hmac))
787 silc_hash_make(silc_hmac_get_hash(channel->hmac),
788 channel->key, channel->key_len / 8,
790 silc_hmac_set_key(channel->hmac, hash,
791 silc_hash_len(silc_hmac_get_hash(channel->hmac)));
792 memset(hash, 0, sizeof(hash));
795 /* Notify application. The channel entry is sent last as this notify
796 is for channel but application don't know it from the arguments
798 client->internal->ops->notify(client, conn, type, id_type,
799 client_entry, mode, NULL, tmp, channel);
802 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
804 * Someone changed user's mode on a channel
807 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
809 /* Get channel entry */
810 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
814 channel = silc_client_get_channel_by_id(client, conn, channel_id);
819 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
822 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
826 /* Find Client entry */
827 if (id_type == SILC_ID_CLIENT) {
828 /* Find Client entry */
830 client_entry = silc_client_get_client_by_id(client, conn, client_id);
832 silc_client_channel_set_wait(client, conn, channel,
833 conn->cmd_ident + 1);
834 silc_client_notify_by_server_resolve(client, conn, packet,
835 SILC_ID_CLIENT, client_id);
838 } else if (id_type == SILC_ID_SERVER) {
839 /* Find Server entry */
841 server = silc_client_get_server_by_id(client, conn, server_id);
843 silc_client_channel_set_wait(client, conn, channel,
844 conn->cmd_ident + 1);
845 silc_client_notify_by_server_resolve(client, conn, packet,
846 SILC_ID_SERVER, server_id);
847 server = silc_client_add_server(client, conn, NULL, NULL, server_id);
851 server->resolve_cmd_ident = conn->cmd_ident;
856 /* If entry being resoled, wait for it before processing this notify */
857 if (server->resolve_cmd_ident) {
858 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
859 res->packet = silc_packet_context_dup(packet);
860 res->context = client;
861 res->sock = silc_socket_dup(conn->sock);
862 silc_client_command_pending(conn, SILC_COMMAND_NONE,
863 server->resolve_cmd_ident,
864 silc_client_notify_by_server_pending, res);
868 /* Save the pointer to the client_entry pointer */
869 client_entry = (SilcClientEntry)server;
871 /* Find Channel entry */
872 silc_free(channel_id);
874 client_entry = (SilcClientEntry)
875 silc_client_get_channel_by_id(client, conn, channel_id);
877 silc_client_channel_set_wait(client, conn, channel,
878 conn->cmd_ident + 1);
879 silc_client_notify_by_server_resolve(client, conn, packet,
880 SILC_ID_CHANNEL, channel_id);
886 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
890 SILC_GET32_MSB(mode, tmp);
892 /* If information is being resolved for this channel, wait for it */
893 if (channel->resolve_cmd_ident) {
894 silc_client_channel_wait(client, conn, channel, packet);
898 /* Get target Client ID */
899 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
903 silc_free(client_id);
904 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
908 /* Find target Client entry */
910 silc_client_get_client_by_id(client, conn, client_id);
911 if (!client_entry2) {
912 silc_client_notify_by_server_resolve(client, conn, packet,
913 SILC_ID_CLIENT, client_id);
918 chu = silc_client_on_channel(channel, client_entry2);
922 /* Notify application. The channel entry is sent last as this notify
923 is for channel but application don't know it from the arguments
925 client->internal->ops->notify(client, conn, type,
926 id_type, client_entry, mode,
927 client_entry2, channel);
930 case SILC_NOTIFY_TYPE_MOTD:
932 * Received Message of the day
935 SILC_LOG_DEBUG(("Notify: MOTD"));
938 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
942 /* Notify application */
943 client->internal->ops->notify(client, conn, type, tmp);
946 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
948 * Router has enforced a new ID to a channel. Let's change the old
949 * ID to the one provided here.
952 SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
955 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
958 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
962 /* Get the channel entry */
963 channel = silc_client_get_channel_by_id(client, conn, channel_id);
967 silc_free(channel_id);
970 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
973 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
977 /* Replace the Channel ID */
978 if (silc_client_replace_channel_id(client, conn, channel, channel_id))
981 /* Notify application */
982 client->internal->ops->notify(client, conn, type, channel, channel);
985 case SILC_NOTIFY_TYPE_KICKED:
987 * A client (maybe me) was kicked from a channel
990 SILC_LOG_DEBUG(("Notify: KICKED"));
993 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
997 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1001 /* Find Client entry */
1002 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1006 /* Get channel entry */
1007 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
1011 channel = silc_client_get_channel_by_id(client, conn, channel_id);
1015 /* From protocol version 1.1 we get the kicker's client ID as well */
1016 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1018 silc_free(client_id);
1019 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1023 /* Find kicker's client entry and if not found resolve it */
1024 client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
1025 if (!client_entry2) {
1026 silc_client_notify_by_server_resolve(client, conn, packet,
1027 SILC_ID_CLIENT, client_id);
1030 if (client_entry2 != conn->local_entry)
1031 silc_client_nickname_format(client, conn, client_entry2);
1036 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1038 /* Notify application. The channel entry is sent last as this notify
1039 is for channel but application don't know it from the arguments
1041 client->internal->ops->notify(client, conn, type, client_entry, tmp,
1042 client_entry2, channel);
1044 /* Remove kicked client from channel */
1045 if (client_entry == conn->local_entry) {
1046 /* If I was kicked from channel, remove the channel */
1047 if (conn->current_channel == channel)
1048 conn->current_channel = NULL;
1049 silc_client_del_channel(client, conn, channel);
1051 chu = silc_client_on_channel(channel, client_entry);
1053 silc_hash_table_del(client_entry->channels, channel);
1054 silc_hash_table_del(channel->user_list, client_entry);
1058 if (!silc_hash_table_count(client_entry->channels)) {
1059 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1060 res->context = client;
1061 res->sock = silc_socket_dup(conn->sock);
1062 res->packet = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1063 silc_schedule_task_add(client->schedule, conn->sock->sock,
1064 silc_client_notify_check_client, res,
1065 (5 + (silc_rng_get_rn16(client->rng) % 529)),
1066 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1071 case SILC_NOTIFY_TYPE_KILLED:
1074 * A client (maybe me) was killed from the network.
1077 SilcUInt32 comment_len;
1079 SILC_LOG_DEBUG(("Notify: KILLED"));
1082 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1086 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1090 /* Find Client entry */
1091 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1096 comment = silc_argument_get_arg_type(args, 2, &comment_len);
1098 /* From protocol version 1.1 we get killer's client ID as well */
1099 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1101 silc_free(client_id);
1102 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
1106 /* Find Client entry */
1107 if (id_type == SILC_ID_CLIENT) {
1108 /* Find Client entry */
1110 client_entry2 = silc_client_get_client_by_id(client, conn,
1112 if (!client_entry) {
1113 silc_client_notify_by_server_resolve(client, conn, packet,
1114 SILC_ID_CLIENT, client_id);
1117 } else if (id_type == SILC_ID_SERVER) {
1118 /* Find Server entry */
1120 server = silc_client_get_server_by_id(client, conn, server_id);
1122 silc_client_notify_by_server_resolve(client, conn, packet,
1123 SILC_ID_SERVER, server_id);
1124 server = silc_client_add_server(client, conn, NULL, NULL,
1129 server->resolve_cmd_ident = conn->cmd_ident;
1134 if (server->resolve_cmd_ident) {
1135 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1136 res->packet = silc_packet_context_dup(packet);
1137 res->context = client;
1138 res->sock = silc_socket_dup(conn->sock);
1139 silc_client_command_pending(conn, SILC_COMMAND_NONE,
1140 server->resolve_cmd_ident,
1141 silc_client_notify_by_server_pending,
1146 /* Save the pointer to the client_entry pointer */
1147 client_entry2 = (SilcClientEntry)server;
1149 /* Find Channel entry */
1151 channel = silc_client_get_channel_by_id(client, conn, channel_id);
1153 silc_client_notify_by_server_resolve(client, conn, packet,
1154 SILC_ID_CHANNEL, channel_id);
1158 /* Save the pointer to the client_entry pointer */
1159 client_entry2 = (SilcClientEntry)channel;
1160 silc_free(channel_id);
1165 /* Notify application. */
1166 client->internal->ops->notify(client, conn, type, client_entry,
1167 comment, id_type, client_entry2);
1169 if (client_entry != conn->local_entry)
1170 /* Remove the client from all channels and free it */
1171 silc_client_del_client(client, conn, client_entry);
1175 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
1178 * A server quit the SILC network and some clients must be removed
1179 * from channels as they quit as well.
1181 SilcClientEntry *clients = NULL;
1182 SilcUInt32 clients_count = 0;
1185 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
1187 for (i = 1; i < silc_argument_get_arg_num(args); i++) {
1189 tmp = silc_argument_get_arg_type(args, i + 1, &tmp_len);
1191 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1195 /* Get the client entry */
1196 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1198 clients = silc_realloc(clients, sizeof(*clients) *
1199 (clients_count + 1));
1200 clients[clients_count] = client_entry;
1203 silc_free(client_id);
1208 /* Notify application. We don't keep server entries so the server
1209 entry is returned as NULL. The client's are returned as array
1210 of SilcClientEntry pointers. */
1211 client->internal->ops->notify(client, conn, type, NULL,
1212 clients, clients_count);
1214 for (i = 0; i < clients_count; i++) {
1215 /* Remove client from all channels */
1216 client_entry = clients[i];
1217 if (client_entry == conn->local_entry)
1220 /* Remove the client from all channels and free it */
1221 silc_client_del_client(client, conn, client_entry);
1228 case SILC_NOTIFY_TYPE_ERROR:
1231 * Some has occurred and server is notifying us about it.
1235 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1236 if (!tmp && tmp_len != 1)
1238 error = (SilcStatus)tmp[0];
1240 SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1242 if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1243 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1245 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1248 client_entry = silc_client_get_client_by_id(client, conn,
1251 silc_client_del_client(client, conn, client_entry);
1255 /* Notify application. */
1256 client->internal->ops->notify(client, conn, type, error);
1260 case SILC_NOTIFY_TYPE_WATCH:
1263 * Received notify about some client we are watching
1265 SilcNotifyType notify = 0;
1266 bool del_client = FALSE;
1268 SILC_LOG_DEBUG(("Notify: WATCH"));
1270 /* Get sender Client ID */
1271 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1274 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1278 /* Find Client entry and if not found query it */
1279 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1280 if (!client_entry) {
1281 silc_client_notify_by_server_resolve(client, conn, packet,
1282 SILC_ID_CLIENT, client_id);
1287 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1288 if (!tmp || tmp_len != 4)
1290 SILC_GET32_MSB(mode, tmp);
1292 /* Get notify type */
1293 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1294 if (tmp && tmp_len != 2)
1297 SILC_GET16_MSB(notify, tmp);
1300 tmp = silc_argument_get_arg_type(args, 2, NULL);
1302 char *tmp_nick = NULL;
1304 if (client->internal->params->nickname_parse)
1305 client->internal->params->nickname_parse(client_entry->nickname,
1308 tmp_nick = strdup(tmp);
1310 /* If same nick, the client was new to us and has become "present"
1311 to network. Send NULL as nick to application. */
1312 if (tmp_nick && !strcmp(tmp, tmp_nick))
1315 silc_free(tmp_nick);
1318 /* Notify application. */
1319 client->internal->ops->notify(client, conn, type, client_entry,
1322 client_entry->mode = mode;
1324 /* If nickname was changed, remove the client entry unless the
1325 client is on some channel */
1326 if (tmp && notify == SILC_NOTIFY_TYPE_NICK_CHANGE &&
1327 !silc_hash_table_count(client_entry->channels))
1329 else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1330 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
1331 notify == SILC_NOTIFY_TYPE_KILLED)
1335 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1336 res->context = client;
1337 res->sock = silc_socket_dup(conn->sock);
1338 res->packet = client_id;
1340 silc_schedule_task_add(client->schedule, conn->sock->sock,
1341 silc_client_notify_del_client_cb, res,
1342 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1352 silc_notify_payload_free(payload);
1353 silc_free(client_id);
1354 silc_free(channel_id);
1355 silc_free(server_id);