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 (conn->local_id && 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 */
485 char *tmp_nick = NULL;
487 /* Check whether nickname changed at all. It is possible that nick
488 change notify is received but nickname didn't changed, only the
490 if (client->internal->params->nickname_parse)
491 client->internal->params->nickname_parse(client_entry->nickname,
494 tmp_nick = strdup(tmp);
496 if (tmp_nick && !strcmp(tmp, tmp_nick)) {
497 /* Nickname didn't change. Update only the ID */
498 silc_idcache_del_by_context(conn->client_cache, client_entry);
499 silc_free(client_entry->id);
500 client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
501 silc_idcache_add(conn->client_cache, strdup(tmp),
502 client_entry->id, client_entry, 0, NULL);
504 /* Notify application */
505 client->internal->ops->notify(client, conn, type,
506 client_entry, client_entry);
511 /* Create new client entry, and save all old information with the
512 new nickname and client ID */
513 client_entry2 = silc_client_add_client(client, conn, NULL, NULL,
514 client_entry->realname,
515 silc_id_dup(client_id,
520 if (client_entry->server)
521 client_entry2->server = strdup(client_entry->server);
522 if (client_entry->username)
523 client_entry2->username = strdup(client_entry->username);
524 if (client_entry->hostname)
525 client_entry2->hostname = strdup(client_entry->hostname);
526 silc_client_update_client(client, conn, client_entry2, tmp, NULL, NULL,
529 /* Protocol version 1.0 */
531 /* Find client entry and if not found resolve it */
532 client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
533 if (!client_entry2) {
534 /* Resolve the entry information */
535 silc_client_notify_by_server_resolve(client, conn, packet,
536 SILC_ID_CLIENT, client_id);
538 /* Add the new entry even though we resolved it. This is because we
539 want to replace the old entry with the new entry here right now. */
541 silc_client_add_client(client, conn, NULL, NULL, NULL,
542 silc_id_dup(client_id, SILC_ID_CLIENT),
545 /* Replace old ID entry with new one on all channels. */
546 silc_client_replace_from_channels(client, conn, client_entry,
551 if (client_entry2 != conn->local_entry)
552 silc_client_nickname_format(client, conn, client_entry2);
555 /* Remove the old from cache */
556 silc_idcache_del_by_context(conn->client_cache, client_entry);
558 /* Replace old ID entry with new one on all channels. */
559 silc_client_replace_from_channels(client, conn, client_entry,
562 /* Notify application */
563 client->internal->ops->notify(client, conn, type,
564 client_entry, client_entry2);
566 /* Free old client entry */
567 silc_client_del_client_entry(client, conn, client_entry);
571 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
573 * Someone changed a channel mode
576 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
579 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
582 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
586 /* Find Client entry */
587 if (id_type == SILC_ID_CLIENT) {
588 /* Find Client entry */
590 client_entry = silc_client_get_client_by_id(client, conn, client_id);
592 silc_client_notify_by_server_resolve(client, conn, packet,
593 SILC_ID_CLIENT, client_id);
596 } else if (id_type == SILC_ID_SERVER) {
597 /* Find Server entry */
599 server = silc_client_get_server_by_id(client, conn, server_id);
601 silc_client_notify_by_server_resolve(client, conn, packet,
602 SILC_ID_SERVER, server_id);
606 /* Save the pointer to the client_entry pointer */
607 client_entry = (SilcClientEntry)server;
609 /* Find Channel entry */
611 channel = silc_client_get_channel_by_id(client, conn, channel_id);
613 silc_client_notify_by_server_resolve(client, conn, packet,
614 SILC_ID_CHANNEL, channel_id);
618 /* Save the pointer to the client_entry pointer */
619 client_entry = (SilcClientEntry)channel;
620 silc_free(channel_id);
625 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
629 SILC_GET32_MSB(mode, tmp);
631 /* Get channel entry */
632 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
636 channel = silc_client_get_channel_by_id(client, conn, channel_id);
640 /* Save the new mode */
641 channel->mode = mode;
644 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
646 unsigned char hash[32];
649 silc_hmac_free(channel->hmac);
650 if (!silc_hmac_alloc(tmp, NULL, &channel->hmac))
653 silc_hash_make(silc_hmac_get_hash(channel->hmac),
654 channel->key, channel->key_len / 8,
656 silc_hmac_set_key(channel->hmac, hash,
657 silc_hash_len(silc_hmac_get_hash(channel->hmac)));
658 memset(hash, 0, sizeof(hash));
661 /* Notify application. The channel entry is sent last as this notify
662 is for channel but application don't know it from the arguments
664 client->internal->ops->notify(client, conn, type, id_type,
665 client_entry, mode, NULL, tmp, channel);
668 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
670 * Someone changed user's mode on a channel
673 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
676 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
679 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
683 /* Find Client entry */
684 if (id_type == SILC_ID_CLIENT) {
685 /* Find Client entry */
687 client_entry = silc_client_get_client_by_id(client, conn, client_id);
689 silc_client_notify_by_server_resolve(client, conn, packet,
690 SILC_ID_CLIENT, client_id);
693 } else if (id_type == SILC_ID_SERVER) {
694 /* Find Server entry */
696 server = silc_client_get_server_by_id(client, conn, server_id);
698 silc_client_notify_by_server_resolve(client, conn, packet,
699 SILC_ID_SERVER, server_id);
703 /* Save the pointer to the client_entry pointer */
704 client_entry = (SilcClientEntry)server;
706 /* Find Channel entry */
708 channel = silc_client_get_channel_by_id(client, conn, channel_id);
710 silc_client_notify_by_server_resolve(client, conn, packet,
711 SILC_ID_CHANNEL, channel_id);
715 /* Save the pointer to the client_entry pointer */
716 client_entry = (SilcClientEntry)channel;
717 silc_free(channel_id);
722 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
726 SILC_GET32_MSB(mode, tmp);
728 /* Get target Client ID */
729 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
733 silc_free(client_id);
734 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
738 /* Find target Client entry */
740 silc_client_get_client_by_id(client, conn, client_id);
744 /* Get channel entry */
745 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
749 channel = silc_client_get_channel_by_id(client, conn, channel_id);
754 chu = silc_client_on_channel(channel, client_entry2);
758 /* Notify application. The channel entry is sent last as this notify
759 is for channel but application don't know it from the arguments
761 client->internal->ops->notify(client, conn, type,
762 id_type, client_entry, mode,
763 client_entry2, channel);
766 case SILC_NOTIFY_TYPE_MOTD:
768 * Received Message of the day
771 SILC_LOG_DEBUG(("Notify: MOTD"));
774 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
778 /* Notify application */
779 client->internal->ops->notify(client, conn, type, tmp);
782 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
784 * Router has enforced a new ID to a channel. Let's change the old
785 * ID to the one provided here.
788 SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
791 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
794 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
798 /* Get the channel entry */
799 channel = silc_client_get_channel_by_id(client, conn, channel_id);
803 silc_free(channel_id);
806 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
809 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
813 /* Replace the Channel ID */
814 silc_client_replace_channel_id(client, conn, channel, channel_id);
816 /* Notify application */
817 client->internal->ops->notify(client, conn, type, channel, channel);
820 case SILC_NOTIFY_TYPE_KICKED:
822 * A client (maybe me) was kicked from a channel
825 SILC_LOG_DEBUG(("Notify: KICKED"));
828 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
832 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
836 /* Find Client entry */
837 client_entry = silc_client_get_client_by_id(client, conn, client_id);
841 /* Get channel entry */
842 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
846 channel = silc_client_get_channel_by_id(client, conn, channel_id);
850 /* From protocol version 1.1 we get the kicker's client ID as well */
851 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
853 silc_free(client_id);
854 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
858 /* Find kicker's client entry and if not found resolve it */
859 client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
860 if (!client_entry2) {
861 silc_client_notify_by_server_resolve(client, conn, packet,
862 SILC_ID_CLIENT, client_id);
865 if (client_entry2 != conn->local_entry)
866 silc_client_nickname_format(client, conn, client_entry2);
871 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
873 /* Notify application. The channel entry is sent last as this notify
874 is for channel but application don't know it from the arguments
876 client->internal->ops->notify(client, conn, type, client_entry, tmp,
877 client_entry2, channel);
879 /* Remove kicked client from channel */
880 if (client_entry == conn->local_entry) {
881 /* If I was kicked from channel, remove the channel */
882 if (conn->current_channel == channel)
883 conn->current_channel = NULL;
884 silc_client_del_channel(client, conn, channel);
886 chu = silc_client_on_channel(channel, client_entry);
888 silc_hash_table_del(client_entry->channels, channel);
889 silc_hash_table_del(channel->user_list, client_entry);
895 case SILC_NOTIFY_TYPE_KILLED:
898 * A client (maybe me) was killed from the network.
901 SilcUInt32 comment_len;
903 SILC_LOG_DEBUG(("Notify: KILLED"));
906 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
910 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
914 /* Find Client entry */
915 client_entry = silc_client_get_client_by_id(client, conn, client_id);
920 comment = silc_argument_get_arg_type(args, 2, &comment_len);
922 /* From protocol version 1.1 we get killer's client ID as well */
923 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
925 silc_free(client_id);
926 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
930 /* Find Client entry */
931 if (id_type == SILC_ID_CLIENT) {
932 /* Find Client entry */
934 client_entry2 = silc_client_get_client_by_id(client, conn,
937 silc_client_notify_by_server_resolve(client, conn, packet,
938 SILC_ID_CLIENT, client_id);
941 } else if (id_type == SILC_ID_SERVER) {
942 /* Find Server entry */
944 server = silc_client_get_server_by_id(client, conn, server_id);
946 silc_client_notify_by_server_resolve(client, conn, packet,
947 SILC_ID_SERVER, server_id);
951 /* Save the pointer to the client_entry pointer */
952 client_entry2 = (SilcClientEntry)server;
954 /* Find Channel entry */
956 channel = silc_client_get_channel_by_id(client, conn, channel_id);
958 silc_client_notify_by_server_resolve(client, conn, packet,
959 SILC_ID_CHANNEL, channel_id);
963 /* Save the pointer to the client_entry pointer */
964 client_entry2 = (SilcClientEntry)channel;
965 silc_free(channel_id);
970 /* Notify application. */
971 client->internal->ops->notify(client, conn, type, client_entry,
972 comment, id_type, client_entry2);
974 if (client_entry != conn->local_entry)
975 /* Remove the client from all channels and free it */
976 silc_client_del_client(client, conn, client_entry);
980 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
983 * A server quit the SILC network and some clients must be removed
984 * from channels as they quit as well.
986 SilcClientEntry *clients = NULL;
987 SilcUInt32 clients_count = 0;
990 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
992 for (i = 1; i < silc_argument_get_arg_num(args); i++) {
994 tmp = silc_argument_get_arg_type(args, i + 1, &tmp_len);
996 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1000 /* Get the client entry */
1001 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1003 clients = silc_realloc(clients, sizeof(*clients) *
1004 (clients_count + 1));
1005 clients[clients_count] = client_entry;
1008 silc_free(client_id);
1013 /* Notify application. We don't keep server entries so the server
1014 entry is returned as NULL. The client's are returned as array
1015 of SilcClientEntry pointers. */
1016 client->internal->ops->notify(client, conn, type, NULL,
1017 clients, clients_count);
1019 for (i = 0; i < clients_count; i++) {
1020 /* Remove client from all channels */
1021 client_entry = clients[i];
1022 if (client_entry == conn->local_entry)
1025 /* Remove the client from all channels and free it */
1026 silc_client_del_client(client, conn, client_entry);
1038 silc_notify_payload_free(payload);
1039 silc_free(client_id);
1040 silc_free(channel_id);
1041 silc_free(server_id);