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 /* Called when notify is received and some async operation (such as command)
48 is required before processing the notify message. This calls again the
49 silc_client_notify_by_server and reprocesses the original notify packet. */
51 static void silc_client_notify_by_server_pending(void *context, void *context2)
53 SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
54 SilcClientCommandReplyContext reply =
55 (SilcClientCommandReplyContext)context2;
57 SILC_LOG_DEBUG(("Start"));
59 if (reply && !silc_command_get_status(reply->payload, NULL, NULL))
62 silc_client_notify_by_server(res->context, res->sock, res->packet);
65 silc_socket_free(res->sock);
66 silc_packet_context_free(res->packet);
70 /* Resolve client, channel or server information. */
72 static void silc_client_notify_by_server_resolve(SilcClient client,
73 SilcClientConnection conn,
74 SilcPacketContext *packet,
78 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
79 SilcBuffer idp = silc_id_payload_encode(id, id_type);
81 res->packet = silc_packet_context_dup(packet);
82 res->context = client;
83 res->sock = silc_socket_dup(conn->sock);
85 /* For client resolving use WHOIS, and otherwise use IDENTIFY */
86 if (id_type == SILC_ID_CLIENT) {
87 silc_client_command_register(client, SILC_COMMAND_WHOIS, NULL, NULL,
88 silc_client_command_reply_whois_i, 0,
90 silc_client_command_send(client, conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
91 1, 4, idp->data, idp->len);
92 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
93 silc_client_notify_by_server_pending, res);
95 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
96 silc_client_command_reply_identify_i, 0,
98 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
99 conn->cmd_ident, 1, 5, idp->data, idp->len);
100 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
101 silc_client_notify_by_server_pending, res);
103 silc_buffer_free(idp);
106 /* Received notify message from server */
108 void silc_client_notify_by_server(SilcClient client,
109 SilcSocketConnection sock,
110 SilcPacketContext *packet)
112 SilcBuffer buffer = packet->buffer;
113 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
114 SilcNotifyPayload payload;
116 SilcArgumentPayload args;
120 SilcClientID *client_id = NULL;
121 SilcChannelID *channel_id = NULL;
122 SilcServerID *server_id = NULL;
123 SilcClientEntry client_entry = NULL;
124 SilcClientEntry client_entry2 = NULL;
125 SilcChannelEntry channel;
127 SilcServerEntry server;
129 SilcUInt32 tmp_len, mode;
131 SILC_LOG_DEBUG(("Start"));
133 payload = silc_notify_payload_parse(buffer->data, buffer->len);
137 type = silc_notify_get_type(payload);
138 args = silc_notify_get_args(payload);
143 case SILC_NOTIFY_TYPE_NONE:
144 /* Notify application */
145 client->internal->ops->notify(client, conn, type,
146 silc_argument_get_arg_type(args, 1, NULL));
149 case SILC_NOTIFY_TYPE_INVITE:
151 * Someone invited me to a channel. Find Client and Channel entries
152 * for the application.
155 SILC_LOG_DEBUG(("Notify: INVITE"));
158 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
162 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
166 /* Get the channel entry */
167 channel = silc_client_get_channel_by_id(client, conn, channel_id);
169 /* Get sender Client ID */
170 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
174 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
178 /* Find Client entry and if not found query it */
179 client_entry = silc_client_get_client_by_id(client, conn, client_id);
181 silc_client_notify_by_server_resolve(client, conn, packet,
182 SILC_ID_CLIENT, client_id);
186 /* Get the channel name */
187 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
191 /* Notify application */
192 client->internal->ops->notify(client, conn, type, channel, tmp,
196 case SILC_NOTIFY_TYPE_JOIN:
198 * Someone has joined to a channel. Get their ID and nickname and
199 * cache them for later use.
202 SILC_LOG_DEBUG(("Notify: JOIN"));
205 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
209 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
213 /* Find Client entry and if not found query it */
214 client_entry = silc_client_get_client_by_id(client, conn, client_id);
216 silc_client_notify_by_server_resolve(client, conn, packet,
217 SILC_ID_CLIENT, client_id);
221 /* If nickname or username hasn't been resolved, do so */
222 if (!client_entry->nickname || !client_entry->username) {
223 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
224 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
227 silc_client_notify_by_server_resolve(client, conn, packet,
228 SILC_ID_CLIENT, client_id);
229 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
230 client_entry->resolve_cmd_ident = conn->cmd_ident;
233 if (client_entry != conn->local_entry)
234 silc_client_nickname_format(client, conn, client_entry);
238 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
242 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
246 /* Get channel entry */
247 channel = silc_client_get_channel_by_id(client, conn, channel_id);
251 /* Join the client to channel */
252 if (!silc_client_on_channel(channel, client_entry)) {
253 chu = silc_calloc(1, sizeof(*chu));
254 chu->client = client_entry;
255 chu->channel = channel;
256 silc_hash_table_add(channel->user_list, client_entry, chu);
257 silc_hash_table_add(client_entry->channels, channel, chu);
260 /* Notify application. The channel entry is sent last as this notify
261 is for channel but application don't know it from the arguments
263 client->internal->ops->notify(client, conn, type, client_entry, channel);
266 case SILC_NOTIFY_TYPE_LEAVE:
268 * Someone has left a channel. We will remove it from the channel but
269 * we'll keep it in the cache in case we'll need it later.
272 SILC_LOG_DEBUG(("Notify: LEAVE"));
275 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
279 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
283 /* Find Client entry */
285 silc_client_get_client_by_id(client, conn, client_id);
289 /* Get channel entry */
290 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
294 channel = silc_client_get_channel_by_id(client, conn, channel_id);
298 /* Remove client from channel */
299 chu = silc_client_on_channel(channel, client_entry);
301 silc_hash_table_del(client_entry->channels, channel);
302 silc_hash_table_del(channel->user_list, client_entry);
306 /* Some client implementations actually quit network by first doing
307 LEAVE and then immediately SIGNOFF. We'll check for this by doing
308 check for the client after 5 - 34 seconds. If it is not valid after
309 that we'll remove the client from cache. */
310 if (!silc_hash_table_count(client_entry->channels)) {
311 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
312 res->context = client;
313 res->sock = silc_socket_dup(conn->sock);
314 res->packet = silc_id_dup(client_id, SILC_ID_CLIENT);
315 silc_schedule_task_add(client->schedule, conn->sock->sock,
316 silc_client_notify_check_client, res,
317 (5 + (silc_rng_get_rn16(client->rng) % 29)),
318 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
321 /* Notify application. The channel entry is sent last as this notify
322 is for channel but application don't know it from the arguments
324 client->internal->ops->notify(client, conn, type, client_entry, channel);
327 case SILC_NOTIFY_TYPE_SIGNOFF:
329 * Someone left SILC. We'll remove it from all channels and from cache.
332 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
335 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
339 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
343 /* Find Client entry */
345 silc_client_get_client_by_id(client, conn, client_id);
349 /* Remove from all channels */
350 silc_client_remove_from_channels(client, conn, client_entry);
352 /* Remove from cache */
353 silc_idcache_del_by_context(conn->client_cache, client_entry);
355 /* Get signoff message */
356 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
360 /* Notify application */
361 client->internal->ops->notify(client, conn, type, client_entry, tmp);
364 silc_client_del_client_entry(client, conn, client_entry);
367 case SILC_NOTIFY_TYPE_TOPIC_SET:
369 * Someone set the topic on a channel.
372 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
375 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
378 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
382 /* Find Client entry */
383 if (id_type == SILC_ID_CLIENT) {
384 /* Find Client entry */
386 client_entry = silc_client_get_client_by_id(client, conn, client_id);
388 silc_client_notify_by_server_resolve(client, conn, packet,
389 SILC_ID_CLIENT, client_id);
392 } else if (id_type == SILC_ID_SERVER) {
393 /* Find Server entry */
395 server = silc_client_get_server_by_id(client, conn, server_id);
397 silc_client_notify_by_server_resolve(client, conn, packet,
398 SILC_ID_SERVER, server_id);
402 /* Save the pointer to the client_entry pointer */
403 client_entry = (SilcClientEntry)server;
405 /* Find Channel entry */
407 channel = silc_client_get_channel_by_id(client, conn, channel_id);
409 silc_client_notify_by_server_resolve(client, conn, packet,
410 SILC_ID_CHANNEL, channel_id);
414 /* Save the pointer to the client_entry pointer */
415 client_entry = (SilcClientEntry)channel;
416 silc_free(channel_id);
421 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
425 /* Get channel entry */
426 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
430 channel = silc_client_get_channel_by_id(client, conn, channel_id);
434 /* Notify application. The channel entry is sent last as this notify
435 is for channel but application don't know it from the arguments
437 client->internal->ops->notify(client, conn, type, id_type,
438 client_entry, tmp, channel);
442 case SILC_NOTIFY_TYPE_NICK_CHANGE:
444 * Someone changed their nickname. If we don't have entry for the new
445 * ID we will query it and return here after it's done. After we've
446 * returned we fetch the old entry and free it and notify the
450 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
452 /* Get old Client ID */
453 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
457 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
462 if (conn->local_id && SILC_ID_CLIENT_COMPARE(client_id, conn->local_id))
465 /* Find old Client entry */
466 client_entry = silc_client_get_client_by_id(client, conn, client_id);
469 silc_free(client_id);
471 client_entry->valid = FALSE;
473 /* Get new Client ID */
474 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
478 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
482 /* From protocol version 1.1 we get the new nickname in notify as well,
483 so we don't have to resolve it. Do it the hard way if server doesn't
485 tmp = silc_argument_get_arg_type(args, 3, NULL);
487 /* Protocol version 1.1 */
488 char *tmp_nick = NULL;
490 /* Check whether nickname changed at all. It is possible that nick
491 change notify is received but nickname didn't changed, only the
493 if (client->internal->params->nickname_parse)
494 client->internal->params->nickname_parse(client_entry->nickname,
497 tmp_nick = strdup(tmp);
499 if (tmp_nick && !strcmp(tmp, tmp_nick)) {
500 /* Nickname didn't change. Update only the ID */
501 silc_idcache_del_by_context(conn->client_cache, client_entry);
502 silc_free(client_entry->id);
503 client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
504 silc_idcache_add(conn->client_cache, strdup(tmp),
505 client_entry->id, client_entry, 0, NULL);
507 /* Notify application */
508 client->internal->ops->notify(client, conn, type,
509 client_entry, client_entry);
514 /* Create new client entry, and save all old information with the
515 new nickname and client ID */
516 client_entry2 = silc_client_add_client(client, conn, NULL, NULL,
517 client_entry->realname,
518 silc_id_dup(client_id,
523 if (client_entry->server)
524 client_entry2->server = strdup(client_entry->server);
525 if (client_entry->username)
526 client_entry2->username = strdup(client_entry->username);
527 if (client_entry->hostname)
528 client_entry2->hostname = strdup(client_entry->hostname);
529 silc_client_update_client(client, conn, client_entry2, tmp, NULL, NULL,
532 /* Protocol version 1.0 */
534 /* Find client entry and if not found resolve it */
535 client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
536 if (!client_entry2) {
537 /* Resolve the entry information */
538 silc_client_notify_by_server_resolve(client, conn, packet,
539 SILC_ID_CLIENT, client_id);
541 /* Add the new entry even though we resolved it. This is because we
542 want to replace the old entry with the new entry here right now. */
544 silc_client_add_client(client, conn, NULL, NULL, NULL,
545 silc_id_dup(client_id, SILC_ID_CLIENT),
548 /* Replace old ID entry with new one on all channels. */
549 silc_client_replace_from_channels(client, conn, client_entry,
554 if (client_entry2 != conn->local_entry)
555 silc_client_nickname_format(client, conn, client_entry2);
558 /* Remove the old from cache */
559 silc_idcache_del_by_context(conn->client_cache, client_entry);
561 /* Replace old ID entry with new one on all channels. */
562 silc_client_replace_from_channels(client, conn, client_entry,
565 /* Notify application */
566 client->internal->ops->notify(client, conn, type,
567 client_entry, client_entry2);
569 /* Free old client entry */
570 silc_client_del_client_entry(client, conn, client_entry);
574 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
576 * Someone changed a channel mode
579 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
582 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
585 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
589 /* Find Client entry */
590 if (id_type == SILC_ID_CLIENT) {
591 /* Find Client entry */
593 client_entry = silc_client_get_client_by_id(client, conn, client_id);
595 silc_client_notify_by_server_resolve(client, conn, packet,
596 SILC_ID_CLIENT, client_id);
599 } else if (id_type == SILC_ID_SERVER) {
600 /* Find Server entry */
602 server = silc_client_get_server_by_id(client, conn, server_id);
604 silc_client_notify_by_server_resolve(client, conn, packet,
605 SILC_ID_SERVER, server_id);
609 /* Save the pointer to the client_entry pointer */
610 client_entry = (SilcClientEntry)server;
612 /* Find Channel entry */
614 channel = silc_client_get_channel_by_id(client, conn, channel_id);
616 silc_client_notify_by_server_resolve(client, conn, packet,
617 SILC_ID_CHANNEL, channel_id);
621 /* Save the pointer to the client_entry pointer */
622 client_entry = (SilcClientEntry)channel;
623 silc_free(channel_id);
628 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
632 SILC_GET32_MSB(mode, tmp);
634 /* Get channel entry */
635 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
639 channel = silc_client_get_channel_by_id(client, conn, channel_id);
643 /* Save the new mode */
644 channel->mode = mode;
647 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
649 unsigned char hash[32];
652 silc_hmac_free(channel->hmac);
653 if (!silc_hmac_alloc(tmp, NULL, &channel->hmac))
656 silc_hash_make(silc_hmac_get_hash(channel->hmac),
657 channel->key, channel->key_len / 8,
659 silc_hmac_set_key(channel->hmac, hash,
660 silc_hash_len(silc_hmac_get_hash(channel->hmac)));
661 memset(hash, 0, sizeof(hash));
664 /* Notify application. The channel entry is sent last as this notify
665 is for channel but application don't know it from the arguments
667 client->internal->ops->notify(client, conn, type, id_type,
668 client_entry, mode, NULL, tmp, channel);
671 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
673 * Someone changed user's mode on a channel
676 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
679 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
682 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
686 /* Find Client entry */
687 if (id_type == SILC_ID_CLIENT) {
688 /* Find Client entry */
690 client_entry = silc_client_get_client_by_id(client, conn, client_id);
692 silc_client_notify_by_server_resolve(client, conn, packet,
693 SILC_ID_CLIENT, client_id);
696 } else if (id_type == SILC_ID_SERVER) {
697 /* Find Server entry */
699 server = silc_client_get_server_by_id(client, conn, server_id);
701 silc_client_notify_by_server_resolve(client, conn, packet,
702 SILC_ID_SERVER, server_id);
706 /* Save the pointer to the client_entry pointer */
707 client_entry = (SilcClientEntry)server;
709 /* Find Channel entry */
711 channel = silc_client_get_channel_by_id(client, conn, channel_id);
713 silc_client_notify_by_server_resolve(client, conn, packet,
714 SILC_ID_CHANNEL, channel_id);
718 /* Save the pointer to the client_entry pointer */
719 client_entry = (SilcClientEntry)channel;
720 silc_free(channel_id);
725 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
729 SILC_GET32_MSB(mode, tmp);
731 /* Get target Client ID */
732 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
736 silc_free(client_id);
737 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
741 /* Find target Client entry */
743 silc_client_get_client_by_id(client, conn, client_id);
744 if (!client_entry2) {
745 silc_client_notify_by_server_resolve(client, conn, packet,
746 SILC_ID_CLIENT, client_id);
750 /* Get channel entry */
751 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
755 channel = silc_client_get_channel_by_id(client, conn, channel_id);
760 chu = silc_client_on_channel(channel, client_entry2);
764 /* Notify application. The channel entry is sent last as this notify
765 is for channel but application don't know it from the arguments
767 client->internal->ops->notify(client, conn, type,
768 id_type, client_entry, mode,
769 client_entry2, channel);
772 case SILC_NOTIFY_TYPE_MOTD:
774 * Received Message of the day
777 SILC_LOG_DEBUG(("Notify: MOTD"));
780 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
784 /* Notify application */
785 client->internal->ops->notify(client, conn, type, tmp);
788 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
790 * Router has enforced a new ID to a channel. Let's change the old
791 * ID to the one provided here.
794 SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
797 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
800 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
804 /* Get the channel entry */
805 channel = silc_client_get_channel_by_id(client, conn, channel_id);
809 silc_free(channel_id);
812 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
815 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
819 /* Replace the Channel ID */
820 if (silc_client_replace_channel_id(client, conn, channel, channel_id))
823 /* Notify application */
824 client->internal->ops->notify(client, conn, type, channel, channel);
827 case SILC_NOTIFY_TYPE_KICKED:
829 * A client (maybe me) was kicked from a channel
832 SILC_LOG_DEBUG(("Notify: KICKED"));
835 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
839 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
843 /* Find Client entry */
844 client_entry = silc_client_get_client_by_id(client, conn, client_id);
848 /* Get channel entry */
849 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
853 channel = silc_client_get_channel_by_id(client, conn, channel_id);
857 /* From protocol version 1.1 we get the kicker's client ID as well */
858 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
860 silc_free(client_id);
861 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
865 /* Find kicker's client entry and if not found resolve it */
866 client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
867 if (!client_entry2) {
868 silc_client_notify_by_server_resolve(client, conn, packet,
869 SILC_ID_CLIENT, client_id);
872 if (client_entry2 != conn->local_entry)
873 silc_client_nickname_format(client, conn, client_entry2);
878 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
880 /* Notify application. The channel entry is sent last as this notify
881 is for channel but application don't know it from the arguments
883 client->internal->ops->notify(client, conn, type, client_entry, tmp,
884 client_entry2, channel);
886 /* Remove kicked client from channel */
887 if (client_entry == conn->local_entry) {
888 /* If I was kicked from channel, remove the channel */
889 if (conn->current_channel == channel)
890 conn->current_channel = NULL;
891 silc_client_del_channel(client, conn, channel);
893 chu = silc_client_on_channel(channel, client_entry);
895 silc_hash_table_del(client_entry->channels, channel);
896 silc_hash_table_del(channel->user_list, client_entry);
900 if (!silc_hash_table_count(client_entry->channels)) {
901 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
902 res->context = client;
903 res->sock = silc_socket_dup(conn->sock);
904 res->packet = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
905 silc_schedule_task_add(client->schedule, conn->sock->sock,
906 silc_client_notify_check_client, res,
907 (5 + (silc_rng_get_rn16(client->rng) % 529)),
908 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
913 case SILC_NOTIFY_TYPE_KILLED:
916 * A client (maybe me) was killed from the network.
919 SilcUInt32 comment_len;
921 SILC_LOG_DEBUG(("Notify: KILLED"));
924 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
928 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
932 /* Find Client entry */
933 client_entry = silc_client_get_client_by_id(client, conn, client_id);
938 comment = silc_argument_get_arg_type(args, 2, &comment_len);
940 /* From protocol version 1.1 we get killer's client ID as well */
941 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
943 silc_free(client_id);
944 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
948 /* Find Client entry */
949 if (id_type == SILC_ID_CLIENT) {
950 /* Find Client entry */
952 client_entry2 = silc_client_get_client_by_id(client, conn,
955 silc_client_notify_by_server_resolve(client, conn, packet,
956 SILC_ID_CLIENT, client_id);
959 } else if (id_type == SILC_ID_SERVER) {
960 /* Find Server entry */
962 server = silc_client_get_server_by_id(client, conn, server_id);
964 silc_client_notify_by_server_resolve(client, conn, packet,
965 SILC_ID_SERVER, server_id);
969 /* Save the pointer to the client_entry pointer */
970 client_entry2 = (SilcClientEntry)server;
972 /* Find Channel entry */
974 channel = silc_client_get_channel_by_id(client, conn, channel_id);
976 silc_client_notify_by_server_resolve(client, conn, packet,
977 SILC_ID_CHANNEL, channel_id);
981 /* Save the pointer to the client_entry pointer */
982 client_entry2 = (SilcClientEntry)channel;
983 silc_free(channel_id);
988 /* Notify application. */
989 client->internal->ops->notify(client, conn, type, client_entry,
990 comment, id_type, client_entry2);
992 if (client_entry != conn->local_entry)
993 /* Remove the client from all channels and free it */
994 silc_client_del_client(client, conn, client_entry);
998 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
1001 * A server quit the SILC network and some clients must be removed
1002 * from channels as they quit as well.
1004 SilcClientEntry *clients = NULL;
1005 SilcUInt32 clients_count = 0;
1008 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
1010 for (i = 1; i < silc_argument_get_arg_num(args); i++) {
1012 tmp = silc_argument_get_arg_type(args, i + 1, &tmp_len);
1014 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1018 /* Get the client entry */
1019 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1021 clients = silc_realloc(clients, sizeof(*clients) *
1022 (clients_count + 1));
1023 clients[clients_count] = client_entry;
1026 silc_free(client_id);
1031 /* Notify application. We don't keep server entries so the server
1032 entry is returned as NULL. The client's are returned as array
1033 of SilcClientEntry pointers. */
1034 client->internal->ops->notify(client, conn, type, NULL,
1035 clients, clients_count);
1037 for (i = 0; i < clients_count; i++) {
1038 /* Remove client from all channels */
1039 client_entry = clients[i];
1040 if (client_entry == conn->local_entry)
1043 /* Remove the client from all channels and free it */
1044 silc_client_del_client(client, conn, client_entry);
1051 case SILC_NOTIFY_TYPE_ERROR:
1054 * Some has occurred and server is notifying us about it.
1058 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1059 if (!tmp && tmp_len != 1)
1061 error = (SilcStatus)tmp[0];
1063 SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1065 if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1066 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1068 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1071 client_entry = silc_client_get_client_by_id(client, conn,
1074 silc_client_del_client(client, conn, client_entry);
1078 /* Notify application. */
1079 client->internal->ops->notify(client, conn, type, error);
1083 case SILC_NOTIFY_TYPE_WATCH:
1086 * Received notify about some client we are watching
1088 SilcNotifyType notify = 0;
1090 SILC_LOG_DEBUG(("Notify: WATCH"));
1092 /* Get sender Client ID */
1093 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1096 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1100 /* Find Client entry and if not found query it */
1101 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1102 if (!client_entry) {
1103 silc_client_notify_by_server_resolve(client, conn, packet,
1104 SILC_ID_CLIENT, client_id);
1109 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1110 if (!tmp || tmp_len != 4)
1112 SILC_GET32_MSB(mode, tmp);
1114 /* Get notify type */
1115 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1116 if (tmp && tmp_len != 2)
1119 SILC_GET16_MSB(notify, tmp);
1122 tmp = silc_argument_get_arg_type(args, 2, NULL);
1124 char *tmp_nick = NULL;
1126 if (client->internal->params->nickname_parse)
1127 client->internal->params->nickname_parse(client_entry->nickname,
1130 tmp_nick = strdup(tmp);
1132 /* If same nick, the client was new to us and has become "present"
1133 to network. Send NULL as nick to application. */
1134 if (!strcmp(tmp, tmp_nick))
1137 silc_free(tmp_nick);
1140 /* Notify application. */
1141 client->internal->ops->notify(client, conn, type, client_entry,
1144 client_entry->mode = mode;
1146 /* If nickname was changed, remove the client entry unless the
1147 client is on some channel */
1148 if (tmp && notify == SILC_NOTIFY_TYPE_NICK_CHANGE &&
1149 !silc_hash_table_count(client_entry->channels))
1150 silc_client_del_client(client, conn, client_entry);
1151 else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1152 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
1153 notify == SILC_NOTIFY_TYPE_KILLED)
1154 silc_client_del_client(client, conn, client_entry);
1163 silc_notify_payload_free(payload);
1164 silc_free(client_id);
1165 silc_free(channel_id);
1166 silc_free(server_id);