5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2008 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);
302 /** Resolve channel */
303 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
304 client, conn, &id.u.channel_id,
305 silc_client_notify_resolved,
310 /* If channel is being resolved handle notify after resolving */
311 if (channel->internal.resolve_cmd_ident) {
312 silc_client_unref_channel(client, conn, channel);
313 SILC_FSM_CALL(silc_client_command_pending(
314 conn, SILC_COMMAND_NONE,
315 channel->internal.resolve_cmd_ident,
316 silc_client_notify_wait_continue,
321 /* Get sender Client ID */
322 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
325 /* Find Client entry and if not found query it */
326 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
327 if (!client_entry || !client_entry->internal.valid) {
328 /** Resolve client */
329 silc_client_unref_client(client, conn, client_entry);
330 notify->channel = channel;
331 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
332 silc_client_get_client_by_id_resolve(
333 client, conn, &id.u.client_id, NULL,
334 silc_client_notify_resolved,
339 /* Notify application */
340 NOTIFY(client, conn, type, channel, tmp, client_entry);
342 silc_client_unref_client(client, conn, client_entry);
345 /** Notify processed */
346 silc_client_unref_channel(client, conn, channel);
347 silc_fsm_next(fsm, silc_client_notify_processed);
348 return SILC_FSM_CONTINUE;
351 /********************************** JOIN ************************************/
353 /* Someone joined a channel */
355 SILC_FSM_STATE(silc_client_notify_join)
357 SilcClientConnection conn = fsm_context;
358 SilcClient client = conn->client;
359 SilcClientNotify notify = state_context;
360 SilcNotifyPayload payload = notify->payload;
361 SilcNotifyType type = silc_notify_get_type(payload);
362 SilcArgumentPayload args = silc_notify_get_args(payload);
363 SilcClientEntry client_entry;
364 SilcChannelEntry channel = NULL;
367 SILC_LOG_DEBUG(("Notify: JOIN"));
370 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
373 /* Get channel entry */
374 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
378 /* If channel is being resolved handle notify after resolving */
379 if (channel->internal.resolve_cmd_ident) {
380 silc_client_unref_channel(client, conn, channel);
381 SILC_FSM_CALL(silc_client_command_pending(
382 conn, SILC_COMMAND_NONE,
383 channel->internal.resolve_cmd_ident,
384 silc_client_notify_wait_continue,
390 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
393 /* Find client entry and if not found query it. If we just queried it
394 don't do it again, unless some data (like username) is missing. */
395 client_entry = notify->client_entry;
397 client_entry = silc_client_get_client(client, conn, &id.u.client_id);
398 if (!client_entry || !client_entry->internal.valid ||
399 !client_entry->username[0]) {
400 /** Resolve client */
401 notify->channel = channel;
402 notify->client_entry = client_entry;
403 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
404 silc_client_get_client_by_id_resolve(
405 client, conn, client_entry ?
406 &client_entry->id : &id.u.client_id,
407 NULL, silc_client_notify_resolved,
412 silc_rwlock_wrlock(client_entry->internal.lock);
413 silc_rwlock_wrlock(channel->internal.lock);
415 if (client_entry != conn->local_entry)
416 silc_client_nickname_format(client, conn, client_entry, FALSE);
418 /* Join the client to channel */
419 if (!silc_client_add_to_channel(client, conn, channel, client_entry, 0)) {
420 silc_rwlock_unlock(channel->internal.lock);
421 silc_rwlock_unlock(client_entry->internal.lock);
425 silc_rwlock_unlock(channel->internal.lock);
426 silc_rwlock_unlock(client_entry->internal.lock);
428 /* Notify application. */
429 NOTIFY(client, conn, type, client_entry, channel);
431 silc_client_unref_client(client, conn, client_entry);
434 /** Notify processed */
435 silc_client_unref_channel(client, conn, channel);
436 silc_fsm_next(fsm, silc_client_notify_processed);
437 return SILC_FSM_CONTINUE;
440 /********************************** LEAVE ***********************************/
442 /* Someone left a channel */
444 SILC_FSM_STATE(silc_client_notify_leave)
446 SilcClientConnection conn = fsm_context;
447 SilcClient client = conn->client;
448 SilcClientNotify notify = state_context;
449 SilcNotifyPayload payload = notify->payload;
450 SilcPacket packet = notify->packet;
451 SilcNotifyType type = silc_notify_get_type(payload);
452 SilcArgumentPayload args = silc_notify_get_args(payload);
453 SilcClientEntry client_entry = NULL;
454 SilcChannelEntry channel = NULL;
457 SILC_LOG_DEBUG(("Notify: LEAVE"));
459 /* Get channel entry */
460 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
461 &id.u.channel_id, sizeof(id.u.channel_id)))
463 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
467 /* If channel is being resolved handle notify after resolving */
468 if (channel->internal.resolve_cmd_ident) {
469 silc_client_unref_channel(client, conn, channel);
470 SILC_FSM_CALL(silc_client_command_pending(
471 conn, SILC_COMMAND_NONE,
472 channel->internal.resolve_cmd_ident,
473 silc_client_notify_wait_continue,
479 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
482 /* Find Client entry */
483 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
487 /* Remove client from channel */
488 if (!silc_client_remove_from_channel(client, conn, channel, client_entry))
491 /* Notify application. */
492 NOTIFY(client, conn, type, client_entry, channel);
494 silc_client_unref_client(client, conn, client_entry);
497 /** Notify processed */
498 silc_client_unref_channel(client, conn, channel);
499 silc_fsm_next(fsm, silc_client_notify_processed);
500 return SILC_FSM_CONTINUE;
503 /********************************* SIGNOFF **********************************/
505 /* Someone quit SILC network */
507 SILC_FSM_STATE(silc_client_notify_signoff)
509 SilcClientConnection conn = fsm_context;
510 SilcClient client = conn->client;
511 SilcClientNotify notify = state_context;
512 SilcNotifyPayload payload = notify->payload;
513 SilcPacket packet = notify->packet;
514 SilcNotifyType type = silc_notify_get_type(payload);
515 SilcArgumentPayload args = silc_notify_get_args(payload);
516 SilcClientEntry client_entry;
517 SilcChannelEntry channel = NULL;
522 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
525 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
528 /* Find Client entry */
529 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
533 /* Get signoff message */
534 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
535 if (tmp && tmp_len > 128)
538 if (packet->dst_id_type == SILC_ID_CHANNEL)
539 if (silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
540 &id.u.channel_id, sizeof(id.u.channel_id)))
541 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
543 /* Notify application */
544 if (client_entry->internal.valid)
545 NOTIFY(client, conn, type, client_entry, tmp, channel);
547 /* Remove from channel */
549 silc_client_remove_from_channel(client, conn, channel, client_entry);
550 silc_client_unref_channel(client, conn, channel);
554 client_entry->internal.valid = FALSE;
555 silc_client_del_client(client, conn, client_entry);
556 silc_client_unref_client(client, conn, client_entry);
559 /** Notify processed */
560 silc_fsm_next(fsm, silc_client_notify_processed);
561 return SILC_FSM_CONTINUE;
564 /******************************** TOPIC_SET *********************************/
566 /* Someone set topic on a channel */
568 SILC_FSM_STATE(silc_client_notify_topic_set)
570 SilcClientConnection conn = fsm_context;
571 SilcClient client = conn->client;
572 SilcClientNotify notify = state_context;
573 SilcNotifyPayload payload = notify->payload;
574 SilcPacket packet = notify->packet;
575 SilcNotifyType type = silc_notify_get_type(payload);
576 SilcArgumentPayload args = silc_notify_get_args(payload);
577 SilcClientEntry client_entry = NULL;
578 SilcChannelEntry channel = NULL, channel_entry = NULL;
579 SilcServerEntry server = NULL;
585 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
587 /* Get channel entry */
588 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
589 &id.u.channel_id, sizeof(id.u.channel_id)))
591 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
595 /* If channel is being resolved handle notify after resolving */
596 if (channel->internal.resolve_cmd_ident) {
597 silc_client_unref_channel(client, conn, channel);
598 SILC_FSM_CALL(silc_client_command_pending(
599 conn, SILC_COMMAND_NONE,
600 channel->internal.resolve_cmd_ident,
601 silc_client_notify_wait_continue,
606 /* Get ID of topic changer */
607 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
611 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
615 if (id.type == SILC_ID_CLIENT) {
616 /* Find Client entry */
617 client_entry = notify->client_entry;
619 client_entry = silc_client_get_client(client, conn, &id.u.client_id);
620 if (!client_entry || !client_entry->internal.valid) {
621 /** Resolve client */
622 notify->channel = channel;
623 notify->client_entry = client_entry;
624 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
625 silc_client_get_client_by_id_resolve(
626 client, conn, &id.u.client_id, NULL,
627 silc_client_notify_resolved,
633 /* If client is not on channel, ignore this notify */
634 if (!silc_client_on_channel(channel, client_entry))
637 entry = client_entry;
638 } else if (id.type == SILC_ID_SERVER) {
639 /* Find Server entry */
640 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
642 /** Resolve server */
643 notify->channel = channel;
644 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
645 silc_client_get_server_by_id_resolve(
646 client, conn, &id.u.server_id,
647 silc_client_notify_resolved,
653 /* Find Channel entry */
654 channel_entry = silc_client_get_channel_by_id(client, conn,
656 if (!channel_entry) {
657 /** Resolve channel */
658 notify->channel = channel;
659 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
660 silc_client_get_channel_by_id_resolve(
661 client, conn, &id.u.channel_id,
662 silc_client_notify_resolved,
666 entry = channel_entry;
669 silc_rwlock_wrlock(channel->internal.lock);
670 silc_free(channel->topic);
671 channel->topic = silc_memdup(tmp, strlen(tmp));
672 silc_rwlock_unlock(channel->internal.lock);
674 /* Notify application. */
675 NOTIFY(client, conn, type, id.type, entry, channel->topic, channel);
678 silc_client_unref_client(client, conn, client_entry);
680 silc_client_unref_server(client, conn, server);
682 silc_client_unref_channel(client, conn, channel_entry);
685 /** Notify processed */
686 silc_client_unref_channel(client, conn, channel);
687 silc_fsm_next(fsm, silc_client_notify_processed);
688 return SILC_FSM_CONTINUE;
691 /****************************** NICK_CHANGE *********************************/
693 /* Someone changed their nickname on a channel */
695 SILC_FSM_STATE(silc_client_notify_nick_change)
697 SilcClientConnection conn = fsm_context;
698 SilcClient client = conn->client;
699 SilcClientNotify notify = state_context;
700 SilcNotifyPayload payload = notify->payload;
701 SilcNotifyType type = silc_notify_get_type(payload);
702 SilcArgumentPayload args = silc_notify_get_args(payload);
703 SilcClientEntry client_entry = NULL;
704 unsigned char *tmp, oldnick[256 + 1];
709 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
712 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
716 if (conn->local_id &&
717 SILC_ID_CLIENT_COMPARE(&id.u.client_id, conn->local_id))
720 /* Get new Client ID */
721 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id2, NULL))
725 if (conn->local_id &&
726 SILC_ID_CLIENT_COMPARE(&id2.u.client_id, conn->local_id))
729 /* Find old client entry. If we don't have the entry, we ignore this
731 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
734 valid = client_entry->internal.valid;
736 /* Take the new nickname */
737 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
741 silc_rwlock_wrlock(client_entry->internal.lock);
743 /* Check whether nickname changed at all. It is possible that nick
744 change notify is received but nickname didn't change, only the
745 ID changes. If Client ID hash match, nickname didn't change. */
746 if (SILC_ID_COMPARE_HASH(&client_entry->id, &id2.u.client_id) &&
747 silc_utf8_strcasecmp(tmp, client_entry->nickname)) {
748 /* Nickname didn't change. Update only Client ID. We don't notify
749 application because nickname didn't change. */
750 silc_mutex_lock(conn->internal->lock);
751 silc_idcache_update_by_context(conn->internal->client_cache, client_entry,
752 &id2.u.client_id, NULL, FALSE);
753 silc_mutex_unlock(conn->internal->lock);
754 silc_rwlock_unlock(client_entry->internal.lock);
758 /* Change the nickname */
759 memcpy(oldnick, client_entry->nickname, sizeof(client_entry->nickname));
760 if (!silc_client_change_nickname(client, conn, client_entry, tmp,
761 &id2.u.client_id, NULL, 0)) {
762 silc_rwlock_unlock(client_entry->internal.lock);
766 silc_rwlock_unlock(client_entry->internal.lock);
768 /* Notify application, if client entry is valid. We do not send nick change
769 notify for entries that were invalid (application doesn't know them). */
771 NOTIFY(client, conn, type, client_entry, oldnick, client_entry->nickname);
774 /** Notify processed */
775 silc_client_unref_client(client, conn, client_entry);
776 silc_fsm_next(fsm, silc_client_notify_processed);
777 return SILC_FSM_CONTINUE;
780 /****************************** CMODE_CHANGE ********************************/
782 /* Someone changed channel mode */
784 SILC_FSM_STATE(silc_client_notify_cmode_change)
786 SilcClientConnection conn = fsm_context;
787 SilcClient client = conn->client;
788 SilcClientNotify notify = state_context;
789 SilcNotifyPayload payload = notify->payload;
790 SilcPacket packet = notify->packet;
791 SilcNotifyType type = silc_notify_get_type(payload);
792 SilcArgumentPayload args = silc_notify_get_args(payload);
793 SilcClientEntry client_entry = NULL;
794 SilcChannelEntry channel = NULL, channel_entry = NULL;
795 SilcServerEntry server = NULL;
798 SilcUInt32 tmp_len, mode;
800 char *passphrase, *cipher, *hmac;
801 SilcPublicKey founder_key = NULL;
802 SilcDList chpks = NULL;
804 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
806 /* Get channel entry */
807 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
808 &id.u.channel_id, sizeof(id.u.channel_id)))
810 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
814 /* If channel is being resolved handle notify after resolving */
815 if (channel->internal.resolve_cmd_ident) {
816 silc_client_unref_channel(client, conn, channel);
817 SILC_FSM_CALL(silc_client_command_pending(
818 conn, SILC_COMMAND_NONE,
819 channel->internal.resolve_cmd_ident,
820 silc_client_notify_wait_continue,
826 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
829 SILC_GET32_MSB(mode, tmp);
831 /* Get ID of who changed the mode */
832 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
835 if (id.type == SILC_ID_CLIENT) {
836 /* Find Client entry */
837 client_entry = notify->client_entry;
839 client_entry = silc_client_get_client(client, conn, &id.u.client_id);
840 if (!client_entry || !client_entry->internal.valid) {
841 /** Resolve client */
842 notify->channel = channel;
843 notify->client_entry = client_entry;
844 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
845 silc_client_get_client_by_id_resolve(
846 client, conn, &id.u.client_id, NULL,
847 silc_client_notify_resolved,
853 /* If client is not on channel, ignore this notify */
854 if (!silc_client_on_channel(channel, client_entry))
857 entry = client_entry;
858 } else if (id.type == SILC_ID_SERVER) {
859 /* Find Server entry */
860 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
862 /** Resolve server */
863 notify->channel = channel;
864 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
865 silc_client_get_server_by_id_resolve(
866 client, conn, &id.u.server_id,
867 silc_client_notify_resolved,
873 /* Find Channel entry */
874 channel_entry = silc_client_get_channel_by_id(client, conn,
876 if (!channel_entry) {
877 /** Resolve channel */
878 notify->channel = channel;
879 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
880 silc_client_get_channel_by_id_resolve(
881 client, conn, &id.u.channel_id,
882 silc_client_notify_resolved,
886 entry = channel_entry;
889 silc_rwlock_wrlock(channel->internal.lock);
891 /* Get the channel founder key if it was set */
892 tmp = silc_argument_get_arg_type(args, 6, &tmp_len);
894 if (!silc_public_key_payload_decode(tmp, tmp_len, &founder_key)) {
895 silc_rwlock_unlock(channel->internal.lock);
898 if (!channel->founder_key) {
899 channel->founder_key = founder_key;
905 cipher = silc_argument_get_arg_type(args, 3, &tmp_len);
908 hmac = silc_argument_get_arg_type(args, 4, &tmp_len);
910 unsigned char hash[SILC_HASH_MAXLEN];
913 if (!silc_hmac_alloc(hmac, NULL, &newhmac)) {
914 silc_rwlock_unlock(channel->internal.lock);
918 /* Get HMAC key from the old HMAC context, and update it to the new one */
919 tmp = (unsigned char *)silc_hmac_get_key(channel->internal.hmac, &tmp_len);
921 silc_hash_make(silc_hmac_get_hash(newhmac), tmp, tmp_len, hash);
922 silc_hmac_set_key(newhmac, hash,
923 silc_hash_len(silc_hmac_get_hash(newhmac)));
924 if (channel->internal.hmac)
925 silc_hmac_free(channel->internal.hmac);
926 channel->internal.hmac = newhmac;
927 memset(hash, 0, sizeof(hash));
931 /* Get the passphrase if it was set */
932 passphrase = silc_argument_get_arg_type(args, 5, &tmp_len);
935 tmp = silc_argument_get_arg_type(args, 8, &tmp_len);
936 if (tmp && tmp_len == 4)
937 SILC_GET32_MSB(channel->user_limit, tmp);
938 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
939 channel->user_limit = 0;
941 /* Get the channel public key that was added or removed */
942 tmp = silc_argument_get_arg_type(args, 7, &tmp_len);
944 silc_client_channel_save_public_keys(channel, tmp, tmp_len, FALSE);
945 else if (channel->mode & SILC_CHANNEL_MODE_CHANNEL_AUTH)
946 silc_client_channel_save_public_keys(channel, NULL, 0, TRUE);
948 /* Save the new mode */
949 channel->mode = mode;
951 silc_rwlock_unlock(channel->internal.lock);
953 /* Notify application. */
954 NOTIFY(client, conn, type, id.type, entry, mode, cipher, hmac,
955 passphrase, channel->founder_key, chpks, channel);
959 silc_pkcs_public_key_free(founder_key);
961 silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
963 silc_client_unref_client(client, conn, client_entry);
965 silc_client_unref_server(client, conn, server);
967 silc_client_unref_channel(client, conn, channel_entry);
968 silc_client_unref_channel(client, conn, channel);
970 /** Notify processed */
971 silc_fsm_next(fsm, silc_client_notify_processed);
972 return SILC_FSM_CONTINUE;
975 /***************************** CUMODE_CHANGE ********************************/
977 /* Someone changed a user's mode on a channel */
979 SILC_FSM_STATE(silc_client_notify_cumode_change)
981 SilcClientConnection conn = fsm_context;
982 SilcClient client = conn->client;
983 SilcClientNotify notify = state_context;
984 SilcNotifyPayload payload = notify->payload;
985 SilcPacket packet = notify->packet;
986 SilcNotifyType type = silc_notify_get_type(payload);
987 SilcArgumentPayload args = silc_notify_get_args(payload);
988 SilcClientEntry client_entry = NULL, client_entry2 = NULL;
989 SilcChannelEntry channel = NULL, channel_entry = NULL;
990 SilcServerEntry server = NULL;
994 SilcUInt32 tmp_len, mode;
997 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
999 /* Get channel entry */
1000 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
1001 &id.u.channel_id, sizeof(id.u.channel_id)))
1003 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1007 /* If channel is being resolved handle notify after resolving */
1008 if (channel->internal.resolve_cmd_ident) {
1009 silc_client_unref_channel(client, conn, channel);
1010 SILC_FSM_CALL(silc_client_command_pending(
1011 conn, SILC_COMMAND_NONE,
1012 channel->internal.resolve_cmd_ident,
1013 silc_client_notify_wait_continue,
1018 /* Get target Client ID */
1019 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id2, NULL))
1022 /* Find target Client entry */
1023 client_entry2 = silc_client_get_client_by_id(client, conn, &id2.u.client_id);
1024 if (!client_entry2 || !client_entry2->internal.valid) {
1025 /** Resolve client */
1026 silc_client_unref_client(client, conn, client_entry2);
1027 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1028 client, conn, &id2.u.client_id, NULL,
1029 silc_client_notify_resolved,
1034 /* If target client is not on channel, ignore this notify */
1035 if (!silc_client_on_channel(channel, client_entry2))
1039 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1042 SILC_GET32_MSB(mode, tmp);
1044 /* Get ID of mode changer */
1045 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1048 if (id.type == SILC_ID_CLIENT) {
1049 /* Find Client entry */
1050 client_entry = notify->client_entry;
1051 if (!client_entry) {
1052 client_entry = silc_client_get_client(client, conn, &id.u.client_id);
1053 if (!client_entry || !client_entry->internal.valid) {
1054 /** Resolve client */
1055 notify->channel = channel;
1056 notify->client_entry = client_entry;
1057 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1058 silc_client_get_client_by_id_resolve(
1059 client, conn, &id.u.client_id, NULL,
1060 silc_client_notify_resolved,
1066 /* If client is not on channel, ignore this notify */
1067 if (!silc_client_on_channel(channel, client_entry))
1070 entry = client_entry;
1071 } else if (id.type == SILC_ID_SERVER) {
1072 /* Find Server entry */
1073 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1075 /** Resolve server */
1076 notify->channel = channel;
1077 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1078 silc_client_get_server_by_id_resolve(
1079 client, conn, &id.u.server_id,
1080 silc_client_notify_resolved,
1086 /* Find Channel entry */
1087 channel_entry = silc_client_get_channel_by_id(client, conn,
1089 if (!channel_entry) {
1090 /** Resolve channel */
1091 notify->channel = channel;
1092 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1093 silc_client_get_channel_by_id_resolve(
1094 client, conn, &id.u.channel_id,
1095 silc_client_notify_resolved,
1099 entry = channel_entry;
1103 silc_rwlock_wrlock(channel->internal.lock);
1104 chu = silc_client_on_channel(channel, client_entry2);
1107 silc_rwlock_unlock(channel->internal.lock);
1109 /* Notify application. */
1110 NOTIFY(client, conn, type, id.type, entry, mode, client_entry2, channel);
1113 silc_client_unref_client(client, conn, client_entry2);
1115 silc_client_unref_client(client, conn, client_entry);
1117 silc_client_unref_server(client, conn, server);
1119 silc_client_unref_channel(client, conn, channel_entry);
1120 silc_client_unref_channel(client, conn, channel);
1122 /** Notify processed */
1123 silc_fsm_next(fsm, silc_client_notify_processed);
1124 return SILC_FSM_CONTINUE;
1127 /********************************* MOTD *************************************/
1129 /* Received Message of the day */
1131 SILC_FSM_STATE(silc_client_notify_motd)
1133 SilcClientConnection conn = fsm_context;
1134 SilcClient client = conn->client;
1135 SilcClientNotify notify = state_context;
1136 SilcNotifyPayload payload = notify->payload;
1137 SilcNotifyType type = silc_notify_get_type(payload);
1138 SilcArgumentPayload args = silc_notify_get_args(payload);
1142 SILC_LOG_DEBUG(("Notify: MOTD"));
1145 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1149 /* Notify application */
1150 NOTIFY(client, conn, type, tmp);
1153 /** Notify processed */
1154 silc_fsm_next(fsm, silc_client_notify_processed);
1155 return SILC_FSM_CONTINUE;
1158 /**************************** CHANNEL CHANGE ********************************/
1160 /* Router has enforced a new ID to a channel, change it */
1162 SILC_FSM_STATE(silc_client_notify_channel_change)
1164 SilcClientConnection conn = fsm_context;
1165 SilcClient client = conn->client;
1166 SilcClientNotify notify = state_context;
1167 SilcNotifyPayload payload = notify->payload;
1168 SilcNotifyType type = silc_notify_get_type(payload);
1169 SilcArgumentPayload args = silc_notify_get_args(payload);
1170 SilcChannelEntry channel = NULL;
1173 SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
1175 /* Get the old ID */
1176 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1179 /* Get the channel entry */
1180 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1184 /* If channel is being resolved handle notify after resolving */
1185 if (channel->internal.resolve_cmd_ident) {
1186 silc_client_unref_channel(client, conn, channel);
1187 SILC_FSM_CALL(silc_client_command_pending(
1188 conn, SILC_COMMAND_NONE,
1189 channel->internal.resolve_cmd_ident,
1190 silc_client_notify_wait_continue,
1195 /* Get the new ID */
1196 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
1199 /* Replace the Channel ID */
1200 if (!silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id))
1203 /* Notify application */
1204 NOTIFY(client, conn, type, channel, channel);
1207 /** Notify processed */
1208 silc_client_unref_channel(client, conn, channel);
1209 silc_fsm_next(fsm, silc_client_notify_processed);
1210 return SILC_FSM_CONTINUE;
1213 /******************************** KICKED ************************************/
1215 /* Some client was kicked from a channel */
1217 SILC_FSM_STATE(silc_client_notify_kicked)
1219 SilcClientConnection conn = fsm_context;
1220 SilcClient client = conn->client;
1221 SilcClientNotify notify = state_context;
1222 SilcNotifyPayload payload = notify->payload;
1223 SilcPacket packet = notify->packet;
1224 SilcNotifyType type = silc_notify_get_type(payload);
1225 SilcArgumentPayload args = silc_notify_get_args(payload);
1226 SilcClientEntry client_entry, client_entry2;
1227 SilcChannelEntry channel = NULL;
1232 SILC_LOG_DEBUG(("Notify: KICKED"));
1234 /* Get channel entry */
1235 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
1236 &id.u.channel_id, sizeof(id.u.channel_id)))
1238 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1242 /* If channel is being resolved handle notify after resolving */
1243 if (channel->internal.resolve_cmd_ident) {
1244 silc_client_unref_channel(client, conn, channel);
1245 SILC_FSM_CALL(silc_client_command_pending(
1246 conn, SILC_COMMAND_NONE,
1247 channel->internal.resolve_cmd_ident,
1248 silc_client_notify_wait_continue,
1253 /* Get the kicked Client ID */
1254 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1257 /* Find client entry */
1258 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1262 /* Get kicker's Client ID */
1263 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
1266 /* Find kicker's client entry and if not found resolve it */
1267 client_entry2 = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1268 if (!client_entry2 || !client_entry2->internal.valid) {
1269 /** Resolve client */
1270 silc_client_unref_client(client, conn, client_entry);
1271 silc_client_unref_client(client, conn, client_entry2);
1272 notify->channel = channel;
1273 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1274 silc_client_get_client_by_id_resolve(
1275 client, conn, &id.u.client_id, NULL,
1276 silc_client_notify_resolved,
1282 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1284 /* Remove kicked client from channel */
1285 if (client_entry != conn->local_entry) {
1286 if (!silc_client_remove_from_channel(client, conn, channel, client_entry))
1290 /* Notify application. */
1291 NOTIFY(client, conn, type, client_entry, tmp, client_entry2, channel);
1293 /* If I was kicked from channel, remove the channel */
1294 if (client_entry == conn->local_entry) {
1295 if (conn->current_channel == channel)
1296 conn->current_channel = NULL;
1297 silc_client_empty_channel(client, conn, channel);
1298 silc_client_del_channel(client, conn, channel);
1301 silc_client_unref_client(client, conn, client_entry);
1302 silc_client_unref_client(client, conn, client_entry2);
1305 /** Notify processed */
1306 silc_client_unref_channel(client, conn, channel);
1307 silc_fsm_next(fsm, silc_client_notify_processed);
1308 return SILC_FSM_CONTINUE;
1311 /******************************** KILLED ************************************/
1313 /* Some client was killed from the network */
1315 SILC_FSM_STATE(silc_client_notify_killed)
1317 SilcClientConnection conn = fsm_context;
1318 SilcClient client = conn->client;
1319 SilcClientNotify notify = state_context;
1320 SilcNotifyPayload payload = notify->payload;
1321 SilcNotifyType type = silc_notify_get_type(payload);
1322 SilcArgumentPayload args = silc_notify_get_args(payload);
1323 SilcClientEntry client_entry = NULL, client_entry2 = NULL;
1324 SilcChannelEntry channel_entry = NULL;
1325 SilcServerEntry server = NULL;
1328 SilcUInt32 comment_len;
1331 SILC_LOG_DEBUG(("Notify: KILLED"));
1334 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1337 /* Find Client entry */
1338 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1343 comment = silc_argument_get_arg_type(args, 2, &comment_len);
1345 /* Get killer's ID */
1346 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
1349 if (id.type == SILC_ID_CLIENT) {
1350 /* Find Client entry */
1351 client_entry2 = silc_client_get_client_by_id(client, conn,
1353 if (!client_entry2 || !client_entry2->internal.valid) {
1354 /** Resolve client */
1355 silc_client_unref_client(client, conn, client_entry);
1356 silc_client_unref_client(client, conn, client_entry2);
1357 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1358 client, conn, &id.u.client_id, NULL,
1359 silc_client_notify_resolved,
1363 entry = client_entry2;
1364 } else if (id.type == SILC_ID_SERVER) {
1365 /* Find Server entry */
1366 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1368 /** Resolve server */
1369 SILC_FSM_CALL(silc_client_get_server_by_id_resolve(
1370 client, conn, &id.u.server_id,
1371 silc_client_notify_resolved,
1377 /* Find Channel entry */
1378 channel_entry = silc_client_get_channel_by_id(client, conn,
1380 if (!channel_entry) {
1381 /** Resolve channel */
1382 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1383 client, conn, &id.u.channel_id,
1384 silc_client_notify_resolved,
1388 entry = channel_entry;
1391 /* Notify application. */
1392 NOTIFY(client, conn, type, client_entry, comment, id.type, entry);
1394 /* Delete the killed client */
1395 if (client_entry != conn->local_entry) {
1396 silc_client_remove_from_channels(client, conn, client_entry);
1397 client_entry->internal.valid = FALSE;
1398 silc_client_del_client(client, conn, client_entry);
1402 silc_client_unref_client(client, conn, client_entry);
1404 silc_client_unref_client(client, conn, client_entry2);
1406 silc_client_unref_server(client, conn, server);
1408 silc_client_unref_channel(client, conn, channel_entry);
1410 /** Notify processed */
1411 silc_fsm_next(fsm, silc_client_notify_processed);
1412 return SILC_FSM_CONTINUE;
1415 /**************************** SERVER SIGNOFF ********************************/
1417 /* Some server quit SILC network. Remove its clients from channels. */
1419 SILC_FSM_STATE(silc_client_notify_server_signoff)
1421 SilcClientConnection conn = fsm_context;
1422 SilcClient client = conn->client;
1423 SilcClientNotify notify = state_context;
1424 SilcNotifyPayload payload = notify->payload;
1425 SilcNotifyType type = silc_notify_get_type(payload);
1426 SilcArgumentPayload args = silc_notify_get_args(payload);
1427 SilcClientEntry client_entry;
1428 SilcServerEntry server_entry = NULL;
1433 SILC_LOG_DEBUG(("Notify: SERVER_SIGNOFF"));
1435 clients = silc_dlist_init();
1440 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1443 /* Get server, in case we have it cached */
1444 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1446 for (i = 1; i < silc_argument_get_arg_num(args); i++) {
1448 if (!silc_argument_get_decoded(args, i + 1, SILC_ARGUMENT_ID, &id, NULL))
1451 /* Get the client entry */
1452 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1453 if (client_entry && client_entry->internal.valid)
1454 silc_dlist_add(clients, client_entry);
1457 /* Notify application. */
1458 NOTIFY(client, conn, type, server_entry, clients);
1460 /* Delete the clients */
1461 silc_dlist_start(clients);
1462 while ((client_entry = silc_dlist_get(clients))) {
1463 silc_client_remove_from_channels(client, conn, client_entry);
1464 client_entry->internal.valid = FALSE;
1465 silc_client_del_client(client, conn, client_entry);
1469 /** Notify processed */
1470 silc_client_unref_server(client, conn, server_entry);
1471 silc_client_list_free(client, conn, clients);
1472 silc_fsm_next(fsm, silc_client_notify_processed);
1473 return SILC_FSM_CONTINUE;
1476 /******************************** ERROR *************************************/
1478 /* Some error occurred */
1480 SILC_FSM_STATE(silc_client_notify_error)
1482 SilcClientConnection conn = fsm_context;
1483 SilcClient client = conn->client;
1484 SilcClientNotify notify = state_context;
1485 SilcNotifyPayload payload = notify->payload;
1486 SilcNotifyType type = silc_notify_get_type(payload);
1487 SilcArgumentPayload args = silc_notify_get_args(payload);
1488 SilcClientEntry client_entry;
1495 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1496 if (!tmp && tmp_len != 1)
1498 error = (SilcStatus)tmp[0];
1500 SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1502 /* Handle the error */
1503 if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1504 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
1506 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1507 if (client_entry && client_entry != conn->local_entry) {
1508 silc_client_remove_from_channels(client, conn, client_entry);
1509 silc_client_del_client(client, conn, client_entry);
1510 silc_client_unref_client(client, conn, client_entry);
1514 /* Notify application. */
1515 NOTIFY(client, conn, type, error);
1518 /** Notify processed */
1519 silc_fsm_next(fsm, silc_client_notify_processed);
1520 return SILC_FSM_CONTINUE;
1523 /******************************** WATCH *************************************/
1525 /* Received notify about some client we are watching */
1527 SILC_FSM_STATE(silc_client_notify_watch)
1529 SilcClientConnection conn = fsm_context;
1530 SilcClient client = conn->client;
1531 SilcClientNotify notify = state_context;
1532 SilcNotifyPayload payload = notify->payload;
1533 SilcNotifyType type = silc_notify_get_type(payload);
1534 SilcArgumentPayload args = silc_notify_get_args(payload);
1535 SilcClientEntry client_entry = NULL;
1536 SilcNotifyType ntype = 0;
1537 unsigned char *pk, *tmp;
1538 SilcUInt32 mode, pk_len, tmp_len;
1539 SilcPublicKey public_key = NULL;
1542 SILC_LOG_DEBUG(("Notify: WATCH"));
1544 /* Get sender Client ID */
1545 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1548 /* Find client entry and if not found resolve it */
1549 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1550 if (!client_entry || !client_entry->internal.valid) {
1551 /** Resolve client */
1552 silc_client_unref_client(client, conn, client_entry);
1553 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1554 client, conn, &id.u.client_id, NULL,
1555 silc_client_notify_resolved,
1561 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1562 if (!tmp || tmp_len != 4)
1564 SILC_GET32_MSB(mode, tmp);
1566 /* Get notify type */
1567 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1568 if (tmp && tmp_len != 2)
1571 SILC_GET16_MSB(ntype, tmp);
1574 tmp = silc_argument_get_arg_type(args, 2, NULL);
1576 char *tmp_nick = NULL;
1578 silc_client_nickname_parse(client, conn, client_entry->nickname,
1581 /* If same nick, the client was new to us and has become "present"
1582 to network. Send NULL as nick to application. */
1583 if (tmp_nick && silc_utf8_strcasecmp(tmp, tmp_nick))
1586 silc_free(tmp_nick);
1589 /* Get public key, if present */
1590 pk = silc_argument_get_arg_type(args, 5, &pk_len);
1591 if (pk && !client_entry->public_key) {
1592 if (silc_public_key_payload_decode(pk, pk_len, &public_key)) {
1593 client_entry->public_key = public_key;
1598 /* Notify application. */
1599 NOTIFY(client, conn, type, client_entry, tmp, mode, ntype,
1600 client_entry->public_key);
1602 client_entry->mode = mode;
1604 /* Remove client that left the network. */
1605 if (ntype == SILC_NOTIFY_TYPE_SIGNOFF ||
1606 ntype == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
1607 ntype == SILC_NOTIFY_TYPE_KILLED) {
1608 silc_client_remove_from_channels(client, conn, client_entry);
1609 client_entry->internal.valid = FALSE;
1610 silc_client_del_client(client, conn, client_entry);
1614 silc_pkcs_public_key_free(public_key);
1617 /** Notify processed */
1618 silc_client_unref_client(client, conn, client_entry);
1619 silc_fsm_next(fsm, silc_client_notify_processed);
1620 return SILC_FSM_CONTINUE;