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);
498 /* Remove from all channels */
499 silc_client_remove_from_channels(client, conn, client_entry);
502 /* Remove from cache */
503 silc_idcache_del_by_context(conn->internal->client_cache, client_entry);
507 silc_client_unref_client(client, conn, client_entry);
508 silc_client_del_client_entry(client, conn, client_entry);
511 /** Notify processed */
512 silc_fsm_next(fsm, silc_client_notify_processed);
513 return SILC_FSM_CONTINUE;
516 /******************************** TOPIC_SET *********************************/
518 /* Someone set topic on a channel */
520 SILC_FSM_STATE(silc_client_notify_topic_set)
522 SilcClientConnection conn = fsm_context;
523 SilcClient client = conn->client;
524 SilcClientNotify notify = state_context;
525 SilcNotifyPayload payload = notify->payload;
526 SilcPacket packet = notify->packet;
527 SilcNotifyType type = silc_notify_get_type(payload);
528 SilcArgumentPayload args = silc_notify_get_args(payload);
529 SilcClientEntry client_entry = NULL;
530 SilcChannelEntry channel = NULL, channel_entry = NULL;
531 SilcServerEntry server = NULL;
537 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
539 /* Get channel entry */
540 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
541 &id.u.channel_id, sizeof(id.u.channel_id)))
543 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
547 /* If channel is being resolved handle notify after resolving */
548 if (channel->internal.resolve_cmd_ident) {
549 silc_client_unref_channel(client, conn, channel);
550 SILC_FSM_CALL(silc_client_command_pending(
551 conn, SILC_COMMAND_NONE,
552 channel->internal.resolve_cmd_ident,
553 silc_client_notify_wait_continue,
559 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
563 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
567 if (id.type == SILC_ID_CLIENT) {
568 /* Find Client entry */
569 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
570 if (!client_entry || !client_entry->nickname[0]) {
571 /** Resolve client */
572 silc_client_unref_client(client, conn, client_entry);
573 notify->channel = channel;
574 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
575 silc_client_get_client_by_id_resolve(
576 client, conn, &id.u.client_id, NULL,
577 silc_client_notify_resolved,
581 entry = client_entry;
582 } else if (id.type == SILC_ID_SERVER) {
583 /* Find Server entry */
584 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
586 /** Resolve server */
587 notify->channel = channel;
588 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
589 silc_client_get_server_by_id_resolve(
590 client, conn, &id.u.server_id,
591 silc_client_notify_resolved,
597 /* Find Channel entry */
598 channel_entry = silc_client_get_channel_by_id(client, conn,
600 if (!channel_entry) {
601 /** Resolve channel */
602 notify->channel = channel;
603 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
604 silc_client_get_channel_by_id_resolve(
605 client, conn, &id.u.channel_id,
606 silc_client_notify_resolved,
610 entry = channel_entry;
613 silc_free(channel->topic);
614 channel->topic = silc_memdup(tmp, strlen(tmp));
616 /* Notify application. */
617 NOTIFY(client, conn, type, id.type, entry, channel->topic, channel);
620 silc_client_unref_client(client, conn, client_entry);
622 silc_client_unref_server(client, conn, server);
624 silc_client_unref_channel(client, conn, channel_entry);
627 /** Notify processed */
628 silc_client_unref_channel(client, conn, channel);
629 silc_fsm_next(fsm, silc_client_notify_processed);
630 return SILC_FSM_CONTINUE;
633 /****************************** NICK_CHANGE *********************************/
635 /* Someone changed their nickname on a channel */
637 SILC_FSM_STATE(silc_client_notify_nick_change)
639 SilcClientConnection conn = fsm_context;
640 SilcClient client = conn->client;
641 SilcClientNotify notify = state_context;
642 SilcNotifyPayload payload = notify->payload;
643 SilcNotifyType type = silc_notify_get_type(payload);
644 SilcArgumentPayload args = silc_notify_get_args(payload);
645 SilcClientEntry client_entry = NULL;
646 unsigned char *tmp, *nick, oldnick[128 + 1];
650 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
653 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
657 if (conn->local_id &&
658 SILC_ID_CLIENT_COMPARE(&id.u.client_id, conn->local_id))
661 /* Get new Client ID */
662 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id2, NULL))
666 if (conn->local_id &&
667 SILC_ID_CLIENT_COMPARE(&id2.u.client_id, conn->local_id))
670 /* Find old Client entry */
671 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
672 if (!client_entry || !client_entry->nickname[0]) {
673 /** Resolve client */
674 silc_client_unref_client(client, conn, client_entry);
675 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
676 client, conn, &id.u.client_id, NULL,
677 silc_client_notify_resolved,
682 /* Take the new nickname */
683 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
687 /* Check whether nickname changed at all. It is possible that nick
688 change notify is received but nickname didn't change, only the
689 ID changes. If Client ID hash match, nickname didn't change. */
690 if (SILC_ID_COMPARE_HASH(&client_entry->id, &id2.u.client_id) &&
691 silc_utf8_strcasecmp(tmp, client_entry->nickname)) {
692 /* Nickname didn't change. Update only Client ID. We don't notify
693 application because nickname didn't change. */
694 silc_mutex_lock(conn->internal->lock);
695 silc_idcache_update_by_context(conn->internal->client_cache, client_entry,
696 &id2.u.client_id, NULL, FALSE);
697 silc_mutex_unlock(conn->internal->lock);
701 /* Normalize nickname */
702 nick = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8, 128, NULL);
706 /* Update nickname */
707 silc_mutex_lock(conn->internal->lock);
708 if (!silc_idcache_update_by_context(conn->internal->client_cache,
709 client_entry, NULL, nick, TRUE)) {
711 silc_mutex_unlock(conn->internal->lock);
714 silc_mutex_unlock(conn->internal->lock);
715 memcpy(oldnick, client_entry->nickname, sizeof(client_entry->nickname));
716 memcpy(client_entry->nickname, tmp, tmp_len);
717 client_entry->nickname_normalized = nick;
718 silc_client_nickname_format(client, conn, client_entry);
720 /* Notify application */
721 NOTIFY(client, conn, type, client_entry, client_entry->nickname, oldnick);
724 /** Notify processed */
725 silc_client_unref_client(client, conn, client_entry);
726 silc_fsm_next(fsm, silc_client_notify_processed);
727 return SILC_FSM_CONTINUE;
730 /****************************** CMODE_CHANGE ********************************/
732 /* Someone changed channel mode */
734 SILC_FSM_STATE(silc_client_notify_cmode_change)
736 SilcClientConnection conn = fsm_context;
737 SilcClient client = conn->client;
738 SilcClientNotify notify = state_context;
739 SilcNotifyPayload payload = notify->payload;
740 SilcPacket packet = notify->packet;
741 SilcNotifyType type = silc_notify_get_type(payload);
742 SilcArgumentPayload args = silc_notify_get_args(payload);
743 SilcClientEntry client_entry = NULL;
744 SilcChannelEntry channel = NULL, channel_entry = NULL;
745 SilcServerEntry server = NULL;
748 SilcUInt32 tmp_len, mode;
750 char *passphrase, *cipher, *hmac;
751 SilcPublicKey founder_key = NULL;
752 SilcDList chpks = NULL;
754 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
756 /* Get channel entry */
757 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
758 &id.u.channel_id, sizeof(id.u.channel_id)))
760 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
764 /* If channel is being resolved handle notify after resolving */
765 if (channel->internal.resolve_cmd_ident) {
766 silc_client_unref_channel(client, conn, channel);
767 SILC_FSM_CALL(silc_client_command_pending(
768 conn, SILC_COMMAND_NONE,
769 channel->internal.resolve_cmd_ident,
770 silc_client_notify_wait_continue,
776 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
779 SILC_GET32_MSB(mode, tmp);
782 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
785 if (id.type == SILC_ID_CLIENT) {
786 /* Find Client entry */
787 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
788 if (!client_entry || !client_entry->nickname[0]) {
789 /** Resolve client */
790 silc_client_unref_client(client, conn, client_entry);
791 notify->channel = channel;
792 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
793 silc_client_get_client_by_id_resolve(
794 client, conn, &id.u.client_id, NULL,
795 silc_client_notify_resolved,
799 entry = client_entry;
800 } else if (id.type == SILC_ID_SERVER) {
801 /* Find Server entry */
802 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
804 /** Resolve server */
805 notify->channel = channel;
806 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
807 silc_client_get_server_by_id_resolve(
808 client, conn, &id.u.server_id,
809 silc_client_notify_resolved,
815 /* Find Channel entry */
816 channel_entry = silc_client_get_channel_by_id(client, conn,
818 if (!channel_entry) {
819 /** Resolve channel */
820 notify->channel = channel;
821 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
822 silc_client_get_channel_by_id_resolve(
823 client, conn, &id.u.channel_id,
824 silc_client_notify_resolved,
828 entry = channel_entry;
831 /* Get the channel founder key if it was set */
832 tmp = silc_argument_get_arg_type(args, 6, &tmp_len);
834 if (!silc_public_key_payload_decode(tmp, tmp_len, &founder_key))
836 if (!channel->founder_key) {
837 channel->founder_key = founder_key;
843 cipher = silc_argument_get_arg_type(args, 3, &tmp_len);
846 hmac = silc_argument_get_arg_type(args, 4, &tmp_len);
848 unsigned char hash[SILC_HASH_MAXLEN];
851 if (!silc_hmac_alloc(hmac, NULL, &newhmac))
854 /* Get HMAC key from the old HMAC context, and update it to the new one */
855 tmp = (unsigned char *)silc_hmac_get_key(channel->internal.hmac, &tmp_len);
857 silc_hash_make(silc_hmac_get_hash(newhmac), tmp, tmp_len, hash);
858 silc_hmac_set_key(newhmac, hash,
859 silc_hash_len(silc_hmac_get_hash(newhmac)));
860 if (channel->internal.hmac)
861 silc_hmac_free(channel->internal.hmac);
862 channel->internal.hmac = newhmac;
863 memset(hash, 0, sizeof(hash));
867 /* Get the passphrase if it was set */
868 passphrase = silc_argument_get_arg_type(args, 5, &tmp_len);
871 tmp = silc_argument_get_arg_type(args, 8, &tmp_len);
872 if (tmp && tmp_len == 4)
873 SILC_GET32_MSB(channel->user_limit, tmp);
874 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
875 channel->user_limit = 0;
877 /* Save the new mode */
878 channel->mode = mode;
880 /* Get the channel public key that was added or removed */
881 tmp = silc_argument_get_arg_type(args, 7, &tmp_len);
883 chpks = silc_argument_list_parse_decoded(tmp, tmp_len,
884 SILC_ARGUMENT_PUBLIC_KEY);
886 /* Notify application. */
887 NOTIFY(client, conn, type, id.type, entry, mode, cipher, hmac,
888 passphrase, channel->founder_key, chpks, channel);
892 silc_pkcs_public_key_free(founder_key);
894 silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
896 silc_client_unref_client(client, conn, client_entry);
898 silc_client_unref_server(client, conn, server);
900 silc_client_unref_channel(client, conn, channel_entry);
901 silc_client_unref_channel(client, conn, channel);
903 /** Notify processed */
904 silc_fsm_next(fsm, silc_client_notify_processed);
905 return SILC_FSM_CONTINUE;
908 /***************************** CUMODE_CHANGE ********************************/
910 /* Someone changed a user's mode on a channel */
912 SILC_FSM_STATE(silc_client_notify_cumode_change)
914 SilcClientConnection conn = fsm_context;
915 SilcClient client = conn->client;
916 SilcClientNotify notify = state_context;
917 SilcNotifyPayload payload = notify->payload;
918 SilcPacket packet = notify->packet;
919 SilcNotifyType type = silc_notify_get_type(payload);
920 SilcArgumentPayload args = silc_notify_get_args(payload);
921 SilcClientEntry client_entry = NULL, client_entry2 = NULL;
922 SilcChannelEntry channel = NULL, channel_entry = NULL;
923 SilcServerEntry server = NULL;
927 SilcUInt32 tmp_len, mode;
930 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
932 /* Get channel entry */
933 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
934 &id.u.channel_id, sizeof(id.u.channel_id)))
936 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
940 /* If channel is being resolved handle notify after resolving */
941 if (channel->internal.resolve_cmd_ident) {
942 silc_client_unref_channel(client, conn, channel);
943 SILC_FSM_CALL(silc_client_command_pending(
944 conn, SILC_COMMAND_NONE,
945 channel->internal.resolve_cmd_ident,
946 silc_client_notify_wait_continue,
951 /* Get target Client ID */
952 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id2, NULL))
955 /* Find target Client entry */
956 client_entry2 = silc_client_get_client_by_id(client, conn, &id2.u.client_id);
957 if (!client_entry2 || !client_entry2->nickname[0]) {
958 /** Resolve client */
959 silc_client_unref_client(client, conn, client_entry2);
960 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
961 client, conn, &id2.u.client_id, NULL,
962 silc_client_notify_resolved,
968 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
971 SILC_GET32_MSB(mode, tmp);
974 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
977 if (id.type == SILC_ID_CLIENT) {
978 /* Find Client entry */
979 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
980 if (!client_entry || !client_entry->nickname[0]) {
981 /** Resolve client */
982 silc_client_unref_client(client, conn, client_entry);
983 notify->channel = channel;
984 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
985 silc_client_get_client_by_id_resolve(
986 client, conn, &id.u.client_id, NULL,
987 silc_client_notify_resolved,
991 entry = client_entry;
992 } else if (id.type == SILC_ID_SERVER) {
993 /* Find Server entry */
994 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
996 /** Resolve server */
997 notify->channel = channel;
998 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
999 silc_client_get_server_by_id_resolve(
1000 client, conn, &id.u.server_id,
1001 silc_client_notify_resolved,
1007 /* Find Channel entry */
1008 channel_entry = silc_client_get_channel_by_id(client, conn,
1010 if (!channel_entry) {
1011 /** Resolve channel */
1012 notify->channel = channel;
1013 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1014 silc_client_get_channel_by_id_resolve(
1015 client, conn, &id.u.channel_id,
1016 silc_client_notify_resolved,
1020 entry = channel_entry;
1024 chu = silc_client_on_channel(channel, client_entry2);
1028 /* Notify application. */
1029 NOTIFY(client, conn, type, id.type, entry, mode, client_entry2, channel);
1032 silc_client_unref_client(client, conn, client_entry2);
1034 silc_client_unref_client(client, conn, client_entry);
1036 silc_client_unref_server(client, conn, server);
1038 silc_client_unref_channel(client, conn, channel_entry);
1039 silc_client_unref_channel(client, conn, channel);
1041 /** Notify processed */
1042 silc_fsm_next(fsm, silc_client_notify_processed);
1043 return SILC_FSM_CONTINUE;
1046 /********************************* MOTD *************************************/
1048 /* Received Message of the day */
1050 SILC_FSM_STATE(silc_client_notify_motd)
1052 SilcClientConnection conn = fsm_context;
1053 SilcClient client = conn->client;
1054 SilcClientNotify notify = state_context;
1055 SilcNotifyPayload payload = notify->payload;
1056 SilcNotifyType type = silc_notify_get_type(payload);
1057 SilcArgumentPayload args = silc_notify_get_args(payload);
1061 SILC_LOG_DEBUG(("Notify: MOTD"));
1064 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1068 /* Notify application */
1069 NOTIFY(client, conn, type, tmp);
1072 /** Notify processed */
1073 silc_fsm_next(fsm, silc_client_notify_processed);
1074 return SILC_FSM_CONTINUE;
1077 /**************************** CHANNEL CHANGE ********************************/
1079 /* Router has enforced a new ID to a channel, change it */
1081 SILC_FSM_STATE(silc_client_notify_channel_change)
1083 SilcClientConnection conn = fsm_context;
1084 SilcClient client = conn->client;
1085 SilcClientNotify notify = state_context;
1086 SilcNotifyPayload payload = notify->payload;
1087 SilcNotifyType type = silc_notify_get_type(payload);
1088 SilcArgumentPayload args = silc_notify_get_args(payload);
1089 SilcChannelEntry channel = NULL;
1092 SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
1094 /* Get the old ID */
1095 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1098 /* Get the channel entry */
1099 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1103 /* If channel is being resolved handle notify after resolving */
1104 if (channel->internal.resolve_cmd_ident) {
1105 silc_client_unref_channel(client, conn, channel);
1106 SILC_FSM_CALL(silc_client_command_pending(
1107 conn, SILC_COMMAND_NONE,
1108 channel->internal.resolve_cmd_ident,
1109 silc_client_notify_wait_continue,
1114 /* Get the new ID */
1115 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
1118 /* Replace the Channel ID */
1119 if (!silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id))
1122 /* Notify application */
1123 NOTIFY(client, conn, type, channel, channel);
1126 /** Notify processed */
1127 silc_client_unref_channel(client, conn, channel);
1128 silc_fsm_next(fsm, silc_client_notify_processed);
1129 return SILC_FSM_CONTINUE;
1132 /******************************** KICKED ************************************/
1134 /* Some client was kicked from a channel */
1136 SILC_FSM_STATE(silc_client_notify_kicked)
1138 SilcClientConnection conn = fsm_context;
1139 SilcClient client = conn->client;
1140 SilcClientNotify notify = state_context;
1141 SilcNotifyPayload payload = notify->payload;
1142 SilcPacket packet = notify->packet;
1143 SilcNotifyType type = silc_notify_get_type(payload);
1144 SilcArgumentPayload args = silc_notify_get_args(payload);
1145 SilcClientEntry client_entry, client_entry2;
1146 SilcChannelEntry channel = NULL;
1147 SilcChannelUser chu;
1152 SILC_LOG_DEBUG(("Notify: KICKED"));
1154 /* Get channel entry */
1155 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
1156 &id.u.channel_id, sizeof(id.u.channel_id)))
1158 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1162 /* If channel is being resolved handle notify after resolving */
1163 if (channel->internal.resolve_cmd_ident) {
1164 silc_client_unref_channel(client, conn, channel);
1165 SILC_FSM_CALL(silc_client_command_pending(
1166 conn, SILC_COMMAND_NONE,
1167 channel->internal.resolve_cmd_ident,
1168 silc_client_notify_wait_continue,
1174 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1177 /* Find Client entry */
1178 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1182 /* Get kicker's Client ID */
1183 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
1186 /* Find kicker's client entry and if not found resolve it */
1187 client_entry2 = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1188 if (!client_entry2 || !client_entry2->nickname[0]) {
1189 /** Resolve client */
1190 silc_client_unref_client(client, conn, client_entry);
1191 silc_client_unref_client(client, conn, client_entry2);
1192 notify->channel = channel;
1193 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1194 silc_client_get_client_by_id_resolve(
1195 client, conn, &id.u.client_id, NULL,
1196 silc_client_notify_resolved,
1202 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1204 /* Remove kicked client from channel */
1205 if (client_entry != conn->local_entry) {
1206 chu = silc_client_on_channel(channel, client_entry);
1208 silc_hash_table_del(client_entry->channels, channel);
1209 silc_hash_table_del(channel->user_list, client_entry);
1214 /* Notify application. */
1215 NOTIFY(client, conn, type, client_entry, tmp, client_entry2, channel);
1217 /* If I was kicked from channel, remove the channel */
1218 if (client_entry == conn->local_entry) {
1219 if (conn->current_channel == channel)
1220 conn->current_channel = NULL;
1221 silc_client_del_channel(client, conn, channel);
1224 silc_client_unref_client(client, conn, client_entry);
1225 silc_client_unref_client(client, conn, client_entry2);
1228 /** Notify processed */
1229 silc_client_unref_channel(client, conn, channel);
1230 silc_fsm_next(fsm, silc_client_notify_processed);
1231 return SILC_FSM_CONTINUE;
1234 /******************************** KILLED ************************************/
1236 /* Some client was killed from the network */
1238 SILC_FSM_STATE(silc_client_notify_killed)
1240 SilcClientConnection conn = fsm_context;
1241 SilcClient client = conn->client;
1242 SilcClientNotify notify = state_context;
1243 SilcNotifyPayload payload = notify->payload;
1244 SilcNotifyType type = silc_notify_get_type(payload);
1245 SilcArgumentPayload args = silc_notify_get_args(payload);
1246 SilcClientEntry client_entry = NULL, client_entry2 = NULL;
1247 SilcChannelEntry channel_entry = NULL;
1248 SilcServerEntry server = NULL;
1251 SilcUInt32 comment_len;
1254 SILC_LOG_DEBUG(("Notify: KILLED"));
1257 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1260 /* Find Client entry */
1261 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1266 comment = silc_argument_get_arg_type(args, 2, &comment_len);
1268 /* Get killer's ID */
1269 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
1272 if (id.type == SILC_ID_CLIENT) {
1273 /* Find Client entry */
1274 client_entry2 = silc_client_get_client_by_id(client, conn,
1276 if (!client_entry2 || !client_entry2->nickname[0]) {
1277 /** Resolve client */
1278 silc_client_unref_client(client, conn, client_entry);
1279 silc_client_unref_client(client, conn, client_entry2);
1280 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1281 client, conn, &id.u.client_id, NULL,
1282 silc_client_notify_resolved,
1286 entry = client_entry2;
1287 } else if (id.type == SILC_ID_SERVER) {
1288 /* Find Server entry */
1289 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1291 /** Resolve server */
1292 SILC_FSM_CALL(silc_client_get_server_by_id_resolve(
1293 client, conn, &id.u.server_id,
1294 silc_client_notify_resolved,
1300 /* Find Channel entry */
1301 channel_entry = silc_client_get_channel_by_id(client, conn,
1303 if (!channel_entry) {
1304 /** Resolve channel */
1305 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1306 client, conn, &id.u.channel_id,
1307 silc_client_notify_resolved,
1311 entry = channel_entry;
1314 /* Notify application. */
1315 NOTIFY(client, conn, type, client_entry, comment, id.type, entry);
1317 /* Delete the killed client */
1318 if (client_entry != conn->local_entry)
1319 silc_client_del_client(client, conn, client_entry);
1322 silc_client_unref_client(client, conn, client_entry);
1324 silc_client_unref_client(client, conn, client_entry2);
1326 silc_client_unref_server(client, conn, server);
1328 silc_client_unref_channel(client, conn, channel_entry);
1330 /** Notify processed */
1331 silc_fsm_next(fsm, silc_client_notify_processed);
1332 return SILC_FSM_CONTINUE;
1335 /**************************** SERVER SIGNOFF ********************************/
1337 /* Some server quit SILC network. Remove its clients from channels. */
1339 SILC_FSM_STATE(silc_client_notify_server_signoff)
1341 SilcClientConnection conn = fsm_context;
1342 SilcClient client = conn->client;
1343 SilcClientNotify notify = state_context;
1344 SilcNotifyPayload payload = notify->payload;
1345 SilcNotifyType type = silc_notify_get_type(payload);
1346 SilcArgumentPayload args = silc_notify_get_args(payload);
1347 SilcClientEntry client_entry;
1352 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
1354 clients = silc_dlist_init();
1358 for (i = 1; i < silc_argument_get_arg_num(args); i++) {
1360 if (!silc_argument_get_decoded(args, i + 1, SILC_ARGUMENT_ID, &id, NULL))
1363 /* Get the client entry */
1364 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1366 silc_dlist_add(clients, client_entry);
1369 /* Notify application. We don't keep server entries so the server
1370 entry is returned as NULL. The client's are returned as list. */
1371 NOTIFY(client, conn, type, NULL, clients);
1373 /* Delete the clients */
1374 silc_dlist_start(clients);
1375 while ((client_entry = silc_dlist_get(clients)))
1376 silc_client_del_client(client, conn, client_entry);
1379 /** Notify processed */
1380 silc_client_list_free(client, conn, clients);
1381 silc_fsm_next(fsm, silc_client_notify_processed);
1382 return SILC_FSM_CONTINUE;
1385 /******************************** ERROR *************************************/
1387 /* Some error occurred */
1389 SILC_FSM_STATE(silc_client_notify_error)
1391 SilcClientConnection conn = fsm_context;
1392 SilcClient client = conn->client;
1393 SilcClientNotify notify = state_context;
1394 SilcNotifyPayload payload = notify->payload;
1395 SilcNotifyType type = silc_notify_get_type(payload);
1396 SilcArgumentPayload args = silc_notify_get_args(payload);
1397 SilcClientEntry client_entry;
1404 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1405 if (!tmp && tmp_len != 1)
1407 error = (SilcStatus)tmp[0];
1409 SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1411 /* Handle the error */
1412 if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1413 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
1415 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1417 silc_client_del_client(client, conn, client_entry);
1418 silc_client_unref_client(client, conn, client_entry);
1422 /* Notify application. */
1423 NOTIFY(client, conn, type, error);
1426 /** Notify processed */
1427 silc_fsm_next(fsm, silc_client_notify_processed);
1428 return SILC_FSM_CONTINUE;
1431 /******************************** WATCH *************************************/
1433 /* Received notify about some client we are watching */
1435 SILC_FSM_STATE(silc_client_notify_watch)
1437 SilcClientConnection conn = fsm_context;
1438 SilcClient client = conn->client;
1439 SilcClientNotify notify = state_context;
1440 SilcNotifyPayload payload = notify->payload;
1441 SilcNotifyType type = silc_notify_get_type(payload);
1442 SilcArgumentPayload args = silc_notify_get_args(payload);
1443 SilcClientEntry client_entry = NULL;
1444 SilcNotifyType ntype = 0;
1445 SilcBool del_client = FALSE;
1446 unsigned char *pk, *tmp;
1447 SilcUInt32 mode, pk_len, tmp_len;
1448 SilcPublicKey public_key = NULL;
1451 SILC_LOG_DEBUG(("Notify: WATCH"));
1453 /* Get sender Client ID */
1454 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1457 /* Find Client entry and if not found resolve it */
1458 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1459 if (!client_entry || !client_entry->nickname[0]) {
1460 /** Resolve client */
1461 silc_client_unref_client(client, conn, client_entry);
1462 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1463 client, conn, &id.u.client_id, NULL,
1464 silc_client_notify_resolved,
1470 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1471 if (!tmp || tmp_len != 4)
1473 SILC_GET32_MSB(mode, tmp);
1475 /* Get notify type */
1476 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1477 if (tmp && tmp_len != 2)
1480 SILC_GET16_MSB(ntype, tmp);
1483 tmp = silc_argument_get_arg_type(args, 2, NULL);
1485 char *tmp_nick = NULL;
1487 if (client->internal->params->nickname_parse)
1488 client->internal->params->nickname_parse(client_entry->nickname,
1491 tmp_nick = strdup(tmp);
1493 /* If same nick, the client was new to us and has become "present"
1494 to network. Send NULL as nick to application. */
1495 if (tmp_nick && silc_utf8_strcasecmp(tmp, tmp_nick))
1498 silc_free(tmp_nick);
1501 /* Get public key, if present */
1502 pk = silc_argument_get_arg_type(args, 5, &pk_len);
1503 if (pk && !client_entry->public_key) {
1504 if (silc_public_key_payload_decode(pk, pk_len, &public_key)) {
1505 client_entry->public_key = public_key;
1510 /* Notify application. */
1511 NOTIFY(client, conn, type, client_entry, tmp, mode, ntype,
1512 client_entry->public_key);
1514 client_entry->mode = mode;
1516 /* If nickname was changed, remove the client entry unless the
1517 client is on some channel */
1518 /* XXX, why do we need to remove the client entry?? */
1519 if (tmp && ntype == SILC_NOTIFY_TYPE_NICK_CHANGE &&
1520 !silc_hash_table_count(client_entry->channels))
1522 else if (ntype == SILC_NOTIFY_TYPE_SIGNOFF ||
1523 ntype == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
1524 ntype == SILC_NOTIFY_TYPE_KILLED)
1528 silc_client_del_client(client, conn, client_entry);
1531 silc_pkcs_public_key_free(public_key);
1534 /** Notify processed */
1535 silc_client_unref_client(client, conn, client_entry);
1536 silc_fsm_next(fsm, silc_client_notify_processed);
1537 return SILC_FSM_CONTINUE;