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_hmac_set_key(newhmac, tmp, tmp_len);
922 if (channel->internal.hmac)
923 silc_hmac_free(channel->internal.hmac);
924 channel->internal.hmac = newhmac;
925 memset(hash, 0, sizeof(hash));
929 /* Get the passphrase if it was set */
930 passphrase = silc_argument_get_arg_type(args, 5, &tmp_len);
933 tmp = silc_argument_get_arg_type(args, 8, &tmp_len);
934 if (tmp && tmp_len == 4)
935 SILC_GET32_MSB(channel->user_limit, tmp);
936 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
937 channel->user_limit = 0;
939 /* Get the channel public key that was added or removed */
940 tmp = silc_argument_get_arg_type(args, 7, &tmp_len);
942 silc_client_channel_save_public_keys(channel, tmp, tmp_len, FALSE);
943 else if (channel->mode & SILC_CHANNEL_MODE_CHANNEL_AUTH)
944 silc_client_channel_save_public_keys(channel, NULL, 0, TRUE);
946 /* Save the new mode */
947 channel->mode = mode;
949 silc_rwlock_unlock(channel->internal.lock);
951 /* Notify application. */
952 NOTIFY(client, conn, type, id.type, entry, mode, cipher, hmac,
953 passphrase, channel->founder_key, chpks, channel);
957 silc_pkcs_public_key_free(founder_key);
959 silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
961 silc_client_unref_client(client, conn, client_entry);
963 silc_client_unref_server(client, conn, server);
965 silc_client_unref_channel(client, conn, channel_entry);
966 silc_client_unref_channel(client, conn, channel);
968 /** Notify processed */
969 silc_fsm_next(fsm, silc_client_notify_processed);
970 return SILC_FSM_CONTINUE;
973 /***************************** CUMODE_CHANGE ********************************/
975 /* Someone changed a user's mode on a channel */
977 SILC_FSM_STATE(silc_client_notify_cumode_change)
979 SilcClientConnection conn = fsm_context;
980 SilcClient client = conn->client;
981 SilcClientNotify notify = state_context;
982 SilcNotifyPayload payload = notify->payload;
983 SilcPacket packet = notify->packet;
984 SilcNotifyType type = silc_notify_get_type(payload);
985 SilcArgumentPayload args = silc_notify_get_args(payload);
986 SilcClientEntry client_entry = NULL, client_entry2 = NULL;
987 SilcChannelEntry channel = NULL, channel_entry = NULL;
988 SilcServerEntry server = NULL;
992 SilcUInt32 tmp_len, mode;
995 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
997 /* Get channel entry */
998 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
999 &id.u.channel_id, sizeof(id.u.channel_id)))
1001 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1005 /* If channel is being resolved handle notify after resolving */
1006 if (channel->internal.resolve_cmd_ident) {
1007 silc_client_unref_channel(client, conn, channel);
1008 SILC_FSM_CALL(silc_client_command_pending(
1009 conn, SILC_COMMAND_NONE,
1010 channel->internal.resolve_cmd_ident,
1011 silc_client_notify_wait_continue,
1016 /* Get target Client ID */
1017 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id2, NULL))
1020 /* Find target Client entry */
1021 client_entry2 = silc_client_get_client_by_id(client, conn, &id2.u.client_id);
1022 if (!client_entry2 || !client_entry2->internal.valid) {
1023 /** Resolve client */
1024 silc_client_unref_client(client, conn, client_entry2);
1025 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1026 client, conn, &id2.u.client_id, NULL,
1027 silc_client_notify_resolved,
1032 /* If target client is not on channel, ignore this notify */
1033 if (!silc_client_on_channel(channel, client_entry2))
1037 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1040 SILC_GET32_MSB(mode, tmp);
1042 /* Get ID of mode changer */
1043 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1046 if (id.type == SILC_ID_CLIENT) {
1047 /* Find Client entry */
1048 client_entry = notify->client_entry;
1049 if (!client_entry) {
1050 client_entry = silc_client_get_client(client, conn, &id.u.client_id);
1051 if (!client_entry || !client_entry->internal.valid) {
1052 /** Resolve client */
1053 notify->channel = channel;
1054 notify->client_entry = client_entry;
1055 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1056 silc_client_get_client_by_id_resolve(
1057 client, conn, &id.u.client_id, NULL,
1058 silc_client_notify_resolved,
1064 /* If client is not on channel, ignore this notify */
1065 if (!silc_client_on_channel(channel, client_entry))
1068 entry = client_entry;
1069 } else if (id.type == SILC_ID_SERVER) {
1070 /* Find Server entry */
1071 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1073 /** Resolve server */
1074 notify->channel = channel;
1075 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1076 silc_client_get_server_by_id_resolve(
1077 client, conn, &id.u.server_id,
1078 silc_client_notify_resolved,
1084 /* Find Channel entry */
1085 channel_entry = silc_client_get_channel_by_id(client, conn,
1087 if (!channel_entry) {
1088 /** Resolve channel */
1089 notify->channel = channel;
1090 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1091 silc_client_get_channel_by_id_resolve(
1092 client, conn, &id.u.channel_id,
1093 silc_client_notify_resolved,
1097 entry = channel_entry;
1101 silc_rwlock_wrlock(channel->internal.lock);
1102 chu = silc_client_on_channel(channel, client_entry2);
1105 silc_rwlock_unlock(channel->internal.lock);
1107 /* Notify application. */
1108 NOTIFY(client, conn, type, id.type, entry, mode, client_entry2, channel);
1111 silc_client_unref_client(client, conn, client_entry2);
1113 silc_client_unref_client(client, conn, client_entry);
1115 silc_client_unref_server(client, conn, server);
1117 silc_client_unref_channel(client, conn, channel_entry);
1118 silc_client_unref_channel(client, conn, channel);
1120 /** Notify processed */
1121 silc_fsm_next(fsm, silc_client_notify_processed);
1122 return SILC_FSM_CONTINUE;
1125 /********************************* MOTD *************************************/
1127 /* Received Message of the day */
1129 SILC_FSM_STATE(silc_client_notify_motd)
1131 SilcClientConnection conn = fsm_context;
1132 SilcClient client = conn->client;
1133 SilcClientNotify notify = state_context;
1134 SilcNotifyPayload payload = notify->payload;
1135 SilcNotifyType type = silc_notify_get_type(payload);
1136 SilcArgumentPayload args = silc_notify_get_args(payload);
1140 SILC_LOG_DEBUG(("Notify: MOTD"));
1143 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1147 /* Notify application */
1148 NOTIFY(client, conn, type, tmp);
1151 /** Notify processed */
1152 silc_fsm_next(fsm, silc_client_notify_processed);
1153 return SILC_FSM_CONTINUE;
1156 /**************************** CHANNEL CHANGE ********************************/
1158 /* Router has enforced a new ID to a channel, change it */
1160 SILC_FSM_STATE(silc_client_notify_channel_change)
1162 SilcClientConnection conn = fsm_context;
1163 SilcClient client = conn->client;
1164 SilcClientNotify notify = state_context;
1165 SilcNotifyPayload payload = notify->payload;
1166 SilcNotifyType type = silc_notify_get_type(payload);
1167 SilcArgumentPayload args = silc_notify_get_args(payload);
1168 SilcChannelEntry channel = NULL;
1171 SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
1173 /* Get the old ID */
1174 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1177 /* Get the channel entry */
1178 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1182 /* If channel is being resolved handle notify after resolving */
1183 if (channel->internal.resolve_cmd_ident) {
1184 silc_client_unref_channel(client, conn, channel);
1185 SILC_FSM_CALL(silc_client_command_pending(
1186 conn, SILC_COMMAND_NONE,
1187 channel->internal.resolve_cmd_ident,
1188 silc_client_notify_wait_continue,
1193 /* Get the new ID */
1194 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
1197 /* Replace the Channel ID */
1198 if (!silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id))
1201 /* Notify application */
1202 NOTIFY(client, conn, type, channel, channel);
1205 /** Notify processed */
1206 silc_client_unref_channel(client, conn, channel);
1207 silc_fsm_next(fsm, silc_client_notify_processed);
1208 return SILC_FSM_CONTINUE;
1211 /******************************** KICKED ************************************/
1213 /* Some client was kicked from a channel */
1215 SILC_FSM_STATE(silc_client_notify_kicked)
1217 SilcClientConnection conn = fsm_context;
1218 SilcClient client = conn->client;
1219 SilcClientNotify notify = state_context;
1220 SilcNotifyPayload payload = notify->payload;
1221 SilcPacket packet = notify->packet;
1222 SilcNotifyType type = silc_notify_get_type(payload);
1223 SilcArgumentPayload args = silc_notify_get_args(payload);
1224 SilcClientEntry client_entry, client_entry2;
1225 SilcChannelEntry channel = NULL;
1230 SILC_LOG_DEBUG(("Notify: KICKED"));
1232 /* Get channel entry */
1233 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
1234 &id.u.channel_id, sizeof(id.u.channel_id)))
1236 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1240 /* If channel is being resolved handle notify after resolving */
1241 if (channel->internal.resolve_cmd_ident) {
1242 silc_client_unref_channel(client, conn, channel);
1243 SILC_FSM_CALL(silc_client_command_pending(
1244 conn, SILC_COMMAND_NONE,
1245 channel->internal.resolve_cmd_ident,
1246 silc_client_notify_wait_continue,
1251 /* Get the kicked Client ID */
1252 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1255 /* Find client entry */
1256 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1260 /* Get kicker's Client ID */
1261 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
1264 /* Find kicker's client entry and if not found resolve it */
1265 client_entry2 = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1266 if (!client_entry2 || !client_entry2->internal.valid) {
1267 /** Resolve client */
1268 silc_client_unref_client(client, conn, client_entry);
1269 silc_client_unref_client(client, conn, client_entry2);
1270 notify->channel = channel;
1271 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1272 silc_client_get_client_by_id_resolve(
1273 client, conn, &id.u.client_id, NULL,
1274 silc_client_notify_resolved,
1280 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1282 /* Remove kicked client from channel */
1283 if (client_entry != conn->local_entry) {
1284 if (!silc_client_remove_from_channel(client, conn, channel, client_entry))
1288 /* Notify application. */
1289 NOTIFY(client, conn, type, client_entry, tmp, client_entry2, channel);
1291 /* If I was kicked from channel, remove the channel */
1292 if (client_entry == conn->local_entry) {
1293 if (conn->current_channel == channel)
1294 conn->current_channel = NULL;
1295 silc_client_empty_channel(client, conn, channel);
1296 silc_client_del_channel(client, conn, channel);
1299 silc_client_unref_client(client, conn, client_entry);
1300 silc_client_unref_client(client, conn, client_entry2);
1303 /** Notify processed */
1304 silc_client_unref_channel(client, conn, channel);
1305 silc_fsm_next(fsm, silc_client_notify_processed);
1306 return SILC_FSM_CONTINUE;
1309 /******************************** KILLED ************************************/
1311 /* Some client was killed from the network */
1313 SILC_FSM_STATE(silc_client_notify_killed)
1315 SilcClientConnection conn = fsm_context;
1316 SilcClient client = conn->client;
1317 SilcClientNotify notify = state_context;
1318 SilcNotifyPayload payload = notify->payload;
1319 SilcNotifyType type = silc_notify_get_type(payload);
1320 SilcArgumentPayload args = silc_notify_get_args(payload);
1321 SilcClientEntry client_entry = NULL, client_entry2 = NULL;
1322 SilcChannelEntry channel_entry = NULL;
1323 SilcServerEntry server = NULL;
1326 SilcUInt32 comment_len;
1329 SILC_LOG_DEBUG(("Notify: KILLED"));
1332 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1335 /* Find Client entry */
1336 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1341 comment = silc_argument_get_arg_type(args, 2, &comment_len);
1343 /* Get killer's ID */
1344 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
1347 if (id.type == SILC_ID_CLIENT) {
1348 /* Find Client entry */
1349 client_entry2 = silc_client_get_client_by_id(client, conn,
1351 if (!client_entry2 || !client_entry2->internal.valid) {
1352 /** Resolve client */
1353 silc_client_unref_client(client, conn, client_entry);
1354 silc_client_unref_client(client, conn, client_entry2);
1355 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1356 client, conn, &id.u.client_id, NULL,
1357 silc_client_notify_resolved,
1361 entry = client_entry2;
1362 } else if (id.type == SILC_ID_SERVER) {
1363 /* Find Server entry */
1364 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1366 /** Resolve server */
1367 SILC_FSM_CALL(silc_client_get_server_by_id_resolve(
1368 client, conn, &id.u.server_id,
1369 silc_client_notify_resolved,
1375 /* Find Channel entry */
1376 channel_entry = silc_client_get_channel_by_id(client, conn,
1378 if (!channel_entry) {
1379 /** Resolve channel */
1380 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1381 client, conn, &id.u.channel_id,
1382 silc_client_notify_resolved,
1386 entry = channel_entry;
1389 /* Notify application. */
1390 NOTIFY(client, conn, type, client_entry, comment, id.type, entry);
1392 /* Delete the killed client */
1393 if (client_entry != conn->local_entry) {
1394 silc_client_remove_from_channels(client, conn, client_entry);
1395 client_entry->internal.valid = FALSE;
1396 silc_client_del_client(client, conn, client_entry);
1400 silc_client_unref_client(client, conn, client_entry);
1402 silc_client_unref_client(client, conn, client_entry2);
1404 silc_client_unref_server(client, conn, server);
1406 silc_client_unref_channel(client, conn, channel_entry);
1408 /** Notify processed */
1409 silc_fsm_next(fsm, silc_client_notify_processed);
1410 return SILC_FSM_CONTINUE;
1413 /**************************** SERVER SIGNOFF ********************************/
1415 /* Some server quit SILC network. Remove its clients from channels. */
1417 SILC_FSM_STATE(silc_client_notify_server_signoff)
1419 SilcClientConnection conn = fsm_context;
1420 SilcClient client = conn->client;
1421 SilcClientNotify notify = state_context;
1422 SilcNotifyPayload payload = notify->payload;
1423 SilcNotifyType type = silc_notify_get_type(payload);
1424 SilcArgumentPayload args = silc_notify_get_args(payload);
1425 SilcClientEntry client_entry;
1426 SilcServerEntry server_entry = NULL;
1431 SILC_LOG_DEBUG(("Notify: SERVER_SIGNOFF"));
1433 clients = silc_dlist_init();
1438 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1441 /* Get server, in case we have it cached */
1442 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1444 for (i = 1; i < silc_argument_get_arg_num(args); i++) {
1446 if (!silc_argument_get_decoded(args, i + 1, SILC_ARGUMENT_ID, &id, NULL))
1449 /* Get the client entry */
1450 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1451 if (client_entry && client_entry->internal.valid)
1452 silc_dlist_add(clients, client_entry);
1455 /* Notify application. */
1456 NOTIFY(client, conn, type, server_entry, clients);
1458 /* Delete the clients */
1459 silc_dlist_start(clients);
1460 while ((client_entry = silc_dlist_get(clients))) {
1461 silc_client_remove_from_channels(client, conn, client_entry);
1462 client_entry->internal.valid = FALSE;
1463 silc_client_del_client(client, conn, client_entry);
1467 /** Notify processed */
1468 silc_client_unref_server(client, conn, server_entry);
1469 silc_client_list_free(client, conn, clients);
1470 silc_fsm_next(fsm, silc_client_notify_processed);
1471 return SILC_FSM_CONTINUE;
1474 /******************************** ERROR *************************************/
1476 /* Some error occurred */
1478 SILC_FSM_STATE(silc_client_notify_error)
1480 SilcClientConnection conn = fsm_context;
1481 SilcClient client = conn->client;
1482 SilcClientNotify notify = state_context;
1483 SilcNotifyPayload payload = notify->payload;
1484 SilcNotifyType type = silc_notify_get_type(payload);
1485 SilcArgumentPayload args = silc_notify_get_args(payload);
1486 SilcClientEntry client_entry;
1493 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1494 if (!tmp || tmp_len != 1)
1496 error = (SilcStatus)tmp[0];
1498 SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1500 /* Handle the error */
1501 if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1502 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
1504 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1505 if (client_entry && client_entry != conn->local_entry) {
1506 silc_client_remove_from_channels(client, conn, client_entry);
1507 silc_client_del_client(client, conn, client_entry);
1508 silc_client_unref_client(client, conn, client_entry);
1512 /* Notify application. */
1513 NOTIFY(client, conn, type, error);
1516 /** Notify processed */
1517 silc_fsm_next(fsm, silc_client_notify_processed);
1518 return SILC_FSM_CONTINUE;
1521 /******************************** WATCH *************************************/
1523 /* Received notify about some client we are watching */
1525 SILC_FSM_STATE(silc_client_notify_watch)
1527 SilcClientConnection conn = fsm_context;
1528 SilcClient client = conn->client;
1529 SilcClientNotify notify = state_context;
1530 SilcNotifyPayload payload = notify->payload;
1531 SilcNotifyType type = silc_notify_get_type(payload);
1532 SilcArgumentPayload args = silc_notify_get_args(payload);
1533 SilcClientEntry client_entry = NULL;
1534 SilcNotifyType ntype = 0;
1535 unsigned char *pk, *tmp;
1536 SilcUInt32 mode, pk_len, tmp_len;
1537 SilcPublicKey public_key = NULL;
1540 SILC_LOG_DEBUG(("Notify: WATCH"));
1542 /* Get sender Client ID */
1543 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1546 /* Find client entry and if not found resolve it */
1547 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1548 if (!client_entry || !client_entry->internal.valid) {
1549 /** Resolve client */
1550 silc_client_unref_client(client, conn, client_entry);
1551 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1552 client, conn, &id.u.client_id, NULL,
1553 silc_client_notify_resolved,
1559 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1560 if (!tmp || tmp_len != 4)
1562 SILC_GET32_MSB(mode, tmp);
1564 /* Get notify type */
1565 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1566 if (tmp && tmp_len != 2)
1569 SILC_GET16_MSB(ntype, tmp);
1572 tmp = silc_argument_get_arg_type(args, 2, NULL);
1574 char *tmp_nick = NULL;
1576 silc_client_nickname_parse(client, conn, client_entry->nickname,
1579 /* If same nick, the client was new to us and has become "present"
1580 to network. Send NULL as nick to application. */
1581 if (tmp_nick && silc_utf8_strcasecmp(tmp, tmp_nick))
1584 silc_free(tmp_nick);
1587 /* Get public key, if present */
1588 pk = silc_argument_get_arg_type(args, 5, &pk_len);
1589 if (pk && !client_entry->public_key) {
1590 if (silc_public_key_payload_decode(pk, pk_len, &public_key)) {
1591 client_entry->public_key = public_key;
1596 /* Notify application. */
1597 NOTIFY(client, conn, type, client_entry, tmp, mode, ntype,
1598 client_entry->public_key);
1600 client_entry->mode = mode;
1602 /* Remove client that left the network. */
1603 if (ntype == SILC_NOTIFY_TYPE_SIGNOFF ||
1604 ntype == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
1605 ntype == SILC_NOTIFY_TYPE_KILLED) {
1606 silc_client_remove_from_channels(client, conn, client_entry);
1607 client_entry->internal.valid = FALSE;
1608 silc_client_del_client(client, conn, client_entry);
1612 silc_pkcs_public_key_free(public_key);
1615 /** Notify processed */
1616 silc_client_unref_client(client, conn, client_entry);
1617 silc_fsm_next(fsm, silc_client_notify_processed);
1618 return SILC_FSM_CONTINUE;