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_unref_client(client, conn, client_entry);
116 silc_client_del_client(client, conn, client_entry);
121 /***************************** Command Reply ********************************/
123 /* Process received command reply packet */
125 SILC_FSM_STATE(silc_client_command_reply)
127 SilcClientConnection conn = fsm_context;
128 SilcPacket packet = state_context;
129 SilcClientCommandContext cmd;
130 SilcCommandPayload payload;
132 SilcUInt16 cmd_ident;
134 /* Get command reply payload from packet */
135 payload = silc_command_payload_parse(silc_buffer_datalen(&packet->buffer));
136 silc_packet_free(packet);
138 SILC_LOG_DEBUG(("Bad command reply packet"));
139 return SILC_FSM_FINISH;
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 == SILC_COMMAND_NONE)
150 && cmd->cmd_ident == cmd_ident)
152 silc_mutex_unlock(conn->internal->lock);
155 SILC_LOG_DEBUG(("Unknown command reply"));
156 silc_command_payload_free(payload);
157 return SILC_FSM_FINISH;
160 /* Signal command thread that command reply has arrived */
161 silc_fsm_set_state_context(&cmd->thread, payload);
162 silc_fsm_next(&cmd->thread, silc_client_command_reply_process);
163 silc_fsm_continue_sync(&cmd->thread);
165 return SILC_FSM_FINISH;
168 /* Wait here for command reply to arrive from remote host */
170 SILC_FSM_STATE(silc_client_command_reply_wait)
172 SILC_LOG_DEBUG(("Wait for command reply"));
174 /** Wait for command reply */
175 silc_fsm_set_state_context(fsm, NULL);
176 silc_fsm_next_later(fsm, silc_client_command_reply_timeout, 20, 0);
177 return SILC_FSM_WAIT;
180 /* Timeout occurred while waiting command reply */
182 SILC_FSM_STATE(silc_client_command_reply_timeout)
184 SilcClientCommandContext cmd = fsm_context;
185 SilcArgumentPayload args = NULL;
187 /* Timeout, reply not received in timely fashion */
188 ERROR_CALLBACK(SILC_STATUS_ERR_TIMEDOUT);
189 return SILC_FSM_FINISH;
192 /* Process received command reply payload */
194 SILC_FSM_STATE(silc_client_command_reply_process)
196 SilcClientCommandContext cmd = fsm_context;
197 SilcCommandPayload payload = state_context;
199 silc_command_get_status(payload, &cmd->status, &cmd->error);
202 case SILC_COMMAND_WHOIS:
204 silc_fsm_next(fsm, silc_client_command_reply_whois);
206 case SILC_COMMAND_WHOWAS:
208 silc_fsm_next(fsm, silc_client_command_reply_whowas);
210 case SILC_COMMAND_IDENTIFY:
212 silc_fsm_next(fsm, silc_client_command_reply_identify);
214 case SILC_COMMAND_NICK:
216 silc_fsm_next(fsm, silc_client_command_reply_nick);
218 case SILC_COMMAND_LIST:
220 silc_fsm_next(fsm, silc_client_command_reply_list);
222 case SILC_COMMAND_TOPIC:
224 silc_fsm_next(fsm, silc_client_command_reply_topic);
226 case SILC_COMMAND_INVITE:
228 silc_fsm_next(fsm, silc_client_command_reply_invite);
230 case SILC_COMMAND_QUIT:
232 silc_fsm_next(fsm, silc_client_command_reply_quit);
234 case SILC_COMMAND_KILL:
236 silc_fsm_next(fsm, silc_client_command_reply_kill);
238 case SILC_COMMAND_INFO:
240 silc_fsm_next(fsm, silc_client_command_reply_info);
242 case SILC_COMMAND_STATS:
244 silc_fsm_next(fsm, silc_client_command_reply_stats);
246 case SILC_COMMAND_PING:
248 silc_fsm_next(fsm, silc_client_command_reply_ping);
250 case SILC_COMMAND_OPER:
252 silc_fsm_next(fsm, silc_client_command_reply_oper);
254 case SILC_COMMAND_JOIN:
256 silc_fsm_next(fsm, silc_client_command_reply_join);
258 case SILC_COMMAND_MOTD:
260 silc_fsm_next(fsm, silc_client_command_reply_motd);
262 case SILC_COMMAND_UMODE:
264 silc_fsm_next(fsm, silc_client_command_reply_umode);
266 case SILC_COMMAND_CMODE:
268 silc_fsm_next(fsm, silc_client_command_reply_cmode);
270 case SILC_COMMAND_CUMODE:
272 silc_fsm_next(fsm, silc_client_command_reply_cumode);
274 case SILC_COMMAND_KICK:
276 silc_fsm_next(fsm, silc_client_command_reply_kick);
278 case SILC_COMMAND_BAN:
280 silc_fsm_next(fsm, silc_client_command_reply_ban);
282 case SILC_COMMAND_DETACH:
284 silc_fsm_next(fsm, silc_client_command_reply_detach);
286 case SILC_COMMAND_WATCH:
288 silc_fsm_next(fsm, silc_client_command_reply_watch);
290 case SILC_COMMAND_SILCOPER:
292 silc_fsm_next(fsm, silc_client_command_reply_silcoper);
294 case SILC_COMMAND_LEAVE:
296 silc_fsm_next(fsm, silc_client_command_reply_leave);
298 case SILC_COMMAND_USERS:
300 silc_fsm_next(fsm, silc_client_command_reply_users);
302 case SILC_COMMAND_GETKEY:
304 silc_fsm_next(fsm, silc_client_command_reply_getkey);
306 case SILC_COMMAND_SERVICE:
308 silc_fsm_next(fsm, silc_client_command_reply_service);
311 return SILC_FSM_FINISH;
314 return SILC_FSM_CONTINUE;
317 /* Completes command reply processing */
319 SILC_FSM_STATE(silc_client_command_reply_processed)
321 SilcClientCommandContext cmd = fsm_context;
322 SilcCommandPayload payload = state_context;
324 silc_command_payload_free(payload);
326 if (cmd->status == SILC_STATUS_OK || cmd->status == SILC_STATUS_LIST_END ||
327 SILC_STATUS_IS_ERROR(cmd->status))
328 return SILC_FSM_FINISH;
330 /** Wait more command payloads */
331 silc_fsm_next(fsm, silc_client_command_reply_wait);
332 return SILC_FSM_CONTINUE;
335 /******************************** WHOIS *************************************/
337 /* Received reply for WHOIS command. */
339 SILC_FSM_STATE(silc_client_command_reply_whois)
341 SilcClientCommandContext cmd = fsm_context;
342 SilcClientConnection conn = cmd->conn;
343 SilcClient client = conn->client;
344 SilcCommandPayload payload = state_context;
345 SilcArgumentPayload args = silc_command_get_args(payload);
346 SilcClientEntry client_entry = NULL;
347 SilcUInt32 idle = 0, mode = 0, fingerprint_len, len, *umodes = NULL;
348 SilcBufferStruct channels, ch_user_modes;
349 SilcBool has_channels = FALSE;
350 SilcDList channel_list = NULL;
352 char *nickname = NULL, *username = NULL, *realname = NULL;
353 unsigned char *fingerprint, *tmp;
355 CHECK_STATUS("WHOIS: ");
359 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
360 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
365 nickname = silc_argument_get_arg_type(args, 3, NULL);
366 username = silc_argument_get_arg_type(args, 4, NULL);
367 realname = silc_argument_get_arg_type(args, 5, NULL);
368 if (!nickname || !username || !realname) {
369 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
373 /* Get joined channel list */
374 memset(&channels, 0, sizeof(channels));
375 tmp = silc_argument_get_arg_type(args, 6, &len);
378 silc_buffer_set(&channels, tmp, len);
380 /* Get channel user mode list */
381 tmp = silc_argument_get_arg_type(args, 10, &len);
383 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
386 silc_buffer_set(&ch_user_modes, tmp, len);
390 tmp = silc_argument_get_arg_type(args, 7, &len);
392 SILC_GET32_MSB(mode, tmp);
395 tmp = silc_argument_get_arg_type(args, 8, &len);
397 SILC_GET32_MSB(idle, tmp);
399 /* Get fingerprint */
400 fingerprint = silc_argument_get_arg_type(args, 9, &fingerprint_len);
402 /* Check if we have this client cached already. */
403 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
405 SILC_LOG_DEBUG(("Adding new client entry (WHOIS)"));
407 silc_client_add_client(client, conn, nickname, username, realname,
408 &id.u.client_id, mode);
410 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
414 silc_client_update_client(client, conn, client_entry,
415 nickname, username, realname, mode);
418 if (fingerprint && fingerprint_len == sizeof(client_entry->fingerprint))
419 memcpy(client_entry->fingerprint, fingerprint, fingerprint_len);
421 /* Get user attributes */
422 tmp = silc_argument_get_arg_type(args, 11, &len);
424 if (client_entry->attrs)
425 silc_attribute_payload_list_free(client_entry->attrs);
426 client_entry->attrs = silc_attribute_payload_parse(tmp, len);
429 /* Parse channel and channel user mode list */
431 channel_list = silc_channel_payload_parse_list(silc_buffer_data(&channels),
432 silc_buffer_len(&channels));
434 silc_get_mode_list(&ch_user_modes, silc_dlist_count(channel_list),
438 /* Notify application */
439 silc_client_command_callback(cmd, client_entry, nickname, username,
440 realname, channel_list, mode, idle, fingerprint,
441 umodes, client_entry->attrs);
443 silc_client_unref_client(client, conn, client_entry);
445 silc_dlist_uninit(channel_list);
450 silc_fsm_next(fsm, silc_client_command_reply_processed);
451 return SILC_FSM_CONTINUE;
454 /******************************** WHOWAS ************************************/
456 /* Received reply for WHOWAS command. */
458 SILC_FSM_STATE(silc_client_command_reply_whowas)
460 SilcClientCommandContext cmd = fsm_context;
461 SilcClientConnection conn = cmd->conn;
462 SilcClient client = conn->client;
463 SilcCommandPayload payload = state_context;
464 SilcArgumentPayload args = silc_command_get_args(payload);
465 SilcClientEntry client_entry = NULL;
467 char *nickname, *username;
468 char *realname = NULL;
470 CHECK_STATUS("WHOWAS: ");
474 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
475 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
479 /* Get the client entry */
480 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
483 nickname = silc_argument_get_arg_type(args, 3, NULL);
484 username = silc_argument_get_arg_type(args, 4, NULL);
485 realname = silc_argument_get_arg_type(args, 5, NULL);
486 if (!nickname || !username) {
487 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
491 /* Notify application. We don't save any history information to any
492 cache. Just pass the data to the application. */
493 silc_client_command_callback(cmd, client_entry, nickname, username,
497 silc_client_unref_client(client, conn, client_entry);
498 silc_fsm_next(fsm, silc_client_command_reply_processed);
499 return SILC_FSM_CONTINUE;
502 /******************************** IDENTIFY **********************************/
504 /* Received reply for IDENTIFY command. */
506 SILC_FSM_STATE(silc_client_command_reply_identify)
508 SilcClientCommandContext cmd = fsm_context;
509 SilcClientConnection conn = cmd->conn;
510 SilcClient client = conn->client;
511 SilcCommandPayload payload = state_context;
512 SilcArgumentPayload args = silc_command_get_args(payload);
513 SilcClientEntry client_entry;
514 SilcServerEntry server_entry;
515 SilcChannelEntry channel_entry;
518 char *name = NULL, *info = NULL;
520 CHECK_STATUS("IDENTIFY: ");
524 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
525 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
530 name = silc_argument_get_arg_type(args, 3, &len);
531 info = silc_argument_get_arg_type(args, 4, &len);
535 SILC_LOG_DEBUG(("Received client information"));
537 /* Check if we have this client cached already. */
538 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
540 SILC_LOG_DEBUG(("Adding new client entry (IDENTIFY)"));
542 silc_client_add_client(client, conn, name, info, NULL,
545 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
549 silc_client_update_client(client, conn, client_entry,
550 name, info, NULL, 0);
553 /* Notify application */
554 silc_client_command_callback(cmd, client_entry, name, info);
555 silc_client_unref_client(client, conn, client_entry);
559 SILC_LOG_DEBUG(("Received server information"));
561 /* Check if we have this server cached already. */
562 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
564 SILC_LOG_DEBUG(("Adding new server entry (IDENTIFY)"));
565 server_entry = silc_client_add_server(client, conn, name, info,
568 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
572 silc_client_update_server(client, conn, server_entry, name, info);
574 server_entry->internal.resolve_cmd_ident = 0;
576 /* Notify application */
577 silc_client_command_callback(cmd, server_entry, name, info);
580 case SILC_ID_CHANNEL:
581 SILC_LOG_DEBUG(("Received channel information"));
583 /* Check if we have this channel cached already. */
584 channel_entry = silc_client_get_channel_by_id(client, conn,
586 if (!channel_entry) {
587 SILC_LOG_DEBUG(("Adding new channel entry (IDENTIFY"));
590 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
594 /* Add new channel entry */
595 channel_entry = silc_client_add_channel(client, conn, name, 0,
597 if (!channel_entry) {
598 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
603 /* Notify application */
604 silc_client_command_callback(cmd, channel_entry, name, info);
609 silc_fsm_next(fsm, silc_client_command_reply_processed);
610 return SILC_FSM_CONTINUE;
613 /********************************** NICK ************************************/
615 /* Received reply for command NICK. */
617 SILC_FSM_STATE(silc_client_command_reply_nick)
619 SilcClientCommandContext cmd = fsm_context;
620 SilcClientConnection conn = cmd->conn;
621 SilcClient client = conn->client;
622 SilcCommandPayload payload = state_context;
623 SilcArgumentPayload args = silc_command_get_args(payload);
624 unsigned char *tmp, *nick, *idp;
625 SilcUInt32 len, idp_len;
626 SilcClientID old_client_id;
630 CHECK_STATUS("Cannot set nickname: ");
633 old_client_id = *conn->local_id;
635 /* Take received Client ID */
636 idp = silc_argument_get_arg_type(args, 2, &idp_len);
638 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
641 if (!silc_id_payload_parse_id(idp, idp_len, &id)) {
642 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
646 /* Take the new nickname */
647 nick = silc_argument_get_arg_type(args, 3, &len);
649 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
653 /* Normalize nickname */
654 tmp = silc_identifier_check(nick, len, SILC_STRING_UTF8, 128, NULL);
656 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_NICKNAME);
660 /* Update the client entry */
661 if (!silc_idcache_update(conn->internal->client_cache,
662 conn->internal->local_entry,
663 &conn->local_entry->id,
665 conn->local_entry->nickname_normalized,
668 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_NICKNAME);
671 memcpy(conn->local_entry->nickname, nick, strlen(nick));
672 conn->local_entry->nickname_normalized = tmp;
673 silc_buffer_enlarge(conn->internal->local_idp, idp_len);
674 silc_buffer_put(conn->internal->local_idp, idp, idp_len);
675 silc_client_nickname_format(client, conn, conn->local_entry);
677 /* Notify application */
678 silc_client_command_callback(cmd, conn->local_entry,
679 conn->local_entry->nickname, &old_client_id);
682 silc_fsm_next(fsm, silc_client_command_reply_processed);
683 return SILC_FSM_CONTINUE;
686 /********************************** LIST ************************************/
688 /* Received reply to the LIST command. */
690 SILC_FSM_STATE(silc_client_command_reply_list)
692 SilcClientCommandContext cmd = fsm_context;
693 SilcClientConnection conn = cmd->conn;
694 SilcClient client = conn->client;
695 SilcCommandPayload payload = state_context;
696 SilcArgumentPayload args = silc_command_get_args(payload);
697 unsigned char *tmp, *name, *topic;
698 SilcUInt32 usercount = 0;
699 SilcChannelEntry channel_entry;
703 CHECK_STATUS("Cannot list channels: ");
705 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
706 /* There were no channels in the network. */
707 silc_client_command_callback(cmd, NULL, NULL, NULL, 0);
708 silc_fsm_next(fsm, silc_client_command_reply_processed);
709 return SILC_FSM_CONTINUE;
714 name = silc_argument_get_arg_type(args, 3, NULL);
716 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
720 topic = silc_argument_get_arg_type(args, 4, NULL);
721 tmp = silc_argument_get_arg_type(args, 5, NULL);
723 SILC_GET32_MSB(usercount, tmp);
725 /* Check whether the channel exists, and add it to cache if it doesn't. */
726 channel_entry = silc_client_get_channel_by_id(client, conn,
728 if (!channel_entry) {
729 /* Add new channel entry */
730 channel_entry = silc_client_add_channel(client, conn, name, 0,
732 if (!channel_entry) {
733 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
738 /* Notify application */
739 silc_client_command_callback(cmd, channel_entry, name, topic, usercount);
742 silc_fsm_next(fsm, silc_client_command_reply_processed);
743 return SILC_FSM_CONTINUE;
746 /********************************* TOPIC ************************************/
748 /* Received reply to topic command. */
750 SILC_FSM_STATE(silc_client_command_reply_topic)
752 SilcClientCommandContext cmd = fsm_context;
753 SilcClientConnection conn = cmd->conn;
754 SilcClient client = conn->client;
755 SilcCommandPayload payload = state_context;
756 SilcArgumentPayload args = silc_command_get_args(payload);
757 SilcChannelEntry channel;
763 CHECK_STATUS("Cannot set topic: ");
766 /* Take Channel ID */
767 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
768 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
772 /* Get the channel entry */
773 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
775 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
780 topic = silc_argument_get_arg_type(args, 3, &len);
782 silc_free(channel->topic);
783 channel->topic = silc_memdup(topic, len);
786 /* Notify application */
787 silc_client_command_callback(cmd, channel, channel->topic);
790 silc_fsm_next(fsm, silc_client_command_reply_processed);
791 return SILC_FSM_CONTINUE;
794 /********************************* INVITE ***********************************/
796 /* Received reply to invite command. */
798 SILC_FSM_STATE(silc_client_command_reply_invite)
800 SilcClientCommandContext cmd = fsm_context;
801 SilcClientConnection conn = cmd->conn;
802 SilcClient client = conn->client;
803 SilcCommandPayload payload = state_context;
804 SilcArgumentPayload args = silc_command_get_args(payload);
805 SilcChannelEntry channel;
808 SilcArgumentPayload invite_args = NULL;
812 CHECK_STATUS("Cannot invite: ");
815 /* Take Channel ID */
816 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
817 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
821 /* Get the channel entry */
822 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
824 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
828 /* Get the invite list */
829 tmp = silc_argument_get_arg_type(args, 3, &len);
831 invite_args = silc_argument_list_parse(tmp, len);
833 /* Notify application */
834 silc_client_command_callback(cmd, channel, invite_args);
837 silc_argument_payload_free(invite_args);
840 silc_fsm_next(fsm, silc_client_command_reply_processed);
841 return SILC_FSM_CONTINUE;
844 /********************************** KILL ************************************/
846 /* Received reply to the KILL command. */
848 SILC_FSM_STATE(silc_client_command_reply_kill)
850 SilcClientCommandContext cmd = fsm_context;
851 SilcClientConnection conn = cmd->conn;
852 SilcClient client = conn->client;
853 SilcCommandPayload payload = state_context;
854 SilcArgumentPayload args = silc_command_get_args(payload);
855 SilcClientEntry client_entry;
859 CHECK_STATUS("Cannot kill: ");
862 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
863 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
867 /* Get the client entry, if exists */
868 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
870 /* Notify application */
871 silc_client_command_callback(cmd, client_entry);
873 /* Remove the client from all channels and free it */
875 silc_client_del_client(client, conn, client_entry);
876 silc_client_unref_client(client, conn, client_entry);
880 silc_fsm_next(fsm, silc_client_command_reply_processed);
881 return SILC_FSM_CONTINUE;
884 /********************************** INFO ************************************/
886 /* Received reply to INFO command. We receive the server ID and some
887 information about the server user requested. */
889 SILC_FSM_STATE(silc_client_command_reply_info)
891 SilcClientCommandContext cmd = fsm_context;
892 SilcClientConnection conn = cmd->conn;
893 SilcClient client = conn->client;
894 SilcCommandPayload payload = state_context;
895 SilcArgumentPayload args = silc_command_get_args(payload);
896 SilcServerEntry server;
897 char *server_name, *server_info;
901 CHECK_STATUS("Cannot get info: ");
905 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
906 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
910 /* Get server name */
911 server_name = silc_argument_get_arg_type(args, 3, NULL);
913 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
917 /* Get server info */
918 server_info = silc_argument_get_arg_type(args, 4, NULL);
920 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
924 /* See whether we have this server cached. If not create it. */
925 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
927 SILC_LOG_DEBUG(("New server entry"));
928 server = silc_client_add_server(client, conn, server_name,
929 server_info, &id.u.server_id);
934 /* Notify application */
935 silc_client_command_callback(cmd, server, server->server_name,
936 server->server_info);
939 silc_fsm_next(fsm, silc_client_command_reply_processed);
940 return SILC_FSM_CONTINUE;
943 /********************************** STATS ***********************************/
945 /* Received reply to STATS command. */
947 SILC_FSM_STATE(silc_client_command_reply_stats)
949 SilcClientCommandContext cmd = fsm_context;
950 SilcCommandPayload payload = state_context;
951 SilcArgumentPayload args = silc_command_get_args(payload);
952 SilcClientStats stats;
953 unsigned char *buf = NULL;
954 SilcUInt32 buf_len = 0;
959 CHECK_STATUS("Cannot get stats: ");
963 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
964 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
968 /* Get statistics structure */
969 memset(&stats, 0, sizeof(stats));
970 buf = silc_argument_get_arg_type(args, 3, &buf_len);
972 silc_buffer_set(&b, buf, buf_len);
973 silc_buffer_unformat(&b,
974 SILC_STR_UI_INT(&stats.starttime),
975 SILC_STR_UI_INT(&stats.uptime),
976 SILC_STR_UI_INT(&stats.my_clients),
977 SILC_STR_UI_INT(&stats.my_channels),
978 SILC_STR_UI_INT(&stats.my_server_ops),
979 SILC_STR_UI_INT(&stats.my_router_ops),
980 SILC_STR_UI_INT(&stats.cell_clients),
981 SILC_STR_UI_INT(&stats.cell_channels),
982 SILC_STR_UI_INT(&stats.cell_servers),
983 SILC_STR_UI_INT(&stats.clients),
984 SILC_STR_UI_INT(&stats.channels),
985 SILC_STR_UI_INT(&stats.servers),
986 SILC_STR_UI_INT(&stats.routers),
987 SILC_STR_UI_INT(&stats.server_ops),
988 SILC_STR_UI_INT(&stats.router_ops),
992 /* Notify application */
993 silc_client_command_callback(cmd, &stats);
996 silc_fsm_next(fsm, silc_client_command_reply_processed);
997 return SILC_FSM_CONTINUE;
1000 /********************************** PING ************************************/
1002 /* Received reply to PING command. */
1004 SILC_FSM_STATE(silc_client_command_reply_ping)
1006 SilcClientCommandContext cmd = fsm_context;
1007 SilcClientConnection conn = cmd->conn;
1008 SilcClient client = conn->client;
1011 diff = silc_time() - SILC_PTR_TO_64(cmd->context);
1012 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO,
1013 "Ping reply from %s: %d second%s", conn->remote_host,
1014 (int)diff, diff == 1 ? "" : "s");
1016 /* Notify application */
1017 silc_client_command_callback(cmd);
1019 silc_fsm_next(fsm, silc_client_command_reply_processed);
1020 return SILC_FSM_CONTINUE;
1023 /********************************** JOIN ************************************/
1025 /* Continue JOIN command reply processing after resolving unknown users */
1028 silc_client_command_reply_join_resolved(SilcClient client,
1029 SilcClientConnection conn,
1034 SilcClientCommandContext cmd = context;
1035 SilcChannelEntry channel = cmd->context;
1037 channel->internal.resolve_cmd_ident = 0;
1038 silc_client_unref_channel(client, conn, channel);
1040 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1044 /* Received reply for JOIN command. */
1046 SILC_FSM_STATE(silc_client_command_reply_join)
1048 SilcClientCommandContext cmd = fsm_context;
1049 SilcClientConnection conn = cmd->conn;
1050 SilcClient client = conn->client;
1051 SilcCommandPayload payload = state_context;
1052 SilcArgumentPayload args = silc_command_get_args(payload);
1053 SilcChannelEntry channel;
1054 SilcUInt32 mode = 0, len, list_count;
1055 char *topic, *tmp, *channel_name = NULL, *hmac;
1057 SilcBufferStruct client_id_list, client_mode_list, keyp;
1058 SilcHashTableList htl;
1059 SilcDList chpks = NULL;
1064 CHECK_STATUS("Cannot join channel: ");
1067 /* Get channel name */
1068 channel_name = silc_argument_get_arg_type(args, 2, NULL);
1069 if (!channel_name) {
1070 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1074 /* Get Channel ID */
1075 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1076 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1080 /* Check whether we have this channel entry already. */
1081 channel = silc_client_get_channel(client, conn, channel_name);
1083 if (!SILC_ID_CHANNEL_COMPARE(&channel->id, &id.u.channel_id))
1084 silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id);
1086 /* Create new channel entry */
1087 channel = silc_client_add_channel(client, conn, channel_name,
1088 mode, &id.u.channel_id);
1090 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_CHANNEL);
1093 silc_client_ref_channel(client, conn, channel);
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);
1110 silc_buffer_set(&client_id_list, tmp, len);
1112 /* Resolve users we do not know about */
1113 if (!cmd->resolved) {
1114 cmd->resolved = TRUE;
1115 cmd->context = channel;
1116 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1117 silc_client_get_clients_by_list(
1118 client, conn, list_count, &client_id_list,
1119 silc_client_command_reply_join_resolved, cmd));
1123 /* Get client mode list */
1124 tmp = silc_argument_get_arg_type(args, 14, &len);
1126 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1129 silc_buffer_set(&client_mode_list, tmp, len);
1131 /* Add clients we received in the reply to the channel */
1132 for (i = 0; i < list_count; i++) {
1136 SilcClientEntry client_entry;
1139 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1141 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1145 SILC_GET32_MSB(mode, client_mode_list.data);
1147 /* Get client entry */
1148 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1152 /* Join client to the channel */
1153 silc_client_add_to_channel(channel, client_entry, mode);
1154 silc_client_unref_client(client, conn, client_entry);
1156 if (!silc_buffer_pull(&client_id_list, idp_len))
1158 if (!silc_buffer_pull(&client_mode_list, 4))
1163 hmac = silc_argument_get_arg_type(args, 11, NULL);
1165 if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) {
1167 SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1168 "Cannot join channel: Unsupported HMAC `%s'", hmac);
1169 ERROR_CALLBACK(SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
1174 /* Get channel mode */
1175 tmp = silc_argument_get_arg_type(args, 5, NULL);
1177 SILC_GET32_MSB(mode, tmp);
1178 channel->mode = mode;
1180 /* Get channel key and save it */
1181 tmp = silc_argument_get_arg_type(args, 7, &len);
1183 silc_buffer_set(&keyp, tmp, len);
1184 silc_client_save_channel_key(client, conn, &keyp, channel);
1188 topic = silc_argument_get_arg_type(args, 10, NULL);
1190 silc_free(channel->topic);
1191 channel->topic = silc_memdup(topic, strlen(topic));
1194 /* Get founder key */
1195 tmp = silc_argument_get_arg_type(args, 15, &len);
1197 if (channel->founder_key)
1198 silc_pkcs_public_key_free(channel->founder_key);
1199 channel->founder_key = NULL;
1200 silc_public_key_payload_decode(tmp, len, &channel->founder_key);
1203 /* Get user limit */
1204 tmp = silc_argument_get_arg_type(args, 17, &len);
1205 if (tmp && len == 4)
1206 SILC_GET32_MSB(channel->user_limit, tmp);
1207 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1208 channel->user_limit = 0;
1210 /* Get channel public key list */
1211 tmp = silc_argument_get_arg_type(args, 16, &len);
1213 chpks = silc_argument_list_parse_decoded(tmp, len,
1214 SILC_ARGUMENT_PUBLIC_KEY);
1216 /* Set current channel */
1217 conn->current_channel = channel;
1219 cipher = (channel->internal.channel_key ?
1220 silc_cipher_get_name(channel->internal.channel_key) : NULL);
1221 silc_hash_table_list(channel->user_list, &htl);
1223 /* Notify application */
1224 silc_client_command_callback(cmd, channel_name, channel, mode, &htl,
1225 topic, cipher, hmac, channel->founder_key,
1226 chpks, channel->user_limit);
1229 silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
1230 silc_hash_table_list_reset(&htl);
1231 silc_client_unref_channel(client, conn, channel);
1234 silc_fsm_next(fsm, silc_client_command_reply_processed);
1235 return SILC_FSM_CONTINUE;
1238 /********************************** MOTD ************************************/
1240 /* Received reply for MOTD command */
1242 SILC_FSM_STATE(silc_client_command_reply_motd)
1244 SilcClientCommandContext cmd = fsm_context;
1245 SilcClientConnection conn = cmd->conn;
1246 SilcClient client = conn->client;
1247 SilcCommandPayload payload = state_context;
1248 SilcArgumentPayload args = silc_command_get_args(payload);
1250 char *motd = NULL, *cp, line[256];
1253 CHECK_STATUS("Cannot get motd: ");
1256 if (silc_argument_get_arg_num(args) == 3) {
1257 motd = silc_argument_get_arg_type(args, 3, NULL);
1259 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1266 if (cp[i++] == '\n') {
1267 memset(line, 0, sizeof(line));
1268 silc_strncat(line, sizeof(line), cp, i - 1);
1275 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1284 /* Notify application */
1285 silc_client_command_callback(cmd, motd);
1288 silc_fsm_next(fsm, silc_client_command_reply_processed);
1289 return SILC_FSM_CONTINUE;
1292 /********************************** UMODE ***********************************/
1294 /* Received reply to the UMODE command. Save the current user mode */
1296 SILC_FSM_STATE(silc_client_command_reply_umode)
1298 SilcClientCommandContext cmd = fsm_context;
1299 SilcClientConnection conn = cmd->conn;
1300 SilcCommandPayload payload = state_context;
1301 SilcArgumentPayload args = silc_command_get_args(payload);
1303 SilcUInt32 mode, len;
1306 CHECK_STATUS("Cannot change mode: ");
1309 tmp = silc_argument_get_arg_type(args, 2, &len);
1310 if (!tmp || len != 4) {
1311 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1315 SILC_GET32_MSB(mode, tmp);
1316 conn->local_entry->mode = mode;
1318 /* Notify application */
1319 silc_client_command_callback(cmd, mode);
1322 silc_fsm_next(fsm, silc_client_command_reply_processed);
1323 return SILC_FSM_CONTINUE;
1326 /********************************** CMODE ***********************************/
1328 /* Received reply for CMODE command. */
1330 SILC_FSM_STATE(silc_client_command_reply_cmode)
1332 SilcClientCommandContext cmd = fsm_context;
1333 SilcClientConnection conn = cmd->conn;
1334 SilcClient client = conn->client;
1335 SilcCommandPayload payload = state_context;
1336 SilcArgumentPayload args = silc_command_get_args(payload);
1339 SilcChannelEntry channel;
1341 SilcPublicKey public_key = NULL;
1342 SilcDList channel_pubkeys = NULL;
1346 CHECK_STATUS("Cannot change mode: ");
1349 /* Take Channel ID */
1350 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1351 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1355 /* Get the channel entry */
1356 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1358 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1362 /* Get channel mode */
1363 tmp = silc_argument_get_arg_type(args, 3, &len);
1364 if (!tmp || len != 4) {
1365 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1370 SILC_GET32_MSB(mode, tmp);
1371 channel->mode = mode;
1373 /* Get founder public key */
1374 tmp = silc_argument_get_arg_type(args, 4, &len);
1376 silc_public_key_payload_decode(tmp, len, &public_key);
1378 /* Get user limit */
1379 tmp = silc_argument_get_arg_type(args, 6, &len);
1380 if (tmp && len == 4)
1381 SILC_GET32_MSB(channel->user_limit, tmp);
1382 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1383 channel->user_limit = 0;
1385 /* Get channel public key(s) */
1386 tmp = silc_argument_get_arg_type(args, 5, &len);
1389 silc_argument_list_parse_decoded(tmp, len, SILC_ARGUMENT_PUBLIC_KEY);
1391 /* Notify application */
1392 silc_client_command_callback(cmd, channel, mode, public_key,
1393 channel_pubkeys, channel->user_limit);
1395 silc_argument_list_free(channel_pubkeys, SILC_ARGUMENT_PUBLIC_KEY);
1399 silc_pkcs_public_key_free(public_key);
1400 silc_fsm_next(fsm, silc_client_command_reply_processed);
1401 return SILC_FSM_CONTINUE;
1404 /********************************** CUMODE **********************************/
1406 /* Received reply for CUMODE command */
1408 SILC_FSM_STATE(silc_client_command_reply_cumode)
1410 SilcClientCommandContext cmd = fsm_context;
1411 SilcClientConnection conn = cmd->conn;
1412 SilcClient client = conn->client;
1413 SilcCommandPayload payload = state_context;
1414 SilcArgumentPayload args = silc_command_get_args(payload);
1415 SilcClientEntry client_entry;
1416 SilcChannelEntry channel;
1417 SilcChannelUser chu;
1418 unsigned char *modev;
1419 SilcUInt32 len, mode;
1423 CHECK_STATUS("Cannot change mode: ");
1426 /* Get channel mode */
1427 modev = silc_argument_get_arg_type(args, 2, &len);
1428 if (!modev || len != 4) {
1429 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1432 SILC_GET32_MSB(mode, modev);
1434 /* Take Channel ID */
1435 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1436 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1440 /* Get the channel entry */
1441 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1443 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1448 if (!silc_argument_get_decoded(args, 4, SILC_ARGUMENT_ID, &id, NULL)) {
1449 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1453 /* Get client entry */
1454 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1455 if (!client_entry) {
1456 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1461 chu = silc_client_on_channel(channel, client_entry);
1465 /* Notify application */
1466 silc_client_command_callback(cmd, mode, channel, client_entry);
1468 silc_client_unref_client(client, conn, client_entry);
1471 silc_fsm_next(fsm, silc_client_command_reply_processed);
1472 return SILC_FSM_CONTINUE;
1475 /********************************** KICK ************************************/
1477 SILC_FSM_STATE(silc_client_command_reply_kick)
1479 SilcClientCommandContext cmd = fsm_context;
1480 SilcClientConnection conn = cmd->conn;
1481 SilcClient client = conn->client;
1482 SilcCommandPayload payload = state_context;
1483 SilcArgumentPayload args = silc_command_get_args(payload);
1484 SilcClientEntry client_entry;
1485 SilcChannelEntry channel;
1489 CHECK_STATUS("Cannot kick: ");
1492 /* Take Channel ID */
1493 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1494 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1498 /* Get the channel entry */
1499 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1501 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1506 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1507 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1511 /* Get client entry */
1512 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1513 if (!client_entry) {
1514 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1518 /* Notify application */
1519 silc_client_command_callback(cmd, channel, client_entry);
1521 silc_client_unref_client(client, conn, client_entry);
1524 silc_fsm_next(fsm, silc_client_command_reply_processed);
1525 return SILC_FSM_CONTINUE;
1528 /******************************** SILCOPER **********************************/
1530 SILC_FSM_STATE(silc_client_command_reply_silcoper)
1532 SilcClientCommandContext cmd = fsm_context;
1533 SilcCommandPayload payload = state_context;
1534 SilcArgumentPayload args = silc_command_get_args(payload);
1537 CHECK_STATUS("Cannot change mode: ");
1540 /* Notify application */
1541 silc_client_command_callback(cmd);
1543 silc_fsm_next(fsm, silc_client_command_reply_processed);
1544 return SILC_FSM_CONTINUE;
1547 /********************************** OPER ************************************/
1549 SILC_FSM_STATE(silc_client_command_reply_oper)
1551 SilcClientCommandContext cmd = fsm_context;
1552 SilcCommandPayload payload = state_context;
1553 SilcArgumentPayload args = silc_command_get_args(payload);
1556 CHECK_STATUS("Cannot change mode: ");
1559 /* Notify application */
1560 silc_client_command_callback(cmd);
1562 silc_fsm_next(fsm, silc_client_command_reply_processed);
1563 return SILC_FSM_CONTINUE;
1566 /********************************* DETACH ***********************************/
1568 SILC_FSM_STATE(silc_client_command_reply_detach)
1570 SilcClientCommandContext cmd = fsm_context;
1571 SilcClientConnection conn = cmd->conn;
1572 SilcClient client = conn->client;
1573 SilcCommandPayload payload = state_context;
1574 SilcArgumentPayload args = silc_command_get_args(payload);
1578 CHECK_STATUS("Cannot detach: ");
1581 /* Notify application */
1582 silc_client_command_callback(cmd);
1585 /* Generate the detachment data and deliver it to the client in the
1586 detach client operation */
1587 detach = silc_client_get_detach_data(client, conn);
1589 client->internal->ops->detach(client, conn, silc_buffer_data(detach),
1590 silc_buffer_len(detach));
1591 silc_buffer_free(detach);
1595 silc_fsm_next(fsm, silc_client_command_reply_processed);
1596 return SILC_FSM_CONTINUE;
1599 /********************************** WATCH ***********************************/
1601 SILC_FSM_STATE(silc_client_command_reply_watch)
1603 SilcClientCommandContext cmd = fsm_context;
1604 SilcCommandPayload payload = state_context;
1605 SilcArgumentPayload args = silc_command_get_args(payload);
1608 CHECK_STATUS("Cannot set watch: ");
1611 /* Notify application */
1612 silc_client_command_callback(cmd);
1614 silc_fsm_next(fsm, silc_client_command_reply_processed);
1615 return SILC_FSM_CONTINUE;
1618 /*********************************** BAN ************************************/
1620 SILC_FSM_STATE(silc_client_command_reply_ban)
1622 SilcClientCommandContext cmd = fsm_context;
1623 SilcClientConnection conn = cmd->conn;
1624 SilcClient client = conn->client;
1625 SilcCommandPayload payload = state_context;
1626 SilcArgumentPayload args = silc_command_get_args(payload);
1627 SilcChannelEntry channel;
1630 SilcArgumentPayload invite_args = NULL;
1634 CHECK_STATUS("Cannot set ban: ");
1637 /* Take Channel ID */
1638 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1639 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1643 /* Get the channel entry */
1644 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1646 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1650 /* Get the invite list */
1651 tmp = silc_argument_get_arg_type(args, 3, &len);
1653 invite_args = silc_argument_list_parse(tmp, len);
1655 /* Notify application */
1656 silc_client_command_callback(cmd, channel, invite_args);
1659 silc_argument_payload_free(invite_args);
1662 silc_fsm_next(fsm, silc_client_command_reply_processed);
1663 return SILC_FSM_CONTINUE;
1666 /********************************** LEAVE ***********************************/
1668 /* Reply to LEAVE command. */
1670 SILC_FSM_STATE(silc_client_command_reply_leave)
1672 SilcClientCommandContext cmd = fsm_context;
1673 SilcClientConnection conn = cmd->conn;
1674 SilcClient client = conn->client;
1675 SilcCommandPayload payload = state_context;
1676 SilcArgumentPayload args = silc_command_get_args(payload);
1677 SilcChannelEntry channel;
1681 CHECK_STATUS("Cannot set leave: ");
1684 /* Get Channel ID */
1685 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1686 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1690 /* Get the channel entry */
1691 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1693 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1697 /* Remove us from this channel. */
1698 silc_client_remove_from_channel(channel, conn->local_entry);
1700 /* Notify application */
1701 silc_client_command_callback(cmd, channel);
1703 /* Now delete the channel. */
1704 silc_client_del_channel(client, conn, channel);
1707 silc_fsm_next(fsm, silc_client_command_reply_processed);
1708 return SILC_FSM_CONTINUE;
1711 /********************************* USERS ************************************/
1713 /* Continue USERS command reply processing after resolving unknown users */
1716 silc_client_command_reply_users_resolved(SilcClient client,
1717 SilcClientConnection conn,
1722 SilcClientCommandContext cmd = context;
1723 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1727 /* Continue USERS command after resolving unknown channel */
1730 silc_client_command_reply_users_continue(SilcClient client,
1731 SilcClientConnection conn,
1736 SilcClientCommandContext cmd = context;
1739 SilcCommandPayload payload = silc_fsm_get_state_context(&cmd->thread);
1740 SilcArgumentPayload args = silc_command_get_args(payload);
1742 cmd->status = SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID;
1743 ERROR_CALLBACK(cmd->status);
1744 silc_fsm_next(&cmd->thread, silc_client_command_reply_processed);
1747 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1750 /* Reply to USERS command. Received list of client ID's and theirs modes
1751 on the channel we requested. */
1753 SILC_FSM_STATE(silc_client_command_reply_users)
1755 SilcClientCommandContext cmd = fsm_context;
1756 SilcClientConnection conn = cmd->conn;
1757 SilcClient client = conn->client;
1758 SilcCommandPayload payload = state_context;
1759 SilcArgumentPayload args = silc_command_get_args(payload);
1761 SilcUInt32 tmp_len, list_count;
1762 SilcUInt16 idp_len, mode;
1763 SilcHashTableList htl;
1764 SilcBufferStruct client_id_list, client_mode_list;
1765 SilcChannelEntry channel;
1766 SilcClientEntry client_entry;
1771 CHECK_STATUS("Cannot get users: ");
1774 /* Get channel ID */
1775 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1776 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1780 /* Get channel entry */
1781 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1783 /* Resolve the channel from server */
1784 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1785 client, conn, &id.u.channel_id,
1786 silc_client_command_reply_users_continue, cmd));
1790 /* Get the list count */
1791 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1792 if (!tmp || tmp_len != 4) {
1793 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1796 SILC_GET32_MSB(list_count, tmp);
1798 /* Get Client ID list */
1799 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1801 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1804 silc_buffer_set(&client_id_list, tmp, tmp_len);
1806 /* Resolve users we do not know about */
1807 if (!cmd->resolved) {
1808 cmd->resolved = TRUE;
1809 SILC_FSM_CALL(silc_client_get_clients_by_list(
1810 client, conn, list_count, &client_id_list,
1811 silc_client_command_reply_users_resolved, cmd));
1815 /* Get client mode list */
1816 tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
1818 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1821 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1823 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1825 /* Cache the received Client ID's and modes. */
1826 for (i = 0; i < list_count; i++) {
1827 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1829 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1833 SILC_GET32_MSB(mode, client_mode_list.data);
1835 /* Save the client on this channel. Unknown clients are ignored as they
1836 clearly do not exist since the resolving didn't find them. */
1837 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1839 silc_client_add_to_channel(channel, client_entry, mode);
1840 silc_client_unref_client(client, conn, client_entry);
1842 if (!silc_buffer_pull(&client_id_list, idp_len))
1844 if (!silc_buffer_pull(&client_mode_list, 4))
1848 /* Notify application */
1849 silc_hash_table_list(channel->user_list, &htl);
1850 silc_client_command_callback(cmd, channel, &htl);
1851 silc_hash_table_list_reset(&htl);
1854 silc_fsm_next(fsm, silc_client_command_reply_processed);
1855 return SILC_FSM_CONTINUE;
1858 /********************************** GETKEY **********************************/
1860 /* Received command reply to GETKEY command. WE've received the remote
1861 client's public key. */
1863 SILC_FSM_STATE(silc_client_command_reply_getkey)
1865 SilcClientCommandContext cmd = fsm_context;
1866 SilcClientConnection conn = cmd->conn;
1867 SilcClient client = conn->client;
1868 SilcCommandPayload payload = state_context;
1869 SilcArgumentPayload args = silc_command_get_args(payload);
1870 SilcClientEntry client_entry;
1871 SilcServerEntry server_entry;
1874 SilcPublicKey public_key;
1878 CHECK_STATUS("Cannot get key: ");
1882 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1883 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1887 /* Get the public key */
1888 tmp = silc_argument_get_arg_type(args, 3, &len);
1890 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1893 if (!silc_public_key_payload_decode(tmp, len, &public_key)) {
1894 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1898 if (id.type == SILC_ID_CLIENT) {
1899 /* Received client's public key */
1900 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1901 if (!client_entry) {
1902 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1906 /* Save fingerprint */
1907 if (!client_entry->fingerprint)
1908 silc_hash_make(conn->internal->sha1hash, tmp + 4, len - 4,
1909 client_entry->fingerprint);
1910 if (!client_entry->public_key) {
1911 client_entry->public_key = public_key;
1915 /* Notify application */
1916 silc_client_command_callback(cmd, SILC_ID_CLIENT, client_entry,
1917 client_entry->public_key);
1918 silc_client_unref_client(client, conn, client_entry);
1919 } else if (id.type == SILC_ID_SERVER) {
1920 /* Received server's public key */
1921 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1922 if (!server_entry) {
1923 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1927 if (!server_entry->public_key) {
1928 server_entry->public_key = public_key;
1932 /* Notify application */
1933 silc_client_command_callback(cmd, SILC_ID_SERVER, server_entry,
1934 server_entry->public_key);
1939 silc_pkcs_public_key_free(public_key);
1940 silc_fsm_next(fsm, silc_client_command_reply_processed);
1941 return SILC_FSM_CONTINUE;
1944 /********************************** SERVICE *********************************/
1946 /* Reply to SERVICE command. */
1947 /* XXX incomplete */
1949 SILC_FSM_STATE(silc_client_command_reply_service)
1951 SilcClientCommandContext cmd = fsm_context;
1952 SilcCommandPayload payload = state_context;
1953 SilcArgumentPayload args = silc_command_get_args(payload);
1955 unsigned char *service_list, *name;
1958 CHECK_STATUS("Cannot get service: ");
1960 /* Get service list */
1961 service_list = silc_argument_get_arg_type(args, 2, &tmp_len);
1963 /* Get requested service name */
1964 name = silc_argument_get_arg_type(args, 3, &tmp_len);
1966 /* Notify application */
1967 silc_client_command_callback(cmd, service_list, name);
1969 silc_fsm_next(fsm, silc_client_command_reply_processed);
1970 return SILC_FSM_CONTINUE;
1973 /*********************************** QUIT ***********************************/
1975 /* QUIT command reply stub */
1977 SILC_FSM_STATE(silc_client_command_reply_quit)
1979 silc_fsm_next(fsm, silc_client_command_reply_processed);
1980 return SILC_FSM_CONTINUE;