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 /* 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, FALSE);
935 else if (channel->mode & SILC_CHANNEL_MODE_CHANNEL_AUTH)
936 silc_client_channel_save_public_keys(channel, NULL, 0, TRUE);
938 /* Save the new mode */
939 channel->mode = mode;
941 silc_rwlock_unlock(channel->internal.lock);
943 /* Notify application. */
944 NOTIFY(client, conn, type, id.type, entry, mode, cipher, hmac,
945 passphrase, channel->founder_key, chpks, channel);
949 silc_pkcs_public_key_free(founder_key);
951 silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
953 silc_client_unref_client(client, conn, client_entry);
955 silc_client_unref_server(client, conn, server);
957 silc_client_unref_channel(client, conn, channel_entry);
958 silc_client_unref_channel(client, conn, channel);
960 /** Notify processed */
961 silc_fsm_next(fsm, silc_client_notify_processed);
962 return SILC_FSM_CONTINUE;
965 /***************************** CUMODE_CHANGE ********************************/
967 /* Someone changed a user's mode on a channel */
969 SILC_FSM_STATE(silc_client_notify_cumode_change)
971 SilcClientConnection conn = fsm_context;
972 SilcClient client = conn->client;
973 SilcClientNotify notify = state_context;
974 SilcNotifyPayload payload = notify->payload;
975 SilcPacket packet = notify->packet;
976 SilcNotifyType type = silc_notify_get_type(payload);
977 SilcArgumentPayload args = silc_notify_get_args(payload);
978 SilcClientEntry client_entry = NULL, client_entry2 = NULL;
979 SilcChannelEntry channel = NULL, channel_entry = NULL;
980 SilcServerEntry server = NULL;
984 SilcUInt32 tmp_len, mode;
987 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
989 /* Get channel entry */
990 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
991 &id.u.channel_id, sizeof(id.u.channel_id)))
993 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
997 /* If channel is being resolved handle notify after resolving */
998 if (channel->internal.resolve_cmd_ident) {
999 silc_client_unref_channel(client, conn, channel);
1000 SILC_FSM_CALL(silc_client_command_pending(
1001 conn, SILC_COMMAND_NONE,
1002 channel->internal.resolve_cmd_ident,
1003 silc_client_notify_wait_continue,
1008 /* Get target Client ID */
1009 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id2, NULL))
1012 /* Find target Client entry */
1013 client_entry2 = silc_client_get_client_by_id(client, conn, &id2.u.client_id);
1014 if (!client_entry2 || !client_entry2->internal.valid) {
1015 /** Resolve client */
1016 silc_client_unref_client(client, conn, client_entry2);
1017 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1018 client, conn, &id2.u.client_id, NULL,
1019 silc_client_notify_resolved,
1024 /* If target client is not on channel, ignore this notify */
1025 if (!silc_client_on_channel(channel, client_entry2))
1029 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1032 SILC_GET32_MSB(mode, tmp);
1034 /* Get ID of mode changer */
1035 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1038 if (id.type == SILC_ID_CLIENT) {
1039 /* Find Client entry */
1040 client_entry = notify->client_entry;
1041 if (!client_entry) {
1042 client_entry = silc_client_get_client(client, conn, &id.u.client_id);
1043 if (!client_entry || !client_entry->internal.valid) {
1044 /** Resolve client */
1045 notify->channel = channel;
1046 notify->client_entry = client_entry;
1047 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1048 silc_client_get_client_by_id_resolve(
1049 client, conn, &id.u.client_id, NULL,
1050 silc_client_notify_resolved,
1056 /* If client is not on channel, ignore this notify */
1057 if (!silc_client_on_channel(channel, client_entry))
1060 entry = client_entry;
1061 } else if (id.type == SILC_ID_SERVER) {
1062 /* Find Server entry */
1063 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1065 /** Resolve server */
1066 notify->channel = channel;
1067 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1068 silc_client_get_server_by_id_resolve(
1069 client, conn, &id.u.server_id,
1070 silc_client_notify_resolved,
1076 /* Find Channel entry */
1077 channel_entry = silc_client_get_channel_by_id(client, conn,
1079 if (!channel_entry) {
1080 /** Resolve channel */
1081 notify->channel = channel;
1082 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1083 silc_client_get_channel_by_id_resolve(
1084 client, conn, &id.u.channel_id,
1085 silc_client_notify_resolved,
1089 entry = channel_entry;
1093 silc_rwlock_wrlock(channel->internal.lock);
1094 chu = silc_client_on_channel(channel, client_entry2);
1097 silc_rwlock_unlock(channel->internal.lock);
1099 /* Notify application. */
1100 NOTIFY(client, conn, type, id.type, entry, mode, client_entry2, channel);
1103 silc_client_unref_client(client, conn, client_entry2);
1105 silc_client_unref_client(client, conn, client_entry);
1107 silc_client_unref_server(client, conn, server);
1109 silc_client_unref_channel(client, conn, channel_entry);
1110 silc_client_unref_channel(client, conn, channel);
1112 /** Notify processed */
1113 silc_fsm_next(fsm, silc_client_notify_processed);
1114 return SILC_FSM_CONTINUE;
1117 /********************************* MOTD *************************************/
1119 /* Received Message of the day */
1121 SILC_FSM_STATE(silc_client_notify_motd)
1123 SilcClientConnection conn = fsm_context;
1124 SilcClient client = conn->client;
1125 SilcClientNotify notify = state_context;
1126 SilcNotifyPayload payload = notify->payload;
1127 SilcNotifyType type = silc_notify_get_type(payload);
1128 SilcArgumentPayload args = silc_notify_get_args(payload);
1132 SILC_LOG_DEBUG(("Notify: MOTD"));
1135 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1139 /* Notify application */
1140 NOTIFY(client, conn, type, tmp);
1143 /** Notify processed */
1144 silc_fsm_next(fsm, silc_client_notify_processed);
1145 return SILC_FSM_CONTINUE;
1148 /**************************** CHANNEL CHANGE ********************************/
1150 /* Router has enforced a new ID to a channel, change it */
1152 SILC_FSM_STATE(silc_client_notify_channel_change)
1154 SilcClientConnection conn = fsm_context;
1155 SilcClient client = conn->client;
1156 SilcClientNotify notify = state_context;
1157 SilcNotifyPayload payload = notify->payload;
1158 SilcNotifyType type = silc_notify_get_type(payload);
1159 SilcArgumentPayload args = silc_notify_get_args(payload);
1160 SilcChannelEntry channel = NULL;
1163 SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
1165 /* Get the old ID */
1166 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1169 /* Get the channel entry */
1170 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1174 /* If channel is being resolved handle notify after resolving */
1175 if (channel->internal.resolve_cmd_ident) {
1176 silc_client_unref_channel(client, conn, channel);
1177 SILC_FSM_CALL(silc_client_command_pending(
1178 conn, SILC_COMMAND_NONE,
1179 channel->internal.resolve_cmd_ident,
1180 silc_client_notify_wait_continue,
1185 /* Get the new ID */
1186 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
1189 /* Replace the Channel ID */
1190 if (!silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id))
1193 /* Notify application */
1194 NOTIFY(client, conn, type, channel, channel);
1197 /** Notify processed */
1198 silc_client_unref_channel(client, conn, channel);
1199 silc_fsm_next(fsm, silc_client_notify_processed);
1200 return SILC_FSM_CONTINUE;
1203 /******************************** KICKED ************************************/
1205 /* Some client was kicked from a channel */
1207 SILC_FSM_STATE(silc_client_notify_kicked)
1209 SilcClientConnection conn = fsm_context;
1210 SilcClient client = conn->client;
1211 SilcClientNotify notify = state_context;
1212 SilcNotifyPayload payload = notify->payload;
1213 SilcPacket packet = notify->packet;
1214 SilcNotifyType type = silc_notify_get_type(payload);
1215 SilcArgumentPayload args = silc_notify_get_args(payload);
1216 SilcClientEntry client_entry, client_entry2;
1217 SilcChannelEntry channel = NULL;
1222 SILC_LOG_DEBUG(("Notify: KICKED"));
1224 /* Get channel entry */
1225 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
1226 &id.u.channel_id, sizeof(id.u.channel_id)))
1228 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1232 /* If channel is being resolved handle notify after resolving */
1233 if (channel->internal.resolve_cmd_ident) {
1234 silc_client_unref_channel(client, conn, channel);
1235 SILC_FSM_CALL(silc_client_command_pending(
1236 conn, SILC_COMMAND_NONE,
1237 channel->internal.resolve_cmd_ident,
1238 silc_client_notify_wait_continue,
1243 /* Get the kicked Client ID */
1244 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1247 /* Find client entry */
1248 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1252 /* Get kicker's Client ID */
1253 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
1256 /* Find kicker's client entry and if not found resolve it */
1257 client_entry2 = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1258 if (!client_entry2 || !client_entry2->internal.valid) {
1259 /** Resolve client */
1260 silc_client_unref_client(client, conn, client_entry);
1261 silc_client_unref_client(client, conn, client_entry2);
1262 notify->channel = channel;
1263 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1264 silc_client_get_client_by_id_resolve(
1265 client, conn, &id.u.client_id, NULL,
1266 silc_client_notify_resolved,
1272 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1274 /* Remove kicked client from channel */
1275 if (client_entry != conn->local_entry) {
1276 if (!silc_client_remove_from_channel(client, conn, channel, client_entry))
1280 /* Notify application. */
1281 NOTIFY(client, conn, type, client_entry, tmp, client_entry2, channel);
1283 /* If I was kicked from channel, remove the channel */
1284 if (client_entry == conn->local_entry) {
1285 if (conn->current_channel == channel)
1286 conn->current_channel = NULL;
1287 silc_client_empty_channel(client, conn, channel);
1288 silc_client_del_channel(client, conn, channel);
1291 silc_client_unref_client(client, conn, client_entry);
1292 silc_client_unref_client(client, conn, client_entry2);
1295 /** Notify processed */
1296 silc_client_unref_channel(client, conn, channel);
1297 silc_fsm_next(fsm, silc_client_notify_processed);
1298 return SILC_FSM_CONTINUE;
1301 /******************************** KILLED ************************************/
1303 /* Some client was killed from the network */
1305 SILC_FSM_STATE(silc_client_notify_killed)
1307 SilcClientConnection conn = fsm_context;
1308 SilcClient client = conn->client;
1309 SilcClientNotify notify = state_context;
1310 SilcNotifyPayload payload = notify->payload;
1311 SilcNotifyType type = silc_notify_get_type(payload);
1312 SilcArgumentPayload args = silc_notify_get_args(payload);
1313 SilcClientEntry client_entry = NULL, client_entry2 = NULL;
1314 SilcChannelEntry channel_entry = NULL;
1315 SilcServerEntry server = NULL;
1318 SilcUInt32 comment_len;
1321 SILC_LOG_DEBUG(("Notify: KILLED"));
1324 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1327 /* Find Client entry */
1328 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1333 comment = silc_argument_get_arg_type(args, 2, &comment_len);
1335 /* Get killer's ID */
1336 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
1339 if (id.type == SILC_ID_CLIENT) {
1340 /* Find Client entry */
1341 client_entry2 = silc_client_get_client_by_id(client, conn,
1343 if (!client_entry2 || !client_entry2->internal.valid) {
1344 /** Resolve client */
1345 silc_client_unref_client(client, conn, client_entry);
1346 silc_client_unref_client(client, conn, client_entry2);
1347 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1348 client, conn, &id.u.client_id, NULL,
1349 silc_client_notify_resolved,
1353 entry = client_entry2;
1354 } else if (id.type == SILC_ID_SERVER) {
1355 /* Find Server entry */
1356 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1358 /** Resolve server */
1359 SILC_FSM_CALL(silc_client_get_server_by_id_resolve(
1360 client, conn, &id.u.server_id,
1361 silc_client_notify_resolved,
1367 /* Find Channel entry */
1368 channel_entry = silc_client_get_channel_by_id(client, conn,
1370 if (!channel_entry) {
1371 /** Resolve channel */
1372 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1373 client, conn, &id.u.channel_id,
1374 silc_client_notify_resolved,
1378 entry = channel_entry;
1381 /* Notify application. */
1382 NOTIFY(client, conn, type, client_entry, comment, id.type, entry);
1384 /* Delete the killed client */
1385 if (client_entry != conn->local_entry) {
1386 silc_client_remove_from_channels(client, conn, client_entry);
1387 client_entry->internal.valid = FALSE;
1388 silc_client_del_client(client, conn, client_entry);
1392 silc_client_unref_client(client, conn, client_entry);
1394 silc_client_unref_client(client, conn, client_entry2);
1396 silc_client_unref_server(client, conn, server);
1398 silc_client_unref_channel(client, conn, channel_entry);
1400 /** Notify processed */
1401 silc_fsm_next(fsm, silc_client_notify_processed);
1402 return SILC_FSM_CONTINUE;
1405 /**************************** SERVER SIGNOFF ********************************/
1407 /* Some server quit SILC network. Remove its clients from channels. */
1409 SILC_FSM_STATE(silc_client_notify_server_signoff)
1411 SilcClientConnection conn = fsm_context;
1412 SilcClient client = conn->client;
1413 SilcClientNotify notify = state_context;
1414 SilcNotifyPayload payload = notify->payload;
1415 SilcNotifyType type = silc_notify_get_type(payload);
1416 SilcArgumentPayload args = silc_notify_get_args(payload);
1417 SilcClientEntry client_entry;
1418 SilcServerEntry server_entry = NULL;
1423 SILC_LOG_DEBUG(("Notify: SERVER_SIGNOFF"));
1425 clients = silc_dlist_init();
1430 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1433 /* Get server, in case we have it cached */
1434 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1436 for (i = 1; i < silc_argument_get_arg_num(args); i++) {
1438 if (!silc_argument_get_decoded(args, i + 1, SILC_ARGUMENT_ID, &id, NULL))
1441 /* Get the client entry */
1442 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1443 if (client_entry && client_entry->internal.valid)
1444 silc_dlist_add(clients, client_entry);
1447 /* Notify application. */
1448 NOTIFY(client, conn, type, server_entry, clients);
1450 /* Delete the clients */
1451 silc_dlist_start(clients);
1452 while ((client_entry = silc_dlist_get(clients))) {
1453 silc_client_remove_from_channels(client, conn, client_entry);
1454 client_entry->internal.valid = FALSE;
1455 silc_client_del_client(client, conn, client_entry);
1459 /** Notify processed */
1460 silc_client_unref_server(client, conn, server_entry);
1461 silc_client_list_free(client, conn, clients);
1462 silc_fsm_next(fsm, silc_client_notify_processed);
1463 return SILC_FSM_CONTINUE;
1466 /******************************** ERROR *************************************/
1468 /* Some error occurred */
1470 SILC_FSM_STATE(silc_client_notify_error)
1472 SilcClientConnection conn = fsm_context;
1473 SilcClient client = conn->client;
1474 SilcClientNotify notify = state_context;
1475 SilcNotifyPayload payload = notify->payload;
1476 SilcNotifyType type = silc_notify_get_type(payload);
1477 SilcArgumentPayload args = silc_notify_get_args(payload);
1478 SilcClientEntry client_entry;
1485 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1486 if (!tmp && tmp_len != 1)
1488 error = (SilcStatus)tmp[0];
1490 SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1492 /* Handle the error */
1493 if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1494 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
1496 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1497 if (client_entry && client_entry != conn->local_entry) {
1498 silc_client_remove_from_channels(client, conn, client_entry);
1499 silc_client_del_client(client, conn, client_entry);
1500 silc_client_unref_client(client, conn, client_entry);
1504 /* Notify application. */
1505 NOTIFY(client, conn, type, error);
1508 /** Notify processed */
1509 silc_fsm_next(fsm, silc_client_notify_processed);
1510 return SILC_FSM_CONTINUE;
1513 /******************************** WATCH *************************************/
1515 /* Received notify about some client we are watching */
1517 SILC_FSM_STATE(silc_client_notify_watch)
1519 SilcClientConnection conn = fsm_context;
1520 SilcClient client = conn->client;
1521 SilcClientNotify notify = state_context;
1522 SilcNotifyPayload payload = notify->payload;
1523 SilcNotifyType type = silc_notify_get_type(payload);
1524 SilcArgumentPayload args = silc_notify_get_args(payload);
1525 SilcClientEntry client_entry = NULL;
1526 SilcNotifyType ntype = 0;
1527 unsigned char *pk, *tmp;
1528 SilcUInt32 mode, pk_len, tmp_len;
1529 SilcPublicKey public_key = NULL;
1532 SILC_LOG_DEBUG(("Notify: WATCH"));
1534 /* Get sender Client ID */
1535 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1538 /* Find client entry and if not found resolve it */
1539 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1540 if (!client_entry || !client_entry->internal.valid) {
1541 /** Resolve client */
1542 silc_client_unref_client(client, conn, client_entry);
1543 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1544 client, conn, &id.u.client_id, NULL,
1545 silc_client_notify_resolved,
1551 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1552 if (!tmp || tmp_len != 4)
1554 SILC_GET32_MSB(mode, tmp);
1556 /* Get notify type */
1557 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1558 if (tmp && tmp_len != 2)
1561 SILC_GET16_MSB(ntype, tmp);
1564 tmp = silc_argument_get_arg_type(args, 2, NULL);
1566 char *tmp_nick = NULL;
1568 silc_client_nickname_parse(client, conn, client_entry->nickname,
1571 /* If same nick, the client was new to us and has become "present"
1572 to network. Send NULL as nick to application. */
1573 if (tmp_nick && silc_utf8_strcasecmp(tmp, tmp_nick))
1576 silc_free(tmp_nick);
1579 /* Get public key, if present */
1580 pk = silc_argument_get_arg_type(args, 5, &pk_len);
1581 if (pk && !client_entry->public_key) {
1582 if (silc_public_key_payload_decode(pk, pk_len, &public_key)) {
1583 client_entry->public_key = public_key;
1588 /* Notify application. */
1589 NOTIFY(client, conn, type, client_entry, tmp, mode, ntype,
1590 client_entry->public_key);
1592 client_entry->mode = mode;
1594 /* Remove client that left the network. */
1595 if (ntype == SILC_NOTIFY_TYPE_SIGNOFF ||
1596 ntype == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
1597 ntype == SILC_NOTIFY_TYPE_KILLED) {
1598 silc_client_remove_from_channels(client, conn, client_entry);
1599 client_entry->internal.valid = FALSE;
1600 silc_client_del_client(client, conn, client_entry);
1604 silc_pkcs_public_key_free(public_key);
1607 /** Notify processed */
1608 silc_client_unref_client(client, conn, client_entry);
1609 silc_fsm_next(fsm, silc_client_notify_processed);
1610 return SILC_FSM_CONTINUE;