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 silc_client_notify_by_server_resolve(client, conn, packet,
227 SILC_ID_CLIENT, client_id);
228 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
229 client_entry->resolve_cmd_ident = conn->cmd_ident;
232 if (client_entry != conn->local_entry)
233 silc_client_nickname_format(client, conn, client_entry);
237 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
241 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
245 /* Get channel entry */
246 channel = silc_client_get_channel_by_id(client, conn, channel_id);
250 /* Join the client to channel */
251 if (!silc_client_on_channel(channel, client_entry)) {
252 chu = silc_calloc(1, sizeof(*chu));
253 chu->client = client_entry;
254 chu->channel = channel;
255 silc_hash_table_add(channel->user_list, client_entry, chu);
256 silc_hash_table_add(client_entry->channels, channel, chu);
259 /* Notify application. The channel entry is sent last as this notify
260 is for channel but application don't know it from the arguments
262 client->internal->ops->notify(client, conn, type, client_entry, channel);
265 case SILC_NOTIFY_TYPE_LEAVE:
267 * Someone has left a channel. We will remove it from the channel but
268 * we'll keep it in the cache in case we'll need it later.
271 SILC_LOG_DEBUG(("Notify: LEAVE"));
274 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
278 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
282 /* Find Client entry */
284 silc_client_get_client_by_id(client, conn, client_id);
288 /* Get channel entry */
289 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
293 channel = silc_client_get_channel_by_id(client, conn, channel_id);
297 /* Remove client from channel */
298 chu = silc_client_on_channel(channel, client_entry);
300 silc_hash_table_del(client_entry->channels, channel);
301 silc_hash_table_del(channel->user_list, client_entry);
305 /* Some client implementations actually quit network by first doing
306 LEAVE and then immediately SIGNOFF. We'll check for this by doing
307 check for the client after 5 - 34 seconds. If it is not valid after
308 that we'll remove the client from cache. */
309 if (!silc_hash_table_count(client_entry->channels)) {
310 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
312 res->packet = silc_id_dup(client_id, SILC_ID_CLIENT);
313 silc_schedule_task_add(client->schedule, 0,
314 silc_client_notify_check_client, conn,
315 (5 + (silc_rng_get_rn16(client->rng) % 29)),
316 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
319 /* Notify application. The channel entry is sent last as this notify
320 is for channel but application don't know it from the arguments
322 client->internal->ops->notify(client, conn, type, client_entry, channel);
325 case SILC_NOTIFY_TYPE_SIGNOFF:
327 * Someone left SILC. We'll remove it from all channels and from cache.
330 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
333 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
337 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
341 /* Find Client entry */
343 silc_client_get_client_by_id(client, conn, client_id);
347 /* Remove from all channels */
348 silc_client_remove_from_channels(client, conn, client_entry);
350 /* Remove from cache */
351 silc_idcache_del_by_context(conn->client_cache, client_entry);
353 /* Get signoff message */
354 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
358 /* Notify application */
359 client->internal->ops->notify(client, conn, type, client_entry, tmp);
362 silc_client_del_client_entry(client, conn, client_entry);
365 case SILC_NOTIFY_TYPE_TOPIC_SET:
367 * Someone set the topic on a channel.
370 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
373 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
376 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
380 /* Find Client entry */
381 if (id_type == SILC_ID_CLIENT) {
382 /* Find Client entry */
384 client_entry = silc_client_get_client_by_id(client, conn, client_id);
386 silc_client_notify_by_server_resolve(client, conn, packet,
387 SILC_ID_CLIENT, client_id);
390 } else if (id_type == SILC_ID_SERVER) {
391 /* Find Server entry */
393 server = silc_client_get_server_by_id(client, conn, server_id);
395 silc_client_notify_by_server_resolve(client, conn, packet,
396 SILC_ID_SERVER, server_id);
400 /* Save the pointer to the client_entry pointer */
401 client_entry = (SilcClientEntry)server;
403 /* Find Channel entry */
405 channel = silc_client_get_channel_by_id(client, conn, channel_id);
407 silc_client_notify_by_server_resolve(client, conn, packet,
408 SILC_ID_CHANNEL, channel_id);
412 /* Save the pointer to the client_entry pointer */
413 client_entry = (SilcClientEntry)channel;
414 silc_free(channel_id);
419 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
423 /* Get channel entry */
424 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
428 channel = silc_client_get_channel_by_id(client, conn, channel_id);
432 /* Notify application. The channel entry is sent last as this notify
433 is for channel but application don't know it from the arguments
435 client->internal->ops->notify(client, conn, type, id_type,
436 client_entry, tmp, channel);
440 case SILC_NOTIFY_TYPE_NICK_CHANGE:
442 * Someone changed their nickname. If we don't have entry for the new
443 * ID we will query it and return here after it's done. After we've
444 * returned we fetch the old entry and free it and notify the
448 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
450 /* Get old Client ID */
451 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
455 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
460 if (conn->local_id && SILC_ID_CLIENT_COMPARE(client_id, conn->local_id))
463 /* Find old Client entry */
464 client_entry = silc_client_get_client_by_id(client, conn, client_id);
467 silc_free(client_id);
469 client_entry->valid = FALSE;
471 /* Get new Client ID */
472 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
476 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
480 /* From protocol version 1.1 we get the new nickname in notify as well,
481 so we don't have to resolve it. Do it the hard way if server doesn't
483 tmp = silc_argument_get_arg_type(args, 3, NULL);
485 /* Protocol version 1.1 */
486 char *tmp_nick = NULL;
488 /* Check whether nickname changed at all. It is possible that nick
489 change notify is received but nickname didn't changed, only the
491 if (client->internal->params->nickname_parse)
492 client->internal->params->nickname_parse(client_entry->nickname,
495 tmp_nick = strdup(tmp);
497 if (tmp_nick && !strcmp(tmp, tmp_nick)) {
498 /* Nickname didn't change. Update only the ID */
499 silc_idcache_del_by_context(conn->client_cache, client_entry);
500 silc_free(client_entry->id);
501 client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
502 silc_idcache_add(conn->client_cache, strdup(tmp),
503 client_entry->id, client_entry, 0, NULL);
505 /* Notify application */
506 client->internal->ops->notify(client, conn, type,
507 client_entry, client_entry);
512 /* Create new client entry, and save all old information with the
513 new nickname and client ID */
514 client_entry2 = silc_client_add_client(client, conn, NULL, NULL,
515 client_entry->realname,
516 silc_id_dup(client_id,
521 if (client_entry->server)
522 client_entry2->server = strdup(client_entry->server);
523 if (client_entry->username)
524 client_entry2->username = strdup(client_entry->username);
525 if (client_entry->hostname)
526 client_entry2->hostname = strdup(client_entry->hostname);
527 silc_client_update_client(client, conn, client_entry2, tmp, NULL, NULL,
530 /* Protocol version 1.0 */
532 /* Find client entry and if not found resolve it */
533 client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
534 if (!client_entry2) {
535 /* Resolve the entry information */
536 silc_client_notify_by_server_resolve(client, conn, packet,
537 SILC_ID_CLIENT, client_id);
539 /* Add the new entry even though we resolved it. This is because we
540 want to replace the old entry with the new entry here right now. */
542 silc_client_add_client(client, conn, NULL, NULL, NULL,
543 silc_id_dup(client_id, SILC_ID_CLIENT),
546 /* Replace old ID entry with new one on all channels. */
547 silc_client_replace_from_channels(client, conn, client_entry,
552 if (client_entry2 != conn->local_entry)
553 silc_client_nickname_format(client, conn, client_entry2);
556 /* Remove the old from cache */
557 silc_idcache_del_by_context(conn->client_cache, client_entry);
559 /* Replace old ID entry with new one on all channels. */
560 silc_client_replace_from_channels(client, conn, client_entry,
563 /* Notify application */
564 client->internal->ops->notify(client, conn, type,
565 client_entry, client_entry2);
567 /* Free old client entry */
568 silc_client_del_client_entry(client, conn, client_entry);
572 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
574 * Someone changed a channel mode
577 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
580 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
583 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
587 /* Find Client entry */
588 if (id_type == SILC_ID_CLIENT) {
589 /* Find Client entry */
591 client_entry = silc_client_get_client_by_id(client, conn, client_id);
593 silc_client_notify_by_server_resolve(client, conn, packet,
594 SILC_ID_CLIENT, client_id);
597 } else if (id_type == SILC_ID_SERVER) {
598 /* Find Server entry */
600 server = silc_client_get_server_by_id(client, conn, server_id);
602 silc_client_notify_by_server_resolve(client, conn, packet,
603 SILC_ID_SERVER, server_id);
607 /* Save the pointer to the client_entry pointer */
608 client_entry = (SilcClientEntry)server;
610 /* Find Channel entry */
612 channel = silc_client_get_channel_by_id(client, conn, channel_id);
614 silc_client_notify_by_server_resolve(client, conn, packet,
615 SILC_ID_CHANNEL, channel_id);
619 /* Save the pointer to the client_entry pointer */
620 client_entry = (SilcClientEntry)channel;
621 silc_free(channel_id);
626 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
630 SILC_GET32_MSB(mode, tmp);
632 /* Get channel entry */
633 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
637 channel = silc_client_get_channel_by_id(client, conn, channel_id);
641 /* Save the new mode */
642 channel->mode = mode;
645 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
647 unsigned char hash[32];
650 silc_hmac_free(channel->hmac);
651 if (!silc_hmac_alloc(tmp, NULL, &channel->hmac))
654 silc_hash_make(silc_hmac_get_hash(channel->hmac),
655 channel->key, channel->key_len / 8,
657 silc_hmac_set_key(channel->hmac, hash,
658 silc_hash_len(silc_hmac_get_hash(channel->hmac)));
659 memset(hash, 0, sizeof(hash));
662 /* Notify application. The channel entry is sent last as this notify
663 is for channel but application don't know it from the arguments
665 client->internal->ops->notify(client, conn, type, id_type,
666 client_entry, mode, NULL, tmp, channel);
669 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
671 * Someone changed user's mode on a channel
674 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
677 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
680 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
684 /* Find Client entry */
685 if (id_type == SILC_ID_CLIENT) {
686 /* Find Client entry */
688 client_entry = silc_client_get_client_by_id(client, conn, client_id);
690 silc_client_notify_by_server_resolve(client, conn, packet,
691 SILC_ID_CLIENT, client_id);
694 } else if (id_type == SILC_ID_SERVER) {
695 /* Find Server entry */
697 server = silc_client_get_server_by_id(client, conn, server_id);
699 silc_client_notify_by_server_resolve(client, conn, packet,
700 SILC_ID_SERVER, server_id);
704 /* Save the pointer to the client_entry pointer */
705 client_entry = (SilcClientEntry)server;
707 /* Find Channel entry */
709 channel = silc_client_get_channel_by_id(client, conn, channel_id);
711 silc_client_notify_by_server_resolve(client, conn, packet,
712 SILC_ID_CHANNEL, channel_id);
716 /* Save the pointer to the client_entry pointer */
717 client_entry = (SilcClientEntry)channel;
718 silc_free(channel_id);
723 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
727 SILC_GET32_MSB(mode, tmp);
729 /* Get target Client ID */
730 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
734 silc_free(client_id);
735 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
739 /* Find target Client entry */
741 silc_client_get_client_by_id(client, conn, client_id);
745 /* Get channel entry */
746 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
750 channel = silc_client_get_channel_by_id(client, conn, channel_id);
755 chu = silc_client_on_channel(channel, client_entry2);
759 /* Notify application. The channel entry is sent last as this notify
760 is for channel but application don't know it from the arguments
762 client->internal->ops->notify(client, conn, type,
763 id_type, client_entry, mode,
764 client_entry2, channel);
767 case SILC_NOTIFY_TYPE_MOTD:
769 * Received Message of the day
772 SILC_LOG_DEBUG(("Notify: MOTD"));
775 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
779 /* Notify application */
780 client->internal->ops->notify(client, conn, type, tmp);
783 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
785 * Router has enforced a new ID to a channel. Let's change the old
786 * ID to the one provided here.
789 SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
792 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
795 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
799 /* Get the channel entry */
800 channel = silc_client_get_channel_by_id(client, conn, channel_id);
804 silc_free(channel_id);
807 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
810 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
814 /* Replace the Channel ID */
815 silc_client_replace_channel_id(client, conn, channel, channel_id);
817 /* Notify application */
818 client->internal->ops->notify(client, conn, type, channel, channel);
821 case SILC_NOTIFY_TYPE_KICKED:
823 * A client (maybe me) was kicked from a channel
826 SILC_LOG_DEBUG(("Notify: KICKED"));
829 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
833 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
837 /* Find Client entry */
838 client_entry = silc_client_get_client_by_id(client, conn, client_id);
842 /* Get channel entry */
843 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
847 channel = silc_client_get_channel_by_id(client, conn, channel_id);
851 /* From protocol version 1.1 we get the kicker's client ID as well */
852 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
854 silc_free(client_id);
855 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
859 /* Find kicker's client entry and if not found resolve it */
860 client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
861 if (!client_entry2) {
862 silc_client_notify_by_server_resolve(client, conn, packet,
863 SILC_ID_CLIENT, client_id);
866 if (client_entry2 != conn->local_entry)
867 silc_client_nickname_format(client, conn, client_entry2);
872 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
874 /* Notify application. The channel entry is sent last as this notify
875 is for channel but application don't know it from the arguments
877 client->internal->ops->notify(client, conn, type, client_entry, tmp,
878 client_entry2, channel);
880 /* Remove kicked client from channel */
881 if (client_entry == conn->local_entry) {
882 /* If I was kicked from channel, remove the channel */
883 if (conn->current_channel == channel)
884 conn->current_channel = NULL;
885 silc_client_del_channel(client, conn, channel);
887 chu = silc_client_on_channel(channel, client_entry);
889 silc_hash_table_del(client_entry->channels, channel);
890 silc_hash_table_del(channel->user_list, client_entry);
896 case SILC_NOTIFY_TYPE_KILLED:
899 * A client (maybe me) was killed from the network.
902 SilcUInt32 comment_len;
904 SILC_LOG_DEBUG(("Notify: KILLED"));
907 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
911 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
915 /* Find Client entry */
916 client_entry = silc_client_get_client_by_id(client, conn, client_id);
921 comment = silc_argument_get_arg_type(args, 2, &comment_len);
923 /* From protocol version 1.1 we get killer's client ID as well */
924 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
926 silc_free(client_id);
927 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
931 /* Find Client entry */
932 if (id_type == SILC_ID_CLIENT) {
933 /* Find Client entry */
935 client_entry2 = silc_client_get_client_by_id(client, conn,
938 silc_client_notify_by_server_resolve(client, conn, packet,
939 SILC_ID_CLIENT, client_id);
942 } else if (id_type == SILC_ID_SERVER) {
943 /* Find Server entry */
945 server = silc_client_get_server_by_id(client, conn, server_id);
947 silc_client_notify_by_server_resolve(client, conn, packet,
948 SILC_ID_SERVER, server_id);
952 /* Save the pointer to the client_entry pointer */
953 client_entry2 = (SilcClientEntry)server;
955 /* Find Channel entry */
957 channel = silc_client_get_channel_by_id(client, conn, channel_id);
959 silc_client_notify_by_server_resolve(client, conn, packet,
960 SILC_ID_CHANNEL, channel_id);
964 /* Save the pointer to the client_entry pointer */
965 client_entry2 = (SilcClientEntry)channel;
966 silc_free(channel_id);
971 /* Notify application. */
972 client->internal->ops->notify(client, conn, type, client_entry,
973 comment, id_type, client_entry2);
975 if (client_entry != conn->local_entry)
976 /* Remove the client from all channels and free it */
977 silc_client_del_client(client, conn, client_entry);
981 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
984 * A server quit the SILC network and some clients must be removed
985 * from channels as they quit as well.
987 SilcClientEntry *clients = NULL;
988 SilcUInt32 clients_count = 0;
991 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
993 for (i = 1; i < silc_argument_get_arg_num(args); i++) {
995 tmp = silc_argument_get_arg_type(args, i + 1, &tmp_len);
997 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1001 /* Get the client entry */
1002 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1004 clients = silc_realloc(clients, sizeof(*clients) *
1005 (clients_count + 1));
1006 clients[clients_count] = client_entry;
1009 silc_free(client_id);
1014 /* Notify application. We don't keep server entries so the server
1015 entry is returned as NULL. The client's are returned as array
1016 of SilcClientEntry pointers. */
1017 client->internal->ops->notify(client, conn, type, NULL,
1018 clients, clients_count);
1020 for (i = 0; i < clients_count; i++) {
1021 /* Remove client from all channels */
1022 client_entry = clients[i];
1023 if (client_entry == conn->local_entry)
1026 /* Remove the client from all channels and free it */
1027 silc_client_del_client(client, conn, client_entry);
1034 case SILC_NOTIFY_TYPE_ERROR:
1037 * Some has occurred and server is notifying us about it.
1041 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1042 if (!tmp && tmp_len != 1)
1044 error = (SilcStatus)tmp[0];
1046 SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1048 if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1049 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1051 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1054 client_entry = silc_client_get_client_by_id(client, conn,
1057 silc_client_del_client(client, conn, client_entry);
1061 /* Notify application. */
1062 client->internal->ops->notify(client, conn, type, error);
1071 silc_notify_payload_free(payload);
1072 silc_free(client_id);
1073 silc_free(channel_id);
1074 silc_free(server_id);