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);
747 /* Get channel entry */
748 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
752 channel = silc_client_get_channel_by_id(client, conn, channel_id);
757 chu = silc_client_on_channel(channel, client_entry2);
761 /* Notify application. The channel entry is sent last as this notify
762 is for channel but application don't know it from the arguments
764 client->internal->ops->notify(client, conn, type,
765 id_type, client_entry, mode,
766 client_entry2, channel);
769 case SILC_NOTIFY_TYPE_MOTD:
771 * Received Message of the day
774 SILC_LOG_DEBUG(("Notify: MOTD"));
777 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
781 /* Notify application */
782 client->internal->ops->notify(client, conn, type, tmp);
785 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
787 * Router has enforced a new ID to a channel. Let's change the old
788 * ID to the one provided here.
791 SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
794 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
797 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
801 /* Get the channel entry */
802 channel = silc_client_get_channel_by_id(client, conn, channel_id);
806 silc_free(channel_id);
809 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
812 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
816 /* Replace the Channel ID */
817 if (silc_client_replace_channel_id(client, conn, channel, channel_id))
820 /* Notify application */
821 client->internal->ops->notify(client, conn, type, channel, channel);
824 case SILC_NOTIFY_TYPE_KICKED:
826 * A client (maybe me) was kicked from a channel
829 SILC_LOG_DEBUG(("Notify: KICKED"));
832 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
836 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
840 /* Find Client entry */
841 client_entry = silc_client_get_client_by_id(client, conn, client_id);
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);
854 /* From protocol version 1.1 we get the kicker's client ID as well */
855 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
857 silc_free(client_id);
858 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
862 /* Find kicker's client entry and if not found resolve it */
863 client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
864 if (!client_entry2) {
865 silc_client_notify_by_server_resolve(client, conn, packet,
866 SILC_ID_CLIENT, client_id);
869 if (client_entry2 != conn->local_entry)
870 silc_client_nickname_format(client, conn, client_entry2);
875 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
877 /* Notify application. The channel entry is sent last as this notify
878 is for channel but application don't know it from the arguments
880 client->internal->ops->notify(client, conn, type, client_entry, tmp,
881 client_entry2, channel);
883 /* Remove kicked client from channel */
884 if (client_entry == conn->local_entry) {
885 /* If I was kicked from channel, remove the channel */
886 if (conn->current_channel == channel)
887 conn->current_channel = NULL;
888 silc_client_del_channel(client, conn, channel);
890 chu = silc_client_on_channel(channel, client_entry);
892 silc_hash_table_del(client_entry->channels, channel);
893 silc_hash_table_del(channel->user_list, client_entry);
897 if (!silc_hash_table_count(client_entry->channels)) {
898 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
899 res->context = client;
900 res->sock = silc_socket_dup(conn->sock);
901 res->packet = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
902 silc_schedule_task_add(client->schedule, conn->sock->sock,
903 silc_client_notify_check_client, res,
904 (5 + (silc_rng_get_rn16(client->rng) % 529)),
905 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
910 case SILC_NOTIFY_TYPE_KILLED:
913 * A client (maybe me) was killed from the network.
916 SilcUInt32 comment_len;
918 SILC_LOG_DEBUG(("Notify: KILLED"));
921 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
925 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
929 /* Find Client entry */
930 client_entry = silc_client_get_client_by_id(client, conn, client_id);
935 comment = silc_argument_get_arg_type(args, 2, &comment_len);
937 /* From protocol version 1.1 we get killer's client ID as well */
938 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
940 silc_free(client_id);
941 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
945 /* Find Client entry */
946 if (id_type == SILC_ID_CLIENT) {
947 /* Find Client entry */
949 client_entry2 = silc_client_get_client_by_id(client, conn,
952 silc_client_notify_by_server_resolve(client, conn, packet,
953 SILC_ID_CLIENT, client_id);
956 } else if (id_type == SILC_ID_SERVER) {
957 /* Find Server entry */
959 server = silc_client_get_server_by_id(client, conn, server_id);
961 silc_client_notify_by_server_resolve(client, conn, packet,
962 SILC_ID_SERVER, server_id);
966 /* Save the pointer to the client_entry pointer */
967 client_entry2 = (SilcClientEntry)server;
969 /* Find Channel entry */
971 channel = silc_client_get_channel_by_id(client, conn, channel_id);
973 silc_client_notify_by_server_resolve(client, conn, packet,
974 SILC_ID_CHANNEL, channel_id);
978 /* Save the pointer to the client_entry pointer */
979 client_entry2 = (SilcClientEntry)channel;
980 silc_free(channel_id);
985 /* Notify application. */
986 client->internal->ops->notify(client, conn, type, client_entry,
987 comment, id_type, client_entry2);
989 if (client_entry != conn->local_entry)
990 /* Remove the client from all channels and free it */
991 silc_client_del_client(client, conn, client_entry);
995 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
998 * A server quit the SILC network and some clients must be removed
999 * from channels as they quit as well.
1001 SilcClientEntry *clients = NULL;
1002 SilcUInt32 clients_count = 0;
1005 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
1007 for (i = 1; i < silc_argument_get_arg_num(args); i++) {
1009 tmp = silc_argument_get_arg_type(args, i + 1, &tmp_len);
1011 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1015 /* Get the client entry */
1016 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1018 clients = silc_realloc(clients, sizeof(*clients) *
1019 (clients_count + 1));
1020 clients[clients_count] = client_entry;
1023 silc_free(client_id);
1028 /* Notify application. We don't keep server entries so the server
1029 entry is returned as NULL. The client's are returned as array
1030 of SilcClientEntry pointers. */
1031 client->internal->ops->notify(client, conn, type, NULL,
1032 clients, clients_count);
1034 for (i = 0; i < clients_count; i++) {
1035 /* Remove client from all channels */
1036 client_entry = clients[i];
1037 if (client_entry == conn->local_entry)
1040 /* Remove the client from all channels and free it */
1041 silc_client_del_client(client, conn, client_entry);
1048 case SILC_NOTIFY_TYPE_ERROR:
1051 * Some has occurred and server is notifying us about it.
1055 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1056 if (!tmp && tmp_len != 1)
1058 error = (SilcStatus)tmp[0];
1060 SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1062 if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1063 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1065 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1068 client_entry = silc_client_get_client_by_id(client, conn,
1071 silc_client_del_client(client, conn, client_entry);
1075 /* Notify application. */
1076 client->internal->ops->notify(client, conn, type, error);
1080 case SILC_NOTIFY_TYPE_WATCH:
1083 * Received notify about some client we are watching
1085 SilcNotifyType notify = 0;
1087 SILC_LOG_DEBUG(("Notify: WATCH"));
1089 /* Get sender Client ID */
1090 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1093 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1097 /* Find Client entry and if not found query it */
1098 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1099 if (!client_entry) {
1100 silc_client_notify_by_server_resolve(client, conn, packet,
1101 SILC_ID_CLIENT, client_id);
1106 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1107 if (!tmp || tmp_len != 4)
1109 SILC_GET32_MSB(mode, tmp);
1111 /* Get notify type */
1112 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1113 if (tmp && tmp_len != 2)
1116 SILC_GET16_MSB(notify, tmp);
1119 tmp = silc_argument_get_arg_type(args, 2, NULL);
1121 char *tmp_nick = NULL;
1123 if (client->internal->params->nickname_parse)
1124 client->internal->params->nickname_parse(client_entry->nickname,
1127 tmp_nick = strdup(tmp);
1129 /* If same nick, the client was new to us and has become "present"
1130 to network. Send NULL as nick to application. */
1131 if (!strcmp(tmp, tmp_nick))
1134 silc_free(tmp_nick);
1137 /* Notify application. */
1138 client->internal->ops->notify(client, conn, type, client_entry,
1141 client_entry->mode = mode;
1143 /* If nickname was changed, remove the client entry unless the
1144 client is on some channel */
1145 if (tmp && notify == SILC_NOTIFY_TYPE_NICK_CHANGE &&
1146 !silc_hash_table_count(client_entry->channels))
1147 silc_client_del_client(client, conn, client_entry);
1148 else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1149 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
1150 notify == SILC_NOTIFY_TYPE_KILLED)
1151 silc_client_del_client(client, conn, client_entry);
1160 silc_notify_payload_free(payload);
1161 silc_free(client_id);
1162 silc_free(channel_id);
1163 silc_free(server_id);