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 = NULL;
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 if (packet->dst_id_type == SILC_ID_CHANNEL)
528 if (silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
529 &id.u.channel_id, sizeof(id.u.channel_id)))
530 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
532 /* Notify application */
533 if (client_entry->internal.valid)
534 NOTIFY(client, conn, type, client_entry, tmp, channel);
536 /* Remove from channel */
538 silc_client_remove_from_channel(client, conn, channel, client_entry);
539 silc_client_unref_channel(client, conn, channel);
543 client_entry->internal.valid = FALSE;
544 silc_client_del_client(client, conn, client_entry);
545 silc_client_unref_client(client, conn, client_entry);
548 /** Notify processed */
549 silc_fsm_next(fsm, silc_client_notify_processed);
550 return SILC_FSM_CONTINUE;
553 /******************************** TOPIC_SET *********************************/
555 /* Someone set topic on a channel */
557 SILC_FSM_STATE(silc_client_notify_topic_set)
559 SilcClientConnection conn = fsm_context;
560 SilcClient client = conn->client;
561 SilcClientNotify notify = state_context;
562 SilcNotifyPayload payload = notify->payload;
563 SilcPacket packet = notify->packet;
564 SilcNotifyType type = silc_notify_get_type(payload);
565 SilcArgumentPayload args = silc_notify_get_args(payload);
566 SilcClientEntry client_entry = NULL;
567 SilcChannelEntry channel = NULL, channel_entry = NULL;
568 SilcServerEntry server = NULL;
574 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
576 /* Get channel entry */
577 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
578 &id.u.channel_id, sizeof(id.u.channel_id)))
580 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
584 /* If channel is being resolved handle notify after resolving */
585 if (channel->internal.resolve_cmd_ident) {
586 silc_client_unref_channel(client, conn, channel);
587 SILC_FSM_CALL(silc_client_command_pending(
588 conn, SILC_COMMAND_NONE,
589 channel->internal.resolve_cmd_ident,
590 silc_client_notify_wait_continue,
595 /* Get ID of topic changer */
596 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
600 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
604 if (id.type == SILC_ID_CLIENT) {
605 /* Find Client entry */
606 client_entry = notify->client_entry;
608 client_entry = silc_client_get_client(client, conn, &id.u.client_id);
609 if (!client_entry || !client_entry->internal.valid) {
610 /** Resolve client */
611 notify->channel = channel;
612 notify->client_entry = client_entry;
613 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
614 silc_client_get_client_by_id_resolve(
615 client, conn, &id.u.client_id, NULL,
616 silc_client_notify_resolved,
622 /* If client is not on channel, ignore this notify */
623 if (!silc_client_on_channel(channel, client_entry))
626 entry = client_entry;
627 } else if (id.type == SILC_ID_SERVER) {
628 /* Find Server entry */
629 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
631 /** Resolve server */
632 notify->channel = channel;
633 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
634 silc_client_get_server_by_id_resolve(
635 client, conn, &id.u.server_id,
636 silc_client_notify_resolved,
642 /* Find Channel entry */
643 channel_entry = silc_client_get_channel_by_id(client, conn,
645 if (!channel_entry) {
646 /** Resolve channel */
647 notify->channel = channel;
648 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
649 silc_client_get_channel_by_id_resolve(
650 client, conn, &id.u.channel_id,
651 silc_client_notify_resolved,
655 entry = channel_entry;
658 silc_rwlock_wrlock(channel->internal.lock);
659 silc_free(channel->topic);
660 channel->topic = silc_memdup(tmp, strlen(tmp));
661 silc_rwlock_unlock(channel->internal.lock);
663 /* Notify application. */
664 NOTIFY(client, conn, type, id.type, entry, channel->topic, channel);
667 silc_client_unref_client(client, conn, client_entry);
669 silc_client_unref_server(client, conn, server);
671 silc_client_unref_channel(client, conn, channel_entry);
674 /** Notify processed */
675 silc_client_unref_channel(client, conn, channel);
676 silc_fsm_next(fsm, silc_client_notify_processed);
677 return SILC_FSM_CONTINUE;
680 /****************************** NICK_CHANGE *********************************/
682 /* Someone changed their nickname on a channel */
684 SILC_FSM_STATE(silc_client_notify_nick_change)
686 SilcClientConnection conn = fsm_context;
687 SilcClient client = conn->client;
688 SilcClientNotify notify = state_context;
689 SilcNotifyPayload payload = notify->payload;
690 SilcNotifyType type = silc_notify_get_type(payload);
691 SilcArgumentPayload args = silc_notify_get_args(payload);
692 SilcClientEntry client_entry = NULL;
693 unsigned char *tmp, oldnick[256 + 1];
698 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
701 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
705 if (conn->local_id &&
706 SILC_ID_CLIENT_COMPARE(&id.u.client_id, conn->local_id))
709 /* Get new Client ID */
710 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id2, NULL))
714 if (conn->local_id &&
715 SILC_ID_CLIENT_COMPARE(&id2.u.client_id, conn->local_id))
718 /* Find old client entry. If we don't have the entry, we ignore this
720 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
723 valid = client_entry->internal.valid;
725 /* Take the new nickname */
726 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
730 silc_rwlock_wrlock(client_entry->internal.lock);
732 /* Check whether nickname changed at all. It is possible that nick
733 change notify is received but nickname didn't change, only the
734 ID changes. If Client ID hash match, nickname didn't change. */
735 if (SILC_ID_COMPARE_HASH(&client_entry->id, &id2.u.client_id) &&
736 silc_utf8_strcasecmp(tmp, client_entry->nickname)) {
737 /* Nickname didn't change. Update only Client ID. We don't notify
738 application because nickname didn't change. */
739 silc_mutex_lock(conn->internal->lock);
740 silc_idcache_update_by_context(conn->internal->client_cache, client_entry,
741 &id2.u.client_id, NULL, FALSE);
742 silc_mutex_unlock(conn->internal->lock);
743 silc_rwlock_unlock(client_entry->internal.lock);
747 /* Change the nickname */
748 memcpy(oldnick, client_entry->nickname, sizeof(client_entry->nickname));
749 if (!silc_client_change_nickname(client, conn, client_entry, tmp,
750 &id2.u.client_id, NULL, 0)) {
751 silc_rwlock_unlock(client_entry->internal.lock);
755 silc_rwlock_unlock(client_entry->internal.lock);
757 /* Notify application, if client entry is valid. We do not send nick change
758 notify for entries that were invalid (application doesn't know them). */
760 NOTIFY(client, conn, type, client_entry, oldnick, client_entry->nickname);
763 /** Notify processed */
764 silc_client_unref_client(client, conn, client_entry);
765 silc_fsm_next(fsm, silc_client_notify_processed);
766 return SILC_FSM_CONTINUE;
769 /****************************** CMODE_CHANGE ********************************/
771 /* Someone changed channel mode */
773 SILC_FSM_STATE(silc_client_notify_cmode_change)
775 SilcClientConnection conn = fsm_context;
776 SilcClient client = conn->client;
777 SilcClientNotify notify = state_context;
778 SilcNotifyPayload payload = notify->payload;
779 SilcPacket packet = notify->packet;
780 SilcNotifyType type = silc_notify_get_type(payload);
781 SilcArgumentPayload args = silc_notify_get_args(payload);
782 SilcClientEntry client_entry = NULL;
783 SilcChannelEntry channel = NULL, channel_entry = NULL;
784 SilcServerEntry server = NULL;
787 SilcUInt32 tmp_len, mode;
789 char *passphrase, *cipher, *hmac;
790 SilcPublicKey founder_key = NULL;
791 SilcDList chpks = NULL;
793 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
795 /* Get channel entry */
796 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
797 &id.u.channel_id, sizeof(id.u.channel_id)))
799 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
803 /* If channel is being resolved handle notify after resolving */
804 if (channel->internal.resolve_cmd_ident) {
805 silc_client_unref_channel(client, conn, channel);
806 SILC_FSM_CALL(silc_client_command_pending(
807 conn, SILC_COMMAND_NONE,
808 channel->internal.resolve_cmd_ident,
809 silc_client_notify_wait_continue,
815 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
818 SILC_GET32_MSB(mode, tmp);
820 /* Get ID of who changed the mode */
821 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
824 if (id.type == SILC_ID_CLIENT) {
825 /* Find Client entry */
826 client_entry = notify->client_entry;
828 client_entry = silc_client_get_client(client, conn, &id.u.client_id);
829 if (!client_entry || !client_entry->internal.valid) {
830 /** Resolve client */
831 notify->channel = channel;
832 notify->client_entry = client_entry;
833 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
834 silc_client_get_client_by_id_resolve(
835 client, conn, &id.u.client_id, NULL,
836 silc_client_notify_resolved,
842 /* If client is not on channel, ignore this notify */
843 if (!silc_client_on_channel(channel, client_entry))
846 entry = client_entry;
847 } else if (id.type == SILC_ID_SERVER) {
848 /* Find Server entry */
849 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
851 /** Resolve server */
852 notify->channel = channel;
853 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
854 silc_client_get_server_by_id_resolve(
855 client, conn, &id.u.server_id,
856 silc_client_notify_resolved,
862 /* Find Channel entry */
863 channel_entry = silc_client_get_channel_by_id(client, conn,
865 if (!channel_entry) {
866 /** Resolve channel */
867 notify->channel = channel;
868 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
869 silc_client_get_channel_by_id_resolve(
870 client, conn, &id.u.channel_id,
871 silc_client_notify_resolved,
875 entry = channel_entry;
878 silc_rwlock_wrlock(channel->internal.lock);
880 /* Get the channel founder key if it was set */
881 tmp = silc_argument_get_arg_type(args, 6, &tmp_len);
883 if (!silc_public_key_payload_decode(tmp, tmp_len, &founder_key)) {
884 silc_rwlock_unlock(channel->internal.lock);
887 if (!channel->founder_key) {
888 channel->founder_key = founder_key;
894 cipher = silc_argument_get_arg_type(args, 3, &tmp_len);
897 hmac = silc_argument_get_arg_type(args, 4, &tmp_len);
899 unsigned char hash[SILC_HASH_MAXLEN];
902 if (!silc_hmac_alloc(hmac, NULL, &newhmac)) {
903 silc_rwlock_unlock(channel->internal.lock);
907 /* Get HMAC key from the old HMAC context, and update it to the new one */
908 tmp = (unsigned char *)silc_hmac_get_key(channel->internal.hmac, &tmp_len);
910 silc_hash_make(silc_hmac_get_hash(newhmac), tmp, tmp_len, hash);
911 silc_hmac_set_key(newhmac, hash,
912 silc_hash_len(silc_hmac_get_hash(newhmac)));
913 if (channel->internal.hmac)
914 silc_hmac_free(channel->internal.hmac);
915 channel->internal.hmac = newhmac;
916 memset(hash, 0, sizeof(hash));
920 /* Get the passphrase if it was set */
921 passphrase = silc_argument_get_arg_type(args, 5, &tmp_len);
924 tmp = silc_argument_get_arg_type(args, 8, &tmp_len);
925 if (tmp && tmp_len == 4)
926 SILC_GET32_MSB(channel->user_limit, tmp);
927 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
928 channel->user_limit = 0;
930 /* Get the channel public key that was added or removed */
931 tmp = silc_argument_get_arg_type(args, 7, &tmp_len);
933 silc_client_channel_save_public_keys(channel, tmp, tmp_len, FALSE);
934 else if (channel->mode & SILC_CHANNEL_MODE_CHANNEL_AUTH)
935 silc_client_channel_save_public_keys(channel, NULL, 0, TRUE);
937 /* Save the new mode */
938 channel->mode = mode;
940 silc_rwlock_unlock(channel->internal.lock);
942 /* Notify application. */
943 NOTIFY(client, conn, type, id.type, entry, mode, cipher, hmac,
944 passphrase, channel->founder_key, chpks, channel);
948 silc_pkcs_public_key_free(founder_key);
950 silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
952 silc_client_unref_client(client, conn, client_entry);
954 silc_client_unref_server(client, conn, server);
956 silc_client_unref_channel(client, conn, channel_entry);
957 silc_client_unref_channel(client, conn, channel);
959 /** Notify processed */
960 silc_fsm_next(fsm, silc_client_notify_processed);
961 return SILC_FSM_CONTINUE;
964 /***************************** CUMODE_CHANGE ********************************/
966 /* Someone changed a user's mode on a channel */
968 SILC_FSM_STATE(silc_client_notify_cumode_change)
970 SilcClientConnection conn = fsm_context;
971 SilcClient client = conn->client;
972 SilcClientNotify notify = state_context;
973 SilcNotifyPayload payload = notify->payload;
974 SilcPacket packet = notify->packet;
975 SilcNotifyType type = silc_notify_get_type(payload);
976 SilcArgumentPayload args = silc_notify_get_args(payload);
977 SilcClientEntry client_entry = NULL, client_entry2 = NULL;
978 SilcChannelEntry channel = NULL, channel_entry = NULL;
979 SilcServerEntry server = NULL;
983 SilcUInt32 tmp_len, mode;
986 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
988 /* Get channel entry */
989 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
990 &id.u.channel_id, sizeof(id.u.channel_id)))
992 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
996 /* If channel is being resolved handle notify after resolving */
997 if (channel->internal.resolve_cmd_ident) {
998 silc_client_unref_channel(client, conn, channel);
999 SILC_FSM_CALL(silc_client_command_pending(
1000 conn, SILC_COMMAND_NONE,
1001 channel->internal.resolve_cmd_ident,
1002 silc_client_notify_wait_continue,
1007 /* Get target Client ID */
1008 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id2, NULL))
1011 /* Find target Client entry */
1012 client_entry2 = silc_client_get_client_by_id(client, conn, &id2.u.client_id);
1013 if (!client_entry2 || !client_entry2->internal.valid) {
1014 /** Resolve client */
1015 silc_client_unref_client(client, conn, client_entry2);
1016 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1017 client, conn, &id2.u.client_id, NULL,
1018 silc_client_notify_resolved,
1023 /* If target client is not on channel, ignore this notify */
1024 if (!silc_client_on_channel(channel, client_entry2))
1028 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1031 SILC_GET32_MSB(mode, tmp);
1033 /* Get ID of mode changer */
1034 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1037 if (id.type == SILC_ID_CLIENT) {
1038 /* Find Client entry */
1039 client_entry = notify->client_entry;
1040 if (!client_entry) {
1041 client_entry = silc_client_get_client(client, conn, &id.u.client_id);
1042 if (!client_entry || !client_entry->internal.valid) {
1043 /** Resolve client */
1044 notify->channel = channel;
1045 notify->client_entry = client_entry;
1046 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1047 silc_client_get_client_by_id_resolve(
1048 client, conn, &id.u.client_id, NULL,
1049 silc_client_notify_resolved,
1055 /* If client is not on channel, ignore this notify */
1056 if (!silc_client_on_channel(channel, client_entry))
1059 entry = client_entry;
1060 } else if (id.type == SILC_ID_SERVER) {
1061 /* Find Server entry */
1062 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1064 /** Resolve server */
1065 notify->channel = channel;
1066 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1067 silc_client_get_server_by_id_resolve(
1068 client, conn, &id.u.server_id,
1069 silc_client_notify_resolved,
1075 /* Find Channel entry */
1076 channel_entry = silc_client_get_channel_by_id(client, conn,
1078 if (!channel_entry) {
1079 /** Resolve channel */
1080 notify->channel = channel;
1081 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1082 silc_client_get_channel_by_id_resolve(
1083 client, conn, &id.u.channel_id,
1084 silc_client_notify_resolved,
1088 entry = channel_entry;
1092 silc_rwlock_wrlock(channel->internal.lock);
1093 chu = silc_client_on_channel(channel, client_entry2);
1096 silc_rwlock_unlock(channel->internal.lock);
1098 /* Notify application. */
1099 NOTIFY(client, conn, type, id.type, entry, mode, client_entry2, channel);
1102 silc_client_unref_client(client, conn, client_entry2);
1104 silc_client_unref_client(client, conn, client_entry);
1106 silc_client_unref_server(client, conn, server);
1108 silc_client_unref_channel(client, conn, channel_entry);
1109 silc_client_unref_channel(client, conn, channel);
1111 /** Notify processed */
1112 silc_fsm_next(fsm, silc_client_notify_processed);
1113 return SILC_FSM_CONTINUE;
1116 /********************************* MOTD *************************************/
1118 /* Received Message of the day */
1120 SILC_FSM_STATE(silc_client_notify_motd)
1122 SilcClientConnection conn = fsm_context;
1123 SilcClient client = conn->client;
1124 SilcClientNotify notify = state_context;
1125 SilcNotifyPayload payload = notify->payload;
1126 SilcNotifyType type = silc_notify_get_type(payload);
1127 SilcArgumentPayload args = silc_notify_get_args(payload);
1131 SILC_LOG_DEBUG(("Notify: MOTD"));
1134 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1138 /* Notify application */
1139 NOTIFY(client, conn, type, tmp);
1142 /** Notify processed */
1143 silc_fsm_next(fsm, silc_client_notify_processed);
1144 return SILC_FSM_CONTINUE;
1147 /**************************** CHANNEL CHANGE ********************************/
1149 /* Router has enforced a new ID to a channel, change it */
1151 SILC_FSM_STATE(silc_client_notify_channel_change)
1153 SilcClientConnection conn = fsm_context;
1154 SilcClient client = conn->client;
1155 SilcClientNotify notify = state_context;
1156 SilcNotifyPayload payload = notify->payload;
1157 SilcNotifyType type = silc_notify_get_type(payload);
1158 SilcArgumentPayload args = silc_notify_get_args(payload);
1159 SilcChannelEntry channel = NULL;
1162 SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
1164 /* Get the old ID */
1165 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1168 /* Get the channel entry */
1169 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1173 /* If channel is being resolved handle notify after resolving */
1174 if (channel->internal.resolve_cmd_ident) {
1175 silc_client_unref_channel(client, conn, channel);
1176 SILC_FSM_CALL(silc_client_command_pending(
1177 conn, SILC_COMMAND_NONE,
1178 channel->internal.resolve_cmd_ident,
1179 silc_client_notify_wait_continue,
1184 /* Get the new ID */
1185 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
1188 /* Replace the Channel ID */
1189 if (!silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id))
1192 /* Notify application */
1193 NOTIFY(client, conn, type, channel, channel);
1196 /** Notify processed */
1197 silc_client_unref_channel(client, conn, channel);
1198 silc_fsm_next(fsm, silc_client_notify_processed);
1199 return SILC_FSM_CONTINUE;
1202 /******************************** KICKED ************************************/
1204 /* Some client was kicked from a channel */
1206 SILC_FSM_STATE(silc_client_notify_kicked)
1208 SilcClientConnection conn = fsm_context;
1209 SilcClient client = conn->client;
1210 SilcClientNotify notify = state_context;
1211 SilcNotifyPayload payload = notify->payload;
1212 SilcPacket packet = notify->packet;
1213 SilcNotifyType type = silc_notify_get_type(payload);
1214 SilcArgumentPayload args = silc_notify_get_args(payload);
1215 SilcClientEntry client_entry, client_entry2;
1216 SilcChannelEntry channel = NULL;
1221 SILC_LOG_DEBUG(("Notify: KICKED"));
1223 /* Get channel entry */
1224 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
1225 &id.u.channel_id, sizeof(id.u.channel_id)))
1227 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1231 /* If channel is being resolved handle notify after resolving */
1232 if (channel->internal.resolve_cmd_ident) {
1233 silc_client_unref_channel(client, conn, channel);
1234 SILC_FSM_CALL(silc_client_command_pending(
1235 conn, SILC_COMMAND_NONE,
1236 channel->internal.resolve_cmd_ident,
1237 silc_client_notify_wait_continue,
1242 /* Get the kicked Client ID */
1243 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1246 /* Find client entry */
1247 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1251 /* Get kicker's Client ID */
1252 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
1255 /* Find kicker's client entry and if not found resolve it */
1256 client_entry2 = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1257 if (!client_entry2 || !client_entry2->internal.valid) {
1258 /** Resolve client */
1259 silc_client_unref_client(client, conn, client_entry);
1260 silc_client_unref_client(client, conn, client_entry2);
1261 notify->channel = channel;
1262 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1263 silc_client_get_client_by_id_resolve(
1264 client, conn, &id.u.client_id, NULL,
1265 silc_client_notify_resolved,
1271 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1273 /* Remove kicked client from channel */
1274 if (client_entry != conn->local_entry) {
1275 if (!silc_client_remove_from_channel(client, conn, channel, client_entry))
1279 /* Notify application. */
1280 NOTIFY(client, conn, type, client_entry, tmp, client_entry2, channel);
1282 /* If I was kicked from channel, remove the channel */
1283 if (client_entry == conn->local_entry) {
1284 if (conn->current_channel == channel)
1285 conn->current_channel = NULL;
1286 silc_client_empty_channel(client, conn, channel);
1287 silc_client_del_channel(client, conn, channel);
1290 silc_client_unref_client(client, conn, client_entry);
1291 silc_client_unref_client(client, conn, client_entry2);
1294 /** Notify processed */
1295 silc_client_unref_channel(client, conn, channel);
1296 silc_fsm_next(fsm, silc_client_notify_processed);
1297 return SILC_FSM_CONTINUE;
1300 /******************************** KILLED ************************************/
1302 /* Some client was killed from the network */
1304 SILC_FSM_STATE(silc_client_notify_killed)
1306 SilcClientConnection conn = fsm_context;
1307 SilcClient client = conn->client;
1308 SilcClientNotify notify = state_context;
1309 SilcNotifyPayload payload = notify->payload;
1310 SilcNotifyType type = silc_notify_get_type(payload);
1311 SilcArgumentPayload args = silc_notify_get_args(payload);
1312 SilcClientEntry client_entry = NULL, client_entry2 = NULL;
1313 SilcChannelEntry channel_entry = NULL;
1314 SilcServerEntry server = NULL;
1317 SilcUInt32 comment_len;
1320 SILC_LOG_DEBUG(("Notify: KILLED"));
1323 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1326 /* Find Client entry */
1327 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1332 comment = silc_argument_get_arg_type(args, 2, &comment_len);
1334 /* Get killer's ID */
1335 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
1338 if (id.type == SILC_ID_CLIENT) {
1339 /* Find Client entry */
1340 client_entry2 = silc_client_get_client_by_id(client, conn,
1342 if (!client_entry2 || !client_entry2->internal.valid) {
1343 /** Resolve client */
1344 silc_client_unref_client(client, conn, client_entry);
1345 silc_client_unref_client(client, conn, client_entry2);
1346 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1347 client, conn, &id.u.client_id, NULL,
1348 silc_client_notify_resolved,
1352 entry = client_entry2;
1353 } else if (id.type == SILC_ID_SERVER) {
1354 /* Find Server entry */
1355 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1357 /** Resolve server */
1358 SILC_FSM_CALL(silc_client_get_server_by_id_resolve(
1359 client, conn, &id.u.server_id,
1360 silc_client_notify_resolved,
1366 /* Find Channel entry */
1367 channel_entry = silc_client_get_channel_by_id(client, conn,
1369 if (!channel_entry) {
1370 /** Resolve channel */
1371 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1372 client, conn, &id.u.channel_id,
1373 silc_client_notify_resolved,
1377 entry = channel_entry;
1380 /* Notify application. */
1381 NOTIFY(client, conn, type, client_entry, comment, id.type, entry);
1383 /* Delete the killed client */
1384 if (client_entry != conn->local_entry) {
1385 silc_client_remove_from_channels(client, conn, client_entry);
1386 client_entry->internal.valid = FALSE;
1387 silc_client_del_client(client, conn, client_entry);
1391 silc_client_unref_client(client, conn, client_entry);
1393 silc_client_unref_client(client, conn, client_entry2);
1395 silc_client_unref_server(client, conn, server);
1397 silc_client_unref_channel(client, conn, channel_entry);
1399 /** Notify processed */
1400 silc_fsm_next(fsm, silc_client_notify_processed);
1401 return SILC_FSM_CONTINUE;
1404 /**************************** SERVER SIGNOFF ********************************/
1406 /* Some server quit SILC network. Remove its clients from channels. */
1408 SILC_FSM_STATE(silc_client_notify_server_signoff)
1410 SilcClientConnection conn = fsm_context;
1411 SilcClient client = conn->client;
1412 SilcClientNotify notify = state_context;
1413 SilcNotifyPayload payload = notify->payload;
1414 SilcNotifyType type = silc_notify_get_type(payload);
1415 SilcArgumentPayload args = silc_notify_get_args(payload);
1416 SilcClientEntry client_entry;
1417 SilcServerEntry server_entry = NULL;
1422 SILC_LOG_DEBUG(("Notify: SERVER_SIGNOFF"));
1424 clients = silc_dlist_init();
1429 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1432 /* Get server, in case we have it cached */
1433 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1435 for (i = 1; i < silc_argument_get_arg_num(args); i++) {
1437 if (!silc_argument_get_decoded(args, i + 1, SILC_ARGUMENT_ID, &id, NULL))
1440 /* Get the client entry */
1441 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1442 if (client_entry && client_entry->internal.valid)
1443 silc_dlist_add(clients, client_entry);
1446 /* Notify application. */
1447 NOTIFY(client, conn, type, server_entry, clients);
1449 /* Delete the clients */
1450 silc_dlist_start(clients);
1451 while ((client_entry = silc_dlist_get(clients))) {
1452 silc_client_remove_from_channels(client, conn, client_entry);
1453 client_entry->internal.valid = FALSE;
1454 silc_client_del_client(client, conn, client_entry);
1458 /** Notify processed */
1459 silc_client_unref_server(client, conn, server_entry);
1460 silc_client_list_free(client, conn, clients);
1461 silc_fsm_next(fsm, silc_client_notify_processed);
1462 return SILC_FSM_CONTINUE;
1465 /******************************** ERROR *************************************/
1467 /* Some error occurred */
1469 SILC_FSM_STATE(silc_client_notify_error)
1471 SilcClientConnection conn = fsm_context;
1472 SilcClient client = conn->client;
1473 SilcClientNotify notify = state_context;
1474 SilcNotifyPayload payload = notify->payload;
1475 SilcNotifyType type = silc_notify_get_type(payload);
1476 SilcArgumentPayload args = silc_notify_get_args(payload);
1477 SilcClientEntry client_entry;
1484 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1485 if (!tmp && tmp_len != 1)
1487 error = (SilcStatus)tmp[0];
1489 SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1491 /* Handle the error */
1492 if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1493 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
1495 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1496 if (client_entry && client_entry != conn->local_entry) {
1497 silc_client_remove_from_channels(client, conn, client_entry);
1498 silc_client_del_client(client, conn, client_entry);
1499 silc_client_unref_client(client, conn, client_entry);
1503 /* Notify application. */
1504 NOTIFY(client, conn, type, error);
1507 /** Notify processed */
1508 silc_fsm_next(fsm, silc_client_notify_processed);
1509 return SILC_FSM_CONTINUE;
1512 /******************************** WATCH *************************************/
1514 /* Received notify about some client we are watching */
1516 SILC_FSM_STATE(silc_client_notify_watch)
1518 SilcClientConnection conn = fsm_context;
1519 SilcClient client = conn->client;
1520 SilcClientNotify notify = state_context;
1521 SilcNotifyPayload payload = notify->payload;
1522 SilcNotifyType type = silc_notify_get_type(payload);
1523 SilcArgumentPayload args = silc_notify_get_args(payload);
1524 SilcClientEntry client_entry = NULL;
1525 SilcNotifyType ntype = 0;
1526 unsigned char *pk, *tmp;
1527 SilcUInt32 mode, pk_len, tmp_len;
1528 SilcPublicKey public_key = NULL;
1531 SILC_LOG_DEBUG(("Notify: WATCH"));
1533 /* Get sender Client ID */
1534 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1537 /* Find client entry and if not found resolve it */
1538 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1539 if (!client_entry || !client_entry->internal.valid) {
1540 /** Resolve client */
1541 silc_client_unref_client(client, conn, client_entry);
1542 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1543 client, conn, &id.u.client_id, NULL,
1544 silc_client_notify_resolved,
1550 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1551 if (!tmp || tmp_len != 4)
1553 SILC_GET32_MSB(mode, tmp);
1555 /* Get notify type */
1556 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1557 if (tmp && tmp_len != 2)
1560 SILC_GET16_MSB(ntype, tmp);
1563 tmp = silc_argument_get_arg_type(args, 2, NULL);
1565 char *tmp_nick = NULL;
1567 silc_client_nickname_parse(client, conn, client_entry->nickname,
1570 /* If same nick, the client was new to us and has become "present"
1571 to network. Send NULL as nick to application. */
1572 if (tmp_nick && silc_utf8_strcasecmp(tmp, tmp_nick))
1575 silc_free(tmp_nick);
1578 /* Get public key, if present */
1579 pk = silc_argument_get_arg_type(args, 5, &pk_len);
1580 if (pk && !client_entry->public_key) {
1581 if (silc_public_key_payload_decode(pk, pk_len, &public_key)) {
1582 client_entry->public_key = public_key;
1587 /* Notify application. */
1588 NOTIFY(client, conn, type, client_entry, tmp, mode, ntype,
1589 client_entry->public_key);
1591 client_entry->mode = mode;
1593 /* Remove client that left the network. */
1594 if (ntype == SILC_NOTIFY_TYPE_SIGNOFF ||
1595 ntype == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
1596 ntype == SILC_NOTIFY_TYPE_KILLED) {
1597 silc_client_remove_from_channels(client, conn, client_entry);
1598 client_entry->internal.valid = FALSE;
1599 silc_client_del_client(client, conn, client_entry);
1603 silc_pkcs_public_key_free(public_key);
1606 /** Notify processed */
1607 silc_client_unref_client(client, conn, client_entry);
1608 silc_fsm_next(fsm, silc_client_notify_processed);
1609 return SILC_FSM_CONTINUE;