5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2006 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 */
32 SilcNotifyPayload payload;
34 SilcChannelEntry channel;
37 /************************ Static utility functions **************************/
39 /* Entry resolving callback. This will continue processing the notify. */
41 static void silc_client_notify_resolved(SilcClient client,
42 SilcClientConnection conn,
47 SilcClientNotify notify = context;
49 /* If no entries found, just finish the notify processing, a silent error */
51 silc_fsm_next(notify->fsm, silc_client_notify_processed);
53 if (notify->channel) {
54 notify->channel->internal.resolve_cmd_ident = 0;
55 silc_client_unref_channel(client, conn, notify->channel);
58 /* Continue processing the notify */
59 SILC_FSM_CALL_CONTINUE_SYNC(notify->fsm);
62 /* Continue notify processing after it was suspended while waiting for
63 channel information being resolved. */
65 static SilcBool silc_client_notify_wait_continue(SilcClient client,
66 SilcClientConnection conn,
73 SilcClientNotify notify = context;
75 /* Continue after last command reply received */
76 if (SILC_STATUS_IS_ERROR(status) || status == SILC_STATUS_OK ||
77 status == SILC_STATUS_LIST_END)
78 SILC_FSM_CALL_CONTINUE(notify->fsm);
83 /********************************* Notify ***********************************/
85 /* Process received notify packet */
87 SILC_FSM_STATE(silc_client_notify)
89 SilcPacket packet = state_context;
90 SilcClientNotify notify;
91 SilcNotifyPayload payload;
93 payload = silc_notify_payload_parse(silc_buffer_data(&packet->buffer),
94 silc_buffer_len(&packet->buffer));
96 SILC_LOG_DEBUG(("Malformed notify payload"));
97 silc_packet_free(packet);
101 if (!silc_notify_get_args(payload)) {
102 SILC_LOG_DEBUG(("Malformed notify %d", silc_notify_get_type(payload)));
103 silc_notify_payload_free(payload);
104 silc_packet_free(packet);
108 notify = silc_calloc(1, sizeof(*notify));
110 silc_notify_payload_free(payload);
111 silc_packet_free(packet);
115 /* Save notify payload to packet context during processing */
116 notify->packet = packet;
117 notify->payload = payload;
119 silc_fsm_set_state_context(fsm, notify);
121 /* Process the notify */
122 switch (silc_notify_get_type(payload)) {
124 case SILC_NOTIFY_TYPE_NONE:
126 silc_fsm_next(fsm, silc_client_notify_none);
129 case SILC_NOTIFY_TYPE_INVITE:
131 silc_fsm_next(fsm, silc_client_notify_invite);
134 case SILC_NOTIFY_TYPE_JOIN:
136 silc_fsm_next(fsm, silc_client_notify_join);
139 case SILC_NOTIFY_TYPE_LEAVE:
141 silc_fsm_next(fsm, silc_client_notify_leave);
144 case SILC_NOTIFY_TYPE_SIGNOFF:
146 silc_fsm_next(fsm, silc_client_notify_signoff);
149 case SILC_NOTIFY_TYPE_TOPIC_SET:
151 silc_fsm_next(fsm, silc_client_notify_topic_set);
154 case SILC_NOTIFY_TYPE_NICK_CHANGE:
156 silc_fsm_next(fsm, silc_client_notify_nick_change);
159 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
161 silc_fsm_next(fsm, silc_client_notify_cmode_change);
164 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
166 silc_fsm_next(fsm, silc_client_notify_cumode_change);
169 case SILC_NOTIFY_TYPE_MOTD:
171 silc_fsm_next(fsm, silc_client_notify_motd);
174 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
175 /** CHANNEL_CHANGE */
176 silc_fsm_next(fsm, silc_client_notify_channel_change);
179 case SILC_NOTIFY_TYPE_KICKED:
181 silc_fsm_next(fsm, silc_client_notify_kicked);
184 case SILC_NOTIFY_TYPE_KILLED:
186 silc_fsm_next(fsm, silc_client_notify_killed);
189 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
190 /** SERVER_SIGNOFF */
191 silc_fsm_next(fsm, silc_client_notify_server_signoff);
194 case SILC_NOTIFY_TYPE_ERROR:
196 silc_fsm_next(fsm, silc_client_notify_error);
199 case SILC_NOTIFY_TYPE_WATCH:
201 silc_fsm_next(fsm, silc_client_notify_watch);
205 /** Unknown notify */
206 silc_notify_payload_free(payload);
207 silc_packet_free(packet);
216 /* Notify processed, finish the packet processing thread */
218 SILC_FSM_STATE(silc_client_notify_processed)
220 SilcClientNotify notify = state_context;
221 SilcPacket packet = notify->packet;
222 SilcNotifyPayload payload = notify->payload;
224 silc_notify_payload_free(payload);
225 silc_packet_free(packet);
230 /********************************** NONE ************************************/
232 SILC_FSM_STATE(silc_client_notify_none)
234 SilcClientConnection conn = fsm_context;
235 SilcClient client = conn->client;
236 SilcClientNotify notify = state_context;
237 SilcNotifyPayload payload = notify->payload;
238 SilcNotifyType type = silc_notify_get_type(payload);
239 SilcArgumentPayload args = silc_notify_get_args(payload);
241 SILC_LOG_DEBUG(("Notify: NONE"));
243 /* Notify application */
244 NOTIFY(client, conn, type, silc_argument_get_arg_type(args, 1, NULL));
246 /** Notify processed */
247 silc_fsm_next(fsm, silc_client_notify_processed);
251 /********************************* INVITE ***********************************/
253 /* Someone invite me to a channel */
255 SILC_FSM_STATE(silc_client_notify_invite)
257 SilcClientConnection conn = fsm_context;
258 SilcClient client = conn->client;
259 SilcClientNotify notify = state_context;
260 SilcNotifyPayload payload = notify->payload;
261 SilcNotifyType type = silc_notify_get_type(payload);
262 SilcArgumentPayload args = silc_notify_get_args(payload);
263 SilcClientEntry client_entry;
264 SilcChannelEntry channel = NULL;
269 SILC_LOG_DEBUG(("Notify: INVITE"));
272 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
275 /* Get the channel name */
276 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
280 /* Get the channel entry */
281 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
285 /* If channel is being resolved handle notify after resolving */
286 if (channel->internal.resolve_cmd_ident) {
287 silc_client_unref_channel(client, conn, channel);
288 SILC_FSM_CALL(silc_client_command_pending(
289 conn, SILC_COMMAND_NONE,
290 channel->internal.resolve_cmd_ident,
291 silc_client_notify_wait_continue,
296 /* Get sender Client ID */
297 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
300 /* Find Client entry and if not found query it */
301 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
302 if (!client_entry || !client_entry->nickname[0]) {
303 /** Resolve client */
304 silc_client_unref_client(client, conn, client_entry);
305 notify->channel = channel;
306 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
307 silc_client_get_client_by_id_resolve(
308 client, conn, &id.u.client_id, NULL,
309 silc_client_notify_resolved,
314 /* Notify application */
315 NOTIFY(client, conn, type, channel, tmp, client_entry);
317 silc_client_unref_client(client, conn, client_entry);
320 /** Notify processed */
321 silc_client_unref_channel(client, conn, channel);
322 silc_fsm_next(fsm, silc_client_notify_processed);
326 /********************************** JOIN ************************************/
328 /* Someone joined a channel */
330 SILC_FSM_STATE(silc_client_notify_join)
332 SilcClientConnection conn = fsm_context;
333 SilcClient client = conn->client;
334 SilcClientNotify notify = state_context;
335 SilcNotifyPayload payload = notify->payload;
336 SilcNotifyType type = silc_notify_get_type(payload);
337 SilcArgumentPayload args = silc_notify_get_args(payload);
338 SilcClientEntry client_entry;
339 SilcChannelEntry channel = NULL;
342 SILC_LOG_DEBUG(("Notify: JOIN"));
345 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
348 /* Get channel entry */
349 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
353 /* If channel is being resolved handle notify after resolving */
354 if (channel->internal.resolve_cmd_ident) {
355 silc_client_unref_channel(client, conn, channel);
356 SILC_FSM_CALL(silc_client_command_pending(
357 conn, SILC_COMMAND_NONE,
358 channel->internal.resolve_cmd_ident,
359 silc_client_notify_wait_continue,
365 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
368 /* Find Client entry and if not found query it */
369 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
370 if (!client_entry || !client_entry->nickname[0] ||
371 !client_entry->username[0]) {
372 /** Resolve client */
373 silc_client_unref_client(client, conn, client_entry);
374 notify->channel = channel;
375 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
376 silc_client_get_client_by_id_resolve(
377 client, conn, &id.u.client_id, NULL,
378 silc_client_notify_resolved,
383 if (client_entry != conn->local_entry)
384 silc_client_nickname_format(client, conn, client_entry, FALSE);
386 /* Join the client to channel */
387 if (!silc_client_add_to_channel(client, conn, channel, client_entry, 0))
390 /* Notify application. */
391 NOTIFY(client, conn, type, client_entry, channel);
393 silc_client_unref_client(client, conn, client_entry);
396 /** Notify processed */
397 silc_client_unref_channel(client, conn, channel);
398 silc_fsm_next(fsm, silc_client_notify_processed);
402 /********************************** LEAVE ***********************************/
404 /* Someone left a channel */
406 SILC_FSM_STATE(silc_client_notify_leave)
408 SilcClientConnection conn = fsm_context;
409 SilcClient client = conn->client;
410 SilcClientNotify notify = state_context;
411 SilcNotifyPayload payload = notify->payload;
412 SilcPacket packet = notify->packet;
413 SilcNotifyType type = silc_notify_get_type(payload);
414 SilcArgumentPayload args = silc_notify_get_args(payload);
415 SilcClientEntry client_entry = NULL;
416 SilcChannelEntry channel = NULL;
419 SILC_LOG_DEBUG(("Notify: LEAVE"));
421 /* Get channel entry */
422 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
423 &id.u.channel_id, sizeof(id.u.channel_id)))
425 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
429 /* If channel is being resolved handle notify after resolving */
430 if (channel->internal.resolve_cmd_ident) {
431 silc_client_unref_channel(client, conn, channel);
432 SILC_FSM_CALL(silc_client_command_pending(
433 conn, SILC_COMMAND_NONE,
434 channel->internal.resolve_cmd_ident,
435 silc_client_notify_wait_continue,
441 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
444 /* Find Client entry */
445 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
449 /* Remove client from channel */
450 silc_client_remove_from_channel(client, conn, channel, client_entry);
452 /* Notify application. */
453 NOTIFY(client, conn, type, client_entry, channel);
455 silc_client_unref_client(client, conn, client_entry);
458 /** Notify processed */
459 silc_client_unref_channel(client, conn, channel);
460 silc_fsm_next(fsm, silc_client_notify_processed);
464 /********************************* SIGNOFF **********************************/
466 /* Someone quit SILC network */
468 SILC_FSM_STATE(silc_client_notify_signoff)
470 SilcClientConnection conn = fsm_context;
471 SilcClient client = conn->client;
472 SilcClientNotify notify = state_context;
473 SilcNotifyPayload payload = notify->payload;
474 SilcNotifyType type = silc_notify_get_type(payload);
475 SilcArgumentPayload args = silc_notify_get_args(payload);
476 SilcClientEntry client_entry;
481 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
484 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
487 /* Find Client entry */
488 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
492 /* Get signoff message */
493 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
494 if (tmp && tmp_len > 128)
497 /* Notify application */
498 NOTIFY(client, conn, type, client_entry, tmp);
501 silc_client_remove_from_channels(client, conn, client_entry);
502 silc_client_del_client(client, conn, client_entry);
503 silc_client_unref_client(client, conn, client_entry);
506 /** Notify processed */
507 silc_fsm_next(fsm, silc_client_notify_processed);
511 /******************************** TOPIC_SET *********************************/
513 /* Someone set topic on a channel */
515 SILC_FSM_STATE(silc_client_notify_topic_set)
517 SilcClientConnection conn = fsm_context;
518 SilcClient client = conn->client;
519 SilcClientNotify notify = state_context;
520 SilcNotifyPayload payload = notify->payload;
521 SilcPacket packet = notify->packet;
522 SilcNotifyType type = silc_notify_get_type(payload);
523 SilcArgumentPayload args = silc_notify_get_args(payload);
524 SilcClientEntry client_entry = NULL;
525 SilcChannelEntry channel = NULL, channel_entry = NULL;
526 SilcServerEntry server = NULL;
532 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
534 /* Get channel entry */
535 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
536 &id.u.channel_id, sizeof(id.u.channel_id)))
538 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
542 /* If channel is being resolved handle notify after resolving */
543 if (channel->internal.resolve_cmd_ident) {
544 silc_client_unref_channel(client, conn, channel);
545 SILC_FSM_CALL(silc_client_command_pending(
546 conn, SILC_COMMAND_NONE,
547 channel->internal.resolve_cmd_ident,
548 silc_client_notify_wait_continue,
554 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
558 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
562 if (id.type == SILC_ID_CLIENT) {
563 /* Find Client entry */
564 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
565 if (!client_entry || !client_entry->nickname[0]) {
566 /** Resolve client */
567 silc_client_unref_client(client, conn, client_entry);
568 notify->channel = channel;
569 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
570 silc_client_get_client_by_id_resolve(
571 client, conn, &id.u.client_id, NULL,
572 silc_client_notify_resolved,
576 entry = client_entry;
577 } else if (id.type == SILC_ID_SERVER) {
578 /* Find Server entry */
579 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
581 /** Resolve server */
582 notify->channel = channel;
583 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
584 silc_client_get_server_by_id_resolve(
585 client, conn, &id.u.server_id,
586 silc_client_notify_resolved,
592 /* Find Channel entry */
593 channel_entry = silc_client_get_channel_by_id(client, conn,
595 if (!channel_entry) {
596 /** Resolve channel */
597 notify->channel = channel;
598 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
599 silc_client_get_channel_by_id_resolve(
600 client, conn, &id.u.channel_id,
601 silc_client_notify_resolved,
605 entry = channel_entry;
608 silc_free(channel->topic);
609 channel->topic = silc_memdup(tmp, strlen(tmp));
611 /* Notify application. */
612 NOTIFY(client, conn, type, id.type, entry, channel->topic, channel);
615 silc_client_unref_client(client, conn, client_entry);
617 silc_client_unref_server(client, conn, server);
619 silc_client_unref_channel(client, conn, channel_entry);
622 /** Notify processed */
623 silc_client_unref_channel(client, conn, channel);
624 silc_fsm_next(fsm, silc_client_notify_processed);
628 /****************************** NICK_CHANGE *********************************/
630 /* Someone changed their nickname on a channel */
632 SILC_FSM_STATE(silc_client_notify_nick_change)
634 SilcClientConnection conn = fsm_context;
635 SilcClient client = conn->client;
636 SilcClientNotify notify = state_context;
637 SilcNotifyPayload payload = notify->payload;
638 SilcNotifyType type = silc_notify_get_type(payload);
639 SilcArgumentPayload args = silc_notify_get_args(payload);
640 SilcClientEntry client_entry = NULL;
641 unsigned char *tmp, oldnick[128 + 1];
645 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
648 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
652 if (conn->local_id &&
653 SILC_ID_CLIENT_COMPARE(&id.u.client_id, conn->local_id))
656 /* Get new Client ID */
657 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id2, NULL))
661 if (conn->local_id &&
662 SILC_ID_CLIENT_COMPARE(&id2.u.client_id, conn->local_id))
665 /* Find old Client entry */
666 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
667 if (!client_entry || !client_entry->nickname[0]) {
668 /** Resolve client */
669 silc_client_unref_client(client, conn, client_entry);
670 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
671 client, conn, &id.u.client_id, NULL,
672 silc_client_notify_resolved,
677 /* Take the new nickname */
678 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
682 /* Check whether nickname changed at all. It is possible that nick
683 change notify is received but nickname didn't change, only the
684 ID changes. If Client ID hash match, nickname didn't change. */
685 if (SILC_ID_COMPARE_HASH(&client_entry->id, &id2.u.client_id) &&
686 silc_utf8_strcasecmp(tmp, client_entry->nickname)) {
687 /* Nickname didn't change. Update only Client ID. We don't notify
688 application because nickname didn't change. */
689 silc_mutex_lock(conn->internal->lock);
690 silc_idcache_update_by_context(conn->internal->client_cache, client_entry,
691 &id2.u.client_id, NULL, FALSE);
692 silc_mutex_unlock(conn->internal->lock);
696 /* Change the nickname */
697 memcpy(oldnick, client_entry->nickname, sizeof(client_entry->nickname));
698 if (!silc_client_change_nickname(client, conn, client_entry, tmp,
699 &id2.u.client_id, NULL, 0))
702 /* Notify application */
703 NOTIFY(client, conn, type, client_entry, client_entry->nickname, oldnick);
706 /** Notify processed */
707 silc_client_unref_client(client, conn, client_entry);
708 silc_fsm_next(fsm, silc_client_notify_processed);
712 /****************************** CMODE_CHANGE ********************************/
714 /* Someone changed channel mode */
716 SILC_FSM_STATE(silc_client_notify_cmode_change)
718 SilcClientConnection conn = fsm_context;
719 SilcClient client = conn->client;
720 SilcClientNotify notify = state_context;
721 SilcNotifyPayload payload = notify->payload;
722 SilcPacket packet = notify->packet;
723 SilcNotifyType type = silc_notify_get_type(payload);
724 SilcArgumentPayload args = silc_notify_get_args(payload);
725 SilcClientEntry client_entry = NULL;
726 SilcChannelEntry channel = NULL, channel_entry = NULL;
727 SilcServerEntry server = NULL;
730 SilcUInt32 tmp_len, mode;
732 char *passphrase, *cipher, *hmac;
733 SilcPublicKey founder_key = NULL;
734 SilcDList chpks = NULL;
736 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
738 /* Get channel entry */
739 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
740 &id.u.channel_id, sizeof(id.u.channel_id)))
742 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
746 /* If channel is being resolved handle notify after resolving */
747 if (channel->internal.resolve_cmd_ident) {
748 silc_client_unref_channel(client, conn, channel);
749 SILC_FSM_CALL(silc_client_command_pending(
750 conn, SILC_COMMAND_NONE,
751 channel->internal.resolve_cmd_ident,
752 silc_client_notify_wait_continue,
758 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
761 SILC_GET32_MSB(mode, tmp);
764 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
767 if (id.type == SILC_ID_CLIENT) {
768 /* Find Client entry */
769 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
770 if (!client_entry || !client_entry->nickname[0]) {
771 /** Resolve client */
772 silc_client_unref_client(client, conn, client_entry);
773 notify->channel = channel;
774 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
775 silc_client_get_client_by_id_resolve(
776 client, conn, &id.u.client_id, NULL,
777 silc_client_notify_resolved,
781 entry = client_entry;
782 } else if (id.type == SILC_ID_SERVER) {
783 /* Find Server entry */
784 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
786 /** Resolve server */
787 notify->channel = channel;
788 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
789 silc_client_get_server_by_id_resolve(
790 client, conn, &id.u.server_id,
791 silc_client_notify_resolved,
797 /* Find Channel entry */
798 channel_entry = silc_client_get_channel_by_id(client, conn,
800 if (!channel_entry) {
801 /** Resolve channel */
802 notify->channel = channel;
803 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
804 silc_client_get_channel_by_id_resolve(
805 client, conn, &id.u.channel_id,
806 silc_client_notify_resolved,
810 entry = channel_entry;
813 /* Get the channel founder key if it was set */
814 tmp = silc_argument_get_arg_type(args, 6, &tmp_len);
816 if (!silc_public_key_payload_decode(tmp, tmp_len, &founder_key))
818 if (!channel->founder_key) {
819 channel->founder_key = founder_key;
825 cipher = silc_argument_get_arg_type(args, 3, &tmp_len);
828 hmac = silc_argument_get_arg_type(args, 4, &tmp_len);
830 unsigned char hash[SILC_HASH_MAXLEN];
833 if (!silc_hmac_alloc(hmac, NULL, &newhmac))
836 /* Get HMAC key from the old HMAC context, and update it to the new one */
837 tmp = (unsigned char *)silc_hmac_get_key(channel->internal.hmac, &tmp_len);
839 silc_hash_make(silc_hmac_get_hash(newhmac), tmp, tmp_len, hash);
840 silc_hmac_set_key(newhmac, hash,
841 silc_hash_len(silc_hmac_get_hash(newhmac)));
842 if (channel->internal.hmac)
843 silc_hmac_free(channel->internal.hmac);
844 channel->internal.hmac = newhmac;
845 memset(hash, 0, sizeof(hash));
849 /* Get the passphrase if it was set */
850 passphrase = silc_argument_get_arg_type(args, 5, &tmp_len);
853 tmp = silc_argument_get_arg_type(args, 8, &tmp_len);
854 if (tmp && tmp_len == 4)
855 SILC_GET32_MSB(channel->user_limit, tmp);
856 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
857 channel->user_limit = 0;
859 /* Save the new mode */
860 channel->mode = mode;
862 /* Get the channel public key that was added or removed */
863 tmp = silc_argument_get_arg_type(args, 7, &tmp_len);
865 chpks = silc_argument_list_parse_decoded(tmp, tmp_len,
866 SILC_ARGUMENT_PUBLIC_KEY);
868 /* XXX add to/remove from channel pubkeys channel->channel_pubkeys */
870 /* Notify application. */
871 NOTIFY(client, conn, type, id.type, entry, mode, cipher, hmac,
872 passphrase, channel->founder_key, chpks, channel);
876 silc_pkcs_public_key_free(founder_key);
878 silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
880 silc_client_unref_client(client, conn, client_entry);
882 silc_client_unref_server(client, conn, server);
884 silc_client_unref_channel(client, conn, channel_entry);
885 silc_client_unref_channel(client, conn, channel);
887 /** Notify processed */
888 silc_fsm_next(fsm, silc_client_notify_processed);
892 /***************************** CUMODE_CHANGE ********************************/
894 /* Someone changed a user's mode on a channel */
896 SILC_FSM_STATE(silc_client_notify_cumode_change)
898 SilcClientConnection conn = fsm_context;
899 SilcClient client = conn->client;
900 SilcClientNotify notify = state_context;
901 SilcNotifyPayload payload = notify->payload;
902 SilcPacket packet = notify->packet;
903 SilcNotifyType type = silc_notify_get_type(payload);
904 SilcArgumentPayload args = silc_notify_get_args(payload);
905 SilcClientEntry client_entry = NULL, client_entry2 = NULL;
906 SilcChannelEntry channel = NULL, channel_entry = NULL;
907 SilcServerEntry server = NULL;
911 SilcUInt32 tmp_len, mode;
914 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
916 /* Get channel entry */
917 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
918 &id.u.channel_id, sizeof(id.u.channel_id)))
920 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
924 /* If channel is being resolved handle notify after resolving */
925 if (channel->internal.resolve_cmd_ident) {
926 silc_client_unref_channel(client, conn, channel);
927 SILC_FSM_CALL(silc_client_command_pending(
928 conn, SILC_COMMAND_NONE,
929 channel->internal.resolve_cmd_ident,
930 silc_client_notify_wait_continue,
935 /* Get target Client ID */
936 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id2, NULL))
939 /* Find target Client entry */
940 client_entry2 = silc_client_get_client_by_id(client, conn, &id2.u.client_id);
941 if (!client_entry2 || !client_entry2->nickname[0]) {
942 /** Resolve client */
943 silc_client_unref_client(client, conn, client_entry2);
944 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
945 client, conn, &id2.u.client_id, NULL,
946 silc_client_notify_resolved,
952 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
955 SILC_GET32_MSB(mode, tmp);
958 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
961 if (id.type == SILC_ID_CLIENT) {
962 /* Find Client entry */
963 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
964 if (!client_entry || !client_entry->nickname[0]) {
965 /** Resolve client */
966 silc_client_unref_client(client, conn, client_entry);
967 notify->channel = channel;
968 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
969 silc_client_get_client_by_id_resolve(
970 client, conn, &id.u.client_id, NULL,
971 silc_client_notify_resolved,
975 entry = client_entry;
976 } else if (id.type == SILC_ID_SERVER) {
977 /* Find Server entry */
978 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
980 /** Resolve server */
981 notify->channel = channel;
982 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
983 silc_client_get_server_by_id_resolve(
984 client, conn, &id.u.server_id,
985 silc_client_notify_resolved,
991 /* Find Channel entry */
992 channel_entry = silc_client_get_channel_by_id(client, conn,
994 if (!channel_entry) {
995 /** Resolve channel */
996 notify->channel = channel;
997 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
998 silc_client_get_channel_by_id_resolve(
999 client, conn, &id.u.channel_id,
1000 silc_client_notify_resolved,
1004 entry = channel_entry;
1008 chu = silc_client_on_channel(channel, client_entry2);
1012 /* Notify application. */
1013 NOTIFY(client, conn, type, id.type, entry, mode, client_entry2, channel);
1016 silc_client_unref_client(client, conn, client_entry2);
1018 silc_client_unref_client(client, conn, client_entry);
1020 silc_client_unref_server(client, conn, server);
1022 silc_client_unref_channel(client, conn, channel_entry);
1023 silc_client_unref_channel(client, conn, channel);
1025 /** Notify processed */
1026 silc_fsm_next(fsm, silc_client_notify_processed);
1030 /********************************* MOTD *************************************/
1032 /* Received Message of the day */
1034 SILC_FSM_STATE(silc_client_notify_motd)
1036 SilcClientConnection conn = fsm_context;
1037 SilcClient client = conn->client;
1038 SilcClientNotify notify = state_context;
1039 SilcNotifyPayload payload = notify->payload;
1040 SilcNotifyType type = silc_notify_get_type(payload);
1041 SilcArgumentPayload args = silc_notify_get_args(payload);
1045 SILC_LOG_DEBUG(("Notify: MOTD"));
1048 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1052 /* Notify application */
1053 NOTIFY(client, conn, type, tmp);
1056 /** Notify processed */
1057 silc_fsm_next(fsm, silc_client_notify_processed);
1061 /**************************** CHANNEL CHANGE ********************************/
1063 /* Router has enforced a new ID to a channel, change it */
1065 SILC_FSM_STATE(silc_client_notify_channel_change)
1067 SilcClientConnection conn = fsm_context;
1068 SilcClient client = conn->client;
1069 SilcClientNotify notify = state_context;
1070 SilcNotifyPayload payload = notify->payload;
1071 SilcNotifyType type = silc_notify_get_type(payload);
1072 SilcArgumentPayload args = silc_notify_get_args(payload);
1073 SilcChannelEntry channel = NULL;
1076 SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
1078 /* Get the old ID */
1079 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1082 /* Get the channel entry */
1083 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1087 /* If channel is being resolved handle notify after resolving */
1088 if (channel->internal.resolve_cmd_ident) {
1089 silc_client_unref_channel(client, conn, channel);
1090 SILC_FSM_CALL(silc_client_command_pending(
1091 conn, SILC_COMMAND_NONE,
1092 channel->internal.resolve_cmd_ident,
1093 silc_client_notify_wait_continue,
1098 /* Get the new ID */
1099 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
1102 /* Replace the Channel ID */
1103 if (!silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id))
1106 /* Notify application */
1107 NOTIFY(client, conn, type, channel, channel);
1110 /** Notify processed */
1111 silc_client_unref_channel(client, conn, channel);
1112 silc_fsm_next(fsm, silc_client_notify_processed);
1116 /******************************** KICKED ************************************/
1118 /* Some client was kicked from a channel */
1120 SILC_FSM_STATE(silc_client_notify_kicked)
1122 SilcClientConnection conn = fsm_context;
1123 SilcClient client = conn->client;
1124 SilcClientNotify notify = state_context;
1125 SilcNotifyPayload payload = notify->payload;
1126 SilcPacket packet = notify->packet;
1127 SilcNotifyType type = silc_notify_get_type(payload);
1128 SilcArgumentPayload args = silc_notify_get_args(payload);
1129 SilcClientEntry client_entry, client_entry2;
1130 SilcChannelEntry channel = NULL;
1135 SILC_LOG_DEBUG(("Notify: KICKED"));
1137 /* Get channel entry */
1138 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
1139 &id.u.channel_id, sizeof(id.u.channel_id)))
1141 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1145 /* If channel is being resolved handle notify after resolving */
1146 if (channel->internal.resolve_cmd_ident) {
1147 silc_client_unref_channel(client, conn, channel);
1148 SILC_FSM_CALL(silc_client_command_pending(
1149 conn, SILC_COMMAND_NONE,
1150 channel->internal.resolve_cmd_ident,
1151 silc_client_notify_wait_continue,
1157 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1160 /* Find Client entry */
1161 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1165 /* Get kicker's Client ID */
1166 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
1169 /* Find kicker's client entry and if not found resolve it */
1170 client_entry2 = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1171 if (!client_entry2 || !client_entry2->nickname[0]) {
1172 /** Resolve client */
1173 silc_client_unref_client(client, conn, client_entry);
1174 silc_client_unref_client(client, conn, client_entry2);
1175 notify->channel = channel;
1176 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1177 silc_client_get_client_by_id_resolve(
1178 client, conn, &id.u.client_id, NULL,
1179 silc_client_notify_resolved,
1185 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1187 /* Remove kicked client from channel */
1188 if (client_entry != conn->local_entry)
1189 silc_client_remove_from_channel(client, conn, channel, client_entry);
1191 /* Notify application. */
1192 NOTIFY(client, conn, type, client_entry, tmp, client_entry2, channel);
1194 /* If I was kicked from channel, remove the channel */
1195 if (client_entry == conn->local_entry) {
1196 if (conn->current_channel == channel)
1197 conn->current_channel = NULL;
1198 silc_client_empty_channel(client, conn, channel);
1199 silc_client_del_channel(client, conn, channel);
1202 silc_client_unref_client(client, conn, client_entry);
1203 silc_client_unref_client(client, conn, client_entry2);
1206 /** Notify processed */
1207 silc_client_unref_channel(client, conn, channel);
1208 silc_fsm_next(fsm, silc_client_notify_processed);
1212 /******************************** KILLED ************************************/
1214 /* Some client was killed from the network */
1216 SILC_FSM_STATE(silc_client_notify_killed)
1218 SilcClientConnection conn = fsm_context;
1219 SilcClient client = conn->client;
1220 SilcClientNotify notify = state_context;
1221 SilcNotifyPayload payload = notify->payload;
1222 SilcNotifyType type = silc_notify_get_type(payload);
1223 SilcArgumentPayload args = silc_notify_get_args(payload);
1224 SilcClientEntry client_entry = NULL, client_entry2 = NULL;
1225 SilcChannelEntry channel_entry = NULL;
1226 SilcServerEntry server = NULL;
1229 SilcUInt32 comment_len;
1232 SILC_LOG_DEBUG(("Notify: KILLED"));
1235 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1238 /* Find Client entry */
1239 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1244 comment = silc_argument_get_arg_type(args, 2, &comment_len);
1246 /* Get killer's ID */
1247 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
1250 if (id.type == SILC_ID_CLIENT) {
1251 /* Find Client entry */
1252 client_entry2 = silc_client_get_client_by_id(client, conn,
1254 if (!client_entry2 || !client_entry2->nickname[0]) {
1255 /** Resolve client */
1256 silc_client_unref_client(client, conn, client_entry);
1257 silc_client_unref_client(client, conn, client_entry2);
1258 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1259 client, conn, &id.u.client_id, NULL,
1260 silc_client_notify_resolved,
1264 entry = client_entry2;
1265 } else if (id.type == SILC_ID_SERVER) {
1266 /* Find Server entry */
1267 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1269 /** Resolve server */
1270 SILC_FSM_CALL(silc_client_get_server_by_id_resolve(
1271 client, conn, &id.u.server_id,
1272 silc_client_notify_resolved,
1278 /* Find Channel entry */
1279 channel_entry = silc_client_get_channel_by_id(client, conn,
1281 if (!channel_entry) {
1282 /** Resolve channel */
1283 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1284 client, conn, &id.u.channel_id,
1285 silc_client_notify_resolved,
1289 entry = channel_entry;
1292 /* Notify application. */
1293 NOTIFY(client, conn, type, client_entry, comment, id.type, entry);
1295 /* Delete the killed client */
1296 if (client_entry != conn->local_entry) {
1297 silc_client_remove_from_channels(client, conn, client_entry);
1298 silc_client_del_client(client, conn, client_entry);
1302 silc_client_unref_client(client, conn, client_entry);
1304 silc_client_unref_client(client, conn, client_entry2);
1306 silc_client_unref_server(client, conn, server);
1308 silc_client_unref_channel(client, conn, channel_entry);
1310 /** Notify processed */
1311 silc_fsm_next(fsm, silc_client_notify_processed);
1315 /**************************** SERVER SIGNOFF ********************************/
1317 /* Some server quit SILC network. Remove its clients from channels. */
1319 SILC_FSM_STATE(silc_client_notify_server_signoff)
1321 SilcClientConnection conn = fsm_context;
1322 SilcClient client = conn->client;
1323 SilcClientNotify notify = state_context;
1324 SilcNotifyPayload payload = notify->payload;
1325 SilcNotifyType type = silc_notify_get_type(payload);
1326 SilcArgumentPayload args = silc_notify_get_args(payload);
1327 SilcClientEntry client_entry;
1332 SILC_LOG_DEBUG(("Notify: SERVER_SIGNOFF"));
1334 clients = silc_dlist_init();
1338 for (i = 1; i < silc_argument_get_arg_num(args); i++) {
1340 if (!silc_argument_get_decoded(args, i + 1, SILC_ARGUMENT_ID, &id, NULL))
1343 /* Get the client entry */
1344 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1346 silc_dlist_add(clients, client_entry);
1349 /* Notify application. We don't keep server entries so the server
1350 entry is returned as NULL. The client's are returned as list. */
1351 NOTIFY(client, conn, type, NULL, clients);
1353 /* Delete the clients */
1354 silc_dlist_start(clients);
1355 while ((client_entry = silc_dlist_get(clients))) {
1356 silc_client_remove_from_channels(client, conn, client_entry);
1357 silc_client_del_client(client, conn, client_entry);
1361 /** Notify processed */
1362 silc_client_list_free(client, conn, clients);
1363 silc_fsm_next(fsm, silc_client_notify_processed);
1367 /******************************** ERROR *************************************/
1369 /* Some error occurred */
1371 SILC_FSM_STATE(silc_client_notify_error)
1373 SilcClientConnection conn = fsm_context;
1374 SilcClient client = conn->client;
1375 SilcClientNotify notify = state_context;
1376 SilcNotifyPayload payload = notify->payload;
1377 SilcNotifyType type = silc_notify_get_type(payload);
1378 SilcArgumentPayload args = silc_notify_get_args(payload);
1379 SilcClientEntry client_entry;
1386 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1387 if (!tmp && tmp_len != 1)
1389 error = (SilcStatus)tmp[0];
1391 SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1393 /* Handle the error */
1394 if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1395 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
1397 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1399 silc_client_remove_from_channels(client, conn, client_entry);
1400 silc_client_del_client(client, conn, client_entry);
1401 silc_client_unref_client(client, conn, client_entry);
1405 /* Notify application. */
1406 NOTIFY(client, conn, type, error);
1409 /** Notify processed */
1410 silc_fsm_next(fsm, silc_client_notify_processed);
1414 /******************************** WATCH *************************************/
1416 /* Received notify about some client we are watching */
1418 SILC_FSM_STATE(silc_client_notify_watch)
1420 SilcClientConnection conn = fsm_context;
1421 SilcClient client = conn->client;
1422 SilcClientNotify notify = state_context;
1423 SilcNotifyPayload payload = notify->payload;
1424 SilcNotifyType type = silc_notify_get_type(payload);
1425 SilcArgumentPayload args = silc_notify_get_args(payload);
1426 SilcClientEntry client_entry = NULL;
1427 SilcNotifyType ntype = 0;
1428 SilcBool del_client = FALSE;
1429 unsigned char *pk, *tmp;
1430 SilcUInt32 mode, pk_len, tmp_len;
1431 SilcPublicKey public_key = NULL;
1434 SILC_LOG_DEBUG(("Notify: WATCH"));
1436 /* Get sender Client ID */
1437 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1440 /* Find Client entry and if not found resolve it */
1441 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1442 if (!client_entry || !client_entry->nickname[0]) {
1443 /** Resolve client */
1444 silc_client_unref_client(client, conn, client_entry);
1445 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1446 client, conn, &id.u.client_id, NULL,
1447 silc_client_notify_resolved,
1453 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1454 if (!tmp || tmp_len != 4)
1456 SILC_GET32_MSB(mode, tmp);
1458 /* Get notify type */
1459 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1460 if (tmp && tmp_len != 2)
1463 SILC_GET16_MSB(ntype, tmp);
1466 tmp = silc_argument_get_arg_type(args, 2, NULL);
1468 char *tmp_nick = NULL;
1470 silc_client_nickname_parse(client, conn, client_entry->nickname,
1473 /* If same nick, the client was new to us and has become "present"
1474 to network. Send NULL as nick to application. */
1475 if (tmp_nick && silc_utf8_strcasecmp(tmp, tmp_nick))
1478 silc_free(tmp_nick);
1481 /* Get public key, if present */
1482 pk = silc_argument_get_arg_type(args, 5, &pk_len);
1483 if (pk && !client_entry->public_key) {
1484 if (silc_public_key_payload_decode(pk, pk_len, &public_key)) {
1485 client_entry->public_key = public_key;
1490 /* Notify application. */
1491 NOTIFY(client, conn, type, client_entry, tmp, mode, ntype,
1492 client_entry->public_key);
1494 client_entry->mode = mode;
1496 /* If nickname was changed, remove the client entry unless the
1497 client is on some channel */
1498 /* XXX, why do we need to remove the client entry?? */
1499 if (tmp && ntype == SILC_NOTIFY_TYPE_NICK_CHANGE &&
1500 !silc_hash_table_count(client_entry->channels))
1502 else if (ntype == SILC_NOTIFY_TYPE_SIGNOFF ||
1503 ntype == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
1504 ntype == SILC_NOTIFY_TYPE_KILLED)
1508 silc_client_remove_from_channels(client, conn, client_entry);
1509 silc_client_del_client(client, conn, client_entry);
1513 silc_pkcs_public_key_free(public_key);
1516 /** Notify processed */
1517 silc_client_unref_client(client, conn, client_entry);
1518 silc_fsm_next(fsm, silc_client_notify_processed);