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);
896 if (!silc_hash_table_count(client_entry->channels)) {
897 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
898 res->context = client;
899 res->sock = silc_socket_dup(conn->sock);
900 res->packet = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
901 silc_schedule_task_add(client->schedule, 0,
902 silc_client_notify_check_client, res,
903 (5 + (silc_rng_get_rn16(client->rng) % 529)),
904 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
909 case SILC_NOTIFY_TYPE_KILLED:
912 * A client (maybe me) was killed from the network.
915 SilcUInt32 comment_len;
917 SILC_LOG_DEBUG(("Notify: KILLED"));
920 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
924 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
928 /* Find Client entry */
929 client_entry = silc_client_get_client_by_id(client, conn, client_id);
934 comment = silc_argument_get_arg_type(args, 2, &comment_len);
936 /* From protocol version 1.1 we get killer's client ID as well */
937 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
939 silc_free(client_id);
940 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
944 /* Find Client entry */
945 if (id_type == SILC_ID_CLIENT) {
946 /* Find Client entry */
948 client_entry2 = silc_client_get_client_by_id(client, conn,
951 silc_client_notify_by_server_resolve(client, conn, packet,
952 SILC_ID_CLIENT, client_id);
955 } else if (id_type == SILC_ID_SERVER) {
956 /* Find Server entry */
958 server = silc_client_get_server_by_id(client, conn, server_id);
960 silc_client_notify_by_server_resolve(client, conn, packet,
961 SILC_ID_SERVER, server_id);
965 /* Save the pointer to the client_entry pointer */
966 client_entry2 = (SilcClientEntry)server;
968 /* Find Channel entry */
970 channel = silc_client_get_channel_by_id(client, conn, channel_id);
972 silc_client_notify_by_server_resolve(client, conn, packet,
973 SILC_ID_CHANNEL, channel_id);
977 /* Save the pointer to the client_entry pointer */
978 client_entry2 = (SilcClientEntry)channel;
979 silc_free(channel_id);
984 /* Notify application. */
985 client->internal->ops->notify(client, conn, type, client_entry,
986 comment, id_type, client_entry2);
988 if (client_entry != conn->local_entry)
989 /* Remove the client from all channels and free it */
990 silc_client_del_client(client, conn, client_entry);
994 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
997 * A server quit the SILC network and some clients must be removed
998 * from channels as they quit as well.
1000 SilcClientEntry *clients = NULL;
1001 SilcUInt32 clients_count = 0;
1004 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
1006 for (i = 1; i < silc_argument_get_arg_num(args); i++) {
1008 tmp = silc_argument_get_arg_type(args, i + 1, &tmp_len);
1010 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1014 /* Get the client entry */
1015 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1017 clients = silc_realloc(clients, sizeof(*clients) *
1018 (clients_count + 1));
1019 clients[clients_count] = client_entry;
1022 silc_free(client_id);
1027 /* Notify application. We don't keep server entries so the server
1028 entry is returned as NULL. The client's are returned as array
1029 of SilcClientEntry pointers. */
1030 client->internal->ops->notify(client, conn, type, NULL,
1031 clients, clients_count);
1033 for (i = 0; i < clients_count; i++) {
1034 /* Remove client from all channels */
1035 client_entry = clients[i];
1036 if (client_entry == conn->local_entry)
1039 /* Remove the client from all channels and free it */
1040 silc_client_del_client(client, conn, client_entry);
1047 case SILC_NOTIFY_TYPE_ERROR:
1050 * Some has occurred and server is notifying us about it.
1054 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1055 if (!tmp && tmp_len != 1)
1057 error = (SilcStatus)tmp[0];
1059 SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1061 if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1062 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1064 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1067 client_entry = silc_client_get_client_by_id(client, conn,
1070 silc_client_del_client(client, conn, client_entry);
1074 /* Notify application. */
1075 client->internal->ops->notify(client, conn, type, error);
1079 case SILC_NOTIFY_TYPE_WATCH:
1082 * Received notify about some client we are watching
1084 SilcNotifyType notify = 0;
1086 SILC_LOG_DEBUG(("Notify: WATCH"));
1088 /* Get sender Client ID */
1089 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1092 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1096 /* Find Client entry and if not found query it */
1097 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1098 if (!client_entry) {
1099 silc_client_notify_by_server_resolve(client, conn, packet,
1100 SILC_ID_CLIENT, client_id);
1105 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1106 if (!tmp || tmp_len != 4)
1108 SILC_GET32_MSB(mode, tmp);
1110 /* Get notify type */
1111 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1112 if (tmp && tmp_len != 2)
1115 SILC_GET16_MSB(notify, tmp);
1118 tmp = silc_argument_get_arg_type(args, 2, NULL);
1120 char *tmp_nick = NULL;
1122 if (client->internal->params->nickname_parse)
1123 client->internal->params->nickname_parse(client_entry->nickname,
1126 tmp_nick = strdup(tmp);
1128 /* If same nick, the client was new to us and has become "present"
1129 to network. Send NULL as nick to application. */
1130 if (!strcmp(tmp, tmp_nick))
1133 silc_free(tmp_nick);
1136 /* Notify application. */
1137 client->internal->ops->notify(client, conn, type, client_entry,
1140 client_entry->mode = mode;
1142 /* If nickname was changed, remove the client entry unless the
1143 client is on some channel */
1144 if (tmp && notify == SILC_NOTIFY_TYPE_NICK_CHANGE &&
1145 !silc_hash_table_count(client_entry->channels))
1146 silc_client_del_client(client, conn, client_entry);
1155 silc_notify_payload_free(payload);
1156 silc_free(client_id);
1157 silc_free(channel_id);
1158 silc_free(server_id);