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);
576 /* Wait for resolving if necessary */
577 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
578 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
579 res->packet = silc_packet_context_dup(packet);
580 res->context = client;
581 res->sock = silc_socket_dup(conn->sock);
582 silc_client_command_pending(conn, SILC_COMMAND_NONE,
583 client_entry->resolve_cmd_ident,
584 silc_client_notify_by_server_pending, res);
588 client_entry->valid = FALSE;
590 /* Get new Client ID */
591 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
595 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
599 /* From protocol version 1.1 we get the new nickname in notify as well,
600 so we don't have to resolve it. Do it the hard way if server doesn't
602 tmp = silc_argument_get_arg_type(args, 3, NULL);
604 /* Protocol version 1.1 */
605 char *tmp_nick = NULL;
607 /* Check whether nickname changed at all. It is possible that nick
608 change notify is received but nickname didn't changed, only the
610 if (client->internal->params->nickname_parse)
611 client->internal->params->nickname_parse(client_entry->nickname,
614 tmp_nick = strdup(tmp);
616 if (tmp_nick && !strcmp(tmp, tmp_nick)) {
617 /* Nickname didn't change. Update only the ID */
618 silc_idcache_del_by_context(conn->internal->client_cache,
620 silc_free(client_entry->id);
621 client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
622 silc_idcache_add(conn->internal->client_cache, strdup(tmp),
623 client_entry->id, client_entry, 0, NULL);
625 /* Notify application */
626 client->internal->ops->notify(client, conn, type,
627 client_entry, client_entry);
632 /* Create new client entry, and save all old information with the
633 new nickname and client ID */
634 client_entry2 = silc_client_add_client(client, conn, NULL, NULL,
635 client_entry->realname,
636 silc_id_dup(client_id,
641 if (client_entry->server)
642 client_entry2->server = strdup(client_entry->server);
643 if (client_entry->username)
644 client_entry2->username = strdup(client_entry->username);
645 if (client_entry->hostname)
646 client_entry2->hostname = strdup(client_entry->hostname);
647 silc_client_update_client(client, conn, client_entry2, tmp, NULL, NULL,
650 /* Protocol version 1.0 */
652 /* Find client entry and if not found resolve it */
653 client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
654 if (!client_entry2) {
655 /* Resolve the entry information */
656 silc_client_notify_by_server_resolve(client, conn, packet,
657 SILC_ID_CLIENT, client_id);
659 /* Add the new entry even though we resolved it. This is because we
660 want to replace the old entry with the new entry here right now. */
662 silc_client_add_client(client, conn, NULL, NULL, NULL,
663 silc_id_dup(client_id, SILC_ID_CLIENT),
666 /* Replace old ID entry with new one on all channels. */
667 silc_client_replace_from_channels(client, conn, client_entry,
672 if (client_entry2 != conn->local_entry)
673 silc_client_nickname_format(client, conn, client_entry2);
676 /* Remove the old from cache */
677 silc_idcache_del_by_context(conn->internal->client_cache, client_entry);
679 /* Replace old ID entry with new one on all channels. */
680 silc_client_replace_from_channels(client, conn, client_entry,
683 /* Notify application */
684 client->internal->ops->notify(client, conn, type,
685 client_entry, client_entry2);
687 /* Free old client entry */
688 silc_client_del_client_entry(client, conn, client_entry);
692 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
694 * Someone changed a channel mode
697 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
699 /* Get channel entry */
700 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
704 channel = silc_client_get_channel_by_id(client, conn, channel_id);
709 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
712 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
716 /* Find Client entry */
717 if (id_type == SILC_ID_CLIENT) {
718 /* Find Client entry */
720 client_entry = silc_client_get_client_by_id(client, conn, client_id);
722 silc_client_channel_set_wait(client, conn, channel,
723 conn->cmd_ident + 1);
724 silc_client_notify_by_server_resolve(client, conn, packet,
725 SILC_ID_CLIENT, client_id);
729 if (!client_entry->nickname) {
730 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
731 /* Attach to existing resolving */
732 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
733 res->packet = silc_packet_context_dup(packet);
734 res->context = client;
735 res->sock = silc_socket_dup(conn->sock);
736 silc_client_command_pending(conn, SILC_COMMAND_NONE,
737 client_entry->resolve_cmd_ident,
738 silc_client_notify_by_server_pending,
743 /* Do new resolving */
744 silc_client_channel_set_wait(client, conn, channel,
745 conn->cmd_ident + 1);
746 silc_client_notify_by_server_resolve(client, conn, packet,
747 SILC_ID_CLIENT, client_id);
750 } else if (id_type == SILC_ID_SERVER) {
751 /* Find Server entry */
753 server = silc_client_get_server_by_id(client, conn, server_id);
755 silc_client_channel_set_wait(client, conn, channel,
756 conn->cmd_ident + 1);
757 silc_client_notify_by_server_resolve(client, conn, packet,
758 SILC_ID_SERVER, server_id);
759 server = silc_client_add_server(client, conn, NULL, NULL, server_id);
763 server->resolve_cmd_ident = conn->cmd_ident;
768 /* If entry being resoled, wait for it before processing this notify */
769 if (server->resolve_cmd_ident) {
770 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
771 res->packet = silc_packet_context_dup(packet);
772 res->context = client;
773 res->sock = silc_socket_dup(conn->sock);
774 silc_client_command_pending(conn, SILC_COMMAND_NONE,
775 server->resolve_cmd_ident,
776 silc_client_notify_by_server_pending, res);
780 /* Save the pointer to the client_entry pointer */
781 client_entry = (SilcClientEntry)server;
783 /* Find Channel entry */
784 silc_free(channel_id);
786 client_entry = (SilcClientEntry)
787 silc_client_get_channel_by_id(client, conn, channel_id);
789 silc_client_channel_set_wait(client, conn, channel,
790 conn->cmd_ident + 1);
791 silc_client_notify_by_server_resolve(client, conn, packet,
792 SILC_ID_CHANNEL, channel_id);
798 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
802 SILC_GET32_MSB(mode, tmp);
804 /* If information is being resolved for this channel, wait for it */
805 if (channel->resolve_cmd_ident) {
806 silc_client_channel_wait(client, conn, channel, packet);
810 /* Save the new mode */
811 channel->mode = mode;
814 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
816 unsigned char hash[32];
819 silc_hmac_free(channel->hmac);
820 if (!silc_hmac_alloc(tmp, NULL, &channel->hmac))
823 silc_hash_make(silc_hmac_get_hash(channel->hmac),
824 channel->key, channel->key_len / 8,
826 silc_hmac_set_key(channel->hmac, hash,
827 silc_hash_len(silc_hmac_get_hash(channel->hmac)));
828 memset(hash, 0, sizeof(hash));
831 /* Notify application. The channel entry is sent last as this notify
832 is for channel but application don't know it from the arguments
834 client->internal->ops->notify(client, conn, type, id_type,
835 client_entry, mode, NULL, tmp, channel);
838 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
840 * Someone changed user's mode on a channel
843 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
845 /* Get channel entry */
846 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
850 channel = silc_client_get_channel_by_id(client, conn, channel_id);
855 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
858 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
862 /* Find Client entry */
863 if (id_type == SILC_ID_CLIENT) {
864 /* Find Client entry */
866 client_entry = silc_client_get_client_by_id(client, conn, client_id);
868 silc_client_channel_set_wait(client, conn, channel,
869 conn->cmd_ident + 1);
870 silc_client_notify_by_server_resolve(client, conn, packet,
871 SILC_ID_CLIENT, client_id);
875 if (!client_entry->nickname) {
876 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
877 /* Attach to existing resolving */
878 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
879 res->packet = silc_packet_context_dup(packet);
880 res->context = client;
881 res->sock = silc_socket_dup(conn->sock);
882 silc_client_command_pending(conn, SILC_COMMAND_NONE,
883 client_entry->resolve_cmd_ident,
884 silc_client_notify_by_server_pending,
889 /* Do new resolving */
890 silc_client_channel_set_wait(client, conn, channel,
891 conn->cmd_ident + 1);
892 silc_client_notify_by_server_resolve(client, conn, packet,
893 SILC_ID_CLIENT, client_id);
896 } else if (id_type == SILC_ID_SERVER) {
897 /* Find Server entry */
899 server = silc_client_get_server_by_id(client, conn, server_id);
901 silc_client_channel_set_wait(client, conn, channel,
902 conn->cmd_ident + 1);
903 silc_client_notify_by_server_resolve(client, conn, packet,
904 SILC_ID_SERVER, server_id);
905 server = silc_client_add_server(client, conn, NULL, NULL, server_id);
909 server->resolve_cmd_ident = conn->cmd_ident;
914 /* If entry being resoled, wait for it before processing this notify */
915 if (server->resolve_cmd_ident) {
916 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
917 res->packet = silc_packet_context_dup(packet);
918 res->context = client;
919 res->sock = silc_socket_dup(conn->sock);
920 silc_client_command_pending(conn, SILC_COMMAND_NONE,
921 server->resolve_cmd_ident,
922 silc_client_notify_by_server_pending, res);
926 /* Save the pointer to the client_entry pointer */
927 client_entry = (SilcClientEntry)server;
929 /* Find Channel entry */
930 silc_free(channel_id);
932 client_entry = (SilcClientEntry)
933 silc_client_get_channel_by_id(client, conn, channel_id);
935 silc_client_channel_set_wait(client, conn, channel,
936 conn->cmd_ident + 1);
937 silc_client_notify_by_server_resolve(client, conn, packet,
938 SILC_ID_CHANNEL, channel_id);
944 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
948 SILC_GET32_MSB(mode, tmp);
950 /* If information is being resolved for this channel, wait for it */
951 if (channel->resolve_cmd_ident) {
952 silc_client_channel_wait(client, conn, channel, packet);
956 /* Get target Client ID */
957 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
961 silc_free(client_id);
962 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
966 /* Find target Client entry */
968 silc_client_get_client_by_id(client, conn, client_id);
969 if (!client_entry2) {
970 silc_client_notify_by_server_resolve(client, conn, packet,
971 SILC_ID_CLIENT, client_id);
976 chu = silc_client_on_channel(channel, client_entry2);
980 /* Notify application. The channel entry is sent last as this notify
981 is for channel but application don't know it from the arguments
983 client->internal->ops->notify(client, conn, type,
984 id_type, client_entry, mode,
985 client_entry2, channel);
988 case SILC_NOTIFY_TYPE_MOTD:
990 * Received Message of the day
993 SILC_LOG_DEBUG(("Notify: MOTD"));
996 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1000 /* Notify application */
1001 client->internal->ops->notify(client, conn, type, tmp);
1004 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
1006 * Router has enforced a new ID to a channel. Let's change the old
1007 * ID to the one provided here.
1010 SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
1012 /* Get the old ID */
1013 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1016 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1020 /* Get the channel entry */
1021 channel = silc_client_get_channel_by_id(client, conn, channel_id);
1025 silc_free(channel_id);
1027 /* Get the new ID */
1028 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1031 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1035 /* Replace the Channel ID */
1036 if (silc_client_replace_channel_id(client, conn, channel, channel_id))
1039 /* Notify application */
1040 client->internal->ops->notify(client, conn, type, channel, channel);
1043 case SILC_NOTIFY_TYPE_KICKED:
1045 * A client (maybe me) was kicked from a channel
1048 SILC_LOG_DEBUG(("Notify: KICKED"));
1051 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1055 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1059 /* Find Client entry */
1060 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1064 /* Get channel entry */
1065 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
1069 channel = silc_client_get_channel_by_id(client, conn, channel_id);
1073 /* From protocol version 1.1 we get the kicker's client ID as well */
1074 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1076 silc_free(client_id);
1077 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1081 /* Find kicker's client entry and if not found resolve it */
1082 client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
1083 if (!client_entry2) {
1084 silc_client_notify_by_server_resolve(client, conn, packet,
1085 SILC_ID_CLIENT, client_id);
1088 if (client_entry2 != conn->local_entry)
1089 silc_client_nickname_format(client, conn, client_entry2);
1094 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1096 /* Notify application. The channel entry is sent last as this notify
1097 is for channel but application don't know it from the arguments
1099 client->internal->ops->notify(client, conn, type, client_entry, tmp,
1100 client_entry2, channel);
1102 /* Remove kicked client from channel */
1103 if (client_entry == conn->local_entry) {
1104 /* If I was kicked from channel, remove the channel */
1105 if (conn->current_channel == channel)
1106 conn->current_channel = NULL;
1107 silc_client_del_channel(client, conn, channel);
1109 chu = silc_client_on_channel(channel, client_entry);
1111 silc_hash_table_del(client_entry->channels, channel);
1112 silc_hash_table_del(channel->user_list, client_entry);
1116 if (!silc_hash_table_count(client_entry->channels)) {
1117 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1118 res->context = client;
1119 res->sock = silc_socket_dup(conn->sock);
1120 res->packet = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1121 silc_schedule_task_add(client->schedule, conn->sock->sock,
1122 silc_client_notify_check_client, res,
1123 (5 + (silc_rng_get_rn16(client->rng) % 529)),
1124 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1129 case SILC_NOTIFY_TYPE_KILLED:
1132 * A client (maybe me) was killed from the network.
1135 SilcUInt32 comment_len;
1137 SILC_LOG_DEBUG(("Notify: KILLED"));
1140 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1144 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1148 /* Find Client entry */
1149 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1154 comment = silc_argument_get_arg_type(args, 2, &comment_len);
1156 /* From protocol version 1.1 we get killer's client ID as well */
1157 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1159 silc_free(client_id);
1160 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
1164 /* Find Client entry */
1165 if (id_type == SILC_ID_CLIENT) {
1166 /* Find Client entry */
1168 client_entry2 = silc_client_get_client_by_id(client, conn,
1170 if (!client_entry) {
1171 silc_client_notify_by_server_resolve(client, conn, packet,
1172 SILC_ID_CLIENT, client_id);
1175 } else if (id_type == SILC_ID_SERVER) {
1176 /* Find Server entry */
1178 server = silc_client_get_server_by_id(client, conn, server_id);
1180 silc_client_notify_by_server_resolve(client, conn, packet,
1181 SILC_ID_SERVER, server_id);
1182 server = silc_client_add_server(client, conn, NULL, NULL,
1187 server->resolve_cmd_ident = conn->cmd_ident;
1192 if (server->resolve_cmd_ident) {
1193 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1194 res->packet = silc_packet_context_dup(packet);
1195 res->context = client;
1196 res->sock = silc_socket_dup(conn->sock);
1197 silc_client_command_pending(conn, SILC_COMMAND_NONE,
1198 server->resolve_cmd_ident,
1199 silc_client_notify_by_server_pending,
1204 /* Save the pointer to the client_entry pointer */
1205 client_entry2 = (SilcClientEntry)server;
1207 /* Find Channel entry */
1209 channel = silc_client_get_channel_by_id(client, conn, channel_id);
1211 silc_client_notify_by_server_resolve(client, conn, packet,
1212 SILC_ID_CHANNEL, channel_id);
1216 /* Save the pointer to the client_entry pointer */
1217 client_entry2 = (SilcClientEntry)channel;
1218 silc_free(channel_id);
1223 /* Notify application. */
1224 client->internal->ops->notify(client, conn, type, client_entry,
1225 comment, id_type, client_entry2);
1227 if (client_entry != conn->local_entry)
1228 /* Remove the client from all channels and free it */
1229 silc_client_del_client(client, conn, client_entry);
1233 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
1236 * A server quit the SILC network and some clients must be removed
1237 * from channels as they quit as well.
1239 SilcClientEntry *clients = NULL;
1240 SilcUInt32 clients_count = 0;
1243 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
1245 for (i = 1; i < silc_argument_get_arg_num(args); i++) {
1247 tmp = silc_argument_get_arg_type(args, i + 1, &tmp_len);
1249 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1253 /* Get the client entry */
1254 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1256 clients = silc_realloc(clients, sizeof(*clients) *
1257 (clients_count + 1));
1258 clients[clients_count] = client_entry;
1261 silc_free(client_id);
1266 /* Notify application. We don't keep server entries so the server
1267 entry is returned as NULL. The client's are returned as array
1268 of SilcClientEntry pointers. */
1269 client->internal->ops->notify(client, conn, type, NULL,
1270 clients, clients_count);
1272 for (i = 0; i < clients_count; i++) {
1273 /* Remove client from all channels */
1274 client_entry = clients[i];
1275 if (client_entry == conn->local_entry)
1278 /* Remove the client from all channels and free it */
1279 silc_client_del_client(client, conn, client_entry);
1286 case SILC_NOTIFY_TYPE_ERROR:
1289 * Some has occurred and server is notifying us about it.
1293 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1294 if (!tmp && tmp_len != 1)
1296 error = (SilcStatus)tmp[0];
1298 SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1300 if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1301 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1303 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1306 client_entry = silc_client_get_client_by_id(client, conn,
1309 silc_client_del_client(client, conn, client_entry);
1313 /* Notify application. */
1314 client->internal->ops->notify(client, conn, type, error);
1318 case SILC_NOTIFY_TYPE_WATCH:
1321 * Received notify about some client we are watching
1323 SilcNotifyType notify = 0;
1324 bool del_client = FALSE;
1326 SILC_LOG_DEBUG(("Notify: WATCH"));
1328 /* Get sender Client ID */
1329 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1332 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1336 /* Find Client entry and if not found query it */
1337 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1338 if (!client_entry) {
1339 silc_client_notify_by_server_resolve(client, conn, packet,
1340 SILC_ID_CLIENT, client_id);
1345 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1346 if (!tmp || tmp_len != 4)
1348 SILC_GET32_MSB(mode, tmp);
1350 /* Get notify type */
1351 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1352 if (tmp && tmp_len != 2)
1355 SILC_GET16_MSB(notify, tmp);
1358 tmp = silc_argument_get_arg_type(args, 2, NULL);
1360 char *tmp_nick = NULL;
1362 if (client->internal->params->nickname_parse)
1363 client->internal->params->nickname_parse(client_entry->nickname,
1366 tmp_nick = strdup(tmp);
1368 /* If same nick, the client was new to us and has become "present"
1369 to network. Send NULL as nick to application. */
1370 if (tmp_nick && !strcmp(tmp, tmp_nick))
1373 silc_free(tmp_nick);
1376 /* Notify application. */
1377 client->internal->ops->notify(client, conn, type, client_entry,
1380 client_entry->mode = mode;
1382 /* If nickname was changed, remove the client entry unless the
1383 client is on some channel */
1384 if (tmp && notify == SILC_NOTIFY_TYPE_NICK_CHANGE &&
1385 !silc_hash_table_count(client_entry->channels))
1387 else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1388 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
1389 notify == SILC_NOTIFY_TYPE_KILLED)
1393 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1394 res->context = client;
1395 res->sock = silc_socket_dup(conn->sock);
1396 res->packet = client_id;
1398 silc_schedule_task_add(client->schedule, conn->sock->sock,
1399 silc_client_notify_del_client_cb, res,
1400 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1410 silc_notify_payload_free(payload);
1411 silc_free(client_id);
1412 silc_free(channel_id);
1413 silc_free(server_id);