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 %d", silc_notify_get_type(payload)));
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);
492 if (tmp && tmp_len > 128)
495 /* Notify application */
496 NOTIFY(client, conn, type, client_entry, tmp);
499 silc_client_remove_from_channels(client, conn, client_entry);
500 silc_client_del_client(client, conn, client_entry);
501 silc_client_unref_client(client, conn, client_entry);
504 /** Notify processed */
505 silc_fsm_next(fsm, silc_client_notify_processed);
506 return SILC_FSM_CONTINUE;
509 /******************************** TOPIC_SET *********************************/
511 /* Someone set topic on a channel */
513 SILC_FSM_STATE(silc_client_notify_topic_set)
515 SilcClientConnection conn = fsm_context;
516 SilcClient client = conn->client;
517 SilcClientNotify notify = state_context;
518 SilcNotifyPayload payload = notify->payload;
519 SilcPacket packet = notify->packet;
520 SilcNotifyType type = silc_notify_get_type(payload);
521 SilcArgumentPayload args = silc_notify_get_args(payload);
522 SilcClientEntry client_entry = NULL;
523 SilcChannelEntry channel = NULL, channel_entry = NULL;
524 SilcServerEntry server = NULL;
530 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
532 /* Get channel entry */
533 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
534 &id.u.channel_id, sizeof(id.u.channel_id)))
536 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
540 /* If channel is being resolved handle notify after resolving */
541 if (channel->internal.resolve_cmd_ident) {
542 silc_client_unref_channel(client, conn, channel);
543 SILC_FSM_CALL(silc_client_command_pending(
544 conn, SILC_COMMAND_NONE,
545 channel->internal.resolve_cmd_ident,
546 silc_client_notify_wait_continue,
552 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
556 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
560 if (id.type == SILC_ID_CLIENT) {
561 /* Find Client entry */
562 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
563 if (!client_entry || !client_entry->nickname[0]) {
564 /** Resolve client */
565 silc_client_unref_client(client, conn, client_entry);
566 notify->channel = channel;
567 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
568 silc_client_get_client_by_id_resolve(
569 client, conn, &id.u.client_id, NULL,
570 silc_client_notify_resolved,
574 entry = client_entry;
575 } else if (id.type == SILC_ID_SERVER) {
576 /* Find Server entry */
577 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
579 /** Resolve server */
580 notify->channel = channel;
581 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
582 silc_client_get_server_by_id_resolve(
583 client, conn, &id.u.server_id,
584 silc_client_notify_resolved,
590 /* Find Channel entry */
591 channel_entry = silc_client_get_channel_by_id(client, conn,
593 if (!channel_entry) {
594 /** Resolve channel */
595 notify->channel = channel;
596 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
597 silc_client_get_channel_by_id_resolve(
598 client, conn, &id.u.channel_id,
599 silc_client_notify_resolved,
603 entry = channel_entry;
606 silc_free(channel->topic);
607 channel->topic = silc_memdup(tmp, strlen(tmp));
609 /* Notify application. */
610 NOTIFY(client, conn, type, id.type, entry, channel->topic, channel);
613 silc_client_unref_client(client, conn, client_entry);
615 silc_client_unref_server(client, conn, server);
617 silc_client_unref_channel(client, conn, channel_entry);
620 /** Notify processed */
621 silc_client_unref_channel(client, conn, channel);
622 silc_fsm_next(fsm, silc_client_notify_processed);
623 return SILC_FSM_CONTINUE;
626 /****************************** NICK_CHANGE *********************************/
628 /* Someone changed their nickname on a channel */
630 SILC_FSM_STATE(silc_client_notify_nick_change)
632 SilcClientConnection conn = fsm_context;
633 SilcClient client = conn->client;
634 SilcClientNotify notify = state_context;
635 SilcNotifyPayload payload = notify->payload;
636 SilcNotifyType type = silc_notify_get_type(payload);
637 SilcArgumentPayload args = silc_notify_get_args(payload);
638 SilcClientEntry client_entry = NULL;
639 unsigned char *tmp, oldnick[128 + 1];
643 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
646 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
650 if (conn->local_id &&
651 SILC_ID_CLIENT_COMPARE(&id.u.client_id, conn->local_id))
654 /* Get new Client ID */
655 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id2, NULL))
659 if (conn->local_id &&
660 SILC_ID_CLIENT_COMPARE(&id2.u.client_id, conn->local_id))
663 /* Find old Client entry */
664 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
665 if (!client_entry || !client_entry->nickname[0]) {
666 /** Resolve client */
667 silc_client_unref_client(client, conn, client_entry);
668 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
669 client, conn, &id.u.client_id, NULL,
670 silc_client_notify_resolved,
675 /* Take the new nickname */
676 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
680 /* Check whether nickname changed at all. It is possible that nick
681 change notify is received but nickname didn't change, only the
682 ID changes. If Client ID hash match, nickname didn't change. */
683 if (SILC_ID_COMPARE_HASH(&client_entry->id, &id2.u.client_id) &&
684 silc_utf8_strcasecmp(tmp, client_entry->nickname)) {
685 /* Nickname didn't change. Update only Client ID. We don't notify
686 application because nickname didn't change. */
687 silc_mutex_lock(conn->internal->lock);
688 silc_idcache_update_by_context(conn->internal->client_cache, client_entry,
689 &id2.u.client_id, NULL, FALSE);
690 silc_mutex_unlock(conn->internal->lock);
694 /* Change the nickname */
695 memcpy(oldnick, client_entry->nickname, sizeof(client_entry->nickname));
696 if (!silc_client_change_nickname(client, conn, client_entry, tmp,
697 &id2.u.client_id, NULL, 0))
700 /* Notify application */
701 NOTIFY(client, conn, type, client_entry, client_entry->nickname, oldnick);
704 /** Notify processed */
705 silc_client_unref_client(client, conn, client_entry);
706 silc_fsm_next(fsm, silc_client_notify_processed);
707 return SILC_FSM_CONTINUE;
710 /****************************** CMODE_CHANGE ********************************/
712 /* Someone changed channel mode */
714 SILC_FSM_STATE(silc_client_notify_cmode_change)
716 SilcClientConnection conn = fsm_context;
717 SilcClient client = conn->client;
718 SilcClientNotify notify = state_context;
719 SilcNotifyPayload payload = notify->payload;
720 SilcPacket packet = notify->packet;
721 SilcNotifyType type = silc_notify_get_type(payload);
722 SilcArgumentPayload args = silc_notify_get_args(payload);
723 SilcClientEntry client_entry = NULL;
724 SilcChannelEntry channel = NULL, channel_entry = NULL;
725 SilcServerEntry server = NULL;
728 SilcUInt32 tmp_len, mode;
730 char *passphrase, *cipher, *hmac;
731 SilcPublicKey founder_key = NULL;
732 SilcDList chpks = NULL;
734 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
736 /* Get channel entry */
737 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
738 &id.u.channel_id, sizeof(id.u.channel_id)))
740 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
744 /* If channel is being resolved handle notify after resolving */
745 if (channel->internal.resolve_cmd_ident) {
746 silc_client_unref_channel(client, conn, channel);
747 SILC_FSM_CALL(silc_client_command_pending(
748 conn, SILC_COMMAND_NONE,
749 channel->internal.resolve_cmd_ident,
750 silc_client_notify_wait_continue,
756 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
759 SILC_GET32_MSB(mode, tmp);
762 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
765 if (id.type == SILC_ID_CLIENT) {
766 /* Find Client entry */
767 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
768 if (!client_entry || !client_entry->nickname[0]) {
769 /** Resolve client */
770 silc_client_unref_client(client, conn, client_entry);
771 notify->channel = channel;
772 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
773 silc_client_get_client_by_id_resolve(
774 client, conn, &id.u.client_id, NULL,
775 silc_client_notify_resolved,
779 entry = client_entry;
780 } else if (id.type == SILC_ID_SERVER) {
781 /* Find Server entry */
782 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
784 /** Resolve server */
785 notify->channel = channel;
786 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
787 silc_client_get_server_by_id_resolve(
788 client, conn, &id.u.server_id,
789 silc_client_notify_resolved,
795 /* Find Channel entry */
796 channel_entry = silc_client_get_channel_by_id(client, conn,
798 if (!channel_entry) {
799 /** Resolve channel */
800 notify->channel = channel;
801 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
802 silc_client_get_channel_by_id_resolve(
803 client, conn, &id.u.channel_id,
804 silc_client_notify_resolved,
808 entry = channel_entry;
811 /* Get the channel founder key if it was set */
812 tmp = silc_argument_get_arg_type(args, 6, &tmp_len);
814 if (!silc_public_key_payload_decode(tmp, tmp_len, &founder_key))
816 if (!channel->founder_key) {
817 channel->founder_key = founder_key;
823 cipher = silc_argument_get_arg_type(args, 3, &tmp_len);
826 hmac = silc_argument_get_arg_type(args, 4, &tmp_len);
828 unsigned char hash[SILC_HASH_MAXLEN];
831 if (!silc_hmac_alloc(hmac, NULL, &newhmac))
834 /* Get HMAC key from the old HMAC context, and update it to the new one */
835 tmp = (unsigned char *)silc_hmac_get_key(channel->internal.hmac, &tmp_len);
837 silc_hash_make(silc_hmac_get_hash(newhmac), tmp, tmp_len, hash);
838 silc_hmac_set_key(newhmac, hash,
839 silc_hash_len(silc_hmac_get_hash(newhmac)));
840 if (channel->internal.hmac)
841 silc_hmac_free(channel->internal.hmac);
842 channel->internal.hmac = newhmac;
843 memset(hash, 0, sizeof(hash));
847 /* Get the passphrase if it was set */
848 passphrase = silc_argument_get_arg_type(args, 5, &tmp_len);
851 tmp = silc_argument_get_arg_type(args, 8, &tmp_len);
852 if (tmp && tmp_len == 4)
853 SILC_GET32_MSB(channel->user_limit, tmp);
854 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
855 channel->user_limit = 0;
857 /* Save the new mode */
858 channel->mode = mode;
860 /* Get the channel public key that was added or removed */
861 tmp = silc_argument_get_arg_type(args, 7, &tmp_len);
863 chpks = silc_argument_list_parse_decoded(tmp, tmp_len,
864 SILC_ARGUMENT_PUBLIC_KEY);
866 /* XXX add to/remove from channel pubkeys channel->channel_pubkeys */
868 /* Notify application. */
869 NOTIFY(client, conn, type, id.type, entry, mode, cipher, hmac,
870 passphrase, channel->founder_key, chpks, channel);
874 silc_pkcs_public_key_free(founder_key);
876 silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
878 silc_client_unref_client(client, conn, client_entry);
880 silc_client_unref_server(client, conn, server);
882 silc_client_unref_channel(client, conn, channel_entry);
883 silc_client_unref_channel(client, conn, channel);
885 /** Notify processed */
886 silc_fsm_next(fsm, silc_client_notify_processed);
887 return SILC_FSM_CONTINUE;
890 /***************************** CUMODE_CHANGE ********************************/
892 /* Someone changed a user's mode on a channel */
894 SILC_FSM_STATE(silc_client_notify_cumode_change)
896 SilcClientConnection conn = fsm_context;
897 SilcClient client = conn->client;
898 SilcClientNotify notify = state_context;
899 SilcNotifyPayload payload = notify->payload;
900 SilcPacket packet = notify->packet;
901 SilcNotifyType type = silc_notify_get_type(payload);
902 SilcArgumentPayload args = silc_notify_get_args(payload);
903 SilcClientEntry client_entry = NULL, client_entry2 = NULL;
904 SilcChannelEntry channel = NULL, channel_entry = NULL;
905 SilcServerEntry server = NULL;
909 SilcUInt32 tmp_len, mode;
912 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
914 /* Get channel entry */
915 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
916 &id.u.channel_id, sizeof(id.u.channel_id)))
918 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
922 /* If channel is being resolved handle notify after resolving */
923 if (channel->internal.resolve_cmd_ident) {
924 silc_client_unref_channel(client, conn, channel);
925 SILC_FSM_CALL(silc_client_command_pending(
926 conn, SILC_COMMAND_NONE,
927 channel->internal.resolve_cmd_ident,
928 silc_client_notify_wait_continue,
933 /* Get target Client ID */
934 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id2, NULL))
937 /* Find target Client entry */
938 client_entry2 = silc_client_get_client_by_id(client, conn, &id2.u.client_id);
939 if (!client_entry2 || !client_entry2->nickname[0]) {
940 /** Resolve client */
941 silc_client_unref_client(client, conn, client_entry2);
942 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
943 client, conn, &id2.u.client_id, NULL,
944 silc_client_notify_resolved,
950 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
953 SILC_GET32_MSB(mode, tmp);
956 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
959 if (id.type == SILC_ID_CLIENT) {
960 /* Find Client entry */
961 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
962 if (!client_entry || !client_entry->nickname[0]) {
963 /** Resolve client */
964 silc_client_unref_client(client, conn, client_entry);
965 notify->channel = channel;
966 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
967 silc_client_get_client_by_id_resolve(
968 client, conn, &id.u.client_id, NULL,
969 silc_client_notify_resolved,
973 entry = client_entry;
974 } else if (id.type == SILC_ID_SERVER) {
975 /* Find Server entry */
976 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
978 /** Resolve server */
979 notify->channel = channel;
980 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
981 silc_client_get_server_by_id_resolve(
982 client, conn, &id.u.server_id,
983 silc_client_notify_resolved,
989 /* Find Channel entry */
990 channel_entry = silc_client_get_channel_by_id(client, conn,
992 if (!channel_entry) {
993 /** Resolve channel */
994 notify->channel = channel;
995 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
996 silc_client_get_channel_by_id_resolve(
997 client, conn, &id.u.channel_id,
998 silc_client_notify_resolved,
1002 entry = channel_entry;
1006 chu = silc_client_on_channel(channel, client_entry2);
1010 /* Notify application. */
1011 NOTIFY(client, conn, type, id.type, entry, mode, client_entry2, channel);
1014 silc_client_unref_client(client, conn, client_entry2);
1016 silc_client_unref_client(client, conn, client_entry);
1018 silc_client_unref_server(client, conn, server);
1020 silc_client_unref_channel(client, conn, channel_entry);
1021 silc_client_unref_channel(client, conn, channel);
1023 /** Notify processed */
1024 silc_fsm_next(fsm, silc_client_notify_processed);
1025 return SILC_FSM_CONTINUE;
1028 /********************************* MOTD *************************************/
1030 /* Received Message of the day */
1032 SILC_FSM_STATE(silc_client_notify_motd)
1034 SilcClientConnection conn = fsm_context;
1035 SilcClient client = conn->client;
1036 SilcClientNotify notify = state_context;
1037 SilcNotifyPayload payload = notify->payload;
1038 SilcNotifyType type = silc_notify_get_type(payload);
1039 SilcArgumentPayload args = silc_notify_get_args(payload);
1043 SILC_LOG_DEBUG(("Notify: MOTD"));
1046 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1050 /* Notify application */
1051 NOTIFY(client, conn, type, tmp);
1054 /** Notify processed */
1055 silc_fsm_next(fsm, silc_client_notify_processed);
1056 return SILC_FSM_CONTINUE;
1059 /**************************** CHANNEL CHANGE ********************************/
1061 /* Router has enforced a new ID to a channel, change it */
1063 SILC_FSM_STATE(silc_client_notify_channel_change)
1065 SilcClientConnection conn = fsm_context;
1066 SilcClient client = conn->client;
1067 SilcClientNotify notify = state_context;
1068 SilcNotifyPayload payload = notify->payload;
1069 SilcNotifyType type = silc_notify_get_type(payload);
1070 SilcArgumentPayload args = silc_notify_get_args(payload);
1071 SilcChannelEntry channel = NULL;
1074 SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
1076 /* Get the old ID */
1077 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1080 /* Get the channel entry */
1081 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1085 /* If channel is being resolved handle notify after resolving */
1086 if (channel->internal.resolve_cmd_ident) {
1087 silc_client_unref_channel(client, conn, channel);
1088 SILC_FSM_CALL(silc_client_command_pending(
1089 conn, SILC_COMMAND_NONE,
1090 channel->internal.resolve_cmd_ident,
1091 silc_client_notify_wait_continue,
1096 /* Get the new ID */
1097 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
1100 /* Replace the Channel ID */
1101 if (!silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id))
1104 /* Notify application */
1105 NOTIFY(client, conn, type, channel, channel);
1108 /** Notify processed */
1109 silc_client_unref_channel(client, conn, channel);
1110 silc_fsm_next(fsm, silc_client_notify_processed);
1111 return SILC_FSM_CONTINUE;
1114 /******************************** KICKED ************************************/
1116 /* Some client was kicked from a channel */
1118 SILC_FSM_STATE(silc_client_notify_kicked)
1120 SilcClientConnection conn = fsm_context;
1121 SilcClient client = conn->client;
1122 SilcClientNotify notify = state_context;
1123 SilcNotifyPayload payload = notify->payload;
1124 SilcPacket packet = notify->packet;
1125 SilcNotifyType type = silc_notify_get_type(payload);
1126 SilcArgumentPayload args = silc_notify_get_args(payload);
1127 SilcClientEntry client_entry, client_entry2;
1128 SilcChannelEntry channel = NULL;
1133 SILC_LOG_DEBUG(("Notify: KICKED"));
1135 /* Get channel entry */
1136 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
1137 &id.u.channel_id, sizeof(id.u.channel_id)))
1139 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1143 /* If channel is being resolved handle notify after resolving */
1144 if (channel->internal.resolve_cmd_ident) {
1145 silc_client_unref_channel(client, conn, channel);
1146 SILC_FSM_CALL(silc_client_command_pending(
1147 conn, SILC_COMMAND_NONE,
1148 channel->internal.resolve_cmd_ident,
1149 silc_client_notify_wait_continue,
1155 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1158 /* Find Client entry */
1159 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1163 /* Get kicker's Client ID */
1164 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
1167 /* Find kicker's client entry and if not found resolve it */
1168 client_entry2 = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1169 if (!client_entry2 || !client_entry2->nickname[0]) {
1170 /** Resolve client */
1171 silc_client_unref_client(client, conn, client_entry);
1172 silc_client_unref_client(client, conn, client_entry2);
1173 notify->channel = channel;
1174 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1175 silc_client_get_client_by_id_resolve(
1176 client, conn, &id.u.client_id, NULL,
1177 silc_client_notify_resolved,
1183 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1185 /* Remove kicked client from channel */
1186 if (client_entry != conn->local_entry)
1187 silc_client_remove_from_channel(client, conn, channel, client_entry);
1189 /* Notify application. */
1190 NOTIFY(client, conn, type, client_entry, tmp, client_entry2, channel);
1192 /* If I was kicked from channel, remove the channel */
1193 if (client_entry == conn->local_entry) {
1194 if (conn->current_channel == channel)
1195 conn->current_channel = NULL;
1196 silc_client_empty_channel(client, conn, channel);
1197 silc_client_del_channel(client, conn, channel);
1200 silc_client_unref_client(client, conn, client_entry);
1201 silc_client_unref_client(client, conn, client_entry2);
1204 /** Notify processed */
1205 silc_client_unref_channel(client, conn, channel);
1206 silc_fsm_next(fsm, silc_client_notify_processed);
1207 return SILC_FSM_CONTINUE;
1210 /******************************** KILLED ************************************/
1212 /* Some client was killed from the network */
1214 SILC_FSM_STATE(silc_client_notify_killed)
1216 SilcClientConnection conn = fsm_context;
1217 SilcClient client = conn->client;
1218 SilcClientNotify notify = state_context;
1219 SilcNotifyPayload payload = notify->payload;
1220 SilcNotifyType type = silc_notify_get_type(payload);
1221 SilcArgumentPayload args = silc_notify_get_args(payload);
1222 SilcClientEntry client_entry = NULL, client_entry2 = NULL;
1223 SilcChannelEntry channel_entry = NULL;
1224 SilcServerEntry server = NULL;
1227 SilcUInt32 comment_len;
1230 SILC_LOG_DEBUG(("Notify: KILLED"));
1233 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1236 /* Find Client entry */
1237 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1242 comment = silc_argument_get_arg_type(args, 2, &comment_len);
1244 /* Get killer's ID */
1245 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
1248 if (id.type == SILC_ID_CLIENT) {
1249 /* Find Client entry */
1250 client_entry2 = silc_client_get_client_by_id(client, conn,
1252 if (!client_entry2 || !client_entry2->nickname[0]) {
1253 /** Resolve client */
1254 silc_client_unref_client(client, conn, client_entry);
1255 silc_client_unref_client(client, conn, client_entry2);
1256 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1257 client, conn, &id.u.client_id, NULL,
1258 silc_client_notify_resolved,
1262 entry = client_entry2;
1263 } else if (id.type == SILC_ID_SERVER) {
1264 /* Find Server entry */
1265 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1267 /** Resolve server */
1268 SILC_FSM_CALL(silc_client_get_server_by_id_resolve(
1269 client, conn, &id.u.server_id,
1270 silc_client_notify_resolved,
1276 /* Find Channel entry */
1277 channel_entry = silc_client_get_channel_by_id(client, conn,
1279 if (!channel_entry) {
1280 /** Resolve channel */
1281 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1282 client, conn, &id.u.channel_id,
1283 silc_client_notify_resolved,
1287 entry = channel_entry;
1290 /* Notify application. */
1291 NOTIFY(client, conn, type, client_entry, comment, id.type, entry);
1293 /* Delete the killed client */
1294 if (client_entry != conn->local_entry) {
1295 silc_client_remove_from_channels(client, conn, client_entry);
1296 silc_client_del_client(client, conn, client_entry);
1300 silc_client_unref_client(client, conn, client_entry);
1302 silc_client_unref_client(client, conn, client_entry2);
1304 silc_client_unref_server(client, conn, server);
1306 silc_client_unref_channel(client, conn, channel_entry);
1308 /** Notify processed */
1309 silc_fsm_next(fsm, silc_client_notify_processed);
1310 return SILC_FSM_CONTINUE;
1313 /**************************** SERVER SIGNOFF ********************************/
1315 /* Some server quit SILC network. Remove its clients from channels. */
1317 SILC_FSM_STATE(silc_client_notify_server_signoff)
1319 SilcClientConnection conn = fsm_context;
1320 SilcClient client = conn->client;
1321 SilcClientNotify notify = state_context;
1322 SilcNotifyPayload payload = notify->payload;
1323 SilcNotifyType type = silc_notify_get_type(payload);
1324 SilcArgumentPayload args = silc_notify_get_args(payload);
1325 SilcClientEntry client_entry;
1330 SILC_LOG_DEBUG(("Notify: SERVER_SIGNOFF"));
1332 clients = silc_dlist_init();
1336 for (i = 1; i < silc_argument_get_arg_num(args); i++) {
1338 if (!silc_argument_get_decoded(args, i + 1, SILC_ARGUMENT_ID, &id, NULL))
1341 /* Get the client entry */
1342 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1344 silc_dlist_add(clients, client_entry);
1347 /* Notify application. We don't keep server entries so the server
1348 entry is returned as NULL. The client's are returned as list. */
1349 NOTIFY(client, conn, type, NULL, clients);
1351 /* Delete the clients */
1352 silc_dlist_start(clients);
1353 while ((client_entry = silc_dlist_get(clients))) {
1354 silc_client_remove_from_channels(client, conn, client_entry);
1355 silc_client_del_client(client, conn, client_entry);
1359 /** Notify processed */
1360 silc_client_list_free(client, conn, clients);
1361 silc_fsm_next(fsm, silc_client_notify_processed);
1362 return SILC_FSM_CONTINUE;
1365 /******************************** ERROR *************************************/
1367 /* Some error occurred */
1369 SILC_FSM_STATE(silc_client_notify_error)
1371 SilcClientConnection conn = fsm_context;
1372 SilcClient client = conn->client;
1373 SilcClientNotify notify = state_context;
1374 SilcNotifyPayload payload = notify->payload;
1375 SilcNotifyType type = silc_notify_get_type(payload);
1376 SilcArgumentPayload args = silc_notify_get_args(payload);
1377 SilcClientEntry client_entry;
1384 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1385 if (!tmp && tmp_len != 1)
1387 error = (SilcStatus)tmp[0];
1389 SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1391 /* Handle the error */
1392 if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1393 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
1395 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1397 silc_client_remove_from_channels(client, conn, client_entry);
1398 silc_client_del_client(client, conn, client_entry);
1399 silc_client_unref_client(client, conn, client_entry);
1403 /* Notify application. */
1404 NOTIFY(client, conn, type, error);
1407 /** Notify processed */
1408 silc_fsm_next(fsm, silc_client_notify_processed);
1409 return SILC_FSM_CONTINUE;
1412 /******************************** WATCH *************************************/
1414 /* Received notify about some client we are watching */
1416 SILC_FSM_STATE(silc_client_notify_watch)
1418 SilcClientConnection conn = fsm_context;
1419 SilcClient client = conn->client;
1420 SilcClientNotify notify = state_context;
1421 SilcNotifyPayload payload = notify->payload;
1422 SilcNotifyType type = silc_notify_get_type(payload);
1423 SilcArgumentPayload args = silc_notify_get_args(payload);
1424 SilcClientEntry client_entry = NULL;
1425 SilcNotifyType ntype = 0;
1426 SilcBool del_client = FALSE;
1427 unsigned char *pk, *tmp;
1428 SilcUInt32 mode, pk_len, tmp_len;
1429 SilcPublicKey public_key = NULL;
1432 SILC_LOG_DEBUG(("Notify: WATCH"));
1434 /* Get sender Client ID */
1435 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1438 /* Find Client entry and if not found resolve it */
1439 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1440 if (!client_entry || !client_entry->nickname[0]) {
1441 /** Resolve client */
1442 silc_client_unref_client(client, conn, client_entry);
1443 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1444 client, conn, &id.u.client_id, NULL,
1445 silc_client_notify_resolved,
1451 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1452 if (!tmp || tmp_len != 4)
1454 SILC_GET32_MSB(mode, tmp);
1456 /* Get notify type */
1457 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1458 if (tmp && tmp_len != 2)
1461 SILC_GET16_MSB(ntype, tmp);
1464 tmp = silc_argument_get_arg_type(args, 2, NULL);
1466 char *tmp_nick = NULL;
1468 if (client->internal->params->nickname_parse)
1469 client->internal->params->nickname_parse(client_entry->nickname,
1472 tmp_nick = strdup(tmp);
1474 /* If same nick, the client was new to us and has become "present"
1475 to network. Send NULL as nick to application. */
1476 if (tmp_nick && silc_utf8_strcasecmp(tmp, tmp_nick))
1479 silc_free(tmp_nick);
1482 /* Get public key, if present */
1483 pk = silc_argument_get_arg_type(args, 5, &pk_len);
1484 if (pk && !client_entry->public_key) {
1485 if (silc_public_key_payload_decode(pk, pk_len, &public_key)) {
1486 client_entry->public_key = public_key;
1491 /* Notify application. */
1492 NOTIFY(client, conn, type, client_entry, tmp, mode, ntype,
1493 client_entry->public_key);
1495 client_entry->mode = mode;
1497 /* If nickname was changed, remove the client entry unless the
1498 client is on some channel */
1499 /* XXX, why do we need to remove the client entry?? */
1500 if (tmp && ntype == SILC_NOTIFY_TYPE_NICK_CHANGE &&
1501 !silc_hash_table_count(client_entry->channels))
1503 else if (ntype == SILC_NOTIFY_TYPE_SIGNOFF ||
1504 ntype == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
1505 ntype == SILC_NOTIFY_TYPE_KILLED)
1509 silc_client_remove_from_channels(client, conn, client_entry);
1510 silc_client_del_client(client, conn, client_entry);
1514 silc_pkcs_public_key_free(public_key);
1517 /** Notify processed */
1518 silc_client_unref_client(client, conn, client_entry);
1519 silc_fsm_next(fsm, silc_client_notify_processed);
1520 return SILC_FSM_CONTINUE;