5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2007 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_SYNC(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 SilcPacket packet = notify->packet;
475 SilcNotifyType type = silc_notify_get_type(payload);
476 SilcArgumentPayload args = silc_notify_get_args(payload);
477 SilcClientEntry client_entry;
478 SilcChannelEntry channel;
483 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
486 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
489 /* Find Client entry */
490 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
494 /* Get signoff message */
495 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
496 if (tmp && tmp_len > 128)
499 /* Notify application */
500 NOTIFY(client, conn, type, client_entry, tmp);
502 /* Remove from channel */
503 if (packet->dst_id_type == SILC_ID_CHANNEL) {
504 if (silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
505 &id.u.channel_id, sizeof(id.u.channel_id))) {
506 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
508 silc_client_remove_from_channel(client, conn, channel, client_entry);
509 silc_client_unref_channel(client, conn, channel);
515 silc_client_del_client(client, conn, client_entry);
516 silc_client_unref_client(client, conn, client_entry);
519 /** Notify processed */
520 silc_fsm_next(fsm, silc_client_notify_processed);
524 /******************************** TOPIC_SET *********************************/
526 /* Someone set topic on a channel */
528 SILC_FSM_STATE(silc_client_notify_topic_set)
530 SilcClientConnection conn = fsm_context;
531 SilcClient client = conn->client;
532 SilcClientNotify notify = state_context;
533 SilcNotifyPayload payload = notify->payload;
534 SilcPacket packet = notify->packet;
535 SilcNotifyType type = silc_notify_get_type(payload);
536 SilcArgumentPayload args = silc_notify_get_args(payload);
537 SilcClientEntry client_entry = NULL;
538 SilcChannelEntry channel = NULL, channel_entry = NULL;
539 SilcServerEntry server = NULL;
545 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
547 /* Get channel entry */
548 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
549 &id.u.channel_id, sizeof(id.u.channel_id)))
551 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
555 /* If channel is being resolved handle notify after resolving */
556 if (channel->internal.resolve_cmd_ident) {
557 silc_client_unref_channel(client, conn, channel);
558 SILC_FSM_CALL(silc_client_command_pending(
559 conn, SILC_COMMAND_NONE,
560 channel->internal.resolve_cmd_ident,
561 silc_client_notify_wait_continue,
567 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
571 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
575 if (id.type == SILC_ID_CLIENT) {
576 /* Find Client entry */
577 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
578 if (!client_entry || !client_entry->nickname[0]) {
579 /** Resolve client */
580 silc_client_unref_client(client, conn, client_entry);
581 notify->channel = channel;
582 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
583 silc_client_get_client_by_id_resolve(
584 client, conn, &id.u.client_id, NULL,
585 silc_client_notify_resolved,
589 entry = client_entry;
590 } else if (id.type == SILC_ID_SERVER) {
591 /* Find Server entry */
592 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
594 /** Resolve server */
595 notify->channel = channel;
596 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
597 silc_client_get_server_by_id_resolve(
598 client, conn, &id.u.server_id,
599 silc_client_notify_resolved,
605 /* Find Channel entry */
606 channel_entry = silc_client_get_channel_by_id(client, conn,
608 if (!channel_entry) {
609 /** Resolve channel */
610 notify->channel = channel;
611 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
612 silc_client_get_channel_by_id_resolve(
613 client, conn, &id.u.channel_id,
614 silc_client_notify_resolved,
618 entry = channel_entry;
621 silc_free(channel->topic);
622 channel->topic = silc_memdup(tmp, strlen(tmp));
624 /* Notify application. */
625 NOTIFY(client, conn, type, id.type, entry, channel->topic, channel);
628 silc_client_unref_client(client, conn, client_entry);
630 silc_client_unref_server(client, conn, server);
632 silc_client_unref_channel(client, conn, channel_entry);
635 /** Notify processed */
636 silc_client_unref_channel(client, conn, channel);
637 silc_fsm_next(fsm, silc_client_notify_processed);
641 /****************************** NICK_CHANGE *********************************/
643 /* Someone changed their nickname on a channel */
645 SILC_FSM_STATE(silc_client_notify_nick_change)
647 SilcClientConnection conn = fsm_context;
648 SilcClient client = conn->client;
649 SilcClientNotify notify = state_context;
650 SilcNotifyPayload payload = notify->payload;
651 SilcNotifyType type = silc_notify_get_type(payload);
652 SilcArgumentPayload args = silc_notify_get_args(payload);
653 SilcClientEntry client_entry = NULL;
654 unsigned char *tmp, oldnick[128 + 1];
658 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
661 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
665 if (conn->local_id &&
666 SILC_ID_CLIENT_COMPARE(&id.u.client_id, conn->local_id))
669 /* Get new Client ID */
670 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id2, NULL))
674 if (conn->local_id &&
675 SILC_ID_CLIENT_COMPARE(&id2.u.client_id, conn->local_id))
678 /* Find old Client entry */
679 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
680 if (!client_entry || !client_entry->nickname[0]) {
681 /** Resolve client */
682 silc_client_unref_client(client, conn, client_entry);
683 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
684 client, conn, &id.u.client_id, NULL,
685 silc_client_notify_resolved,
690 /* Take the new nickname */
691 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
695 /* Check whether nickname changed at all. It is possible that nick
696 change notify is received but nickname didn't change, only the
697 ID changes. If Client ID hash match, nickname didn't change. */
698 if (SILC_ID_COMPARE_HASH(&client_entry->id, &id2.u.client_id) &&
699 silc_utf8_strcasecmp(tmp, client_entry->nickname)) {
700 /* Nickname didn't change. Update only Client ID. We don't notify
701 application because nickname didn't change. */
702 silc_mutex_lock(conn->internal->lock);
703 silc_idcache_update_by_context(conn->internal->client_cache, client_entry,
704 &id2.u.client_id, NULL, FALSE);
705 silc_mutex_unlock(conn->internal->lock);
709 /* Change the nickname */
710 memcpy(oldnick, client_entry->nickname, sizeof(client_entry->nickname));
711 if (!silc_client_change_nickname(client, conn, client_entry, tmp,
712 &id2.u.client_id, NULL, 0))
715 /* Notify application */
716 NOTIFY(client, conn, type, client_entry, client_entry->nickname, oldnick);
719 /** Notify processed */
720 silc_client_unref_client(client, conn, client_entry);
721 silc_fsm_next(fsm, silc_client_notify_processed);
725 /****************************** CMODE_CHANGE ********************************/
727 /* Someone changed channel mode */
729 SILC_FSM_STATE(silc_client_notify_cmode_change)
731 SilcClientConnection conn = fsm_context;
732 SilcClient client = conn->client;
733 SilcClientNotify notify = state_context;
734 SilcNotifyPayload payload = notify->payload;
735 SilcPacket packet = notify->packet;
736 SilcNotifyType type = silc_notify_get_type(payload);
737 SilcArgumentPayload args = silc_notify_get_args(payload);
738 SilcClientEntry client_entry = NULL;
739 SilcChannelEntry channel = NULL, channel_entry = NULL;
740 SilcServerEntry server = NULL;
743 SilcUInt32 tmp_len, mode;
745 char *passphrase, *cipher, *hmac;
746 SilcPublicKey founder_key = NULL;
747 SilcDList chpks = NULL;
749 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
751 /* Get channel entry */
752 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
753 &id.u.channel_id, sizeof(id.u.channel_id)))
755 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
759 /* If channel is being resolved handle notify after resolving */
760 if (channel->internal.resolve_cmd_ident) {
761 silc_client_unref_channel(client, conn, channel);
762 SILC_FSM_CALL(silc_client_command_pending(
763 conn, SILC_COMMAND_NONE,
764 channel->internal.resolve_cmd_ident,
765 silc_client_notify_wait_continue,
771 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
774 SILC_GET32_MSB(mode, tmp);
777 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
780 if (id.type == SILC_ID_CLIENT) {
781 /* Find Client entry */
782 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
783 if (!client_entry || !client_entry->nickname[0]) {
784 /** Resolve client */
785 silc_client_unref_client(client, conn, client_entry);
786 notify->channel = channel;
787 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
788 silc_client_get_client_by_id_resolve(
789 client, conn, &id.u.client_id, NULL,
790 silc_client_notify_resolved,
794 entry = client_entry;
795 } else if (id.type == SILC_ID_SERVER) {
796 /* Find Server entry */
797 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
799 /** Resolve server */
800 notify->channel = channel;
801 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
802 silc_client_get_server_by_id_resolve(
803 client, conn, &id.u.server_id,
804 silc_client_notify_resolved,
810 /* Find Channel entry */
811 channel_entry = silc_client_get_channel_by_id(client, conn,
813 if (!channel_entry) {
814 /** Resolve channel */
815 notify->channel = channel;
816 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
817 silc_client_get_channel_by_id_resolve(
818 client, conn, &id.u.channel_id,
819 silc_client_notify_resolved,
823 entry = channel_entry;
826 /* Get the channel founder key if it was set */
827 tmp = silc_argument_get_arg_type(args, 6, &tmp_len);
829 if (!silc_public_key_payload_decode(tmp, tmp_len, &founder_key))
831 if (!channel->founder_key) {
832 channel->founder_key = founder_key;
838 cipher = silc_argument_get_arg_type(args, 3, &tmp_len);
841 hmac = silc_argument_get_arg_type(args, 4, &tmp_len);
843 unsigned char hash[SILC_HASH_MAXLEN];
846 if (!silc_hmac_alloc(hmac, NULL, &newhmac))
849 /* Get HMAC key from the old HMAC context, and update it to the new one */
850 tmp = (unsigned char *)silc_hmac_get_key(channel->internal.hmac, &tmp_len);
852 silc_hash_make(silc_hmac_get_hash(newhmac), tmp, tmp_len, hash);
853 silc_hmac_set_key(newhmac, hash,
854 silc_hash_len(silc_hmac_get_hash(newhmac)));
855 if (channel->internal.hmac)
856 silc_hmac_free(channel->internal.hmac);
857 channel->internal.hmac = newhmac;
858 memset(hash, 0, sizeof(hash));
862 /* Get the passphrase if it was set */
863 passphrase = silc_argument_get_arg_type(args, 5, &tmp_len);
866 tmp = silc_argument_get_arg_type(args, 8, &tmp_len);
867 if (tmp && tmp_len == 4)
868 SILC_GET32_MSB(channel->user_limit, tmp);
869 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
870 channel->user_limit = 0;
872 /* Save the new mode */
873 channel->mode = mode;
875 /* Get the channel public key that was added or removed */
876 tmp = silc_argument_get_arg_type(args, 7, &tmp_len);
878 chpks = silc_argument_list_parse_decoded(tmp, tmp_len,
879 SILC_ARGUMENT_PUBLIC_KEY);
881 /* XXX add to/remove from channel pubkeys channel->channel_pubkeys */
883 /* Notify application. */
884 NOTIFY(client, conn, type, id.type, entry, mode, cipher, hmac,
885 passphrase, channel->founder_key, chpks, channel);
889 silc_pkcs_public_key_free(founder_key);
891 silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
893 silc_client_unref_client(client, conn, client_entry);
895 silc_client_unref_server(client, conn, server);
897 silc_client_unref_channel(client, conn, channel_entry);
898 silc_client_unref_channel(client, conn, channel);
900 /** Notify processed */
901 silc_fsm_next(fsm, silc_client_notify_processed);
905 /***************************** CUMODE_CHANGE ********************************/
907 /* Someone changed a user's mode on a channel */
909 SILC_FSM_STATE(silc_client_notify_cumode_change)
911 SilcClientConnection conn = fsm_context;
912 SilcClient client = conn->client;
913 SilcClientNotify notify = state_context;
914 SilcNotifyPayload payload = notify->payload;
915 SilcPacket packet = notify->packet;
916 SilcNotifyType type = silc_notify_get_type(payload);
917 SilcArgumentPayload args = silc_notify_get_args(payload);
918 SilcClientEntry client_entry = NULL, client_entry2 = NULL;
919 SilcChannelEntry channel = NULL, channel_entry = NULL;
920 SilcServerEntry server = NULL;
924 SilcUInt32 tmp_len, mode;
927 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
929 /* Get channel entry */
930 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
931 &id.u.channel_id, sizeof(id.u.channel_id)))
933 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
937 /* If channel is being resolved handle notify after resolving */
938 if (channel->internal.resolve_cmd_ident) {
939 silc_client_unref_channel(client, conn, channel);
940 SILC_FSM_CALL(silc_client_command_pending(
941 conn, SILC_COMMAND_NONE,
942 channel->internal.resolve_cmd_ident,
943 silc_client_notify_wait_continue,
948 /* Get target Client ID */
949 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id2, NULL))
952 /* Find target Client entry */
953 client_entry2 = silc_client_get_client_by_id(client, conn, &id2.u.client_id);
954 if (!client_entry2 || !client_entry2->nickname[0]) {
955 /** Resolve client */
956 silc_client_unref_client(client, conn, client_entry2);
957 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
958 client, conn, &id2.u.client_id, NULL,
959 silc_client_notify_resolved,
965 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
968 SILC_GET32_MSB(mode, tmp);
971 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
974 if (id.type == SILC_ID_CLIENT) {
975 /* Find Client entry */
976 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
977 if (!client_entry || !client_entry->nickname[0]) {
978 /** Resolve client */
979 silc_client_unref_client(client, conn, client_entry);
980 notify->channel = channel;
981 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
982 silc_client_get_client_by_id_resolve(
983 client, conn, &id.u.client_id, NULL,
984 silc_client_notify_resolved,
988 entry = client_entry;
989 } else if (id.type == SILC_ID_SERVER) {
990 /* Find Server entry */
991 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
993 /** Resolve server */
994 notify->channel = channel;
995 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
996 silc_client_get_server_by_id_resolve(
997 client, conn, &id.u.server_id,
998 silc_client_notify_resolved,
1004 /* Find Channel entry */
1005 channel_entry = silc_client_get_channel_by_id(client, conn,
1007 if (!channel_entry) {
1008 /** Resolve channel */
1009 notify->channel = channel;
1010 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1011 silc_client_get_channel_by_id_resolve(
1012 client, conn, &id.u.channel_id,
1013 silc_client_notify_resolved,
1017 entry = channel_entry;
1021 chu = silc_client_on_channel(channel, client_entry2);
1025 /* Notify application. */
1026 NOTIFY(client, conn, type, id.type, entry, mode, client_entry2, channel);
1029 silc_client_unref_client(client, conn, client_entry2);
1031 silc_client_unref_client(client, conn, client_entry);
1033 silc_client_unref_server(client, conn, server);
1035 silc_client_unref_channel(client, conn, channel_entry);
1036 silc_client_unref_channel(client, conn, channel);
1038 /** Notify processed */
1039 silc_fsm_next(fsm, silc_client_notify_processed);
1043 /********************************* MOTD *************************************/
1045 /* Received Message of the day */
1047 SILC_FSM_STATE(silc_client_notify_motd)
1049 SilcClientConnection conn = fsm_context;
1050 SilcClient client = conn->client;
1051 SilcClientNotify notify = state_context;
1052 SilcNotifyPayload payload = notify->payload;
1053 SilcNotifyType type = silc_notify_get_type(payload);
1054 SilcArgumentPayload args = silc_notify_get_args(payload);
1058 SILC_LOG_DEBUG(("Notify: MOTD"));
1061 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1065 /* Notify application */
1066 NOTIFY(client, conn, type, tmp);
1069 /** Notify processed */
1070 silc_fsm_next(fsm, silc_client_notify_processed);
1074 /**************************** CHANNEL CHANGE ********************************/
1076 /* Router has enforced a new ID to a channel, change it */
1078 SILC_FSM_STATE(silc_client_notify_channel_change)
1080 SilcClientConnection conn = fsm_context;
1081 SilcClient client = conn->client;
1082 SilcClientNotify notify = state_context;
1083 SilcNotifyPayload payload = notify->payload;
1084 SilcNotifyType type = silc_notify_get_type(payload);
1085 SilcArgumentPayload args = silc_notify_get_args(payload);
1086 SilcChannelEntry channel = NULL;
1089 SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
1091 /* Get the old ID */
1092 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1095 /* Get the channel entry */
1096 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1100 /* If channel is being resolved handle notify after resolving */
1101 if (channel->internal.resolve_cmd_ident) {
1102 silc_client_unref_channel(client, conn, channel);
1103 SILC_FSM_CALL(silc_client_command_pending(
1104 conn, SILC_COMMAND_NONE,
1105 channel->internal.resolve_cmd_ident,
1106 silc_client_notify_wait_continue,
1111 /* Get the new ID */
1112 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
1115 /* Replace the Channel ID */
1116 if (!silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id))
1119 /* Notify application */
1120 NOTIFY(client, conn, type, channel, channel);
1123 /** Notify processed */
1124 silc_client_unref_channel(client, conn, channel);
1125 silc_fsm_next(fsm, silc_client_notify_processed);
1129 /******************************** KICKED ************************************/
1131 /* Some client was kicked from a channel */
1133 SILC_FSM_STATE(silc_client_notify_kicked)
1135 SilcClientConnection conn = fsm_context;
1136 SilcClient client = conn->client;
1137 SilcClientNotify notify = state_context;
1138 SilcNotifyPayload payload = notify->payload;
1139 SilcPacket packet = notify->packet;
1140 SilcNotifyType type = silc_notify_get_type(payload);
1141 SilcArgumentPayload args = silc_notify_get_args(payload);
1142 SilcClientEntry client_entry, client_entry2;
1143 SilcChannelEntry channel = NULL;
1148 SILC_LOG_DEBUG(("Notify: KICKED"));
1150 /* Get channel entry */
1151 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
1152 &id.u.channel_id, sizeof(id.u.channel_id)))
1154 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1158 /* If channel is being resolved handle notify after resolving */
1159 if (channel->internal.resolve_cmd_ident) {
1160 silc_client_unref_channel(client, conn, channel);
1161 SILC_FSM_CALL(silc_client_command_pending(
1162 conn, SILC_COMMAND_NONE,
1163 channel->internal.resolve_cmd_ident,
1164 silc_client_notify_wait_continue,
1170 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1173 /* Find Client entry */
1174 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1178 /* Get kicker's Client ID */
1179 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
1182 /* Find kicker's client entry and if not found resolve it */
1183 client_entry2 = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1184 if (!client_entry2 || !client_entry2->nickname[0]) {
1185 /** Resolve client */
1186 silc_client_unref_client(client, conn, client_entry);
1187 silc_client_unref_client(client, conn, client_entry2);
1188 notify->channel = channel;
1189 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1190 silc_client_get_client_by_id_resolve(
1191 client, conn, &id.u.client_id, NULL,
1192 silc_client_notify_resolved,
1198 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1200 /* Remove kicked client from channel */
1201 if (client_entry != conn->local_entry)
1202 silc_client_remove_from_channel(client, conn, channel, client_entry);
1204 /* Notify application. */
1205 NOTIFY(client, conn, type, client_entry, tmp, client_entry2, channel);
1207 /* If I was kicked from channel, remove the channel */
1208 if (client_entry == conn->local_entry) {
1209 if (conn->current_channel == channel)
1210 conn->current_channel = NULL;
1211 silc_client_empty_channel(client, conn, channel);
1212 silc_client_del_channel(client, conn, channel);
1215 silc_client_unref_client(client, conn, client_entry);
1216 silc_client_unref_client(client, conn, client_entry2);
1219 /** Notify processed */
1220 silc_client_unref_channel(client, conn, channel);
1221 silc_fsm_next(fsm, silc_client_notify_processed);
1225 /******************************** KILLED ************************************/
1227 /* Some client was killed from the network */
1229 SILC_FSM_STATE(silc_client_notify_killed)
1231 SilcClientConnection conn = fsm_context;
1232 SilcClient client = conn->client;
1233 SilcClientNotify notify = state_context;
1234 SilcNotifyPayload payload = notify->payload;
1235 SilcNotifyType type = silc_notify_get_type(payload);
1236 SilcArgumentPayload args = silc_notify_get_args(payload);
1237 SilcClientEntry client_entry = NULL, client_entry2 = NULL;
1238 SilcChannelEntry channel_entry = NULL;
1239 SilcServerEntry server = NULL;
1242 SilcUInt32 comment_len;
1245 SILC_LOG_DEBUG(("Notify: KILLED"));
1248 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1251 /* Find Client entry */
1252 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1257 comment = silc_argument_get_arg_type(args, 2, &comment_len);
1259 /* Get killer's ID */
1260 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
1263 if (id.type == SILC_ID_CLIENT) {
1264 /* Find Client entry */
1265 client_entry2 = silc_client_get_client_by_id(client, conn,
1267 if (!client_entry2 || !client_entry2->nickname[0]) {
1268 /** Resolve client */
1269 silc_client_unref_client(client, conn, client_entry);
1270 silc_client_unref_client(client, conn, client_entry2);
1271 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1272 client, conn, &id.u.client_id, NULL,
1273 silc_client_notify_resolved,
1277 entry = client_entry2;
1278 } else if (id.type == SILC_ID_SERVER) {
1279 /* Find Server entry */
1280 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1282 /** Resolve server */
1283 SILC_FSM_CALL(silc_client_get_server_by_id_resolve(
1284 client, conn, &id.u.server_id,
1285 silc_client_notify_resolved,
1291 /* Find Channel entry */
1292 channel_entry = silc_client_get_channel_by_id(client, conn,
1294 if (!channel_entry) {
1295 /** Resolve channel */
1296 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1297 client, conn, &id.u.channel_id,
1298 silc_client_notify_resolved,
1302 entry = channel_entry;
1305 /* Notify application. */
1306 NOTIFY(client, conn, type, client_entry, comment, id.type, entry);
1308 /* Delete the killed client */
1309 if (client_entry != conn->local_entry) {
1310 silc_client_remove_from_channels(client, conn, client_entry);
1311 silc_client_del_client(client, conn, client_entry);
1315 silc_client_unref_client(client, conn, client_entry);
1317 silc_client_unref_client(client, conn, client_entry2);
1319 silc_client_unref_server(client, conn, server);
1321 silc_client_unref_channel(client, conn, channel_entry);
1323 /** Notify processed */
1324 silc_fsm_next(fsm, silc_client_notify_processed);
1328 /**************************** SERVER SIGNOFF ********************************/
1330 /* Some server quit SILC network. Remove its clients from channels. */
1332 SILC_FSM_STATE(silc_client_notify_server_signoff)
1334 SilcClientConnection conn = fsm_context;
1335 SilcClient client = conn->client;
1336 SilcClientNotify notify = state_context;
1337 SilcNotifyPayload payload = notify->payload;
1338 SilcNotifyType type = silc_notify_get_type(payload);
1339 SilcArgumentPayload args = silc_notify_get_args(payload);
1340 SilcClientEntry client_entry;
1345 SILC_LOG_DEBUG(("Notify: SERVER_SIGNOFF"));
1347 clients = silc_dlist_init();
1351 for (i = 1; i < silc_argument_get_arg_num(args); i++) {
1353 if (!silc_argument_get_decoded(args, i + 1, SILC_ARGUMENT_ID, &id, NULL))
1356 /* Get the client entry */
1357 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1359 silc_dlist_add(clients, client_entry);
1362 /* Notify application. We don't keep server entries so the server
1363 entry is returned as NULL. The client's are returned as list. */
1364 NOTIFY(client, conn, type, NULL, clients);
1366 /* Delete the clients */
1367 silc_dlist_start(clients);
1368 while ((client_entry = silc_dlist_get(clients))) {
1369 silc_client_remove_from_channels(client, conn, client_entry);
1370 silc_client_del_client(client, conn, client_entry);
1374 /** Notify processed */
1375 silc_client_list_free(client, conn, clients);
1376 silc_fsm_next(fsm, silc_client_notify_processed);
1380 /******************************** ERROR *************************************/
1382 /* Some error occurred */
1384 SILC_FSM_STATE(silc_client_notify_error)
1386 SilcClientConnection conn = fsm_context;
1387 SilcClient client = conn->client;
1388 SilcClientNotify notify = state_context;
1389 SilcNotifyPayload payload = notify->payload;
1390 SilcNotifyType type = silc_notify_get_type(payload);
1391 SilcArgumentPayload args = silc_notify_get_args(payload);
1392 SilcClientEntry client_entry;
1399 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1400 if (!tmp && tmp_len != 1)
1402 error = (SilcStatus)tmp[0];
1404 SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1406 /* Handle the error */
1407 if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1408 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
1410 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1412 silc_client_remove_from_channels(client, conn, client_entry);
1413 silc_client_del_client(client, conn, client_entry);
1414 silc_client_unref_client(client, conn, client_entry);
1418 /* Notify application. */
1419 NOTIFY(client, conn, type, error);
1422 /** Notify processed */
1423 silc_fsm_next(fsm, silc_client_notify_processed);
1427 /******************************** WATCH *************************************/
1429 /* Received notify about some client we are watching */
1431 SILC_FSM_STATE(silc_client_notify_watch)
1433 SilcClientConnection conn = fsm_context;
1434 SilcClient client = conn->client;
1435 SilcClientNotify notify = state_context;
1436 SilcNotifyPayload payload = notify->payload;
1437 SilcNotifyType type = silc_notify_get_type(payload);
1438 SilcArgumentPayload args = silc_notify_get_args(payload);
1439 SilcClientEntry client_entry = NULL;
1440 SilcNotifyType ntype = 0;
1441 SilcBool del_client = FALSE;
1442 unsigned char *pk, *tmp;
1443 SilcUInt32 mode, pk_len, tmp_len;
1444 SilcPublicKey public_key = NULL;
1447 SILC_LOG_DEBUG(("Notify: WATCH"));
1449 /* Get sender Client ID */
1450 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1453 /* Find Client entry and if not found resolve it */
1454 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1455 if (!client_entry || !client_entry->nickname[0]) {
1456 /** Resolve client */
1457 silc_client_unref_client(client, conn, client_entry);
1458 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1459 client, conn, &id.u.client_id, NULL,
1460 silc_client_notify_resolved,
1466 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1467 if (!tmp || tmp_len != 4)
1469 SILC_GET32_MSB(mode, tmp);
1471 /* Get notify type */
1472 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1473 if (tmp && tmp_len != 2)
1476 SILC_GET16_MSB(ntype, tmp);
1479 tmp = silc_argument_get_arg_type(args, 2, NULL);
1481 char *tmp_nick = NULL;
1483 silc_client_nickname_parse(client, conn, client_entry->nickname,
1486 /* If same nick, the client was new to us and has become "present"
1487 to network. Send NULL as nick to application. */
1488 if (tmp_nick && silc_utf8_strcasecmp(tmp, tmp_nick))
1491 silc_free(tmp_nick);
1494 /* Get public key, if present */
1495 pk = silc_argument_get_arg_type(args, 5, &pk_len);
1496 if (pk && !client_entry->public_key) {
1497 if (silc_public_key_payload_decode(pk, pk_len, &public_key)) {
1498 client_entry->public_key = public_key;
1503 /* Notify application. */
1504 NOTIFY(client, conn, type, client_entry, tmp, mode, ntype,
1505 client_entry->public_key);
1507 client_entry->mode = mode;
1509 /* If nickname was changed, remove the client entry unless the
1510 client is on some channel */
1511 /* XXX, why do we need to remove the client entry?? */
1512 if (tmp && ntype == SILC_NOTIFY_TYPE_NICK_CHANGE &&
1513 !silc_hash_table_count(client_entry->channels))
1515 else if (ntype == SILC_NOTIFY_TYPE_SIGNOFF ||
1516 ntype == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
1517 ntype == SILC_NOTIFY_TYPE_KILLED)
1521 silc_client_remove_from_channels(client, conn, client_entry);
1522 silc_client_del_client(client, conn, client_entry);
1526 silc_pkcs_public_key_free(public_key);
1529 /** Notify processed */
1530 silc_client_unref_client(client, conn, client_entry);
1531 silc_fsm_next(fsm, silc_client_notify_processed);