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 /************************ Static utility functions **************************/
31 /* Entry resolving callback. This will continue processing the notify. */
33 static void silc_client_notify_resolved(SilcClient client,
34 SilcClientConnection conn,
39 /* If no entries found, just finish the notify processing, a silent error */
41 silc_fsm_next(context, silc_client_notify_processed);
43 /* Continue processing the notify */
44 SILC_FSM_CALL_CONTINUE_SYNC(context);
47 /********************************* Notify ***********************************/
49 /* Process received notify packet */
51 SILC_FSM_STATE(silc_client_notify)
53 SilcPacket packet = state_context;
54 SilcNotifyPayload payload;
56 payload = silc_notify_payload_parse(silc_buffer_data(&packet->buffer),
57 silc_buffer_len(&packet->buffer));
59 SILC_LOG_DEBUG(("Malformed notify payload"));
60 silc_packet_free(packet);
61 return SILC_FSM_FINISH;
64 if (!silc_notify_get_args(payload)) {
65 SILC_LOG_DEBUG(("Malformed notify"));
66 silc_notify_payload_free(payload);
67 silc_packet_free(packet);
68 return SILC_FSM_FINISH;
71 /* Save notify payload to packet context during processing */
72 packet->next = (void *)payload;
74 /* Process the notify */
75 switch (silc_notify_get_type(payload)) {
77 case SILC_NOTIFY_TYPE_NONE:
79 silc_fsm_next(fsm, silc_client_notify_none);
82 case SILC_NOTIFY_TYPE_INVITE:
84 silc_fsm_next(fsm, silc_client_notify_invite);
87 case SILC_NOTIFY_TYPE_JOIN:
89 silc_fsm_next(fsm, silc_client_notify_join);
92 case SILC_NOTIFY_TYPE_LEAVE:
94 silc_fsm_next(fsm, silc_client_notify_leave);
97 case SILC_NOTIFY_TYPE_SIGNOFF:
99 silc_fsm_next(fsm, silc_client_notify_signoff);
102 case SILC_NOTIFY_TYPE_TOPIC_SET:
104 silc_fsm_next(fsm, silc_client_notify_topic_set);
107 case SILC_NOTIFY_TYPE_NICK_CHANGE:
109 silc_fsm_next(fsm, silc_client_notify_nick_change);
112 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
114 silc_fsm_next(fsm, silc_client_notify_cmode_change);
117 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
119 silc_fsm_next(fsm, silc_client_notify_cumode_change);
122 case SILC_NOTIFY_TYPE_MOTD:
124 silc_fsm_next(fsm, silc_client_notify_motd);
127 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
128 /** CHANNEL_CHANGE */
129 silc_fsm_next(fsm, silc_client_notify_channel_change);
132 case SILC_NOTIFY_TYPE_KICKED:
134 silc_fsm_next(fsm, silc_client_notify_kicked);
137 case SILC_NOTIFY_TYPE_KILLED:
139 silc_fsm_next(fsm, silc_client_notify_killed);
142 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
143 /** SERVER_SIGNOFF */
144 silc_fsm_next(fsm, silc_client_notify_server_signoff);
147 case SILC_NOTIFY_TYPE_ERROR:
149 silc_fsm_next(fsm, silc_client_notify_error);
152 case SILC_NOTIFY_TYPE_WATCH:
154 silc_fsm_next(fsm, silc_client_notify_watch);
158 /** Unknown notify */
159 silc_notify_payload_free(payload);
160 silc_packet_free(packet);
161 return SILC_FSM_FINISH;
165 return SILC_FSM_YIELD;
168 /* Notify processed, finish the packet processing thread */
170 SILC_FSM_STATE(silc_client_notify_processed)
172 SilcPacket packet = state_context;
173 SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
174 silc_notify_payload_free(payload);
175 silc_packet_free(packet);
176 return SILC_FSM_FINISH;
179 /********************************** NONE ************************************/
181 SILC_FSM_STATE(silc_client_notify_none)
183 SilcClientConnection conn = fsm_context;
184 SilcClient client = conn->client;
185 SilcPacket packet = state_context;
186 SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
187 SilcNotifyType type = silc_notify_get_type(payload);
188 SilcArgumentPayload args = silc_notify_get_args(payload);
190 /* Notify application */
191 NOTIFY(client, conn, type, silc_argument_get_arg_type(args, 1, NULL));
193 /** Notify processed */
194 silc_fsm_next(fsm, silc_client_notify_processed);
195 return SILC_FSM_CONTINUE;
198 /********************************* INVITE ***********************************/
200 /* Someone invite me to a channel */
202 SILC_FSM_STATE(silc_client_notify_invite)
204 SilcClientConnection conn = fsm_context;
205 SilcClient client = conn->client;
206 SilcPacket packet = state_context;
207 SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
208 SilcNotifyType type = silc_notify_get_type(payload);
209 SilcArgumentPayload args = silc_notify_get_args(payload);
210 SilcClientEntry client_entry;
211 SilcChannelEntry channel = NULL;
216 SILC_LOG_DEBUG(("Notify: INVITE"));
219 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
222 /* Get the channel name */
223 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
227 /* Get the channel entry */
228 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
230 /* Get sender Client ID */
231 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
234 /* Find Client entry and if not found query it */
235 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
236 if (!client_entry || !client_entry->nickname[0]) {
237 /** Resolve client */
238 silc_client_unref_client(client, conn, client_entry);
239 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
240 client, conn, &id.u.client_id, NULL,
241 silc_client_notify_resolved,
246 /* Notify application */
247 NOTIFY(client, conn, type, channel, tmp, client_entry);
249 silc_client_unref_client(client, conn, client_entry);
252 /** Notify processed */
253 silc_client_unref_channel(client, conn, channel);
254 silc_fsm_next(fsm, silc_client_notify_processed);
255 return SILC_FSM_CONTINUE;
258 /********************************** JOIN ************************************/
260 /* Someone joined a channel */
262 SILC_FSM_STATE(silc_client_notify_join)
264 SilcClientConnection conn = fsm_context;
265 SilcClient client = conn->client;
266 SilcPacket packet = state_context;
267 SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
268 SilcNotifyType type = silc_notify_get_type(payload);
269 SilcArgumentPayload args = silc_notify_get_args(payload);
270 SilcClientEntry client_entry;
271 SilcChannelEntry channel = NULL;
274 SILC_LOG_DEBUG(("Notify: JOIN"));
277 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
280 /* Get channel entry */
281 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
286 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
289 /* Find Client entry and if not found query it */
290 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
291 if (!client_entry || !client_entry->nickname[0] ||
292 !client_entry->username[0]) {
293 /** Resolve client */
294 silc_client_unref_client(client, conn, client_entry);
295 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
296 client, conn, &id.u.client_id, NULL,
297 silc_client_notify_resolved,
302 if (client_entry != conn->local_entry)
303 silc_client_nickname_format(client, conn, client_entry);
305 /* Join the client to channel */
306 silc_client_add_to_channel(channel, client_entry, 0);
308 /* Notify application. */
309 NOTIFY(client, conn, type, client_entry, channel);
311 silc_client_unref_client(client, conn, client_entry);
314 /** Notify processed */
315 silc_client_unref_channel(client, conn, channel);
316 silc_fsm_next(fsm, silc_client_notify_processed);
317 return SILC_FSM_CONTINUE;
320 /********************************** LEAVE ***********************************/
322 /* Someone left a channel */
324 SILC_FSM_STATE(silc_client_notify_leave)
326 SilcClientConnection conn = fsm_context;
327 SilcClient client = conn->client;
328 SilcPacket packet = state_context;
329 SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
330 SilcNotifyType type = silc_notify_get_type(payload);
331 SilcArgumentPayload args = silc_notify_get_args(payload);
332 SilcClientEntry client_entry = NULL;
333 SilcChannelEntry channel = NULL;
337 SILC_LOG_DEBUG(("Notify: LEAVE"));
339 /* Get channel entry */
340 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
341 &id.u.channel_id, sizeof(id.u.channel_id)))
343 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
348 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
351 /* Find Client entry */
352 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
356 /* Remove client from channel */
357 chu = silc_client_on_channel(channel, client_entry);
359 silc_hash_table_del(client_entry->channels, channel);
360 silc_hash_table_del(channel->user_list, client_entry);
364 #if 0 /* Kind of useless, server will return error if client keeps using
365 non-existing client, and the entry is removed then. */
366 /* Some client implementations actually quit network by first doing
367 LEAVE and then immediately SIGNOFF. We'll check for this by doing
368 check for the client after 5 - 34 seconds. If it is not valid after
369 that we'll remove the client from cache. */
370 if (!silc_hash_table_count(client_entry->channels)) {
371 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
372 res->context = client;
373 res->sock = silc_socket_dup(conn->sock);
374 res->packet = silc_id_dup(client_id, SILC_ID_CLIENT);
375 silc_schedule_task_add(client->schedule, conn->sock->sock,
376 silc_client_notify_check_client, res,
377 (5 + (silc_rng_get_rn16(client->rng) % 29)),
378 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
382 /* Notify application. */
383 NOTIFY(client, conn, type, client_entry, channel);
385 silc_client_unref_client(client, conn, client_entry);
388 /** Notify processed */
389 silc_client_unref_channel(client, conn, channel);
390 silc_fsm_next(fsm, silc_client_notify_processed);
391 return SILC_FSM_CONTINUE;
394 /********************************* SIGNOFF **********************************/
396 /* Someone quit SILC network */
398 SILC_FSM_STATE(silc_client_notify_signoff)
400 SilcClientConnection conn = fsm_context;
401 SilcClient client = conn->client;
402 SilcPacket packet = state_context;
403 SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
404 SilcNotifyType type = silc_notify_get_type(payload);
405 SilcArgumentPayload args = silc_notify_get_args(payload);
406 SilcClientEntry client_entry;
411 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
414 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
417 /* Find Client entry */
418 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
422 /* Get signoff message */
423 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
427 /* Notify application */
428 NOTIFY(client, conn, type, client_entry, tmp);
430 /* Remove from all channels */
431 silc_client_remove_from_channels(client, conn, client_entry);
434 /* Remove from cache */
435 silc_idcache_del_by_context(conn->internal->client_cache, client_entry);
439 silc_client_unref_client(client, conn, client_entry);
440 silc_client_del_client_entry(client, conn, client_entry);
443 /** Notify processed */
444 silc_fsm_next(fsm, silc_client_notify_processed);
445 return SILC_FSM_CONTINUE;
448 /******************************** TOPIC_SET *********************************/
450 /* Someone set topic on a channel */
452 SILC_FSM_STATE(silc_client_notify_topic_set)
454 SilcClientConnection conn = fsm_context;
455 SilcClient client = conn->client;
456 SilcPacket packet = state_context;
457 SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
458 SilcNotifyType type = silc_notify_get_type(payload);
459 SilcArgumentPayload args = silc_notify_get_args(payload);
460 SilcClientEntry client_entry = NULL;
461 SilcChannelEntry channel = NULL, channel_entry = NULL;
462 SilcServerEntry server = NULL;
468 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
470 /* Get channel entry */
471 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
472 &id.u.channel_id, sizeof(id.u.channel_id)))
474 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
479 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
483 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
487 if (id.type == SILC_ID_CLIENT) {
488 /* Find Client entry */
489 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
490 if (!client_entry || !client_entry->nickname[0]) {
491 /** Resolve client */
492 silc_client_unref_client(client, conn, client_entry);
493 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
494 client, conn, &id.u.client_id, NULL,
495 silc_client_notify_resolved,
499 entry = client_entry;
500 } else if (id.type == SILC_ID_SERVER) {
501 /* Find Server entry */
502 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
504 /** Resolve server */
505 SILC_FSM_CALL(silc_client_get_server_by_id_resolve(
506 client, conn, &id.u.server_id,
507 silc_client_notify_resolved,
513 /* Find Channel entry */
514 channel_entry = silc_client_get_channel_by_id(client, conn,
516 if (!channel_entry) {
517 /** Resolve channel */
518 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
519 client, conn, &id.u.channel_id,
520 silc_client_notify_resolved,
524 entry = channel_entry;
527 silc_free(channel->topic);
528 channel->topic = silc_memdup(tmp, strlen(tmp));
530 /* Notify application. */
531 NOTIFY(client, conn, type, id.type, entry, channel->topic, channel);
534 silc_client_unref_client(client, conn, client_entry);
536 silc_client_unref_server(client, conn, server);
538 silc_client_unref_channel(client, conn, channel_entry);
541 /** Notify processed */
542 silc_client_unref_channel(client, conn, channel);
543 silc_fsm_next(fsm, silc_client_notify_processed);
544 return SILC_FSM_CONTINUE;
547 /****************************** NICK_CHANGE *********************************/
549 /* Someone changed their nickname on a channel */
551 SILC_FSM_STATE(silc_client_notify_nick_change)
553 SilcClientConnection conn = fsm_context;
554 SilcClient client = conn->client;
555 SilcPacket packet = state_context;
556 SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
557 SilcNotifyType type = silc_notify_get_type(payload);
558 SilcArgumentPayload args = silc_notify_get_args(payload);
559 SilcClientEntry client_entry = NULL;
560 unsigned char *tmp, *nick, oldnick[128 + 1];
564 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
567 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
571 if (conn->local_id &&
572 SILC_ID_CLIENT_COMPARE(&id.u.client_id, conn->local_id))
575 /* Find old 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 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
581 client, conn, &id.u.client_id, NULL,
582 silc_client_notify_resolved,
587 /* Get new Client ID */
588 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
591 /* Take the new nickname */
592 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
596 /* Check whether nickname changed at all. It is possible that nick
597 change notify is received but nickname didn't change, only the
598 ID changes. If Client ID hash match, nickname didn't change. */
599 if (SILC_ID_COMPARE_HASH(&client_entry->id, &id.u.client_id) &&
600 silc_utf8_strcasecmp(tmp, client_entry->nickname)) {
601 /* Nickname didn't change. Update only Client ID. We don't notify
602 application because nickname didn't change. */
603 silc_idcache_update(conn->internal->client_cache, client_entry,
604 &client_entry->id, &id.u.client_id, NULL, NULL, FALSE);
608 /* Normalize nickname */
609 nick = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8, 128, NULL);
613 /* Update nickname */
614 if (!silc_idcache_update(conn->internal->client_cache, client_entry,
615 NULL, NULL, client_entry->nickname_normalized,
620 memcpy(oldnick, client_entry->nickname, sizeof(client_entry->nickname));
621 memcpy(client_entry->nickname, tmp, tmp_len);
622 client_entry->nickname_normalized = nick;
623 silc_client_nickname_format(client, conn, client_entry);
625 /* Notify application */
626 NOTIFY(client, conn, type, client_entry, client_entry->nickname, oldnick);
629 /** Notify processed */
630 silc_client_unref_client(client, conn, client_entry);
631 silc_fsm_next(fsm, silc_client_notify_processed);
632 return SILC_FSM_CONTINUE;
635 /****************************** CMODE_CHANGE ********************************/
637 /* Someone changed channel mode */
639 SILC_FSM_STATE(silc_client_notify_cmode_change)
641 SilcClientConnection conn = fsm_context;
642 SilcClient client = conn->client;
643 SilcPacket packet = state_context;
644 SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
645 SilcNotifyType type = silc_notify_get_type(payload);
646 SilcArgumentPayload args = silc_notify_get_args(payload);
647 SilcClientEntry client_entry = NULL;
648 SilcChannelEntry channel = NULL, channel_entry = NULL;
649 SilcServerEntry server = NULL;
652 SilcUInt32 tmp_len, mode;
654 char *passphrase, *cipher, *hmac;
655 SilcPublicKey founder_key = NULL;
656 SilcDList chpks = NULL;
658 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
660 /* Get channel entry */
661 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
662 &id.u.channel_id, sizeof(id.u.channel_id)))
664 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
669 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
672 SILC_GET32_MSB(mode, tmp);
675 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
678 if (id.type == SILC_ID_CLIENT) {
679 /* Find Client entry */
680 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
681 if (!client_entry || !client_entry->nickname[0]) {
682 /** Resolve client */
683 silc_client_unref_client(client, conn, client_entry);
684 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
685 client, conn, &id.u.client_id, NULL,
686 silc_client_notify_resolved,
690 entry = client_entry;
691 } else if (id.type == SILC_ID_SERVER) {
692 /* Find Server entry */
693 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
695 /** Resolve server */
696 SILC_FSM_CALL(silc_client_get_server_by_id_resolve(
697 client, conn, &id.u.server_id,
698 silc_client_notify_resolved,
704 /* Find Channel entry */
705 channel_entry = silc_client_get_channel_by_id(client, conn,
707 if (!channel_entry) {
708 /** Resolve channel */
709 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
710 client, conn, &id.u.channel_id,
711 silc_client_notify_resolved,
715 entry = channel_entry;
718 /* Get the channel founder key if it was set */
719 tmp = silc_argument_get_arg_type(args, 6, &tmp_len);
721 if (!silc_public_key_payload_decode(tmp, tmp_len, &founder_key))
723 if (!channel->founder_key) {
724 channel->founder_key = founder_key;
730 cipher = silc_argument_get_arg_type(args, 3, &tmp_len);
733 hmac = silc_argument_get_arg_type(args, 4, &tmp_len);
735 unsigned char hash[SILC_HASH_MAXLEN];
738 if (!silc_hmac_alloc(hmac, NULL, &newhmac))
741 /* Get HMAC key from the old HMAC context, and update it to the new one */
742 tmp = (unsigned char *)silc_hmac_get_key(channel->internal.hmac, &tmp_len);
744 silc_hash_make(silc_hmac_get_hash(newhmac), tmp, tmp_len, hash);
745 silc_hmac_set_key(newhmac, hash,
746 silc_hash_len(silc_hmac_get_hash(newhmac)));
747 if (channel->internal.hmac)
748 silc_hmac_free(channel->internal.hmac);
749 channel->internal.hmac = newhmac;
750 memset(hash, 0, sizeof(hash));
754 /* Get the passphrase if it was set */
755 passphrase = silc_argument_get_arg_type(args, 5, &tmp_len);
758 tmp = silc_argument_get_arg_type(args, 8, &tmp_len);
759 if (tmp && tmp_len == 4)
760 SILC_GET32_MSB(channel->user_limit, tmp);
761 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
762 channel->user_limit = 0;
764 /* Save the new mode */
765 channel->mode = mode;
767 /* Get the channel public key that was added or removed */
768 tmp = silc_argument_get_arg_type(args, 7, &tmp_len);
770 chpks = silc_argument_list_parse_decoded(tmp, tmp_len,
771 SILC_ARGUMENT_PUBLIC_KEY);
773 /* Notify application. */
774 NOTIFY(client, conn, type, id.type, entry, mode, cipher, hmac,
775 passphrase, channel->founder_key, chpks, channel);
779 silc_pkcs_public_key_free(founder_key);
781 silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
783 silc_client_unref_client(client, conn, client_entry);
785 silc_client_unref_server(client, conn, server);
787 silc_client_unref_channel(client, conn, channel_entry);
788 silc_client_unref_channel(client, conn, channel);
790 /** Notify processed */
791 silc_fsm_next(fsm, silc_client_notify_processed);
792 return SILC_FSM_CONTINUE;
795 /***************************** CUMODE_CHANGE ********************************/
797 /* Someone changed a user's mode on a channel */
799 SILC_FSM_STATE(silc_client_notify_cumode_change)
801 SilcClientConnection conn = fsm_context;
802 SilcClient client = conn->client;
803 SilcPacket packet = state_context;
804 SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
805 SilcNotifyType type = silc_notify_get_type(payload);
806 SilcArgumentPayload args = silc_notify_get_args(payload);
807 SilcClientEntry client_entry = NULL, client_entry2 = NULL;
808 SilcChannelEntry channel = NULL, channel_entry = NULL;
809 SilcServerEntry server = NULL;
813 SilcUInt32 tmp_len, mode;
816 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
818 /* Get channel entry */
819 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
820 &id.u.channel_id, sizeof(id.u.channel_id)))
822 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
827 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
830 SILC_GET32_MSB(mode, tmp);
833 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
836 if (id.type == SILC_ID_CLIENT) {
837 /* Find Client entry */
838 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
839 if (!client_entry || !client_entry->nickname[0]) {
840 /** Resolve client */
841 silc_client_unref_client(client, conn, client_entry);
842 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
843 client, conn, &id.u.client_id, NULL,
844 silc_client_notify_resolved,
848 entry = client_entry;
849 } else if (id.type == SILC_ID_SERVER) {
850 /* Find Server entry */
851 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
853 /** Resolve server */
854 SILC_FSM_CALL(silc_client_get_server_by_id_resolve(
855 client, conn, &id.u.server_id,
856 silc_client_notify_resolved,
862 /* Find Channel entry */
863 channel_entry = silc_client_get_channel_by_id(client, conn,
865 if (!channel_entry) {
866 /** Resolve channel */
867 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
868 client, conn, &id.u.channel_id,
869 silc_client_notify_resolved,
873 entry = channel_entry;
876 /* Get target Client ID */
877 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id2, NULL))
880 /* Find target Client entry */
881 client_entry2 = silc_client_get_client_by_id(client, conn, &id2.u.client_id);
882 if (!client_entry2 || !client_entry2->nickname[0]) {
883 /** Resolve client */
884 silc_client_unref_client(client, conn, client_entry);
885 silc_client_unref_client(client, conn, client_entry2);
886 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
887 client, conn, &id2.u.client_id, NULL,
888 silc_client_notify_resolved,
894 chu = silc_client_on_channel(channel, client_entry2);
898 /* Notify application. */
899 NOTIFY(client, conn, type, id.type, entry, mode, client_entry2, channel);
902 silc_client_unref_client(client, conn, client_entry2);
904 silc_client_unref_client(client, conn, client_entry);
906 silc_client_unref_server(client, conn, server);
908 silc_client_unref_channel(client, conn, channel_entry);
909 silc_client_unref_channel(client, conn, channel);
911 /** Notify processed */
912 silc_fsm_next(fsm, silc_client_notify_processed);
913 return SILC_FSM_CONTINUE;
916 /********************************* MOTD *************************************/
918 /* Received Message of the day */
920 SILC_FSM_STATE(silc_client_notify_motd)
922 SilcClientConnection conn = fsm_context;
923 SilcClient client = conn->client;
924 SilcPacket packet = state_context;
925 SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
926 SilcNotifyType type = silc_notify_get_type(payload);
927 SilcArgumentPayload args = silc_notify_get_args(payload);
931 SILC_LOG_DEBUG(("Notify: MOTD"));
934 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
938 /* Notify application */
939 NOTIFY(client, conn, type, tmp);
942 /** Notify processed */
943 silc_fsm_next(fsm, silc_client_notify_processed);
944 return SILC_FSM_CONTINUE;
947 /**************************** CHANNEL CHANGE ********************************/
949 /* Router has enforced a new ID to a channel, change it */
951 SILC_FSM_STATE(silc_client_notify_channel_change)
953 SilcClientConnection conn = fsm_context;
954 SilcClient client = conn->client;
955 SilcPacket packet = state_context;
956 SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
957 SilcNotifyType type = silc_notify_get_type(payload);
958 SilcArgumentPayload args = silc_notify_get_args(payload);
959 SilcChannelEntry channel = NULL;
962 SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
965 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
968 /* Get the channel entry */
969 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
974 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
977 /* Replace the Channel ID */
978 if (!silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id))
981 /* Notify application */
982 NOTIFY(client, conn, type, channel, channel);
985 /** Notify processed */
986 silc_client_unref_channel(client, conn, channel);
987 silc_fsm_next(fsm, silc_client_notify_processed);
988 return SILC_FSM_CONTINUE;
991 /******************************** KICKED ************************************/
993 /* Some client was kicked from a channel */
995 SILC_FSM_STATE(silc_client_notify_kicked)
997 SilcClientConnection conn = fsm_context;
998 SilcClient client = conn->client;
999 SilcPacket packet = state_context;
1000 SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
1001 SilcNotifyType type = silc_notify_get_type(payload);
1002 SilcArgumentPayload args = silc_notify_get_args(payload);
1003 SilcClientEntry client_entry, client_entry2;
1004 SilcChannelEntry channel = NULL;
1005 SilcChannelUser chu;
1010 SILC_LOG_DEBUG(("Notify: KICKED"));
1013 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1016 /* Find Client entry */
1017 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1021 /* Get channel entry */
1022 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
1023 &id.u.channel_id, sizeof(id.u.channel_id)))
1025 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1029 /* Get kicker's Client ID */
1030 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
1033 /* Find kicker's client entry and if not found resolve it */
1034 client_entry2 = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1035 if (!client_entry2 || !client_entry2->nickname[0]) {
1036 /** Resolve client */
1037 silc_client_unref_client(client, conn, client_entry);
1038 silc_client_unref_client(client, conn, client_entry2);
1039 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1040 client, conn, &id.u.client_id, NULL,
1041 silc_client_notify_resolved,
1047 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1049 /* Remove kicked client from channel */
1050 if (client_entry != conn->local_entry) {
1051 chu = silc_client_on_channel(channel, client_entry);
1053 silc_hash_table_del(client_entry->channels, channel);
1054 silc_hash_table_del(channel->user_list, client_entry);
1059 /* Notify application. */
1060 NOTIFY(client, conn, type, client_entry, tmp, client_entry2, channel);
1062 /* If I was kicked from channel, remove the channel */
1063 if (client_entry == conn->local_entry) {
1064 if (conn->current_channel == channel)
1065 conn->current_channel = NULL;
1066 silc_client_del_channel(client, conn, channel);
1069 silc_client_unref_client(client, conn, client_entry);
1070 silc_client_unref_client(client, conn, client_entry2);
1073 /** Notify processed */
1074 silc_client_unref_channel(client, conn, channel);
1075 silc_fsm_next(fsm, silc_client_notify_processed);
1076 return SILC_FSM_CONTINUE;
1079 /******************************** KILLED ************************************/
1081 /* Some client was killed from the network */
1083 SILC_FSM_STATE(silc_client_notify_killed)
1085 SilcClientConnection conn = fsm_context;
1086 SilcClient client = conn->client;
1087 SilcPacket packet = state_context;
1088 SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
1089 SilcNotifyType type = silc_notify_get_type(payload);
1090 SilcArgumentPayload args = silc_notify_get_args(payload);
1091 SilcClientEntry client_entry = NULL, client_entry2 = NULL;
1092 SilcChannelEntry channel_entry = NULL;
1093 SilcServerEntry server = NULL;
1096 SilcUInt32 comment_len;
1099 SILC_LOG_DEBUG(("Notify: KILLED"));
1102 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1105 /* Find Client entry */
1106 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1111 comment = silc_argument_get_arg_type(args, 2, &comment_len);
1113 /* Get killer's ID */
1114 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
1117 if (id.type == SILC_ID_CLIENT) {
1118 /* Find Client entry */
1119 client_entry2 = silc_client_get_client_by_id(client, conn,
1121 if (!client_entry2 || !client_entry2->nickname[0]) {
1122 /** Resolve client */
1123 silc_client_unref_client(client, conn, client_entry);
1124 silc_client_unref_client(client, conn, client_entry2);
1125 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1126 client, conn, &id.u.client_id, NULL,
1127 silc_client_notify_resolved,
1131 entry = client_entry2;
1132 } else if (id.type == SILC_ID_SERVER) {
1133 /* Find Server entry */
1134 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1136 /** Resolve server */
1137 SILC_FSM_CALL(silc_client_get_server_by_id_resolve(
1138 client, conn, &id.u.server_id,
1139 silc_client_notify_resolved,
1145 /* Find Channel entry */
1146 channel_entry = silc_client_get_channel_by_id(client, conn,
1148 if (!channel_entry) {
1149 /** Resolve channel */
1150 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1151 client, conn, &id.u.channel_id,
1152 silc_client_notify_resolved,
1156 entry = channel_entry;
1159 /* Notify application. */
1160 NOTIFY(client, conn, type, client_entry, comment, id.type, entry);
1162 /* Delete the killed client */
1163 if (client_entry != conn->local_entry)
1164 silc_client_del_client(client, conn, client_entry);
1167 silc_client_unref_client(client, conn, client_entry);
1169 silc_client_unref_client(client, conn, client_entry2);
1171 silc_client_unref_server(client, conn, server);
1173 silc_client_unref_channel(client, conn, channel_entry);
1175 /** Notify processed */
1176 silc_fsm_next(fsm, silc_client_notify_processed);
1177 return SILC_FSM_CONTINUE;
1180 /**************************** SERVER SIGNOFF ********************************/
1182 /* Some server quit SILC network. Remove its clients from channels. */
1184 SILC_FSM_STATE(silc_client_notify_server_signoff)
1186 SilcClientConnection conn = fsm_context;
1187 SilcClient client = conn->client;
1188 SilcPacket packet = state_context;
1189 SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
1190 SilcNotifyType type = silc_notify_get_type(payload);
1191 SilcArgumentPayload args = silc_notify_get_args(payload);
1192 SilcClientEntry client_entry;
1197 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
1199 clients = silc_dlist_init();
1203 for (i = 1; i < silc_argument_get_arg_num(args); i++) {
1205 if (!silc_argument_get_decoded(args, i + 1, SILC_ARGUMENT_ID, &id, NULL))
1208 /* Get the client entry */
1209 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1211 silc_dlist_add(clients, client_entry);
1214 /* Notify application. We don't keep server entries so the server
1215 entry is returned as NULL. The client's are returned as list. */
1216 NOTIFY(client, conn, type, NULL, clients);
1218 /* Delete the clients */
1219 silc_dlist_start(clients);
1220 while ((client_entry = silc_dlist_get(clients)))
1221 silc_client_del_client(client, conn, client_entry);
1224 /** Notify processed */
1225 silc_client_list_free(client, conn, clients);
1226 silc_fsm_next(fsm, silc_client_notify_processed);
1227 return SILC_FSM_CONTINUE;
1230 /******************************** ERROR *************************************/
1232 /* Some error occurred */
1234 SILC_FSM_STATE(silc_client_notify_error)
1236 SilcClientConnection conn = fsm_context;
1237 SilcClient client = conn->client;
1238 SilcPacket packet = state_context;
1239 SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
1240 SilcNotifyType type = silc_notify_get_type(payload);
1241 SilcArgumentPayload args = silc_notify_get_args(payload);
1242 SilcClientEntry client_entry;
1249 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1250 if (!tmp && tmp_len != 1)
1252 error = (SilcStatus)tmp[0];
1254 SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1256 /* Handle the error */
1257 if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1258 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
1260 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1262 silc_client_del_client(client, conn, client_entry);
1263 silc_client_unref_client(client, conn, client_entry);
1267 /* Notify application. */
1268 NOTIFY(client, conn, type, error);
1271 /** Notify processed */
1272 silc_fsm_next(fsm, silc_client_notify_processed);
1273 return SILC_FSM_CONTINUE;
1276 /******************************** WATCH *************************************/
1278 /* Received notify about some client we are watching */
1280 SILC_FSM_STATE(silc_client_notify_watch)
1282 SilcClientConnection conn = fsm_context;
1283 SilcClient client = conn->client;
1284 SilcPacket packet = state_context;
1285 SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
1286 SilcNotifyType type = silc_notify_get_type(payload);
1287 SilcArgumentPayload args = silc_notify_get_args(payload);
1288 SilcClientEntry client_entry = NULL;
1289 SilcNotifyType notify = 0;
1290 SilcBool del_client = FALSE;
1291 unsigned char *pk, *tmp;
1292 SilcUInt32 mode, pk_len, tmp_len;
1293 SilcPublicKey public_key = NULL;
1296 SILC_LOG_DEBUG(("Notify: WATCH"));
1298 /* Get sender Client ID */
1299 if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1302 /* Find Client entry and if not found resolve it */
1303 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1304 if (!client_entry || !client_entry->nickname[0]) {
1305 /** Resolve client */
1306 silc_client_unref_client(client, conn, client_entry);
1307 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1308 client, conn, &id.u.client_id, NULL,
1309 silc_client_notify_resolved,
1315 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1316 if (!tmp || tmp_len != 4)
1318 SILC_GET32_MSB(mode, tmp);
1320 /* Get notify type */
1321 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1322 if (tmp && tmp_len != 2)
1325 SILC_GET16_MSB(notify, tmp);
1328 tmp = silc_argument_get_arg_type(args, 2, NULL);
1330 char *tmp_nick = NULL;
1332 if (client->internal->params->nickname_parse)
1333 client->internal->params->nickname_parse(client_entry->nickname,
1336 tmp_nick = strdup(tmp);
1338 /* If same nick, the client was new to us and has become "present"
1339 to network. Send NULL as nick to application. */
1340 if (tmp_nick && silc_utf8_strcasecmp(tmp, tmp_nick))
1343 silc_free(tmp_nick);
1346 /* Get public key, if present */
1347 pk = silc_argument_get_arg_type(args, 5, &pk_len);
1348 if (pk && !client_entry->public_key) {
1349 if (silc_public_key_payload_decode(pk, pk_len, &public_key)) {
1350 client_entry->public_key = public_key;
1355 /* Notify application. */
1356 NOTIFY(client, conn, type, client_entry, tmp, mode, notify,
1357 client_entry->public_key);
1359 client_entry->mode = mode;
1361 /* If nickname was changed, remove the client entry unless the
1362 client is on some channel */
1363 /* XXX, why do we need to remove the client entry?? */
1364 if (tmp && notify == SILC_NOTIFY_TYPE_NICK_CHANGE &&
1365 !silc_hash_table_count(client_entry->channels))
1367 else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1368 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
1369 notify == SILC_NOTIFY_TYPE_KILLED)
1373 silc_client_del_client(client, conn, client_entry);
1376 silc_pkcs_public_key_free(public_key);
1379 /** Notify processed */
1380 silc_client_unref_client(client, conn, client_entry);
1381 silc_fsm_next(fsm, silc_client_notify_processed);
1382 return SILC_FSM_CONTINUE;