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 /* Wait for resolving if necessary */
576 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
577 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
578 res->packet = silc_packet_context_dup(packet);
579 res->context = client;
580 res->sock = silc_socket_dup(conn->sock);
581 silc_client_command_pending(conn, SILC_COMMAND_NONE,
582 client_entry->resolve_cmd_ident,
583 silc_client_notify_by_server_pending, res);
587 client_entry->valid = FALSE;
589 /* Get new Client ID */
590 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
594 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
598 /* From protocol version 1.1 we get the new nickname in notify as well,
599 so we don't have to resolve it. Do it the hard way if server doesn't
601 tmp = silc_argument_get_arg_type(args, 3, NULL);
603 /* Protocol version 1.1 */
604 char *tmp_nick = NULL;
606 /* Check whether nickname changed at all. It is possible that nick
607 change notify is received but nickname didn't changed, only the
609 if (client->internal->params->nickname_parse)
610 client->internal->params->nickname_parse(client_entry->nickname,
613 tmp_nick = strdup(tmp);
615 if (tmp_nick && !strcmp(tmp, tmp_nick)) {
616 /* Nickname didn't change. Update only the ID */
617 silc_idcache_del_by_context(conn->client_cache, client_entry);
618 silc_free(client_entry->id);
619 client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
620 silc_idcache_add(conn->client_cache, strdup(tmp),
621 client_entry->id, client_entry, 0, NULL);
623 /* Notify application */
624 client->internal->ops->notify(client, conn, type,
625 client_entry, client_entry);
630 /* Create new client entry, and save all old information with the
631 new nickname and client ID */
632 client_entry2 = silc_client_add_client(client, conn, NULL, NULL,
633 client_entry->realname,
634 silc_id_dup(client_id,
639 if (client_entry->server)
640 client_entry2->server = strdup(client_entry->server);
641 if (client_entry->username)
642 client_entry2->username = strdup(client_entry->username);
643 if (client_entry->hostname)
644 client_entry2->hostname = strdup(client_entry->hostname);
645 silc_client_update_client(client, conn, client_entry2, tmp, NULL, NULL,
648 /* Protocol version 1.0 */
650 /* Find client entry and if not found resolve it */
651 client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
652 if (!client_entry2) {
653 /* Resolve the entry information */
654 silc_client_notify_by_server_resolve(client, conn, packet,
655 SILC_ID_CLIENT, client_id);
657 /* Add the new entry even though we resolved it. This is because we
658 want to replace the old entry with the new entry here right now. */
660 silc_client_add_client(client, conn, NULL, NULL, NULL,
661 silc_id_dup(client_id, SILC_ID_CLIENT),
664 /* Replace old ID entry with new one on all channels. */
665 silc_client_replace_from_channels(client, conn, client_entry,
670 if (client_entry2 != conn->local_entry)
671 silc_client_nickname_format(client, conn, client_entry2);
674 /* Remove the old from cache */
675 silc_idcache_del_by_context(conn->client_cache, client_entry);
677 /* Replace old ID entry with new one on all channels. */
678 silc_client_replace_from_channels(client, conn, client_entry,
681 /* Notify application */
682 client->internal->ops->notify(client, conn, type,
683 client_entry, client_entry2);
685 /* Free old client entry */
686 silc_client_del_client_entry(client, conn, client_entry);
690 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
692 * Someone changed a channel mode
695 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
697 /* Get channel entry */
698 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
702 channel = silc_client_get_channel_by_id(client, conn, channel_id);
707 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
710 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
714 /* Find Client entry */
715 if (id_type == SILC_ID_CLIENT) {
716 /* Find Client entry */
718 client_entry = silc_client_get_client_by_id(client, conn, client_id);
720 silc_client_channel_set_wait(client, conn, channel,
721 conn->cmd_ident + 1);
722 silc_client_notify_by_server_resolve(client, conn, packet,
723 SILC_ID_CLIENT, client_id);
726 } else if (id_type == SILC_ID_SERVER) {
727 /* Find Server entry */
729 server = silc_client_get_server_by_id(client, conn, server_id);
731 silc_client_channel_set_wait(client, conn, channel,
732 conn->cmd_ident + 1);
733 silc_client_notify_by_server_resolve(client, conn, packet,
734 SILC_ID_SERVER, server_id);
735 server = silc_client_add_server(client, conn, NULL, NULL, server_id);
739 server->resolve_cmd_ident = conn->cmd_ident;
744 /* If entry being resoled, wait for it before processing this notify */
745 if (server->resolve_cmd_ident) {
746 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
747 res->packet = silc_packet_context_dup(packet);
748 res->context = client;
749 res->sock = silc_socket_dup(conn->sock);
750 silc_client_command_pending(conn, SILC_COMMAND_NONE,
751 server->resolve_cmd_ident,
752 silc_client_notify_by_server_pending, res);
756 /* Save the pointer to the client_entry pointer */
757 client_entry = (SilcClientEntry)server;
759 /* Find Channel entry */
760 silc_free(channel_id);
762 client_entry = (SilcClientEntry)
763 silc_client_get_channel_by_id(client, conn, channel_id);
765 silc_client_channel_set_wait(client, conn, channel,
766 conn->cmd_ident + 1);
767 silc_client_notify_by_server_resolve(client, conn, packet,
768 SILC_ID_CHANNEL, channel_id);
774 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
778 SILC_GET32_MSB(mode, tmp);
780 /* If information is being resolved for this channel, wait for it */
781 if (channel->resolve_cmd_ident) {
782 silc_client_channel_wait(client, conn, channel, packet);
786 /* Save the new mode */
787 channel->mode = mode;
790 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
792 unsigned char hash[32];
795 silc_hmac_free(channel->hmac);
796 if (!silc_hmac_alloc(tmp, NULL, &channel->hmac))
799 silc_hash_make(silc_hmac_get_hash(channel->hmac),
800 channel->key, channel->key_len / 8,
802 silc_hmac_set_key(channel->hmac, hash,
803 silc_hash_len(silc_hmac_get_hash(channel->hmac)));
804 memset(hash, 0, sizeof(hash));
807 /* Notify application. The channel entry is sent last as this notify
808 is for channel but application don't know it from the arguments
810 client->internal->ops->notify(client, conn, type, id_type,
811 client_entry, mode, NULL, tmp, channel);
814 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
816 * Someone changed user's mode on a channel
819 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
821 /* Get channel entry */
822 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
826 channel = silc_client_get_channel_by_id(client, conn, channel_id);
831 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
834 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
838 /* Find Client entry */
839 if (id_type == SILC_ID_CLIENT) {
840 /* Find Client entry */
842 client_entry = silc_client_get_client_by_id(client, conn, client_id);
844 silc_client_channel_set_wait(client, conn, channel,
845 conn->cmd_ident + 1);
846 silc_client_notify_by_server_resolve(client, conn, packet,
847 SILC_ID_CLIENT, client_id);
850 } else if (id_type == SILC_ID_SERVER) {
851 /* Find Server entry */
853 server = silc_client_get_server_by_id(client, conn, server_id);
855 silc_client_channel_set_wait(client, conn, channel,
856 conn->cmd_ident + 1);
857 silc_client_notify_by_server_resolve(client, conn, packet,
858 SILC_ID_SERVER, server_id);
859 server = silc_client_add_server(client, conn, NULL, NULL, server_id);
863 server->resolve_cmd_ident = conn->cmd_ident;
868 /* If entry being resoled, wait for it before processing this notify */
869 if (server->resolve_cmd_ident) {
870 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
871 res->packet = silc_packet_context_dup(packet);
872 res->context = client;
873 res->sock = silc_socket_dup(conn->sock);
874 silc_client_command_pending(conn, SILC_COMMAND_NONE,
875 server->resolve_cmd_ident,
876 silc_client_notify_by_server_pending, res);
880 /* Save the pointer to the client_entry pointer */
881 client_entry = (SilcClientEntry)server;
883 /* Find Channel entry */
884 silc_free(channel_id);
886 client_entry = (SilcClientEntry)
887 silc_client_get_channel_by_id(client, conn, channel_id);
889 silc_client_channel_set_wait(client, conn, channel,
890 conn->cmd_ident + 1);
891 silc_client_notify_by_server_resolve(client, conn, packet,
892 SILC_ID_CHANNEL, channel_id);
898 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
902 SILC_GET32_MSB(mode, tmp);
904 /* If information is being resolved for this channel, wait for it */
905 if (channel->resolve_cmd_ident) {
906 silc_client_channel_wait(client, conn, channel, packet);
910 /* Get target Client ID */
911 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
915 silc_free(client_id);
916 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
920 /* Find target Client entry */
922 silc_client_get_client_by_id(client, conn, client_id);
923 if (!client_entry2) {
924 silc_client_notify_by_server_resolve(client, conn, packet,
925 SILC_ID_CLIENT, client_id);
930 chu = silc_client_on_channel(channel, client_entry2);
934 /* Notify application. The channel entry is sent last as this notify
935 is for channel but application don't know it from the arguments
937 client->internal->ops->notify(client, conn, type,
938 id_type, client_entry, mode,
939 client_entry2, channel);
942 case SILC_NOTIFY_TYPE_MOTD:
944 * Received Message of the day
947 SILC_LOG_DEBUG(("Notify: MOTD"));
950 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
954 /* Notify application */
955 client->internal->ops->notify(client, conn, type, tmp);
958 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
960 * Router has enforced a new ID to a channel. Let's change the old
961 * ID to the one provided here.
964 SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
967 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
970 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
974 /* Get the channel entry */
975 channel = silc_client_get_channel_by_id(client, conn, channel_id);
979 silc_free(channel_id);
982 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
985 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
989 /* Replace the Channel ID */
990 if (silc_client_replace_channel_id(client, conn, channel, channel_id))
993 /* Notify application */
994 client->internal->ops->notify(client, conn, type, channel, channel);
997 case SILC_NOTIFY_TYPE_KICKED:
999 * A client (maybe me) was kicked from a channel
1002 SILC_LOG_DEBUG(("Notify: KICKED"));
1005 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1009 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1013 /* Find Client entry */
1014 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1018 /* Get channel entry */
1019 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
1023 channel = silc_client_get_channel_by_id(client, conn, channel_id);
1027 /* From protocol version 1.1 we get the kicker's client ID as well */
1028 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1030 silc_free(client_id);
1031 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1035 /* Find kicker's client entry and if not found resolve it */
1036 client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
1037 if (!client_entry2) {
1038 silc_client_notify_by_server_resolve(client, conn, packet,
1039 SILC_ID_CLIENT, client_id);
1042 if (client_entry2 != conn->local_entry)
1043 silc_client_nickname_format(client, conn, client_entry2);
1048 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1050 /* Notify application. The channel entry is sent last as this notify
1051 is for channel but application don't know it from the arguments
1053 client->internal->ops->notify(client, conn, type, client_entry, tmp,
1054 client_entry2, channel);
1056 /* Remove kicked client from channel */
1057 if (client_entry == conn->local_entry) {
1058 /* If I was kicked from channel, remove the channel */
1059 if (conn->current_channel == channel)
1060 conn->current_channel = NULL;
1061 silc_client_del_channel(client, conn, channel);
1063 chu = silc_client_on_channel(channel, client_entry);
1065 silc_hash_table_del(client_entry->channels, channel);
1066 silc_hash_table_del(channel->user_list, client_entry);
1070 if (!silc_hash_table_count(client_entry->channels)) {
1071 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1072 res->context = client;
1073 res->sock = silc_socket_dup(conn->sock);
1074 res->packet = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1075 silc_schedule_task_add(client->schedule, conn->sock->sock,
1076 silc_client_notify_check_client, res,
1077 (5 + (silc_rng_get_rn16(client->rng) % 529)),
1078 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1083 case SILC_NOTIFY_TYPE_KILLED:
1086 * A client (maybe me) was killed from the network.
1089 SilcUInt32 comment_len;
1091 SILC_LOG_DEBUG(("Notify: KILLED"));
1094 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1098 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1102 /* Find Client entry */
1103 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1108 comment = silc_argument_get_arg_type(args, 2, &comment_len);
1110 /* From protocol version 1.1 we get killer's client ID as well */
1111 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1113 silc_free(client_id);
1114 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
1118 /* Find Client entry */
1119 if (id_type == SILC_ID_CLIENT) {
1120 /* Find Client entry */
1122 client_entry2 = silc_client_get_client_by_id(client, conn,
1124 if (!client_entry) {
1125 silc_client_notify_by_server_resolve(client, conn, packet,
1126 SILC_ID_CLIENT, client_id);
1129 } else if (id_type == SILC_ID_SERVER) {
1130 /* Find Server entry */
1132 server = silc_client_get_server_by_id(client, conn, server_id);
1134 silc_client_notify_by_server_resolve(client, conn, packet,
1135 SILC_ID_SERVER, server_id);
1136 server = silc_client_add_server(client, conn, NULL, NULL,
1141 server->resolve_cmd_ident = conn->cmd_ident;
1146 if (server->resolve_cmd_ident) {
1147 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1148 res->packet = silc_packet_context_dup(packet);
1149 res->context = client;
1150 res->sock = silc_socket_dup(conn->sock);
1151 silc_client_command_pending(conn, SILC_COMMAND_NONE,
1152 server->resolve_cmd_ident,
1153 silc_client_notify_by_server_pending,
1158 /* Save the pointer to the client_entry pointer */
1159 client_entry2 = (SilcClientEntry)server;
1161 /* Find Channel entry */
1163 channel = silc_client_get_channel_by_id(client, conn, channel_id);
1165 silc_client_notify_by_server_resolve(client, conn, packet,
1166 SILC_ID_CHANNEL, channel_id);
1170 /* Save the pointer to the client_entry pointer */
1171 client_entry2 = (SilcClientEntry)channel;
1172 silc_free(channel_id);
1177 /* Notify application. */
1178 client->internal->ops->notify(client, conn, type, client_entry,
1179 comment, id_type, client_entry2);
1181 if (client_entry != conn->local_entry)
1182 /* Remove the client from all channels and free it */
1183 silc_client_del_client(client, conn, client_entry);
1187 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
1190 * A server quit the SILC network and some clients must be removed
1191 * from channels as they quit as well.
1193 SilcClientEntry *clients = NULL;
1194 SilcUInt32 clients_count = 0;
1197 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
1199 for (i = 1; i < silc_argument_get_arg_num(args); i++) {
1201 tmp = silc_argument_get_arg_type(args, i + 1, &tmp_len);
1203 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1207 /* Get the client entry */
1208 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1210 clients = silc_realloc(clients, sizeof(*clients) *
1211 (clients_count + 1));
1212 clients[clients_count] = client_entry;
1215 silc_free(client_id);
1220 /* Notify application. We don't keep server entries so the server
1221 entry is returned as NULL. The client's are returned as array
1222 of SilcClientEntry pointers. */
1223 client->internal->ops->notify(client, conn, type, NULL,
1224 clients, clients_count);
1226 for (i = 0; i < clients_count; i++) {
1227 /* Remove client from all channels */
1228 client_entry = clients[i];
1229 if (client_entry == conn->local_entry)
1232 /* Remove the client from all channels and free it */
1233 silc_client_del_client(client, conn, client_entry);
1240 case SILC_NOTIFY_TYPE_ERROR:
1243 * Some has occurred and server is notifying us about it.
1247 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1248 if (!tmp && tmp_len != 1)
1250 error = (SilcStatus)tmp[0];
1252 SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1254 if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1255 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1257 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1260 client_entry = silc_client_get_client_by_id(client, conn,
1263 silc_client_del_client(client, conn, client_entry);
1267 /* Notify application. */
1268 client->internal->ops->notify(client, conn, type, error);
1272 case SILC_NOTIFY_TYPE_WATCH:
1275 * Received notify about some client we are watching
1277 SilcNotifyType notify = 0;
1278 bool del_client = FALSE;
1280 SILC_LOG_DEBUG(("Notify: WATCH"));
1282 /* Get sender Client ID */
1283 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1286 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1290 /* Find Client entry and if not found query it */
1291 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1292 if (!client_entry) {
1293 silc_client_notify_by_server_resolve(client, conn, packet,
1294 SILC_ID_CLIENT, client_id);
1299 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1300 if (!tmp || tmp_len != 4)
1302 SILC_GET32_MSB(mode, tmp);
1304 /* Get notify type */
1305 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1306 if (tmp && tmp_len != 2)
1309 SILC_GET16_MSB(notify, tmp);
1312 tmp = silc_argument_get_arg_type(args, 2, NULL);
1314 char *tmp_nick = NULL;
1316 if (client->internal->params->nickname_parse)
1317 client->internal->params->nickname_parse(client_entry->nickname,
1320 tmp_nick = strdup(tmp);
1322 /* If same nick, the client was new to us and has become "present"
1323 to network. Send NULL as nick to application. */
1324 if (tmp_nick && !strcmp(tmp, tmp_nick))
1327 silc_free(tmp_nick);
1330 /* Notify application. */
1331 client->internal->ops->notify(client, conn, type, client_entry,
1334 client_entry->mode = mode;
1336 /* If nickname was changed, remove the client entry unless the
1337 client is on some channel */
1338 if (tmp && notify == SILC_NOTIFY_TYPE_NICK_CHANGE &&
1339 !silc_hash_table_count(client_entry->channels))
1341 else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1342 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
1343 notify == SILC_NOTIFY_TYPE_KILLED)
1347 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1348 res->context = client;
1349 res->sock = silc_socket_dup(conn->sock);
1350 res->packet = client_id;
1352 silc_schedule_task_add(client->schedule, conn->sock->sock,
1353 silc_client_notify_del_client_cb, res,
1354 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1364 silc_notify_payload_free(payload);
1365 silc_free(client_id);
1366 silc_free(channel_id);
1367 silc_free(server_id);