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_client_command_callback(cmd, arg1, arg2); \
39 #define CHECK_STATUS(msg) \
40 SILC_LOG_DEBUG(("Start")); \
41 if (cmd->error != SILC_STATUS_OK) { \
43 SAY(cmd->conn->client, cmd->conn, SILC_CLIENT_MESSAGE_ERROR, \
44 msg "%s", silc_get_status_message(cmd->error)); \
45 ERROR_CALLBACK(cmd->error); \
46 silc_client_command_process_error(cmd, state_context, cmd->error); \
47 silc_fsm_next(fsm, silc_client_command_reply_process); \
48 return SILC_FSM_YIELD; \
51 /* Check for correct arguments */
52 #define CHECK_ARGS(min, max) \
53 if (silc_argument_get_arg_num(args) < min || \
54 silc_argument_get_arg_num(args) > max) { \
55 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); \
56 silc_fsm_next(fsm, silc_client_command_reply_process); \
57 return SILC_FSM_YIELD; \
60 #define SAY cmd->conn->client->internal->ops->say
62 /************************ Static utility functions **************************/
64 /* Delivers the command reply back to application */
67 silc_client_command_callback(SilcClientCommandContext cmd, ...)
69 SilcClientCommandReplyCallback cb;
74 /* Default reply callback */
77 cmd->conn->client->internal->ops->command_reply(
78 cmd->conn->client, cmd->conn, cmd->cmd, cmd->status,
84 silc_list_start(cmd->reply_callbacks);
85 while ((cb = silc_list_get(cmd->reply_callbacks)))
86 if (!cb->do_not_call) {
88 cb->do_not_call = cb->reply(cmd->conn->client, cmd->conn, cmd->cmd,
89 cmd->status, cmd->error, cb->context, cp);
96 /* Handles common error status types. */
98 static void silc_client_command_process_error(SilcClientCommandContext cmd,
99 SilcCommandPayload payload,
102 SilcClient client = cmd->conn->client;
103 SilcClientConnection conn = cmd->conn;
104 SilcArgumentPayload args = silc_command_get_args(payload);
105 SilcClientEntry client_entry;
108 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
109 /* Remove unknown client entry from cache */
110 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
113 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
115 silc_client_del_client(client, conn, client_entry);
119 /***************************** Command Reply ********************************/
121 /* Process received command reply packet */
123 SILC_FSM_STATE(silc_client_command_reply)
125 SilcClientConnection conn = fsm_context;
126 SilcPacket packet = state_context;
127 SilcClientCommandContext cmd;
128 SilcCommandPayload payload;
130 SilcUInt16 cmd_ident;
132 /* Get command reply payload from packet */
133 payload = silc_command_payload_parse(silc_buffer_datalen(&packet->buffer));
134 silc_packet_free(packet);
136 /** Bad reply payload */
137 SILC_LOG_DEBUG(("Bad command reply packet"));
138 silc_fsm_next(fsm, silc_client_connection_st_packet);
139 return SILC_FSM_CONTINUE;
142 cmd_ident = silc_command_get_ident(payload);
143 command = silc_command_get(payload);
145 /* Find the command pending reply */
146 silc_mutex_lock(conn->internal->lock);
147 silc_list_start(conn->internal->pending_commands);
148 while ((cmd = silc_list_get(conn->internal->pending_commands)))
149 if (cmd->cmd == command && cmd->cmd_ident == cmd_ident)
151 silc_mutex_unlock(conn->internal->lock);
154 /** Unknown command reply */
155 SILC_LOG_DEBUG(("Unknown command reply"));
156 silc_command_payload_free(payload);
157 silc_fsm_next(fsm, silc_client_connection_st_packet);
158 return SILC_FSM_CONTINUE;
161 /* Signal command thread that command reply has arrived */
162 silc_fsm_set_state_context(&cmd->thread, payload);
163 silc_fsm_next(&cmd->thread, silc_client_command_reply_process);
164 silc_fsm_continue_sync(&cmd->thread);
166 /** Packet processed */
167 silc_fsm_next(fsm, silc_client_connection_st_packet);
168 return SILC_FSM_CONTINUE;
171 /* Wait here for command reply to arrive from remote host */
173 SILC_FSM_STATE(silc_client_command_reply_wait)
175 SilcClientCommandContext cmd = fsm_context;
177 SILC_LOG_DEBUG(("Wait for command reply"));
179 /** Wait for command reply */
180 cmd->processed = FALSE;
181 silc_fsm_set_state_context(fsm, NULL);
182 silc_fsm_next_later(fsm, silc_client_command_reply_process, 20, 0);
183 return SILC_FSM_WAIT;
186 /* Process received command reply payload */
188 SILC_FSM_STATE(silc_client_command_reply_process)
190 SilcClientCommandContext cmd = fsm_context;
191 SilcCommandPayload payload = state_context;
194 /* Timeout, reply not received in timely fashion */
195 SilcArgumentPayload args = NULL;
196 ERROR_CALLBACK(SILC_STATUS_ERR_TIMEDOUT);
197 return SILC_FSM_FINISH;
200 if (cmd->processed) {
201 /* Command reply processed */
202 silc_command_payload_free(payload);
204 if (cmd->status == SILC_STATUS_OK || cmd->status == SILC_STATUS_LIST_END ||
205 SILC_STATUS_IS_ERROR(cmd->status))
206 return SILC_FSM_FINISH;
208 /** Wait more command payloads */
209 silc_fsm_next(fsm, silc_client_command_reply_wait);
210 return SILC_FSM_CONTINUE;
213 silc_command_get_status(payload, &cmd->status, &cmd->error);
214 silc_fsm_set_state_context(fsm, payload);
215 cmd->processed = TRUE;
218 case SILC_COMMAND_WHOIS:
220 silc_fsm_next(fsm, silc_client_command_reply_whois);
222 case SILC_COMMAND_WHOWAS:
224 silc_fsm_next(fsm, silc_client_command_reply_whowas);
226 case SILC_COMMAND_IDENTIFY:
228 silc_fsm_next(fsm, silc_client_command_reply_identify);
230 case SILC_COMMAND_NICK:
232 silc_fsm_next(fsm, silc_client_command_reply_nick);
234 case SILC_COMMAND_LIST:
236 silc_fsm_next(fsm, silc_client_command_reply_list);
238 case SILC_COMMAND_TOPIC:
240 silc_fsm_next(fsm, silc_client_command_reply_topic);
242 case SILC_COMMAND_INVITE:
244 silc_fsm_next(fsm, silc_client_command_reply_invite);
246 case SILC_COMMAND_QUIT:
248 silc_fsm_next(fsm, silc_client_command_reply_quit);
250 case SILC_COMMAND_KILL:
252 silc_fsm_next(fsm, silc_client_command_reply_kill);
254 case SILC_COMMAND_INFO:
256 silc_fsm_next(fsm, silc_client_command_reply_info);
258 case SILC_COMMAND_STATS:
260 silc_fsm_next(fsm, silc_client_command_reply_stats);
262 case SILC_COMMAND_PING:
264 silc_fsm_next(fsm, silc_client_command_reply_ping);
266 case SILC_COMMAND_OPER:
268 silc_fsm_next(fsm, silc_client_command_reply_oper);
270 case SILC_COMMAND_JOIN:
272 silc_fsm_next(fsm, silc_client_command_reply_join);
274 case SILC_COMMAND_MOTD:
276 silc_fsm_next(fsm, silc_client_command_reply_motd);
278 case SILC_COMMAND_UMODE:
280 silc_fsm_next(fsm, silc_client_command_reply_umode);
282 case SILC_COMMAND_CMODE:
284 silc_fsm_next(fsm, silc_client_command_reply_cmode);
286 case SILC_COMMAND_CUMODE:
288 silc_fsm_next(fsm, silc_client_command_reply_cumode);
290 case SILC_COMMAND_KICK:
292 silc_fsm_next(fsm, silc_client_command_reply_kick);
294 case SILC_COMMAND_BAN:
296 silc_fsm_next(fsm, silc_client_command_reply_ban);
298 case SILC_COMMAND_DETACH:
300 silc_fsm_next(fsm, silc_client_command_reply_detach);
302 case SILC_COMMAND_WATCH:
304 silc_fsm_next(fsm, silc_client_command_reply_watch);
306 case SILC_COMMAND_SILCOPER:
308 silc_fsm_next(fsm, silc_client_command_reply_silcoper);
310 case SILC_COMMAND_LEAVE:
312 silc_fsm_next(fsm, silc_client_command_reply_leave);
314 case SILC_COMMAND_USERS:
316 silc_fsm_next(fsm, silc_client_command_reply_users);
318 case SILC_COMMAND_GETKEY:
320 silc_fsm_next(fsm, silc_client_command_reply_getkey);
322 case SILC_COMMAND_SERVICE:
324 silc_fsm_next(fsm, silc_client_command_reply_service);
327 return SILC_FSM_FINISH;
330 return SILC_FSM_CONTINUE;
333 /******************************** WHOIS *************************************/
335 /* Received reply for WHOIS command. */
337 SILC_FSM_STATE(silc_client_command_reply_whois)
339 SilcClientCommandContext cmd = fsm_context;
340 SilcClientConnection conn = cmd->conn;
341 SilcClient client = conn->client;
342 SilcCommandPayload payload = state_context;
343 SilcArgumentPayload args = silc_command_get_args(payload);
344 SilcClientEntry client_entry = NULL;
345 SilcUInt32 idle = 0, mode = 0, fingerprint_len, len, *umodes = NULL;
346 SilcBufferStruct channels, ch_user_modes;
347 SilcBool has_channels = FALSE;
348 SilcDList channel_list = NULL;
350 char *nickname = NULL, *username = NULL, *realname = NULL;
351 unsigned char *fingerprint, *tmp;
353 CHECK_STATUS("WHOIS: ");
357 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
358 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
363 nickname = silc_argument_get_arg_type(args, 3, NULL);
364 username = silc_argument_get_arg_type(args, 4, NULL);
365 realname = silc_argument_get_arg_type(args, 5, NULL);
366 if (!nickname || !username || !realname) {
367 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
371 /* Get joined channel list */
372 memset(&channels, 0, sizeof(channels));
373 tmp = silc_argument_get_arg_type(args, 6, &len);
376 silc_buffer_set(&channels, tmp, len);
378 /* Get channel user mode list */
379 tmp = silc_argument_get_arg_type(args, 10, &len);
381 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
384 silc_buffer_set(&ch_user_modes, tmp, len);
388 tmp = silc_argument_get_arg_type(args, 7, &len);
390 SILC_GET32_MSB(mode, tmp);
393 tmp = silc_argument_get_arg_type(args, 8, &len);
395 SILC_GET32_MSB(idle, tmp);
397 /* Get fingerprint */
398 fingerprint = silc_argument_get_arg_type(args, 9, &fingerprint_len);
400 /* Check if we have this client cached already. */
401 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
403 SILC_LOG_DEBUG(("Adding new client entry (WHOIS)"));
405 silc_client_add_client(client, conn, nickname, username, realname,
406 &id.u.client_id, mode);
408 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
412 silc_client_update_client(client, conn, client_entry,
413 nickname, username, realname, mode);
416 if (fingerprint && fingerprint_len == sizeof(client_entry->fingerprint))
417 memcpy(client_entry->fingerprint, fingerprint, fingerprint_len);
419 /* Get user attributes */
420 tmp = silc_argument_get_arg_type(args, 11, &len);
422 if (client_entry->attrs)
423 silc_attribute_payload_list_free(client_entry->attrs);
424 client_entry->attrs = silc_attribute_payload_parse(tmp, len);
427 /* Parse channel and channel user mode list */
429 channel_list = silc_channel_payload_parse_list(silc_buffer_data(&channels),
430 silc_buffer_len(&channels));
432 silc_get_mode_list(&ch_user_modes, silc_dlist_count(channel_list),
436 /* Notify application */
437 silc_client_command_callback(cmd, client_entry, nickname, username,
438 realname, channel_list, mode, idle, fingerprint,
439 umodes, client_entry->attrs);
442 silc_dlist_uninit(channel_list);
447 silc_fsm_next(fsm, silc_client_command_reply_process);
448 return SILC_FSM_CONTINUE;
451 /******************************** WHOWAS ************************************/
453 /* Received reply for WHOWAS command. */
455 SILC_FSM_STATE(silc_client_command_reply_whowas)
457 SilcClientCommandContext cmd = fsm_context;
458 SilcClientConnection conn = cmd->conn;
459 SilcClient client = conn->client;
460 SilcCommandPayload payload = state_context;
461 SilcArgumentPayload args = silc_command_get_args(payload);
462 SilcClientEntry client_entry;
464 char *nickname, *username;
465 char *realname = NULL;
467 CHECK_STATUS("WHOWAS: ");
471 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
472 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
476 /* Get the client entry */
477 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
480 nickname = silc_argument_get_arg_type(args, 3, NULL);
481 username = silc_argument_get_arg_type(args, 4, NULL);
482 realname = silc_argument_get_arg_type(args, 5, NULL);
483 if (!nickname || !username) {
484 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
488 /* Notify application. We don't save any history information to any
489 cache. Just pass the data to the application. */
490 silc_client_command_callback(cmd, client_entry, nickname, username,
494 silc_fsm_next(fsm, silc_client_command_reply_process);
495 return SILC_FSM_CONTINUE;
498 /******************************** IDENTIFY **********************************/
500 /* Received reply for IDENTIFY command. */
502 SILC_FSM_STATE(silc_client_command_reply_identify)
504 SilcClientCommandContext cmd = fsm_context;
505 SilcClientConnection conn = cmd->conn;
506 SilcClient client = conn->client;
507 SilcCommandPayload payload = state_context;
508 SilcArgumentPayload args = silc_command_get_args(payload);
509 SilcClientEntry client_entry;
510 SilcServerEntry server_entry;
511 SilcChannelEntry channel_entry;
514 char *name = NULL, *info = NULL;
516 CHECK_STATUS("IDENTIFY: ");
520 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
521 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
526 name = silc_argument_get_arg_type(args, 3, &len);
527 info = silc_argument_get_arg_type(args, 4, &len);
531 SILC_LOG_DEBUG(("Received client information"));
533 /* Check if we have this client cached already. */
534 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
536 SILC_LOG_DEBUG(("Adding new client entry (IDENTIFY)"));
538 silc_client_add_client(client, conn, name, info, NULL,
541 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
545 silc_client_update_client(client, conn, client_entry,
546 name, info, NULL, 0);
549 /* Notify application */
550 silc_client_command_callback(cmd, client_entry, name, info);
554 SILC_LOG_DEBUG(("Received server information"));
556 /* Check if we have this server cached already. */
557 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
559 SILC_LOG_DEBUG(("Adding new server entry (IDENTIFY)"));
560 server_entry = silc_client_add_server(client, conn, name, info,
563 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
567 silc_client_update_server(client, conn, server_entry, name, info);
569 server_entry->resolve_cmd_ident = 0;
571 /* Notify application */
572 silc_client_command_callback(cmd, server_entry, name, info);
575 case SILC_ID_CHANNEL:
576 SILC_LOG_DEBUG(("Received channel information"));
578 /* Check if we have this channel cached already. */
579 channel_entry = silc_client_get_channel_by_id(client, conn,
581 if (!channel_entry) {
582 SILC_LOG_DEBUG(("Adding new channel entry (IDENTIFY"));
585 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
589 /* Add new channel entry */
590 channel_entry = silc_client_add_channel(client, conn, name, 0,
592 if (!channel_entry) {
593 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
598 /* Notify application */
599 silc_client_command_callback(cmd, channel_entry, name, info);
604 silc_fsm_next(fsm, silc_client_command_reply_process);
605 return SILC_FSM_CONTINUE;
608 /********************************** NICK ************************************/
610 /* Received reply for command NICK. */
612 SILC_FSM_STATE(silc_client_command_reply_nick)
614 SilcClientCommandContext cmd = fsm_context;
615 SilcClientConnection conn = cmd->conn;
616 SilcClient client = conn->client;
617 SilcCommandPayload payload = state_context;
618 SilcArgumentPayload args = silc_command_get_args(payload);
619 unsigned char *tmp, *nick, *idp;
620 SilcUInt32 len, idp_len;
621 SilcClientID old_client_id;
625 CHECK_STATUS("Cannot set nickname: ");
628 old_client_id = *conn->local_id;
630 /* Take received Client ID */
631 idp = silc_argument_get_arg_type(args, 2, &idp_len);
633 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
636 if (!silc_id_payload_parse_id(idp, idp_len, &id)) {
637 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
641 /* Take the new nickname */
642 nick = silc_argument_get_arg_type(args, 3, &len);
644 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
648 /* Normalize nickname */
649 tmp = silc_identifier_check(nick, len, SILC_STRING_UTF8, 128, NULL);
651 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_NICKNAME);
655 /* Update the client entry */
656 if (!silc_idcache_update(conn->internal->client_cache,
657 conn->internal->local_entry,
658 &conn->local_entry->id,
660 conn->local_entry->nickname_normalized,
663 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_NICKNAME);
666 memcpy(conn->local_entry->nickname, nick, strlen(nick));
667 conn->local_entry->nickname_normalized = tmp;
668 silc_buffer_enlarge(conn->local_idp, idp_len);
669 silc_buffer_put(conn->local_idp, idp, idp_len);
670 silc_client_nickname_format(client, conn, conn->local_entry);
672 /* Notify application */
673 silc_client_command_callback(cmd, conn->local_entry,
674 conn->local_entry->nickname, &old_client_id);
677 silc_fsm_next(fsm, silc_client_command_reply_process);
678 return SILC_FSM_CONTINUE;
681 /********************************** LIST ************************************/
683 /* Received reply to the LIST command. */
685 SILC_FSM_STATE(silc_client_command_reply_list)
687 SilcClientCommandContext cmd = fsm_context;
688 SilcClientConnection conn = cmd->conn;
689 SilcClient client = conn->client;
690 SilcCommandPayload payload = state_context;
691 SilcArgumentPayload args = silc_command_get_args(payload);
692 unsigned char *tmp, *name, *topic;
693 SilcUInt32 usercount = 0;
694 SilcChannelEntry channel_entry;
698 CHECK_STATUS("Cannot list channels: ");
700 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
701 /* There were no channels in the network. */
702 silc_client_command_callback(cmd, NULL, NULL, NULL, 0);
703 silc_fsm_next(fsm, silc_client_command_reply_process);
704 return SILC_FSM_CONTINUE;
709 name = silc_argument_get_arg_type(args, 3, NULL);
711 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
715 topic = silc_argument_get_arg_type(args, 4, NULL);
716 tmp = silc_argument_get_arg_type(args, 5, NULL);
718 SILC_GET32_MSB(usercount, tmp);
720 /* Check whether the channel exists, and add it to cache if it doesn't. */
721 channel_entry = silc_client_get_channel_by_id(client, conn,
723 if (!channel_entry) {
724 /* Add new channel entry */
725 channel_entry = silc_client_add_channel(client, conn, name, 0,
727 if (!channel_entry) {
728 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
733 /* Notify application */
734 silc_client_command_callback(cmd, channel_entry, name, topic, usercount);
737 silc_fsm_next(fsm, silc_client_command_reply_process);
738 return SILC_FSM_CONTINUE;
741 /********************************* TOPIC ************************************/
743 /* Received reply to topic command. */
745 SILC_FSM_STATE(silc_client_command_reply_topic)
747 SilcClientCommandContext cmd = fsm_context;
748 SilcClientConnection conn = cmd->conn;
749 SilcClient client = conn->client;
750 SilcCommandPayload payload = state_context;
751 SilcArgumentPayload args = silc_command_get_args(payload);
752 SilcChannelEntry channel;
758 CHECK_STATUS("Cannot set topic: ");
761 /* Take Channel ID */
762 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
763 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
767 /* Get the channel entry */
768 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
770 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
775 topic = silc_argument_get_arg_type(args, 3, &len);
777 silc_free(channel->topic);
778 channel->topic = silc_memdup(topic, len);
781 /* Notify application */
782 silc_client_command_callback(cmd, channel, channel->topic);
785 silc_fsm_next(fsm, silc_client_command_reply_process);
786 return SILC_FSM_CONTINUE;
789 /********************************* INVITE ***********************************/
791 /* Received reply to invite command. */
793 SILC_FSM_STATE(silc_client_command_reply_invite)
795 SilcClientCommandContext cmd = fsm_context;
796 SilcClientConnection conn = cmd->conn;
797 SilcClient client = conn->client;
798 SilcCommandPayload payload = state_context;
799 SilcArgumentPayload args = silc_command_get_args(payload);
800 SilcChannelEntry channel;
803 SilcBufferStruct buf;
807 CHECK_STATUS("Cannot invite: ");
810 /* Take Channel ID */
811 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
812 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
816 /* Get the channel entry */
817 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
819 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
823 /* Get the invite list */
824 tmp = silc_argument_get_arg_type(args, 3, &len);
826 silc_buffer_set(&buf, tmp, len);
828 /* Notify application */
829 silc_client_command_callback(cmd, channel, tmp ? &buf : NULL);
832 silc_fsm_next(fsm, silc_client_command_reply_process);
833 return SILC_FSM_CONTINUE;
836 /********************************** KILL ************************************/
838 /* Received reply to the KILL command. */
840 SILC_FSM_STATE(silc_client_command_reply_kill)
842 SilcClientCommandContext cmd = fsm_context;
843 SilcClientConnection conn = cmd->conn;
844 SilcClient client = conn->client;
845 SilcCommandPayload payload = state_context;
846 SilcArgumentPayload args = silc_command_get_args(payload);
847 SilcClientEntry client_entry;
851 CHECK_STATUS("Cannot kill: ");
854 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
855 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
859 /* Get the client entry, if exists */
860 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
862 /* Notify application */
863 silc_client_command_callback(cmd, client_entry);
865 /* Remove the client from all channels and free it */
867 silc_client_del_client(client, conn, client_entry);
870 silc_fsm_next(fsm, silc_client_command_reply_process);
871 return SILC_FSM_CONTINUE;
874 /********************************** INFO ************************************/
876 /* Received reply to INFO command. We receive the server ID and some
877 information about the server user requested. */
879 SILC_FSM_STATE(silc_client_command_reply_info)
881 SilcClientCommandContext cmd = fsm_context;
882 SilcClientConnection conn = cmd->conn;
883 SilcClient client = conn->client;
884 SilcCommandPayload payload = state_context;
885 SilcArgumentPayload args = silc_command_get_args(payload);
886 SilcServerEntry server;
887 char *server_name, *server_info;
891 CHECK_STATUS("Cannot get info: ");
895 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
896 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
900 /* Get server name */
901 server_name = silc_argument_get_arg_type(args, 3, NULL);
903 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
907 /* Get server info */
908 server_info = silc_argument_get_arg_type(args, 4, NULL);
910 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
914 /* See whether we have this server cached. If not create it. */
915 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
917 SILC_LOG_DEBUG(("New server entry"));
918 server = silc_client_add_server(client, conn, server_name,
919 server_info, &id.u.server_id);
924 /* Notify application */
925 silc_client_command_callback(cmd, server, server->server_name,
926 server->server_info);
929 silc_fsm_next(fsm, silc_client_command_reply_process);
930 return SILC_FSM_CONTINUE;
933 /********************************** STATS ***********************************/
935 /* Received reply to STATS command. */
937 SILC_FSM_STATE(silc_client_command_reply_stats)
939 SilcClientCommandContext cmd = fsm_context;
940 SilcCommandPayload payload = state_context;
941 SilcArgumentPayload args = silc_command_get_args(payload);
942 SilcClientStats stats;
943 unsigned char *buf = NULL;
944 SilcUInt32 buf_len = 0;
949 CHECK_STATUS("Cannot get stats: ");
953 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
954 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
958 /* Get statistics structure */
959 memset(&stats, 0, sizeof(stats));
960 buf = silc_argument_get_arg_type(args, 3, &buf_len);
962 silc_buffer_set(&b, buf, buf_len);
963 silc_buffer_unformat(&b,
964 SILC_STR_UI_INT(&stats.starttime),
965 SILC_STR_UI_INT(&stats.uptime),
966 SILC_STR_UI_INT(&stats.my_clients),
967 SILC_STR_UI_INT(&stats.my_channels),
968 SILC_STR_UI_INT(&stats.my_server_ops),
969 SILC_STR_UI_INT(&stats.my_router_ops),
970 SILC_STR_UI_INT(&stats.cell_clients),
971 SILC_STR_UI_INT(&stats.cell_channels),
972 SILC_STR_UI_INT(&stats.cell_servers),
973 SILC_STR_UI_INT(&stats.clients),
974 SILC_STR_UI_INT(&stats.channels),
975 SILC_STR_UI_INT(&stats.servers),
976 SILC_STR_UI_INT(&stats.routers),
977 SILC_STR_UI_INT(&stats.server_ops),
978 SILC_STR_UI_INT(&stats.router_ops),
982 /* Notify application */
983 silc_client_command_callback(cmd, &stats);
986 silc_fsm_next(fsm, silc_client_command_reply_process);
987 return SILC_FSM_CONTINUE;
990 /********************************** PING ************************************/
992 /* Received reply to PING command. */
994 SILC_FSM_STATE(silc_client_command_reply_ping)
996 SilcClientCommandContext cmd = fsm_context;
997 SilcClientConnection conn = cmd->conn;
998 SilcClient client = conn->client;
1001 diff = silc_time() - SILC_PTR_TO_64(cmd->context);
1002 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO,
1003 "Ping reply from %s: %d second%s", conn->remote_host,
1004 (int)diff, diff == 1 ? "" : "s");
1006 /* Notify application */
1007 silc_client_command_callback(cmd);
1009 silc_fsm_next(fsm, silc_client_command_reply_process);
1010 return SILC_FSM_CONTINUE;
1013 /********************************** JOIN ************************************/
1015 /* Received reply for JOIN command. */
1017 SILC_FSM_STATE(silc_client_command_reply_join)
1019 SilcClientCommandContext cmd = fsm_context;
1020 SilcClientConnection conn = cmd->conn;
1021 SilcClient client = conn->client;
1022 SilcCommandPayload payload = state_context;
1023 SilcArgumentPayload args = silc_command_get_args(payload);
1024 SilcChannelEntry channel;
1025 SilcChannelUser chu;
1026 SilcUInt32 mode = 0, len, list_count;
1027 char *topic, *tmp, *channel_name = NULL, *hmac;
1028 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
1029 SilcBufferStruct chpklist;
1034 CHECK_STATUS("Cannot join channel: ");
1037 /* Get channel name */
1038 channel_name = silc_argument_get_arg_type(args, 2, NULL);
1039 if (!channel_name) {
1040 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1044 /* Get Channel ID */
1045 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1046 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1050 /* Get channel mode */
1051 tmp = silc_argument_get_arg_type(args, 5, NULL);
1053 SILC_GET32_MSB(mode, tmp);
1055 /* Get channel key */
1056 tmp = silc_argument_get_arg_type(args, 7, &len);
1058 keyp = silc_buffer_alloc_size(len);
1060 silc_buffer_put(keyp, tmp, len);
1064 topic = silc_argument_get_arg_type(args, 10, NULL);
1066 /* Check whether we have this channel entry already. */
1067 channel = silc_client_get_channel(client, conn, channel_name);
1069 if (!SILC_ID_CHANNEL_COMPARE(channel->id, &id.u.channel_id))
1070 silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id);
1072 /* Create new channel entry */
1073 channel = silc_client_add_channel(client, conn, channel_name,
1074 mode, &id.u.channel_id);
1076 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_CHANNEL);
1081 conn->current_channel = channel;
1082 channel->mode = mode;
1085 hmac = silc_argument_get_arg_type(args, 11, NULL);
1087 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
1089 SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1090 "Cannot join channel: Unsupported HMAC `%s'", hmac);
1091 ERROR_CALLBACK(SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
1096 /* Get the list count */
1097 tmp = silc_argument_get_arg_type(args, 12, &len);
1099 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1102 SILC_GET32_MSB(list_count, tmp);
1104 /* Get Client ID list */
1105 tmp = silc_argument_get_arg_type(args, 13, &len);
1107 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1111 client_id_list = silc_buffer_alloc_size(len);
1113 silc_buffer_put(client_id_list, tmp, len);
1115 /* Get client mode list */
1116 tmp = silc_argument_get_arg_type(args, 14, &len);
1118 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1122 client_mode_list = silc_buffer_alloc_size(len);
1123 if (client_mode_list)
1124 silc_buffer_put(client_mode_list, tmp, len);
1126 /* Add clients we received in the reply to the channel */
1127 for (i = 0; i < list_count; i++) {
1131 SilcClientEntry client_entry;
1134 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1136 if (!silc_id_payload_parse_id(client_id_list->data, idp_len, &id))
1140 SILC_GET32_MSB(mode, client_mode_list->data);
1142 /* Check if we have this client cached already. */
1143 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1144 if (!client_entry) {
1145 /* No, we don't have it, add entry for it. */
1147 silc_client_add_client(client, conn, NULL, NULL, NULL,
1148 &id.u.client_id, 0);
1153 /* Join client to the channel */
1154 if (!silc_client_on_channel(channel, client_entry)) {
1155 chu = silc_calloc(1, sizeof(*chu));
1158 chu->client = client_entry;
1159 chu->channel = channel;
1161 silc_hash_table_add(channel->user_list, client_entry, chu);
1162 silc_hash_table_add(client_entry->channels, channel, chu);
1165 silc_buffer_pull(client_id_list, idp_len);
1166 silc_buffer_pull(client_mode_list, 4);
1168 silc_buffer_start(client_id_list);
1169 silc_buffer_start(client_mode_list);
1171 /* Save channel key */
1174 silc_client_save_channel_key(client, conn, keyp, channel);
1177 /* Get founder key */
1178 tmp = silc_argument_get_arg_type(args, 15, &len);
1180 if (channel->founder_key)
1181 silc_pkcs_public_key_free(channel->founder_key);
1182 channel->founder_key = NULL;
1183 silc_public_key_payload_decode(tmp, len, &channel->founder_key);
1186 /* Get user limit */
1187 tmp = silc_argument_get_arg_type(args, 17, &len);
1188 if (tmp && len == 4)
1189 SILC_GET32_MSB(channel->user_limit, tmp);
1190 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1191 channel->user_limit = 0;
1193 /* Get channel public key list */
1194 tmp = silc_argument_get_arg_type(args, 16, &len);
1196 silc_buffer_set(&chpklist, tmp, len);
1199 silc_free(channel->topic);
1200 channel->topic = silc_memdup(topic, strlen(topic));
1203 /* Notify application */
1204 silc_client_command_callback(cmd, channel_name, channel, mode, 0,
1205 keyp ? keyp->head : NULL, NULL,
1206 NULL, topic, hmac, list_count, client_id_list,
1207 client_mode_list, channel->founder_key,
1208 tmp ? &chpklist : NULL, channel->user_limit);
1211 silc_buffer_free(keyp);
1212 silc_buffer_free(client_id_list);
1213 silc_buffer_free(client_mode_list);
1214 silc_fsm_next(fsm, silc_client_command_reply_process);
1215 return SILC_FSM_CONTINUE;
1218 /********************************** MOTD ************************************/
1220 /* Received reply for MOTD command */
1222 SILC_FSM_STATE(silc_client_command_reply_motd)
1224 SilcClientCommandContext cmd = fsm_context;
1225 SilcClientConnection conn = cmd->conn;
1226 SilcClient client = conn->client;
1227 SilcCommandPayload payload = state_context;
1228 SilcArgumentPayload args = silc_command_get_args(payload);
1230 char *motd = NULL, *cp, line[256];
1233 CHECK_STATUS("Cannot get motd: ");
1236 if (silc_argument_get_arg_num(args) == 3) {
1237 motd = silc_argument_get_arg_type(args, 3, NULL);
1239 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1246 if (cp[i++] == '\n') {
1247 memset(line, 0, sizeof(line));
1248 silc_strncat(line, sizeof(line), cp, i - 1);
1255 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1264 /* Notify application */
1265 silc_client_command_callback(cmd, motd);
1268 silc_fsm_next(fsm, silc_client_command_reply_process);
1269 return SILC_FSM_CONTINUE;
1272 /********************************** UMODE ***********************************/
1274 /* Received reply tot he UMODE command. Save the current user mode */
1276 SILC_FSM_STATE(silc_client_command_reply_umode)
1278 SilcClientCommandContext cmd = fsm_context;
1279 SilcClientConnection conn = cmd->conn;
1280 SilcCommandPayload payload = state_context;
1281 SilcArgumentPayload args = silc_command_get_args(payload);
1283 SilcUInt32 mode, len;
1286 CHECK_STATUS("Cannot change mode: ");
1289 tmp = silc_argument_get_arg_type(args, 2, &len);
1290 if (!tmp || len != 4) {
1291 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1295 SILC_GET32_MSB(mode, tmp);
1296 conn->local_entry->mode = mode;
1298 /* Notify application */
1299 silc_client_command_callback(cmd, mode);
1302 silc_fsm_next(fsm, silc_client_command_reply_process);
1303 return SILC_FSM_CONTINUE;
1306 /********************************** CMODE ***********************************/
1308 /* Received reply for CMODE command. */
1310 SILC_FSM_STATE(silc_client_command_reply_cmode)
1312 SilcClientCommandContext cmd = fsm_context;
1313 SilcClientConnection conn = cmd->conn;
1314 SilcClient client = conn->client;
1315 SilcCommandPayload payload = state_context;
1316 SilcArgumentPayload args = silc_command_get_args(payload);
1319 SilcChannelEntry channel;
1321 SilcPublicKey public_key = NULL;
1322 SilcBufferStruct channel_pubkeys;
1326 CHECK_STATUS("Cannot change mode: ");
1329 /* Take Channel ID */
1330 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1331 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1335 /* Get the channel entry */
1336 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1338 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1342 /* Get channel mode */
1343 tmp = silc_argument_get_arg_type(args, 3, &len);
1344 if (!tmp || len != 4) {
1345 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1350 SILC_GET32_MSB(mode, tmp);
1351 channel->mode = mode;
1353 /* Get founder public key */
1354 tmp = silc_argument_get_arg_type(args, 4, &len);
1356 silc_public_key_payload_decode(tmp, len, &public_key);
1358 /* Get user limit */
1359 tmp = silc_argument_get_arg_type(args, 6, &len);
1360 if (tmp && len == 4)
1361 SILC_GET32_MSB(channel->user_limit, tmp);
1362 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1363 channel->user_limit = 0;
1365 /* Get channel public key(s) */
1366 tmp = silc_argument_get_arg_type(args, 5, &len);
1368 silc_buffer_set(&channel_pubkeys, tmp, len);
1370 /* Notify application */
1371 silc_client_command_callback(cmd, channel, mode, public_key,
1372 tmp ? &channel_pubkeys : NULL,
1373 channel->user_limit);
1377 silc_pkcs_public_key_free(public_key);
1378 silc_fsm_next(fsm, silc_client_command_reply_process);
1379 return SILC_FSM_CONTINUE;
1382 /********************************** CUMODE **********************************/
1384 /* Received reply for CUMODE command */
1386 SILC_FSM_STATE(silc_client_command_reply_cumode)
1388 SilcClientCommandContext cmd = fsm_context;
1389 SilcClientConnection conn = cmd->conn;
1390 SilcClient client = conn->client;
1391 SilcCommandPayload payload = state_context;
1392 SilcArgumentPayload args = silc_command_get_args(payload);
1393 SilcClientEntry client_entry;
1394 SilcChannelEntry channel;
1395 SilcChannelUser chu;
1396 unsigned char *modev;
1397 SilcUInt32 len, mode;
1401 CHECK_STATUS("Cannot change mode: ");
1404 /* Get channel mode */
1405 modev = silc_argument_get_arg_type(args, 2, &len);
1406 if (!modev || len != 4) {
1407 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1410 SILC_GET32_MSB(mode, modev);
1412 /* Take Channel ID */
1413 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1414 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1418 /* Get the channel entry */
1419 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1421 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1426 if (!silc_argument_get_decoded(args, 4, SILC_ARGUMENT_ID, &id, NULL)) {
1427 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1431 /* Get client entry */
1432 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1433 if (!client_entry) {
1434 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1439 chu = silc_client_on_channel(channel, client_entry);
1443 /* Notify application */
1444 silc_client_command_callback(cmd, mode, channel, client_entry);
1447 silc_fsm_next(fsm, silc_client_command_reply_process);
1448 return SILC_FSM_CONTINUE;
1451 /********************************** KICK ************************************/
1453 SILC_FSM_STATE(silc_client_command_reply_kick)
1455 SilcClientCommandContext cmd = fsm_context;
1456 SilcClientConnection conn = cmd->conn;
1457 SilcClient client = conn->client;
1458 SilcCommandPayload payload = state_context;
1459 SilcArgumentPayload args = silc_command_get_args(payload);
1460 SilcClientEntry client_entry;
1461 SilcChannelEntry channel;
1465 CHECK_STATUS("Cannot kick: ");
1468 /* Take Channel ID */
1469 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1470 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1474 /* Get the channel entry */
1475 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1477 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1482 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1483 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1487 /* Get client entry */
1488 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1489 if (!client_entry) {
1490 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1494 /* Notify application */
1495 silc_client_command_callback(cmd, channel, client_entry);
1498 silc_fsm_next(fsm, silc_client_command_reply_process);
1499 return SILC_FSM_CONTINUE;
1502 /******************************** SILCOPER **********************************/
1504 SILC_FSM_STATE(silc_client_command_reply_silcoper)
1506 SilcClientCommandContext cmd = fsm_context;
1507 SilcCommandPayload payload = state_context;
1508 SilcArgumentPayload args = silc_command_get_args(payload);
1511 CHECK_STATUS("Cannot change mode: ");
1514 /* Notify application */
1515 silc_client_command_callback(cmd);
1517 silc_fsm_next(fsm, silc_client_command_reply_process);
1518 return SILC_FSM_CONTINUE;
1521 /********************************** OPER ************************************/
1523 SILC_FSM_STATE(silc_client_command_reply_oper)
1525 SilcClientCommandContext cmd = fsm_context;
1526 SilcCommandPayload payload = state_context;
1527 SilcArgumentPayload args = silc_command_get_args(payload);
1530 CHECK_STATUS("Cannot change mode: ");
1533 /* Notify application */
1534 silc_client_command_callback(cmd);
1536 silc_fsm_next(fsm, silc_client_command_reply_process);
1537 return SILC_FSM_CONTINUE;
1540 /********************************* DETACH ***********************************/
1542 SILC_FSM_STATE(silc_client_command_reply_detach)
1544 SilcClientCommandContext cmd = fsm_context;
1545 SilcClientConnection conn = cmd->conn;
1546 SilcClient client = conn->client;
1547 SilcCommandPayload payload = state_context;
1548 SilcArgumentPayload args = silc_command_get_args(payload);
1552 CHECK_STATUS("Cannot detach: ");
1555 /* Notify application */
1556 silc_client_command_callback(cmd);
1559 /* Generate the detachment data and deliver it to the client in the
1560 detach client operation */
1561 detach = silc_client_get_detach_data(client, conn);
1563 client->internal->ops->detach(client, conn, silc_buffer_data(detach),
1564 silc_buffer_len(detach));
1565 silc_buffer_free(detach);
1569 silc_fsm_next(fsm, silc_client_command_reply_process);
1570 return SILC_FSM_CONTINUE;
1573 /********************************** WATCH ***********************************/
1575 SILC_FSM_STATE(silc_client_command_reply_watch)
1577 SilcClientCommandContext cmd = fsm_context;
1578 SilcCommandPayload payload = state_context;
1579 SilcArgumentPayload args = silc_command_get_args(payload);
1582 CHECK_STATUS("Cannot set watch: ");
1585 /* Notify application */
1586 silc_client_command_callback(cmd);
1588 silc_fsm_next(fsm, silc_client_command_reply_process);
1589 return SILC_FSM_CONTINUE;
1592 /*********************************** BAN ************************************/
1594 SILC_FSM_STATE(silc_client_command_reply_ban)
1596 SilcClientCommandContext cmd = fsm_context;
1597 SilcClientConnection conn = cmd->conn;
1598 SilcClient client = conn->client;
1599 SilcCommandPayload payload = state_context;
1600 SilcArgumentPayload args = silc_command_get_args(payload);
1601 SilcChannelEntry channel;
1604 SilcBufferStruct buf;
1608 CHECK_STATUS("Cannot set ban: ");
1611 /* Take Channel ID */
1612 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1613 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1617 /* Get the channel entry */
1618 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1620 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1624 /* Get the ban list */
1625 tmp = silc_argument_get_arg_type(args, 3, &len);
1627 silc_buffer_set(&buf, tmp, len);
1629 /* Notify application */
1630 silc_client_command_callback(cmd, channel, tmp ? &buf : NULL);
1633 silc_fsm_next(fsm, silc_client_command_reply_process);
1634 return SILC_FSM_CONTINUE;
1637 /********************************** LEAVE ***********************************/
1639 /* Reply to LEAVE command. */
1641 SILC_FSM_STATE(silc_client_command_reply_leave)
1643 SilcClientCommandContext cmd = fsm_context;
1644 SilcClientConnection conn = cmd->conn;
1645 SilcClient client = conn->client;
1646 SilcCommandPayload payload = state_context;
1647 SilcArgumentPayload args = silc_command_get_args(payload);
1648 SilcChannelEntry channel;
1649 SilcChannelUser chu;
1653 CHECK_STATUS("Cannot set leave: ");
1656 /* Get Channel ID */
1657 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1658 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1662 /* Get the channel entry */
1663 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1665 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1669 /* Remove us from this channel. */
1670 chu = silc_client_on_channel(channel, conn->local_entry);
1672 silc_hash_table_del(chu->client->channels, chu->channel);
1673 silc_hash_table_del(chu->channel->user_list, chu->client);
1677 /* Notify application */
1678 silc_client_command_callback(cmd, channel);
1680 /* Now delete the channel. */
1681 silc_client_del_channel(client, conn, channel);
1684 silc_fsm_next(fsm, silc_client_command_reply_process);
1685 return SILC_FSM_CONTINUE;
1688 /********************************* USERS ************************************/
1691 silc_client_command_reply_users_continue(SilcClient client,
1692 SilcClientConnection conn,
1693 SilcCommand command,
1699 SilcClientCommandContext cmd = context;
1704 /* Continue USERS command after resolving unknown users */
1707 silc_client_command_reply_users_resolved(SilcClient client,
1708 SilcClientConnection conn,
1713 SilcClientCommandContext cmd = context;
1714 SILC_FSM_CALL_CONTINUE_SYNC(&cmd->thread);
1717 /* Reply to USERS command. Received list of client ID's and theirs modes
1718 on the channel we requested. */
1720 SILC_FSM_STATE(silc_client_command_reply_users)
1722 SilcClientCommandContext cmd = fsm_context;
1723 SilcClientConnection conn = cmd->conn;
1724 SilcClient client = conn->client;
1725 SilcCommandPayload payload = state_context;
1726 SilcArgumentPayload args = silc_command_get_args(payload);
1728 SilcUInt32 tmp_len, list_count;
1729 SilcUInt16 idp_len, mode;
1730 SilcHashTableList htl;
1731 SilcBufferStruct client_id_list, client_mode_list;
1732 SilcChannelEntry channel;
1733 SilcClientEntry client_entry;
1734 SilcChannelUser chu;
1739 CHECK_STATUS("Cannot get users: ");
1742 /* Get channel ID */
1743 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1744 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1748 /* Get channel entry */
1749 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1751 /* Resolve the channel from server */
1753 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1754 client, conn, &id.u.channel_id,
1755 silc_client_command_reply_users_continue, cmd));
1760 /* Get the list count */
1761 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1762 if (!tmp || tmp_len != 4) {
1763 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1766 SILC_GET32_MSB(list_count, tmp);
1768 /* Get Client ID list */
1769 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1771 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1774 silc_buffer_set(&client_id_list, tmp, tmp_len);
1776 /* Resolve users we do not know about */
1777 if (!cmd->resolved) {
1778 cmd->resolved = TRUE;
1779 SILC_FSM_CALL(silc_client_get_clients_by_list(
1780 client, conn, list_count, &client_id_list,
1781 silc_client_command_reply_users_resolved, cmd));
1785 /* Get client mode list */
1786 tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
1788 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1791 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1793 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1795 /* Cache the received Client ID's and modes. */
1796 for (i = 0; i < list_count; i++) {
1797 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1799 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1803 SILC_GET32_MSB(mode, client_mode_list.data);
1805 /* Save the client on this channel. Unknown clients are ignored as they
1806 clearly do not exist since the resolving didn't find them. */
1807 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1808 if (client_entry && !silc_client_on_channel(channel, client_entry)) {
1809 chu = silc_calloc(1, sizeof(*chu));
1812 chu->client = client_entry;
1814 chu->channel = channel;
1815 silc_hash_table_add(channel->user_list, client_entry, chu);
1816 silc_hash_table_add(client_entry->channels, channel, chu);
1819 if (!silc_buffer_pull(&client_id_list, idp_len))
1821 if (!silc_buffer_pull(&client_mode_list, 4))
1825 /* Notify application */
1826 silc_hash_table_list(channel->user_list, &htl);
1827 silc_client_command_callback(cmd, channel, &htl);
1828 silc_hash_table_list_reset(&htl);
1831 silc_fsm_next(fsm, silc_client_command_reply_process);
1832 return SILC_FSM_CONTINUE;
1835 /********************************** GETKEY **********************************/
1837 /* Received command reply to GETKEY command. WE've received the remote
1838 client's public key. */
1840 SILC_FSM_STATE(silc_client_command_reply_getkey)
1842 SilcClientCommandContext cmd = fsm_context;
1843 SilcClientConnection conn = cmd->conn;
1844 SilcClient client = conn->client;
1845 SilcCommandPayload payload = state_context;
1846 SilcArgumentPayload args = silc_command_get_args(payload);
1847 SilcClientEntry client_entry;
1848 SilcServerEntry server_entry;
1851 SilcPublicKey public_key;
1855 CHECK_STATUS("Cannot get key: ");
1859 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1860 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1864 /* Get the public key */
1865 tmp = silc_argument_get_arg_type(args, 3, &len);
1867 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1870 if (!silc_public_key_payload_decode(tmp, len, &public_key)) {
1871 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1875 if (id.type == SILC_ID_CLIENT) {
1876 /* Received client's public key */
1877 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1878 if (!client_entry) {
1879 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1883 /* Save fingerprint */
1884 if (!client_entry->fingerprint)
1885 silc_hash_make(client->sha1hash, tmp + 4, len - 4,
1886 client_entry->fingerprint);
1887 if (!client_entry->public_key) {
1888 client_entry->public_key = public_key;
1892 /* Notify application */
1893 silc_client_command_callback(cmd, SILC_ID_CLIENT, client_entry,
1894 client_entry->public_key);
1895 } else if (id.type == SILC_ID_SERVER) {
1896 /* Received server's public key */
1897 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1898 if (!server_entry) {
1899 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1903 /* Notify application */
1904 silc_client_command_callback(cmd, SILC_ID_SERVER, server_entry,
1910 silc_pkcs_public_key_free(public_key);
1911 silc_fsm_next(fsm, silc_client_command_reply_process);
1912 return SILC_FSM_CONTINUE;
1915 /********************************** SERVICE *********************************/
1917 /* Reply to SERVICE command. */
1918 /* XXX incomplete */
1920 SILC_FSM_STATE(silc_client_command_reply_service)
1922 SilcClientCommandContext cmd = fsm_context;
1923 SilcCommandPayload payload = state_context;
1924 SilcArgumentPayload args = silc_command_get_args(payload);
1926 unsigned char *service_list, *name;
1929 CHECK_STATUS("Cannot get service: ");
1931 /* Get service list */
1932 service_list = silc_argument_get_arg_type(args, 2, &tmp_len);
1934 /* Get requested service name */
1935 name = silc_argument_get_arg_type(args, 3, &tmp_len);
1937 /* Notify application */
1938 silc_client_command_callback(cmd, service_list, name);
1940 silc_fsm_next(fsm, silc_client_command_reply_process);
1941 return SILC_FSM_CONTINUE;
1944 /*********************************** QUIT ***********************************/
1946 /* QUIT command reply stub */
1948 SILC_FSM_STATE(silc_client_command_reply_quit)
1950 silc_fsm_next(fsm, silc_client_command_reply_process);
1951 return SILC_FSM_CONTINUE;