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 SilcClientConnection conn = res->context;
39 SilcClient client = conn->client;
40 SilcClientID *client_id = res->packet;
41 silc_client_get_client_by_id_resolve(client, conn, client_id, NULL, NULL);
46 /* Called when notify is received and some async operation (such as command)
47 is required before processing the notify message. This calls again the
48 silc_client_notify_by_server and reprocesses the original notify packet. */
50 static void silc_client_notify_by_server_pending(void *context, void *context2)
52 SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
53 SilcClientCommandReplyContext reply =
54 (SilcClientCommandReplyContext)context2;
56 SILC_LOG_DEBUG(("Start"));
58 if (reply && !silc_command_get_status(reply->payload, NULL, NULL))
61 silc_client_notify_by_server(res->context, res->sock, res->packet);
64 silc_socket_free(res->sock);
65 silc_packet_context_free(res->packet);
69 /* Resolve client, channel or server information. */
71 static void silc_client_notify_by_server_resolve(SilcClient client,
72 SilcClientConnection conn,
73 SilcPacketContext *packet,
77 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
78 SilcBuffer idp = silc_id_payload_encode(id, id_type);
80 res->packet = silc_packet_context_dup(packet);
81 res->context = client;
82 res->sock = silc_socket_dup(conn->sock);
84 /* For client resolving use WHOIS, and otherwise use IDENTIFY */
85 if (id_type == SILC_ID_CLIENT) {
86 silc_client_command_register(client, SILC_COMMAND_WHOIS, NULL, NULL,
87 silc_client_command_reply_whois_i, 0,
89 silc_client_command_send(client, conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
90 1, 3, idp->data, idp->len);
91 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
92 silc_client_notify_by_server_pending, res);
94 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
95 silc_client_command_reply_identify_i, 0,
97 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
98 conn->cmd_ident, 1, 5, idp->data, idp->len);
99 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
100 silc_client_notify_by_server_pending, res);
102 silc_buffer_free(idp);
105 /* Received notify message from server */
107 void silc_client_notify_by_server(SilcClient client,
108 SilcSocketConnection sock,
109 SilcPacketContext *packet)
111 SilcBuffer buffer = packet->buffer;
112 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
113 SilcNotifyPayload payload;
115 SilcArgumentPayload args;
119 SilcClientID *client_id = NULL;
120 SilcChannelID *channel_id = NULL;
121 SilcServerID *server_id = NULL;
122 SilcClientEntry client_entry = NULL;
123 SilcClientEntry client_entry2 = NULL;
124 SilcChannelEntry channel;
126 SilcServerEntry server;
128 SilcUInt32 tmp_len, mode;
130 SILC_LOG_DEBUG(("Start"));
132 payload = silc_notify_payload_parse(buffer->data, buffer->len);
136 type = silc_notify_get_type(payload);
137 args = silc_notify_get_args(payload);
142 case SILC_NOTIFY_TYPE_NONE:
143 /* Notify application */
144 client->internal->ops->notify(client, conn, type,
145 silc_argument_get_arg_type(args, 1, NULL));
148 case SILC_NOTIFY_TYPE_INVITE:
150 * Someone invited me to a channel. Find Client and Channel entries
151 * for the application.
154 SILC_LOG_DEBUG(("Notify: INVITE"));
157 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
161 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
165 /* Get the channel entry */
166 channel = silc_client_get_channel_by_id(client, conn, channel_id);
168 /* Get sender Client ID */
169 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
173 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
177 /* Find Client entry and if not found query it */
178 client_entry = silc_client_get_client_by_id(client, conn, client_id);
180 silc_client_notify_by_server_resolve(client, conn, packet,
181 SILC_ID_CLIENT, client_id);
185 /* Get the channel name */
186 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
190 /* Notify application */
191 client->internal->ops->notify(client, conn, type, channel, tmp,
195 case SILC_NOTIFY_TYPE_JOIN:
197 * Someone has joined to a channel. Get their ID and nickname and
198 * cache them for later use.
201 SILC_LOG_DEBUG(("Notify: JOIN"));
204 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
208 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
212 /* Find Client entry and if not found query it */
213 client_entry = silc_client_get_client_by_id(client, conn, client_id);
215 silc_client_notify_by_server_resolve(client, conn, packet,
216 SILC_ID_CLIENT, client_id);
220 /* If nickname or username hasn't been resolved, do so */
221 if (!client_entry->nickname || !client_entry->username) {
222 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
223 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
226 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
227 silc_client_notify_by_server_resolve(client, conn, packet,
228 SILC_ID_CLIENT, client_id);
231 if (client_entry != conn->local_entry)
232 silc_client_nickname_format(client, conn, client_entry);
236 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
240 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
244 /* Get channel entry */
245 channel = silc_client_get_channel_by_id(client, conn, channel_id);
249 /* Join the client to channel */
250 if (!silc_client_on_channel(channel, client_entry)) {
251 chu = silc_calloc(1, sizeof(*chu));
252 chu->client = client_entry;
253 chu->channel = channel;
254 silc_hash_table_add(channel->user_list, client_entry, chu);
255 silc_hash_table_add(client_entry->channels, channel, chu);
258 /* Notify application. The channel entry is sent last as this notify
259 is for channel but application don't know it from the arguments
261 client->internal->ops->notify(client, conn, type, client_entry, channel);
264 case SILC_NOTIFY_TYPE_LEAVE:
266 * Someone has left a channel. We will remove it from the channel but
267 * we'll keep it in the cache in case we'll need it later.
270 SILC_LOG_DEBUG(("Notify: LEAVE"));
273 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
277 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
281 /* Find Client entry */
283 silc_client_get_client_by_id(client, conn, client_id);
287 /* Get channel entry */
288 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
292 channel = silc_client_get_channel_by_id(client, conn, channel_id);
296 /* Remove client from channel */
297 chu = silc_client_on_channel(channel, client_entry);
299 silc_hash_table_del(client_entry->channels, channel);
300 silc_hash_table_del(channel->user_list, client_entry);
304 /* Some client implementations actually quit network by first doing
305 LEAVE and then immediately SIGNOFF. We'll check for this by doing
306 check for the client after 5 - 34 seconds. If it is not valid after
307 that we'll remove the client from cache. */
308 if (!silc_hash_table_count(client_entry->channels)) {
309 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
311 res->packet = silc_id_dup(client_id, SILC_ID_CLIENT);
312 silc_schedule_task_add(client->schedule, 0,
313 silc_client_notify_check_client, conn,
314 (5 + (silc_rng_get_rn16(client->rng) % 29)),
315 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
318 /* Notify application. The channel entry is sent last as this notify
319 is for channel but application don't know it from the arguments
321 client->internal->ops->notify(client, conn, type, client_entry, channel);
324 case SILC_NOTIFY_TYPE_SIGNOFF:
326 * Someone left SILC. We'll remove it from all channels and from cache.
329 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
332 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
336 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
340 /* Find Client entry */
342 silc_client_get_client_by_id(client, conn, client_id);
346 /* Remove from all channels */
347 silc_client_remove_from_channels(client, conn, client_entry);
349 /* Remove from cache */
350 silc_idcache_del_by_context(conn->client_cache, client_entry);
352 /* Get signoff message */
353 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
357 /* Notify application */
358 client->internal->ops->notify(client, conn, type, client_entry, tmp);
361 silc_client_del_client_entry(client, conn, client_entry);
364 case SILC_NOTIFY_TYPE_TOPIC_SET:
366 * Someone set the topic on a channel.
369 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
372 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
375 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
379 /* Find Client entry */
380 if (id_type == SILC_ID_CLIENT) {
381 /* Find Client entry */
383 client_entry = silc_client_get_client_by_id(client, conn, client_id);
385 silc_client_notify_by_server_resolve(client, conn, packet,
386 SILC_ID_CLIENT, client_id);
389 } else if (id_type == SILC_ID_SERVER) {
390 /* Find Server entry */
392 server = silc_client_get_server_by_id(client, conn, server_id);
394 silc_client_notify_by_server_resolve(client, conn, packet,
395 SILC_ID_SERVER, server_id);
399 /* Save the pointer to the client_entry pointer */
400 client_entry = (SilcClientEntry)server;
402 /* Find Channel entry */
404 channel = silc_client_get_channel_by_id(client, conn, channel_id);
406 silc_client_notify_by_server_resolve(client, conn, packet,
407 SILC_ID_CHANNEL, channel_id);
411 /* Save the pointer to the client_entry pointer */
412 client_entry = (SilcClientEntry)channel;
413 silc_free(channel_id);
418 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
422 /* Get channel entry */
423 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
427 channel = silc_client_get_channel_by_id(client, conn, channel_id);
431 /* Notify application. The channel entry is sent last as this notify
432 is for channel but application don't know it from the arguments
434 client->internal->ops->notify(client, conn, type, id_type,
435 client_entry, tmp, channel);
439 case SILC_NOTIFY_TYPE_NICK_CHANGE:
441 * Someone changed their nickname. If we don't have entry for the new
442 * ID we will query it and return here after it's done. After we've
443 * returned we fetch the old entry and free it and notify the
447 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
449 /* Get old Client ID */
450 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
454 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
459 if (SILC_ID_CLIENT_COMPARE(client_id, conn->local_id))
462 /* Find old Client entry */
463 client_entry = silc_client_get_client_by_id(client, conn, client_id);
466 silc_free(client_id);
468 client_entry->valid = FALSE;
470 /* Get new Client ID */
471 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
475 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
479 /* From protocol version 1.1 we get the new nickname in notify as well,
480 so we don't have to resolve it. Do it the hard way if server doesn't
482 tmp = silc_argument_get_arg_type(args, 3, NULL);
484 /* Protocol version 1.1 */
486 /* Create new client entry, and save all old information with the
487 new nickname and client ID */
488 client_entry2 = silc_client_add_client(client, conn, NULL, NULL,
489 client_entry->realname,
490 silc_id_dup(client_id,
495 if (client_entry->server)
496 client_entry2->server = strdup(client_entry->server);
497 if (client_entry->username)
498 client_entry2->username = strdup(client_entry->username);
499 if (client_entry->hostname)
500 client_entry2->hostname = strdup(client_entry->hostname);
501 silc_client_update_client(client, conn, client_entry2, tmp, NULL, NULL,
504 /* Protocol version 1.0 */
506 /* Find client entry and if not found resolve it */
507 client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
508 if (!client_entry2) {
509 /* Resolve the entry information */
510 silc_client_notify_by_server_resolve(client, conn, packet,
511 SILC_ID_CLIENT, client_id);
513 /* Add the new entry even though we resolved it. This is because we
514 want to replace the old entry with the new entry here right now. */
516 silc_client_add_client(client, conn, NULL, NULL, NULL,
517 silc_id_dup(client_id, SILC_ID_CLIENT),
520 /* Replace old ID entry with new one on all channels. */
521 silc_client_replace_from_channels(client, conn, client_entry,
526 if (client_entry2 != conn->local_entry)
527 silc_client_nickname_format(client, conn, client_entry2);
530 /* Remove the old from cache */
531 silc_idcache_del_by_context(conn->client_cache, client_entry);
533 /* Replace old ID entry with new one on all channels. */
534 silc_client_replace_from_channels(client, conn, client_entry,
537 /* Notify application */
538 client->internal->ops->notify(client, conn, type,
539 client_entry, client_entry2);
541 /* Free old client entry */
542 silc_client_del_client_entry(client, conn, client_entry);
546 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
548 * Someone changed a channel mode
551 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
554 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
557 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
561 /* Find Client entry */
562 if (id_type == SILC_ID_CLIENT) {
563 /* Find Client entry */
565 client_entry = silc_client_get_client_by_id(client, conn, client_id);
567 silc_client_notify_by_server_resolve(client, conn, packet,
568 SILC_ID_CLIENT, client_id);
571 } else if (id_type == SILC_ID_SERVER) {
572 /* Find Server entry */
574 server = silc_client_get_server_by_id(client, conn, server_id);
576 silc_client_notify_by_server_resolve(client, conn, packet,
577 SILC_ID_SERVER, server_id);
581 /* Save the pointer to the client_entry pointer */
582 client_entry = (SilcClientEntry)server;
584 /* Find Channel entry */
586 channel = silc_client_get_channel_by_id(client, conn, channel_id);
588 silc_client_notify_by_server_resolve(client, conn, packet,
589 SILC_ID_CHANNEL, channel_id);
593 /* Save the pointer to the client_entry pointer */
594 client_entry = (SilcClientEntry)channel;
595 silc_free(channel_id);
600 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
604 SILC_GET32_MSB(mode, tmp);
606 /* Get channel entry */
607 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
611 channel = silc_client_get_channel_by_id(client, conn, channel_id);
615 /* Save the new mode */
616 channel->mode = mode;
619 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
621 unsigned char hash[32];
624 silc_hmac_free(channel->hmac);
625 if (!silc_hmac_alloc(tmp, NULL, &channel->hmac))
628 silc_hash_make(silc_hmac_get_hash(channel->hmac),
629 channel->key, channel->key_len / 8,
631 silc_hmac_set_key(channel->hmac, hash,
632 silc_hash_len(silc_hmac_get_hash(channel->hmac)));
633 memset(hash, 0, sizeof(hash));
636 /* Notify application. The channel entry is sent last as this notify
637 is for channel but application don't know it from the arguments
639 client->internal->ops->notify(client, conn, type, id_type,
640 client_entry, mode, NULL, tmp, channel);
643 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
645 * Someone changed user's mode on a channel
648 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
651 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
654 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
658 /* Find Client entry */
659 if (id_type == SILC_ID_CLIENT) {
660 /* Find Client entry */
662 client_entry = silc_client_get_client_by_id(client, conn, client_id);
664 silc_client_notify_by_server_resolve(client, conn, packet,
665 SILC_ID_CLIENT, client_id);
668 } else if (id_type == SILC_ID_SERVER) {
669 /* Find Server entry */
671 server = silc_client_get_server_by_id(client, conn, server_id);
673 silc_client_notify_by_server_resolve(client, conn, packet,
674 SILC_ID_SERVER, server_id);
678 /* Save the pointer to the client_entry pointer */
679 client_entry = (SilcClientEntry)server;
681 /* Find Channel entry */
683 channel = silc_client_get_channel_by_id(client, conn, channel_id);
685 silc_client_notify_by_server_resolve(client, conn, packet,
686 SILC_ID_CHANNEL, channel_id);
690 /* Save the pointer to the client_entry pointer */
691 client_entry = (SilcClientEntry)channel;
692 silc_free(channel_id);
697 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
701 SILC_GET32_MSB(mode, tmp);
703 /* Get target Client ID */
704 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
708 silc_free(client_id);
709 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
713 /* Find target Client entry */
715 silc_client_get_client_by_id(client, conn, client_id);
719 /* Get channel entry */
720 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
724 channel = silc_client_get_channel_by_id(client, conn, channel_id);
729 chu = silc_client_on_channel(channel, client_entry2);
733 /* Notify application. The channel entry is sent last as this notify
734 is for channel but application don't know it from the arguments
736 client->internal->ops->notify(client, conn, type,
737 id_type, client_entry, mode,
738 client_entry2, channel);
741 case SILC_NOTIFY_TYPE_MOTD:
743 * Received Message of the day
746 SILC_LOG_DEBUG(("Notify: MOTD"));
749 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
753 /* Notify application */
754 client->internal->ops->notify(client, conn, type, tmp);
757 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
759 * Router has enforced a new ID to a channel. Let's change the old
760 * ID to the one provided here.
763 SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
766 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
769 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
773 /* Get the channel entry */
774 channel = silc_client_get_channel_by_id(client, conn, channel_id);
778 silc_free(channel_id);
781 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
784 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
788 /* Replace the Channel ID */
789 silc_client_replace_channel_id(client, conn, channel, channel_id);
791 /* Notify application */
792 client->internal->ops->notify(client, conn, type, channel, channel);
795 case SILC_NOTIFY_TYPE_KICKED:
797 * A client (maybe me) was kicked from a channel
800 SILC_LOG_DEBUG(("Notify: KICKED"));
803 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
807 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
811 /* Find Client entry */
812 client_entry = silc_client_get_client_by_id(client, conn, client_id);
816 /* Get channel entry */
817 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
821 channel = silc_client_get_channel_by_id(client, conn, channel_id);
825 /* From protocol version 1.1 we get the kicker's client ID as well */
826 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
828 silc_free(client_id);
829 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
833 /* Find kicker's client entry and if not found resolve it */
834 client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
835 if (!client_entry2) {
836 silc_client_notify_by_server_resolve(client, conn, packet,
837 SILC_ID_CLIENT, client_id);
840 if (client_entry2 != conn->local_entry)
841 silc_client_nickname_format(client, conn, client_entry2);
846 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
848 /* Notify application. The channel entry is sent last as this notify
849 is for channel but application don't know it from the arguments
851 client->internal->ops->notify(client, conn, type, client_entry, tmp,
852 client_entry2, channel);
854 /* Remove kicked client from channel */
855 if (client_entry == conn->local_entry) {
856 /* If I was kicked from channel, remove the channel */
857 if (conn->current_channel == channel)
858 conn->current_channel = NULL;
859 silc_client_del_channel(client, conn, channel);
861 chu = silc_client_on_channel(channel, client_entry);
863 silc_hash_table_del(client_entry->channels, channel);
864 silc_hash_table_del(channel->user_list, client_entry);
870 case SILC_NOTIFY_TYPE_KILLED:
873 * A client (maybe me) was killed from the network.
876 SilcUInt32 comment_len;
878 SILC_LOG_DEBUG(("Notify: KILLED"));
881 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
885 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
889 /* Find Client entry */
890 client_entry = silc_client_get_client_by_id(client, conn, client_id);
895 comment = silc_argument_get_arg_type(args, 2, &comment_len);
897 /* From protocol version 1.1 we get killer's client ID as well */
898 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
900 silc_free(client_id);
901 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
905 /* Find Client entry */
906 if (id_type == SILC_ID_CLIENT) {
907 /* Find Client entry */
909 client_entry2 = silc_client_get_client_by_id(client, conn,
912 silc_client_notify_by_server_resolve(client, conn, packet,
913 SILC_ID_CLIENT, client_id);
916 } else if (id_type == SILC_ID_SERVER) {
917 /* Find Server entry */
919 server = silc_client_get_server_by_id(client, conn, server_id);
921 silc_client_notify_by_server_resolve(client, conn, packet,
922 SILC_ID_SERVER, server_id);
926 /* Save the pointer to the client_entry pointer */
927 client_entry2 = (SilcClientEntry)server;
929 /* Find Channel entry */
931 channel = silc_client_get_channel_by_id(client, conn, channel_id);
933 silc_client_notify_by_server_resolve(client, conn, packet,
934 SILC_ID_CHANNEL, channel_id);
938 /* Save the pointer to the client_entry pointer */
939 client_entry2 = (SilcClientEntry)channel;
940 silc_free(channel_id);
945 /* Notify application. */
946 client->internal->ops->notify(client, conn, type, client_entry,
947 comment, id_type, client_entry2);
949 if (client_entry != conn->local_entry)
950 /* Remove the client from all channels and free it */
951 silc_client_del_client(client, conn, client_entry);
955 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
958 * A server quit the SILC network and some clients must be removed
959 * from channels as they quit as well.
961 SilcClientEntry *clients = NULL;
962 SilcUInt32 clients_count = 0;
965 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
967 for (i = 1; i < silc_argument_get_arg_num(args); i++) {
969 tmp = silc_argument_get_arg_type(args, i + 1, &tmp_len);
971 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
975 /* Get the client entry */
976 client_entry = silc_client_get_client_by_id(client, conn, client_id);
978 clients = silc_realloc(clients, sizeof(*clients) *
979 (clients_count + 1));
980 clients[clients_count] = client_entry;
983 silc_free(client_id);
988 /* Notify application. We don't keep server entries so the server
989 entry is returned as NULL. The client's are returned as array
990 of SilcClientEntry pointers. */
991 client->internal->ops->notify(client, conn, type, NULL,
992 clients, clients_count);
994 for (i = 0; i < clients_count; i++) {
995 /* Remove client from all channels */
996 client_entry = clients[i];
997 if (client_entry == conn->local_entry)
1000 /* Remove the client from all channels and free it */
1001 silc_client_del_client(client, conn, client_entry);
1013 silc_notify_payload_free(payload);
1014 silc_free(client_id);
1015 silc_free(channel_id);
1016 silc_free(server_id);