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);
62 /* Unref client only in case of non-timeout error. In case of timeout
63 occurred, the routine reprocessing the notify is expected not to
64 create new references of the entry. */
65 silc_client_unref_client(client, conn, notify->client_entry);
69 /* If no entries found, just finish the notify processing */
70 if (!entries && !notify->client_entry)
71 silc_fsm_next(notify->fsm, silc_client_notify_processed);
73 if (notify->channel) {
74 notify->channel->internal.resolve_cmd_ident = 0;
75 silc_client_unref_channel(client, conn, notify->channel);
78 /* Continue processing the notify */
79 SILC_FSM_CALL_CONTINUE_SYNC(notify->fsm);
82 /* Continue notify processing after it was suspended while waiting for
83 channel information being resolved. */
85 static SilcBool silc_client_notify_wait_continue(SilcClient client,
86 SilcClientConnection conn,
93 SilcClientNotify notify = context;
95 /* Continue after last command reply received */
96 if (SILC_STATUS_IS_ERROR(status) || status == SILC_STATUS_OK ||
97 status == SILC_STATUS_LIST_END)
98 SILC_FSM_CALL_CONTINUE_SYNC(notify->fsm);
103 /********************************* Notify ***********************************/
105 /* Process received notify packet */
107 SILC_FSM_STATE(silc_client_notify)
109 SilcPacket packet = state_context;
110 SilcClientNotify notify;
111 SilcNotifyPayload payload;
113 payload = silc_notify_payload_parse(silc_buffer_data(&packet->buffer),
114 silc_buffer_len(&packet->buffer));
116 SILC_LOG_DEBUG(("Malformed notify payload"));
117 silc_packet_free(packet);
118 return SILC_FSM_FINISH;
121 if (!silc_notify_get_args(payload)) {
122 SILC_LOG_DEBUG(("Malformed notify %d", silc_notify_get_type(payload)));
123 silc_notify_payload_free(payload);
124 silc_packet_free(packet);
125 return SILC_FSM_FINISH;
128 notify = silc_calloc(1, sizeof(*notify));
130 silc_notify_payload_free(payload);
131 silc_packet_free(packet);
132 return SILC_FSM_FINISH;
135 notify->packet = packet;
136 notify->payload = payload;
138 silc_fsm_set_state_context(fsm, notify);
140 /* Process the notify */
141 switch (silc_notify_get_type(payload)) {
143 case SILC_NOTIFY_TYPE_NONE:
145 silc_fsm_next(fsm, silc_client_notify_none);
148 case SILC_NOTIFY_TYPE_INVITE:
150 silc_fsm_next(fsm, silc_client_notify_invite);
153 case SILC_NOTIFY_TYPE_JOIN:
155 silc_fsm_next(fsm, silc_client_notify_join);
158 case SILC_NOTIFY_TYPE_LEAVE:
160 silc_fsm_next(fsm, silc_client_notify_leave);
163 case SILC_NOTIFY_TYPE_SIGNOFF:
165 silc_fsm_next(fsm, silc_client_notify_signoff);
168 case SILC_NOTIFY_TYPE_TOPIC_SET:
170 silc_fsm_next(fsm, silc_client_notify_topic_set);
173 case SILC_NOTIFY_TYPE_NICK_CHANGE:
175 silc_fsm_next(fsm, silc_client_notify_nick_change);
178 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
180 silc_fsm_next(fsm, silc_client_notify_cmode_change);
183 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
185 silc_fsm_next(fsm, silc_client_notify_cumode_change);
188 case SILC_NOTIFY_TYPE_MOTD:
190 silc_fsm_next(fsm, silc_client_notify_motd);
193 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
194 /** CHANNEL_CHANGE */
195 silc_fsm_next(fsm, silc_client_notify_channel_change);
198 case SILC_NOTIFY_TYPE_KICKED:
200 silc_fsm_next(fsm, silc_client_notify_kicked);
203 case SILC_NOTIFY_TYPE_KILLED:
205 silc_fsm_next(fsm, silc_client_notify_killed);
208 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
209 /** SERVER_SIGNOFF */
210 silc_fsm_next(fsm, silc_client_notify_server_signoff);
213 case SILC_NOTIFY_TYPE_ERROR:
215 silc_fsm_next(fsm, silc_client_notify_error);
218 case SILC_NOTIFY_TYPE_WATCH:
220 silc_fsm_next(fsm, silc_client_notify_watch);
224 /** Unknown notify */
225 silc_notify_payload_free(payload);
226 silc_packet_free(packet);
228 return SILC_FSM_FINISH;
232 return SILC_FSM_CONTINUE;
235 /* Notify processed, finish the packet processing thread */
237 SILC_FSM_STATE(silc_client_notify_processed)
239 SilcClientNotify notify = state_context;
240 SilcPacket packet = notify->packet;
241 SilcNotifyPayload payload = notify->payload;
243 silc_notify_payload_free(payload);
244 silc_packet_free(packet);
246 return SILC_FSM_FINISH;
249 /********************************** NONE ************************************/
251 SILC_FSM_STATE(silc_client_notify_none)
253 SilcClientConnection conn = fsm_context;
254 SilcClient client = conn->client;
255 SilcClientNotify notify = state_context;
256 SilcNotifyPayload payload = notify->payload;
257 SilcNotifyType type = silc_notify_get_type(payload);
258 SilcArgumentPayload args = silc_notify_get_args(payload);
260 SILC_LOG_DEBUG(("Notify: NONE"));
262 /* Notify application */
263 NOTIFY(client, conn, type, silc_argument_get_arg_type(args, 1, NULL));
265 /** Notify processed */
266 silc_fsm_next(fsm, silc_client_notify_processed);
267 return SILC_FSM_CONTINUE;
270 /********************************* INVITE ***********************************/
272 /* Someone invite me to a channel */
274 SILC_FSM_STATE(silc_client_notify_invite)
276 SilcClientConnection conn = fsm_context;
277 SilcClient client = conn->client;
278 SilcClientNotify notify = state_context;
279 SilcNotifyPayload payload = notify->payload;
280 SilcNotifyType type = silc_notify_get_type(payload);
281 SilcArgumentPayload args = silc_notify_get_args(payload);
282 SilcClientEntry client_entry;
283 SilcChannelEntry channel = NULL;
288 SILC_LOG_DEBUG(("Notify: INVITE"));
291 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
294 /* Get the channel name */
295 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
299 /* Get the channel entry */
300 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
304 /* If channel is being resolved handle notify after resolving */
305 if (channel->internal.resolve_cmd_ident) {
306 silc_client_unref_channel(client, conn, channel);
307 SILC_FSM_CALL(silc_client_command_pending(
308 conn, SILC_COMMAND_NONE,
309 channel->internal.resolve_cmd_ident,
310 silc_client_notify_wait_continue,
315 /* Get sender Client ID */
316 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
319 /* Find Client entry and if not found query it */
320 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
321 if (!client_entry || !client_entry->internal.valid) {
322 /** Resolve client */
323 silc_client_unref_client(client, conn, client_entry);
324 notify->channel = channel;
325 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
326 silc_client_get_client_by_id_resolve(
327 client, conn, &id.u.client_id, NULL,
328 silc_client_notify_resolved,
333 /* Notify application */
334 NOTIFY(client, conn, type, channel, tmp, client_entry);
336 silc_client_unref_client(client, conn, client_entry);
339 /** Notify processed */
340 silc_client_unref_channel(client, conn, channel);
341 silc_fsm_next(fsm, silc_client_notify_processed);
342 return SILC_FSM_CONTINUE;
345 /********************************** JOIN ************************************/
347 /* Someone joined a channel */
349 SILC_FSM_STATE(silc_client_notify_join)
351 SilcClientConnection conn = fsm_context;
352 SilcClient client = conn->client;
353 SilcClientNotify notify = state_context;
354 SilcNotifyPayload payload = notify->payload;
355 SilcNotifyType type = silc_notify_get_type(payload);
356 SilcArgumentPayload args = silc_notify_get_args(payload);
357 SilcClientEntry client_entry;
358 SilcChannelEntry channel = NULL;
361 SILC_LOG_DEBUG(("Notify: JOIN"));
364 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
367 /* Get channel entry */
368 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
372 /* If channel is being resolved handle notify after resolving */
373 if (channel->internal.resolve_cmd_ident) {
374 silc_client_unref_channel(client, conn, channel);
375 SILC_FSM_CALL(silc_client_command_pending(
376 conn, SILC_COMMAND_NONE,
377 channel->internal.resolve_cmd_ident,
378 silc_client_notify_wait_continue,
384 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
387 /* Find client entry and if not found query it. If we just queried it
388 don't do it again, unless some data (like username) is missing. */
389 client_entry = notify->client_entry;
391 client_entry = silc_client_get_client(client, conn, &id.u.client_id);
392 if (!client_entry || !client_entry->internal.valid ||
393 !client_entry->username[0]) {
394 /** Resolve client */
395 notify->channel = channel;
396 notify->client_entry = client_entry;
397 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
398 silc_client_get_client_by_id_resolve(
399 client, conn, client_entry ?
400 &client_entry->id : &id.u.client_id,
401 NULL, silc_client_notify_resolved,
406 silc_rwlock_wrlock(client_entry->internal.lock);
407 silc_rwlock_wrlock(channel->internal.lock);
409 if (client_entry != conn->local_entry)
410 silc_client_nickname_format(client, conn, client_entry, FALSE);
412 /* Join the client to channel */
413 if (!silc_client_add_to_channel(client, conn, channel, client_entry, 0)) {
414 silc_rwlock_unlock(channel->internal.lock);
415 silc_rwlock_unlock(client_entry->internal.lock);
419 silc_rwlock_unlock(channel->internal.lock);
420 silc_rwlock_unlock(client_entry->internal.lock);
422 /* Notify application. */
423 NOTIFY(client, conn, type, client_entry, channel);
425 silc_client_unref_client(client, conn, client_entry);
428 /** Notify processed */
429 silc_client_unref_channel(client, conn, channel);
430 silc_fsm_next(fsm, silc_client_notify_processed);
431 return SILC_FSM_CONTINUE;
434 /********************************** LEAVE ***********************************/
436 /* Someone left a channel */
438 SILC_FSM_STATE(silc_client_notify_leave)
440 SilcClientConnection conn = fsm_context;
441 SilcClient client = conn->client;
442 SilcClientNotify notify = state_context;
443 SilcNotifyPayload payload = notify->payload;
444 SilcPacket packet = notify->packet;
445 SilcNotifyType type = silc_notify_get_type(payload);
446 SilcArgumentPayload args = silc_notify_get_args(payload);
447 SilcClientEntry client_entry = NULL;
448 SilcChannelEntry channel = NULL;
451 SILC_LOG_DEBUG(("Notify: LEAVE"));
453 /* Get channel entry */
454 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
455 &id.u.channel_id, sizeof(id.u.channel_id)))
457 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
461 /* If channel is being resolved handle notify after resolving */
462 if (channel->internal.resolve_cmd_ident) {
463 silc_client_unref_channel(client, conn, channel);
464 SILC_FSM_CALL(silc_client_command_pending(
465 conn, SILC_COMMAND_NONE,
466 channel->internal.resolve_cmd_ident,
467 silc_client_notify_wait_continue,
473 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
476 /* Find Client entry */
477 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
481 /* Remove client from channel */
482 if (!silc_client_remove_from_channel(client, conn, channel, client_entry))
485 /* Notify application. */
486 NOTIFY(client, conn, type, client_entry, channel);
488 silc_client_unref_client(client, conn, client_entry);
491 /** Notify processed */
492 silc_client_unref_channel(client, conn, channel);
493 silc_fsm_next(fsm, silc_client_notify_processed);
494 return SILC_FSM_CONTINUE;
497 /********************************* SIGNOFF **********************************/
499 /* Someone quit SILC network */
501 SILC_FSM_STATE(silc_client_notify_signoff)
503 SilcClientConnection conn = fsm_context;
504 SilcClient client = conn->client;
505 SilcClientNotify notify = state_context;
506 SilcNotifyPayload payload = notify->payload;
507 SilcPacket packet = notify->packet;
508 SilcNotifyType type = silc_notify_get_type(payload);
509 SilcArgumentPayload args = silc_notify_get_args(payload);
510 SilcClientEntry client_entry;
511 SilcChannelEntry channel = NULL;
516 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
519 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
522 /* Find Client entry */
523 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
527 /* Get signoff message */
528 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
529 if (tmp && tmp_len > 128)
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 /* Notify application */
538 if (client_entry->internal.valid)
539 NOTIFY(client, conn, type, client_entry, tmp, channel);
541 /* Remove from channel */
543 silc_client_remove_from_channel(client, conn, channel, client_entry);
544 silc_client_unref_channel(client, conn, channel);
548 client_entry->internal.valid = FALSE;
549 silc_client_del_client(client, conn, client_entry);
550 silc_client_unref_client(client, conn, client_entry);
553 /** Notify processed */
554 silc_fsm_next(fsm, silc_client_notify_processed);
555 return SILC_FSM_CONTINUE;
558 /******************************** TOPIC_SET *********************************/
560 /* Someone set topic on a channel */
562 SILC_FSM_STATE(silc_client_notify_topic_set)
564 SilcClientConnection conn = fsm_context;
565 SilcClient client = conn->client;
566 SilcClientNotify notify = state_context;
567 SilcNotifyPayload payload = notify->payload;
568 SilcPacket packet = notify->packet;
569 SilcNotifyType type = silc_notify_get_type(payload);
570 SilcArgumentPayload args = silc_notify_get_args(payload);
571 SilcClientEntry client_entry = NULL;
572 SilcChannelEntry channel = NULL, channel_entry = NULL;
573 SilcServerEntry server = NULL;
579 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
581 /* Get channel entry */
582 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
583 &id.u.channel_id, sizeof(id.u.channel_id)))
585 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
589 /* If channel is being resolved handle notify after resolving */
590 if (channel->internal.resolve_cmd_ident) {
591 silc_client_unref_channel(client, conn, channel);
592 SILC_FSM_CALL(silc_client_command_pending(
593 conn, SILC_COMMAND_NONE,
594 channel->internal.resolve_cmd_ident,
595 silc_client_notify_wait_continue,
600 /* Get ID of topic changer */
601 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
605 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
609 if (id.type == SILC_ID_CLIENT) {
610 /* Find Client entry */
611 client_entry = notify->client_entry;
613 client_entry = silc_client_get_client(client, conn, &id.u.client_id);
614 if (!client_entry || !client_entry->internal.valid) {
615 /** Resolve client */
616 notify->channel = channel;
617 notify->client_entry = client_entry;
618 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
619 silc_client_get_client_by_id_resolve(
620 client, conn, &id.u.client_id, NULL,
621 silc_client_notify_resolved,
627 /* If client is not on channel, ignore this notify */
628 if (!silc_client_on_channel(channel, client_entry))
631 entry = client_entry;
632 } else if (id.type == SILC_ID_SERVER) {
633 /* Find Server entry */
634 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
636 /** Resolve server */
637 notify->channel = channel;
638 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
639 silc_client_get_server_by_id_resolve(
640 client, conn, &id.u.server_id,
641 silc_client_notify_resolved,
647 /* Find Channel entry */
648 channel_entry = silc_client_get_channel_by_id(client, conn,
650 if (!channel_entry) {
651 /** Resolve channel */
652 notify->channel = channel;
653 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
654 silc_client_get_channel_by_id_resolve(
655 client, conn, &id.u.channel_id,
656 silc_client_notify_resolved,
660 entry = channel_entry;
663 silc_rwlock_wrlock(channel->internal.lock);
664 silc_free(channel->topic);
665 channel->topic = silc_memdup(tmp, strlen(tmp));
666 silc_rwlock_unlock(channel->internal.lock);
668 /* Notify application. */
669 NOTIFY(client, conn, type, id.type, entry, channel->topic, channel);
672 silc_client_unref_client(client, conn, client_entry);
674 silc_client_unref_server(client, conn, server);
676 silc_client_unref_channel(client, conn, channel_entry);
679 /** Notify processed */
680 silc_client_unref_channel(client, conn, channel);
681 silc_fsm_next(fsm, silc_client_notify_processed);
682 return SILC_FSM_CONTINUE;
685 /****************************** NICK_CHANGE *********************************/
687 /* Someone changed their nickname on a channel */
689 SILC_FSM_STATE(silc_client_notify_nick_change)
691 SilcClientConnection conn = fsm_context;
692 SilcClient client = conn->client;
693 SilcClientNotify notify = state_context;
694 SilcNotifyPayload payload = notify->payload;
695 SilcNotifyType type = silc_notify_get_type(payload);
696 SilcArgumentPayload args = silc_notify_get_args(payload);
697 SilcClientEntry client_entry = NULL;
698 unsigned char *tmp, oldnick[256 + 1];
703 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
706 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
710 if (conn->local_id &&
711 SILC_ID_CLIENT_COMPARE(&id.u.client_id, conn->local_id))
714 /* Get new Client ID */
715 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id2, NULL))
719 if (conn->local_id &&
720 SILC_ID_CLIENT_COMPARE(&id2.u.client_id, conn->local_id))
723 /* Find old client entry. If we don't have the entry, we ignore this
725 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
728 valid = client_entry->internal.valid;
730 /* Take the new nickname */
731 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
735 silc_rwlock_wrlock(client_entry->internal.lock);
737 /* Check whether nickname changed at all. It is possible that nick
738 change notify is received but nickname didn't change, only the
739 ID changes. If Client ID hash match, nickname didn't change. */
740 if (SILC_ID_COMPARE_HASH(&client_entry->id, &id2.u.client_id) &&
741 silc_utf8_strcasecmp(tmp, client_entry->nickname)) {
742 /* Nickname didn't change. Update only Client ID. We don't notify
743 application because nickname didn't change. */
744 silc_mutex_lock(conn->internal->lock);
745 silc_idcache_update_by_context(conn->internal->client_cache, client_entry,
746 &id2.u.client_id, NULL, FALSE);
747 silc_mutex_unlock(conn->internal->lock);
748 silc_rwlock_unlock(client_entry->internal.lock);
752 /* Change the nickname */
753 memcpy(oldnick, client_entry->nickname, sizeof(client_entry->nickname));
754 if (!silc_client_change_nickname(client, conn, client_entry, tmp,
755 &id2.u.client_id, NULL, 0)) {
756 silc_rwlock_unlock(client_entry->internal.lock);
760 silc_rwlock_unlock(client_entry->internal.lock);
762 /* Notify application, if client entry is valid. We do not send nick change
763 notify for entries that were invalid (application doesn't know them). */
765 NOTIFY(client, conn, type, client_entry, oldnick, client_entry->nickname);
768 /** Notify processed */
769 silc_client_unref_client(client, conn, client_entry);
770 silc_fsm_next(fsm, silc_client_notify_processed);
771 return SILC_FSM_CONTINUE;
774 /****************************** CMODE_CHANGE ********************************/
776 /* Someone changed channel mode */
778 SILC_FSM_STATE(silc_client_notify_cmode_change)
780 SilcClientConnection conn = fsm_context;
781 SilcClient client = conn->client;
782 SilcClientNotify notify = state_context;
783 SilcNotifyPayload payload = notify->payload;
784 SilcPacket packet = notify->packet;
785 SilcNotifyType type = silc_notify_get_type(payload);
786 SilcArgumentPayload args = silc_notify_get_args(payload);
787 SilcClientEntry client_entry = NULL;
788 SilcChannelEntry channel = NULL, channel_entry = NULL;
789 SilcServerEntry server = NULL;
792 SilcUInt32 tmp_len, mode;
794 char *passphrase, *cipher, *hmac;
795 SilcPublicKey founder_key = NULL;
796 SilcDList chpks = NULL;
798 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
800 /* Get channel entry */
801 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
802 &id.u.channel_id, sizeof(id.u.channel_id)))
804 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
808 /* If channel is being resolved handle notify after resolving */
809 if (channel->internal.resolve_cmd_ident) {
810 silc_client_unref_channel(client, conn, channel);
811 SILC_FSM_CALL(silc_client_command_pending(
812 conn, SILC_COMMAND_NONE,
813 channel->internal.resolve_cmd_ident,
814 silc_client_notify_wait_continue,
820 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
823 SILC_GET32_MSB(mode, tmp);
825 /* Get ID of who changed the mode */
826 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
829 if (id.type == SILC_ID_CLIENT) {
830 /* Find Client entry */
831 client_entry = notify->client_entry;
833 client_entry = silc_client_get_client(client, conn, &id.u.client_id);
834 if (!client_entry || !client_entry->internal.valid) {
835 /** Resolve client */
836 notify->channel = channel;
837 notify->client_entry = client_entry;
838 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
839 silc_client_get_client_by_id_resolve(
840 client, conn, &id.u.client_id, NULL,
841 silc_client_notify_resolved,
847 /* If client is not on channel, ignore this notify */
848 if (!silc_client_on_channel(channel, client_entry))
851 entry = client_entry;
852 } else if (id.type == SILC_ID_SERVER) {
853 /* Find Server entry */
854 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
856 /** Resolve server */
857 notify->channel = channel;
858 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
859 silc_client_get_server_by_id_resolve(
860 client, conn, &id.u.server_id,
861 silc_client_notify_resolved,
867 /* Find Channel entry */
868 channel_entry = silc_client_get_channel_by_id(client, conn,
870 if (!channel_entry) {
871 /** Resolve channel */
872 notify->channel = channel;
873 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
874 silc_client_get_channel_by_id_resolve(
875 client, conn, &id.u.channel_id,
876 silc_client_notify_resolved,
880 entry = channel_entry;
883 silc_rwlock_wrlock(channel->internal.lock);
885 /* Get the channel founder key if it was set */
886 tmp = silc_argument_get_arg_type(args, 6, &tmp_len);
888 if (!silc_public_key_payload_decode(tmp, tmp_len, &founder_key)) {
889 silc_rwlock_unlock(channel->internal.lock);
892 if (!channel->founder_key) {
893 channel->founder_key = founder_key;
899 cipher = silc_argument_get_arg_type(args, 3, &tmp_len);
902 hmac = silc_argument_get_arg_type(args, 4, &tmp_len);
904 unsigned char hash[SILC_HASH_MAXLEN];
907 if (!silc_hmac_alloc(hmac, NULL, &newhmac)) {
908 silc_rwlock_unlock(channel->internal.lock);
912 /* Get HMAC key from the old HMAC context, and update it to the new one */
913 tmp = (unsigned char *)silc_hmac_get_key(channel->internal.hmac, &tmp_len);
915 silc_hash_make(silc_hmac_get_hash(newhmac), tmp, tmp_len, hash);
916 silc_hmac_set_key(newhmac, hash,
917 silc_hash_len(silc_hmac_get_hash(newhmac)));
918 if (channel->internal.hmac)
919 silc_hmac_free(channel->internal.hmac);
920 channel->internal.hmac = newhmac;
921 memset(hash, 0, sizeof(hash));
925 /* Get the passphrase if it was set */
926 passphrase = silc_argument_get_arg_type(args, 5, &tmp_len);
929 tmp = silc_argument_get_arg_type(args, 8, &tmp_len);
930 if (tmp && tmp_len == 4)
931 SILC_GET32_MSB(channel->user_limit, tmp);
932 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
933 channel->user_limit = 0;
935 /* Get the channel public key that was added or removed */
936 tmp = silc_argument_get_arg_type(args, 7, &tmp_len);
938 silc_client_channel_save_public_keys(channel, tmp, tmp_len, FALSE);
939 else if (channel->mode & SILC_CHANNEL_MODE_CHANNEL_AUTH)
940 silc_client_channel_save_public_keys(channel, NULL, 0, TRUE);
942 /* Save the new mode */
943 channel->mode = mode;
945 silc_rwlock_unlock(channel->internal.lock);
947 /* Notify application. */
948 NOTIFY(client, conn, type, id.type, entry, mode, cipher, hmac,
949 passphrase, channel->founder_key, chpks, channel);
953 silc_pkcs_public_key_free(founder_key);
955 silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
957 silc_client_unref_client(client, conn, client_entry);
959 silc_client_unref_server(client, conn, server);
961 silc_client_unref_channel(client, conn, channel_entry);
962 silc_client_unref_channel(client, conn, channel);
964 /** Notify processed */
965 silc_fsm_next(fsm, silc_client_notify_processed);
966 return SILC_FSM_CONTINUE;
969 /***************************** CUMODE_CHANGE ********************************/
971 /* Someone changed a user's mode on a channel */
973 SILC_FSM_STATE(silc_client_notify_cumode_change)
975 SilcClientConnection conn = fsm_context;
976 SilcClient client = conn->client;
977 SilcClientNotify notify = state_context;
978 SilcNotifyPayload payload = notify->payload;
979 SilcPacket packet = notify->packet;
980 SilcNotifyType type = silc_notify_get_type(payload);
981 SilcArgumentPayload args = silc_notify_get_args(payload);
982 SilcClientEntry client_entry = NULL, client_entry2 = NULL;
983 SilcChannelEntry channel = NULL, channel_entry = NULL;
984 SilcServerEntry server = NULL;
988 SilcUInt32 tmp_len, mode;
991 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
993 /* Get channel entry */
994 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
995 &id.u.channel_id, sizeof(id.u.channel_id)))
997 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1001 /* If channel is being resolved handle notify after resolving */
1002 if (channel->internal.resolve_cmd_ident) {
1003 silc_client_unref_channel(client, conn, channel);
1004 SILC_FSM_CALL(silc_client_command_pending(
1005 conn, SILC_COMMAND_NONE,
1006 channel->internal.resolve_cmd_ident,
1007 silc_client_notify_wait_continue,
1012 /* Get target Client ID */
1013 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id2, NULL))
1016 /* Find target Client entry */
1017 client_entry2 = silc_client_get_client_by_id(client, conn, &id2.u.client_id);
1018 if (!client_entry2 || !client_entry2->internal.valid) {
1019 /** Resolve client */
1020 silc_client_unref_client(client, conn, client_entry2);
1021 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1022 client, conn, &id2.u.client_id, NULL,
1023 silc_client_notify_resolved,
1028 /* If target client is not on channel, ignore this notify */
1029 if (!silc_client_on_channel(channel, client_entry2))
1033 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1036 SILC_GET32_MSB(mode, tmp);
1038 /* Get ID of mode changer */
1039 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1042 if (id.type == SILC_ID_CLIENT) {
1043 /* Find Client entry */
1044 client_entry = notify->client_entry;
1045 if (!client_entry) {
1046 client_entry = silc_client_get_client(client, conn, &id.u.client_id);
1047 if (!client_entry || !client_entry->internal.valid) {
1048 /** Resolve client */
1049 notify->channel = channel;
1050 notify->client_entry = client_entry;
1051 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1052 silc_client_get_client_by_id_resolve(
1053 client, conn, &id.u.client_id, NULL,
1054 silc_client_notify_resolved,
1060 /* If client is not on channel, ignore this notify */
1061 if (!silc_client_on_channel(channel, client_entry))
1064 entry = client_entry;
1065 } else if (id.type == SILC_ID_SERVER) {
1066 /* Find Server entry */
1067 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1069 /** Resolve server */
1070 notify->channel = channel;
1071 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1072 silc_client_get_server_by_id_resolve(
1073 client, conn, &id.u.server_id,
1074 silc_client_notify_resolved,
1080 /* Find Channel entry */
1081 channel_entry = silc_client_get_channel_by_id(client, conn,
1083 if (!channel_entry) {
1084 /** Resolve channel */
1085 notify->channel = channel;
1086 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1087 silc_client_get_channel_by_id_resolve(
1088 client, conn, &id.u.channel_id,
1089 silc_client_notify_resolved,
1093 entry = channel_entry;
1097 silc_rwlock_wrlock(channel->internal.lock);
1098 chu = silc_client_on_channel(channel, client_entry2);
1101 silc_rwlock_unlock(channel->internal.lock);
1103 /* Notify application. */
1104 NOTIFY(client, conn, type, id.type, entry, mode, client_entry2, channel);
1107 silc_client_unref_client(client, conn, client_entry2);
1109 silc_client_unref_client(client, conn, client_entry);
1111 silc_client_unref_server(client, conn, server);
1113 silc_client_unref_channel(client, conn, channel_entry);
1114 silc_client_unref_channel(client, conn, channel);
1116 /** Notify processed */
1117 silc_fsm_next(fsm, silc_client_notify_processed);
1118 return SILC_FSM_CONTINUE;
1121 /********************************* MOTD *************************************/
1123 /* Received Message of the day */
1125 SILC_FSM_STATE(silc_client_notify_motd)
1127 SilcClientConnection conn = fsm_context;
1128 SilcClient client = conn->client;
1129 SilcClientNotify notify = state_context;
1130 SilcNotifyPayload payload = notify->payload;
1131 SilcNotifyType type = silc_notify_get_type(payload);
1132 SilcArgumentPayload args = silc_notify_get_args(payload);
1136 SILC_LOG_DEBUG(("Notify: MOTD"));
1139 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1143 /* Notify application */
1144 NOTIFY(client, conn, type, tmp);
1147 /** Notify processed */
1148 silc_fsm_next(fsm, silc_client_notify_processed);
1149 return SILC_FSM_CONTINUE;
1152 /**************************** CHANNEL CHANGE ********************************/
1154 /* Router has enforced a new ID to a channel, change it */
1156 SILC_FSM_STATE(silc_client_notify_channel_change)
1158 SilcClientConnection conn = fsm_context;
1159 SilcClient client = conn->client;
1160 SilcClientNotify notify = state_context;
1161 SilcNotifyPayload payload = notify->payload;
1162 SilcNotifyType type = silc_notify_get_type(payload);
1163 SilcArgumentPayload args = silc_notify_get_args(payload);
1164 SilcChannelEntry channel = NULL;
1167 SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
1169 /* Get the old ID */
1170 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1173 /* Get the channel entry */
1174 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1178 /* If channel is being resolved handle notify after resolving */
1179 if (channel->internal.resolve_cmd_ident) {
1180 silc_client_unref_channel(client, conn, channel);
1181 SILC_FSM_CALL(silc_client_command_pending(
1182 conn, SILC_COMMAND_NONE,
1183 channel->internal.resolve_cmd_ident,
1184 silc_client_notify_wait_continue,
1189 /* Get the new ID */
1190 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
1193 /* Replace the Channel ID */
1194 if (!silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id))
1197 /* Notify application */
1198 NOTIFY(client, conn, type, channel, channel);
1201 /** Notify processed */
1202 silc_client_unref_channel(client, conn, channel);
1203 silc_fsm_next(fsm, silc_client_notify_processed);
1204 return SILC_FSM_CONTINUE;
1207 /******************************** KICKED ************************************/
1209 /* Some client was kicked from a channel */
1211 SILC_FSM_STATE(silc_client_notify_kicked)
1213 SilcClientConnection conn = fsm_context;
1214 SilcClient client = conn->client;
1215 SilcClientNotify notify = state_context;
1216 SilcNotifyPayload payload = notify->payload;
1217 SilcPacket packet = notify->packet;
1218 SilcNotifyType type = silc_notify_get_type(payload);
1219 SilcArgumentPayload args = silc_notify_get_args(payload);
1220 SilcClientEntry client_entry, client_entry2;
1221 SilcChannelEntry channel = NULL;
1226 SILC_LOG_DEBUG(("Notify: KICKED"));
1228 /* Get channel entry */
1229 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
1230 &id.u.channel_id, sizeof(id.u.channel_id)))
1232 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1236 /* If channel is being resolved handle notify after resolving */
1237 if (channel->internal.resolve_cmd_ident) {
1238 silc_client_unref_channel(client, conn, channel);
1239 SILC_FSM_CALL(silc_client_command_pending(
1240 conn, SILC_COMMAND_NONE,
1241 channel->internal.resolve_cmd_ident,
1242 silc_client_notify_wait_continue,
1247 /* Get the kicked Client ID */
1248 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1251 /* Find client entry */
1252 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1256 /* Get kicker's Client ID */
1257 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
1260 /* Find kicker's client entry and if not found resolve it */
1261 client_entry2 = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1262 if (!client_entry2 || !client_entry2->internal.valid) {
1263 /** Resolve client */
1264 silc_client_unref_client(client, conn, client_entry);
1265 silc_client_unref_client(client, conn, client_entry2);
1266 notify->channel = channel;
1267 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1268 silc_client_get_client_by_id_resolve(
1269 client, conn, &id.u.client_id, NULL,
1270 silc_client_notify_resolved,
1276 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1278 /* Remove kicked client from channel */
1279 if (client_entry != conn->local_entry) {
1280 if (!silc_client_remove_from_channel(client, conn, channel, client_entry))
1284 /* Notify application. */
1285 NOTIFY(client, conn, type, client_entry, tmp, client_entry2, channel);
1287 /* If I was kicked from channel, remove the channel */
1288 if (client_entry == conn->local_entry) {
1289 if (conn->current_channel == channel)
1290 conn->current_channel = NULL;
1291 silc_client_empty_channel(client, conn, channel);
1292 silc_client_del_channel(client, conn, channel);
1295 silc_client_unref_client(client, conn, client_entry);
1296 silc_client_unref_client(client, conn, client_entry2);
1299 /** Notify processed */
1300 silc_client_unref_channel(client, conn, channel);
1301 silc_fsm_next(fsm, silc_client_notify_processed);
1302 return SILC_FSM_CONTINUE;
1305 /******************************** KILLED ************************************/
1307 /* Some client was killed from the network */
1309 SILC_FSM_STATE(silc_client_notify_killed)
1311 SilcClientConnection conn = fsm_context;
1312 SilcClient client = conn->client;
1313 SilcClientNotify notify = state_context;
1314 SilcNotifyPayload payload = notify->payload;
1315 SilcNotifyType type = silc_notify_get_type(payload);
1316 SilcArgumentPayload args = silc_notify_get_args(payload);
1317 SilcClientEntry client_entry = NULL, client_entry2 = NULL;
1318 SilcChannelEntry channel_entry = NULL;
1319 SilcServerEntry server = NULL;
1322 SilcUInt32 comment_len;
1325 SILC_LOG_DEBUG(("Notify: KILLED"));
1328 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1331 /* Find Client entry */
1332 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1337 comment = silc_argument_get_arg_type(args, 2, &comment_len);
1339 /* Get killer's ID */
1340 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
1343 if (id.type == SILC_ID_CLIENT) {
1344 /* Find Client entry */
1345 client_entry2 = silc_client_get_client_by_id(client, conn,
1347 if (!client_entry2 || !client_entry2->internal.valid) {
1348 /** Resolve client */
1349 silc_client_unref_client(client, conn, client_entry);
1350 silc_client_unref_client(client, conn, client_entry2);
1351 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1352 client, conn, &id.u.client_id, NULL,
1353 silc_client_notify_resolved,
1357 entry = client_entry2;
1358 } else if (id.type == SILC_ID_SERVER) {
1359 /* Find Server entry */
1360 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1362 /** Resolve server */
1363 SILC_FSM_CALL(silc_client_get_server_by_id_resolve(
1364 client, conn, &id.u.server_id,
1365 silc_client_notify_resolved,
1371 /* Find Channel entry */
1372 channel_entry = silc_client_get_channel_by_id(client, conn,
1374 if (!channel_entry) {
1375 /** Resolve channel */
1376 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1377 client, conn, &id.u.channel_id,
1378 silc_client_notify_resolved,
1382 entry = channel_entry;
1385 /* Notify application. */
1386 NOTIFY(client, conn, type, client_entry, comment, id.type, entry);
1388 /* Delete the killed client */
1389 if (client_entry != conn->local_entry) {
1390 silc_client_remove_from_channels(client, conn, client_entry);
1391 client_entry->internal.valid = FALSE;
1392 silc_client_del_client(client, conn, client_entry);
1396 silc_client_unref_client(client, conn, client_entry);
1398 silc_client_unref_client(client, conn, client_entry2);
1400 silc_client_unref_server(client, conn, server);
1402 silc_client_unref_channel(client, conn, channel_entry);
1404 /** Notify processed */
1405 silc_fsm_next(fsm, silc_client_notify_processed);
1406 return SILC_FSM_CONTINUE;
1409 /**************************** SERVER SIGNOFF ********************************/
1411 /* Some server quit SILC network. Remove its clients from channels. */
1413 SILC_FSM_STATE(silc_client_notify_server_signoff)
1415 SilcClientConnection conn = fsm_context;
1416 SilcClient client = conn->client;
1417 SilcClientNotify notify = state_context;
1418 SilcNotifyPayload payload = notify->payload;
1419 SilcNotifyType type = silc_notify_get_type(payload);
1420 SilcArgumentPayload args = silc_notify_get_args(payload);
1421 SilcClientEntry client_entry;
1422 SilcServerEntry server_entry = NULL;
1427 SILC_LOG_DEBUG(("Notify: SERVER_SIGNOFF"));
1429 clients = silc_dlist_init();
1434 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1437 /* Get server, in case we have it cached */
1438 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1440 for (i = 1; i < silc_argument_get_arg_num(args); i++) {
1442 if (!silc_argument_get_decoded(args, i + 1, SILC_ARGUMENT_ID, &id, NULL))
1445 /* Get the client entry */
1446 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1447 if (client_entry && client_entry->internal.valid)
1448 silc_dlist_add(clients, client_entry);
1451 /* Notify application. */
1452 NOTIFY(client, conn, type, server_entry, clients);
1454 /* Delete the clients */
1455 silc_dlist_start(clients);
1456 while ((client_entry = silc_dlist_get(clients))) {
1457 silc_client_remove_from_channels(client, conn, client_entry);
1458 client_entry->internal.valid = FALSE;
1459 silc_client_del_client(client, conn, client_entry);
1463 /** Notify processed */
1464 silc_client_unref_server(client, conn, server_entry);
1465 silc_client_list_free(client, conn, clients);
1466 silc_fsm_next(fsm, silc_client_notify_processed);
1467 return SILC_FSM_CONTINUE;
1470 /******************************** ERROR *************************************/
1472 /* Some error occurred */
1474 SILC_FSM_STATE(silc_client_notify_error)
1476 SilcClientConnection conn = fsm_context;
1477 SilcClient client = conn->client;
1478 SilcClientNotify notify = state_context;
1479 SilcNotifyPayload payload = notify->payload;
1480 SilcNotifyType type = silc_notify_get_type(payload);
1481 SilcArgumentPayload args = silc_notify_get_args(payload);
1482 SilcClientEntry client_entry;
1489 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1490 if (!tmp && tmp_len != 1)
1492 error = (SilcStatus)tmp[0];
1494 SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1496 /* Handle the error */
1497 if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1498 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
1500 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1501 if (client_entry && client_entry != conn->local_entry) {
1502 silc_client_remove_from_channels(client, conn, client_entry);
1503 silc_client_del_client(client, conn, client_entry);
1504 silc_client_unref_client(client, conn, client_entry);
1508 /* Notify application. */
1509 NOTIFY(client, conn, type, error);
1512 /** Notify processed */
1513 silc_fsm_next(fsm, silc_client_notify_processed);
1514 return SILC_FSM_CONTINUE;
1517 /******************************** WATCH *************************************/
1519 /* Received notify about some client we are watching */
1521 SILC_FSM_STATE(silc_client_notify_watch)
1523 SilcClientConnection conn = fsm_context;
1524 SilcClient client = conn->client;
1525 SilcClientNotify notify = state_context;
1526 SilcNotifyPayload payload = notify->payload;
1527 SilcNotifyType type = silc_notify_get_type(payload);
1528 SilcArgumentPayload args = silc_notify_get_args(payload);
1529 SilcClientEntry client_entry = NULL;
1530 SilcNotifyType ntype = 0;
1531 unsigned char *pk, *tmp;
1532 SilcUInt32 mode, pk_len, tmp_len;
1533 SilcPublicKey public_key = NULL;
1536 SILC_LOG_DEBUG(("Notify: WATCH"));
1538 /* Get sender Client ID */
1539 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1542 /* Find client entry and if not found resolve it */
1543 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1544 if (!client_entry || !client_entry->internal.valid) {
1545 /** Resolve client */
1546 silc_client_unref_client(client, conn, client_entry);
1547 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1548 client, conn, &id.u.client_id, NULL,
1549 silc_client_notify_resolved,
1555 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1556 if (!tmp || tmp_len != 4)
1558 SILC_GET32_MSB(mode, tmp);
1560 /* Get notify type */
1561 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1562 if (tmp && tmp_len != 2)
1565 SILC_GET16_MSB(ntype, tmp);
1568 tmp = silc_argument_get_arg_type(args, 2, NULL);
1570 char *tmp_nick = NULL;
1572 silc_client_nickname_parse(client, conn, client_entry->nickname,
1575 /* If same nick, the client was new to us and has become "present"
1576 to network. Send NULL as nick to application. */
1577 if (tmp_nick && silc_utf8_strcasecmp(tmp, tmp_nick))
1580 silc_free(tmp_nick);
1583 /* Get public key, if present */
1584 pk = silc_argument_get_arg_type(args, 5, &pk_len);
1585 if (pk && !client_entry->public_key) {
1586 if (silc_public_key_payload_decode(pk, pk_len, &public_key)) {
1587 client_entry->public_key = public_key;
1592 /* Notify application. */
1593 NOTIFY(client, conn, type, client_entry, tmp, mode, ntype,
1594 client_entry->public_key);
1596 client_entry->mode = mode;
1598 /* Remove client that left the network. */
1599 if (ntype == SILC_NOTIFY_TYPE_SIGNOFF ||
1600 ntype == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
1601 ntype == SILC_NOTIFY_TYPE_KILLED) {
1602 silc_client_remove_from_channels(client, conn, client_entry);
1603 client_entry->internal.valid = FALSE;
1604 silc_client_del_client(client, conn, client_entry);
1608 silc_pkcs_public_key_free(public_key);
1611 /** Notify processed */
1612 silc_client_unref_client(client, conn, client_entry);
1613 silc_fsm_next(fsm, silc_client_notify_processed);
1614 return SILC_FSM_CONTINUE;