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);
98 return SILC_FSM_FINISH;
101 if (!silc_notify_get_args(payload)) {
102 SILC_LOG_DEBUG(("Malformed notify %d", silc_notify_get_type(payload)));
103 silc_notify_payload_free(payload);
104 silc_packet_free(packet);
105 return SILC_FSM_FINISH;
108 notify = silc_calloc(1, sizeof(*notify));
110 silc_notify_payload_free(payload);
111 silc_packet_free(packet);
112 return SILC_FSM_FINISH;
115 notify->packet = packet;
116 notify->payload = payload;
118 silc_fsm_set_state_context(fsm, notify);
120 /* Process the notify */
121 switch (silc_notify_get_type(payload)) {
123 case SILC_NOTIFY_TYPE_NONE:
125 silc_fsm_next(fsm, silc_client_notify_none);
128 case SILC_NOTIFY_TYPE_INVITE:
130 silc_fsm_next(fsm, silc_client_notify_invite);
133 case SILC_NOTIFY_TYPE_JOIN:
135 silc_fsm_next(fsm, silc_client_notify_join);
138 case SILC_NOTIFY_TYPE_LEAVE:
140 silc_fsm_next(fsm, silc_client_notify_leave);
143 case SILC_NOTIFY_TYPE_SIGNOFF:
145 silc_fsm_next(fsm, silc_client_notify_signoff);
148 case SILC_NOTIFY_TYPE_TOPIC_SET:
150 silc_fsm_next(fsm, silc_client_notify_topic_set);
153 case SILC_NOTIFY_TYPE_NICK_CHANGE:
155 silc_fsm_next(fsm, silc_client_notify_nick_change);
158 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
160 silc_fsm_next(fsm, silc_client_notify_cmode_change);
163 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
165 silc_fsm_next(fsm, silc_client_notify_cumode_change);
168 case SILC_NOTIFY_TYPE_MOTD:
170 silc_fsm_next(fsm, silc_client_notify_motd);
173 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
174 /** CHANNEL_CHANGE */
175 silc_fsm_next(fsm, silc_client_notify_channel_change);
178 case SILC_NOTIFY_TYPE_KICKED:
180 silc_fsm_next(fsm, silc_client_notify_kicked);
183 case SILC_NOTIFY_TYPE_KILLED:
185 silc_fsm_next(fsm, silc_client_notify_killed);
188 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
189 /** SERVER_SIGNOFF */
190 silc_fsm_next(fsm, silc_client_notify_server_signoff);
193 case SILC_NOTIFY_TYPE_ERROR:
195 silc_fsm_next(fsm, silc_client_notify_error);
198 case SILC_NOTIFY_TYPE_WATCH:
200 silc_fsm_next(fsm, silc_client_notify_watch);
204 /** Unknown notify */
205 silc_notify_payload_free(payload);
206 silc_packet_free(packet);
208 return SILC_FSM_FINISH;
212 return SILC_FSM_YIELD;
215 /* Notify processed, finish the packet processing thread */
217 SILC_FSM_STATE(silc_client_notify_processed)
219 SilcClientNotify notify = state_context;
220 SilcPacket packet = notify->packet;
221 SilcNotifyPayload payload = notify->payload;
223 silc_notify_payload_free(payload);
224 silc_packet_free(packet);
226 return SILC_FSM_FINISH;
229 /********************************** NONE ************************************/
231 SILC_FSM_STATE(silc_client_notify_none)
233 SilcClientConnection conn = fsm_context;
234 SilcClient client = conn->client;
235 SilcClientNotify notify = state_context;
236 SilcNotifyPayload payload = notify->payload;
237 SilcNotifyType type = silc_notify_get_type(payload);
238 SilcArgumentPayload args = silc_notify_get_args(payload);
240 SILC_LOG_DEBUG(("Notify: NONE"));
242 /* Notify application */
243 NOTIFY(client, conn, type, silc_argument_get_arg_type(args, 1, NULL));
245 /** Notify processed */
246 silc_fsm_next(fsm, silc_client_notify_processed);
247 return SILC_FSM_CONTINUE;
250 /********************************* INVITE ***********************************/
252 /* Someone invite me to a channel */
254 SILC_FSM_STATE(silc_client_notify_invite)
256 SilcClientConnection conn = fsm_context;
257 SilcClient client = conn->client;
258 SilcClientNotify notify = state_context;
259 SilcNotifyPayload payload = notify->payload;
260 SilcNotifyType type = silc_notify_get_type(payload);
261 SilcArgumentPayload args = silc_notify_get_args(payload);
262 SilcClientEntry client_entry;
263 SilcChannelEntry channel = NULL;
268 SILC_LOG_DEBUG(("Notify: INVITE"));
271 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
274 /* Get the channel name */
275 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
279 /* Get the channel entry */
280 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
284 /* If channel is being resolved handle notify after resolving */
285 if (channel->internal.resolve_cmd_ident) {
286 silc_client_unref_channel(client, conn, channel);
287 SILC_FSM_CALL(silc_client_command_pending(
288 conn, SILC_COMMAND_NONE,
289 channel->internal.resolve_cmd_ident,
290 silc_client_notify_wait_continue,
295 /* Get sender Client ID */
296 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
299 /* Find Client entry and if not found query it */
300 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
301 if (!client_entry || !client_entry->nickname[0]) {
302 /** Resolve client */
303 silc_client_unref_client(client, conn, client_entry);
304 notify->channel = channel;
305 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
306 silc_client_get_client_by_id_resolve(
307 client, conn, &id.u.client_id, NULL,
308 silc_client_notify_resolved,
313 /* Notify application */
314 NOTIFY(client, conn, type, channel, tmp, client_entry);
316 silc_client_unref_client(client, conn, client_entry);
319 /** Notify processed */
320 silc_client_unref_channel(client, conn, channel);
321 silc_fsm_next(fsm, silc_client_notify_processed);
322 return SILC_FSM_CONTINUE;
325 /********************************** JOIN ************************************/
327 /* Someone joined a channel */
329 SILC_FSM_STATE(silc_client_notify_join)
331 SilcClientConnection conn = fsm_context;
332 SilcClient client = conn->client;
333 SilcClientNotify notify = state_context;
334 SilcNotifyPayload payload = notify->payload;
335 SilcNotifyType type = silc_notify_get_type(payload);
336 SilcArgumentPayload args = silc_notify_get_args(payload);
337 SilcClientEntry client_entry;
338 SilcChannelEntry channel = NULL;
341 SILC_LOG_DEBUG(("Notify: JOIN"));
344 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
347 /* Get channel entry */
348 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
352 /* If channel is being resolved handle notify after resolving */
353 if (channel->internal.resolve_cmd_ident) {
354 silc_client_unref_channel(client, conn, channel);
355 SILC_FSM_CALL(silc_client_command_pending(
356 conn, SILC_COMMAND_NONE,
357 channel->internal.resolve_cmd_ident,
358 silc_client_notify_wait_continue,
364 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
367 /* Find Client entry and if not found query it */
368 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
369 if (!client_entry || !client_entry->nickname[0] ||
370 !client_entry->username[0]) {
371 /** Resolve client */
372 silc_client_unref_client(client, conn, client_entry);
373 notify->channel = channel;
374 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
375 silc_client_get_client_by_id_resolve(
376 client, conn, &id.u.client_id, NULL,
377 silc_client_notify_resolved,
382 if (client_entry != conn->local_entry)
383 silc_client_nickname_format(client, conn, client_entry, FALSE);
385 /* Join the client to channel */
386 if (!silc_client_add_to_channel(client, conn, channel, client_entry, 0))
389 /* Notify application. */
390 NOTIFY(client, conn, type, client_entry, channel);
392 silc_client_unref_client(client, conn, client_entry);
395 /** Notify processed */
396 silc_client_unref_channel(client, conn, channel);
397 silc_fsm_next(fsm, silc_client_notify_processed);
398 return SILC_FSM_CONTINUE;
401 /********************************** LEAVE ***********************************/
403 /* Someone left a channel */
405 SILC_FSM_STATE(silc_client_notify_leave)
407 SilcClientConnection conn = fsm_context;
408 SilcClient client = conn->client;
409 SilcClientNotify notify = state_context;
410 SilcNotifyPayload payload = notify->payload;
411 SilcPacket packet = notify->packet;
412 SilcNotifyType type = silc_notify_get_type(payload);
413 SilcArgumentPayload args = silc_notify_get_args(payload);
414 SilcClientEntry client_entry = NULL;
415 SilcChannelEntry channel = NULL;
418 SILC_LOG_DEBUG(("Notify: LEAVE"));
420 /* Get channel entry */
421 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
422 &id.u.channel_id, sizeof(id.u.channel_id)))
424 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
428 /* If channel is being resolved handle notify after resolving */
429 if (channel->internal.resolve_cmd_ident) {
430 silc_client_unref_channel(client, conn, channel);
431 SILC_FSM_CALL(silc_client_command_pending(
432 conn, SILC_COMMAND_NONE,
433 channel->internal.resolve_cmd_ident,
434 silc_client_notify_wait_continue,
440 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
443 /* Find Client entry */
444 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
448 /* Remove client from channel */
449 silc_client_remove_from_channel(client, conn, channel, client_entry);
451 /* Notify application. */
452 NOTIFY(client, conn, type, client_entry, channel);
454 silc_client_unref_client(client, conn, client_entry);
457 /** Notify processed */
458 silc_client_unref_channel(client, conn, channel);
459 silc_fsm_next(fsm, silc_client_notify_processed);
460 return SILC_FSM_CONTINUE;
463 /********************************* SIGNOFF **********************************/
465 /* Someone quit SILC network */
467 SILC_FSM_STATE(silc_client_notify_signoff)
469 SilcClientConnection conn = fsm_context;
470 SilcClient client = conn->client;
471 SilcClientNotify notify = state_context;
472 SilcNotifyPayload payload = notify->payload;
473 SilcPacket packet = notify->packet;
474 SilcNotifyType type = silc_notify_get_type(payload);
475 SilcArgumentPayload args = silc_notify_get_args(payload);
476 SilcClientEntry client_entry;
477 SilcChannelEntry channel;
482 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
485 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
488 /* Find Client entry */
489 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
493 /* Get signoff message */
494 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
495 if (tmp && tmp_len > 128)
498 /* Notify application */
499 NOTIFY(client, conn, type, client_entry, tmp);
501 /* Remove from channel */
502 if (packet->dst_id_type == SILC_ID_CHANNEL) {
503 if (silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
504 &id.u.channel_id, sizeof(id.u.channel_id))) {
505 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
507 silc_client_remove_from_channel(client, conn, channel, client_entry);
508 silc_client_unref_channel(client, conn, channel);
514 silc_client_del_client(client, conn, client_entry);
515 silc_client_unref_client(client, conn, client_entry);
518 /** Notify processed */
519 silc_fsm_next(fsm, silc_client_notify_processed);
520 return SILC_FSM_CONTINUE;
523 /******************************** TOPIC_SET *********************************/
525 /* Someone set topic on a channel */
527 SILC_FSM_STATE(silc_client_notify_topic_set)
529 SilcClientConnection conn = fsm_context;
530 SilcClient client = conn->client;
531 SilcClientNotify notify = state_context;
532 SilcNotifyPayload payload = notify->payload;
533 SilcPacket packet = notify->packet;
534 SilcNotifyType type = silc_notify_get_type(payload);
535 SilcArgumentPayload args = silc_notify_get_args(payload);
536 SilcClientEntry client_entry = NULL;
537 SilcChannelEntry channel = NULL, channel_entry = NULL;
538 SilcServerEntry server = NULL;
544 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
546 /* Get channel entry */
547 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
548 &id.u.channel_id, sizeof(id.u.channel_id)))
550 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
554 /* If channel is being resolved handle notify after resolving */
555 if (channel->internal.resolve_cmd_ident) {
556 silc_client_unref_channel(client, conn, channel);
557 SILC_FSM_CALL(silc_client_command_pending(
558 conn, SILC_COMMAND_NONE,
559 channel->internal.resolve_cmd_ident,
560 silc_client_notify_wait_continue,
566 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
570 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
574 if (id.type == SILC_ID_CLIENT) {
575 /* Find Client entry */
576 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
577 if (!client_entry || !client_entry->nickname[0]) {
578 /** Resolve client */
579 silc_client_unref_client(client, conn, client_entry);
580 notify->channel = channel;
581 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
582 silc_client_get_client_by_id_resolve(
583 client, conn, &id.u.client_id, NULL,
584 silc_client_notify_resolved,
588 entry = client_entry;
589 } else if (id.type == SILC_ID_SERVER) {
590 /* Find Server entry */
591 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
593 /** Resolve server */
594 notify->channel = channel;
595 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
596 silc_client_get_server_by_id_resolve(
597 client, conn, &id.u.server_id,
598 silc_client_notify_resolved,
604 /* Find Channel entry */
605 channel_entry = silc_client_get_channel_by_id(client, conn,
607 if (!channel_entry) {
608 /** Resolve channel */
609 notify->channel = channel;
610 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
611 silc_client_get_channel_by_id_resolve(
612 client, conn, &id.u.channel_id,
613 silc_client_notify_resolved,
617 entry = channel_entry;
620 silc_free(channel->topic);
621 channel->topic = silc_memdup(tmp, strlen(tmp));
623 /* Notify application. */
624 NOTIFY(client, conn, type, id.type, entry, channel->topic, channel);
627 silc_client_unref_client(client, conn, client_entry);
629 silc_client_unref_server(client, conn, server);
631 silc_client_unref_channel(client, conn, channel_entry);
634 /** Notify processed */
635 silc_client_unref_channel(client, conn, channel);
636 silc_fsm_next(fsm, silc_client_notify_processed);
637 return SILC_FSM_CONTINUE;
640 /****************************** NICK_CHANGE *********************************/
642 /* Someone changed their nickname on a channel */
644 SILC_FSM_STATE(silc_client_notify_nick_change)
646 SilcClientConnection conn = fsm_context;
647 SilcClient client = conn->client;
648 SilcClientNotify notify = state_context;
649 SilcNotifyPayload payload = notify->payload;
650 SilcNotifyType type = silc_notify_get_type(payload);
651 SilcArgumentPayload args = silc_notify_get_args(payload);
652 SilcClientEntry client_entry = NULL;
653 unsigned char *tmp, oldnick[128 + 1];
657 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
660 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
664 if (conn->local_id &&
665 SILC_ID_CLIENT_COMPARE(&id.u.client_id, conn->local_id))
668 /* Get new Client ID */
669 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id2, NULL))
673 if (conn->local_id &&
674 SILC_ID_CLIENT_COMPARE(&id2.u.client_id, conn->local_id))
677 /* Find old Client entry */
678 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
679 if (!client_entry || !client_entry->nickname[0]) {
680 /** Resolve client */
681 silc_client_unref_client(client, conn, client_entry);
682 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
683 client, conn, &id.u.client_id, NULL,
684 silc_client_notify_resolved,
689 /* Take the new nickname */
690 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
694 /* Check whether nickname changed at all. It is possible that nick
695 change notify is received but nickname didn't change, only the
696 ID changes. If Client ID hash match, nickname didn't change. */
697 if (SILC_ID_COMPARE_HASH(&client_entry->id, &id2.u.client_id) &&
698 silc_utf8_strcasecmp(tmp, client_entry->nickname)) {
699 /* Nickname didn't change. Update only Client ID. We don't notify
700 application because nickname didn't change. */
701 silc_mutex_lock(conn->internal->lock);
702 silc_idcache_update_by_context(conn->internal->client_cache, client_entry,
703 &id2.u.client_id, NULL, FALSE);
704 silc_mutex_unlock(conn->internal->lock);
708 /* Change the nickname */
709 memcpy(oldnick, client_entry->nickname, sizeof(client_entry->nickname));
710 if (!silc_client_change_nickname(client, conn, client_entry, tmp,
711 &id2.u.client_id, NULL, 0))
714 /* Notify application */
715 NOTIFY(client, conn, type, client_entry, client_entry->nickname, oldnick);
718 /** Notify processed */
719 silc_client_unref_client(client, conn, client_entry);
720 silc_fsm_next(fsm, silc_client_notify_processed);
721 return SILC_FSM_CONTINUE;
724 /****************************** CMODE_CHANGE ********************************/
726 /* Someone changed channel mode */
728 SILC_FSM_STATE(silc_client_notify_cmode_change)
730 SilcClientConnection conn = fsm_context;
731 SilcClient client = conn->client;
732 SilcClientNotify notify = state_context;
733 SilcNotifyPayload payload = notify->payload;
734 SilcPacket packet = notify->packet;
735 SilcNotifyType type = silc_notify_get_type(payload);
736 SilcArgumentPayload args = silc_notify_get_args(payload);
737 SilcClientEntry client_entry = NULL;
738 SilcChannelEntry channel = NULL, channel_entry = NULL;
739 SilcServerEntry server = NULL;
742 SilcUInt32 tmp_len, mode;
744 char *passphrase, *cipher, *hmac;
745 SilcPublicKey founder_key = NULL;
746 SilcDList chpks = NULL;
748 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
750 /* Get channel entry */
751 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
752 &id.u.channel_id, sizeof(id.u.channel_id)))
754 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
758 /* If channel is being resolved handle notify after resolving */
759 if (channel->internal.resolve_cmd_ident) {
760 silc_client_unref_channel(client, conn, channel);
761 SILC_FSM_CALL(silc_client_command_pending(
762 conn, SILC_COMMAND_NONE,
763 channel->internal.resolve_cmd_ident,
764 silc_client_notify_wait_continue,
770 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
773 SILC_GET32_MSB(mode, tmp);
776 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
779 if (id.type == SILC_ID_CLIENT) {
780 /* Find Client entry */
781 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
782 if (!client_entry || !client_entry->nickname[0]) {
783 /** Resolve client */
784 silc_client_unref_client(client, conn, client_entry);
785 notify->channel = channel;
786 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
787 silc_client_get_client_by_id_resolve(
788 client, conn, &id.u.client_id, NULL,
789 silc_client_notify_resolved,
793 entry = client_entry;
794 } else if (id.type == SILC_ID_SERVER) {
795 /* Find Server entry */
796 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
798 /** Resolve server */
799 notify->channel = channel;
800 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
801 silc_client_get_server_by_id_resolve(
802 client, conn, &id.u.server_id,
803 silc_client_notify_resolved,
809 /* Find Channel entry */
810 channel_entry = silc_client_get_channel_by_id(client, conn,
812 if (!channel_entry) {
813 /** Resolve channel */
814 notify->channel = channel;
815 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
816 silc_client_get_channel_by_id_resolve(
817 client, conn, &id.u.channel_id,
818 silc_client_notify_resolved,
822 entry = channel_entry;
825 /* Get the channel founder key if it was set */
826 tmp = silc_argument_get_arg_type(args, 6, &tmp_len);
828 if (!silc_public_key_payload_decode(tmp, tmp_len, &founder_key))
830 if (!channel->founder_key) {
831 channel->founder_key = founder_key;
837 cipher = silc_argument_get_arg_type(args, 3, &tmp_len);
840 hmac = silc_argument_get_arg_type(args, 4, &tmp_len);
842 unsigned char hash[SILC_HASH_MAXLEN];
845 if (!silc_hmac_alloc(hmac, NULL, &newhmac))
848 /* Get HMAC key from the old HMAC context, and update it to the new one */
849 tmp = (unsigned char *)silc_hmac_get_key(channel->internal.hmac, &tmp_len);
851 silc_hash_make(silc_hmac_get_hash(newhmac), tmp, tmp_len, hash);
852 silc_hmac_set_key(newhmac, hash,
853 silc_hash_len(silc_hmac_get_hash(newhmac)));
854 if (channel->internal.hmac)
855 silc_hmac_free(channel->internal.hmac);
856 channel->internal.hmac = newhmac;
857 memset(hash, 0, sizeof(hash));
861 /* Get the passphrase if it was set */
862 passphrase = silc_argument_get_arg_type(args, 5, &tmp_len);
865 tmp = silc_argument_get_arg_type(args, 8, &tmp_len);
866 if (tmp && tmp_len == 4)
867 SILC_GET32_MSB(channel->user_limit, tmp);
868 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
869 channel->user_limit = 0;
871 /* Save the new mode */
872 channel->mode = mode;
874 /* Get the channel public key that was added or removed */
875 tmp = silc_argument_get_arg_type(args, 7, &tmp_len);
877 chpks = silc_argument_list_parse_decoded(tmp, tmp_len,
878 SILC_ARGUMENT_PUBLIC_KEY);
880 /* XXX add to/remove from channel pubkeys channel->channel_pubkeys */
882 /* Notify application. */
883 NOTIFY(client, conn, type, id.type, entry, mode, cipher, hmac,
884 passphrase, channel->founder_key, chpks, channel);
888 silc_pkcs_public_key_free(founder_key);
890 silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
892 silc_client_unref_client(client, conn, client_entry);
894 silc_client_unref_server(client, conn, server);
896 silc_client_unref_channel(client, conn, channel_entry);
897 silc_client_unref_channel(client, conn, channel);
899 /** Notify processed */
900 silc_fsm_next(fsm, silc_client_notify_processed);
901 return SILC_FSM_CONTINUE;
904 /***************************** CUMODE_CHANGE ********************************/
906 /* Someone changed a user's mode on a channel */
908 SILC_FSM_STATE(silc_client_notify_cumode_change)
910 SilcClientConnection conn = fsm_context;
911 SilcClient client = conn->client;
912 SilcClientNotify notify = state_context;
913 SilcNotifyPayload payload = notify->payload;
914 SilcPacket packet = notify->packet;
915 SilcNotifyType type = silc_notify_get_type(payload);
916 SilcArgumentPayload args = silc_notify_get_args(payload);
917 SilcClientEntry client_entry = NULL, client_entry2 = NULL;
918 SilcChannelEntry channel = NULL, channel_entry = NULL;
919 SilcServerEntry server = NULL;
923 SilcUInt32 tmp_len, mode;
926 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
928 /* Get channel entry */
929 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
930 &id.u.channel_id, sizeof(id.u.channel_id)))
932 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
936 /* If channel is being resolved handle notify after resolving */
937 if (channel->internal.resolve_cmd_ident) {
938 silc_client_unref_channel(client, conn, channel);
939 SILC_FSM_CALL(silc_client_command_pending(
940 conn, SILC_COMMAND_NONE,
941 channel->internal.resolve_cmd_ident,
942 silc_client_notify_wait_continue,
947 /* Get target Client ID */
948 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id2, NULL))
951 /* Find target Client entry */
952 client_entry2 = silc_client_get_client_by_id(client, conn, &id2.u.client_id);
953 if (!client_entry2 || !client_entry2->nickname[0]) {
954 /** Resolve client */
955 silc_client_unref_client(client, conn, client_entry2);
956 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
957 client, conn, &id2.u.client_id, NULL,
958 silc_client_notify_resolved,
964 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
967 SILC_GET32_MSB(mode, tmp);
970 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
973 if (id.type == SILC_ID_CLIENT) {
974 /* Find Client entry */
975 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
976 if (!client_entry || !client_entry->nickname[0]) {
977 /** Resolve client */
978 silc_client_unref_client(client, conn, client_entry);
979 notify->channel = channel;
980 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
981 silc_client_get_client_by_id_resolve(
982 client, conn, &id.u.client_id, NULL,
983 silc_client_notify_resolved,
987 entry = client_entry;
988 } else if (id.type == SILC_ID_SERVER) {
989 /* Find Server entry */
990 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
992 /** Resolve server */
993 notify->channel = channel;
994 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
995 silc_client_get_server_by_id_resolve(
996 client, conn, &id.u.server_id,
997 silc_client_notify_resolved,
1003 /* Find Channel entry */
1004 channel_entry = silc_client_get_channel_by_id(client, conn,
1006 if (!channel_entry) {
1007 /** Resolve channel */
1008 notify->channel = channel;
1009 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1010 silc_client_get_channel_by_id_resolve(
1011 client, conn, &id.u.channel_id,
1012 silc_client_notify_resolved,
1016 entry = channel_entry;
1020 chu = silc_client_on_channel(channel, client_entry2);
1024 /* Notify application. */
1025 NOTIFY(client, conn, type, id.type, entry, mode, client_entry2, channel);
1028 silc_client_unref_client(client, conn, client_entry2);
1030 silc_client_unref_client(client, conn, client_entry);
1032 silc_client_unref_server(client, conn, server);
1034 silc_client_unref_channel(client, conn, channel_entry);
1035 silc_client_unref_channel(client, conn, channel);
1037 /** Notify processed */
1038 silc_fsm_next(fsm, silc_client_notify_processed);
1039 return SILC_FSM_CONTINUE;
1042 /********************************* MOTD *************************************/
1044 /* Received Message of the day */
1046 SILC_FSM_STATE(silc_client_notify_motd)
1048 SilcClientConnection conn = fsm_context;
1049 SilcClient client = conn->client;
1050 SilcClientNotify notify = state_context;
1051 SilcNotifyPayload payload = notify->payload;
1052 SilcNotifyType type = silc_notify_get_type(payload);
1053 SilcArgumentPayload args = silc_notify_get_args(payload);
1057 SILC_LOG_DEBUG(("Notify: MOTD"));
1060 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1064 /* Notify application */
1065 NOTIFY(client, conn, type, tmp);
1068 /** Notify processed */
1069 silc_fsm_next(fsm, silc_client_notify_processed);
1070 return SILC_FSM_CONTINUE;
1073 /**************************** CHANNEL CHANGE ********************************/
1075 /* Router has enforced a new ID to a channel, change it */
1077 SILC_FSM_STATE(silc_client_notify_channel_change)
1079 SilcClientConnection conn = fsm_context;
1080 SilcClient client = conn->client;
1081 SilcClientNotify notify = state_context;
1082 SilcNotifyPayload payload = notify->payload;
1083 SilcNotifyType type = silc_notify_get_type(payload);
1084 SilcArgumentPayload args = silc_notify_get_args(payload);
1085 SilcChannelEntry channel = NULL;
1088 SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
1090 /* Get the old ID */
1091 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1094 /* Get the channel entry */
1095 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1099 /* If channel is being resolved handle notify after resolving */
1100 if (channel->internal.resolve_cmd_ident) {
1101 silc_client_unref_channel(client, conn, channel);
1102 SILC_FSM_CALL(silc_client_command_pending(
1103 conn, SILC_COMMAND_NONE,
1104 channel->internal.resolve_cmd_ident,
1105 silc_client_notify_wait_continue,
1110 /* Get the new ID */
1111 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
1114 /* Replace the Channel ID */
1115 if (!silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id))
1118 /* Notify application */
1119 NOTIFY(client, conn, type, channel, channel);
1122 /** Notify processed */
1123 silc_client_unref_channel(client, conn, channel);
1124 silc_fsm_next(fsm, silc_client_notify_processed);
1125 return SILC_FSM_CONTINUE;
1128 /******************************** KICKED ************************************/
1130 /* Some client was kicked from a channel */
1132 SILC_FSM_STATE(silc_client_notify_kicked)
1134 SilcClientConnection conn = fsm_context;
1135 SilcClient client = conn->client;
1136 SilcClientNotify notify = state_context;
1137 SilcNotifyPayload payload = notify->payload;
1138 SilcPacket packet = notify->packet;
1139 SilcNotifyType type = silc_notify_get_type(payload);
1140 SilcArgumentPayload args = silc_notify_get_args(payload);
1141 SilcClientEntry client_entry, client_entry2;
1142 SilcChannelEntry channel = NULL;
1147 SILC_LOG_DEBUG(("Notify: KICKED"));
1149 /* Get channel entry */
1150 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
1151 &id.u.channel_id, sizeof(id.u.channel_id)))
1153 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1157 /* If channel is being resolved handle notify after resolving */
1158 if (channel->internal.resolve_cmd_ident) {
1159 silc_client_unref_channel(client, conn, channel);
1160 SILC_FSM_CALL(silc_client_command_pending(
1161 conn, SILC_COMMAND_NONE,
1162 channel->internal.resolve_cmd_ident,
1163 silc_client_notify_wait_continue,
1169 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1172 /* Find Client entry */
1173 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1177 /* Get kicker's Client ID */
1178 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
1181 /* Find kicker's client entry and if not found resolve it */
1182 client_entry2 = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1183 if (!client_entry2 || !client_entry2->nickname[0]) {
1184 /** Resolve client */
1185 silc_client_unref_client(client, conn, client_entry);
1186 silc_client_unref_client(client, conn, client_entry2);
1187 notify->channel = channel;
1188 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1189 silc_client_get_client_by_id_resolve(
1190 client, conn, &id.u.client_id, NULL,
1191 silc_client_notify_resolved,
1197 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1199 /* Remove kicked client from channel */
1200 if (client_entry != conn->local_entry)
1201 silc_client_remove_from_channel(client, conn, channel, client_entry);
1203 /* Notify application. */
1204 NOTIFY(client, conn, type, client_entry, tmp, client_entry2, channel);
1206 /* If I was kicked from channel, remove the channel */
1207 if (client_entry == conn->local_entry) {
1208 if (conn->current_channel == channel)
1209 conn->current_channel = NULL;
1210 silc_client_empty_channel(client, conn, channel);
1211 silc_client_del_channel(client, conn, channel);
1214 silc_client_unref_client(client, conn, client_entry);
1215 silc_client_unref_client(client, conn, client_entry2);
1218 /** Notify processed */
1219 silc_client_unref_channel(client, conn, channel);
1220 silc_fsm_next(fsm, silc_client_notify_processed);
1221 return SILC_FSM_CONTINUE;
1224 /******************************** KILLED ************************************/
1226 /* Some client was killed from the network */
1228 SILC_FSM_STATE(silc_client_notify_killed)
1230 SilcClientConnection conn = fsm_context;
1231 SilcClient client = conn->client;
1232 SilcClientNotify notify = state_context;
1233 SilcNotifyPayload payload = notify->payload;
1234 SilcNotifyType type = silc_notify_get_type(payload);
1235 SilcArgumentPayload args = silc_notify_get_args(payload);
1236 SilcClientEntry client_entry = NULL, client_entry2 = NULL;
1237 SilcChannelEntry channel_entry = NULL;
1238 SilcServerEntry server = NULL;
1241 SilcUInt32 comment_len;
1244 SILC_LOG_DEBUG(("Notify: KILLED"));
1247 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1250 /* Find Client entry */
1251 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1256 comment = silc_argument_get_arg_type(args, 2, &comment_len);
1258 /* Get killer's ID */
1259 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
1262 if (id.type == SILC_ID_CLIENT) {
1263 /* Find Client entry */
1264 client_entry2 = silc_client_get_client_by_id(client, conn,
1266 if (!client_entry2 || !client_entry2->nickname[0]) {
1267 /** Resolve client */
1268 silc_client_unref_client(client, conn, client_entry);
1269 silc_client_unref_client(client, conn, client_entry2);
1270 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1271 client, conn, &id.u.client_id, NULL,
1272 silc_client_notify_resolved,
1276 entry = client_entry2;
1277 } else if (id.type == SILC_ID_SERVER) {
1278 /* Find Server entry */
1279 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1281 /** Resolve server */
1282 SILC_FSM_CALL(silc_client_get_server_by_id_resolve(
1283 client, conn, &id.u.server_id,
1284 silc_client_notify_resolved,
1290 /* Find Channel entry */
1291 channel_entry = silc_client_get_channel_by_id(client, conn,
1293 if (!channel_entry) {
1294 /** Resolve channel */
1295 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1296 client, conn, &id.u.channel_id,
1297 silc_client_notify_resolved,
1301 entry = channel_entry;
1304 /* Notify application. */
1305 NOTIFY(client, conn, type, client_entry, comment, id.type, entry);
1307 /* Delete the killed client */
1308 if (client_entry != conn->local_entry) {
1309 silc_client_remove_from_channels(client, conn, client_entry);
1310 silc_client_del_client(client, conn, client_entry);
1314 silc_client_unref_client(client, conn, client_entry);
1316 silc_client_unref_client(client, conn, client_entry2);
1318 silc_client_unref_server(client, conn, server);
1320 silc_client_unref_channel(client, conn, channel_entry);
1322 /** Notify processed */
1323 silc_fsm_next(fsm, silc_client_notify_processed);
1324 return SILC_FSM_CONTINUE;
1327 /**************************** SERVER SIGNOFF ********************************/
1329 /* Some server quit SILC network. Remove its clients from channels. */
1331 SILC_FSM_STATE(silc_client_notify_server_signoff)
1333 SilcClientConnection conn = fsm_context;
1334 SilcClient client = conn->client;
1335 SilcClientNotify notify = state_context;
1336 SilcNotifyPayload payload = notify->payload;
1337 SilcNotifyType type = silc_notify_get_type(payload);
1338 SilcArgumentPayload args = silc_notify_get_args(payload);
1339 SilcClientEntry client_entry;
1344 SILC_LOG_DEBUG(("Notify: SERVER_SIGNOFF"));
1346 clients = silc_dlist_init();
1350 for (i = 1; i < silc_argument_get_arg_num(args); i++) {
1352 if (!silc_argument_get_decoded(args, i + 1, SILC_ARGUMENT_ID, &id, NULL))
1355 /* Get the client entry */
1356 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1358 silc_dlist_add(clients, client_entry);
1361 /* Notify application. We don't keep server entries so the server
1362 entry is returned as NULL. The client's are returned as list. */
1363 NOTIFY(client, conn, type, NULL, clients);
1365 /* Delete the clients */
1366 silc_dlist_start(clients);
1367 while ((client_entry = silc_dlist_get(clients))) {
1368 silc_client_remove_from_channels(client, conn, client_entry);
1369 silc_client_del_client(client, conn, client_entry);
1373 /** Notify processed */
1374 silc_client_list_free(client, conn, clients);
1375 silc_fsm_next(fsm, silc_client_notify_processed);
1376 return SILC_FSM_CONTINUE;
1379 /******************************** ERROR *************************************/
1381 /* Some error occurred */
1383 SILC_FSM_STATE(silc_client_notify_error)
1385 SilcClientConnection conn = fsm_context;
1386 SilcClient client = conn->client;
1387 SilcClientNotify notify = state_context;
1388 SilcNotifyPayload payload = notify->payload;
1389 SilcNotifyType type = silc_notify_get_type(payload);
1390 SilcArgumentPayload args = silc_notify_get_args(payload);
1391 SilcClientEntry client_entry;
1398 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1399 if (!tmp && tmp_len != 1)
1401 error = (SilcStatus)tmp[0];
1403 SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1405 /* Handle the error */
1406 if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1407 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
1409 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1411 silc_client_remove_from_channels(client, conn, client_entry);
1412 silc_client_del_client(client, conn, client_entry);
1413 silc_client_unref_client(client, conn, client_entry);
1417 /* Notify application. */
1418 NOTIFY(client, conn, type, error);
1421 /** Notify processed */
1422 silc_fsm_next(fsm, silc_client_notify_processed);
1423 return SILC_FSM_CONTINUE;
1426 /******************************** WATCH *************************************/
1428 /* Received notify about some client we are watching */
1430 SILC_FSM_STATE(silc_client_notify_watch)
1432 SilcClientConnection conn = fsm_context;
1433 SilcClient client = conn->client;
1434 SilcClientNotify notify = state_context;
1435 SilcNotifyPayload payload = notify->payload;
1436 SilcNotifyType type = silc_notify_get_type(payload);
1437 SilcArgumentPayload args = silc_notify_get_args(payload);
1438 SilcClientEntry client_entry = NULL;
1439 SilcNotifyType ntype = 0;
1440 SilcBool del_client = FALSE;
1441 unsigned char *pk, *tmp;
1442 SilcUInt32 mode, pk_len, tmp_len;
1443 SilcPublicKey public_key = NULL;
1446 SILC_LOG_DEBUG(("Notify: WATCH"));
1448 /* Get sender Client ID */
1449 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1452 /* Find Client entry and if not found resolve it */
1453 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1454 if (!client_entry || !client_entry->nickname[0]) {
1455 /** Resolve client */
1456 silc_client_unref_client(client, conn, client_entry);
1457 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1458 client, conn, &id.u.client_id, NULL,
1459 silc_client_notify_resolved,
1465 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1466 if (!tmp || tmp_len != 4)
1468 SILC_GET32_MSB(mode, tmp);
1470 /* Get notify type */
1471 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1472 if (tmp && tmp_len != 2)
1475 SILC_GET16_MSB(ntype, tmp);
1478 tmp = silc_argument_get_arg_type(args, 2, NULL);
1480 char *tmp_nick = NULL;
1482 silc_client_nickname_parse(client, conn, client_entry->nickname,
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;