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 */
36 SilcUInt32 resolve_retry; /* Resolving retry counter */
39 /************************ Static utility functions **************************/
41 /* The client entires in notify processing are resolved if they do not exist,
42 or they are not valid. We go to this callback after resolving where we
43 check if the client entry has become valid. If resolving succeeded the
44 entry is valid but remains invalid if resolving failed. This callback
45 will continue processing the notify. We use this callback also with other
48 static void silc_client_notify_resolved(SilcClient client,
49 SilcClientConnection conn,
54 SilcClientNotify notify = context;
56 /* If entry is still invalid, resolving failed. Finish notify processing. */
57 if (notify->client_entry && !notify->client_entry->internal.valid) {
58 /* If resolving timedout try it again many times. */
59 if (status != SILC_STATUS_ERR_TIMEDOUT || ++notify->resolve_retry > 1000)
60 silc_fsm_next(notify->fsm, silc_client_notify_processed);
61 silc_client_unref_client(client, conn, notify->client_entry);
64 /* If no entries found, just finish the notify processing */
65 if (!entries && !notify->client_entry)
66 silc_fsm_next(notify->fsm, silc_client_notify_processed);
68 if (notify->channel) {
69 notify->channel->internal.resolve_cmd_ident = 0;
70 silc_client_unref_channel(client, conn, notify->channel);
73 /* Continue processing the notify */
74 SILC_FSM_CALL_CONTINUE_SYNC(notify->fsm);
77 /* Continue notify processing after it was suspended while waiting for
78 channel information being resolved. */
80 static SilcBool silc_client_notify_wait_continue(SilcClient client,
81 SilcClientConnection conn,
88 SilcClientNotify notify = context;
90 /* Continue after last command reply received */
91 if (SILC_STATUS_IS_ERROR(status) || status == SILC_STATUS_OK ||
92 status == SILC_STATUS_LIST_END)
93 SILC_FSM_CALL_CONTINUE_SYNC(notify->fsm);
98 /********************************* Notify ***********************************/
100 /* Process received notify packet */
102 SILC_FSM_STATE(silc_client_notify)
104 SilcPacket packet = state_context;
105 SilcClientNotify notify;
106 SilcNotifyPayload payload;
108 payload = silc_notify_payload_parse(silc_buffer_data(&packet->buffer),
109 silc_buffer_len(&packet->buffer));
111 SILC_LOG_DEBUG(("Malformed notify payload"));
112 silc_packet_free(packet);
113 return SILC_FSM_FINISH;
116 if (!silc_notify_get_args(payload)) {
117 SILC_LOG_DEBUG(("Malformed notify %d", silc_notify_get_type(payload)));
118 silc_notify_payload_free(payload);
119 silc_packet_free(packet);
120 return SILC_FSM_FINISH;
123 notify = silc_calloc(1, sizeof(*notify));
125 silc_notify_payload_free(payload);
126 silc_packet_free(packet);
127 return SILC_FSM_FINISH;
130 notify->packet = packet;
131 notify->payload = payload;
133 silc_fsm_set_state_context(fsm, notify);
135 /* Process the notify */
136 switch (silc_notify_get_type(payload)) {
138 case SILC_NOTIFY_TYPE_NONE:
140 silc_fsm_next(fsm, silc_client_notify_none);
143 case SILC_NOTIFY_TYPE_INVITE:
145 silc_fsm_next(fsm, silc_client_notify_invite);
148 case SILC_NOTIFY_TYPE_JOIN:
150 silc_fsm_next(fsm, silc_client_notify_join);
153 case SILC_NOTIFY_TYPE_LEAVE:
155 silc_fsm_next(fsm, silc_client_notify_leave);
158 case SILC_NOTIFY_TYPE_SIGNOFF:
160 silc_fsm_next(fsm, silc_client_notify_signoff);
163 case SILC_NOTIFY_TYPE_TOPIC_SET:
165 silc_fsm_next(fsm, silc_client_notify_topic_set);
168 case SILC_NOTIFY_TYPE_NICK_CHANGE:
170 silc_fsm_next(fsm, silc_client_notify_nick_change);
173 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
175 silc_fsm_next(fsm, silc_client_notify_cmode_change);
178 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
180 silc_fsm_next(fsm, silc_client_notify_cumode_change);
183 case SILC_NOTIFY_TYPE_MOTD:
185 silc_fsm_next(fsm, silc_client_notify_motd);
188 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
189 /** CHANNEL_CHANGE */
190 silc_fsm_next(fsm, silc_client_notify_channel_change);
193 case SILC_NOTIFY_TYPE_KICKED:
195 silc_fsm_next(fsm, silc_client_notify_kicked);
198 case SILC_NOTIFY_TYPE_KILLED:
200 silc_fsm_next(fsm, silc_client_notify_killed);
203 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
204 /** SERVER_SIGNOFF */
205 silc_fsm_next(fsm, silc_client_notify_server_signoff);
208 case SILC_NOTIFY_TYPE_ERROR:
210 silc_fsm_next(fsm, silc_client_notify_error);
213 case SILC_NOTIFY_TYPE_WATCH:
215 silc_fsm_next(fsm, silc_client_notify_watch);
219 /** Unknown notify */
220 silc_notify_payload_free(payload);
221 silc_packet_free(packet);
223 return SILC_FSM_FINISH;
227 return SILC_FSM_CONTINUE;
230 /* Notify processed, finish the packet processing thread */
232 SILC_FSM_STATE(silc_client_notify_processed)
234 SilcClientNotify notify = state_context;
235 SilcPacket packet = notify->packet;
236 SilcNotifyPayload payload = notify->payload;
238 silc_notify_payload_free(payload);
239 silc_packet_free(packet);
241 return SILC_FSM_FINISH;
244 /********************************** NONE ************************************/
246 SILC_FSM_STATE(silc_client_notify_none)
248 SilcClientConnection conn = fsm_context;
249 SilcClient client = conn->client;
250 SilcClientNotify notify = state_context;
251 SilcNotifyPayload payload = notify->payload;
252 SilcNotifyType type = silc_notify_get_type(payload);
253 SilcArgumentPayload args = silc_notify_get_args(payload);
255 SILC_LOG_DEBUG(("Notify: NONE"));
257 /* Notify application */
258 NOTIFY(client, conn, type, silc_argument_get_arg_type(args, 1, NULL));
260 /** Notify processed */
261 silc_fsm_next(fsm, silc_client_notify_processed);
262 return SILC_FSM_CONTINUE;
265 /********************************* INVITE ***********************************/
267 /* Someone invite me to a channel */
269 SILC_FSM_STATE(silc_client_notify_invite)
271 SilcClientConnection conn = fsm_context;
272 SilcClient client = conn->client;
273 SilcClientNotify notify = state_context;
274 SilcNotifyPayload payload = notify->payload;
275 SilcNotifyType type = silc_notify_get_type(payload);
276 SilcArgumentPayload args = silc_notify_get_args(payload);
277 SilcClientEntry client_entry;
278 SilcChannelEntry channel = NULL;
283 SILC_LOG_DEBUG(("Notify: INVITE"));
286 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
289 /* Get the channel name */
290 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
294 /* Get the channel entry */
295 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
299 /* If channel is being resolved handle notify after resolving */
300 if (channel->internal.resolve_cmd_ident) {
301 silc_client_unref_channel(client, conn, channel);
302 SILC_FSM_CALL(silc_client_command_pending(
303 conn, SILC_COMMAND_NONE,
304 channel->internal.resolve_cmd_ident,
305 silc_client_notify_wait_continue,
310 /* Get sender Client ID */
311 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
314 /* Find Client entry and if not found query it */
315 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
316 if (!client_entry || !client_entry->internal.valid) {
317 /** Resolve client */
318 silc_client_unref_client(client, conn, client_entry);
319 notify->channel = channel;
320 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
321 silc_client_get_client_by_id_resolve(
322 client, conn, &id.u.client_id, NULL,
323 silc_client_notify_resolved,
328 /* Notify application */
329 NOTIFY(client, conn, type, channel, tmp, client_entry);
331 silc_client_unref_client(client, conn, client_entry);
334 /** Notify processed */
335 silc_client_unref_channel(client, conn, channel);
336 silc_fsm_next(fsm, silc_client_notify_processed);
337 return SILC_FSM_CONTINUE;
340 /********************************** JOIN ************************************/
342 /* Someone joined a channel */
344 SILC_FSM_STATE(silc_client_notify_join)
346 SilcClientConnection conn = fsm_context;
347 SilcClient client = conn->client;
348 SilcClientNotify notify = state_context;
349 SilcNotifyPayload payload = notify->payload;
350 SilcNotifyType type = silc_notify_get_type(payload);
351 SilcArgumentPayload args = silc_notify_get_args(payload);
352 SilcClientEntry client_entry;
353 SilcChannelEntry channel = NULL;
356 SILC_LOG_DEBUG(("Notify: JOIN"));
359 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
362 /* Get channel entry */
363 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
367 /* If channel is being resolved handle notify after resolving */
368 if (channel->internal.resolve_cmd_ident) {
369 silc_client_unref_channel(client, conn, channel);
370 SILC_FSM_CALL(silc_client_command_pending(
371 conn, SILC_COMMAND_NONE,
372 channel->internal.resolve_cmd_ident,
373 silc_client_notify_wait_continue,
379 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
382 /* Find client entry and if not found query it. If we just queried it
383 don't do it again, unless some data (like username) is missing. */
384 client_entry = notify->client_entry;
386 client_entry = silc_client_get_client(client, conn, &id.u.client_id);
387 if (!client_entry || !client_entry->internal.valid ||
388 !client_entry->username[0]) {
389 /** Resolve client */
390 notify->channel = channel;
391 notify->client_entry = client_entry;
392 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
393 silc_client_get_client_by_id_resolve(
394 client, conn, client_entry ?
395 &client_entry->id : &id.u.client_id,
396 NULL, silc_client_notify_resolved,
401 silc_rwlock_wrlock(client_entry->internal.lock);
402 silc_rwlock_wrlock(channel->internal.lock);
404 if (client_entry != conn->local_entry)
405 silc_client_nickname_format(client, conn, client_entry, FALSE);
407 /* Join the client to channel */
408 if (!silc_client_add_to_channel(client, conn, channel, client_entry, 0)) {
409 silc_rwlock_unlock(channel->internal.lock);
410 silc_rwlock_unlock(client_entry->internal.lock);
414 silc_rwlock_unlock(channel->internal.lock);
415 silc_rwlock_unlock(client_entry->internal.lock);
417 /* Notify application. */
418 NOTIFY(client, conn, type, client_entry, channel);
420 silc_client_unref_client(client, conn, client_entry);
423 /** Notify processed */
424 silc_client_unref_channel(client, conn, channel);
425 silc_fsm_next(fsm, silc_client_notify_processed);
426 return SILC_FSM_CONTINUE;
429 /********************************** LEAVE ***********************************/
431 /* Someone left a channel */
433 SILC_FSM_STATE(silc_client_notify_leave)
435 SilcClientConnection conn = fsm_context;
436 SilcClient client = conn->client;
437 SilcClientNotify notify = state_context;
438 SilcNotifyPayload payload = notify->payload;
439 SilcPacket packet = notify->packet;
440 SilcNotifyType type = silc_notify_get_type(payload);
441 SilcArgumentPayload args = silc_notify_get_args(payload);
442 SilcClientEntry client_entry = NULL;
443 SilcChannelEntry channel = NULL;
446 SILC_LOG_DEBUG(("Notify: LEAVE"));
448 /* Get channel entry */
449 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
450 &id.u.channel_id, sizeof(id.u.channel_id)))
452 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
456 /* If channel is being resolved handle notify after resolving */
457 if (channel->internal.resolve_cmd_ident) {
458 silc_client_unref_channel(client, conn, channel);
459 SILC_FSM_CALL(silc_client_command_pending(
460 conn, SILC_COMMAND_NONE,
461 channel->internal.resolve_cmd_ident,
462 silc_client_notify_wait_continue,
468 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
471 /* Find Client entry */
472 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
476 /* Remove client from channel */
477 if (!silc_client_remove_from_channel(client, conn, channel, client_entry))
480 /* Notify application. */
481 NOTIFY(client, conn, type, client_entry, channel);
483 silc_client_unref_client(client, conn, client_entry);
486 /** Notify processed */
487 silc_client_unref_channel(client, conn, channel);
488 silc_fsm_next(fsm, silc_client_notify_processed);
489 return SILC_FSM_CONTINUE;
492 /********************************* SIGNOFF **********************************/
494 /* Someone quit SILC network */
496 SILC_FSM_STATE(silc_client_notify_signoff)
498 SilcClientConnection conn = fsm_context;
499 SilcClient client = conn->client;
500 SilcClientNotify notify = state_context;
501 SilcNotifyPayload payload = notify->payload;
502 SilcPacket packet = notify->packet;
503 SilcNotifyType type = silc_notify_get_type(payload);
504 SilcArgumentPayload args = silc_notify_get_args(payload);
505 SilcClientEntry client_entry;
506 SilcChannelEntry channel;
511 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
514 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
517 /* Find Client entry */
518 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
522 /* Get signoff message */
523 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
524 if (tmp && tmp_len > 128)
527 /* Notify application */
528 if (client_entry->internal.valid)
529 NOTIFY(client, conn, type, client_entry, tmp);
531 /* Remove from channel */
532 if (packet->dst_id_type == SILC_ID_CHANNEL) {
533 if (silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
534 &id.u.channel_id, sizeof(id.u.channel_id))) {
535 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
537 silc_client_remove_from_channel(client, conn, channel, client_entry);
538 silc_client_unref_channel(client, conn, channel);
544 client_entry->internal.valid = FALSE;
545 silc_client_del_client(client, conn, client_entry);
546 silc_client_unref_client(client, conn, client_entry);
549 /** Notify processed */
550 silc_fsm_next(fsm, silc_client_notify_processed);
551 return SILC_FSM_CONTINUE;
554 /******************************** TOPIC_SET *********************************/
556 /* Someone set topic on a channel */
558 SILC_FSM_STATE(silc_client_notify_topic_set)
560 SilcClientConnection conn = fsm_context;
561 SilcClient client = conn->client;
562 SilcClientNotify notify = state_context;
563 SilcNotifyPayload payload = notify->payload;
564 SilcPacket packet = notify->packet;
565 SilcNotifyType type = silc_notify_get_type(payload);
566 SilcArgumentPayload args = silc_notify_get_args(payload);
567 SilcClientEntry client_entry = NULL;
568 SilcChannelEntry channel = NULL, channel_entry = NULL;
569 SilcServerEntry server = NULL;
575 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
577 /* Get channel entry */
578 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
579 &id.u.channel_id, sizeof(id.u.channel_id)))
581 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
585 /* If channel is being resolved handle notify after resolving */
586 if (channel->internal.resolve_cmd_ident) {
587 silc_client_unref_channel(client, conn, channel);
588 SILC_FSM_CALL(silc_client_command_pending(
589 conn, SILC_COMMAND_NONE,
590 channel->internal.resolve_cmd_ident,
591 silc_client_notify_wait_continue,
596 /* Get ID of topic changer */
597 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
601 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
605 if (id.type == SILC_ID_CLIENT) {
606 /* Find Client entry */
607 client_entry = notify->client_entry;
609 client_entry = silc_client_get_client(client, conn, &id.u.client_id);
610 if (!client_entry || !client_entry->internal.valid) {
611 /** Resolve client */
612 notify->channel = channel;
613 notify->client_entry = client_entry;
614 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
615 silc_client_get_client_by_id_resolve(
616 client, conn, &id.u.client_id, NULL,
617 silc_client_notify_resolved,
623 /* If client is not on channel, ignore this notify */
624 if (!silc_client_on_channel(channel, client_entry))
627 entry = client_entry;
628 } else if (id.type == SILC_ID_SERVER) {
629 /* Find Server entry */
630 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
632 /** Resolve server */
633 notify->channel = channel;
634 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
635 silc_client_get_server_by_id_resolve(
636 client, conn, &id.u.server_id,
637 silc_client_notify_resolved,
643 /* Find Channel entry */
644 channel_entry = silc_client_get_channel_by_id(client, conn,
646 if (!channel_entry) {
647 /** Resolve channel */
648 notify->channel = channel;
649 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
650 silc_client_get_channel_by_id_resolve(
651 client, conn, &id.u.channel_id,
652 silc_client_notify_resolved,
656 entry = channel_entry;
659 silc_rwlock_wrlock(channel->internal.lock);
660 silc_free(channel->topic);
661 channel->topic = silc_memdup(tmp, strlen(tmp));
662 silc_rwlock_unlock(channel->internal.lock);
664 /* Notify application. */
665 NOTIFY(client, conn, type, id.type, entry, channel->topic, channel);
668 silc_client_unref_client(client, conn, client_entry);
670 silc_client_unref_server(client, conn, server);
672 silc_client_unref_channel(client, conn, channel_entry);
675 /** Notify processed */
676 silc_client_unref_channel(client, conn, channel);
677 silc_fsm_next(fsm, silc_client_notify_processed);
678 return SILC_FSM_CONTINUE;
681 /****************************** NICK_CHANGE *********************************/
683 /* Someone changed their nickname on a channel */
685 SILC_FSM_STATE(silc_client_notify_nick_change)
687 SilcClientConnection conn = fsm_context;
688 SilcClient client = conn->client;
689 SilcClientNotify notify = state_context;
690 SilcNotifyPayload payload = notify->payload;
691 SilcNotifyType type = silc_notify_get_type(payload);
692 SilcArgumentPayload args = silc_notify_get_args(payload);
693 SilcClientEntry client_entry = NULL;
694 unsigned char *tmp, oldnick[128 + 1];
699 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
702 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
706 if (conn->local_id &&
707 SILC_ID_CLIENT_COMPARE(&id.u.client_id, conn->local_id))
710 /* Get new Client ID */
711 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id2, NULL))
715 if (conn->local_id &&
716 SILC_ID_CLIENT_COMPARE(&id2.u.client_id, conn->local_id))
719 /* Find old client entry. If we don't have the entry, we ignore this
721 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
724 valid = client_entry->internal.valid;
726 /* Take the new nickname */
727 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
731 silc_rwlock_wrlock(client_entry->internal.lock);
733 /* Check whether nickname changed at all. It is possible that nick
734 change notify is received but nickname didn't change, only the
735 ID changes. If Client ID hash match, nickname didn't change. */
736 if (SILC_ID_COMPARE_HASH(&client_entry->id, &id2.u.client_id) &&
737 silc_utf8_strcasecmp(tmp, client_entry->nickname)) {
738 /* Nickname didn't change. Update only Client ID. We don't notify
739 application because nickname didn't change. */
740 silc_mutex_lock(conn->internal->lock);
741 silc_idcache_update_by_context(conn->internal->client_cache, client_entry,
742 &id2.u.client_id, NULL, FALSE);
743 silc_mutex_unlock(conn->internal->lock);
744 silc_rwlock_unlock(client_entry->internal.lock);
748 /* Change the nickname */
749 memcpy(oldnick, client_entry->nickname, sizeof(client_entry->nickname));
750 if (!silc_client_change_nickname(client, conn, client_entry, tmp,
751 &id2.u.client_id, NULL, 0)) {
752 silc_rwlock_unlock(client_entry->internal.lock);
756 silc_rwlock_unlock(client_entry->internal.lock);
758 /* Notify application, if client entry is valid. We do not send nick change
759 notify for entries that were invalid (application doesn't know them). */
761 NOTIFY(client, conn, type, client_entry, oldnick, client_entry->nickname);
764 /** Notify processed */
765 silc_client_unref_client(client, conn, client_entry);
766 silc_fsm_next(fsm, silc_client_notify_processed);
767 return SILC_FSM_CONTINUE;
770 /****************************** CMODE_CHANGE ********************************/
772 /* Someone changed channel mode */
774 SILC_FSM_STATE(silc_client_notify_cmode_change)
776 SilcClientConnection conn = fsm_context;
777 SilcClient client = conn->client;
778 SilcClientNotify notify = state_context;
779 SilcNotifyPayload payload = notify->payload;
780 SilcPacket packet = notify->packet;
781 SilcNotifyType type = silc_notify_get_type(payload);
782 SilcArgumentPayload args = silc_notify_get_args(payload);
783 SilcClientEntry client_entry = NULL;
784 SilcChannelEntry channel = NULL, channel_entry = NULL;
785 SilcServerEntry server = NULL;
788 SilcUInt32 tmp_len, mode;
790 char *passphrase, *cipher, *hmac;
791 SilcPublicKey founder_key = NULL;
792 SilcDList chpks = NULL;
794 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
796 /* Get channel entry */
797 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
798 &id.u.channel_id, sizeof(id.u.channel_id)))
800 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
804 /* If channel is being resolved handle notify after resolving */
805 if (channel->internal.resolve_cmd_ident) {
806 silc_client_unref_channel(client, conn, channel);
807 SILC_FSM_CALL(silc_client_command_pending(
808 conn, SILC_COMMAND_NONE,
809 channel->internal.resolve_cmd_ident,
810 silc_client_notify_wait_continue,
816 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
819 SILC_GET32_MSB(mode, tmp);
821 /* Get ID of who changed the mode */
822 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
825 if (id.type == SILC_ID_CLIENT) {
826 /* Find Client entry */
827 client_entry = notify->client_entry;
829 client_entry = silc_client_get_client(client, conn, &id.u.client_id);
830 if (!client_entry || !client_entry->internal.valid) {
831 /** Resolve client */
832 notify->channel = channel;
833 notify->client_entry = client_entry;
834 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
835 silc_client_get_client_by_id_resolve(
836 client, conn, &id.u.client_id, NULL,
837 silc_client_notify_resolved,
843 /* If client is not on channel, ignore this notify */
844 if (!silc_client_on_channel(channel, client_entry))
847 entry = client_entry;
848 } else if (id.type == SILC_ID_SERVER) {
849 /* Find Server entry */
850 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
852 /** Resolve server */
853 notify->channel = channel;
854 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
855 silc_client_get_server_by_id_resolve(
856 client, conn, &id.u.server_id,
857 silc_client_notify_resolved,
863 /* Find Channel entry */
864 channel_entry = silc_client_get_channel_by_id(client, conn,
866 if (!channel_entry) {
867 /** Resolve channel */
868 notify->channel = channel;
869 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
870 silc_client_get_channel_by_id_resolve(
871 client, conn, &id.u.channel_id,
872 silc_client_notify_resolved,
876 entry = channel_entry;
879 silc_rwlock_wrlock(channel->internal.lock);
881 /* Get the channel founder key if it was set */
882 tmp = silc_argument_get_arg_type(args, 6, &tmp_len);
884 if (!silc_public_key_payload_decode(tmp, tmp_len, &founder_key)) {
885 silc_rwlock_unlock(channel->internal.lock);
888 if (!channel->founder_key) {
889 channel->founder_key = founder_key;
895 cipher = silc_argument_get_arg_type(args, 3, &tmp_len);
898 hmac = silc_argument_get_arg_type(args, 4, &tmp_len);
900 unsigned char hash[SILC_HASH_MAXLEN];
903 if (!silc_hmac_alloc(hmac, NULL, &newhmac)) {
904 silc_rwlock_unlock(channel->internal.lock);
908 /* Get HMAC key from the old HMAC context, and update it to the new one */
909 tmp = (unsigned char *)silc_hmac_get_key(channel->internal.hmac, &tmp_len);
911 silc_hash_make(silc_hmac_get_hash(newhmac), tmp, tmp_len, hash);
912 silc_hmac_set_key(newhmac, hash,
913 silc_hash_len(silc_hmac_get_hash(newhmac)));
914 if (channel->internal.hmac)
915 silc_hmac_free(channel->internal.hmac);
916 channel->internal.hmac = newhmac;
917 memset(hash, 0, sizeof(hash));
921 /* Get the passphrase if it was set */
922 passphrase = silc_argument_get_arg_type(args, 5, &tmp_len);
925 tmp = silc_argument_get_arg_type(args, 8, &tmp_len);
926 if (tmp && tmp_len == 4)
927 SILC_GET32_MSB(channel->user_limit, tmp);
928 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
929 channel->user_limit = 0;
931 /* Save the new mode */
932 channel->mode = mode;
934 /* Get the channel public key that was added or removed */
935 tmp = silc_argument_get_arg_type(args, 7, &tmp_len);
937 silc_client_channel_save_public_keys(channel, tmp, tmp_len);
939 silc_rwlock_unlock(channel->internal.lock);
941 /* Notify application. */
942 NOTIFY(client, conn, type, id.type, entry, mode, cipher, hmac,
943 passphrase, channel->founder_key, chpks, channel);
947 silc_pkcs_public_key_free(founder_key);
949 silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
951 silc_client_unref_client(client, conn, client_entry);
953 silc_client_unref_server(client, conn, server);
955 silc_client_unref_channel(client, conn, channel_entry);
956 silc_client_unref_channel(client, conn, channel);
958 /** Notify processed */
959 silc_fsm_next(fsm, silc_client_notify_processed);
960 return SILC_FSM_CONTINUE;
963 /***************************** CUMODE_CHANGE ********************************/
965 /* Someone changed a user's mode on a channel */
967 SILC_FSM_STATE(silc_client_notify_cumode_change)
969 SilcClientConnection conn = fsm_context;
970 SilcClient client = conn->client;
971 SilcClientNotify notify = state_context;
972 SilcNotifyPayload payload = notify->payload;
973 SilcPacket packet = notify->packet;
974 SilcNotifyType type = silc_notify_get_type(payload);
975 SilcArgumentPayload args = silc_notify_get_args(payload);
976 SilcClientEntry client_entry = NULL, client_entry2 = NULL;
977 SilcChannelEntry channel = NULL, channel_entry = NULL;
978 SilcServerEntry server = NULL;
982 SilcUInt32 tmp_len, mode;
985 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
987 /* Get channel entry */
988 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
989 &id.u.channel_id, sizeof(id.u.channel_id)))
991 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
995 /* If channel is being resolved handle notify after resolving */
996 if (channel->internal.resolve_cmd_ident) {
997 silc_client_unref_channel(client, conn, channel);
998 SILC_FSM_CALL(silc_client_command_pending(
999 conn, SILC_COMMAND_NONE,
1000 channel->internal.resolve_cmd_ident,
1001 silc_client_notify_wait_continue,
1006 /* Get target Client ID */
1007 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id2, NULL))
1010 /* Find target Client entry */
1011 client_entry2 = silc_client_get_client_by_id(client, conn, &id2.u.client_id);
1012 if (!client_entry2 || !client_entry2->internal.valid) {
1013 /** Resolve client */
1014 silc_client_unref_client(client, conn, client_entry2);
1015 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1016 client, conn, &id2.u.client_id, NULL,
1017 silc_client_notify_resolved,
1022 /* If target client is not on channel, ignore this notify */
1023 if (!silc_client_on_channel(channel, client_entry2))
1027 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1030 SILC_GET32_MSB(mode, tmp);
1032 /* Get ID of mode changer */
1033 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1036 if (id.type == SILC_ID_CLIENT) {
1037 /* Find Client entry */
1038 client_entry = notify->client_entry;
1039 if (!client_entry) {
1040 client_entry = silc_client_get_client(client, conn, &id.u.client_id);
1041 if (!client_entry || !client_entry->internal.valid) {
1042 /** Resolve client */
1043 notify->channel = channel;
1044 notify->client_entry = client_entry;
1045 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1046 silc_client_get_client_by_id_resolve(
1047 client, conn, &id.u.client_id, NULL,
1048 silc_client_notify_resolved,
1054 /* If client is not on channel, ignore this notify */
1055 if (!silc_client_on_channel(channel, client_entry))
1058 entry = client_entry;
1059 } else if (id.type == SILC_ID_SERVER) {
1060 /* Find Server entry */
1061 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1063 /** Resolve server */
1064 notify->channel = channel;
1065 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1066 silc_client_get_server_by_id_resolve(
1067 client, conn, &id.u.server_id,
1068 silc_client_notify_resolved,
1074 /* Find Channel entry */
1075 channel_entry = silc_client_get_channel_by_id(client, conn,
1077 if (!channel_entry) {
1078 /** Resolve channel */
1079 notify->channel = channel;
1080 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1081 silc_client_get_channel_by_id_resolve(
1082 client, conn, &id.u.channel_id,
1083 silc_client_notify_resolved,
1087 entry = channel_entry;
1091 silc_rwlock_wrlock(channel->internal.lock);
1092 chu = silc_client_on_channel(channel, client_entry2);
1095 silc_rwlock_unlock(channel->internal.lock);
1097 /* Notify application. */
1098 NOTIFY(client, conn, type, id.type, entry, mode, client_entry2, channel);
1101 silc_client_unref_client(client, conn, client_entry2);
1103 silc_client_unref_client(client, conn, client_entry);
1105 silc_client_unref_server(client, conn, server);
1107 silc_client_unref_channel(client, conn, channel_entry);
1108 silc_client_unref_channel(client, conn, channel);
1110 /** Notify processed */
1111 silc_fsm_next(fsm, silc_client_notify_processed);
1112 return SILC_FSM_CONTINUE;
1115 /********************************* MOTD *************************************/
1117 /* Received Message of the day */
1119 SILC_FSM_STATE(silc_client_notify_motd)
1121 SilcClientConnection conn = fsm_context;
1122 SilcClient client = conn->client;
1123 SilcClientNotify notify = state_context;
1124 SilcNotifyPayload payload = notify->payload;
1125 SilcNotifyType type = silc_notify_get_type(payload);
1126 SilcArgumentPayload args = silc_notify_get_args(payload);
1130 SILC_LOG_DEBUG(("Notify: MOTD"));
1133 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1137 /* Notify application */
1138 NOTIFY(client, conn, type, tmp);
1141 /** Notify processed */
1142 silc_fsm_next(fsm, silc_client_notify_processed);
1143 return SILC_FSM_CONTINUE;
1146 /**************************** CHANNEL CHANGE ********************************/
1148 /* Router has enforced a new ID to a channel, change it */
1150 SILC_FSM_STATE(silc_client_notify_channel_change)
1152 SilcClientConnection conn = fsm_context;
1153 SilcClient client = conn->client;
1154 SilcClientNotify notify = state_context;
1155 SilcNotifyPayload payload = notify->payload;
1156 SilcNotifyType type = silc_notify_get_type(payload);
1157 SilcArgumentPayload args = silc_notify_get_args(payload);
1158 SilcChannelEntry channel = NULL;
1161 SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
1163 /* Get the old ID */
1164 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1167 /* Get the channel entry */
1168 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1172 /* If channel is being resolved handle notify after resolving */
1173 if (channel->internal.resolve_cmd_ident) {
1174 silc_client_unref_channel(client, conn, channel);
1175 SILC_FSM_CALL(silc_client_command_pending(
1176 conn, SILC_COMMAND_NONE,
1177 channel->internal.resolve_cmd_ident,
1178 silc_client_notify_wait_continue,
1183 /* Get the new ID */
1184 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
1187 /* Replace the Channel ID */
1188 if (!silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id))
1191 /* Notify application */
1192 NOTIFY(client, conn, type, channel, channel);
1195 /** Notify processed */
1196 silc_client_unref_channel(client, conn, channel);
1197 silc_fsm_next(fsm, silc_client_notify_processed);
1198 return SILC_FSM_CONTINUE;
1201 /******************************** KICKED ************************************/
1203 /* Some client was kicked from a channel */
1205 SILC_FSM_STATE(silc_client_notify_kicked)
1207 SilcClientConnection conn = fsm_context;
1208 SilcClient client = conn->client;
1209 SilcClientNotify notify = state_context;
1210 SilcNotifyPayload payload = notify->payload;
1211 SilcPacket packet = notify->packet;
1212 SilcNotifyType type = silc_notify_get_type(payload);
1213 SilcArgumentPayload args = silc_notify_get_args(payload);
1214 SilcClientEntry client_entry, client_entry2;
1215 SilcChannelEntry channel = NULL;
1220 SILC_LOG_DEBUG(("Notify: KICKED"));
1222 /* Get channel entry */
1223 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
1224 &id.u.channel_id, sizeof(id.u.channel_id)))
1226 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1230 /* If channel is being resolved handle notify after resolving */
1231 if (channel->internal.resolve_cmd_ident) {
1232 silc_client_unref_channel(client, conn, channel);
1233 SILC_FSM_CALL(silc_client_command_pending(
1234 conn, SILC_COMMAND_NONE,
1235 channel->internal.resolve_cmd_ident,
1236 silc_client_notify_wait_continue,
1241 /* Get the kicked Client ID */
1242 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1245 /* Find client entry */
1246 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1250 /* Get kicker's Client ID */
1251 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
1254 /* Find kicker's client entry and if not found resolve it */
1255 client_entry2 = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1256 if (!client_entry2 || !client_entry2->internal.valid) {
1257 /** Resolve client */
1258 silc_client_unref_client(client, conn, client_entry);
1259 silc_client_unref_client(client, conn, client_entry2);
1260 notify->channel = channel;
1261 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1262 silc_client_get_client_by_id_resolve(
1263 client, conn, &id.u.client_id, NULL,
1264 silc_client_notify_resolved,
1270 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1272 /* Remove kicked client from channel */
1273 if (client_entry != conn->local_entry) {
1274 if (!silc_client_remove_from_channel(client, conn, channel, client_entry))
1278 /* Notify application. */
1279 NOTIFY(client, conn, type, client_entry, tmp, client_entry2, channel);
1281 /* If I was kicked from channel, remove the channel */
1282 if (client_entry == conn->local_entry) {
1283 if (conn->current_channel == channel)
1284 conn->current_channel = NULL;
1285 silc_client_empty_channel(client, conn, channel);
1286 silc_client_del_channel(client, conn, channel);
1289 silc_client_unref_client(client, conn, client_entry);
1290 silc_client_unref_client(client, conn, client_entry2);
1293 /** Notify processed */
1294 silc_client_unref_channel(client, conn, channel);
1295 silc_fsm_next(fsm, silc_client_notify_processed);
1296 return SILC_FSM_CONTINUE;
1299 /******************************** KILLED ************************************/
1301 /* Some client was killed from the network */
1303 SILC_FSM_STATE(silc_client_notify_killed)
1305 SilcClientConnection conn = fsm_context;
1306 SilcClient client = conn->client;
1307 SilcClientNotify notify = state_context;
1308 SilcNotifyPayload payload = notify->payload;
1309 SilcNotifyType type = silc_notify_get_type(payload);
1310 SilcArgumentPayload args = silc_notify_get_args(payload);
1311 SilcClientEntry client_entry = NULL, client_entry2 = NULL;
1312 SilcChannelEntry channel_entry = NULL;
1313 SilcServerEntry server = NULL;
1316 SilcUInt32 comment_len;
1319 SILC_LOG_DEBUG(("Notify: KILLED"));
1322 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1325 /* Find Client entry */
1326 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1331 comment = silc_argument_get_arg_type(args, 2, &comment_len);
1333 /* Get killer's ID */
1334 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
1337 if (id.type == SILC_ID_CLIENT) {
1338 /* Find Client entry */
1339 client_entry2 = silc_client_get_client_by_id(client, conn,
1341 if (!client_entry2 || !client_entry2->internal.valid) {
1342 /** Resolve client */
1343 silc_client_unref_client(client, conn, client_entry);
1344 silc_client_unref_client(client, conn, client_entry2);
1345 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1346 client, conn, &id.u.client_id, NULL,
1347 silc_client_notify_resolved,
1351 entry = client_entry2;
1352 } else if (id.type == SILC_ID_SERVER) {
1353 /* Find Server entry */
1354 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1356 /** Resolve server */
1357 SILC_FSM_CALL(silc_client_get_server_by_id_resolve(
1358 client, conn, &id.u.server_id,
1359 silc_client_notify_resolved,
1365 /* Find Channel entry */
1366 channel_entry = silc_client_get_channel_by_id(client, conn,
1368 if (!channel_entry) {
1369 /** Resolve channel */
1370 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1371 client, conn, &id.u.channel_id,
1372 silc_client_notify_resolved,
1376 entry = channel_entry;
1379 /* Notify application. */
1380 NOTIFY(client, conn, type, client_entry, comment, id.type, entry);
1382 /* Delete the killed client */
1383 if (client_entry != conn->local_entry) {
1384 silc_client_remove_from_channels(client, conn, client_entry);
1385 client_entry->internal.valid = FALSE;
1386 silc_client_del_client(client, conn, client_entry);
1390 silc_client_unref_client(client, conn, client_entry);
1392 silc_client_unref_client(client, conn, client_entry2);
1394 silc_client_unref_server(client, conn, server);
1396 silc_client_unref_channel(client, conn, channel_entry);
1398 /** Notify processed */
1399 silc_fsm_next(fsm, silc_client_notify_processed);
1400 return SILC_FSM_CONTINUE;
1403 /**************************** SERVER SIGNOFF ********************************/
1405 /* Some server quit SILC network. Remove its clients from channels. */
1407 SILC_FSM_STATE(silc_client_notify_server_signoff)
1409 SilcClientConnection conn = fsm_context;
1410 SilcClient client = conn->client;
1411 SilcClientNotify notify = state_context;
1412 SilcNotifyPayload payload = notify->payload;
1413 SilcNotifyType type = silc_notify_get_type(payload);
1414 SilcArgumentPayload args = silc_notify_get_args(payload);
1415 SilcClientEntry client_entry;
1416 SilcServerEntry server_entry = NULL;
1421 SILC_LOG_DEBUG(("Notify: SERVER_SIGNOFF"));
1423 clients = silc_dlist_init();
1428 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1431 /* Get server, in case we have it cached */
1432 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1434 for (i = 1; i < silc_argument_get_arg_num(args); i++) {
1436 if (!silc_argument_get_decoded(args, i + 1, SILC_ARGUMENT_ID, &id, NULL))
1439 /* Get the client entry */
1440 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1441 if (client_entry && client_entry->internal.valid)
1442 silc_dlist_add(clients, client_entry);
1445 /* Notify application. */
1446 NOTIFY(client, conn, type, server_entry, clients);
1448 /* Delete the clients */
1449 silc_dlist_start(clients);
1450 while ((client_entry = silc_dlist_get(clients))) {
1451 silc_client_remove_from_channels(client, conn, client_entry);
1452 client_entry->internal.valid = FALSE;
1453 silc_client_del_client(client, conn, client_entry);
1457 /** Notify processed */
1458 silc_client_unref_server(client, conn, server_entry);
1459 silc_client_list_free(client, conn, clients);
1460 silc_fsm_next(fsm, silc_client_notify_processed);
1461 return SILC_FSM_CONTINUE;
1464 /******************************** ERROR *************************************/
1466 /* Some error occurred */
1468 SILC_FSM_STATE(silc_client_notify_error)
1470 SilcClientConnection conn = fsm_context;
1471 SilcClient client = conn->client;
1472 SilcClientNotify notify = state_context;
1473 SilcNotifyPayload payload = notify->payload;
1474 SilcNotifyType type = silc_notify_get_type(payload);
1475 SilcArgumentPayload args = silc_notify_get_args(payload);
1476 SilcClientEntry client_entry;
1483 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1484 if (!tmp && tmp_len != 1)
1486 error = (SilcStatus)tmp[0];
1488 SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1490 /* Handle the error */
1491 if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1492 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
1494 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1496 silc_client_remove_from_channels(client, conn, client_entry);
1497 silc_client_del_client(client, conn, client_entry);
1498 silc_client_unref_client(client, conn, client_entry);
1502 /* Notify application. */
1503 NOTIFY(client, conn, type, error);
1506 /** Notify processed */
1507 silc_fsm_next(fsm, silc_client_notify_processed);
1508 return SILC_FSM_CONTINUE;
1511 /******************************** WATCH *************************************/
1513 /* Received notify about some client we are watching */
1515 SILC_FSM_STATE(silc_client_notify_watch)
1517 SilcClientConnection conn = fsm_context;
1518 SilcClient client = conn->client;
1519 SilcClientNotify notify = state_context;
1520 SilcNotifyPayload payload = notify->payload;
1521 SilcNotifyType type = silc_notify_get_type(payload);
1522 SilcArgumentPayload args = silc_notify_get_args(payload);
1523 SilcClientEntry client_entry = NULL;
1524 SilcNotifyType ntype = 0;
1525 unsigned char *pk, *tmp;
1526 SilcUInt32 mode, pk_len, tmp_len;
1527 SilcPublicKey public_key = NULL;
1530 SILC_LOG_DEBUG(("Notify: WATCH"));
1532 /* Get sender Client ID */
1533 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1536 /* Find client entry and if not found resolve it */
1537 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1538 if (!client_entry || !client_entry->internal.valid) {
1539 /** Resolve client */
1540 silc_client_unref_client(client, conn, client_entry);
1541 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1542 client, conn, &id.u.client_id, NULL,
1543 silc_client_notify_resolved,
1549 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1550 if (!tmp || tmp_len != 4)
1552 SILC_GET32_MSB(mode, tmp);
1554 /* Get notify type */
1555 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1556 if (tmp && tmp_len != 2)
1559 SILC_GET16_MSB(ntype, tmp);
1562 tmp = silc_argument_get_arg_type(args, 2, NULL);
1564 char *tmp_nick = NULL;
1566 silc_client_nickname_parse(client, conn, client_entry->nickname,
1569 /* If same nick, the client was new to us and has become "present"
1570 to network. Send NULL as nick to application. */
1571 if (tmp_nick && silc_utf8_strcasecmp(tmp, tmp_nick))
1574 silc_free(tmp_nick);
1577 /* Get public key, if present */
1578 pk = silc_argument_get_arg_type(args, 5, &pk_len);
1579 if (pk && !client_entry->public_key) {
1580 if (silc_public_key_payload_decode(pk, pk_len, &public_key)) {
1581 client_entry->public_key = public_key;
1586 /* Notify application. */
1587 NOTIFY(client, conn, type, client_entry, tmp, mode, ntype,
1588 client_entry->public_key);
1590 client_entry->mode = mode;
1592 /* Remove client that left the network. */
1593 if (ntype == SILC_NOTIFY_TYPE_SIGNOFF ||
1594 ntype == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
1595 ntype == SILC_NOTIFY_TYPE_KILLED) {
1596 silc_client_remove_from_channels(client, conn, client_entry);
1597 client_entry->internal.valid = FALSE;
1598 silc_client_del_client(client, conn, client_entry);
1602 silc_pkcs_public_key_free(public_key);
1605 /** Notify processed */
1606 silc_client_unref_client(client, conn, client_entry);
1607 silc_fsm_next(fsm, silc_client_notify_processed);
1608 return SILC_FSM_CONTINUE;