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, 0,
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 silc_client_replace_channel_id(client, conn, channel, channel_id);
819 /* Notify application */
820 client->internal->ops->notify(client, conn, type, channel, channel);
823 case SILC_NOTIFY_TYPE_KICKED:
825 * A client (maybe me) was kicked from a channel
828 SILC_LOG_DEBUG(("Notify: KICKED"));
831 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
835 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
839 /* Find Client entry */
840 client_entry = silc_client_get_client_by_id(client, conn, client_id);
844 /* Get channel entry */
845 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
849 channel = silc_client_get_channel_by_id(client, conn, channel_id);
853 /* From protocol version 1.1 we get the kicker's client ID as well */
854 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
856 silc_free(client_id);
857 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
861 /* Find kicker's client entry and if not found resolve it */
862 client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
863 if (!client_entry2) {
864 silc_client_notify_by_server_resolve(client, conn, packet,
865 SILC_ID_CLIENT, client_id);
868 if (client_entry2 != conn->local_entry)
869 silc_client_nickname_format(client, conn, client_entry2);
874 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
876 /* Notify application. The channel entry is sent last as this notify
877 is for channel but application don't know it from the arguments
879 client->internal->ops->notify(client, conn, type, client_entry, tmp,
880 client_entry2, channel);
882 /* Remove kicked client from channel */
883 if (client_entry == conn->local_entry) {
884 /* If I was kicked from channel, remove the channel */
885 if (conn->current_channel == channel)
886 conn->current_channel = NULL;
887 silc_client_del_channel(client, conn, channel);
889 chu = silc_client_on_channel(channel, client_entry);
891 silc_hash_table_del(client_entry->channels, channel);
892 silc_hash_table_del(channel->user_list, client_entry);
898 case SILC_NOTIFY_TYPE_KILLED:
901 * A client (maybe me) was killed from the network.
904 SilcUInt32 comment_len;
906 SILC_LOG_DEBUG(("Notify: KILLED"));
909 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
913 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
917 /* Find Client entry */
918 client_entry = silc_client_get_client_by_id(client, conn, client_id);
923 comment = silc_argument_get_arg_type(args, 2, &comment_len);
925 /* From protocol version 1.1 we get killer's client ID as well */
926 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
928 silc_free(client_id);
929 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
933 /* Find Client entry */
934 if (id_type == SILC_ID_CLIENT) {
935 /* Find Client entry */
937 client_entry2 = silc_client_get_client_by_id(client, conn,
940 silc_client_notify_by_server_resolve(client, conn, packet,
941 SILC_ID_CLIENT, client_id);
944 } else if (id_type == SILC_ID_SERVER) {
945 /* Find Server entry */
947 server = silc_client_get_server_by_id(client, conn, server_id);
949 silc_client_notify_by_server_resolve(client, conn, packet,
950 SILC_ID_SERVER, server_id);
954 /* Save the pointer to the client_entry pointer */
955 client_entry2 = (SilcClientEntry)server;
957 /* Find Channel entry */
959 channel = silc_client_get_channel_by_id(client, conn, channel_id);
961 silc_client_notify_by_server_resolve(client, conn, packet,
962 SILC_ID_CHANNEL, channel_id);
966 /* Save the pointer to the client_entry pointer */
967 client_entry2 = (SilcClientEntry)channel;
968 silc_free(channel_id);
973 /* Notify application. */
974 client->internal->ops->notify(client, conn, type, client_entry,
975 comment, id_type, client_entry2);
977 if (client_entry != conn->local_entry)
978 /* Remove the client from all channels and free it */
979 silc_client_del_client(client, conn, client_entry);
983 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
986 * A server quit the SILC network and some clients must be removed
987 * from channels as they quit as well.
989 SilcClientEntry *clients = NULL;
990 SilcUInt32 clients_count = 0;
993 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
995 for (i = 1; i < silc_argument_get_arg_num(args); i++) {
997 tmp = silc_argument_get_arg_type(args, i + 1, &tmp_len);
999 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1003 /* Get the client entry */
1004 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1006 clients = silc_realloc(clients, sizeof(*clients) *
1007 (clients_count + 1));
1008 clients[clients_count] = client_entry;
1011 silc_free(client_id);
1016 /* Notify application. We don't keep server entries so the server
1017 entry is returned as NULL. The client's are returned as array
1018 of SilcClientEntry pointers. */
1019 client->internal->ops->notify(client, conn, type, NULL,
1020 clients, clients_count);
1022 for (i = 0; i < clients_count; i++) {
1023 /* Remove client from all channels */
1024 client_entry = clients[i];
1025 if (client_entry == conn->local_entry)
1028 /* Remove the client from all channels and free it */
1029 silc_client_del_client(client, conn, client_entry);
1036 case SILC_NOTIFY_TYPE_ERROR:
1039 * Some has occurred and server is notifying us about it.
1043 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1044 if (!tmp && tmp_len != 1)
1046 error = (SilcStatus)tmp[0];
1048 SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1050 if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1051 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1053 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1056 client_entry = silc_client_get_client_by_id(client, conn,
1059 silc_client_del_client(client, conn, client_entry);
1063 /* Notify application. */
1064 client->internal->ops->notify(client, conn, type, error);
1068 case SILC_NOTIFY_TYPE_WATCH:
1071 * Received notify about some client we are watching
1073 SilcNotifyType notify = 0;
1075 SILC_LOG_DEBUG(("Notify: WATCH"));
1077 /* Get sender Client ID */
1078 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1081 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1085 /* Find Client entry and if not found query it */
1086 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1087 if (!client_entry) {
1088 silc_client_notify_by_server_resolve(client, conn, packet,
1089 SILC_ID_CLIENT, client_id);
1094 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1095 if (!tmp || tmp_len != 4)
1097 SILC_GET32_MSB(mode, tmp);
1099 /* Get notify type */
1100 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1101 if (tmp && tmp_len != 2)
1104 SILC_GET16_MSB(notify, tmp);
1107 tmp = silc_argument_get_arg_type(args, 2, NULL);
1109 char *tmp_nick = NULL;
1111 if (client->internal->params->nickname_parse)
1112 client->internal->params->nickname_parse(client_entry->nickname,
1115 tmp_nick = strdup(tmp);
1117 /* If same nick, the client was new to us and has become "present"
1118 to network. Send NULL as nick to application. */
1119 if (!strcmp(tmp, tmp_nick))
1122 silc_free(tmp_nick);
1125 /* Notify application. */
1126 client->internal->ops->notify(client, conn, type, client_entry,
1129 client_entry->mode = mode;
1131 /* If nickname was changed, remove the client entry unless the
1132 client is on some channel */
1133 if (tmp && notify == SILC_NOTIFY_TYPE_NICK_CHANGE &&
1134 !silc_hash_table_count(client_entry->channels))
1135 silc_client_del_client(client, conn, client_entry);
1144 silc_notify_payload_free(payload);
1145 silc_free(client_id);
1146 silc_free(channel_id);
1147 silc_free(server_id);