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 SILC_TASK_CALLBACK(silc_client_notify_del_client_cb)
49 SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
50 SilcClient client = res->context;
51 SilcClientConnection conn = res->sock->user_data;
52 SilcClientID *client_id = res->packet;
53 SilcClientEntry client_entry;
54 client_entry = silc_client_get_client_by_id(client, conn, client_id);
56 silc_client_del_client(client, conn, client_entry);
58 silc_socket_free(res->sock);
62 /* Called when notify is received and some async operation (such as command)
63 is required before processing the notify message. This calls again the
64 silc_client_notify_by_server and reprocesses the original notify packet. */
66 static void silc_client_notify_by_server_pending(void *context, void *context2)
68 SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
69 SilcClientCommandReplyContext reply =
70 (SilcClientCommandReplyContext)context2;
72 SILC_LOG_DEBUG(("Start"));
74 if (reply && !silc_command_get_status(reply->payload, NULL, NULL))
77 silc_client_notify_by_server(res->context, res->sock, res->packet);
80 silc_socket_free(res->sock);
81 silc_packet_context_free(res->packet);
85 /* Resolve client, channel or server information. */
87 static void silc_client_notify_by_server_resolve(SilcClient client,
88 SilcClientConnection conn,
89 SilcPacketContext *packet,
93 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
94 SilcBuffer idp = silc_id_payload_encode(id, id_type);
96 res->packet = silc_packet_context_dup(packet);
97 res->context = client;
98 res->sock = silc_socket_dup(conn->sock);
100 /* For client resolving use WHOIS, and otherwise use IDENTIFY */
101 if (id_type == SILC_ID_CLIENT) {
102 silc_client_command_register(client, SILC_COMMAND_WHOIS, NULL, NULL,
103 silc_client_command_reply_whois_i, 0,
105 silc_client_command_send(client, conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
106 1, 4, idp->data, idp->len);
107 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
108 silc_client_notify_by_server_pending, res);
110 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
111 silc_client_command_reply_identify_i, 0,
113 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
114 conn->cmd_ident, 1, 5, idp->data, idp->len);
115 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
116 silc_client_notify_by_server_pending, res);
118 silc_buffer_free(idp);
121 /* Received notify message from server */
123 void silc_client_notify_by_server(SilcClient client,
124 SilcSocketConnection sock,
125 SilcPacketContext *packet)
127 SilcBuffer buffer = packet->buffer;
128 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
129 SilcNotifyPayload payload;
131 SilcArgumentPayload args;
135 SilcClientID *client_id = NULL;
136 SilcChannelID *channel_id = NULL;
137 SilcServerID *server_id = NULL;
138 SilcClientEntry client_entry = NULL;
139 SilcClientEntry client_entry2 = NULL;
140 SilcChannelEntry channel;
142 SilcServerEntry server;
144 SilcUInt32 tmp_len, mode;
146 SILC_LOG_DEBUG(("Start"));
148 payload = silc_notify_payload_parse(buffer->data, buffer->len);
152 type = silc_notify_get_type(payload);
153 args = silc_notify_get_args(payload);
158 case SILC_NOTIFY_TYPE_NONE:
159 /* Notify application */
160 client->internal->ops->notify(client, conn, type,
161 silc_argument_get_arg_type(args, 1, NULL));
164 case SILC_NOTIFY_TYPE_INVITE:
166 * Someone invited me to a channel. Find Client and Channel entries
167 * for the application.
170 SILC_LOG_DEBUG(("Notify: INVITE"));
173 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
177 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
181 /* Get the channel entry */
182 channel = silc_client_get_channel_by_id(client, conn, channel_id);
184 /* Get sender Client ID */
185 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
189 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
193 /* Find Client entry and if not found query it */
194 client_entry = silc_client_get_client_by_id(client, conn, client_id);
196 silc_client_notify_by_server_resolve(client, conn, packet,
197 SILC_ID_CLIENT, client_id);
201 /* Get the channel name */
202 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
206 /* Notify application */
207 client->internal->ops->notify(client, conn, type, channel, tmp,
211 case SILC_NOTIFY_TYPE_JOIN:
213 * Someone has joined to a channel. Get their ID and nickname and
214 * cache them for later use.
217 SILC_LOG_DEBUG(("Notify: JOIN"));
220 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
224 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
228 /* Find Client entry and if not found query it */
229 client_entry = silc_client_get_client_by_id(client, conn, client_id);
231 silc_client_notify_by_server_resolve(client, conn, packet,
232 SILC_ID_CLIENT, client_id);
236 /* If nickname or username hasn't been resolved, do so */
237 if (!client_entry->nickname || !client_entry->username) {
238 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
239 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
242 silc_client_notify_by_server_resolve(client, conn, packet,
243 SILC_ID_CLIENT, client_id);
244 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
245 client_entry->resolve_cmd_ident = conn->cmd_ident;
248 if (client_entry != conn->local_entry)
249 silc_client_nickname_format(client, conn, client_entry);
253 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
257 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
261 /* Get channel entry */
262 channel = silc_client_get_channel_by_id(client, conn, channel_id);
266 /* Join the client to channel */
267 if (!silc_client_on_channel(channel, client_entry)) {
268 chu = silc_calloc(1, sizeof(*chu));
269 chu->client = client_entry;
270 chu->channel = channel;
271 silc_hash_table_add(channel->user_list, client_entry, chu);
272 silc_hash_table_add(client_entry->channels, channel, chu);
275 /* Notify application. The channel entry is sent last as this notify
276 is for channel but application don't know it from the arguments
278 client->internal->ops->notify(client, conn, type, client_entry, channel);
281 case SILC_NOTIFY_TYPE_LEAVE:
283 * Someone has left a channel. We will remove it from the channel but
284 * we'll keep it in the cache in case we'll need it later.
287 SILC_LOG_DEBUG(("Notify: LEAVE"));
290 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
294 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
298 /* Find Client entry */
300 silc_client_get_client_by_id(client, conn, client_id);
304 /* Get channel entry */
305 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
309 channel = silc_client_get_channel_by_id(client, conn, channel_id);
313 /* Remove client from channel */
314 chu = silc_client_on_channel(channel, client_entry);
316 silc_hash_table_del(client_entry->channels, channel);
317 silc_hash_table_del(channel->user_list, client_entry);
321 /* Some client implementations actually quit network by first doing
322 LEAVE and then immediately SIGNOFF. We'll check for this by doing
323 check for the client after 5 - 34 seconds. If it is not valid after
324 that we'll remove the client from cache. */
325 if (!silc_hash_table_count(client_entry->channels)) {
326 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
327 res->context = client;
328 res->sock = silc_socket_dup(conn->sock);
329 res->packet = silc_id_dup(client_id, SILC_ID_CLIENT);
330 silc_schedule_task_add(client->schedule, conn->sock->sock,
331 silc_client_notify_check_client, res,
332 (5 + (silc_rng_get_rn16(client->rng) % 29)),
333 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
336 /* Notify application. The channel entry is sent last as this notify
337 is for channel but application don't know it from the arguments
339 client->internal->ops->notify(client, conn, type, client_entry, channel);
342 case SILC_NOTIFY_TYPE_SIGNOFF:
344 * Someone left SILC. We'll remove it from all channels and from cache.
347 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
350 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
354 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
358 /* Find Client entry */
360 silc_client_get_client_by_id(client, conn, client_id);
364 /* Remove from all channels */
365 silc_client_remove_from_channels(client, conn, client_entry);
367 /* Remove from cache */
368 silc_idcache_del_by_context(conn->client_cache, client_entry);
370 /* Get signoff message */
371 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
375 /* Notify application */
376 client->internal->ops->notify(client, conn, type, client_entry, tmp);
379 silc_client_del_client_entry(client, conn, client_entry);
382 case SILC_NOTIFY_TYPE_TOPIC_SET:
384 * Someone set the topic on a channel.
387 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
390 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
393 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
397 /* Find Client entry */
398 if (id_type == SILC_ID_CLIENT) {
399 /* Find Client entry */
401 client_entry = silc_client_get_client_by_id(client, conn, client_id);
403 silc_client_notify_by_server_resolve(client, conn, packet,
404 SILC_ID_CLIENT, client_id);
407 } else if (id_type == SILC_ID_SERVER) {
408 /* Find Server entry */
410 server = silc_client_get_server_by_id(client, conn, server_id);
412 silc_client_notify_by_server_resolve(client, conn, packet,
413 SILC_ID_SERVER, server_id);
417 /* Save the pointer to the client_entry pointer */
418 client_entry = (SilcClientEntry)server;
420 /* Find Channel entry */
422 channel = silc_client_get_channel_by_id(client, conn, channel_id);
424 silc_client_notify_by_server_resolve(client, conn, packet,
425 SILC_ID_CHANNEL, channel_id);
429 /* Save the pointer to the client_entry pointer */
430 client_entry = (SilcClientEntry)channel;
431 silc_free(channel_id);
436 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
440 /* Get channel entry */
441 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
445 channel = silc_client_get_channel_by_id(client, conn, channel_id);
449 /* Notify application. The channel entry is sent last as this notify
450 is for channel but application don't know it from the arguments
452 client->internal->ops->notify(client, conn, type, id_type,
453 client_entry, tmp, channel);
457 case SILC_NOTIFY_TYPE_NICK_CHANGE:
459 * Someone changed their nickname. If we don't have entry for the new
460 * ID we will query it and return here after it's done. After we've
461 * returned we fetch the old entry and free it and notify the
465 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
467 /* Get old Client ID */
468 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
472 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
477 if (conn->local_id && SILC_ID_CLIENT_COMPARE(client_id, conn->local_id))
480 /* Find old Client entry */
481 client_entry = silc_client_get_client_by_id(client, conn, client_id);
484 silc_free(client_id);
486 client_entry->valid = FALSE;
488 /* Get new Client ID */
489 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
493 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
497 /* From protocol version 1.1 we get the new nickname in notify as well,
498 so we don't have to resolve it. Do it the hard way if server doesn't
500 tmp = silc_argument_get_arg_type(args, 3, NULL);
502 /* Protocol version 1.1 */
503 char *tmp_nick = NULL;
505 /* Check whether nickname changed at all. It is possible that nick
506 change notify is received but nickname didn't changed, only the
508 if (client->internal->params->nickname_parse)
509 client->internal->params->nickname_parse(client_entry->nickname,
512 tmp_nick = strdup(tmp);
514 if (tmp_nick && !strcmp(tmp, tmp_nick)) {
515 /* Nickname didn't change. Update only the ID */
516 silc_idcache_del_by_context(conn->client_cache, client_entry);
517 silc_free(client_entry->id);
518 client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
519 silc_idcache_add(conn->client_cache, strdup(tmp),
520 client_entry->id, client_entry, 0, NULL);
522 /* Notify application */
523 client->internal->ops->notify(client, conn, type,
524 client_entry, client_entry);
529 /* Create new client entry, and save all old information with the
530 new nickname and client ID */
531 client_entry2 = silc_client_add_client(client, conn, NULL, NULL,
532 client_entry->realname,
533 silc_id_dup(client_id,
538 if (client_entry->server)
539 client_entry2->server = strdup(client_entry->server);
540 if (client_entry->username)
541 client_entry2->username = strdup(client_entry->username);
542 if (client_entry->hostname)
543 client_entry2->hostname = strdup(client_entry->hostname);
544 silc_client_update_client(client, conn, client_entry2, tmp, NULL, NULL,
547 /* Protocol version 1.0 */
549 /* Find client entry and if not found resolve it */
550 client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
551 if (!client_entry2) {
552 /* Resolve the entry information */
553 silc_client_notify_by_server_resolve(client, conn, packet,
554 SILC_ID_CLIENT, client_id);
556 /* Add the new entry even though we resolved it. This is because we
557 want to replace the old entry with the new entry here right now. */
559 silc_client_add_client(client, conn, NULL, NULL, NULL,
560 silc_id_dup(client_id, SILC_ID_CLIENT),
563 /* Replace old ID entry with new one on all channels. */
564 silc_client_replace_from_channels(client, conn, client_entry,
569 if (client_entry2 != conn->local_entry)
570 silc_client_nickname_format(client, conn, client_entry2);
573 /* Remove the old from cache */
574 silc_idcache_del_by_context(conn->client_cache, client_entry);
576 /* Replace old ID entry with new one on all channels. */
577 silc_client_replace_from_channels(client, conn, client_entry,
580 /* Notify application */
581 client->internal->ops->notify(client, conn, type,
582 client_entry, client_entry2);
584 /* Free old client entry */
585 silc_client_del_client_entry(client, conn, client_entry);
589 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
591 * Someone changed a channel mode
594 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
597 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
600 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
604 /* Find Client entry */
605 if (id_type == SILC_ID_CLIENT) {
606 /* Find Client entry */
608 client_entry = silc_client_get_client_by_id(client, conn, client_id);
610 silc_client_notify_by_server_resolve(client, conn, packet,
611 SILC_ID_CLIENT, client_id);
614 } else if (id_type == SILC_ID_SERVER) {
615 /* Find Server entry */
617 server = silc_client_get_server_by_id(client, conn, server_id);
619 silc_client_notify_by_server_resolve(client, conn, packet,
620 SILC_ID_SERVER, server_id);
624 /* Save the pointer to the client_entry pointer */
625 client_entry = (SilcClientEntry)server;
627 /* Find Channel entry */
629 channel = silc_client_get_channel_by_id(client, conn, channel_id);
631 silc_client_notify_by_server_resolve(client, conn, packet,
632 SILC_ID_CHANNEL, channel_id);
636 /* Save the pointer to the client_entry pointer */
637 client_entry = (SilcClientEntry)channel;
638 silc_free(channel_id);
643 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
647 SILC_GET32_MSB(mode, tmp);
649 /* Get channel entry */
650 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
654 channel = silc_client_get_channel_by_id(client, conn, channel_id);
658 /* Save the new mode */
659 channel->mode = mode;
662 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
664 unsigned char hash[32];
667 silc_hmac_free(channel->hmac);
668 if (!silc_hmac_alloc(tmp, NULL, &channel->hmac))
671 silc_hash_make(silc_hmac_get_hash(channel->hmac),
672 channel->key, channel->key_len / 8,
674 silc_hmac_set_key(channel->hmac, hash,
675 silc_hash_len(silc_hmac_get_hash(channel->hmac)));
676 memset(hash, 0, sizeof(hash));
679 /* Notify application. The channel entry is sent last as this notify
680 is for channel but application don't know it from the arguments
682 client->internal->ops->notify(client, conn, type, id_type,
683 client_entry, mode, NULL, tmp, channel);
686 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
688 * Someone changed user's mode on a channel
691 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
694 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
697 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
701 /* Find Client entry */
702 if (id_type == SILC_ID_CLIENT) {
703 /* Find Client entry */
705 client_entry = silc_client_get_client_by_id(client, conn, client_id);
707 silc_client_notify_by_server_resolve(client, conn, packet,
708 SILC_ID_CLIENT, client_id);
711 } else if (id_type == SILC_ID_SERVER) {
712 /* Find Server entry */
714 server = silc_client_get_server_by_id(client, conn, server_id);
716 silc_client_notify_by_server_resolve(client, conn, packet,
717 SILC_ID_SERVER, server_id);
721 /* Save the pointer to the client_entry pointer */
722 client_entry = (SilcClientEntry)server;
724 /* Find Channel entry */
726 channel = silc_client_get_channel_by_id(client, conn, channel_id);
728 silc_client_notify_by_server_resolve(client, conn, packet,
729 SILC_ID_CHANNEL, channel_id);
733 /* Save the pointer to the client_entry pointer */
734 client_entry = (SilcClientEntry)channel;
735 silc_free(channel_id);
740 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
744 SILC_GET32_MSB(mode, tmp);
746 /* Get target Client ID */
747 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
751 silc_free(client_id);
752 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
756 /* Find target Client entry */
758 silc_client_get_client_by_id(client, conn, client_id);
759 if (!client_entry2) {
760 silc_client_notify_by_server_resolve(client, conn, packet,
761 SILC_ID_CLIENT, client_id);
765 /* Get channel entry */
766 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
770 channel = silc_client_get_channel_by_id(client, conn, channel_id);
775 chu = silc_client_on_channel(channel, client_entry2);
779 /* Notify application. The channel entry is sent last as this notify
780 is for channel but application don't know it from the arguments
782 client->internal->ops->notify(client, conn, type,
783 id_type, client_entry, mode,
784 client_entry2, channel);
787 case SILC_NOTIFY_TYPE_MOTD:
789 * Received Message of the day
792 SILC_LOG_DEBUG(("Notify: MOTD"));
795 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
799 /* Notify application */
800 client->internal->ops->notify(client, conn, type, tmp);
803 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
805 * Router has enforced a new ID to a channel. Let's change the old
806 * ID to the one provided here.
809 SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
812 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
815 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
819 /* Get the channel entry */
820 channel = silc_client_get_channel_by_id(client, conn, channel_id);
824 silc_free(channel_id);
827 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
830 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
834 /* Replace the Channel ID */
835 if (silc_client_replace_channel_id(client, conn, channel, channel_id))
838 /* Notify application */
839 client->internal->ops->notify(client, conn, type, channel, channel);
842 case SILC_NOTIFY_TYPE_KICKED:
844 * A client (maybe me) was kicked from a channel
847 SILC_LOG_DEBUG(("Notify: KICKED"));
850 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
854 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
858 /* Find Client entry */
859 client_entry = silc_client_get_client_by_id(client, conn, client_id);
863 /* Get channel entry */
864 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
868 channel = silc_client_get_channel_by_id(client, conn, channel_id);
872 /* From protocol version 1.1 we get the kicker's client ID as well */
873 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
875 silc_free(client_id);
876 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
880 /* Find kicker's client entry and if not found resolve it */
881 client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
882 if (!client_entry2) {
883 silc_client_notify_by_server_resolve(client, conn, packet,
884 SILC_ID_CLIENT, client_id);
887 if (client_entry2 != conn->local_entry)
888 silc_client_nickname_format(client, conn, client_entry2);
893 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
895 /* Notify application. The channel entry is sent last as this notify
896 is for channel but application don't know it from the arguments
898 client->internal->ops->notify(client, conn, type, client_entry, tmp,
899 client_entry2, channel);
901 /* Remove kicked client from channel */
902 if (client_entry == conn->local_entry) {
903 /* If I was kicked from channel, remove the channel */
904 if (conn->current_channel == channel)
905 conn->current_channel = NULL;
906 silc_client_del_channel(client, conn, channel);
908 chu = silc_client_on_channel(channel, client_entry);
910 silc_hash_table_del(client_entry->channels, channel);
911 silc_hash_table_del(channel->user_list, client_entry);
915 if (!silc_hash_table_count(client_entry->channels)) {
916 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
917 res->context = client;
918 res->sock = silc_socket_dup(conn->sock);
919 res->packet = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
920 silc_schedule_task_add(client->schedule, conn->sock->sock,
921 silc_client_notify_check_client, res,
922 (5 + (silc_rng_get_rn16(client->rng) % 529)),
923 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
928 case SILC_NOTIFY_TYPE_KILLED:
931 * A client (maybe me) was killed from the network.
934 SilcUInt32 comment_len;
936 SILC_LOG_DEBUG(("Notify: KILLED"));
939 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
943 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
947 /* Find Client entry */
948 client_entry = silc_client_get_client_by_id(client, conn, client_id);
953 comment = silc_argument_get_arg_type(args, 2, &comment_len);
955 /* From protocol version 1.1 we get killer's client ID as well */
956 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
958 silc_free(client_id);
959 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
963 /* Find Client entry */
964 if (id_type == SILC_ID_CLIENT) {
965 /* Find Client entry */
967 client_entry2 = silc_client_get_client_by_id(client, conn,
970 silc_client_notify_by_server_resolve(client, conn, packet,
971 SILC_ID_CLIENT, client_id);
974 } else if (id_type == SILC_ID_SERVER) {
975 /* Find Server entry */
977 server = silc_client_get_server_by_id(client, conn, server_id);
979 silc_client_notify_by_server_resolve(client, conn, packet,
980 SILC_ID_SERVER, server_id);
984 /* Save the pointer to the client_entry pointer */
985 client_entry2 = (SilcClientEntry)server;
987 /* Find Channel entry */
989 channel = silc_client_get_channel_by_id(client, conn, channel_id);
991 silc_client_notify_by_server_resolve(client, conn, packet,
992 SILC_ID_CHANNEL, channel_id);
996 /* Save the pointer to the client_entry pointer */
997 client_entry2 = (SilcClientEntry)channel;
998 silc_free(channel_id);
1003 /* Notify application. */
1004 client->internal->ops->notify(client, conn, type, client_entry,
1005 comment, id_type, client_entry2);
1007 if (client_entry != conn->local_entry)
1008 /* Remove the client from all channels and free it */
1009 silc_client_del_client(client, conn, client_entry);
1013 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
1016 * A server quit the SILC network and some clients must be removed
1017 * from channels as they quit as well.
1019 SilcClientEntry *clients = NULL;
1020 SilcUInt32 clients_count = 0;
1023 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
1025 for (i = 1; i < silc_argument_get_arg_num(args); i++) {
1027 tmp = silc_argument_get_arg_type(args, i + 1, &tmp_len);
1029 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1033 /* Get the client entry */
1034 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1036 clients = silc_realloc(clients, sizeof(*clients) *
1037 (clients_count + 1));
1038 clients[clients_count] = client_entry;
1041 silc_free(client_id);
1046 /* Notify application. We don't keep server entries so the server
1047 entry is returned as NULL. The client's are returned as array
1048 of SilcClientEntry pointers. */
1049 client->internal->ops->notify(client, conn, type, NULL,
1050 clients, clients_count);
1052 for (i = 0; i < clients_count; i++) {
1053 /* Remove client from all channels */
1054 client_entry = clients[i];
1055 if (client_entry == conn->local_entry)
1058 /* Remove the client from all channels and free it */
1059 silc_client_del_client(client, conn, client_entry);
1066 case SILC_NOTIFY_TYPE_ERROR:
1069 * Some has occurred and server is notifying us about it.
1073 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1074 if (!tmp && tmp_len != 1)
1076 error = (SilcStatus)tmp[0];
1078 SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1080 if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1081 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1083 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1086 client_entry = silc_client_get_client_by_id(client, conn,
1089 silc_client_del_client(client, conn, client_entry);
1093 /* Notify application. */
1094 client->internal->ops->notify(client, conn, type, error);
1098 case SILC_NOTIFY_TYPE_WATCH:
1101 * Received notify about some client we are watching
1103 SilcNotifyType notify = 0;
1104 bool del_client = FALSE;
1106 SILC_LOG_DEBUG(("Notify: WATCH"));
1108 /* Get sender Client ID */
1109 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1112 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1116 /* Find Client entry and if not found query it */
1117 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1118 if (!client_entry) {
1119 silc_client_notify_by_server_resolve(client, conn, packet,
1120 SILC_ID_CLIENT, client_id);
1125 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1126 if (!tmp || tmp_len != 4)
1128 SILC_GET32_MSB(mode, tmp);
1130 /* Get notify type */
1131 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1132 if (tmp && tmp_len != 2)
1135 SILC_GET16_MSB(notify, tmp);
1138 tmp = silc_argument_get_arg_type(args, 2, NULL);
1140 char *tmp_nick = NULL;
1142 if (client->internal->params->nickname_parse)
1143 client->internal->params->nickname_parse(client_entry->nickname,
1146 tmp_nick = strdup(tmp);
1148 /* If same nick, the client was new to us and has become "present"
1149 to network. Send NULL as nick to application. */
1150 if (tmp_nick && !strcmp(tmp, tmp_nick))
1153 silc_free(tmp_nick);
1156 /* Notify application. */
1157 client->internal->ops->notify(client, conn, type, client_entry,
1160 client_entry->mode = mode;
1162 /* If nickname was changed, remove the client entry unless the
1163 client is on some channel */
1164 if (tmp && notify == SILC_NOTIFY_TYPE_NICK_CHANGE &&
1165 !silc_hash_table_count(client_entry->channels))
1167 else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1168 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
1169 notify == SILC_NOTIFY_TYPE_KILLED)
1173 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1174 res->context = client;
1175 res->sock = silc_socket_dup(conn->sock);
1176 res->packet = client_id;
1178 silc_schedule_task_add(client->schedule, conn->sock->sock,
1179 silc_client_notify_del_client_cb, res,
1180 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1190 silc_notify_payload_free(payload);
1191 silc_free(client_id);
1192 silc_free(channel_id);
1193 silc_free(server_id);