5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2007 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.
22 #include "silcclient.h"
23 #include "client_internal.h"
25 /************************** Types and definitions ***************************/
27 #define NOTIFY conn->client->internal->ops->notify
29 /* Notify processing context */
31 SilcPacket packet; /* Notify packet */
32 SilcNotifyPayload payload; /* Parsed notify payload */
33 SilcFSMThread fsm; /* Notify FSM thread */
34 SilcChannelEntry channel; /* Channel entry being resolved */
35 SilcClientEntry client_entry; /* Client entry being resolved */
38 /************************ Static utility functions **************************/
40 /* The client entires in notify processing are resolved if they do not exist,
41 or they are not valid. We go to this callback after resolving where we
42 check if the client entry has become valid. If resolving succeeded the
43 entry is valid but remains invalid if resolving failed. This callback
44 will continue processing the notify. We use this callback also with other
47 static void silc_client_notify_resolved(SilcClient client,
48 SilcClientConnection conn,
53 SilcClientNotify notify = context;
55 /* If entry is still invalid, resolving failed. Finish notify processing. */
56 if (notify->client_entry && !notify->client_entry->internal.valid) {
57 silc_fsm_next(notify->fsm, silc_client_notify_processed);
58 silc_client_unref_client(client, conn, notify->client_entry);
61 /* If no entries found, just finish the notify processing */
62 if (!entries && !notify->client_entry)
63 silc_fsm_next(notify->fsm, silc_client_notify_processed);
65 if (notify->channel) {
66 notify->channel->internal.resolve_cmd_ident = 0;
67 silc_client_unref_channel(client, conn, notify->channel);
70 /* Continue processing the notify */
71 SILC_FSM_CALL_CONTINUE_SYNC(notify->fsm);
74 /* Continue notify processing after it was suspended while waiting for
75 channel information being resolved. */
77 static SilcBool silc_client_notify_wait_continue(SilcClient client,
78 SilcClientConnection conn,
85 SilcClientNotify notify = context;
87 /* Continue after last command reply received */
88 if (SILC_STATUS_IS_ERROR(status) || status == SILC_STATUS_OK ||
89 status == SILC_STATUS_LIST_END)
90 SILC_FSM_CALL_CONTINUE_SYNC(notify->fsm);
95 /********************************* Notify ***********************************/
97 /* Process received notify packet */
99 SILC_FSM_STATE(silc_client_notify)
101 SilcPacket packet = state_context;
102 SilcClientNotify notify;
103 SilcNotifyPayload payload;
105 payload = silc_notify_payload_parse(silc_buffer_data(&packet->buffer),
106 silc_buffer_len(&packet->buffer));
108 SILC_LOG_DEBUG(("Malformed notify payload"));
109 silc_packet_free(packet);
110 return SILC_FSM_FINISH;
113 if (!silc_notify_get_args(payload)) {
114 SILC_LOG_DEBUG(("Malformed notify %d", silc_notify_get_type(payload)));
115 silc_notify_payload_free(payload);
116 silc_packet_free(packet);
117 return SILC_FSM_FINISH;
120 notify = silc_calloc(1, sizeof(*notify));
122 silc_notify_payload_free(payload);
123 silc_packet_free(packet);
124 return SILC_FSM_FINISH;
127 notify->packet = packet;
128 notify->payload = payload;
130 silc_fsm_set_state_context(fsm, notify);
132 /* Process the notify */
133 switch (silc_notify_get_type(payload)) {
135 case SILC_NOTIFY_TYPE_NONE:
137 silc_fsm_next(fsm, silc_client_notify_none);
140 case SILC_NOTIFY_TYPE_INVITE:
142 silc_fsm_next(fsm, silc_client_notify_invite);
145 case SILC_NOTIFY_TYPE_JOIN:
147 silc_fsm_next(fsm, silc_client_notify_join);
150 case SILC_NOTIFY_TYPE_LEAVE:
152 silc_fsm_next(fsm, silc_client_notify_leave);
155 case SILC_NOTIFY_TYPE_SIGNOFF:
157 silc_fsm_next(fsm, silc_client_notify_signoff);
160 case SILC_NOTIFY_TYPE_TOPIC_SET:
162 silc_fsm_next(fsm, silc_client_notify_topic_set);
165 case SILC_NOTIFY_TYPE_NICK_CHANGE:
167 silc_fsm_next(fsm, silc_client_notify_nick_change);
170 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
172 silc_fsm_next(fsm, silc_client_notify_cmode_change);
175 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
177 silc_fsm_next(fsm, silc_client_notify_cumode_change);
180 case SILC_NOTIFY_TYPE_MOTD:
182 silc_fsm_next(fsm, silc_client_notify_motd);
185 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
186 /** CHANNEL_CHANGE */
187 silc_fsm_next(fsm, silc_client_notify_channel_change);
190 case SILC_NOTIFY_TYPE_KICKED:
192 silc_fsm_next(fsm, silc_client_notify_kicked);
195 case SILC_NOTIFY_TYPE_KILLED:
197 silc_fsm_next(fsm, silc_client_notify_killed);
200 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
201 /** SERVER_SIGNOFF */
202 silc_fsm_next(fsm, silc_client_notify_server_signoff);
205 case SILC_NOTIFY_TYPE_ERROR:
207 silc_fsm_next(fsm, silc_client_notify_error);
210 case SILC_NOTIFY_TYPE_WATCH:
212 silc_fsm_next(fsm, silc_client_notify_watch);
216 /** Unknown notify */
217 silc_notify_payload_free(payload);
218 silc_packet_free(packet);
220 return SILC_FSM_FINISH;
224 return SILC_FSM_CONTINUE;
227 /* Notify processed, finish the packet processing thread */
229 SILC_FSM_STATE(silc_client_notify_processed)
231 SilcClientNotify notify = state_context;
232 SilcPacket packet = notify->packet;
233 SilcNotifyPayload payload = notify->payload;
235 silc_notify_payload_free(payload);
236 silc_packet_free(packet);
238 return SILC_FSM_FINISH;
241 /********************************** NONE ************************************/
243 SILC_FSM_STATE(silc_client_notify_none)
245 SilcClientConnection conn = fsm_context;
246 SilcClient client = conn->client;
247 SilcClientNotify notify = state_context;
248 SilcNotifyPayload payload = notify->payload;
249 SilcNotifyType type = silc_notify_get_type(payload);
250 SilcArgumentPayload args = silc_notify_get_args(payload);
252 SILC_LOG_DEBUG(("Notify: NONE"));
254 /* Notify application */
255 NOTIFY(client, conn, type, silc_argument_get_arg_type(args, 1, NULL));
257 /** Notify processed */
258 silc_fsm_next(fsm, silc_client_notify_processed);
259 return SILC_FSM_CONTINUE;
262 /********************************* INVITE ***********************************/
264 /* Someone invite me to a channel */
266 SILC_FSM_STATE(silc_client_notify_invite)
268 SilcClientConnection conn = fsm_context;
269 SilcClient client = conn->client;
270 SilcClientNotify notify = state_context;
271 SilcNotifyPayload payload = notify->payload;
272 SilcNotifyType type = silc_notify_get_type(payload);
273 SilcArgumentPayload args = silc_notify_get_args(payload);
274 SilcClientEntry client_entry;
275 SilcChannelEntry channel = NULL;
280 SILC_LOG_DEBUG(("Notify: INVITE"));
283 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
286 /* Get the channel name */
287 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
291 /* Get the channel entry */
292 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
296 /* If channel is being resolved handle notify after resolving */
297 if (channel->internal.resolve_cmd_ident) {
298 silc_client_unref_channel(client, conn, channel);
299 SILC_FSM_CALL(silc_client_command_pending(
300 conn, SILC_COMMAND_NONE,
301 channel->internal.resolve_cmd_ident,
302 silc_client_notify_wait_continue,
307 /* Get sender Client ID */
308 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
311 /* Find Client entry and if not found query it */
312 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
313 if (!client_entry || !client_entry->internal.valid) {
314 /** Resolve client */
315 silc_client_unref_client(client, conn, client_entry);
316 notify->channel = channel;
317 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
318 silc_client_get_client_by_id_resolve(
319 client, conn, &id.u.client_id, NULL,
320 silc_client_notify_resolved,
325 /* Notify application */
326 NOTIFY(client, conn, type, channel, tmp, client_entry);
328 silc_client_unref_client(client, conn, client_entry);
331 /** Notify processed */
332 silc_client_unref_channel(client, conn, channel);
333 silc_fsm_next(fsm, silc_client_notify_processed);
334 return SILC_FSM_CONTINUE;
337 /********************************** JOIN ************************************/
339 /* Someone joined a channel */
341 SILC_FSM_STATE(silc_client_notify_join)
343 SilcClientConnection conn = fsm_context;
344 SilcClient client = conn->client;
345 SilcClientNotify notify = state_context;
346 SilcNotifyPayload payload = notify->payload;
347 SilcNotifyType type = silc_notify_get_type(payload);
348 SilcArgumentPayload args = silc_notify_get_args(payload);
349 SilcClientEntry client_entry;
350 SilcChannelEntry channel = NULL;
353 SILC_LOG_DEBUG(("Notify: JOIN"));
356 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
359 /* Get channel entry */
360 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
364 /* If channel is being resolved handle notify after resolving */
365 if (channel->internal.resolve_cmd_ident) {
366 silc_client_unref_channel(client, conn, channel);
367 SILC_FSM_CALL(silc_client_command_pending(
368 conn, SILC_COMMAND_NONE,
369 channel->internal.resolve_cmd_ident,
370 silc_client_notify_wait_continue,
376 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
379 /* Find client entry and if not found query it. If we just queried it
380 don't do it again, unless some data (like username) is missing. */
381 client_entry = notify->client_entry;
383 client_entry = silc_client_get_client(client, conn, &id.u.client_id);
384 if (!client_entry || !client_entry->internal.valid ||
385 !client_entry->username[0]) {
386 /** Resolve client */
387 notify->channel = channel;
388 notify->client_entry = client_entry;
389 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
390 silc_client_get_client_by_id_resolve(
391 client, conn, client_entry ?
392 &client_entry->id : &id.u.client_id,
393 NULL, silc_client_notify_resolved,
398 silc_rwlock_wrlock(client_entry->internal.lock);
399 silc_rwlock_wrlock(channel->internal.lock);
401 if (client_entry != conn->local_entry)
402 silc_client_nickname_format(client, conn, client_entry, FALSE);
404 /* Join the client to channel */
405 if (!silc_client_add_to_channel(client, conn, channel, client_entry, 0)) {
406 silc_rwlock_unlock(channel->internal.lock);
407 silc_rwlock_unlock(client_entry->internal.lock);
411 silc_rwlock_unlock(channel->internal.lock);
412 silc_rwlock_unlock(client_entry->internal.lock);
414 /* Notify application. */
415 NOTIFY(client, conn, type, client_entry, channel);
417 silc_client_unref_client(client, conn, client_entry);
420 /** Notify processed */
421 silc_client_unref_channel(client, conn, channel);
422 silc_fsm_next(fsm, silc_client_notify_processed);
423 return SILC_FSM_CONTINUE;
426 /********************************** LEAVE ***********************************/
428 /* Someone left a channel */
430 SILC_FSM_STATE(silc_client_notify_leave)
432 SilcClientConnection conn = fsm_context;
433 SilcClient client = conn->client;
434 SilcClientNotify notify = state_context;
435 SilcNotifyPayload payload = notify->payload;
436 SilcPacket packet = notify->packet;
437 SilcNotifyType type = silc_notify_get_type(payload);
438 SilcArgumentPayload args = silc_notify_get_args(payload);
439 SilcClientEntry client_entry = NULL;
440 SilcChannelEntry channel = NULL;
443 SILC_LOG_DEBUG(("Notify: LEAVE"));
445 /* Get channel entry */
446 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
447 &id.u.channel_id, sizeof(id.u.channel_id)))
449 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
453 /* If channel is being resolved handle notify after resolving */
454 if (channel->internal.resolve_cmd_ident) {
455 silc_client_unref_channel(client, conn, channel);
456 SILC_FSM_CALL(silc_client_command_pending(
457 conn, SILC_COMMAND_NONE,
458 channel->internal.resolve_cmd_ident,
459 silc_client_notify_wait_continue,
465 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
468 /* Find Client entry */
469 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
473 /* Remove client from channel */
474 if (!silc_client_remove_from_channel(client, conn, channel, client_entry))
477 /* Notify application. */
478 NOTIFY(client, conn, type, client_entry, channel);
480 silc_client_unref_client(client, conn, client_entry);
483 /** Notify processed */
484 silc_client_unref_channel(client, conn, channel);
485 silc_fsm_next(fsm, silc_client_notify_processed);
486 return SILC_FSM_CONTINUE;
489 /********************************* SIGNOFF **********************************/
491 /* Someone quit SILC network */
493 SILC_FSM_STATE(silc_client_notify_signoff)
495 SilcClientConnection conn = fsm_context;
496 SilcClient client = conn->client;
497 SilcClientNotify notify = state_context;
498 SilcNotifyPayload payload = notify->payload;
499 SilcPacket packet = notify->packet;
500 SilcNotifyType type = silc_notify_get_type(payload);
501 SilcArgumentPayload args = silc_notify_get_args(payload);
502 SilcClientEntry client_entry;
503 SilcChannelEntry channel;
508 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
511 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
514 /* Find Client entry */
515 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
519 /* Get signoff message */
520 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
521 if (tmp && tmp_len > 128)
524 /* Notify application */
525 if (client_entry->internal.valid)
526 NOTIFY(client, conn, type, client_entry, tmp);
528 /* Remove from channel */
529 if (packet->dst_id_type == SILC_ID_CHANNEL) {
530 if (silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
531 &id.u.channel_id, sizeof(id.u.channel_id))) {
532 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
534 silc_client_remove_from_channel(client, conn, channel, client_entry);
535 silc_client_unref_channel(client, conn, channel);
541 client_entry->internal.valid = FALSE;
542 silc_client_del_client(client, conn, client_entry);
543 silc_client_unref_client(client, conn, client_entry);
546 /** Notify processed */
547 silc_fsm_next(fsm, silc_client_notify_processed);
548 return SILC_FSM_CONTINUE;
551 /******************************** TOPIC_SET *********************************/
553 /* Someone set topic on a channel */
555 SILC_FSM_STATE(silc_client_notify_topic_set)
557 SilcClientConnection conn = fsm_context;
558 SilcClient client = conn->client;
559 SilcClientNotify notify = state_context;
560 SilcNotifyPayload payload = notify->payload;
561 SilcPacket packet = notify->packet;
562 SilcNotifyType type = silc_notify_get_type(payload);
563 SilcArgumentPayload args = silc_notify_get_args(payload);
564 SilcClientEntry client_entry = NULL;
565 SilcChannelEntry channel = NULL, channel_entry = NULL;
566 SilcServerEntry server = NULL;
572 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
574 /* Get channel entry */
575 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
576 &id.u.channel_id, sizeof(id.u.channel_id)))
578 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
582 /* If channel is being resolved handle notify after resolving */
583 if (channel->internal.resolve_cmd_ident) {
584 silc_client_unref_channel(client, conn, channel);
585 SILC_FSM_CALL(silc_client_command_pending(
586 conn, SILC_COMMAND_NONE,
587 channel->internal.resolve_cmd_ident,
588 silc_client_notify_wait_continue,
593 /* Get ID of topic changer */
594 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
598 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
602 if (id.type == SILC_ID_CLIENT) {
603 /* Find Client entry */
604 client_entry = notify->client_entry;
606 client_entry = silc_client_get_client(client, conn, &id.u.client_id);
607 if (!client_entry || !client_entry->internal.valid) {
608 /** Resolve client */
609 notify->channel = channel;
610 notify->client_entry = client_entry;
611 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
612 silc_client_get_client_by_id_resolve(
613 client, conn, &id.u.client_id, NULL,
614 silc_client_notify_resolved,
620 /* If client is not on channel, ignore this notify */
621 if (!silc_client_on_channel(channel, client_entry))
624 entry = client_entry;
625 } else if (id.type == SILC_ID_SERVER) {
626 /* Find Server entry */
627 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
629 /** Resolve server */
630 notify->channel = channel;
631 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
632 silc_client_get_server_by_id_resolve(
633 client, conn, &id.u.server_id,
634 silc_client_notify_resolved,
640 /* Find Channel entry */
641 channel_entry = silc_client_get_channel_by_id(client, conn,
643 if (!channel_entry) {
644 /** Resolve channel */
645 notify->channel = channel;
646 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
647 silc_client_get_channel_by_id_resolve(
648 client, conn, &id.u.channel_id,
649 silc_client_notify_resolved,
653 entry = channel_entry;
656 silc_rwlock_wrlock(channel->internal.lock);
657 silc_free(channel->topic);
658 channel->topic = silc_memdup(tmp, strlen(tmp));
659 silc_rwlock_unlock(channel->internal.lock);
661 /* Notify application. */
662 NOTIFY(client, conn, type, id.type, entry, channel->topic, channel);
665 silc_client_unref_client(client, conn, client_entry);
667 silc_client_unref_server(client, conn, server);
669 silc_client_unref_channel(client, conn, channel_entry);
672 /** Notify processed */
673 silc_client_unref_channel(client, conn, channel);
674 silc_fsm_next(fsm, silc_client_notify_processed);
675 return SILC_FSM_CONTINUE;
678 /****************************** NICK_CHANGE *********************************/
680 /* Someone changed their nickname on a channel */
682 SILC_FSM_STATE(silc_client_notify_nick_change)
684 SilcClientConnection conn = fsm_context;
685 SilcClient client = conn->client;
686 SilcClientNotify notify = state_context;
687 SilcNotifyPayload payload = notify->payload;
688 SilcNotifyType type = silc_notify_get_type(payload);
689 SilcArgumentPayload args = silc_notify_get_args(payload);
690 SilcClientEntry client_entry = NULL;
691 unsigned char *tmp, oldnick[128 + 1];
696 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
699 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
703 if (conn->local_id &&
704 SILC_ID_CLIENT_COMPARE(&id.u.client_id, conn->local_id))
707 /* Get new Client ID */
708 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id2, NULL))
712 if (conn->local_id &&
713 SILC_ID_CLIENT_COMPARE(&id2.u.client_id, conn->local_id))
716 /* Find old client entry. If we don't have the entry, we ignore this
718 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
721 valid = client_entry->internal.valid;
723 /* Take the new nickname */
724 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
728 silc_rwlock_wrlock(client_entry->internal.lock);
730 /* Check whether nickname changed at all. It is possible that nick
731 change notify is received but nickname didn't change, only the
732 ID changes. If Client ID hash match, nickname didn't change. */
733 if (SILC_ID_COMPARE_HASH(&client_entry->id, &id2.u.client_id) &&
734 silc_utf8_strcasecmp(tmp, client_entry->nickname)) {
735 /* Nickname didn't change. Update only Client ID. We don't notify
736 application because nickname didn't change. */
737 silc_mutex_lock(conn->internal->lock);
738 silc_idcache_update_by_context(conn->internal->client_cache, client_entry,
739 &id2.u.client_id, NULL, FALSE);
740 silc_mutex_unlock(conn->internal->lock);
741 silc_rwlock_unlock(client_entry->internal.lock);
745 /* Change the nickname */
746 memcpy(oldnick, client_entry->nickname, sizeof(client_entry->nickname));
747 if (!silc_client_change_nickname(client, conn, client_entry, tmp,
748 &id2.u.client_id, NULL, 0)) {
749 silc_rwlock_unlock(client_entry->internal.lock);
753 silc_rwlock_unlock(client_entry->internal.lock);
755 /* Notify application, if client entry is valid. We do not send nick change
756 notify for entries that were invalid (application doesn't know them). */
758 NOTIFY(client, conn, type, client_entry, oldnick, client_entry->nickname);
761 /** Notify processed */
762 silc_client_unref_client(client, conn, client_entry);
763 silc_fsm_next(fsm, silc_client_notify_processed);
764 return SILC_FSM_CONTINUE;
767 /****************************** CMODE_CHANGE ********************************/
769 /* Someone changed channel mode */
771 SILC_FSM_STATE(silc_client_notify_cmode_change)
773 SilcClientConnection conn = fsm_context;
774 SilcClient client = conn->client;
775 SilcClientNotify notify = state_context;
776 SilcNotifyPayload payload = notify->payload;
777 SilcPacket packet = notify->packet;
778 SilcNotifyType type = silc_notify_get_type(payload);
779 SilcArgumentPayload args = silc_notify_get_args(payload);
780 SilcClientEntry client_entry = NULL;
781 SilcChannelEntry channel = NULL, channel_entry = NULL;
782 SilcServerEntry server = NULL;
785 SilcUInt32 tmp_len, mode;
787 char *passphrase, *cipher, *hmac;
788 SilcPublicKey founder_key = NULL;
789 SilcDList chpks = NULL;
791 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
793 /* Get channel entry */
794 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
795 &id.u.channel_id, sizeof(id.u.channel_id)))
797 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
801 /* If channel is being resolved handle notify after resolving */
802 if (channel->internal.resolve_cmd_ident) {
803 silc_client_unref_channel(client, conn, channel);
804 SILC_FSM_CALL(silc_client_command_pending(
805 conn, SILC_COMMAND_NONE,
806 channel->internal.resolve_cmd_ident,
807 silc_client_notify_wait_continue,
813 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
816 SILC_GET32_MSB(mode, tmp);
818 /* Get ID of who changed the mode */
819 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
822 if (id.type == SILC_ID_CLIENT) {
823 /* Find Client entry */
824 client_entry = notify->client_entry;
826 client_entry = silc_client_get_client(client, conn, &id.u.client_id);
827 if (!client_entry || !client_entry->internal.valid) {
828 /** Resolve client */
829 notify->channel = channel;
830 notify->client_entry = client_entry;
831 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
832 silc_client_get_client_by_id_resolve(
833 client, conn, &id.u.client_id, NULL,
834 silc_client_notify_resolved,
840 /* If client is not on channel, ignore this notify */
841 if (!silc_client_on_channel(channel, client_entry))
844 entry = client_entry;
845 } else if (id.type == SILC_ID_SERVER) {
846 /* Find Server entry */
847 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
849 /** Resolve server */
850 notify->channel = channel;
851 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
852 silc_client_get_server_by_id_resolve(
853 client, conn, &id.u.server_id,
854 silc_client_notify_resolved,
860 /* Find Channel entry */
861 channel_entry = silc_client_get_channel_by_id(client, conn,
863 if (!channel_entry) {
864 /** Resolve channel */
865 notify->channel = channel;
866 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
867 silc_client_get_channel_by_id_resolve(
868 client, conn, &id.u.channel_id,
869 silc_client_notify_resolved,
873 entry = channel_entry;
876 silc_rwlock_wrlock(channel->internal.lock);
878 /* Get the channel founder key if it was set */
879 tmp = silc_argument_get_arg_type(args, 6, &tmp_len);
881 if (!silc_public_key_payload_decode(tmp, tmp_len, &founder_key)) {
882 silc_rwlock_unlock(channel->internal.lock);
885 if (!channel->founder_key) {
886 channel->founder_key = founder_key;
892 cipher = silc_argument_get_arg_type(args, 3, &tmp_len);
895 hmac = silc_argument_get_arg_type(args, 4, &tmp_len);
897 unsigned char hash[SILC_HASH_MAXLEN];
900 if (!silc_hmac_alloc(hmac, NULL, &newhmac)) {
901 silc_rwlock_unlock(channel->internal.lock);
905 /* Get HMAC key from the old HMAC context, and update it to the new one */
906 tmp = (unsigned char *)silc_hmac_get_key(channel->internal.hmac, &tmp_len);
908 silc_hash_make(silc_hmac_get_hash(newhmac), tmp, tmp_len, hash);
909 silc_hmac_set_key(newhmac, hash,
910 silc_hash_len(silc_hmac_get_hash(newhmac)));
911 if (channel->internal.hmac)
912 silc_hmac_free(channel->internal.hmac);
913 channel->internal.hmac = newhmac;
914 memset(hash, 0, sizeof(hash));
918 /* Get the passphrase if it was set */
919 passphrase = silc_argument_get_arg_type(args, 5, &tmp_len);
922 tmp = silc_argument_get_arg_type(args, 8, &tmp_len);
923 if (tmp && tmp_len == 4)
924 SILC_GET32_MSB(channel->user_limit, tmp);
925 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
926 channel->user_limit = 0;
928 /* Save the new mode */
929 channel->mode = mode;
931 /* Get the channel public key that was added or removed */
932 tmp = silc_argument_get_arg_type(args, 7, &tmp_len);
934 silc_client_channel_save_public_keys(channel, tmp, tmp_len);
936 silc_rwlock_unlock(channel->internal.lock);
938 /* Notify application. */
939 NOTIFY(client, conn, type, id.type, entry, mode, cipher, hmac,
940 passphrase, channel->founder_key, chpks, channel);
944 silc_pkcs_public_key_free(founder_key);
946 silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
948 silc_client_unref_client(client, conn, client_entry);
950 silc_client_unref_server(client, conn, server);
952 silc_client_unref_channel(client, conn, channel_entry);
953 silc_client_unref_channel(client, conn, channel);
955 /** Notify processed */
956 silc_fsm_next(fsm, silc_client_notify_processed);
957 return SILC_FSM_CONTINUE;
960 /***************************** CUMODE_CHANGE ********************************/
962 /* Someone changed a user's mode on a channel */
964 SILC_FSM_STATE(silc_client_notify_cumode_change)
966 SilcClientConnection conn = fsm_context;
967 SilcClient client = conn->client;
968 SilcClientNotify notify = state_context;
969 SilcNotifyPayload payload = notify->payload;
970 SilcPacket packet = notify->packet;
971 SilcNotifyType type = silc_notify_get_type(payload);
972 SilcArgumentPayload args = silc_notify_get_args(payload);
973 SilcClientEntry client_entry = NULL, client_entry2 = NULL;
974 SilcChannelEntry channel = NULL, channel_entry = NULL;
975 SilcServerEntry server = NULL;
979 SilcUInt32 tmp_len, mode;
982 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
984 /* Get channel entry */
985 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
986 &id.u.channel_id, sizeof(id.u.channel_id)))
988 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
992 /* If channel is being resolved handle notify after resolving */
993 if (channel->internal.resolve_cmd_ident) {
994 silc_client_unref_channel(client, conn, channel);
995 SILC_FSM_CALL(silc_client_command_pending(
996 conn, SILC_COMMAND_NONE,
997 channel->internal.resolve_cmd_ident,
998 silc_client_notify_wait_continue,
1003 /* Get target Client ID */
1004 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id2, NULL))
1007 /* Find target Client entry */
1008 client_entry2 = silc_client_get_client_by_id(client, conn, &id2.u.client_id);
1009 if (!client_entry2 || !client_entry2->internal.valid) {
1010 /** Resolve client */
1011 silc_client_unref_client(client, conn, client_entry2);
1012 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1013 client, conn, &id2.u.client_id, NULL,
1014 silc_client_notify_resolved,
1019 /* If target client is not on channel, ignore this notify */
1020 if (!silc_client_on_channel(channel, client_entry2))
1024 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1027 SILC_GET32_MSB(mode, tmp);
1029 /* Get ID of mode changer */
1030 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1033 if (id.type == SILC_ID_CLIENT) {
1034 /* Find Client entry */
1035 client_entry = notify->client_entry;
1036 if (!client_entry) {
1037 client_entry = silc_client_get_client(client, conn, &id.u.client_id);
1038 if (!client_entry || !client_entry->internal.valid) {
1039 /** Resolve client */
1040 notify->channel = channel;
1041 notify->client_entry = client_entry;
1042 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1043 silc_client_get_client_by_id_resolve(
1044 client, conn, &id.u.client_id, NULL,
1045 silc_client_notify_resolved,
1051 /* If client is not on channel, ignore this notify */
1052 if (!silc_client_on_channel(channel, client_entry))
1055 entry = client_entry;
1056 } else if (id.type == SILC_ID_SERVER) {
1057 /* Find Server entry */
1058 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1060 /** Resolve server */
1061 notify->channel = channel;
1062 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1063 silc_client_get_server_by_id_resolve(
1064 client, conn, &id.u.server_id,
1065 silc_client_notify_resolved,
1071 /* Find Channel entry */
1072 channel_entry = silc_client_get_channel_by_id(client, conn,
1074 if (!channel_entry) {
1075 /** Resolve channel */
1076 notify->channel = channel;
1077 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1078 silc_client_get_channel_by_id_resolve(
1079 client, conn, &id.u.channel_id,
1080 silc_client_notify_resolved,
1084 entry = channel_entry;
1088 silc_rwlock_wrlock(channel->internal.lock);
1089 chu = silc_client_on_channel(channel, client_entry2);
1092 silc_rwlock_unlock(channel->internal.lock);
1094 /* Notify application. */
1095 NOTIFY(client, conn, type, id.type, entry, mode, client_entry2, channel);
1098 silc_client_unref_client(client, conn, client_entry2);
1100 silc_client_unref_client(client, conn, client_entry);
1102 silc_client_unref_server(client, conn, server);
1104 silc_client_unref_channel(client, conn, channel_entry);
1105 silc_client_unref_channel(client, conn, channel);
1107 /** Notify processed */
1108 silc_fsm_next(fsm, silc_client_notify_processed);
1109 return SILC_FSM_CONTINUE;
1112 /********************************* MOTD *************************************/
1114 /* Received Message of the day */
1116 SILC_FSM_STATE(silc_client_notify_motd)
1118 SilcClientConnection conn = fsm_context;
1119 SilcClient client = conn->client;
1120 SilcClientNotify notify = state_context;
1121 SilcNotifyPayload payload = notify->payload;
1122 SilcNotifyType type = silc_notify_get_type(payload);
1123 SilcArgumentPayload args = silc_notify_get_args(payload);
1127 SILC_LOG_DEBUG(("Notify: MOTD"));
1130 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1134 /* Notify application */
1135 NOTIFY(client, conn, type, tmp);
1138 /** Notify processed */
1139 silc_fsm_next(fsm, silc_client_notify_processed);
1140 return SILC_FSM_CONTINUE;
1143 /**************************** CHANNEL CHANGE ********************************/
1145 /* Router has enforced a new ID to a channel, change it */
1147 SILC_FSM_STATE(silc_client_notify_channel_change)
1149 SilcClientConnection conn = fsm_context;
1150 SilcClient client = conn->client;
1151 SilcClientNotify notify = state_context;
1152 SilcNotifyPayload payload = notify->payload;
1153 SilcNotifyType type = silc_notify_get_type(payload);
1154 SilcArgumentPayload args = silc_notify_get_args(payload);
1155 SilcChannelEntry channel = NULL;
1158 SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
1160 /* Get the old ID */
1161 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1164 /* Get the channel entry */
1165 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1169 /* If channel is being resolved handle notify after resolving */
1170 if (channel->internal.resolve_cmd_ident) {
1171 silc_client_unref_channel(client, conn, channel);
1172 SILC_FSM_CALL(silc_client_command_pending(
1173 conn, SILC_COMMAND_NONE,
1174 channel->internal.resolve_cmd_ident,
1175 silc_client_notify_wait_continue,
1180 /* Get the new ID */
1181 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
1184 /* Replace the Channel ID */
1185 if (!silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id))
1188 /* Notify application */
1189 NOTIFY(client, conn, type, channel, channel);
1192 /** Notify processed */
1193 silc_client_unref_channel(client, conn, channel);
1194 silc_fsm_next(fsm, silc_client_notify_processed);
1195 return SILC_FSM_CONTINUE;
1198 /******************************** KICKED ************************************/
1200 /* Some client was kicked from a channel */
1202 SILC_FSM_STATE(silc_client_notify_kicked)
1204 SilcClientConnection conn = fsm_context;
1205 SilcClient client = conn->client;
1206 SilcClientNotify notify = state_context;
1207 SilcNotifyPayload payload = notify->payload;
1208 SilcPacket packet = notify->packet;
1209 SilcNotifyType type = silc_notify_get_type(payload);
1210 SilcArgumentPayload args = silc_notify_get_args(payload);
1211 SilcClientEntry client_entry, client_entry2;
1212 SilcChannelEntry channel = NULL;
1217 SILC_LOG_DEBUG(("Notify: KICKED"));
1219 /* Get channel entry */
1220 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
1221 &id.u.channel_id, sizeof(id.u.channel_id)))
1223 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1227 /* If channel is being resolved handle notify after resolving */
1228 if (channel->internal.resolve_cmd_ident) {
1229 silc_client_unref_channel(client, conn, channel);
1230 SILC_FSM_CALL(silc_client_command_pending(
1231 conn, SILC_COMMAND_NONE,
1232 channel->internal.resolve_cmd_ident,
1233 silc_client_notify_wait_continue,
1238 /* Get the kicked Client ID */
1239 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1242 /* Find client entry */
1243 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1247 /* Get kicker's Client ID */
1248 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
1251 /* Find kicker's client entry and if not found resolve it */
1252 client_entry2 = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1253 if (!client_entry2 || !client_entry2->internal.valid) {
1254 /** Resolve client */
1255 silc_client_unref_client(client, conn, client_entry);
1256 silc_client_unref_client(client, conn, client_entry2);
1257 notify->channel = channel;
1258 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1259 silc_client_get_client_by_id_resolve(
1260 client, conn, &id.u.client_id, NULL,
1261 silc_client_notify_resolved,
1267 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1269 /* Remove kicked client from channel */
1270 if (client_entry != conn->local_entry) {
1271 if (!silc_client_remove_from_channel(client, conn, channel, client_entry))
1275 /* Notify application. */
1276 NOTIFY(client, conn, type, client_entry, tmp, client_entry2, channel);
1278 /* If I was kicked from channel, remove the channel */
1279 if (client_entry == conn->local_entry) {
1280 if (conn->current_channel == channel)
1281 conn->current_channel = NULL;
1282 silc_client_empty_channel(client, conn, channel);
1283 silc_client_del_channel(client, conn, channel);
1286 silc_client_unref_client(client, conn, client_entry);
1287 silc_client_unref_client(client, conn, client_entry2);
1290 /** Notify processed */
1291 silc_client_unref_channel(client, conn, channel);
1292 silc_fsm_next(fsm, silc_client_notify_processed);
1293 return SILC_FSM_CONTINUE;
1296 /******************************** KILLED ************************************/
1298 /* Some client was killed from the network */
1300 SILC_FSM_STATE(silc_client_notify_killed)
1302 SilcClientConnection conn = fsm_context;
1303 SilcClient client = conn->client;
1304 SilcClientNotify notify = state_context;
1305 SilcNotifyPayload payload = notify->payload;
1306 SilcNotifyType type = silc_notify_get_type(payload);
1307 SilcArgumentPayload args = silc_notify_get_args(payload);
1308 SilcClientEntry client_entry = NULL, client_entry2 = NULL;
1309 SilcChannelEntry channel_entry = NULL;
1310 SilcServerEntry server = NULL;
1313 SilcUInt32 comment_len;
1316 SILC_LOG_DEBUG(("Notify: KILLED"));
1319 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1322 /* Find Client entry */
1323 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1328 comment = silc_argument_get_arg_type(args, 2, &comment_len);
1330 /* Get killer's ID */
1331 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
1334 if (id.type == SILC_ID_CLIENT) {
1335 /* Find Client entry */
1336 client_entry2 = silc_client_get_client_by_id(client, conn,
1338 if (!client_entry2 || !client_entry2->internal.valid) {
1339 /** Resolve client */
1340 silc_client_unref_client(client, conn, client_entry);
1341 silc_client_unref_client(client, conn, client_entry2);
1342 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1343 client, conn, &id.u.client_id, NULL,
1344 silc_client_notify_resolved,
1348 entry = client_entry2;
1349 } else if (id.type == SILC_ID_SERVER) {
1350 /* Find Server entry */
1351 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1353 /** Resolve server */
1354 SILC_FSM_CALL(silc_client_get_server_by_id_resolve(
1355 client, conn, &id.u.server_id,
1356 silc_client_notify_resolved,
1362 /* Find Channel entry */
1363 channel_entry = silc_client_get_channel_by_id(client, conn,
1365 if (!channel_entry) {
1366 /** Resolve channel */
1367 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1368 client, conn, &id.u.channel_id,
1369 silc_client_notify_resolved,
1373 entry = channel_entry;
1376 /* Notify application. */
1377 NOTIFY(client, conn, type, client_entry, comment, id.type, entry);
1379 /* Delete the killed client */
1380 if (client_entry != conn->local_entry) {
1381 silc_client_remove_from_channels(client, conn, client_entry);
1382 client_entry->internal.valid = FALSE;
1383 silc_client_del_client(client, conn, client_entry);
1387 silc_client_unref_client(client, conn, client_entry);
1389 silc_client_unref_client(client, conn, client_entry2);
1391 silc_client_unref_server(client, conn, server);
1393 silc_client_unref_channel(client, conn, channel_entry);
1395 /** Notify processed */
1396 silc_fsm_next(fsm, silc_client_notify_processed);
1397 return SILC_FSM_CONTINUE;
1400 /**************************** SERVER SIGNOFF ********************************/
1402 /* Some server quit SILC network. Remove its clients from channels. */
1404 SILC_FSM_STATE(silc_client_notify_server_signoff)
1406 SilcClientConnection conn = fsm_context;
1407 SilcClient client = conn->client;
1408 SilcClientNotify notify = state_context;
1409 SilcNotifyPayload payload = notify->payload;
1410 SilcNotifyType type = silc_notify_get_type(payload);
1411 SilcArgumentPayload args = silc_notify_get_args(payload);
1412 SilcClientEntry client_entry;
1417 SILC_LOG_DEBUG(("Notify: SERVER_SIGNOFF"));
1419 clients = silc_dlist_init();
1423 for (i = 1; i < silc_argument_get_arg_num(args); i++) {
1425 if (!silc_argument_get_decoded(args, i + 1, SILC_ARGUMENT_ID, &id, NULL))
1428 /* Get the client entry */
1429 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1430 if (client_entry && client_entry->internal.valid)
1431 silc_dlist_add(clients, client_entry);
1434 /* Notify application. We don't keep server entries so the server
1435 entry is returned as NULL. The client's are returned as list. */
1436 NOTIFY(client, conn, type, NULL, clients);
1438 /* Delete the clients */
1439 silc_dlist_start(clients);
1440 while ((client_entry = silc_dlist_get(clients))) {
1441 silc_client_remove_from_channels(client, conn, client_entry);
1442 client_entry->internal.valid = FALSE;
1443 silc_client_del_client(client, conn, client_entry);
1447 /** Notify processed */
1448 silc_client_list_free(client, conn, clients);
1449 silc_fsm_next(fsm, silc_client_notify_processed);
1450 return SILC_FSM_CONTINUE;
1453 /******************************** ERROR *************************************/
1455 /* Some error occurred */
1457 SILC_FSM_STATE(silc_client_notify_error)
1459 SilcClientConnection conn = fsm_context;
1460 SilcClient client = conn->client;
1461 SilcClientNotify notify = state_context;
1462 SilcNotifyPayload payload = notify->payload;
1463 SilcNotifyType type = silc_notify_get_type(payload);
1464 SilcArgumentPayload args = silc_notify_get_args(payload);
1465 SilcClientEntry client_entry;
1472 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1473 if (!tmp && tmp_len != 1)
1475 error = (SilcStatus)tmp[0];
1477 SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1479 /* Handle the error */
1480 if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1481 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
1483 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1485 silc_client_remove_from_channels(client, conn, client_entry);
1486 silc_client_del_client(client, conn, client_entry);
1487 silc_client_unref_client(client, conn, client_entry);
1491 /* Notify application. */
1492 NOTIFY(client, conn, type, error);
1495 /** Notify processed */
1496 silc_fsm_next(fsm, silc_client_notify_processed);
1497 return SILC_FSM_CONTINUE;
1500 /******************************** WATCH *************************************/
1502 /* Received notify about some client we are watching */
1504 SILC_FSM_STATE(silc_client_notify_watch)
1506 SilcClientConnection conn = fsm_context;
1507 SilcClient client = conn->client;
1508 SilcClientNotify notify = state_context;
1509 SilcNotifyPayload payload = notify->payload;
1510 SilcNotifyType type = silc_notify_get_type(payload);
1511 SilcArgumentPayload args = silc_notify_get_args(payload);
1512 SilcClientEntry client_entry = NULL;
1513 SilcNotifyType ntype = 0;
1514 SilcBool del_client = FALSE;
1515 unsigned char *pk, *tmp;
1516 SilcUInt32 mode, pk_len, tmp_len;
1517 SilcPublicKey public_key = NULL;
1520 SILC_LOG_DEBUG(("Notify: WATCH"));
1522 /* Get sender Client ID */
1523 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1526 /* Find client entry and if not found resolve it */
1527 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1528 if (!client_entry || !client_entry->internal.valid) {
1529 /** Resolve client */
1530 silc_client_unref_client(client, conn, client_entry);
1531 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1532 client, conn, &id.u.client_id, NULL,
1533 silc_client_notify_resolved,
1539 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1540 if (!tmp || tmp_len != 4)
1542 SILC_GET32_MSB(mode, tmp);
1544 /* Get notify type */
1545 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1546 if (tmp && tmp_len != 2)
1549 SILC_GET16_MSB(ntype, tmp);
1552 tmp = silc_argument_get_arg_type(args, 2, NULL);
1554 char *tmp_nick = NULL;
1556 silc_client_nickname_parse(client, conn, client_entry->nickname,
1559 /* If same nick, the client was new to us and has become "present"
1560 to network. Send NULL as nick to application. */
1561 if (tmp_nick && silc_utf8_strcasecmp(tmp, tmp_nick))
1564 silc_free(tmp_nick);
1567 /* Get public key, if present */
1568 pk = silc_argument_get_arg_type(args, 5, &pk_len);
1569 if (pk && !client_entry->public_key) {
1570 if (silc_public_key_payload_decode(pk, pk_len, &public_key)) {
1571 client_entry->public_key = public_key;
1576 /* Notify application. */
1577 NOTIFY(client, conn, type, client_entry, tmp, mode, ntype,
1578 client_entry->public_key);
1580 client_entry->mode = mode;
1582 /* If nickname was changed, remove the client entry unless the
1583 client is on some channel */
1584 /* XXX, why do we need to remove the client entry?? */
1585 if (tmp && ntype == SILC_NOTIFY_TYPE_NICK_CHANGE &&
1586 !silc_hash_table_count(client_entry->channels))
1588 else if (ntype == SILC_NOTIFY_TYPE_SIGNOFF ||
1589 ntype == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
1590 ntype == SILC_NOTIFY_TYPE_KILLED)
1594 silc_client_remove_from_channels(client, conn, client_entry);
1595 silc_client_del_client(client, conn, client_entry);
1599 silc_pkcs_public_key_free(public_key);
1602 /** Notify processed */
1603 silc_client_unref_client(client, conn, client_entry);
1604 silc_fsm_next(fsm, silc_client_notify_processed);
1605 return SILC_FSM_CONTINUE;