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);
98 return SILC_FSM_FINISH;
101 if (!silc_notify_get_args(payload)) {
102 SILC_LOG_DEBUG(("Malformed notify"));
103 silc_notify_payload_free(payload);
104 silc_packet_free(packet);
105 return SILC_FSM_FINISH;
108 notify = silc_calloc(1, sizeof(*notify));
110 silc_notify_payload_free(payload);
111 silc_packet_free(packet);
112 return SILC_FSM_FINISH;
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);
209 return SILC_FSM_FINISH;
213 return SILC_FSM_YIELD;
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);
227 return SILC_FSM_FINISH;
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);
248 return SILC_FSM_CONTINUE;
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);
283 /* If channel is being resolved handle notify after resolving */
284 if (channel->internal.resolve_cmd_ident) {
285 silc_client_unref_channel(client, conn, channel);
286 SILC_FSM_CALL(silc_client_command_pending(
287 conn, SILC_COMMAND_NONE,
288 channel->internal.resolve_cmd_ident,
289 silc_client_notify_wait_continue,
294 /* Get sender Client ID */
295 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
298 /* Find Client entry and if not found query it */
299 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
300 if (!client_entry || !client_entry->nickname[0]) {
301 /** Resolve client */
302 silc_client_unref_client(client, conn, client_entry);
303 notify->channel = channel;
304 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
305 silc_client_get_client_by_id_resolve(
306 client, conn, &id.u.client_id, NULL,
307 silc_client_notify_resolved,
312 /* Notify application */
313 NOTIFY(client, conn, type, channel, tmp, client_entry);
315 silc_client_unref_client(client, conn, client_entry);
318 /** Notify processed */
319 silc_client_unref_channel(client, conn, channel);
320 silc_fsm_next(fsm, silc_client_notify_processed);
321 return SILC_FSM_CONTINUE;
324 /********************************** JOIN ************************************/
326 /* Someone joined a channel */
328 SILC_FSM_STATE(silc_client_notify_join)
330 SilcClientConnection conn = fsm_context;
331 SilcClient client = conn->client;
332 SilcClientNotify notify = state_context;
333 SilcNotifyPayload payload = notify->payload;
334 SilcNotifyType type = silc_notify_get_type(payload);
335 SilcArgumentPayload args = silc_notify_get_args(payload);
336 SilcClientEntry client_entry;
337 SilcChannelEntry channel = NULL;
340 SILC_LOG_DEBUG(("Notify: JOIN"));
343 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
346 /* Get channel entry */
347 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
351 /* If channel is being resolved handle notify after resolving */
352 if (channel->internal.resolve_cmd_ident) {
353 silc_client_unref_channel(client, conn, channel);
354 SILC_FSM_CALL(silc_client_command_pending(
355 conn, SILC_COMMAND_NONE,
356 channel->internal.resolve_cmd_ident,
357 silc_client_notify_wait_continue,
363 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
366 /* Find Client entry and if not found query it */
367 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
368 if (!client_entry || !client_entry->nickname[0] ||
369 !client_entry->username[0]) {
370 /** Resolve client */
371 silc_client_unref_client(client, conn, client_entry);
372 notify->channel = channel;
373 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
374 silc_client_get_client_by_id_resolve(
375 client, conn, &id.u.client_id, NULL,
376 silc_client_notify_resolved,
381 if (client_entry != conn->local_entry)
382 silc_client_nickname_format(client, conn, client_entry);
384 /* Join the client to channel */
385 if (!silc_client_add_to_channel(client, conn, channel, client_entry, 0))
388 /* Notify application. */
389 NOTIFY(client, conn, type, client_entry, channel);
391 silc_client_unref_client(client, conn, client_entry);
394 /** Notify processed */
395 silc_client_unref_channel(client, conn, channel);
396 silc_fsm_next(fsm, silc_client_notify_processed);
397 return SILC_FSM_CONTINUE;
400 /********************************** LEAVE ***********************************/
402 /* Someone left a channel */
404 SILC_FSM_STATE(silc_client_notify_leave)
406 SilcClientConnection conn = fsm_context;
407 SilcClient client = conn->client;
408 SilcClientNotify notify = state_context;
409 SilcNotifyPayload payload = notify->payload;
410 SilcPacket packet = notify->packet;
411 SilcNotifyType type = silc_notify_get_type(payload);
412 SilcArgumentPayload args = silc_notify_get_args(payload);
413 SilcClientEntry client_entry = NULL;
414 SilcChannelEntry channel = NULL;
417 SILC_LOG_DEBUG(("Notify: LEAVE"));
419 /* Get channel entry */
420 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
421 &id.u.channel_id, sizeof(id.u.channel_id)))
423 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
427 /* If channel is being resolved handle notify after resolving */
428 if (channel->internal.resolve_cmd_ident) {
429 silc_client_unref_channel(client, conn, channel);
430 SILC_FSM_CALL(silc_client_command_pending(
431 conn, SILC_COMMAND_NONE,
432 channel->internal.resolve_cmd_ident,
433 silc_client_notify_wait_continue,
439 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
442 /* Find Client entry */
443 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
447 /* Remove client from channel */
448 silc_client_remove_from_channel(client, conn, channel, client_entry);
450 /* Notify application. */
451 NOTIFY(client, conn, type, client_entry, channel);
453 silc_client_unref_client(client, conn, client_entry);
456 /** Notify processed */
457 silc_client_unref_channel(client, conn, channel);
458 silc_fsm_next(fsm, silc_client_notify_processed);
459 return SILC_FSM_CONTINUE;
462 /********************************* SIGNOFF **********************************/
464 /* Someone quit SILC network */
466 SILC_FSM_STATE(silc_client_notify_signoff)
468 SilcClientConnection conn = fsm_context;
469 SilcClient client = conn->client;
470 SilcClientNotify notify = state_context;
471 SilcNotifyPayload payload = notify->payload;
472 SilcNotifyType type = silc_notify_get_type(payload);
473 SilcArgumentPayload args = silc_notify_get_args(payload);
474 SilcClientEntry client_entry;
479 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
482 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
485 /* Find Client entry */
486 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
490 /* Get signoff message */
491 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
495 /* Notify application */
496 NOTIFY(client, conn, type, client_entry, tmp);
499 silc_client_del_client(client, conn, client_entry);
500 silc_client_unref_client(client, conn, client_entry);
503 /** Notify processed */
504 silc_fsm_next(fsm, silc_client_notify_processed);
505 return SILC_FSM_CONTINUE;
508 /******************************** TOPIC_SET *********************************/
510 /* Someone set topic on a channel */
512 SILC_FSM_STATE(silc_client_notify_topic_set)
514 SilcClientConnection conn = fsm_context;
515 SilcClient client = conn->client;
516 SilcClientNotify notify = state_context;
517 SilcNotifyPayload payload = notify->payload;
518 SilcPacket packet = notify->packet;
519 SilcNotifyType type = silc_notify_get_type(payload);
520 SilcArgumentPayload args = silc_notify_get_args(payload);
521 SilcClientEntry client_entry = NULL;
522 SilcChannelEntry channel = NULL, channel_entry = NULL;
523 SilcServerEntry server = NULL;
529 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
531 /* Get channel entry */
532 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
533 &id.u.channel_id, sizeof(id.u.channel_id)))
535 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
539 /* If channel is being resolved handle notify after resolving */
540 if (channel->internal.resolve_cmd_ident) {
541 silc_client_unref_channel(client, conn, channel);
542 SILC_FSM_CALL(silc_client_command_pending(
543 conn, SILC_COMMAND_NONE,
544 channel->internal.resolve_cmd_ident,
545 silc_client_notify_wait_continue,
551 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
555 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
559 if (id.type == SILC_ID_CLIENT) {
560 /* Find Client entry */
561 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
562 if (!client_entry || !client_entry->nickname[0]) {
563 /** Resolve client */
564 silc_client_unref_client(client, conn, client_entry);
565 notify->channel = channel;
566 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
567 silc_client_get_client_by_id_resolve(
568 client, conn, &id.u.client_id, NULL,
569 silc_client_notify_resolved,
573 entry = client_entry;
574 } else if (id.type == SILC_ID_SERVER) {
575 /* Find Server entry */
576 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
578 /** Resolve server */
579 notify->channel = channel;
580 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
581 silc_client_get_server_by_id_resolve(
582 client, conn, &id.u.server_id,
583 silc_client_notify_resolved,
589 /* Find Channel entry */
590 channel_entry = silc_client_get_channel_by_id(client, conn,
592 if (!channel_entry) {
593 /** Resolve channel */
594 notify->channel = channel;
595 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
596 silc_client_get_channel_by_id_resolve(
597 client, conn, &id.u.channel_id,
598 silc_client_notify_resolved,
602 entry = channel_entry;
605 silc_free(channel->topic);
606 channel->topic = silc_memdup(tmp, strlen(tmp));
608 /* Notify application. */
609 NOTIFY(client, conn, type, id.type, entry, channel->topic, channel);
612 silc_client_unref_client(client, conn, client_entry);
614 silc_client_unref_server(client, conn, server);
616 silc_client_unref_channel(client, conn, channel_entry);
619 /** Notify processed */
620 silc_client_unref_channel(client, conn, channel);
621 silc_fsm_next(fsm, silc_client_notify_processed);
622 return SILC_FSM_CONTINUE;
625 /****************************** NICK_CHANGE *********************************/
627 /* Someone changed their nickname on a channel */
629 SILC_FSM_STATE(silc_client_notify_nick_change)
631 SilcClientConnection conn = fsm_context;
632 SilcClient client = conn->client;
633 SilcClientNotify notify = state_context;
634 SilcNotifyPayload payload = notify->payload;
635 SilcNotifyType type = silc_notify_get_type(payload);
636 SilcArgumentPayload args = silc_notify_get_args(payload);
637 SilcClientEntry client_entry = NULL;
638 unsigned char *tmp, *nick, oldnick[128 + 1];
642 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
645 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
649 if (conn->local_id &&
650 SILC_ID_CLIENT_COMPARE(&id.u.client_id, conn->local_id))
653 /* Get new Client ID */
654 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id2, NULL))
658 if (conn->local_id &&
659 SILC_ID_CLIENT_COMPARE(&id2.u.client_id, conn->local_id))
662 /* Find old Client entry */
663 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
664 if (!client_entry || !client_entry->nickname[0]) {
665 /** Resolve client */
666 silc_client_unref_client(client, conn, client_entry);
667 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
668 client, conn, &id.u.client_id, NULL,
669 silc_client_notify_resolved,
674 /* Take the new nickname */
675 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
679 /* Check whether nickname changed at all. It is possible that nick
680 change notify is received but nickname didn't change, only the
681 ID changes. If Client ID hash match, nickname didn't change. */
682 if (SILC_ID_COMPARE_HASH(&client_entry->id, &id2.u.client_id) &&
683 silc_utf8_strcasecmp(tmp, client_entry->nickname)) {
684 /* Nickname didn't change. Update only Client ID. We don't notify
685 application because nickname didn't change. */
686 silc_mutex_lock(conn->internal->lock);
687 silc_idcache_update_by_context(conn->internal->client_cache, client_entry,
688 &id2.u.client_id, NULL, FALSE);
689 silc_mutex_unlock(conn->internal->lock);
693 /* Normalize nickname */
694 nick = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8, 128, NULL);
698 /* Update nickname */
699 silc_mutex_lock(conn->internal->lock);
700 if (!silc_idcache_update_by_context(conn->internal->client_cache,
701 client_entry, NULL, nick, TRUE)) {
703 silc_mutex_unlock(conn->internal->lock);
706 silc_mutex_unlock(conn->internal->lock);
707 memcpy(oldnick, client_entry->nickname, sizeof(client_entry->nickname));
708 memcpy(client_entry->nickname, tmp, tmp_len);
709 client_entry->nickname_normalized = nick;
710 silc_client_nickname_format(client, conn, client_entry);
712 /* Notify application */
713 NOTIFY(client, conn, type, client_entry, client_entry->nickname, oldnick);
716 /** Notify processed */
717 silc_client_unref_client(client, conn, client_entry);
718 silc_fsm_next(fsm, silc_client_notify_processed);
719 return SILC_FSM_CONTINUE;
722 /****************************** CMODE_CHANGE ********************************/
724 /* Someone changed channel mode */
726 SILC_FSM_STATE(silc_client_notify_cmode_change)
728 SilcClientConnection conn = fsm_context;
729 SilcClient client = conn->client;
730 SilcClientNotify notify = state_context;
731 SilcNotifyPayload payload = notify->payload;
732 SilcPacket packet = notify->packet;
733 SilcNotifyType type = silc_notify_get_type(payload);
734 SilcArgumentPayload args = silc_notify_get_args(payload);
735 SilcClientEntry client_entry = NULL;
736 SilcChannelEntry channel = NULL, channel_entry = NULL;
737 SilcServerEntry server = NULL;
740 SilcUInt32 tmp_len, mode;
742 char *passphrase, *cipher, *hmac;
743 SilcPublicKey founder_key = NULL;
744 SilcDList chpks = NULL;
746 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
748 /* Get channel entry */
749 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
750 &id.u.channel_id, sizeof(id.u.channel_id)))
752 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
756 /* If channel is being resolved handle notify after resolving */
757 if (channel->internal.resolve_cmd_ident) {
758 silc_client_unref_channel(client, conn, channel);
759 SILC_FSM_CALL(silc_client_command_pending(
760 conn, SILC_COMMAND_NONE,
761 channel->internal.resolve_cmd_ident,
762 silc_client_notify_wait_continue,
768 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
771 SILC_GET32_MSB(mode, tmp);
774 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
777 if (id.type == SILC_ID_CLIENT) {
778 /* Find Client entry */
779 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
780 if (!client_entry || !client_entry->nickname[0]) {
781 /** Resolve client */
782 silc_client_unref_client(client, conn, client_entry);
783 notify->channel = channel;
784 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
785 silc_client_get_client_by_id_resolve(
786 client, conn, &id.u.client_id, NULL,
787 silc_client_notify_resolved,
791 entry = client_entry;
792 } else if (id.type == SILC_ID_SERVER) {
793 /* Find Server entry */
794 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
796 /** Resolve server */
797 notify->channel = channel;
798 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
799 silc_client_get_server_by_id_resolve(
800 client, conn, &id.u.server_id,
801 silc_client_notify_resolved,
807 /* Find Channel entry */
808 channel_entry = silc_client_get_channel_by_id(client, conn,
810 if (!channel_entry) {
811 /** Resolve channel */
812 notify->channel = channel;
813 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
814 silc_client_get_channel_by_id_resolve(
815 client, conn, &id.u.channel_id,
816 silc_client_notify_resolved,
820 entry = channel_entry;
823 /* Get the channel founder key if it was set */
824 tmp = silc_argument_get_arg_type(args, 6, &tmp_len);
826 if (!silc_public_key_payload_decode(tmp, tmp_len, &founder_key))
828 if (!channel->founder_key) {
829 channel->founder_key = founder_key;
835 cipher = silc_argument_get_arg_type(args, 3, &tmp_len);
838 hmac = silc_argument_get_arg_type(args, 4, &tmp_len);
840 unsigned char hash[SILC_HASH_MAXLEN];
843 if (!silc_hmac_alloc(hmac, NULL, &newhmac))
846 /* Get HMAC key from the old HMAC context, and update it to the new one */
847 tmp = (unsigned char *)silc_hmac_get_key(channel->internal.hmac, &tmp_len);
849 silc_hash_make(silc_hmac_get_hash(newhmac), tmp, tmp_len, hash);
850 silc_hmac_set_key(newhmac, hash,
851 silc_hash_len(silc_hmac_get_hash(newhmac)));
852 if (channel->internal.hmac)
853 silc_hmac_free(channel->internal.hmac);
854 channel->internal.hmac = newhmac;
855 memset(hash, 0, sizeof(hash));
859 /* Get the passphrase if it was set */
860 passphrase = silc_argument_get_arg_type(args, 5, &tmp_len);
863 tmp = silc_argument_get_arg_type(args, 8, &tmp_len);
864 if (tmp && tmp_len == 4)
865 SILC_GET32_MSB(channel->user_limit, tmp);
866 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
867 channel->user_limit = 0;
869 /* Save the new mode */
870 channel->mode = mode;
872 /* Get the channel public key that was added or removed */
873 tmp = silc_argument_get_arg_type(args, 7, &tmp_len);
875 chpks = silc_argument_list_parse_decoded(tmp, tmp_len,
876 SILC_ARGUMENT_PUBLIC_KEY);
878 /* Notify application. */
879 NOTIFY(client, conn, type, id.type, entry, mode, cipher, hmac,
880 passphrase, channel->founder_key, chpks, channel);
884 silc_pkcs_public_key_free(founder_key);
886 silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
888 silc_client_unref_client(client, conn, client_entry);
890 silc_client_unref_server(client, conn, server);
892 silc_client_unref_channel(client, conn, channel_entry);
893 silc_client_unref_channel(client, conn, channel);
895 /** Notify processed */
896 silc_fsm_next(fsm, silc_client_notify_processed);
897 return SILC_FSM_CONTINUE;
900 /***************************** CUMODE_CHANGE ********************************/
902 /* Someone changed a user's mode on a channel */
904 SILC_FSM_STATE(silc_client_notify_cumode_change)
906 SilcClientConnection conn = fsm_context;
907 SilcClient client = conn->client;
908 SilcClientNotify notify = state_context;
909 SilcNotifyPayload payload = notify->payload;
910 SilcPacket packet = notify->packet;
911 SilcNotifyType type = silc_notify_get_type(payload);
912 SilcArgumentPayload args = silc_notify_get_args(payload);
913 SilcClientEntry client_entry = NULL, client_entry2 = NULL;
914 SilcChannelEntry channel = NULL, channel_entry = NULL;
915 SilcServerEntry server = NULL;
919 SilcUInt32 tmp_len, mode;
922 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
924 /* Get channel entry */
925 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
926 &id.u.channel_id, sizeof(id.u.channel_id)))
928 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
932 /* If channel is being resolved handle notify after resolving */
933 if (channel->internal.resolve_cmd_ident) {
934 silc_client_unref_channel(client, conn, channel);
935 SILC_FSM_CALL(silc_client_command_pending(
936 conn, SILC_COMMAND_NONE,
937 channel->internal.resolve_cmd_ident,
938 silc_client_notify_wait_continue,
943 /* Get target Client ID */
944 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id2, NULL))
947 /* Find target Client entry */
948 client_entry2 = silc_client_get_client_by_id(client, conn, &id2.u.client_id);
949 if (!client_entry2 || !client_entry2->nickname[0]) {
950 /** Resolve client */
951 silc_client_unref_client(client, conn, client_entry2);
952 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
953 client, conn, &id2.u.client_id, NULL,
954 silc_client_notify_resolved,
960 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
963 SILC_GET32_MSB(mode, tmp);
966 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
969 if (id.type == SILC_ID_CLIENT) {
970 /* Find Client entry */
971 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
972 if (!client_entry || !client_entry->nickname[0]) {
973 /** Resolve client */
974 silc_client_unref_client(client, conn, client_entry);
975 notify->channel = channel;
976 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
977 silc_client_get_client_by_id_resolve(
978 client, conn, &id.u.client_id, NULL,
979 silc_client_notify_resolved,
983 entry = client_entry;
984 } else if (id.type == SILC_ID_SERVER) {
985 /* Find Server entry */
986 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
988 /** Resolve server */
989 notify->channel = channel;
990 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
991 silc_client_get_server_by_id_resolve(
992 client, conn, &id.u.server_id,
993 silc_client_notify_resolved,
999 /* Find Channel entry */
1000 channel_entry = silc_client_get_channel_by_id(client, conn,
1002 if (!channel_entry) {
1003 /** Resolve channel */
1004 notify->channel = channel;
1005 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1006 silc_client_get_channel_by_id_resolve(
1007 client, conn, &id.u.channel_id,
1008 silc_client_notify_resolved,
1012 entry = channel_entry;
1016 chu = silc_client_on_channel(channel, client_entry2);
1020 /* Notify application. */
1021 NOTIFY(client, conn, type, id.type, entry, mode, client_entry2, channel);
1024 silc_client_unref_client(client, conn, client_entry2);
1026 silc_client_unref_client(client, conn, client_entry);
1028 silc_client_unref_server(client, conn, server);
1030 silc_client_unref_channel(client, conn, channel_entry);
1031 silc_client_unref_channel(client, conn, channel);
1033 /** Notify processed */
1034 silc_fsm_next(fsm, silc_client_notify_processed);
1035 return SILC_FSM_CONTINUE;
1038 /********************************* MOTD *************************************/
1040 /* Received Message of the day */
1042 SILC_FSM_STATE(silc_client_notify_motd)
1044 SilcClientConnection conn = fsm_context;
1045 SilcClient client = conn->client;
1046 SilcClientNotify notify = state_context;
1047 SilcNotifyPayload payload = notify->payload;
1048 SilcNotifyType type = silc_notify_get_type(payload);
1049 SilcArgumentPayload args = silc_notify_get_args(payload);
1053 SILC_LOG_DEBUG(("Notify: MOTD"));
1056 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1060 /* Notify application */
1061 NOTIFY(client, conn, type, tmp);
1064 /** Notify processed */
1065 silc_fsm_next(fsm, silc_client_notify_processed);
1066 return SILC_FSM_CONTINUE;
1069 /**************************** CHANNEL CHANGE ********************************/
1071 /* Router has enforced a new ID to a channel, change it */
1073 SILC_FSM_STATE(silc_client_notify_channel_change)
1075 SilcClientConnection conn = fsm_context;
1076 SilcClient client = conn->client;
1077 SilcClientNotify notify = state_context;
1078 SilcNotifyPayload payload = notify->payload;
1079 SilcNotifyType type = silc_notify_get_type(payload);
1080 SilcArgumentPayload args = silc_notify_get_args(payload);
1081 SilcChannelEntry channel = NULL;
1084 SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
1086 /* Get the old ID */
1087 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1090 /* Get the channel entry */
1091 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1095 /* If channel is being resolved handle notify after resolving */
1096 if (channel->internal.resolve_cmd_ident) {
1097 silc_client_unref_channel(client, conn, channel);
1098 SILC_FSM_CALL(silc_client_command_pending(
1099 conn, SILC_COMMAND_NONE,
1100 channel->internal.resolve_cmd_ident,
1101 silc_client_notify_wait_continue,
1106 /* Get the new ID */
1107 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
1110 /* Replace the Channel ID */
1111 if (!silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id))
1114 /* Notify application */
1115 NOTIFY(client, conn, type, channel, channel);
1118 /** Notify processed */
1119 silc_client_unref_channel(client, conn, channel);
1120 silc_fsm_next(fsm, silc_client_notify_processed);
1121 return SILC_FSM_CONTINUE;
1124 /******************************** KICKED ************************************/
1126 /* Some client was kicked from a channel */
1128 SILC_FSM_STATE(silc_client_notify_kicked)
1130 SilcClientConnection conn = fsm_context;
1131 SilcClient client = conn->client;
1132 SilcClientNotify notify = state_context;
1133 SilcNotifyPayload payload = notify->payload;
1134 SilcPacket packet = notify->packet;
1135 SilcNotifyType type = silc_notify_get_type(payload);
1136 SilcArgumentPayload args = silc_notify_get_args(payload);
1137 SilcClientEntry client_entry, client_entry2;
1138 SilcChannelEntry channel = NULL;
1139 SilcChannelUser chu;
1144 SILC_LOG_DEBUG(("Notify: KICKED"));
1146 /* Get channel entry */
1147 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
1148 &id.u.channel_id, sizeof(id.u.channel_id)))
1150 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1154 /* If channel is being resolved handle notify after resolving */
1155 if (channel->internal.resolve_cmd_ident) {
1156 silc_client_unref_channel(client, conn, channel);
1157 SILC_FSM_CALL(silc_client_command_pending(
1158 conn, SILC_COMMAND_NONE,
1159 channel->internal.resolve_cmd_ident,
1160 silc_client_notify_wait_continue,
1166 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1169 /* Find Client entry */
1170 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1174 /* Get kicker's Client ID */
1175 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
1178 /* Find kicker's client entry and if not found resolve it */
1179 client_entry2 = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1180 if (!client_entry2 || !client_entry2->nickname[0]) {
1181 /** Resolve client */
1182 silc_client_unref_client(client, conn, client_entry);
1183 silc_client_unref_client(client, conn, client_entry2);
1184 notify->channel = channel;
1185 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1186 silc_client_get_client_by_id_resolve(
1187 client, conn, &id.u.client_id, NULL,
1188 silc_client_notify_resolved,
1194 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1196 /* Remove kicked client from channel */
1197 if (client_entry != conn->local_entry) {
1198 chu = silc_client_on_channel(channel, client_entry);
1200 silc_hash_table_del(client_entry->channels, channel);
1201 silc_hash_table_del(channel->user_list, client_entry);
1206 /* Notify application. */
1207 NOTIFY(client, conn, type, client_entry, tmp, client_entry2, channel);
1209 /* If I was kicked from channel, remove the channel */
1210 if (client_entry == conn->local_entry) {
1211 if (conn->current_channel == channel)
1212 conn->current_channel = NULL;
1213 silc_client_del_channel(client, conn, channel);
1216 silc_client_unref_client(client, conn, client_entry);
1217 silc_client_unref_client(client, conn, client_entry2);
1220 /** Notify processed */
1221 silc_client_unref_channel(client, conn, channel);
1222 silc_fsm_next(fsm, silc_client_notify_processed);
1223 return SILC_FSM_CONTINUE;
1226 /******************************** KILLED ************************************/
1228 /* Some client was killed from the network */
1230 SILC_FSM_STATE(silc_client_notify_killed)
1232 SilcClientConnection conn = fsm_context;
1233 SilcClient client = conn->client;
1234 SilcClientNotify notify = state_context;
1235 SilcNotifyPayload payload = notify->payload;
1236 SilcNotifyType type = silc_notify_get_type(payload);
1237 SilcArgumentPayload args = silc_notify_get_args(payload);
1238 SilcClientEntry client_entry = NULL, client_entry2 = NULL;
1239 SilcChannelEntry channel_entry = NULL;
1240 SilcServerEntry server = NULL;
1243 SilcUInt32 comment_len;
1246 SILC_LOG_DEBUG(("Notify: KILLED"));
1249 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1252 /* Find Client entry */
1253 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1258 comment = silc_argument_get_arg_type(args, 2, &comment_len);
1260 /* Get killer's ID */
1261 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
1264 if (id.type == SILC_ID_CLIENT) {
1265 /* Find Client entry */
1266 client_entry2 = silc_client_get_client_by_id(client, conn,
1268 if (!client_entry2 || !client_entry2->nickname[0]) {
1269 /** Resolve client */
1270 silc_client_unref_client(client, conn, client_entry);
1271 silc_client_unref_client(client, conn, client_entry2);
1272 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1273 client, conn, &id.u.client_id, NULL,
1274 silc_client_notify_resolved,
1278 entry = client_entry2;
1279 } else if (id.type == SILC_ID_SERVER) {
1280 /* Find Server entry */
1281 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1283 /** Resolve server */
1284 SILC_FSM_CALL(silc_client_get_server_by_id_resolve(
1285 client, conn, &id.u.server_id,
1286 silc_client_notify_resolved,
1292 /* Find Channel entry */
1293 channel_entry = silc_client_get_channel_by_id(client, conn,
1295 if (!channel_entry) {
1296 /** Resolve channel */
1297 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1298 client, conn, &id.u.channel_id,
1299 silc_client_notify_resolved,
1303 entry = channel_entry;
1306 /* Notify application. */
1307 NOTIFY(client, conn, type, client_entry, comment, id.type, entry);
1309 /* Delete the killed client */
1310 if (client_entry != conn->local_entry)
1311 silc_client_del_client(client, conn, client_entry);
1314 silc_client_unref_client(client, conn, client_entry);
1316 silc_client_unref_client(client, conn, client_entry2);
1318 silc_client_unref_server(client, conn, server);
1320 silc_client_unref_channel(client, conn, channel_entry);
1322 /** Notify processed */
1323 silc_fsm_next(fsm, silc_client_notify_processed);
1324 return SILC_FSM_CONTINUE;
1327 /**************************** SERVER SIGNOFF ********************************/
1329 /* Some server quit SILC network. Remove its clients from channels. */
1331 SILC_FSM_STATE(silc_client_notify_server_signoff)
1333 SilcClientConnection conn = fsm_context;
1334 SilcClient client = conn->client;
1335 SilcClientNotify notify = state_context;
1336 SilcNotifyPayload payload = notify->payload;
1337 SilcNotifyType type = silc_notify_get_type(payload);
1338 SilcArgumentPayload args = silc_notify_get_args(payload);
1339 SilcClientEntry client_entry;
1344 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
1346 clients = silc_dlist_init();
1350 for (i = 1; i < silc_argument_get_arg_num(args); i++) {
1352 if (!silc_argument_get_decoded(args, i + 1, SILC_ARGUMENT_ID, &id, NULL))
1355 /* Get the client entry */
1356 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1358 silc_dlist_add(clients, client_entry);
1361 /* Notify application. We don't keep server entries so the server
1362 entry is returned as NULL. The client's are returned as list. */
1363 NOTIFY(client, conn, type, NULL, clients);
1365 /* Delete the clients */
1366 silc_dlist_start(clients);
1367 while ((client_entry = silc_dlist_get(clients)))
1368 silc_client_del_client(client, conn, client_entry);
1371 /** Notify processed */
1372 silc_client_list_free(client, conn, clients);
1373 silc_fsm_next(fsm, silc_client_notify_processed);
1374 return SILC_FSM_CONTINUE;
1377 /******************************** ERROR *************************************/
1379 /* Some error occurred */
1381 SILC_FSM_STATE(silc_client_notify_error)
1383 SilcClientConnection conn = fsm_context;
1384 SilcClient client = conn->client;
1385 SilcClientNotify notify = state_context;
1386 SilcNotifyPayload payload = notify->payload;
1387 SilcNotifyType type = silc_notify_get_type(payload);
1388 SilcArgumentPayload args = silc_notify_get_args(payload);
1389 SilcClientEntry client_entry;
1396 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1397 if (!tmp && tmp_len != 1)
1399 error = (SilcStatus)tmp[0];
1401 SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1403 /* Handle the error */
1404 if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1405 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
1407 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1409 silc_client_del_client(client, conn, client_entry);
1410 silc_client_unref_client(client, conn, client_entry);
1414 /* Notify application. */
1415 NOTIFY(client, conn, type, error);
1418 /** Notify processed */
1419 silc_fsm_next(fsm, silc_client_notify_processed);
1420 return SILC_FSM_CONTINUE;
1423 /******************************** WATCH *************************************/
1425 /* Received notify about some client we are watching */
1427 SILC_FSM_STATE(silc_client_notify_watch)
1429 SilcClientConnection conn = fsm_context;
1430 SilcClient client = conn->client;
1431 SilcClientNotify notify = state_context;
1432 SilcNotifyPayload payload = notify->payload;
1433 SilcNotifyType type = silc_notify_get_type(payload);
1434 SilcArgumentPayload args = silc_notify_get_args(payload);
1435 SilcClientEntry client_entry = NULL;
1436 SilcNotifyType ntype = 0;
1437 SilcBool del_client = FALSE;
1438 unsigned char *pk, *tmp;
1439 SilcUInt32 mode, pk_len, tmp_len;
1440 SilcPublicKey public_key = NULL;
1443 SILC_LOG_DEBUG(("Notify: WATCH"));
1445 /* Get sender Client ID */
1446 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1449 /* Find Client entry and if not found resolve it */
1450 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1451 if (!client_entry || !client_entry->nickname[0]) {
1452 /** Resolve client */
1453 silc_client_unref_client(client, conn, client_entry);
1454 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1455 client, conn, &id.u.client_id, NULL,
1456 silc_client_notify_resolved,
1462 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1463 if (!tmp || tmp_len != 4)
1465 SILC_GET32_MSB(mode, tmp);
1467 /* Get notify type */
1468 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1469 if (tmp && tmp_len != 2)
1472 SILC_GET16_MSB(ntype, tmp);
1475 tmp = silc_argument_get_arg_type(args, 2, NULL);
1477 char *tmp_nick = NULL;
1479 if (client->internal->params->nickname_parse)
1480 client->internal->params->nickname_parse(client_entry->nickname,
1483 tmp_nick = strdup(tmp);
1485 /* If same nick, the client was new to us and has become "present"
1486 to network. Send NULL as nick to application. */
1487 if (tmp_nick && silc_utf8_strcasecmp(tmp, tmp_nick))
1490 silc_free(tmp_nick);
1493 /* Get public key, if present */
1494 pk = silc_argument_get_arg_type(args, 5, &pk_len);
1495 if (pk && !client_entry->public_key) {
1496 if (silc_public_key_payload_decode(pk, pk_len, &public_key)) {
1497 client_entry->public_key = public_key;
1502 /* Notify application. */
1503 NOTIFY(client, conn, type, client_entry, tmp, mode, ntype,
1504 client_entry->public_key);
1506 client_entry->mode = mode;
1508 /* If nickname was changed, remove the client entry unless the
1509 client is on some channel */
1510 /* XXX, why do we need to remove the client entry?? */
1511 if (tmp && ntype == SILC_NOTIFY_TYPE_NICK_CHANGE &&
1512 !silc_hash_table_count(client_entry->channels))
1514 else if (ntype == SILC_NOTIFY_TYPE_SIGNOFF ||
1515 ntype == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
1516 ntype == SILC_NOTIFY_TYPE_KILLED)
1520 silc_client_del_client(client, conn, client_entry);
1523 silc_pkcs_public_key_free(public_key);
1526 /** Notify processed */
1527 silc_client_unref_client(client, conn, client_entry);
1528 silc_fsm_next(fsm, silc_client_notify_processed);
1529 return SILC_FSM_CONTINUE;