5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2006 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
22 #include "silcclient.h"
23 #include "client_internal.h"
25 /************************** Types and definitions ***************************/
27 #define NOTIFY conn->client->internal->ops->notify
29 /* Notify processing context */
32 SilcNotifyPayload payload;
34 SilcChannelEntry channel;
37 /************************ Static utility functions **************************/
39 /* Entry resolving callback. This will continue processing the notify. */
41 static void silc_client_notify_resolved(SilcClient client,
42 SilcClientConnection conn,
47 SilcClientNotify notify = context;
49 /* If no entries found, just finish the notify processing, a silent error */
51 silc_fsm_next(notify->fsm, silc_client_notify_processed);
53 if (notify->channel) {
54 notify->channel->internal.resolve_cmd_ident = 0;
55 silc_client_unref_channel(client, conn, notify->channel);
58 /* Continue processing the notify */
59 SILC_FSM_CALL_CONTINUE_SYNC(notify->fsm);
62 /* Continue notify processing after it was suspended while waiting for
63 channel information being resolved. */
65 static SilcBool silc_client_notify_wait_continue(SilcClient client,
66 SilcClientConnection conn,
73 SilcClientNotify notify = context;
75 /* Continue after last command reply received */
76 if (SILC_STATUS_IS_ERROR(status) || status == SILC_STATUS_OK ||
77 status == SILC_STATUS_LIST_END)
78 SILC_FSM_CALL_CONTINUE(notify->fsm);
83 /********************************* Notify ***********************************/
85 /* Process received notify packet */
87 SILC_FSM_STATE(silc_client_notify)
89 SilcPacket packet = state_context;
90 SilcClientNotify notify;
91 SilcNotifyPayload payload;
93 payload = silc_notify_payload_parse(silc_buffer_data(&packet->buffer),
94 silc_buffer_len(&packet->buffer));
96 SILC_LOG_DEBUG(("Malformed notify payload"));
97 silc_packet_free(packet);
98 return SILC_FSM_FINISH;
101 if (!silc_notify_get_args(payload)) {
102 SILC_LOG_DEBUG(("Malformed notify"));
103 silc_notify_payload_free(payload);
104 silc_packet_free(packet);
105 return SILC_FSM_FINISH;
108 notify = silc_calloc(1, sizeof(*notify));
110 silc_notify_payload_free(payload);
111 silc_packet_free(packet);
112 return SILC_FSM_FINISH;
115 /* Save notify payload to packet context during processing */
116 notify->packet = packet;
117 notify->payload = payload;
119 silc_fsm_set_state_context(fsm, notify);
121 /* Process the notify */
122 switch (silc_notify_get_type(payload)) {
124 case SILC_NOTIFY_TYPE_NONE:
126 silc_fsm_next(fsm, silc_client_notify_none);
129 case SILC_NOTIFY_TYPE_INVITE:
131 silc_fsm_next(fsm, silc_client_notify_invite);
134 case SILC_NOTIFY_TYPE_JOIN:
136 silc_fsm_next(fsm, silc_client_notify_join);
139 case SILC_NOTIFY_TYPE_LEAVE:
141 silc_fsm_next(fsm, silc_client_notify_leave);
144 case SILC_NOTIFY_TYPE_SIGNOFF:
146 silc_fsm_next(fsm, silc_client_notify_signoff);
149 case SILC_NOTIFY_TYPE_TOPIC_SET:
151 silc_fsm_next(fsm, silc_client_notify_topic_set);
154 case SILC_NOTIFY_TYPE_NICK_CHANGE:
156 silc_fsm_next(fsm, silc_client_notify_nick_change);
159 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
161 silc_fsm_next(fsm, silc_client_notify_cmode_change);
164 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
166 silc_fsm_next(fsm, silc_client_notify_cumode_change);
169 case SILC_NOTIFY_TYPE_MOTD:
171 silc_fsm_next(fsm, silc_client_notify_motd);
174 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
175 /** CHANNEL_CHANGE */
176 silc_fsm_next(fsm, silc_client_notify_channel_change);
179 case SILC_NOTIFY_TYPE_KICKED:
181 silc_fsm_next(fsm, silc_client_notify_kicked);
184 case SILC_NOTIFY_TYPE_KILLED:
186 silc_fsm_next(fsm, silc_client_notify_killed);
189 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
190 /** SERVER_SIGNOFF */
191 silc_fsm_next(fsm, silc_client_notify_server_signoff);
194 case SILC_NOTIFY_TYPE_ERROR:
196 silc_fsm_next(fsm, silc_client_notify_error);
199 case SILC_NOTIFY_TYPE_WATCH:
201 silc_fsm_next(fsm, silc_client_notify_watch);
205 /** Unknown notify */
206 silc_notify_payload_free(payload);
207 silc_packet_free(packet);
209 return SILC_FSM_FINISH;
213 return SILC_FSM_YIELD;
216 /* Notify processed, finish the packet processing thread */
218 SILC_FSM_STATE(silc_client_notify_processed)
220 SilcClientNotify notify = state_context;
221 SilcPacket packet = notify->packet;
222 SilcNotifyPayload payload = notify->payload;
224 silc_notify_payload_free(payload);
225 silc_packet_free(packet);
227 return SILC_FSM_FINISH;
230 /********************************** NONE ************************************/
232 SILC_FSM_STATE(silc_client_notify_none)
234 SilcClientConnection conn = fsm_context;
235 SilcClient client = conn->client;
236 SilcClientNotify notify = state_context;
237 SilcNotifyPayload payload = notify->payload;
238 SilcNotifyType type = silc_notify_get_type(payload);
239 SilcArgumentPayload args = silc_notify_get_args(payload);
241 SILC_LOG_DEBUG(("Notify: NONE"));
243 /* Notify application */
244 NOTIFY(client, conn, type, silc_argument_get_arg_type(args, 1, NULL));
246 /** Notify processed */
247 silc_fsm_next(fsm, silc_client_notify_processed);
248 return SILC_FSM_CONTINUE;
251 /********************************* INVITE ***********************************/
253 /* Someone invite me to a channel */
255 SILC_FSM_STATE(silc_client_notify_invite)
257 SilcClientConnection conn = fsm_context;
258 SilcClient client = conn->client;
259 SilcClientNotify notify = state_context;
260 SilcNotifyPayload payload = notify->payload;
261 SilcNotifyType type = silc_notify_get_type(payload);
262 SilcArgumentPayload args = silc_notify_get_args(payload);
263 SilcClientEntry client_entry;
264 SilcChannelEntry channel = NULL;
269 SILC_LOG_DEBUG(("Notify: INVITE"));
272 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
275 /* Get the channel name */
276 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
280 /* Get the channel entry */
281 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
283 /* If channel is being resolved handle notify after resolving */
284 if (channel->internal.resolve_cmd_ident) {
285 silc_client_unref_channel(client, conn, channel);
286 SILC_FSM_CALL(silc_client_command_pending(
287 conn, SILC_COMMAND_NONE,
288 channel->internal.resolve_cmd_ident,
289 silc_client_notify_wait_continue,
294 /* Get sender Client ID */
295 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
298 /* Find Client entry and if not found query it */
299 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
300 if (!client_entry || !client_entry->nickname[0]) {
301 /** Resolve client */
302 silc_client_unref_client(client, conn, client_entry);
303 notify->channel = channel;
304 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
305 silc_client_get_client_by_id_resolve(
306 client, conn, &id.u.client_id, NULL,
307 silc_client_notify_resolved,
312 /* Notify application */
313 NOTIFY(client, conn, type, channel, tmp, client_entry);
315 silc_client_unref_client(client, conn, client_entry);
318 /** Notify processed */
319 silc_client_unref_channel(client, conn, channel);
320 silc_fsm_next(fsm, silc_client_notify_processed);
321 return SILC_FSM_CONTINUE;
324 /********************************** JOIN ************************************/
326 /* Someone joined a channel */
328 SILC_FSM_STATE(silc_client_notify_join)
330 SilcClientConnection conn = fsm_context;
331 SilcClient client = conn->client;
332 SilcClientNotify notify = state_context;
333 SilcNotifyPayload payload = notify->payload;
334 SilcNotifyType type = silc_notify_get_type(payload);
335 SilcArgumentPayload args = silc_notify_get_args(payload);
336 SilcClientEntry client_entry;
337 SilcChannelEntry channel = NULL;
340 SILC_LOG_DEBUG(("Notify: JOIN"));
343 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
346 /* Get channel entry */
347 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
351 /* If channel is being resolved handle notify after resolving */
352 if (channel->internal.resolve_cmd_ident) {
353 silc_client_unref_channel(client, conn, channel);
354 SILC_FSM_CALL(silc_client_command_pending(
355 conn, SILC_COMMAND_NONE,
356 channel->internal.resolve_cmd_ident,
357 silc_client_notify_wait_continue,
363 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
366 /* Find Client entry and if not found query it */
367 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
368 if (!client_entry || !client_entry->nickname[0] ||
369 !client_entry->username[0]) {
370 /** Resolve client */
371 silc_client_unref_client(client, conn, client_entry);
372 notify->channel = channel;
373 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
374 silc_client_get_client_by_id_resolve(
375 client, conn, &id.u.client_id, NULL,
376 silc_client_notify_resolved,
381 if (client_entry != conn->local_entry)
382 silc_client_nickname_format(client, conn, client_entry);
384 /* Join the client to channel */
385 if (!silc_client_add_to_channel(client, conn, channel, client_entry, 0))
388 /* Notify application. */
389 NOTIFY(client, conn, type, client_entry, channel);
391 silc_client_unref_client(client, conn, client_entry);
394 /** Notify processed */
395 silc_client_unref_channel(client, conn, channel);
396 silc_fsm_next(fsm, silc_client_notify_processed);
397 return SILC_FSM_CONTINUE;
400 /********************************** LEAVE ***********************************/
402 /* Someone left a channel */
404 SILC_FSM_STATE(silc_client_notify_leave)
406 SilcClientConnection conn = fsm_context;
407 SilcClient client = conn->client;
408 SilcClientNotify notify = state_context;
409 SilcNotifyPayload payload = notify->payload;
410 SilcPacket packet = notify->packet;
411 SilcNotifyType type = silc_notify_get_type(payload);
412 SilcArgumentPayload args = silc_notify_get_args(payload);
413 SilcClientEntry client_entry = NULL;
414 SilcChannelEntry channel = NULL;
417 SILC_LOG_DEBUG(("Notify: LEAVE"));
419 /* Get channel entry */
420 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
421 &id.u.channel_id, sizeof(id.u.channel_id)))
423 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
427 /* If channel is being resolved handle notify after resolving */
428 if (channel->internal.resolve_cmd_ident) {
429 silc_client_unref_channel(client, conn, channel);
430 SILC_FSM_CALL(silc_client_command_pending(
431 conn, SILC_COMMAND_NONE,
432 channel->internal.resolve_cmd_ident,
433 silc_client_notify_wait_continue,
439 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
442 /* Find Client entry */
443 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
447 /* Remove client from channel */
448 silc_client_remove_from_channel(client, conn, channel, client_entry);
450 /* Notify application. */
451 NOTIFY(client, conn, type, client_entry, channel);
453 silc_client_unref_client(client, conn, client_entry);
456 /** Notify processed */
457 silc_client_unref_channel(client, conn, channel);
458 silc_fsm_next(fsm, silc_client_notify_processed);
459 return SILC_FSM_CONTINUE;
462 /********************************* SIGNOFF **********************************/
464 /* Someone quit SILC network */
466 SILC_FSM_STATE(silc_client_notify_signoff)
468 SilcClientConnection conn = fsm_context;
469 SilcClient client = conn->client;
470 SilcClientNotify notify = state_context;
471 SilcNotifyPayload payload = notify->payload;
472 SilcNotifyType type = silc_notify_get_type(payload);
473 SilcArgumentPayload args = silc_notify_get_args(payload);
474 SilcClientEntry client_entry;
479 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
482 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
485 /* Find Client entry */
486 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
490 /* Get signoff message */
491 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
495 /* Notify application */
496 NOTIFY(client, conn, type, client_entry, tmp);
499 silc_client_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, *nick, 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 /* Normalize nickname */
695 nick = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8, 128, NULL);
699 /* Update nickname */
700 silc_mutex_lock(conn->internal->lock);
701 if (!silc_idcache_update_by_context(conn->internal->client_cache,
702 client_entry, NULL, nick, TRUE)) {
704 silc_mutex_unlock(conn->internal->lock);
707 silc_mutex_unlock(conn->internal->lock);
708 memcpy(oldnick, client_entry->nickname, sizeof(client_entry->nickname));
709 memcpy(client_entry->nickname, tmp, tmp_len);
710 client_entry->nickname_normalized = nick;
711 silc_client_nickname_format(client, conn, client_entry);
713 /* Notify application */
714 NOTIFY(client, conn, type, client_entry, client_entry->nickname, oldnick);
717 /** Notify processed */
718 silc_client_unref_client(client, conn, client_entry);
719 silc_fsm_next(fsm, silc_client_notify_processed);
720 return SILC_FSM_CONTINUE;
723 /****************************** CMODE_CHANGE ********************************/
725 /* Someone changed channel mode */
727 SILC_FSM_STATE(silc_client_notify_cmode_change)
729 SilcClientConnection conn = fsm_context;
730 SilcClient client = conn->client;
731 SilcClientNotify notify = state_context;
732 SilcNotifyPayload payload = notify->payload;
733 SilcPacket packet = notify->packet;
734 SilcNotifyType type = silc_notify_get_type(payload);
735 SilcArgumentPayload args = silc_notify_get_args(payload);
736 SilcClientEntry client_entry = NULL;
737 SilcChannelEntry channel = NULL, channel_entry = NULL;
738 SilcServerEntry server = NULL;
741 SilcUInt32 tmp_len, mode;
743 char *passphrase, *cipher, *hmac;
744 SilcPublicKey founder_key = NULL;
745 SilcDList chpks = NULL;
747 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
749 /* Get channel entry */
750 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
751 &id.u.channel_id, sizeof(id.u.channel_id)))
753 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
757 /* If channel is being resolved handle notify after resolving */
758 if (channel->internal.resolve_cmd_ident) {
759 silc_client_unref_channel(client, conn, channel);
760 SILC_FSM_CALL(silc_client_command_pending(
761 conn, SILC_COMMAND_NONE,
762 channel->internal.resolve_cmd_ident,
763 silc_client_notify_wait_continue,
769 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
772 SILC_GET32_MSB(mode, tmp);
775 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
778 if (id.type == SILC_ID_CLIENT) {
779 /* Find Client entry */
780 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
781 if (!client_entry || !client_entry->nickname[0]) {
782 /** Resolve client */
783 silc_client_unref_client(client, conn, client_entry);
784 notify->channel = channel;
785 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
786 silc_client_get_client_by_id_resolve(
787 client, conn, &id.u.client_id, NULL,
788 silc_client_notify_resolved,
792 entry = client_entry;
793 } else if (id.type == SILC_ID_SERVER) {
794 /* Find Server entry */
795 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
797 /** Resolve server */
798 notify->channel = channel;
799 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
800 silc_client_get_server_by_id_resolve(
801 client, conn, &id.u.server_id,
802 silc_client_notify_resolved,
808 /* Find Channel entry */
809 channel_entry = silc_client_get_channel_by_id(client, conn,
811 if (!channel_entry) {
812 /** Resolve channel */
813 notify->channel = channel;
814 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
815 silc_client_get_channel_by_id_resolve(
816 client, conn, &id.u.channel_id,
817 silc_client_notify_resolved,
821 entry = channel_entry;
824 /* Get the channel founder key if it was set */
825 tmp = silc_argument_get_arg_type(args, 6, &tmp_len);
827 if (!silc_public_key_payload_decode(tmp, tmp_len, &founder_key))
829 if (!channel->founder_key) {
830 channel->founder_key = founder_key;
836 cipher = silc_argument_get_arg_type(args, 3, &tmp_len);
839 hmac = silc_argument_get_arg_type(args, 4, &tmp_len);
841 unsigned char hash[SILC_HASH_MAXLEN];
844 if (!silc_hmac_alloc(hmac, NULL, &newhmac))
847 /* Get HMAC key from the old HMAC context, and update it to the new one */
848 tmp = (unsigned char *)silc_hmac_get_key(channel->internal.hmac, &tmp_len);
850 silc_hash_make(silc_hmac_get_hash(newhmac), tmp, tmp_len, hash);
851 silc_hmac_set_key(newhmac, hash,
852 silc_hash_len(silc_hmac_get_hash(newhmac)));
853 if (channel->internal.hmac)
854 silc_hmac_free(channel->internal.hmac);
855 channel->internal.hmac = newhmac;
856 memset(hash, 0, sizeof(hash));
860 /* Get the passphrase if it was set */
861 passphrase = silc_argument_get_arg_type(args, 5, &tmp_len);
864 tmp = silc_argument_get_arg_type(args, 8, &tmp_len);
865 if (tmp && tmp_len == 4)
866 SILC_GET32_MSB(channel->user_limit, tmp);
867 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
868 channel->user_limit = 0;
870 /* Save the new mode */
871 channel->mode = mode;
873 /* Get the channel public key that was added or removed */
874 tmp = silc_argument_get_arg_type(args, 7, &tmp_len);
876 chpks = silc_argument_list_parse_decoded(tmp, tmp_len,
877 SILC_ARGUMENT_PUBLIC_KEY);
879 /* Notify application. */
880 NOTIFY(client, conn, type, id.type, entry, mode, cipher, hmac,
881 passphrase, channel->founder_key, chpks, channel);
885 silc_pkcs_public_key_free(founder_key);
887 silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
889 silc_client_unref_client(client, conn, client_entry);
891 silc_client_unref_server(client, conn, server);
893 silc_client_unref_channel(client, conn, channel_entry);
894 silc_client_unref_channel(client, conn, channel);
896 /** Notify processed */
897 silc_fsm_next(fsm, silc_client_notify_processed);
898 return SILC_FSM_CONTINUE;
901 /***************************** CUMODE_CHANGE ********************************/
903 /* Someone changed a user's mode on a channel */
905 SILC_FSM_STATE(silc_client_notify_cumode_change)
907 SilcClientConnection conn = fsm_context;
908 SilcClient client = conn->client;
909 SilcClientNotify notify = state_context;
910 SilcNotifyPayload payload = notify->payload;
911 SilcPacket packet = notify->packet;
912 SilcNotifyType type = silc_notify_get_type(payload);
913 SilcArgumentPayload args = silc_notify_get_args(payload);
914 SilcClientEntry client_entry = NULL, client_entry2 = NULL;
915 SilcChannelEntry channel = NULL, channel_entry = NULL;
916 SilcServerEntry server = NULL;
920 SilcUInt32 tmp_len, mode;
923 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
925 /* Get channel entry */
926 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
927 &id.u.channel_id, sizeof(id.u.channel_id)))
929 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
933 /* If channel is being resolved handle notify after resolving */
934 if (channel->internal.resolve_cmd_ident) {
935 silc_client_unref_channel(client, conn, channel);
936 SILC_FSM_CALL(silc_client_command_pending(
937 conn, SILC_COMMAND_NONE,
938 channel->internal.resolve_cmd_ident,
939 silc_client_notify_wait_continue,
944 /* Get target Client ID */
945 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id2, NULL))
948 /* Find target Client entry */
949 client_entry2 = silc_client_get_client_by_id(client, conn, &id2.u.client_id);
950 if (!client_entry2 || !client_entry2->nickname[0]) {
951 /** Resolve client */
952 silc_client_unref_client(client, conn, client_entry2);
953 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
954 client, conn, &id2.u.client_id, NULL,
955 silc_client_notify_resolved,
961 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
964 SILC_GET32_MSB(mode, tmp);
967 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
970 if (id.type == SILC_ID_CLIENT) {
971 /* Find Client entry */
972 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
973 if (!client_entry || !client_entry->nickname[0]) {
974 /** Resolve client */
975 silc_client_unref_client(client, conn, client_entry);
976 notify->channel = channel;
977 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
978 silc_client_get_client_by_id_resolve(
979 client, conn, &id.u.client_id, NULL,
980 silc_client_notify_resolved,
984 entry = client_entry;
985 } else if (id.type == SILC_ID_SERVER) {
986 /* Find Server entry */
987 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
989 /** Resolve server */
990 notify->channel = channel;
991 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
992 silc_client_get_server_by_id_resolve(
993 client, conn, &id.u.server_id,
994 silc_client_notify_resolved,
1000 /* Find Channel entry */
1001 channel_entry = silc_client_get_channel_by_id(client, conn,
1003 if (!channel_entry) {
1004 /** Resolve channel */
1005 notify->channel = channel;
1006 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1007 silc_client_get_channel_by_id_resolve(
1008 client, conn, &id.u.channel_id,
1009 silc_client_notify_resolved,
1013 entry = channel_entry;
1017 chu = silc_client_on_channel(channel, client_entry2);
1021 /* Notify application. */
1022 NOTIFY(client, conn, type, id.type, entry, mode, client_entry2, channel);
1025 silc_client_unref_client(client, conn, client_entry2);
1027 silc_client_unref_client(client, conn, client_entry);
1029 silc_client_unref_server(client, conn, server);
1031 silc_client_unref_channel(client, conn, channel_entry);
1032 silc_client_unref_channel(client, conn, channel);
1034 /** Notify processed */
1035 silc_fsm_next(fsm, silc_client_notify_processed);
1036 return SILC_FSM_CONTINUE;
1039 /********************************* MOTD *************************************/
1041 /* Received Message of the day */
1043 SILC_FSM_STATE(silc_client_notify_motd)
1045 SilcClientConnection conn = fsm_context;
1046 SilcClient client = conn->client;
1047 SilcClientNotify notify = state_context;
1048 SilcNotifyPayload payload = notify->payload;
1049 SilcNotifyType type = silc_notify_get_type(payload);
1050 SilcArgumentPayload args = silc_notify_get_args(payload);
1054 SILC_LOG_DEBUG(("Notify: MOTD"));
1057 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1061 /* Notify application */
1062 NOTIFY(client, conn, type, tmp);
1065 /** Notify processed */
1066 silc_fsm_next(fsm, silc_client_notify_processed);
1067 return SILC_FSM_CONTINUE;
1070 /**************************** CHANNEL CHANGE ********************************/
1072 /* Router has enforced a new ID to a channel, change it */
1074 SILC_FSM_STATE(silc_client_notify_channel_change)
1076 SilcClientConnection conn = fsm_context;
1077 SilcClient client = conn->client;
1078 SilcClientNotify notify = state_context;
1079 SilcNotifyPayload payload = notify->payload;
1080 SilcNotifyType type = silc_notify_get_type(payload);
1081 SilcArgumentPayload args = silc_notify_get_args(payload);
1082 SilcChannelEntry channel = NULL;
1085 SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
1087 /* Get the old ID */
1088 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1091 /* Get the channel entry */
1092 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1096 /* If channel is being resolved handle notify after resolving */
1097 if (channel->internal.resolve_cmd_ident) {
1098 silc_client_unref_channel(client, conn, channel);
1099 SILC_FSM_CALL(silc_client_command_pending(
1100 conn, SILC_COMMAND_NONE,
1101 channel->internal.resolve_cmd_ident,
1102 silc_client_notify_wait_continue,
1107 /* Get the new ID */
1108 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
1111 /* Replace the Channel ID */
1112 if (!silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id))
1115 /* Notify application */
1116 NOTIFY(client, conn, type, channel, channel);
1119 /** Notify processed */
1120 silc_client_unref_channel(client, conn, channel);
1121 silc_fsm_next(fsm, silc_client_notify_processed);
1122 return SILC_FSM_CONTINUE;
1125 /******************************** KICKED ************************************/
1127 /* Some client was kicked from a channel */
1129 SILC_FSM_STATE(silc_client_notify_kicked)
1131 SilcClientConnection conn = fsm_context;
1132 SilcClient client = conn->client;
1133 SilcClientNotify notify = state_context;
1134 SilcNotifyPayload payload = notify->payload;
1135 SilcPacket packet = notify->packet;
1136 SilcNotifyType type = silc_notify_get_type(payload);
1137 SilcArgumentPayload args = silc_notify_get_args(payload);
1138 SilcClientEntry client_entry, client_entry2;
1139 SilcChannelEntry channel = NULL;
1144 SILC_LOG_DEBUG(("Notify: KICKED"));
1146 /* Get channel entry */
1147 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
1148 &id.u.channel_id, sizeof(id.u.channel_id)))
1150 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1154 /* If channel is being resolved handle notify after resolving */
1155 if (channel->internal.resolve_cmd_ident) {
1156 silc_client_unref_channel(client, conn, channel);
1157 SILC_FSM_CALL(silc_client_command_pending(
1158 conn, SILC_COMMAND_NONE,
1159 channel->internal.resolve_cmd_ident,
1160 silc_client_notify_wait_continue,
1166 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1169 /* Find Client entry */
1170 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1174 /* Get kicker's Client ID */
1175 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
1178 /* Find kicker's client entry and if not found resolve it */
1179 client_entry2 = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1180 if (!client_entry2 || !client_entry2->nickname[0]) {
1181 /** Resolve client */
1182 silc_client_unref_client(client, conn, client_entry);
1183 silc_client_unref_client(client, conn, client_entry2);
1184 notify->channel = channel;
1185 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1186 silc_client_get_client_by_id_resolve(
1187 client, conn, &id.u.client_id, NULL,
1188 silc_client_notify_resolved,
1194 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1196 /* Remove kicked client from channel */
1197 if (client_entry != conn->local_entry)
1198 silc_client_remove_from_channel(client, conn, channel, client_entry);
1200 /* Notify application. */
1201 NOTIFY(client, conn, type, client_entry, tmp, client_entry2, channel);
1203 /* If I was kicked from channel, remove the channel */
1204 if (client_entry == conn->local_entry) {
1205 if (conn->current_channel == channel)
1206 conn->current_channel = NULL;
1207 silc_client_empty_channel(client, conn, channel);
1208 silc_client_del_channel(client, conn, channel);
1211 silc_client_unref_client(client, conn, client_entry);
1212 silc_client_unref_client(client, conn, client_entry2);
1215 /** Notify processed */
1216 silc_client_unref_channel(client, conn, channel);
1217 silc_fsm_next(fsm, silc_client_notify_processed);
1218 return SILC_FSM_CONTINUE;
1221 /******************************** KILLED ************************************/
1223 /* Some client was killed from the network */
1225 SILC_FSM_STATE(silc_client_notify_killed)
1227 SilcClientConnection conn = fsm_context;
1228 SilcClient client = conn->client;
1229 SilcClientNotify notify = state_context;
1230 SilcNotifyPayload payload = notify->payload;
1231 SilcNotifyType type = silc_notify_get_type(payload);
1232 SilcArgumentPayload args = silc_notify_get_args(payload);
1233 SilcClientEntry client_entry = NULL, client_entry2 = NULL;
1234 SilcChannelEntry channel_entry = NULL;
1235 SilcServerEntry server = NULL;
1238 SilcUInt32 comment_len;
1241 SILC_LOG_DEBUG(("Notify: KILLED"));
1244 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1247 /* Find Client entry */
1248 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1253 comment = silc_argument_get_arg_type(args, 2, &comment_len);
1255 /* Get killer's ID */
1256 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
1259 if (id.type == SILC_ID_CLIENT) {
1260 /* Find Client entry */
1261 client_entry2 = silc_client_get_client_by_id(client, conn,
1263 if (!client_entry2 || !client_entry2->nickname[0]) {
1264 /** Resolve client */
1265 silc_client_unref_client(client, conn, client_entry);
1266 silc_client_unref_client(client, conn, client_entry2);
1267 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1268 client, conn, &id.u.client_id, NULL,
1269 silc_client_notify_resolved,
1273 entry = client_entry2;
1274 } else if (id.type == SILC_ID_SERVER) {
1275 /* Find Server entry */
1276 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1278 /** Resolve server */
1279 SILC_FSM_CALL(silc_client_get_server_by_id_resolve(
1280 client, conn, &id.u.server_id,
1281 silc_client_notify_resolved,
1287 /* Find Channel entry */
1288 channel_entry = silc_client_get_channel_by_id(client, conn,
1290 if (!channel_entry) {
1291 /** Resolve channel */
1292 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1293 client, conn, &id.u.channel_id,
1294 silc_client_notify_resolved,
1298 entry = channel_entry;
1301 /* Notify application. */
1302 NOTIFY(client, conn, type, client_entry, comment, id.type, entry);
1304 /* Delete the killed client */
1305 if (client_entry != conn->local_entry) {
1306 silc_client_remove_from_channels(client, conn, client_entry);
1307 silc_client_del_client(client, conn, client_entry);
1311 silc_client_unref_client(client, conn, client_entry);
1313 silc_client_unref_client(client, conn, client_entry2);
1315 silc_client_unref_server(client, conn, server);
1317 silc_client_unref_channel(client, conn, channel_entry);
1319 /** Notify processed */
1320 silc_fsm_next(fsm, silc_client_notify_processed);
1321 return SILC_FSM_CONTINUE;
1324 /**************************** SERVER SIGNOFF ********************************/
1326 /* Some server quit SILC network. Remove its clients from channels. */
1328 SILC_FSM_STATE(silc_client_notify_server_signoff)
1330 SilcClientConnection conn = fsm_context;
1331 SilcClient client = conn->client;
1332 SilcClientNotify notify = state_context;
1333 SilcNotifyPayload payload = notify->payload;
1334 SilcNotifyType type = silc_notify_get_type(payload);
1335 SilcArgumentPayload args = silc_notify_get_args(payload);
1336 SilcClientEntry client_entry;
1341 SILC_LOG_DEBUG(("Notify: SERVER_SIGNOFF"));
1343 clients = silc_dlist_init();
1347 for (i = 1; i < silc_argument_get_arg_num(args); i++) {
1349 if (!silc_argument_get_decoded(args, i + 1, SILC_ARGUMENT_ID, &id, NULL))
1352 /* Get the client entry */
1353 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1355 silc_dlist_add(clients, client_entry);
1358 /* Notify application. We don't keep server entries so the server
1359 entry is returned as NULL. The client's are returned as list. */
1360 NOTIFY(client, conn, type, NULL, clients);
1362 /* Delete the clients */
1363 silc_dlist_start(clients);
1364 while ((client_entry = silc_dlist_get(clients))) {
1365 silc_client_remove_from_channels(client, conn, client_entry);
1366 silc_client_del_client(client, conn, client_entry);
1370 /** Notify processed */
1371 silc_client_list_free(client, conn, clients);
1372 silc_fsm_next(fsm, silc_client_notify_processed);
1373 return SILC_FSM_CONTINUE;
1376 /******************************** ERROR *************************************/
1378 /* Some error occurred */
1380 SILC_FSM_STATE(silc_client_notify_error)
1382 SilcClientConnection conn = fsm_context;
1383 SilcClient client = conn->client;
1384 SilcClientNotify notify = state_context;
1385 SilcNotifyPayload payload = notify->payload;
1386 SilcNotifyType type = silc_notify_get_type(payload);
1387 SilcArgumentPayload args = silc_notify_get_args(payload);
1388 SilcClientEntry client_entry;
1395 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1396 if (!tmp && tmp_len != 1)
1398 error = (SilcStatus)tmp[0];
1400 SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1402 /* Handle the error */
1403 if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1404 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
1406 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1408 silc_client_remove_from_channels(client, conn, client_entry);
1409 silc_client_del_client(client, conn, client_entry);
1410 silc_client_unref_client(client, conn, client_entry);
1414 /* Notify application. */
1415 NOTIFY(client, conn, type, error);
1418 /** Notify processed */
1419 silc_fsm_next(fsm, silc_client_notify_processed);
1420 return SILC_FSM_CONTINUE;
1423 /******************************** WATCH *************************************/
1425 /* Received notify about some client we are watching */
1427 SILC_FSM_STATE(silc_client_notify_watch)
1429 SilcClientConnection conn = fsm_context;
1430 SilcClient client = conn->client;
1431 SilcClientNotify notify = state_context;
1432 SilcNotifyPayload payload = notify->payload;
1433 SilcNotifyType type = silc_notify_get_type(payload);
1434 SilcArgumentPayload args = silc_notify_get_args(payload);
1435 SilcClientEntry client_entry = NULL;
1436 SilcNotifyType ntype = 0;
1437 SilcBool del_client = FALSE;
1438 unsigned char *pk, *tmp;
1439 SilcUInt32 mode, pk_len, tmp_len;
1440 SilcPublicKey public_key = NULL;
1443 SILC_LOG_DEBUG(("Notify: WATCH"));
1445 /* Get sender Client ID */
1446 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1449 /* Find Client entry and if not found resolve it */
1450 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1451 if (!client_entry || !client_entry->nickname[0]) {
1452 /** Resolve client */
1453 silc_client_unref_client(client, conn, client_entry);
1454 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1455 client, conn, &id.u.client_id, NULL,
1456 silc_client_notify_resolved,
1462 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1463 if (!tmp || tmp_len != 4)
1465 SILC_GET32_MSB(mode, tmp);
1467 /* Get notify type */
1468 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1469 if (tmp && tmp_len != 2)
1472 SILC_GET16_MSB(ntype, tmp);
1475 tmp = silc_argument_get_arg_type(args, 2, NULL);
1477 char *tmp_nick = NULL;
1479 if (client->internal->params->nickname_parse)
1480 client->internal->params->nickname_parse(client_entry->nickname,
1483 tmp_nick = strdup(tmp);
1485 /* If same nick, the client was new to us and has become "present"
1486 to network. Send NULL as nick to application. */
1487 if (tmp_nick && silc_utf8_strcasecmp(tmp, tmp_nick))
1490 silc_free(tmp_nick);
1493 /* Get public key, if present */
1494 pk = silc_argument_get_arg_type(args, 5, &pk_len);
1495 if (pk && !client_entry->public_key) {
1496 if (silc_public_key_payload_decode(pk, pk_len, &public_key)) {
1497 client_entry->public_key = public_key;
1502 /* Notify application. */
1503 NOTIFY(client, conn, type, client_entry, tmp, mode, ntype,
1504 client_entry->public_key);
1506 client_entry->mode = mode;
1508 /* If nickname was changed, remove the client entry unless the
1509 client is on some channel */
1510 /* XXX, why do we need to remove the client entry?? */
1511 if (tmp && ntype == SILC_NOTIFY_TYPE_NICK_CHANGE &&
1512 !silc_hash_table_count(client_entry->channels))
1514 else if (ntype == SILC_NOTIFY_TYPE_SIGNOFF ||
1515 ntype == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
1516 ntype == SILC_NOTIFY_TYPE_KILLED)
1520 silc_client_remove_from_channels(client, conn, client_entry);
1521 silc_client_del_client(client, conn, client_entry);
1525 silc_pkcs_public_key_free(public_key);
1528 /** Notify processed */
1529 silc_client_unref_client(client, conn, client_entry);
1530 silc_fsm_next(fsm, silc_client_notify_processed);
1531 return SILC_FSM_CONTINUE;