5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2006 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
22 #include "silcclient.h"
23 #include "client_internal.h"
25 /************************** Types and definitions ***************************/
27 /* Calls error command reply callback back to command sender. */
28 #define ERROR_CALLBACK(error) \
30 void *arg1 = NULL, *arg2 = NULL; \
31 if (cmd->status != SILC_STATUS_OK) \
32 silc_status_get_args(cmd->status, args, &arg1, &arg2); \
34 cmd->status = error; \
35 SILC_LOG_DEBUG(("Error in command reply: %s", \
36 silc_get_status_message(cmd->status))); \
37 silc_client_command_callback(cmd, arg1, arg2); \
41 #define CHECK_STATUS(msg) \
42 SILC_LOG_DEBUG(("%s", silc_get_command_name(cmd->cmd))); \
43 if (cmd->error != SILC_STATUS_OK) { \
45 SAY(cmd->conn->client, cmd->conn, SILC_CLIENT_MESSAGE_ERROR, \
46 msg "%s", silc_get_status_message(cmd->error)); \
47 ERROR_CALLBACK(cmd->error); \
48 silc_client_command_process_error(cmd, state_context, cmd->error); \
49 silc_fsm_next(fsm, silc_client_command_reply_processed); \
50 return SILC_FSM_CONTINUE; \
53 /* Check for correct arguments */
54 #define CHECK_ARGS(min, max) \
55 if (silc_argument_get_arg_num(args) < min || \
56 silc_argument_get_arg_num(args) > max) { \
57 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); \
58 silc_fsm_next(fsm, silc_client_command_reply_processed); \
59 return SILC_FSM_CONTINUE; \
62 #define SAY cmd->conn->client->internal->ops->say
64 /************************ Static utility functions **************************/
66 /* Delivers the command reply back to application */
69 silc_client_command_callback(SilcClientCommandContext cmd, ...)
71 SilcClientCommandReplyCallback cb;
76 /* Default reply callback */
79 cmd->conn->client->internal->ops->command_reply(
80 cmd->conn->client, cmd->conn, cmd->cmd, cmd->status,
86 silc_list_start(cmd->reply_callbacks);
87 while ((cb = silc_list_get(cmd->reply_callbacks)))
88 if (!cb->do_not_call) {
90 cb->do_not_call = !cb->reply(cmd->conn->client, cmd->conn, cmd->cmd,
91 cmd->status, cmd->error, cb->context, cp);
98 /* Handles common error status types. */
100 static void silc_client_command_process_error(SilcClientCommandContext cmd,
101 SilcCommandPayload payload,
104 SilcClient client = cmd->conn->client;
105 SilcClientConnection conn = cmd->conn;
106 SilcArgumentPayload args = silc_command_get_args(payload);
107 SilcClientEntry client_entry;
110 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
111 /* Remove unknown client entry from cache */
112 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
115 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
117 silc_client_unref_client(client, conn, client_entry);
118 silc_client_del_client(client, conn, client_entry);
123 /***************************** Command Reply ********************************/
125 /* Process received command reply packet */
127 SILC_FSM_STATE(silc_client_command_reply)
129 SilcClientConnection conn = fsm_context;
130 SilcPacket packet = state_context;
131 SilcClientCommandContext cmd;
132 SilcCommandPayload payload;
134 SilcUInt16 cmd_ident;
136 /* Get command reply payload from packet */
137 payload = silc_command_payload_parse(silc_buffer_datalen(&packet->buffer));
138 silc_packet_free(packet);
140 SILC_LOG_DEBUG(("Bad command reply packet"));
141 return SILC_FSM_FINISH;
144 cmd_ident = silc_command_get_ident(payload);
145 command = silc_command_get(payload);
147 /* Find the command pending reply */
148 silc_mutex_lock(conn->internal->lock);
149 silc_list_start(conn->internal->pending_commands);
150 while ((cmd = silc_list_get(conn->internal->pending_commands))) {
151 if ((cmd->cmd == command || cmd->cmd == SILC_COMMAND_NONE)
152 && cmd->cmd_ident == cmd_ident) {
153 silc_list_del(conn->internal->pending_commands, cmd);
157 silc_mutex_unlock(conn->internal->lock);
160 SILC_LOG_DEBUG(("Unknown command reply %s, ident %d",
161 silc_get_command_name(command), cmd_ident));
162 silc_command_payload_free(payload);
163 return SILC_FSM_FINISH;
166 /* Signal command thread that command reply has arrived */
167 silc_fsm_set_state_context(&cmd->thread, payload);
168 silc_fsm_next(&cmd->thread, silc_client_command_reply_process);
169 silc_fsm_continue_sync(&cmd->thread);
171 return SILC_FSM_FINISH;
174 /* Wait here for command reply to arrive from remote host */
176 SILC_FSM_STATE(silc_client_command_reply_wait)
178 SILC_LOG_DEBUG(("Wait for command reply"));
180 /** Wait for command reply */
181 silc_fsm_set_state_context(fsm, NULL);
182 silc_fsm_next_later(fsm, silc_client_command_reply_timeout, 20, 0);
183 return SILC_FSM_WAIT;
186 /* Timeout occurred while waiting command reply */
188 SILC_FSM_STATE(silc_client_command_reply_timeout)
190 SilcClientCommandContext cmd = fsm_context;
191 SilcArgumentPayload args = NULL;
193 /* Timeout, reply not received in timely fashion */
194 ERROR_CALLBACK(SILC_STATUS_ERR_TIMEDOUT);
195 return SILC_FSM_FINISH;
198 /* Process received command reply payload */
200 SILC_FSM_STATE(silc_client_command_reply_process)
202 SilcClientCommandContext cmd = fsm_context;
203 SilcCommandPayload payload = state_context;
205 silc_command_get_status(payload, &cmd->status, &cmd->error);
208 case SILC_COMMAND_WHOIS:
210 silc_fsm_next(fsm, silc_client_command_reply_whois);
212 case SILC_COMMAND_WHOWAS:
214 silc_fsm_next(fsm, silc_client_command_reply_whowas);
216 case SILC_COMMAND_IDENTIFY:
218 silc_fsm_next(fsm, silc_client_command_reply_identify);
220 case SILC_COMMAND_NICK:
222 silc_fsm_next(fsm, silc_client_command_reply_nick);
224 case SILC_COMMAND_LIST:
226 silc_fsm_next(fsm, silc_client_command_reply_list);
228 case SILC_COMMAND_TOPIC:
230 silc_fsm_next(fsm, silc_client_command_reply_topic);
232 case SILC_COMMAND_INVITE:
234 silc_fsm_next(fsm, silc_client_command_reply_invite);
236 case SILC_COMMAND_QUIT:
238 silc_fsm_next(fsm, silc_client_command_reply_quit);
240 case SILC_COMMAND_KILL:
242 silc_fsm_next(fsm, silc_client_command_reply_kill);
244 case SILC_COMMAND_INFO:
246 silc_fsm_next(fsm, silc_client_command_reply_info);
248 case SILC_COMMAND_STATS:
250 silc_fsm_next(fsm, silc_client_command_reply_stats);
252 case SILC_COMMAND_PING:
254 silc_fsm_next(fsm, silc_client_command_reply_ping);
256 case SILC_COMMAND_OPER:
258 silc_fsm_next(fsm, silc_client_command_reply_oper);
260 case SILC_COMMAND_JOIN:
262 silc_fsm_next(fsm, silc_client_command_reply_join);
264 case SILC_COMMAND_MOTD:
266 silc_fsm_next(fsm, silc_client_command_reply_motd);
268 case SILC_COMMAND_UMODE:
270 silc_fsm_next(fsm, silc_client_command_reply_umode);
272 case SILC_COMMAND_CMODE:
274 silc_fsm_next(fsm, silc_client_command_reply_cmode);
276 case SILC_COMMAND_CUMODE:
278 silc_fsm_next(fsm, silc_client_command_reply_cumode);
280 case SILC_COMMAND_KICK:
282 silc_fsm_next(fsm, silc_client_command_reply_kick);
284 case SILC_COMMAND_BAN:
286 silc_fsm_next(fsm, silc_client_command_reply_ban);
288 case SILC_COMMAND_DETACH:
290 silc_fsm_next(fsm, silc_client_command_reply_detach);
292 case SILC_COMMAND_WATCH:
294 silc_fsm_next(fsm, silc_client_command_reply_watch);
296 case SILC_COMMAND_SILCOPER:
298 silc_fsm_next(fsm, silc_client_command_reply_silcoper);
300 case SILC_COMMAND_LEAVE:
302 silc_fsm_next(fsm, silc_client_command_reply_leave);
304 case SILC_COMMAND_USERS:
306 silc_fsm_next(fsm, silc_client_command_reply_users);
308 case SILC_COMMAND_GETKEY:
310 silc_fsm_next(fsm, silc_client_command_reply_getkey);
312 case SILC_COMMAND_SERVICE:
314 silc_fsm_next(fsm, silc_client_command_reply_service);
317 return SILC_FSM_FINISH;
320 return SILC_FSM_CONTINUE;
323 /* Completes command reply processing */
325 SILC_FSM_STATE(silc_client_command_reply_processed)
327 SilcClientCommandContext cmd = fsm_context;
328 SilcClientConnection conn = cmd->conn;
329 SilcCommandPayload payload = state_context;
331 silc_command_payload_free(payload);
333 if (cmd->status == SILC_STATUS_OK || cmd->status == SILC_STATUS_LIST_END ||
334 SILC_STATUS_IS_ERROR(cmd->status))
335 return SILC_FSM_FINISH;
337 /* Add back to pending command reply list */
338 silc_mutex_lock(conn->internal->lock);
339 cmd->resolved = FALSE;
340 silc_list_add(conn->internal->pending_commands, cmd);
341 silc_mutex_unlock(conn->internal->lock);
343 /** Wait more command payloads */
344 silc_fsm_next(fsm, silc_client_command_reply_wait);
345 return SILC_FSM_CONTINUE;
348 /******************************** WHOIS *************************************/
350 /* Received reply for WHOIS command. */
352 SILC_FSM_STATE(silc_client_command_reply_whois)
354 SilcClientCommandContext cmd = fsm_context;
355 SilcClientConnection conn = cmd->conn;
356 SilcClient client = conn->client;
357 SilcCommandPayload payload = state_context;
358 SilcArgumentPayload args = silc_command_get_args(payload);
359 SilcClientEntry client_entry = NULL;
360 SilcUInt32 idle = 0, mode = 0, fingerprint_len, len, *umodes = NULL;
361 SilcBufferStruct channels, ch_user_modes;
362 SilcBool has_channels = FALSE;
363 SilcDList channel_list = NULL;
365 char *nickname = NULL, *username = NULL, *realname = NULL;
366 unsigned char *fingerprint, *tmp;
368 CHECK_STATUS("WHOIS: ");
372 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
373 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
378 nickname = silc_argument_get_arg_type(args, 3, NULL);
379 username = silc_argument_get_arg_type(args, 4, NULL);
380 realname = silc_argument_get_arg_type(args, 5, NULL);
381 if (!nickname || !username || !realname) {
382 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
386 /* Get joined channel list */
387 memset(&channels, 0, sizeof(channels));
388 tmp = silc_argument_get_arg_type(args, 6, &len);
391 silc_buffer_set(&channels, tmp, len);
393 /* Get channel user mode list */
394 tmp = silc_argument_get_arg_type(args, 10, &len);
396 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
399 silc_buffer_set(&ch_user_modes, tmp, len);
403 tmp = silc_argument_get_arg_type(args, 7, &len);
405 SILC_GET32_MSB(mode, tmp);
408 tmp = silc_argument_get_arg_type(args, 8, &len);
410 SILC_GET32_MSB(idle, tmp);
412 /* Get fingerprint */
413 fingerprint = silc_argument_get_arg_type(args, 9, &fingerprint_len);
415 /* Check if we have this client cached already. */
416 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
418 SILC_LOG_DEBUG(("Adding new client entry (WHOIS)"));
420 silc_client_add_client(client, conn, nickname, username, realname,
421 &id.u.client_id, mode);
423 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
426 silc_client_ref_client(client, conn, client_entry);
428 silc_client_update_client(client, conn, client_entry,
429 nickname, username, realname, mode);
432 if (fingerprint && fingerprint_len == sizeof(client_entry->fingerprint))
433 memcpy(client_entry->fingerprint, fingerprint, fingerprint_len);
435 /* Get user attributes */
436 tmp = silc_argument_get_arg_type(args, 11, &len);
438 if (client_entry->attrs)
439 silc_attribute_payload_list_free(client_entry->attrs);
440 client_entry->attrs = silc_attribute_payload_parse(tmp, len);
443 /* Parse channel and channel user mode list */
445 channel_list = silc_channel_payload_parse_list(silc_buffer_data(&channels),
446 silc_buffer_len(&channels));
448 silc_get_mode_list(&ch_user_modes, silc_dlist_count(channel_list),
452 /* Notify application */
453 silc_client_command_callback(cmd, client_entry, nickname, username,
454 realname, channel_list, mode, idle, fingerprint,
455 umodes, client_entry->attrs);
457 silc_client_unref_client(client, conn, client_entry);
459 silc_dlist_uninit(channel_list);
464 silc_fsm_next(fsm, silc_client_command_reply_processed);
465 return SILC_FSM_CONTINUE;
468 /******************************** WHOWAS ************************************/
470 /* Received reply for WHOWAS command. */
472 SILC_FSM_STATE(silc_client_command_reply_whowas)
474 SilcClientCommandContext cmd = fsm_context;
475 SilcClientConnection conn = cmd->conn;
476 SilcClient client = conn->client;
477 SilcCommandPayload payload = state_context;
478 SilcArgumentPayload args = silc_command_get_args(payload);
479 SilcClientEntry client_entry = NULL;
481 char *nickname, *username;
482 char *realname = NULL;
484 CHECK_STATUS("WHOWAS: ");
488 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
489 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
493 /* Get the client entry */
494 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
497 nickname = silc_argument_get_arg_type(args, 3, NULL);
498 username = silc_argument_get_arg_type(args, 4, NULL);
499 realname = silc_argument_get_arg_type(args, 5, NULL);
500 if (!nickname || !username) {
501 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
505 /* Notify application. We don't save any history information to any
506 cache. Just pass the data to the application. */
507 silc_client_command_callback(cmd, client_entry, nickname, username,
511 silc_client_unref_client(client, conn, client_entry);
512 silc_fsm_next(fsm, silc_client_command_reply_processed);
513 return SILC_FSM_CONTINUE;
516 /******************************** IDENTIFY **********************************/
518 /* Received reply for IDENTIFY command. */
520 SILC_FSM_STATE(silc_client_command_reply_identify)
522 SilcClientCommandContext cmd = fsm_context;
523 SilcClientConnection conn = cmd->conn;
524 SilcClient client = conn->client;
525 SilcCommandPayload payload = state_context;
526 SilcArgumentPayload args = silc_command_get_args(payload);
527 SilcClientEntry client_entry;
528 SilcServerEntry server_entry;
529 SilcChannelEntry channel_entry;
532 char *name = NULL, *info = NULL;
534 CHECK_STATUS("IDENTIFY: ");
538 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
539 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
544 name = silc_argument_get_arg_type(args, 3, &len);
545 info = silc_argument_get_arg_type(args, 4, &len);
549 SILC_LOG_DEBUG(("Received client information"));
551 /* Check if we have this client cached already. */
552 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
554 SILC_LOG_DEBUG(("Adding new client entry (IDENTIFY)"));
556 silc_client_add_client(client, conn, name, info, NULL,
559 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
562 silc_client_ref_client(client, conn, client_entry);
564 silc_client_update_client(client, conn, client_entry,
565 name, info, NULL, 0);
568 /* Notify application */
569 silc_client_command_callback(cmd, client_entry, name, info);
570 silc_client_unref_client(client, conn, client_entry);
574 SILC_LOG_DEBUG(("Received server information"));
576 /* Check if we have this server cached already. */
577 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
579 SILC_LOG_DEBUG(("Adding new server entry (IDENTIFY)"));
580 server_entry = silc_client_add_server(client, conn, name, info,
583 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
586 silc_client_ref_server(client, conn, server_entry);
588 silc_client_update_server(client, conn, server_entry, name, info);
590 server_entry->internal.resolve_cmd_ident = 0;
592 /* Notify application */
593 silc_client_command_callback(cmd, server_entry, name, info);
594 silc_client_unref_server(client, conn, server_entry);
597 case SILC_ID_CHANNEL:
598 SILC_LOG_DEBUG(("Received channel information"));
600 /* Check if we have this channel cached already. */
601 channel_entry = silc_client_get_channel_by_id(client, conn,
603 if (!channel_entry) {
604 SILC_LOG_DEBUG(("Adding new channel entry (IDENTIFY"));
607 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
611 /* Add new channel entry */
612 channel_entry = silc_client_add_channel(client, conn, name, 0,
614 if (!channel_entry) {
615 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
618 silc_client_ref_channel(client, conn, channel_entry);
621 /* Notify application */
622 silc_client_command_callback(cmd, channel_entry, name, info);
623 silc_client_unref_channel(client, conn, channel_entry);
628 silc_fsm_next(fsm, silc_client_command_reply_processed);
629 return SILC_FSM_CONTINUE;
632 /********************************** NICK ************************************/
634 /* Received reply for command NICK. */
636 SILC_FSM_STATE(silc_client_command_reply_nick)
638 SilcClientCommandContext cmd = fsm_context;
639 SilcClientConnection conn = cmd->conn;
640 SilcClient client = conn->client;
641 SilcCommandPayload payload = state_context;
642 SilcArgumentPayload args = silc_command_get_args(payload);
643 unsigned char *tmp, *nick, *idp;
644 SilcUInt32 len, idp_len;
645 SilcClientID old_client_id;
649 CHECK_STATUS("Cannot set nickname: ");
652 old_client_id = *conn->local_id;
654 /* Take received Client ID */
655 idp = silc_argument_get_arg_type(args, 2, &idp_len);
657 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
660 if (!silc_id_payload_parse_id(idp, idp_len, &id)) {
661 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
665 /* Take the new nickname */
666 nick = silc_argument_get_arg_type(args, 3, &len);
668 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
672 /* Normalize nickname */
673 tmp = silc_identifier_check(nick, len, SILC_STRING_UTF8, 128, NULL);
675 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_NICKNAME);
679 /* Update the client entry */
680 silc_mutex_lock(conn->internal->lock);
681 if (!silc_idcache_update(conn->internal->client_cache,
682 conn->internal->local_entry,
683 &conn->local_entry->id,
685 conn->local_entry->nickname_normalized,
688 silc_mutex_unlock(conn->internal->lock);
689 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_NICKNAME);
692 silc_mutex_unlock(conn->internal->lock);
693 memset(conn->local_entry->nickname, 0, sizeof(conn->local_entry->nickname));
694 memcpy(conn->local_entry->nickname, nick, len);
695 conn->local_entry->nickname_normalized = tmp;
696 silc_buffer_enlarge(conn->internal->local_idp, idp_len);
697 silc_buffer_put(conn->internal->local_idp, idp, idp_len);
698 silc_client_nickname_format(client, conn, conn->local_entry);
699 silc_packet_set_ids(conn->stream, SILC_ID_CLIENT, conn->local_id, 0, NULL);
701 /* Notify application */
702 silc_client_command_callback(cmd, conn->local_entry,
703 conn->local_entry->nickname, &old_client_id);
706 silc_fsm_next(fsm, silc_client_command_reply_processed);
707 return SILC_FSM_CONTINUE;
710 /********************************** LIST ************************************/
712 /* Received reply to the LIST command. */
714 SILC_FSM_STATE(silc_client_command_reply_list)
716 SilcClientCommandContext cmd = fsm_context;
717 SilcClientConnection conn = cmd->conn;
718 SilcClient client = conn->client;
719 SilcCommandPayload payload = state_context;
720 SilcArgumentPayload args = silc_command_get_args(payload);
721 unsigned char *tmp, *name, *topic;
722 SilcUInt32 usercount = 0;
723 SilcChannelEntry channel_entry = NULL;
727 CHECK_STATUS("Cannot list channels: ");
729 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
730 /* There were no channels in the network. */
731 silc_client_command_callback(cmd, NULL, NULL, NULL, 0);
732 silc_fsm_next(fsm, silc_client_command_reply_processed);
733 return SILC_FSM_CONTINUE;
738 name = silc_argument_get_arg_type(args, 3, NULL);
740 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
744 topic = silc_argument_get_arg_type(args, 4, NULL);
745 tmp = silc_argument_get_arg_type(args, 5, NULL);
747 SILC_GET32_MSB(usercount, tmp);
749 /* Check whether the channel exists, and add it to cache if it doesn't. */
750 channel_entry = silc_client_get_channel_by_id(client, conn,
752 if (!channel_entry) {
753 /* Add new channel entry */
754 channel_entry = silc_client_add_channel(client, conn, name, 0,
756 if (!channel_entry) {
757 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
760 silc_client_ref_channel(client, conn, channel_entry);
763 /* Notify application */
764 silc_client_command_callback(cmd, channel_entry, name, topic, usercount);
767 silc_client_unref_channel(client, conn, channel_entry);
768 silc_fsm_next(fsm, silc_client_command_reply_processed);
769 return SILC_FSM_CONTINUE;
772 /********************************* TOPIC ************************************/
774 /* Received reply to topic command. */
776 SILC_FSM_STATE(silc_client_command_reply_topic)
778 SilcClientCommandContext cmd = fsm_context;
779 SilcClientConnection conn = cmd->conn;
780 SilcClient client = conn->client;
781 SilcCommandPayload payload = state_context;
782 SilcArgumentPayload args = silc_command_get_args(payload);
783 SilcChannelEntry channel;
789 CHECK_STATUS("Cannot set topic: ");
792 /* Take Channel ID */
793 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
794 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
798 /* Get the channel entry */
799 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
801 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
806 topic = silc_argument_get_arg_type(args, 3, &len);
808 silc_free(channel->topic);
809 channel->topic = silc_memdup(topic, len);
812 /* Notify application */
813 silc_client_command_callback(cmd, channel, channel->topic);
816 silc_fsm_next(fsm, silc_client_command_reply_processed);
817 return SILC_FSM_CONTINUE;
820 /********************************* INVITE ***********************************/
822 /* Received reply to invite command. */
824 SILC_FSM_STATE(silc_client_command_reply_invite)
826 SilcClientCommandContext cmd = fsm_context;
827 SilcClientConnection conn = cmd->conn;
828 SilcClient client = conn->client;
829 SilcCommandPayload payload = state_context;
830 SilcArgumentPayload args = silc_command_get_args(payload);
831 SilcChannelEntry channel;
834 SilcArgumentPayload invite_args = NULL;
838 CHECK_STATUS("Cannot invite: ");
841 /* Take Channel ID */
842 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
843 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
847 /* Get the channel entry */
848 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
850 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
854 /* Get the invite list */
855 tmp = silc_argument_get_arg_type(args, 3, &len);
857 invite_args = silc_argument_list_parse(tmp, len);
859 /* Notify application */
860 silc_client_command_callback(cmd, channel, invite_args);
863 silc_argument_payload_free(invite_args);
866 silc_fsm_next(fsm, silc_client_command_reply_processed);
867 return SILC_FSM_CONTINUE;
870 /********************************** KILL ************************************/
872 /* Received reply to the KILL command. */
874 SILC_FSM_STATE(silc_client_command_reply_kill)
876 SilcClientCommandContext cmd = fsm_context;
877 SilcClientConnection conn = cmd->conn;
878 SilcClient client = conn->client;
879 SilcCommandPayload payload = state_context;
880 SilcArgumentPayload args = silc_command_get_args(payload);
881 SilcClientEntry client_entry;
885 CHECK_STATUS("Cannot kill: ");
888 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
889 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
893 /* Get the client entry, if exists */
894 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
896 /* Notify application */
897 silc_client_command_callback(cmd, client_entry);
899 /* Remove the client from all channels and free it */
901 silc_client_del_client(client, conn, client_entry);
902 silc_client_unref_client(client, conn, client_entry);
906 silc_fsm_next(fsm, silc_client_command_reply_processed);
907 return SILC_FSM_CONTINUE;
910 /********************************** INFO ************************************/
912 /* Received reply to INFO command. We receive the server ID and some
913 information about the server user requested. */
915 SILC_FSM_STATE(silc_client_command_reply_info)
917 SilcClientCommandContext cmd = fsm_context;
918 SilcClientConnection conn = cmd->conn;
919 SilcClient client = conn->client;
920 SilcCommandPayload payload = state_context;
921 SilcArgumentPayload args = silc_command_get_args(payload);
922 SilcServerEntry server;
923 char *server_name, *server_info;
927 CHECK_STATUS("Cannot get info: ");
931 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
932 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
936 /* Get server name */
937 server_name = silc_argument_get_arg_type(args, 3, NULL);
939 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
943 /* Get server info */
944 server_info = silc_argument_get_arg_type(args, 4, NULL);
946 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
950 /* See whether we have this server cached. If not create it. */
951 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
953 SILC_LOG_DEBUG(("New server entry"));
954 server = silc_client_add_server(client, conn, server_name,
955 server_info, &id.u.server_id);
960 /* Notify application */
961 silc_client_command_callback(cmd, server, server->server_name,
962 server->server_info);
965 silc_fsm_next(fsm, silc_client_command_reply_processed);
966 return SILC_FSM_CONTINUE;
969 /********************************** STATS ***********************************/
971 /* Received reply to STATS command. */
973 SILC_FSM_STATE(silc_client_command_reply_stats)
975 SilcClientCommandContext cmd = fsm_context;
976 SilcCommandPayload payload = state_context;
977 SilcArgumentPayload args = silc_command_get_args(payload);
978 SilcClientStats stats;
979 unsigned char *buf = NULL;
980 SilcUInt32 buf_len = 0;
985 CHECK_STATUS("Cannot get stats: ");
989 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
990 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
994 /* Get statistics structure */
995 memset(&stats, 0, sizeof(stats));
996 buf = silc_argument_get_arg_type(args, 3, &buf_len);
998 silc_buffer_set(&b, buf, buf_len);
999 silc_buffer_unformat(&b,
1000 SILC_STR_UI_INT(&stats.starttime),
1001 SILC_STR_UI_INT(&stats.uptime),
1002 SILC_STR_UI_INT(&stats.my_clients),
1003 SILC_STR_UI_INT(&stats.my_channels),
1004 SILC_STR_UI_INT(&stats.my_server_ops),
1005 SILC_STR_UI_INT(&stats.my_router_ops),
1006 SILC_STR_UI_INT(&stats.cell_clients),
1007 SILC_STR_UI_INT(&stats.cell_channels),
1008 SILC_STR_UI_INT(&stats.cell_servers),
1009 SILC_STR_UI_INT(&stats.clients),
1010 SILC_STR_UI_INT(&stats.channels),
1011 SILC_STR_UI_INT(&stats.servers),
1012 SILC_STR_UI_INT(&stats.routers),
1013 SILC_STR_UI_INT(&stats.server_ops),
1014 SILC_STR_UI_INT(&stats.router_ops),
1018 /* Notify application */
1019 silc_client_command_callback(cmd, &stats);
1022 silc_fsm_next(fsm, silc_client_command_reply_processed);
1023 return SILC_FSM_CONTINUE;
1026 /********************************** PING ************************************/
1028 /* Received reply to PING command. */
1030 SILC_FSM_STATE(silc_client_command_reply_ping)
1032 SilcClientCommandContext cmd = fsm_context;
1033 SilcClientConnection conn = cmd->conn;
1034 SilcClient client = conn->client;
1037 diff = silc_time() - SILC_PTR_TO_64(cmd->context);
1039 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO,
1040 "Ping reply from %s: %d second%s", conn->remote_host,
1041 (int)diff, diff == 1 ? "" : "s");
1043 /* Notify application */
1044 silc_client_command_callback(cmd);
1046 silc_fsm_next(fsm, silc_client_command_reply_processed);
1047 return SILC_FSM_CONTINUE;
1050 /********************************** JOIN ************************************/
1052 /* Continue JOIN command reply processing after resolving unknown users */
1055 silc_client_command_reply_join_resolved(SilcClient client,
1056 SilcClientConnection conn,
1061 SilcClientCommandContext cmd = context;
1062 SilcChannelEntry channel = cmd->context;
1064 channel->internal.resolve_cmd_ident = 0;
1065 silc_client_unref_channel(client, conn, channel);
1067 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1071 /* Received reply for JOIN command. */
1073 SILC_FSM_STATE(silc_client_command_reply_join)
1075 SilcClientCommandContext cmd = fsm_context;
1076 SilcClientConnection conn = cmd->conn;
1077 SilcClient client = conn->client;
1078 SilcCommandPayload payload = state_context;
1079 SilcArgumentPayload args = silc_command_get_args(payload);
1080 SilcChannelEntry channel;
1081 SilcUInt32 mode = 0, len, list_count;
1082 char *topic, *tmp, *channel_name = NULL, *hmac;
1084 SilcBufferStruct client_id_list, client_mode_list, keyp;
1085 SilcHashTableList htl;
1086 SilcDList chpks = NULL;
1091 CHECK_STATUS("Cannot join channel: ");
1094 /* Get channel name */
1095 channel_name = silc_argument_get_arg_type(args, 2, NULL);
1096 if (!channel_name) {
1097 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1101 /* Get Channel ID */
1102 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1103 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1107 /* Check whether we have this channel entry already. */
1108 channel = silc_client_get_channel(client, conn, channel_name);
1110 if (!SILC_ID_CHANNEL_COMPARE(&channel->id, &id.u.channel_id))
1111 silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id);
1113 /* Create new channel entry */
1114 channel = silc_client_add_channel(client, conn, channel_name,
1115 mode, &id.u.channel_id);
1117 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_CHANNEL);
1120 silc_client_ref_channel(client, conn, channel);
1123 /* Get the list count */
1124 tmp = silc_argument_get_arg_type(args, 12, &len);
1126 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1129 SILC_GET32_MSB(list_count, tmp);
1131 /* Get Client ID list */
1132 tmp = silc_argument_get_arg_type(args, 13, &len);
1134 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1137 silc_buffer_set(&client_id_list, tmp, len);
1139 /* Resolve users we do not know about */
1140 if (!cmd->resolved) {
1141 cmd->resolved = TRUE;
1142 cmd->context = channel;
1143 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1144 silc_client_get_clients_by_list(
1145 client, conn, list_count, &client_id_list,
1146 silc_client_command_reply_join_resolved, cmd));
1150 /* Get client mode list */
1151 tmp = silc_argument_get_arg_type(args, 14, &len);
1153 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1156 silc_buffer_set(&client_mode_list, tmp, len);
1158 /* Add clients we received in the reply to the channel */
1159 for (i = 0; i < list_count; i++) {
1163 SilcClientEntry client_entry;
1166 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1168 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1172 SILC_GET32_MSB(mode, client_mode_list.data);
1174 SILC_LOG_DEBUG(("id %s", silc_id_render(&id.u.client_id, SILC_ID_CLIENT)));
1176 /* Get client entry */
1177 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1181 /* Join client to the channel */
1182 silc_client_add_to_channel(channel, client_entry, mode);
1183 silc_client_unref_client(client, conn, client_entry);
1185 if (!silc_buffer_pull(&client_id_list, idp_len))
1187 if (!silc_buffer_pull(&client_mode_list, 4))
1192 hmac = silc_argument_get_arg_type(args, 11, NULL);
1194 if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) {
1196 SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1197 "Cannot join channel: Unsupported HMAC `%s'", hmac);
1198 ERROR_CALLBACK(SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
1203 /* Get channel mode */
1204 tmp = silc_argument_get_arg_type(args, 5, NULL);
1206 SILC_GET32_MSB(mode, tmp);
1207 channel->mode = mode;
1209 /* Get channel key and save it */
1210 tmp = silc_argument_get_arg_type(args, 7, &len);
1212 silc_buffer_set(&keyp, tmp, len);
1213 silc_client_save_channel_key(client, conn, &keyp, channel);
1217 topic = silc_argument_get_arg_type(args, 10, NULL);
1219 silc_free(channel->topic);
1220 channel->topic = silc_memdup(topic, strlen(topic));
1223 /* Get founder key */
1224 tmp = silc_argument_get_arg_type(args, 15, &len);
1226 if (channel->founder_key)
1227 silc_pkcs_public_key_free(channel->founder_key);
1228 channel->founder_key = NULL;
1229 silc_public_key_payload_decode(tmp, len, &channel->founder_key);
1232 /* Get user limit */
1233 tmp = silc_argument_get_arg_type(args, 17, &len);
1234 if (tmp && len == 4)
1235 SILC_GET32_MSB(channel->user_limit, tmp);
1236 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1237 channel->user_limit = 0;
1239 /* Get channel public key list */
1240 tmp = silc_argument_get_arg_type(args, 16, &len);
1242 chpks = silc_argument_list_parse_decoded(tmp, len,
1243 SILC_ARGUMENT_PUBLIC_KEY);
1245 /* Set current channel */
1246 conn->current_channel = channel;
1248 cipher = (channel->internal.channel_key ?
1249 silc_cipher_get_name(channel->internal.channel_key) : NULL);
1250 silc_hash_table_list(channel->user_list, &htl);
1252 /* Notify application */
1253 silc_client_command_callback(cmd, channel_name, channel, mode, &htl,
1254 topic, cipher, hmac, channel->founder_key,
1255 chpks, channel->user_limit);
1258 silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
1259 silc_hash_table_list_reset(&htl);
1260 silc_client_unref_channel(client, conn, channel);
1263 silc_fsm_next(fsm, silc_client_command_reply_processed);
1264 return SILC_FSM_CONTINUE;
1267 /********************************** MOTD ************************************/
1269 /* Received reply for MOTD command */
1271 SILC_FSM_STATE(silc_client_command_reply_motd)
1273 SilcClientCommandContext cmd = fsm_context;
1274 SilcClientConnection conn = cmd->conn;
1275 SilcClient client = conn->client;
1276 SilcCommandPayload payload = state_context;
1277 SilcArgumentPayload args = silc_command_get_args(payload);
1279 char *motd = NULL, *cp, line[256];
1282 CHECK_STATUS("Cannot get motd: ");
1285 if (silc_argument_get_arg_num(args) == 3) {
1286 motd = silc_argument_get_arg_type(args, 3, NULL);
1288 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1295 if (cp[i++] == '\n') {
1296 memset(line, 0, sizeof(line));
1297 silc_strncat(line, sizeof(line), cp, i - 1);
1304 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1313 /* Notify application */
1314 silc_client_command_callback(cmd, motd);
1317 silc_fsm_next(fsm, silc_client_command_reply_processed);
1318 return SILC_FSM_CONTINUE;
1321 /********************************** UMODE ***********************************/
1323 /* Received reply to the UMODE command. Save the current user mode */
1325 SILC_FSM_STATE(silc_client_command_reply_umode)
1327 SilcClientCommandContext cmd = fsm_context;
1328 SilcClientConnection conn = cmd->conn;
1329 SilcCommandPayload payload = state_context;
1330 SilcArgumentPayload args = silc_command_get_args(payload);
1332 SilcUInt32 mode, len;
1335 CHECK_STATUS("Cannot change mode: ");
1338 tmp = silc_argument_get_arg_type(args, 2, &len);
1339 if (!tmp || len != 4) {
1340 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1344 SILC_GET32_MSB(mode, tmp);
1345 conn->local_entry->mode = mode;
1347 /* Notify application */
1348 silc_client_command_callback(cmd, mode);
1351 silc_fsm_next(fsm, silc_client_command_reply_processed);
1352 return SILC_FSM_CONTINUE;
1355 /********************************** CMODE ***********************************/
1357 /* Received reply for CMODE command. */
1359 SILC_FSM_STATE(silc_client_command_reply_cmode)
1361 SilcClientCommandContext cmd = fsm_context;
1362 SilcClientConnection conn = cmd->conn;
1363 SilcClient client = conn->client;
1364 SilcCommandPayload payload = state_context;
1365 SilcArgumentPayload args = silc_command_get_args(payload);
1368 SilcChannelEntry channel;
1370 SilcPublicKey public_key = NULL;
1371 SilcDList channel_pubkeys = NULL;
1375 CHECK_STATUS("Cannot change mode: ");
1378 /* Take Channel ID */
1379 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1380 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1384 /* Get the channel entry */
1385 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1387 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1391 /* Get channel mode */
1392 tmp = silc_argument_get_arg_type(args, 3, &len);
1393 if (!tmp || len != 4) {
1394 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1399 SILC_GET32_MSB(mode, tmp);
1400 channel->mode = mode;
1402 /* Get founder public key */
1403 tmp = silc_argument_get_arg_type(args, 4, &len);
1405 silc_public_key_payload_decode(tmp, len, &public_key);
1407 /* Get user limit */
1408 tmp = silc_argument_get_arg_type(args, 6, &len);
1409 if (tmp && len == 4)
1410 SILC_GET32_MSB(channel->user_limit, tmp);
1411 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1412 channel->user_limit = 0;
1414 /* Get channel public key(s) */
1415 tmp = silc_argument_get_arg_type(args, 5, &len);
1418 silc_argument_list_parse_decoded(tmp, len, SILC_ARGUMENT_PUBLIC_KEY);
1420 /* Notify application */
1421 silc_client_command_callback(cmd, channel, mode, public_key,
1422 channel_pubkeys, channel->user_limit);
1424 silc_argument_list_free(channel_pubkeys, SILC_ARGUMENT_PUBLIC_KEY);
1428 silc_pkcs_public_key_free(public_key);
1429 silc_fsm_next(fsm, silc_client_command_reply_processed);
1430 return SILC_FSM_CONTINUE;
1433 /********************************** CUMODE **********************************/
1435 /* Received reply for CUMODE command */
1437 SILC_FSM_STATE(silc_client_command_reply_cumode)
1439 SilcClientCommandContext cmd = fsm_context;
1440 SilcClientConnection conn = cmd->conn;
1441 SilcClient client = conn->client;
1442 SilcCommandPayload payload = state_context;
1443 SilcArgumentPayload args = silc_command_get_args(payload);
1444 SilcClientEntry client_entry;
1445 SilcChannelEntry channel;
1446 SilcChannelUser chu;
1447 unsigned char *modev;
1448 SilcUInt32 len, mode;
1452 CHECK_STATUS("Cannot change mode: ");
1455 /* Get channel mode */
1456 modev = silc_argument_get_arg_type(args, 2, &len);
1457 if (!modev || len != 4) {
1458 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1461 SILC_GET32_MSB(mode, modev);
1463 /* Take Channel ID */
1464 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1465 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1469 /* Get the channel entry */
1470 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1472 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1477 if (!silc_argument_get_decoded(args, 4, SILC_ARGUMENT_ID, &id, NULL)) {
1478 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1482 /* Get client entry */
1483 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1484 if (!client_entry) {
1485 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1490 chu = silc_client_on_channel(channel, client_entry);
1494 /* Notify application */
1495 silc_client_command_callback(cmd, mode, channel, client_entry);
1497 silc_client_unref_client(client, conn, client_entry);
1500 silc_fsm_next(fsm, silc_client_command_reply_processed);
1501 return SILC_FSM_CONTINUE;
1504 /********************************** KICK ************************************/
1506 SILC_FSM_STATE(silc_client_command_reply_kick)
1508 SilcClientCommandContext cmd = fsm_context;
1509 SilcClientConnection conn = cmd->conn;
1510 SilcClient client = conn->client;
1511 SilcCommandPayload payload = state_context;
1512 SilcArgumentPayload args = silc_command_get_args(payload);
1513 SilcClientEntry client_entry;
1514 SilcChannelEntry channel;
1518 CHECK_STATUS("Cannot kick: ");
1521 /* Take Channel ID */
1522 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1523 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1527 /* Get the channel entry */
1528 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1530 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1535 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1536 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1540 /* Get client entry */
1541 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1542 if (!client_entry) {
1543 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1547 /* Notify application */
1548 silc_client_command_callback(cmd, channel, client_entry);
1550 silc_client_unref_client(client, conn, client_entry);
1553 silc_fsm_next(fsm, silc_client_command_reply_processed);
1554 return SILC_FSM_CONTINUE;
1557 /******************************** SILCOPER **********************************/
1559 SILC_FSM_STATE(silc_client_command_reply_silcoper)
1561 SilcClientCommandContext cmd = fsm_context;
1562 SilcCommandPayload payload = state_context;
1563 SilcArgumentPayload args = silc_command_get_args(payload);
1566 CHECK_STATUS("Cannot change mode: ");
1569 /* Notify application */
1570 silc_client_command_callback(cmd);
1572 silc_fsm_next(fsm, silc_client_command_reply_processed);
1573 return SILC_FSM_CONTINUE;
1576 /********************************** OPER ************************************/
1578 SILC_FSM_STATE(silc_client_command_reply_oper)
1580 SilcClientCommandContext cmd = fsm_context;
1581 SilcCommandPayload payload = state_context;
1582 SilcArgumentPayload args = silc_command_get_args(payload);
1585 CHECK_STATUS("Cannot change mode: ");
1588 /* Notify application */
1589 silc_client_command_callback(cmd);
1591 silc_fsm_next(fsm, silc_client_command_reply_processed);
1592 return SILC_FSM_CONTINUE;
1595 /********************************* DETACH ***********************************/
1597 SILC_FSM_STATE(silc_client_command_reply_detach)
1599 SilcClientCommandContext cmd = fsm_context;
1600 SilcClientConnection conn = cmd->conn;
1601 SilcClient client = conn->client;
1602 SilcCommandPayload payload = state_context;
1603 SilcArgumentPayload args = silc_command_get_args(payload);
1607 CHECK_STATUS("Cannot detach: ");
1610 /* Notify application */
1611 silc_client_command_callback(cmd);
1614 /* Generate the detachment data and deliver it to the client in the
1615 detach client operation */
1616 detach = silc_client_get_detach_data(client, conn);
1618 client->internal->ops->detach(client, conn, silc_buffer_data(detach),
1619 silc_buffer_len(detach));
1620 silc_buffer_free(detach);
1624 silc_fsm_next(fsm, silc_client_command_reply_processed);
1625 return SILC_FSM_CONTINUE;
1628 /********************************** WATCH ***********************************/
1630 SILC_FSM_STATE(silc_client_command_reply_watch)
1632 SilcClientCommandContext cmd = fsm_context;
1633 SilcCommandPayload payload = state_context;
1634 SilcArgumentPayload args = silc_command_get_args(payload);
1637 CHECK_STATUS("Cannot set watch: ");
1640 /* Notify application */
1641 silc_client_command_callback(cmd);
1643 silc_fsm_next(fsm, silc_client_command_reply_processed);
1644 return SILC_FSM_CONTINUE;
1647 /*********************************** BAN ************************************/
1649 SILC_FSM_STATE(silc_client_command_reply_ban)
1651 SilcClientCommandContext cmd = fsm_context;
1652 SilcClientConnection conn = cmd->conn;
1653 SilcClient client = conn->client;
1654 SilcCommandPayload payload = state_context;
1655 SilcArgumentPayload args = silc_command_get_args(payload);
1656 SilcChannelEntry channel;
1659 SilcArgumentPayload invite_args = NULL;
1663 CHECK_STATUS("Cannot set ban: ");
1666 /* Take Channel ID */
1667 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1668 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1672 /* Get the channel entry */
1673 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1675 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1679 /* Get the invite list */
1680 tmp = silc_argument_get_arg_type(args, 3, &len);
1682 invite_args = silc_argument_list_parse(tmp, len);
1684 /* Notify application */
1685 silc_client_command_callback(cmd, channel, invite_args);
1688 silc_argument_payload_free(invite_args);
1691 silc_fsm_next(fsm, silc_client_command_reply_processed);
1692 return SILC_FSM_CONTINUE;
1695 /********************************** LEAVE ***********************************/
1697 /* Reply to LEAVE command. */
1699 SILC_FSM_STATE(silc_client_command_reply_leave)
1701 SilcClientCommandContext cmd = fsm_context;
1702 SilcClientConnection conn = cmd->conn;
1703 SilcClient client = conn->client;
1704 SilcCommandPayload payload = state_context;
1705 SilcArgumentPayload args = silc_command_get_args(payload);
1706 SilcChannelEntry channel;
1710 CHECK_STATUS("Cannot set leave: ");
1713 /* Get Channel ID */
1714 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1715 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1719 /* Get the channel entry */
1720 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1722 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1726 /* Remove us from this channel. */
1727 silc_client_remove_from_channel(channel, conn->local_entry);
1729 /* Notify application */
1730 silc_client_command_callback(cmd, channel);
1732 /* Now delete the channel. */
1733 silc_client_del_channel(client, conn, channel);
1736 silc_fsm_next(fsm, silc_client_command_reply_processed);
1737 return SILC_FSM_CONTINUE;
1740 /********************************* USERS ************************************/
1742 /* Continue USERS command reply processing after resolving unknown users */
1745 silc_client_command_reply_users_resolved(SilcClient client,
1746 SilcClientConnection conn,
1751 SilcClientCommandContext cmd = context;
1752 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1756 /* Continue USERS command after resolving unknown channel */
1759 silc_client_command_reply_users_continue(SilcClient client,
1760 SilcClientConnection conn,
1765 SilcClientCommandContext cmd = context;
1768 SilcCommandPayload payload = silc_fsm_get_state_context(&cmd->thread);
1769 SilcArgumentPayload args = silc_command_get_args(payload);
1771 cmd->status = SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID;
1772 ERROR_CALLBACK(cmd->status);
1773 silc_fsm_next(&cmd->thread, silc_client_command_reply_processed);
1776 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1779 /* Reply to USERS command. Received list of client ID's and theirs modes
1780 on the channel we requested. */
1782 SILC_FSM_STATE(silc_client_command_reply_users)
1784 SilcClientCommandContext cmd = fsm_context;
1785 SilcClientConnection conn = cmd->conn;
1786 SilcClient client = conn->client;
1787 SilcCommandPayload payload = state_context;
1788 SilcArgumentPayload args = silc_command_get_args(payload);
1790 SilcUInt32 tmp_len, list_count;
1791 SilcUInt16 idp_len, mode;
1792 SilcHashTableList htl;
1793 SilcBufferStruct client_id_list, client_mode_list;
1794 SilcChannelEntry channel;
1795 SilcClientEntry client_entry;
1800 CHECK_STATUS("Cannot get users: ");
1803 /* Get channel ID */
1804 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1805 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1809 /* Get channel entry */
1810 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1812 /* Resolve the channel from server */
1813 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1814 client, conn, &id.u.channel_id,
1815 silc_client_command_reply_users_continue, cmd));
1819 /* Get the list count */
1820 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1821 if (!tmp || tmp_len != 4) {
1822 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1825 SILC_GET32_MSB(list_count, tmp);
1827 /* Get Client ID list */
1828 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1830 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1833 silc_buffer_set(&client_id_list, tmp, tmp_len);
1835 /* Resolve users we do not know about */
1836 if (!cmd->resolved) {
1837 cmd->resolved = TRUE;
1838 SILC_FSM_CALL(silc_client_get_clients_by_list(
1839 client, conn, list_count, &client_id_list,
1840 silc_client_command_reply_users_resolved, cmd));
1844 /* Get client mode list */
1845 tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
1847 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1850 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1852 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1854 /* Cache the received Client ID's and modes. */
1855 for (i = 0; i < list_count; i++) {
1856 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1858 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1862 SILC_GET32_MSB(mode, client_mode_list.data);
1864 /* Save the client on this channel. Unknown clients are ignored as they
1865 clearly do not exist since the resolving didn't find them. */
1866 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1868 silc_client_add_to_channel(channel, client_entry, mode);
1869 silc_client_unref_client(client, conn, client_entry);
1871 if (!silc_buffer_pull(&client_id_list, idp_len))
1873 if (!silc_buffer_pull(&client_mode_list, 4))
1877 /* Notify application */
1878 silc_hash_table_list(channel->user_list, &htl);
1879 silc_client_command_callback(cmd, channel, &htl);
1880 silc_hash_table_list_reset(&htl);
1883 silc_fsm_next(fsm, silc_client_command_reply_processed);
1884 return SILC_FSM_CONTINUE;
1887 /********************************** GETKEY **********************************/
1889 /* Received command reply to GETKEY command. WE've received the remote
1890 client's public key. */
1892 SILC_FSM_STATE(silc_client_command_reply_getkey)
1894 SilcClientCommandContext cmd = fsm_context;
1895 SilcClientConnection conn = cmd->conn;
1896 SilcClient client = conn->client;
1897 SilcCommandPayload payload = state_context;
1898 SilcArgumentPayload args = silc_command_get_args(payload);
1899 SilcClientEntry client_entry;
1900 SilcServerEntry server_entry;
1903 SilcPublicKey public_key;
1907 CHECK_STATUS("Cannot get key: ");
1911 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1912 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1916 /* Get the public key */
1917 tmp = silc_argument_get_arg_type(args, 3, &len);
1919 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1922 if (!silc_public_key_payload_decode(tmp, len, &public_key)) {
1923 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1927 if (id.type == SILC_ID_CLIENT) {
1928 /* Received client's public key */
1929 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1930 if (!client_entry) {
1931 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1935 /* Save fingerprint */
1936 if (!client_entry->fingerprint)
1937 silc_hash_make(conn->internal->sha1hash, tmp + 4, len - 4,
1938 client_entry->fingerprint);
1939 if (!client_entry->public_key) {
1940 client_entry->public_key = public_key;
1944 /* Notify application */
1945 silc_client_command_callback(cmd, SILC_ID_CLIENT, client_entry,
1946 client_entry->public_key);
1947 silc_client_unref_client(client, conn, client_entry);
1948 } else if (id.type == SILC_ID_SERVER) {
1949 /* Received server's public key */
1950 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1951 if (!server_entry) {
1952 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1956 if (!server_entry->public_key) {
1957 server_entry->public_key = public_key;
1961 /* Notify application */
1962 silc_client_command_callback(cmd, SILC_ID_SERVER, server_entry,
1963 server_entry->public_key);
1968 silc_pkcs_public_key_free(public_key);
1969 silc_fsm_next(fsm, silc_client_command_reply_processed);
1970 return SILC_FSM_CONTINUE;
1973 /********************************** SERVICE *********************************/
1975 /* Reply to SERVICE command. */
1976 /* XXX incomplete */
1978 SILC_FSM_STATE(silc_client_command_reply_service)
1980 SilcClientCommandContext cmd = fsm_context;
1981 SilcCommandPayload payload = state_context;
1982 SilcArgumentPayload args = silc_command_get_args(payload);
1984 unsigned char *service_list, *name;
1987 CHECK_STATUS("Cannot get service: ");
1989 /* Get service list */
1990 service_list = silc_argument_get_arg_type(args, 2, &tmp_len);
1992 /* Get requested service name */
1993 name = silc_argument_get_arg_type(args, 3, &tmp_len);
1995 /* Notify application */
1996 silc_client_command_callback(cmd, service_list, name);
1998 silc_fsm_next(fsm, silc_client_command_reply_processed);
1999 return SILC_FSM_CONTINUE;
2002 /*********************************** QUIT ***********************************/
2004 /* QUIT command reply stub */
2006 SILC_FSM_STATE(silc_client_command_reply_quit)
2008 silc_fsm_next(fsm, silc_client_command_reply_processed);
2009 return SILC_FSM_CONTINUE;