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 /* Calls error command reply callback back to command sender. */
28 #define ERROR_CALLBACK(error) \
30 void *arg1 = NULL, *arg2 = NULL; \
31 if (cmd->status != SILC_STATUS_OK) \
32 silc_status_get_args(cmd->status, args, &arg1, &arg2); \
34 cmd->status = error; \
35 SILC_LOG_DEBUG(("Error in command reply")); \
36 silc_client_command_callback(cmd, arg1, arg2); \
40 #define CHECK_STATUS(msg) \
41 SILC_LOG_DEBUG(("Start")); \
42 if (cmd->error != SILC_STATUS_OK) { \
44 SAY(cmd->conn->client, cmd->conn, SILC_CLIENT_MESSAGE_ERROR, \
45 msg "%s", silc_get_status_message(cmd->error)); \
46 ERROR_CALLBACK(cmd->error); \
47 silc_client_command_process_error(cmd, state_context, cmd->error); \
48 silc_fsm_next(fsm, silc_client_command_reply_process); \
49 return SILC_FSM_YIELD; \
52 /* Check for correct arguments */
53 #define CHECK_ARGS(min, max) \
54 if (silc_argument_get_arg_num(args) < min || \
55 silc_argument_get_arg_num(args) > max) { \
56 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); \
57 silc_fsm_next(fsm, silc_client_command_reply_process); \
58 return SILC_FSM_YIELD; \
61 #define SAY cmd->conn->client->internal->ops->say
63 /************************ Static utility functions **************************/
65 /* Delivers the command reply back to application */
68 silc_client_command_callback(SilcClientCommandContext cmd, ...)
70 SilcClientCommandReplyCallback cb;
75 /* Default reply callback */
77 SILC_LOG_DEBUG(("cp %p, ap %p", cp, ap));
79 SILC_LOG_DEBUG(("cp %p, ap %p", cp, ap));
80 cmd->conn->client->internal->ops->command_reply(
81 cmd->conn->client, cmd->conn, cmd->cmd, cmd->status,
87 silc_list_start(cmd->reply_callbacks);
88 while ((cb = silc_list_get(cmd->reply_callbacks)))
89 if (!cb->do_not_call) {
90 SILC_LOG_DEBUG(("cp %p, ap %p", cp, ap));
92 SILC_LOG_DEBUG(("cp %p, ap %p", cp, ap));
93 cb->do_not_call = cb->reply(cmd->conn->client, cmd->conn, cmd->cmd,
94 cmd->status, cmd->error, cb->context, cp);
101 /* Handles common error status types. */
103 static void silc_client_command_process_error(SilcClientCommandContext cmd,
104 SilcCommandPayload payload,
107 SilcClient client = cmd->conn->client;
108 SilcClientConnection conn = cmd->conn;
109 SilcArgumentPayload args = silc_command_get_args(payload);
110 SilcClientEntry client_entry;
113 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
114 /* Remove unknown client entry from cache */
115 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
118 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
120 silc_client_unref_client(client, conn, client_entry);
121 silc_client_del_client(client, conn, client_entry);
126 /***************************** Command Reply ********************************/
128 /* Process received command reply packet */
130 SILC_FSM_STATE(silc_client_command_reply)
132 SilcClientConnection conn = fsm_context;
133 SilcPacket packet = state_context;
134 SilcClientCommandContext cmd;
135 SilcCommandPayload payload;
137 SilcUInt16 cmd_ident;
139 /* Get command reply payload from packet */
140 payload = silc_command_payload_parse(silc_buffer_datalen(&packet->buffer));
141 silc_packet_free(packet);
143 SILC_LOG_DEBUG(("Bad command reply packet"));
144 return SILC_FSM_FINISH;
147 cmd_ident = silc_command_get_ident(payload);
148 command = silc_command_get(payload);
150 /* Find the command pending reply */
151 silc_mutex_lock(conn->internal->lock);
152 silc_list_start(conn->internal->pending_commands);
153 while ((cmd = silc_list_get(conn->internal->pending_commands))) {
154 SILC_LOG_DEBUG(("cmd %p, command %d, ident %d", cmd, cmd->cmd,
156 if ((cmd->cmd == command || cmd->cmd == SILC_COMMAND_NONE)
157 && cmd->cmd_ident == cmd_ident) {
158 silc_list_del(conn->internal->pending_commands, cmd);
162 silc_mutex_unlock(conn->internal->lock);
165 SILC_LOG_DEBUG(("Unknown command reply"));
166 silc_command_payload_free(payload);
167 return SILC_FSM_FINISH;
170 SILC_LOG_DEBUG(("cmd %p, command %d", cmd, cmd->cmd));
172 /* Signal command thread that command reply has arrived */
173 silc_fsm_set_state_context(&cmd->thread, payload);
174 silc_fsm_next(&cmd->thread, silc_client_command_reply_process);
175 silc_fsm_continue_sync(&cmd->thread);
177 return SILC_FSM_FINISH;
180 /* Wait here for command reply to arrive from remote host */
182 SILC_FSM_STATE(silc_client_command_reply_wait)
184 SILC_LOG_DEBUG(("Wait for command reply"));
186 /** Wait for command reply */
187 silc_fsm_set_state_context(fsm, NULL);
188 silc_fsm_next_later(fsm, silc_client_command_reply_timeout, 20, 0);
189 return SILC_FSM_WAIT;
192 /* Timeout occurred while waiting command reply */
194 SILC_FSM_STATE(silc_client_command_reply_timeout)
196 SilcClientCommandContext cmd = fsm_context;
197 SilcArgumentPayload args = NULL;
199 /* Timeout, reply not received in timely fashion */
200 ERROR_CALLBACK(SILC_STATUS_ERR_TIMEDOUT);
201 return SILC_FSM_FINISH;
204 /* Process received command reply payload */
206 SILC_FSM_STATE(silc_client_command_reply_process)
208 SilcClientCommandContext cmd = fsm_context;
209 SilcCommandPayload payload = state_context;
211 silc_command_get_status(payload, &cmd->status, &cmd->error);
214 case SILC_COMMAND_WHOIS:
216 silc_fsm_next(fsm, silc_client_command_reply_whois);
218 case SILC_COMMAND_WHOWAS:
220 silc_fsm_next(fsm, silc_client_command_reply_whowas);
222 case SILC_COMMAND_IDENTIFY:
224 silc_fsm_next(fsm, silc_client_command_reply_identify);
226 case SILC_COMMAND_NICK:
228 silc_fsm_next(fsm, silc_client_command_reply_nick);
230 case SILC_COMMAND_LIST:
232 silc_fsm_next(fsm, silc_client_command_reply_list);
234 case SILC_COMMAND_TOPIC:
236 silc_fsm_next(fsm, silc_client_command_reply_topic);
238 case SILC_COMMAND_INVITE:
240 silc_fsm_next(fsm, silc_client_command_reply_invite);
242 case SILC_COMMAND_QUIT:
244 silc_fsm_next(fsm, silc_client_command_reply_quit);
246 case SILC_COMMAND_KILL:
248 silc_fsm_next(fsm, silc_client_command_reply_kill);
250 case SILC_COMMAND_INFO:
252 silc_fsm_next(fsm, silc_client_command_reply_info);
254 case SILC_COMMAND_STATS:
256 silc_fsm_next(fsm, silc_client_command_reply_stats);
258 case SILC_COMMAND_PING:
260 silc_fsm_next(fsm, silc_client_command_reply_ping);
262 case SILC_COMMAND_OPER:
264 silc_fsm_next(fsm, silc_client_command_reply_oper);
266 case SILC_COMMAND_JOIN:
268 silc_fsm_next(fsm, silc_client_command_reply_join);
270 case SILC_COMMAND_MOTD:
272 silc_fsm_next(fsm, silc_client_command_reply_motd);
274 case SILC_COMMAND_UMODE:
276 silc_fsm_next(fsm, silc_client_command_reply_umode);
278 case SILC_COMMAND_CMODE:
280 silc_fsm_next(fsm, silc_client_command_reply_cmode);
282 case SILC_COMMAND_CUMODE:
284 silc_fsm_next(fsm, silc_client_command_reply_cumode);
286 case SILC_COMMAND_KICK:
288 silc_fsm_next(fsm, silc_client_command_reply_kick);
290 case SILC_COMMAND_BAN:
292 silc_fsm_next(fsm, silc_client_command_reply_ban);
294 case SILC_COMMAND_DETACH:
296 silc_fsm_next(fsm, silc_client_command_reply_detach);
298 case SILC_COMMAND_WATCH:
300 silc_fsm_next(fsm, silc_client_command_reply_watch);
302 case SILC_COMMAND_SILCOPER:
304 silc_fsm_next(fsm, silc_client_command_reply_silcoper);
306 case SILC_COMMAND_LEAVE:
308 silc_fsm_next(fsm, silc_client_command_reply_leave);
310 case SILC_COMMAND_USERS:
312 silc_fsm_next(fsm, silc_client_command_reply_users);
314 case SILC_COMMAND_GETKEY:
316 silc_fsm_next(fsm, silc_client_command_reply_getkey);
318 case SILC_COMMAND_SERVICE:
320 silc_fsm_next(fsm, silc_client_command_reply_service);
323 return SILC_FSM_FINISH;
326 return SILC_FSM_CONTINUE;
329 /* Completes command reply processing */
331 SILC_FSM_STATE(silc_client_command_reply_processed)
333 SilcClientCommandContext cmd = fsm_context;
334 SilcCommandPayload payload = state_context;
336 silc_command_payload_free(payload);
338 if (cmd->status == SILC_STATUS_OK || cmd->status == SILC_STATUS_LIST_END ||
339 SILC_STATUS_IS_ERROR(cmd->status))
340 return SILC_FSM_FINISH;
342 /** Wait more command payloads */
343 silc_fsm_next(fsm, silc_client_command_reply_wait);
344 return SILC_FSM_CONTINUE;
347 /******************************** WHOIS *************************************/
349 /* Received reply for WHOIS command. */
351 SILC_FSM_STATE(silc_client_command_reply_whois)
353 SilcClientCommandContext cmd = fsm_context;
354 SilcClientConnection conn = cmd->conn;
355 SilcClient client = conn->client;
356 SilcCommandPayload payload = state_context;
357 SilcArgumentPayload args = silc_command_get_args(payload);
358 SilcClientEntry client_entry = NULL;
359 SilcUInt32 idle = 0, mode = 0, fingerprint_len, len, *umodes = NULL;
360 SilcBufferStruct channels, ch_user_modes;
361 SilcBool has_channels = FALSE;
362 SilcDList channel_list = NULL;
364 char *nickname = NULL, *username = NULL, *realname = NULL;
365 unsigned char *fingerprint, *tmp;
367 CHECK_STATUS("WHOIS: ");
371 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
372 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
377 nickname = silc_argument_get_arg_type(args, 3, NULL);
378 username = silc_argument_get_arg_type(args, 4, NULL);
379 realname = silc_argument_get_arg_type(args, 5, NULL);
380 if (!nickname || !username || !realname) {
381 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
385 /* Get joined channel list */
386 memset(&channels, 0, sizeof(channels));
387 tmp = silc_argument_get_arg_type(args, 6, &len);
390 silc_buffer_set(&channels, tmp, len);
392 /* Get channel user mode list */
393 tmp = silc_argument_get_arg_type(args, 10, &len);
395 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
398 silc_buffer_set(&ch_user_modes, tmp, len);
402 tmp = silc_argument_get_arg_type(args, 7, &len);
404 SILC_GET32_MSB(mode, tmp);
407 tmp = silc_argument_get_arg_type(args, 8, &len);
409 SILC_GET32_MSB(idle, tmp);
411 /* Get fingerprint */
412 fingerprint = silc_argument_get_arg_type(args, 9, &fingerprint_len);
414 /* Check if we have this client cached already. */
415 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
417 SILC_LOG_DEBUG(("Adding new client entry (WHOIS)"));
419 silc_client_add_client(client, conn, nickname, username, realname,
420 &id.u.client_id, mode);
422 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
426 silc_client_update_client(client, conn, client_entry,
427 nickname, username, realname, mode);
430 if (fingerprint && fingerprint_len == sizeof(client_entry->fingerprint))
431 memcpy(client_entry->fingerprint, fingerprint, fingerprint_len);
433 /* Get user attributes */
434 tmp = silc_argument_get_arg_type(args, 11, &len);
436 if (client_entry->attrs)
437 silc_attribute_payload_list_free(client_entry->attrs);
438 client_entry->attrs = silc_attribute_payload_parse(tmp, len);
441 /* Parse channel and channel user mode list */
443 channel_list = silc_channel_payload_parse_list(silc_buffer_data(&channels),
444 silc_buffer_len(&channels));
446 silc_get_mode_list(&ch_user_modes, silc_dlist_count(channel_list),
450 /* Notify application */
451 silc_client_command_callback(cmd, client_entry, nickname, username,
452 realname, channel_list, mode, idle, fingerprint,
453 umodes, client_entry->attrs);
455 silc_client_unref_client(client, conn, client_entry);
457 silc_dlist_uninit(channel_list);
462 silc_fsm_next(fsm, silc_client_command_reply_processed);
463 return SILC_FSM_CONTINUE;
466 /******************************** WHOWAS ************************************/
468 /* Received reply for WHOWAS command. */
470 SILC_FSM_STATE(silc_client_command_reply_whowas)
472 SilcClientCommandContext cmd = fsm_context;
473 SilcClientConnection conn = cmd->conn;
474 SilcClient client = conn->client;
475 SilcCommandPayload payload = state_context;
476 SilcArgumentPayload args = silc_command_get_args(payload);
477 SilcClientEntry client_entry = NULL;
479 char *nickname, *username;
480 char *realname = NULL;
482 CHECK_STATUS("WHOWAS: ");
486 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
487 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
491 /* Get the client entry */
492 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
495 nickname = silc_argument_get_arg_type(args, 3, NULL);
496 username = silc_argument_get_arg_type(args, 4, NULL);
497 realname = silc_argument_get_arg_type(args, 5, NULL);
498 if (!nickname || !username) {
499 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
503 /* Notify application. We don't save any history information to any
504 cache. Just pass the data to the application. */
505 silc_client_command_callback(cmd, client_entry, nickname, username,
509 silc_client_unref_client(client, conn, client_entry);
510 silc_fsm_next(fsm, silc_client_command_reply_processed);
511 return SILC_FSM_CONTINUE;
514 /******************************** IDENTIFY **********************************/
516 /* Received reply for IDENTIFY command. */
518 SILC_FSM_STATE(silc_client_command_reply_identify)
520 SilcClientCommandContext cmd = fsm_context;
521 SilcClientConnection conn = cmd->conn;
522 SilcClient client = conn->client;
523 SilcCommandPayload payload = state_context;
524 SilcArgumentPayload args = silc_command_get_args(payload);
525 SilcClientEntry client_entry;
526 SilcServerEntry server_entry;
527 SilcChannelEntry channel_entry;
530 char *name = NULL, *info = NULL;
532 CHECK_STATUS("IDENTIFY: ");
536 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
537 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
542 name = silc_argument_get_arg_type(args, 3, &len);
543 info = silc_argument_get_arg_type(args, 4, &len);
547 SILC_LOG_DEBUG(("Received client information"));
549 /* Check if we have this client cached already. */
550 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
552 SILC_LOG_DEBUG(("Adding new client entry (IDENTIFY)"));
554 silc_client_add_client(client, conn, name, info, NULL,
557 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
561 silc_client_update_client(client, conn, client_entry,
562 name, info, NULL, 0);
565 /* Notify application */
566 silc_client_command_callback(cmd, client_entry, name, info);
567 silc_client_unref_client(client, conn, client_entry);
571 SILC_LOG_DEBUG(("Received server information"));
573 /* Check if we have this server cached already. */
574 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
576 SILC_LOG_DEBUG(("Adding new server entry (IDENTIFY)"));
577 server_entry = silc_client_add_server(client, conn, name, info,
580 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
584 silc_client_update_server(client, conn, server_entry, name, info);
586 server_entry->internal.resolve_cmd_ident = 0;
588 /* Notify application */
589 silc_client_command_callback(cmd, server_entry, name, info);
592 case SILC_ID_CHANNEL:
593 SILC_LOG_DEBUG(("Received channel information"));
595 /* Check if we have this channel cached already. */
596 channel_entry = silc_client_get_channel_by_id(client, conn,
598 if (!channel_entry) {
599 SILC_LOG_DEBUG(("Adding new channel entry (IDENTIFY"));
602 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
606 /* Add new channel entry */
607 channel_entry = silc_client_add_channel(client, conn, name, 0,
609 if (!channel_entry) {
610 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
615 /* Notify application */
616 silc_client_command_callback(cmd, channel_entry, name, info);
621 silc_fsm_next(fsm, silc_client_command_reply_processed);
622 return SILC_FSM_CONTINUE;
625 /********************************** NICK ************************************/
627 /* Received reply for command NICK. */
629 SILC_FSM_STATE(silc_client_command_reply_nick)
631 SilcClientCommandContext cmd = fsm_context;
632 SilcClientConnection conn = cmd->conn;
633 SilcClient client = conn->client;
634 SilcCommandPayload payload = state_context;
635 SilcArgumentPayload args = silc_command_get_args(payload);
636 unsigned char *tmp, *nick, *idp;
637 SilcUInt32 len, idp_len;
638 SilcClientID old_client_id;
642 CHECK_STATUS("Cannot set nickname: ");
645 old_client_id = *conn->local_id;
647 /* Take received Client ID */
648 idp = silc_argument_get_arg_type(args, 2, &idp_len);
650 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
653 if (!silc_id_payload_parse_id(idp, idp_len, &id)) {
654 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
658 /* Take the new nickname */
659 nick = silc_argument_get_arg_type(args, 3, &len);
661 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
665 /* Normalize nickname */
666 tmp = silc_identifier_check(nick, len, SILC_STRING_UTF8, 128, NULL);
668 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_NICKNAME);
672 /* Update the client entry */
673 silc_mutex_lock(conn->internal->lock);
674 if (!silc_idcache_update(conn->internal->client_cache,
675 conn->internal->local_entry,
676 &conn->local_entry->id,
678 conn->local_entry->nickname_normalized,
681 silc_mutex_unlock(conn->internal->lock);
682 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_NICKNAME);
685 silc_mutex_unlock(conn->internal->lock);
686 memset(conn->local_entry->nickname, 0, sizeof(conn->local_entry->nickname));
687 memcpy(conn->local_entry->nickname, nick, len);
688 conn->local_entry->nickname_normalized = tmp;
689 silc_buffer_enlarge(conn->internal->local_idp, idp_len);
690 silc_buffer_put(conn->internal->local_idp, idp, idp_len);
691 silc_client_nickname_format(client, conn, conn->local_entry);
692 silc_packet_set_ids(conn->stream, SILC_ID_CLIENT, conn->local_id, 0, NULL);
694 /* Notify application */
695 silc_client_command_callback(cmd, conn->local_entry,
696 conn->local_entry->nickname, &old_client_id);
699 silc_fsm_next(fsm, silc_client_command_reply_processed);
700 return SILC_FSM_CONTINUE;
703 /********************************** LIST ************************************/
705 /* Received reply to the LIST command. */
707 SILC_FSM_STATE(silc_client_command_reply_list)
709 SilcClientCommandContext cmd = fsm_context;
710 SilcClientConnection conn = cmd->conn;
711 SilcClient client = conn->client;
712 SilcCommandPayload payload = state_context;
713 SilcArgumentPayload args = silc_command_get_args(payload);
714 unsigned char *tmp, *name, *topic;
715 SilcUInt32 usercount = 0;
716 SilcChannelEntry channel_entry;
720 CHECK_STATUS("Cannot list channels: ");
722 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
723 /* There were no channels in the network. */
724 silc_client_command_callback(cmd, NULL, NULL, NULL, 0);
725 silc_fsm_next(fsm, silc_client_command_reply_processed);
726 return SILC_FSM_CONTINUE;
731 name = silc_argument_get_arg_type(args, 3, NULL);
733 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
737 topic = silc_argument_get_arg_type(args, 4, NULL);
738 tmp = silc_argument_get_arg_type(args, 5, NULL);
740 SILC_GET32_MSB(usercount, tmp);
742 /* Check whether the channel exists, and add it to cache if it doesn't. */
743 channel_entry = silc_client_get_channel_by_id(client, conn,
745 if (!channel_entry) {
746 /* Add new channel entry */
747 channel_entry = silc_client_add_channel(client, conn, name, 0,
749 if (!channel_entry) {
750 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
755 /* Notify application */
756 silc_client_command_callback(cmd, channel_entry, name, topic, usercount);
759 silc_fsm_next(fsm, silc_client_command_reply_processed);
760 return SILC_FSM_CONTINUE;
763 /********************************* TOPIC ************************************/
765 /* Received reply to topic command. */
767 SILC_FSM_STATE(silc_client_command_reply_topic)
769 SilcClientCommandContext cmd = fsm_context;
770 SilcClientConnection conn = cmd->conn;
771 SilcClient client = conn->client;
772 SilcCommandPayload payload = state_context;
773 SilcArgumentPayload args = silc_command_get_args(payload);
774 SilcChannelEntry channel;
780 CHECK_STATUS("Cannot set topic: ");
783 /* Take Channel ID */
784 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
785 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
789 /* Get the channel entry */
790 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
792 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
797 topic = silc_argument_get_arg_type(args, 3, &len);
799 silc_free(channel->topic);
800 channel->topic = silc_memdup(topic, len);
803 /* Notify application */
804 silc_client_command_callback(cmd, channel, channel->topic);
807 silc_fsm_next(fsm, silc_client_command_reply_processed);
808 return SILC_FSM_CONTINUE;
811 /********************************* INVITE ***********************************/
813 /* Received reply to invite command. */
815 SILC_FSM_STATE(silc_client_command_reply_invite)
817 SilcClientCommandContext cmd = fsm_context;
818 SilcClientConnection conn = cmd->conn;
819 SilcClient client = conn->client;
820 SilcCommandPayload payload = state_context;
821 SilcArgumentPayload args = silc_command_get_args(payload);
822 SilcChannelEntry channel;
825 SilcArgumentPayload invite_args = NULL;
829 CHECK_STATUS("Cannot invite: ");
832 /* Take Channel ID */
833 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
834 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
838 /* Get the channel entry */
839 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
841 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
845 /* Get the invite list */
846 tmp = silc_argument_get_arg_type(args, 3, &len);
848 invite_args = silc_argument_list_parse(tmp, len);
850 /* Notify application */
851 silc_client_command_callback(cmd, channel, invite_args);
854 silc_argument_payload_free(invite_args);
857 silc_fsm_next(fsm, silc_client_command_reply_processed);
858 return SILC_FSM_CONTINUE;
861 /********************************** KILL ************************************/
863 /* Received reply to the KILL command. */
865 SILC_FSM_STATE(silc_client_command_reply_kill)
867 SilcClientCommandContext cmd = fsm_context;
868 SilcClientConnection conn = cmd->conn;
869 SilcClient client = conn->client;
870 SilcCommandPayload payload = state_context;
871 SilcArgumentPayload args = silc_command_get_args(payload);
872 SilcClientEntry client_entry;
876 CHECK_STATUS("Cannot kill: ");
879 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
880 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
884 /* Get the client entry, if exists */
885 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
887 /* Notify application */
888 silc_client_command_callback(cmd, client_entry);
890 /* Remove the client from all channels and free it */
892 silc_client_del_client(client, conn, client_entry);
893 silc_client_unref_client(client, conn, client_entry);
897 silc_fsm_next(fsm, silc_client_command_reply_processed);
898 return SILC_FSM_CONTINUE;
901 /********************************** INFO ************************************/
903 /* Received reply to INFO command. We receive the server ID and some
904 information about the server user requested. */
906 SILC_FSM_STATE(silc_client_command_reply_info)
908 SilcClientCommandContext cmd = fsm_context;
909 SilcClientConnection conn = cmd->conn;
910 SilcClient client = conn->client;
911 SilcCommandPayload payload = state_context;
912 SilcArgumentPayload args = silc_command_get_args(payload);
913 SilcServerEntry server;
914 char *server_name, *server_info;
918 CHECK_STATUS("Cannot get info: ");
922 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
923 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
927 /* Get server name */
928 server_name = silc_argument_get_arg_type(args, 3, NULL);
930 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
934 /* Get server info */
935 server_info = silc_argument_get_arg_type(args, 4, NULL);
937 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
941 /* See whether we have this server cached. If not create it. */
942 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
944 SILC_LOG_DEBUG(("New server entry"));
945 server = silc_client_add_server(client, conn, server_name,
946 server_info, &id.u.server_id);
951 /* Notify application */
952 silc_client_command_callback(cmd, server, server->server_name,
953 server->server_info);
956 silc_fsm_next(fsm, silc_client_command_reply_processed);
957 return SILC_FSM_CONTINUE;
960 /********************************** STATS ***********************************/
962 /* Received reply to STATS command. */
964 SILC_FSM_STATE(silc_client_command_reply_stats)
966 SilcClientCommandContext cmd = fsm_context;
967 SilcCommandPayload payload = state_context;
968 SilcArgumentPayload args = silc_command_get_args(payload);
969 SilcClientStats stats;
970 unsigned char *buf = NULL;
971 SilcUInt32 buf_len = 0;
976 CHECK_STATUS("Cannot get stats: ");
980 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
981 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
985 /* Get statistics structure */
986 memset(&stats, 0, sizeof(stats));
987 buf = silc_argument_get_arg_type(args, 3, &buf_len);
989 silc_buffer_set(&b, buf, buf_len);
990 silc_buffer_unformat(&b,
991 SILC_STR_UI_INT(&stats.starttime),
992 SILC_STR_UI_INT(&stats.uptime),
993 SILC_STR_UI_INT(&stats.my_clients),
994 SILC_STR_UI_INT(&stats.my_channels),
995 SILC_STR_UI_INT(&stats.my_server_ops),
996 SILC_STR_UI_INT(&stats.my_router_ops),
997 SILC_STR_UI_INT(&stats.cell_clients),
998 SILC_STR_UI_INT(&stats.cell_channels),
999 SILC_STR_UI_INT(&stats.cell_servers),
1000 SILC_STR_UI_INT(&stats.clients),
1001 SILC_STR_UI_INT(&stats.channels),
1002 SILC_STR_UI_INT(&stats.servers),
1003 SILC_STR_UI_INT(&stats.routers),
1004 SILC_STR_UI_INT(&stats.server_ops),
1005 SILC_STR_UI_INT(&stats.router_ops),
1009 /* Notify application */
1010 silc_client_command_callback(cmd, &stats);
1013 silc_fsm_next(fsm, silc_client_command_reply_processed);
1014 return SILC_FSM_CONTINUE;
1017 /********************************** PING ************************************/
1019 /* Received reply to PING command. */
1021 SILC_FSM_STATE(silc_client_command_reply_ping)
1023 SilcClientCommandContext cmd = fsm_context;
1024 SilcClientConnection conn = cmd->conn;
1025 SilcClient client = conn->client;
1028 diff = silc_time() - SILC_PTR_TO_64(cmd->context);
1030 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO,
1031 "Ping reply from %s: %d second%s", conn->remote_host,
1032 (int)diff, diff == 1 ? "" : "s");
1034 /* Notify application */
1035 silc_client_command_callback(cmd);
1037 silc_fsm_next(fsm, silc_client_command_reply_processed);
1038 return SILC_FSM_CONTINUE;
1041 /********************************** JOIN ************************************/
1043 /* Continue JOIN command reply processing after resolving unknown users */
1046 silc_client_command_reply_join_resolved(SilcClient client,
1047 SilcClientConnection conn,
1052 SilcClientCommandContext cmd = context;
1053 SilcChannelEntry channel = cmd->context;
1055 channel->internal.resolve_cmd_ident = 0;
1056 silc_client_unref_channel(client, conn, channel);
1058 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1062 /* Received reply for JOIN command. */
1064 SILC_FSM_STATE(silc_client_command_reply_join)
1066 SilcClientCommandContext cmd = fsm_context;
1067 SilcClientConnection conn = cmd->conn;
1068 SilcClient client = conn->client;
1069 SilcCommandPayload payload = state_context;
1070 SilcArgumentPayload args = silc_command_get_args(payload);
1071 SilcChannelEntry channel;
1072 SilcUInt32 mode = 0, len, list_count;
1073 char *topic, *tmp, *channel_name = NULL, *hmac;
1075 SilcBufferStruct client_id_list, client_mode_list, keyp;
1076 SilcHashTableList htl;
1077 SilcDList chpks = NULL;
1082 CHECK_STATUS("Cannot join channel: ");
1085 /* Get channel name */
1086 channel_name = silc_argument_get_arg_type(args, 2, NULL);
1087 if (!channel_name) {
1088 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1092 /* Get Channel ID */
1093 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1094 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1098 /* Check whether we have this channel entry already. */
1099 channel = silc_client_get_channel(client, conn, channel_name);
1101 if (!SILC_ID_CHANNEL_COMPARE(&channel->id, &id.u.channel_id))
1102 silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id);
1104 /* Create new channel entry */
1105 channel = silc_client_add_channel(client, conn, channel_name,
1106 mode, &id.u.channel_id);
1108 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_CHANNEL);
1111 silc_client_ref_channel(client, conn, channel);
1114 /* Get the list count */
1115 tmp = silc_argument_get_arg_type(args, 12, &len);
1117 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1120 SILC_GET32_MSB(list_count, tmp);
1122 /* Get Client ID list */
1123 tmp = silc_argument_get_arg_type(args, 13, &len);
1125 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1128 silc_buffer_set(&client_id_list, tmp, len);
1130 /* Resolve users we do not know about */
1131 if (!cmd->resolved) {
1132 cmd->resolved = TRUE;
1133 cmd->context = channel;
1134 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1135 silc_client_get_clients_by_list(
1136 client, conn, list_count, &client_id_list,
1137 silc_client_command_reply_join_resolved, cmd));
1141 /* Get client mode list */
1142 tmp = silc_argument_get_arg_type(args, 14, &len);
1144 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1147 silc_buffer_set(&client_mode_list, tmp, len);
1149 /* Add clients we received in the reply to the channel */
1150 for (i = 0; i < list_count; i++) {
1154 SilcClientEntry client_entry;
1157 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1159 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1163 SILC_GET32_MSB(mode, client_mode_list.data);
1165 SILC_LOG_DEBUG(("id %s", silc_id_render(&id.u.client_id, SILC_ID_CLIENT)));
1167 /* Get client entry */
1168 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1172 /* Join client to the channel */
1173 silc_client_add_to_channel(channel, client_entry, mode);
1174 silc_client_unref_client(client, conn, client_entry);
1176 if (!silc_buffer_pull(&client_id_list, idp_len))
1178 if (!silc_buffer_pull(&client_mode_list, 4))
1183 hmac = silc_argument_get_arg_type(args, 11, NULL);
1185 if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) {
1187 SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1188 "Cannot join channel: Unsupported HMAC `%s'", hmac);
1189 ERROR_CALLBACK(SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
1194 /* Get channel mode */
1195 tmp = silc_argument_get_arg_type(args, 5, NULL);
1197 SILC_GET32_MSB(mode, tmp);
1198 channel->mode = mode;
1200 /* Get channel key and save it */
1201 tmp = silc_argument_get_arg_type(args, 7, &len);
1203 silc_buffer_set(&keyp, tmp, len);
1204 silc_client_save_channel_key(client, conn, &keyp, channel);
1208 topic = silc_argument_get_arg_type(args, 10, NULL);
1210 silc_free(channel->topic);
1211 channel->topic = silc_memdup(topic, strlen(topic));
1214 /* Get founder key */
1215 tmp = silc_argument_get_arg_type(args, 15, &len);
1217 if (channel->founder_key)
1218 silc_pkcs_public_key_free(channel->founder_key);
1219 channel->founder_key = NULL;
1220 silc_public_key_payload_decode(tmp, len, &channel->founder_key);
1223 /* Get user limit */
1224 tmp = silc_argument_get_arg_type(args, 17, &len);
1225 if (tmp && len == 4)
1226 SILC_GET32_MSB(channel->user_limit, tmp);
1227 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1228 channel->user_limit = 0;
1230 /* Get channel public key list */
1231 tmp = silc_argument_get_arg_type(args, 16, &len);
1233 chpks = silc_argument_list_parse_decoded(tmp, len,
1234 SILC_ARGUMENT_PUBLIC_KEY);
1236 /* Set current channel */
1237 conn->current_channel = channel;
1239 cipher = (channel->internal.channel_key ?
1240 silc_cipher_get_name(channel->internal.channel_key) : NULL);
1241 silc_hash_table_list(channel->user_list, &htl);
1243 /* Notify application */
1244 silc_client_command_callback(cmd, channel_name, channel, mode, &htl,
1245 topic, cipher, hmac, channel->founder_key,
1246 chpks, channel->user_limit);
1249 silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
1250 silc_hash_table_list_reset(&htl);
1251 silc_client_unref_channel(client, conn, channel);
1254 silc_fsm_next(fsm, silc_client_command_reply_processed);
1255 return SILC_FSM_CONTINUE;
1258 /********************************** MOTD ************************************/
1260 /* Received reply for MOTD command */
1262 SILC_FSM_STATE(silc_client_command_reply_motd)
1264 SilcClientCommandContext cmd = fsm_context;
1265 SilcClientConnection conn = cmd->conn;
1266 SilcClient client = conn->client;
1267 SilcCommandPayload payload = state_context;
1268 SilcArgumentPayload args = silc_command_get_args(payload);
1270 char *motd = NULL, *cp, line[256];
1273 CHECK_STATUS("Cannot get motd: ");
1276 if (silc_argument_get_arg_num(args) == 3) {
1277 motd = silc_argument_get_arg_type(args, 3, NULL);
1279 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1286 if (cp[i++] == '\n') {
1287 memset(line, 0, sizeof(line));
1288 silc_strncat(line, sizeof(line), cp, i - 1);
1295 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1304 /* Notify application */
1305 silc_client_command_callback(cmd, motd);
1308 silc_fsm_next(fsm, silc_client_command_reply_processed);
1309 return SILC_FSM_CONTINUE;
1312 /********************************** UMODE ***********************************/
1314 /* Received reply to the UMODE command. Save the current user mode */
1316 SILC_FSM_STATE(silc_client_command_reply_umode)
1318 SilcClientCommandContext cmd = fsm_context;
1319 SilcClientConnection conn = cmd->conn;
1320 SilcCommandPayload payload = state_context;
1321 SilcArgumentPayload args = silc_command_get_args(payload);
1323 SilcUInt32 mode, len;
1326 CHECK_STATUS("Cannot change mode: ");
1329 tmp = silc_argument_get_arg_type(args, 2, &len);
1330 if (!tmp || len != 4) {
1331 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1335 SILC_GET32_MSB(mode, tmp);
1336 conn->local_entry->mode = mode;
1338 /* Notify application */
1339 silc_client_command_callback(cmd, mode);
1342 silc_fsm_next(fsm, silc_client_command_reply_processed);
1343 return SILC_FSM_CONTINUE;
1346 /********************************** CMODE ***********************************/
1348 /* Received reply for CMODE command. */
1350 SILC_FSM_STATE(silc_client_command_reply_cmode)
1352 SilcClientCommandContext cmd = fsm_context;
1353 SilcClientConnection conn = cmd->conn;
1354 SilcClient client = conn->client;
1355 SilcCommandPayload payload = state_context;
1356 SilcArgumentPayload args = silc_command_get_args(payload);
1359 SilcChannelEntry channel;
1361 SilcPublicKey public_key = NULL;
1362 SilcDList channel_pubkeys = NULL;
1366 CHECK_STATUS("Cannot change mode: ");
1369 /* Take Channel ID */
1370 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1371 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1375 /* Get the channel entry */
1376 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1378 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1382 /* Get channel mode */
1383 tmp = silc_argument_get_arg_type(args, 3, &len);
1384 if (!tmp || len != 4) {
1385 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1390 SILC_GET32_MSB(mode, tmp);
1391 channel->mode = mode;
1393 /* Get founder public key */
1394 tmp = silc_argument_get_arg_type(args, 4, &len);
1396 silc_public_key_payload_decode(tmp, len, &public_key);
1398 /* Get user limit */
1399 tmp = silc_argument_get_arg_type(args, 6, &len);
1400 if (tmp && len == 4)
1401 SILC_GET32_MSB(channel->user_limit, tmp);
1402 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1403 channel->user_limit = 0;
1405 /* Get channel public key(s) */
1406 tmp = silc_argument_get_arg_type(args, 5, &len);
1409 silc_argument_list_parse_decoded(tmp, len, SILC_ARGUMENT_PUBLIC_KEY);
1411 /* Notify application */
1412 silc_client_command_callback(cmd, channel, mode, public_key,
1413 channel_pubkeys, channel->user_limit);
1415 silc_argument_list_free(channel_pubkeys, SILC_ARGUMENT_PUBLIC_KEY);
1419 silc_pkcs_public_key_free(public_key);
1420 silc_fsm_next(fsm, silc_client_command_reply_processed);
1421 return SILC_FSM_CONTINUE;
1424 /********************************** CUMODE **********************************/
1426 /* Received reply for CUMODE command */
1428 SILC_FSM_STATE(silc_client_command_reply_cumode)
1430 SilcClientCommandContext cmd = fsm_context;
1431 SilcClientConnection conn = cmd->conn;
1432 SilcClient client = conn->client;
1433 SilcCommandPayload payload = state_context;
1434 SilcArgumentPayload args = silc_command_get_args(payload);
1435 SilcClientEntry client_entry;
1436 SilcChannelEntry channel;
1437 SilcChannelUser chu;
1438 unsigned char *modev;
1439 SilcUInt32 len, mode;
1443 CHECK_STATUS("Cannot change mode: ");
1446 /* Get channel mode */
1447 modev = silc_argument_get_arg_type(args, 2, &len);
1448 if (!modev || len != 4) {
1449 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1452 SILC_GET32_MSB(mode, modev);
1454 /* Take Channel ID */
1455 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1456 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1460 /* Get the channel entry */
1461 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1463 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1468 if (!silc_argument_get_decoded(args, 4, SILC_ARGUMENT_ID, &id, NULL)) {
1469 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1473 /* Get client entry */
1474 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1475 if (!client_entry) {
1476 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1481 chu = silc_client_on_channel(channel, client_entry);
1485 /* Notify application */
1486 silc_client_command_callback(cmd, mode, channel, client_entry);
1488 silc_client_unref_client(client, conn, client_entry);
1491 silc_fsm_next(fsm, silc_client_command_reply_processed);
1492 return SILC_FSM_CONTINUE;
1495 /********************************** KICK ************************************/
1497 SILC_FSM_STATE(silc_client_command_reply_kick)
1499 SilcClientCommandContext cmd = fsm_context;
1500 SilcClientConnection conn = cmd->conn;
1501 SilcClient client = conn->client;
1502 SilcCommandPayload payload = state_context;
1503 SilcArgumentPayload args = silc_command_get_args(payload);
1504 SilcClientEntry client_entry;
1505 SilcChannelEntry channel;
1509 CHECK_STATUS("Cannot kick: ");
1512 /* Take Channel ID */
1513 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1514 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1518 /* Get the channel entry */
1519 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1521 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1526 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1527 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1531 /* Get client entry */
1532 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1533 if (!client_entry) {
1534 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1538 /* Notify application */
1539 silc_client_command_callback(cmd, channel, client_entry);
1541 silc_client_unref_client(client, conn, client_entry);
1544 silc_fsm_next(fsm, silc_client_command_reply_processed);
1545 return SILC_FSM_CONTINUE;
1548 /******************************** SILCOPER **********************************/
1550 SILC_FSM_STATE(silc_client_command_reply_silcoper)
1552 SilcClientCommandContext cmd = fsm_context;
1553 SilcCommandPayload payload = state_context;
1554 SilcArgumentPayload args = silc_command_get_args(payload);
1557 CHECK_STATUS("Cannot change mode: ");
1560 /* Notify application */
1561 silc_client_command_callback(cmd);
1563 silc_fsm_next(fsm, silc_client_command_reply_processed);
1564 return SILC_FSM_CONTINUE;
1567 /********************************** OPER ************************************/
1569 SILC_FSM_STATE(silc_client_command_reply_oper)
1571 SilcClientCommandContext cmd = fsm_context;
1572 SilcCommandPayload payload = state_context;
1573 SilcArgumentPayload args = silc_command_get_args(payload);
1576 CHECK_STATUS("Cannot change mode: ");
1579 /* Notify application */
1580 silc_client_command_callback(cmd);
1582 silc_fsm_next(fsm, silc_client_command_reply_processed);
1583 return SILC_FSM_CONTINUE;
1586 /********************************* DETACH ***********************************/
1588 SILC_FSM_STATE(silc_client_command_reply_detach)
1590 SilcClientCommandContext cmd = fsm_context;
1591 SilcClientConnection conn = cmd->conn;
1592 SilcClient client = conn->client;
1593 SilcCommandPayload payload = state_context;
1594 SilcArgumentPayload args = silc_command_get_args(payload);
1598 CHECK_STATUS("Cannot detach: ");
1601 /* Notify application */
1602 silc_client_command_callback(cmd);
1605 /* Generate the detachment data and deliver it to the client in the
1606 detach client operation */
1607 detach = silc_client_get_detach_data(client, conn);
1609 client->internal->ops->detach(client, conn, silc_buffer_data(detach),
1610 silc_buffer_len(detach));
1611 silc_buffer_free(detach);
1615 silc_fsm_next(fsm, silc_client_command_reply_processed);
1616 return SILC_FSM_CONTINUE;
1619 /********************************** WATCH ***********************************/
1621 SILC_FSM_STATE(silc_client_command_reply_watch)
1623 SilcClientCommandContext cmd = fsm_context;
1624 SilcCommandPayload payload = state_context;
1625 SilcArgumentPayload args = silc_command_get_args(payload);
1628 CHECK_STATUS("Cannot set watch: ");
1631 /* Notify application */
1632 silc_client_command_callback(cmd);
1634 silc_fsm_next(fsm, silc_client_command_reply_processed);
1635 return SILC_FSM_CONTINUE;
1638 /*********************************** BAN ************************************/
1640 SILC_FSM_STATE(silc_client_command_reply_ban)
1642 SilcClientCommandContext cmd = fsm_context;
1643 SilcClientConnection conn = cmd->conn;
1644 SilcClient client = conn->client;
1645 SilcCommandPayload payload = state_context;
1646 SilcArgumentPayload args = silc_command_get_args(payload);
1647 SilcChannelEntry channel;
1650 SilcArgumentPayload invite_args = NULL;
1654 CHECK_STATUS("Cannot set ban: ");
1657 /* Take Channel ID */
1658 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1659 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1663 /* Get the channel entry */
1664 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1666 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1670 /* Get the invite list */
1671 tmp = silc_argument_get_arg_type(args, 3, &len);
1673 invite_args = silc_argument_list_parse(tmp, len);
1675 /* Notify application */
1676 silc_client_command_callback(cmd, channel, invite_args);
1679 silc_argument_payload_free(invite_args);
1682 silc_fsm_next(fsm, silc_client_command_reply_processed);
1683 return SILC_FSM_CONTINUE;
1686 /********************************** LEAVE ***********************************/
1688 /* Reply to LEAVE command. */
1690 SILC_FSM_STATE(silc_client_command_reply_leave)
1692 SilcClientCommandContext cmd = fsm_context;
1693 SilcClientConnection conn = cmd->conn;
1694 SilcClient client = conn->client;
1695 SilcCommandPayload payload = state_context;
1696 SilcArgumentPayload args = silc_command_get_args(payload);
1697 SilcChannelEntry channel;
1701 CHECK_STATUS("Cannot set leave: ");
1704 /* Get Channel ID */
1705 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1706 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1710 /* Get the channel entry */
1711 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1713 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1717 /* Remove us from this channel. */
1718 silc_client_remove_from_channel(channel, conn->local_entry);
1720 /* Notify application */
1721 silc_client_command_callback(cmd, channel);
1723 /* Now delete the channel. */
1724 silc_client_del_channel(client, conn, channel);
1727 silc_fsm_next(fsm, silc_client_command_reply_processed);
1728 return SILC_FSM_CONTINUE;
1731 /********************************* USERS ************************************/
1733 /* Continue USERS command reply processing after resolving unknown users */
1736 silc_client_command_reply_users_resolved(SilcClient client,
1737 SilcClientConnection conn,
1742 SilcClientCommandContext cmd = context;
1743 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1747 /* Continue USERS command after resolving unknown channel */
1750 silc_client_command_reply_users_continue(SilcClient client,
1751 SilcClientConnection conn,
1756 SilcClientCommandContext cmd = context;
1759 SilcCommandPayload payload = silc_fsm_get_state_context(&cmd->thread);
1760 SilcArgumentPayload args = silc_command_get_args(payload);
1762 cmd->status = SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID;
1763 ERROR_CALLBACK(cmd->status);
1764 silc_fsm_next(&cmd->thread, silc_client_command_reply_processed);
1767 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1770 /* Reply to USERS command. Received list of client ID's and theirs modes
1771 on the channel we requested. */
1773 SILC_FSM_STATE(silc_client_command_reply_users)
1775 SilcClientCommandContext cmd = fsm_context;
1776 SilcClientConnection conn = cmd->conn;
1777 SilcClient client = conn->client;
1778 SilcCommandPayload payload = state_context;
1779 SilcArgumentPayload args = silc_command_get_args(payload);
1781 SilcUInt32 tmp_len, list_count;
1782 SilcUInt16 idp_len, mode;
1783 SilcHashTableList htl;
1784 SilcBufferStruct client_id_list, client_mode_list;
1785 SilcChannelEntry channel;
1786 SilcClientEntry client_entry;
1791 CHECK_STATUS("Cannot get users: ");
1794 /* Get channel ID */
1795 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1796 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1800 /* Get channel entry */
1801 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1803 /* Resolve the channel from server */
1804 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1805 client, conn, &id.u.channel_id,
1806 silc_client_command_reply_users_continue, cmd));
1810 /* Get the list count */
1811 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1812 if (!tmp || tmp_len != 4) {
1813 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1816 SILC_GET32_MSB(list_count, tmp);
1818 /* Get Client ID list */
1819 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1821 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1824 silc_buffer_set(&client_id_list, tmp, tmp_len);
1826 /* Resolve users we do not know about */
1827 if (!cmd->resolved) {
1828 cmd->resolved = TRUE;
1829 SILC_FSM_CALL(silc_client_get_clients_by_list(
1830 client, conn, list_count, &client_id_list,
1831 silc_client_command_reply_users_resolved, cmd));
1835 /* Get client mode list */
1836 tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
1838 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1841 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1843 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1845 /* Cache the received Client ID's and modes. */
1846 for (i = 0; i < list_count; i++) {
1847 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1849 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1853 SILC_GET32_MSB(mode, client_mode_list.data);
1855 /* Save the client on this channel. Unknown clients are ignored as they
1856 clearly do not exist since the resolving didn't find them. */
1857 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1859 silc_client_add_to_channel(channel, client_entry, mode);
1860 silc_client_unref_client(client, conn, client_entry);
1862 if (!silc_buffer_pull(&client_id_list, idp_len))
1864 if (!silc_buffer_pull(&client_mode_list, 4))
1868 /* Notify application */
1869 silc_hash_table_list(channel->user_list, &htl);
1870 silc_client_command_callback(cmd, channel, &htl);
1871 silc_hash_table_list_reset(&htl);
1874 silc_fsm_next(fsm, silc_client_command_reply_processed);
1875 return SILC_FSM_CONTINUE;
1878 /********************************** GETKEY **********************************/
1880 /* Received command reply to GETKEY command. WE've received the remote
1881 client's public key. */
1883 SILC_FSM_STATE(silc_client_command_reply_getkey)
1885 SilcClientCommandContext cmd = fsm_context;
1886 SilcClientConnection conn = cmd->conn;
1887 SilcClient client = conn->client;
1888 SilcCommandPayload payload = state_context;
1889 SilcArgumentPayload args = silc_command_get_args(payload);
1890 SilcClientEntry client_entry;
1891 SilcServerEntry server_entry;
1894 SilcPublicKey public_key;
1898 CHECK_STATUS("Cannot get key: ");
1902 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1903 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1907 /* Get the public key */
1908 tmp = silc_argument_get_arg_type(args, 3, &len);
1910 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1913 if (!silc_public_key_payload_decode(tmp, len, &public_key)) {
1914 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1918 if (id.type == SILC_ID_CLIENT) {
1919 /* Received client's public key */
1920 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1921 if (!client_entry) {
1922 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1926 /* Save fingerprint */
1927 if (!client_entry->fingerprint)
1928 silc_hash_make(conn->internal->sha1hash, tmp + 4, len - 4,
1929 client_entry->fingerprint);
1930 if (!client_entry->public_key) {
1931 client_entry->public_key = public_key;
1935 /* Notify application */
1936 silc_client_command_callback(cmd, SILC_ID_CLIENT, client_entry,
1937 client_entry->public_key);
1938 silc_client_unref_client(client, conn, client_entry);
1939 } else if (id.type == SILC_ID_SERVER) {
1940 /* Received server's public key */
1941 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1942 if (!server_entry) {
1943 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1947 if (!server_entry->public_key) {
1948 server_entry->public_key = public_key;
1952 /* Notify application */
1953 silc_client_command_callback(cmd, SILC_ID_SERVER, server_entry,
1954 server_entry->public_key);
1959 silc_pkcs_public_key_free(public_key);
1960 silc_fsm_next(fsm, silc_client_command_reply_processed);
1961 return SILC_FSM_CONTINUE;
1964 /********************************** SERVICE *********************************/
1966 /* Reply to SERVICE command. */
1967 /* XXX incomplete */
1969 SILC_FSM_STATE(silc_client_command_reply_service)
1971 SilcClientCommandContext cmd = fsm_context;
1972 SilcCommandPayload payload = state_context;
1973 SilcArgumentPayload args = silc_command_get_args(payload);
1975 unsigned char *service_list, *name;
1978 CHECK_STATUS("Cannot get service: ");
1980 /* Get service list */
1981 service_list = silc_argument_get_arg_type(args, 2, &tmp_len);
1983 /* Get requested service name */
1984 name = silc_argument_get_arg_type(args, 3, &tmp_len);
1986 /* Notify application */
1987 silc_client_command_callback(cmd, service_list, name);
1989 silc_fsm_next(fsm, silc_client_command_reply_processed);
1990 return SILC_FSM_CONTINUE;
1993 /*********************************** QUIT ***********************************/
1995 /* QUIT command reply stub */
1997 SILC_FSM_STATE(silc_client_command_reply_quit)
1999 silc_fsm_next(fsm, silc_client_command_reply_processed);
2000 return SILC_FSM_CONTINUE;