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(err) \
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 = cmd->error = err; \
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 SilcClientConnection conn = cmd->conn;
192 SilcArgumentPayload args = NULL;
194 SILC_LOG_DEBUG(("Command %s timeout", silc_get_command_name(cmd->cmd)));
196 /* Timeout, reply not received in timely fashion */
197 silc_list_del(conn->internal->pending_commands, cmd);
198 ERROR_CALLBACK(SILC_STATUS_ERR_TIMEDOUT);
199 return SILC_FSM_FINISH;
202 /* Process received command reply payload */
204 SILC_FSM_STATE(silc_client_command_reply_process)
206 SilcClientCommandContext cmd = fsm_context;
207 SilcCommandPayload payload = state_context;
209 silc_command_get_status(payload, &cmd->status, &cmd->error);
212 case SILC_COMMAND_WHOIS:
214 silc_fsm_next(fsm, silc_client_command_reply_whois);
216 case SILC_COMMAND_WHOWAS:
218 silc_fsm_next(fsm, silc_client_command_reply_whowas);
220 case SILC_COMMAND_IDENTIFY:
222 silc_fsm_next(fsm, silc_client_command_reply_identify);
224 case SILC_COMMAND_NICK:
226 silc_fsm_next(fsm, silc_client_command_reply_nick);
228 case SILC_COMMAND_LIST:
230 silc_fsm_next(fsm, silc_client_command_reply_list);
232 case SILC_COMMAND_TOPIC:
234 silc_fsm_next(fsm, silc_client_command_reply_topic);
236 case SILC_COMMAND_INVITE:
238 silc_fsm_next(fsm, silc_client_command_reply_invite);
240 case SILC_COMMAND_QUIT:
242 silc_fsm_next(fsm, silc_client_command_reply_quit);
244 case SILC_COMMAND_KILL:
246 silc_fsm_next(fsm, silc_client_command_reply_kill);
248 case SILC_COMMAND_INFO:
250 silc_fsm_next(fsm, silc_client_command_reply_info);
252 case SILC_COMMAND_STATS:
254 silc_fsm_next(fsm, silc_client_command_reply_stats);
256 case SILC_COMMAND_PING:
258 silc_fsm_next(fsm, silc_client_command_reply_ping);
260 case SILC_COMMAND_OPER:
262 silc_fsm_next(fsm, silc_client_command_reply_oper);
264 case SILC_COMMAND_JOIN:
266 silc_fsm_next(fsm, silc_client_command_reply_join);
268 case SILC_COMMAND_MOTD:
270 silc_fsm_next(fsm, silc_client_command_reply_motd);
272 case SILC_COMMAND_UMODE:
274 silc_fsm_next(fsm, silc_client_command_reply_umode);
276 case SILC_COMMAND_CMODE:
278 silc_fsm_next(fsm, silc_client_command_reply_cmode);
280 case SILC_COMMAND_CUMODE:
282 silc_fsm_next(fsm, silc_client_command_reply_cumode);
284 case SILC_COMMAND_KICK:
286 silc_fsm_next(fsm, silc_client_command_reply_kick);
288 case SILC_COMMAND_BAN:
290 silc_fsm_next(fsm, silc_client_command_reply_ban);
292 case SILC_COMMAND_DETACH:
294 silc_fsm_next(fsm, silc_client_command_reply_detach);
296 case SILC_COMMAND_WATCH:
298 silc_fsm_next(fsm, silc_client_command_reply_watch);
300 case SILC_COMMAND_SILCOPER:
302 silc_fsm_next(fsm, silc_client_command_reply_silcoper);
304 case SILC_COMMAND_LEAVE:
306 silc_fsm_next(fsm, silc_client_command_reply_leave);
308 case SILC_COMMAND_USERS:
310 silc_fsm_next(fsm, silc_client_command_reply_users);
312 case SILC_COMMAND_GETKEY:
314 silc_fsm_next(fsm, silc_client_command_reply_getkey);
316 case SILC_COMMAND_SERVICE:
318 silc_fsm_next(fsm, silc_client_command_reply_service);
321 return SILC_FSM_FINISH;
324 return SILC_FSM_CONTINUE;
327 /* Completes command reply processing */
329 SILC_FSM_STATE(silc_client_command_reply_processed)
331 SilcClientCommandContext cmd = fsm_context;
332 SilcClientConnection conn = cmd->conn;
333 SilcCommandPayload payload = state_context;
335 silc_command_payload_free(payload);
337 if (cmd->status == SILC_STATUS_OK || cmd->status == SILC_STATUS_LIST_END ||
338 SILC_STATUS_IS_ERROR(cmd->status))
339 return SILC_FSM_FINISH;
341 /* Add back to pending command reply list */
342 silc_mutex_lock(conn->internal->lock);
343 cmd->resolved = FALSE;
344 silc_list_add(conn->internal->pending_commands, cmd);
345 silc_mutex_unlock(conn->internal->lock);
347 /** Wait more command payloads */
348 silc_fsm_next(fsm, silc_client_command_reply_wait);
349 return SILC_FSM_CONTINUE;
352 /******************************** WHOIS *************************************/
354 /* Received reply for WHOIS command. */
356 SILC_FSM_STATE(silc_client_command_reply_whois)
358 SilcClientCommandContext cmd = fsm_context;
359 SilcClientConnection conn = cmd->conn;
360 SilcClient client = conn->client;
361 SilcCommandPayload payload = state_context;
362 SilcArgumentPayload args = silc_command_get_args(payload);
363 SilcClientEntry client_entry = NULL;
364 SilcUInt32 idle = 0, mode = 0, fingerprint_len, len, *umodes = NULL;
365 SilcBufferStruct channels, ch_user_modes;
366 SilcBool has_channels = FALSE;
367 SilcDList channel_list = NULL;
369 char *nickname = NULL, *username = NULL, *realname = NULL;
370 unsigned char *fingerprint, *tmp;
372 CHECK_STATUS("WHOIS: ");
376 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
377 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
382 nickname = silc_argument_get_arg_type(args, 3, NULL);
383 username = silc_argument_get_arg_type(args, 4, NULL);
384 realname = silc_argument_get_arg_type(args, 5, NULL);
385 if (!nickname || !username || !realname) {
386 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
390 /* Get joined channel list */
391 memset(&channels, 0, sizeof(channels));
392 tmp = silc_argument_get_arg_type(args, 6, &len);
395 silc_buffer_set(&channels, tmp, len);
397 /* Get channel user mode list */
398 tmp = silc_argument_get_arg_type(args, 10, &len);
400 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
403 silc_buffer_set(&ch_user_modes, tmp, len);
407 tmp = silc_argument_get_arg_type(args, 7, &len);
409 SILC_GET32_MSB(mode, tmp);
412 tmp = silc_argument_get_arg_type(args, 8, &len);
414 SILC_GET32_MSB(idle, tmp);
416 /* Get fingerprint */
417 fingerprint = silc_argument_get_arg_type(args, 9, &fingerprint_len);
419 /* Check if we have this client cached already. */
420 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
422 SILC_LOG_DEBUG(("Adding new client entry (WHOIS)"));
424 silc_client_add_client(client, conn, nickname, username, realname,
425 &id.u.client_id, mode);
427 ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
430 silc_client_ref_client(client, conn, client_entry);
432 silc_client_update_client(client, conn, client_entry,
433 nickname, username, realname, mode);
436 if (fingerprint && fingerprint_len == sizeof(client_entry->fingerprint))
437 memcpy(client_entry->fingerprint, fingerprint, fingerprint_len);
439 /* Get user attributes */
440 tmp = silc_argument_get_arg_type(args, 11, &len);
442 if (client_entry->attrs)
443 silc_attribute_payload_list_free(client_entry->attrs);
444 client_entry->attrs = silc_attribute_payload_parse(tmp, len);
447 /* Parse channel and channel user mode list */
449 channel_list = silc_channel_payload_parse_list(silc_buffer_data(&channels),
450 silc_buffer_len(&channels));
452 silc_get_mode_list(&ch_user_modes, silc_dlist_count(channel_list),
456 /* Notify application */
457 silc_client_command_callback(cmd, client_entry, nickname, username,
458 realname, channel_list, mode, idle, fingerprint,
459 umodes, client_entry->attrs);
461 silc_client_unref_client(client, conn, client_entry);
463 silc_dlist_uninit(channel_list);
468 silc_fsm_next(fsm, silc_client_command_reply_processed);
469 return SILC_FSM_CONTINUE;
472 /******************************** WHOWAS ************************************/
474 /* Received reply for WHOWAS command. */
476 SILC_FSM_STATE(silc_client_command_reply_whowas)
478 SilcClientCommandContext cmd = fsm_context;
479 SilcClientConnection conn = cmd->conn;
480 SilcClient client = conn->client;
481 SilcCommandPayload payload = state_context;
482 SilcArgumentPayload args = silc_command_get_args(payload);
483 SilcClientEntry client_entry = NULL;
485 char *nickname, *username;
486 char *realname = NULL;
488 CHECK_STATUS("WHOWAS: ");
492 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
493 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
497 /* Get the client entry */
498 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
501 nickname = silc_argument_get_arg_type(args, 3, NULL);
502 username = silc_argument_get_arg_type(args, 4, NULL);
503 realname = silc_argument_get_arg_type(args, 5, NULL);
504 if (!nickname || !username) {
505 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
509 /* Notify application. We don't save any history information to any
510 cache. Just pass the data to the application. */
511 silc_client_command_callback(cmd, client_entry, nickname, username,
515 silc_client_unref_client(client, conn, client_entry);
516 silc_fsm_next(fsm, silc_client_command_reply_processed);
517 return SILC_FSM_CONTINUE;
520 /******************************** IDENTIFY **********************************/
522 /* Received reply for IDENTIFY command. */
524 SILC_FSM_STATE(silc_client_command_reply_identify)
526 SilcClientCommandContext cmd = fsm_context;
527 SilcClientConnection conn = cmd->conn;
528 SilcClient client = conn->client;
529 SilcCommandPayload payload = state_context;
530 SilcArgumentPayload args = silc_command_get_args(payload);
531 SilcClientEntry client_entry;
532 SilcServerEntry server_entry;
533 SilcChannelEntry channel_entry;
536 char *name = NULL, *info = NULL;
538 CHECK_STATUS("IDENTIFY: ");
542 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
543 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
548 name = silc_argument_get_arg_type(args, 3, &len);
549 info = silc_argument_get_arg_type(args, 4, &len);
553 SILC_LOG_DEBUG(("Received client information"));
555 /* Check if we have this client cached already. */
556 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
558 SILC_LOG_DEBUG(("Adding new client entry (IDENTIFY)"));
560 silc_client_add_client(client, conn, name, info, NULL,
563 ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
566 silc_client_ref_client(client, conn, client_entry);
568 silc_client_update_client(client, conn, client_entry,
569 name, info, NULL, 0);
572 /* Notify application */
573 silc_client_command_callback(cmd, client_entry, name, info);
574 silc_client_unref_client(client, conn, client_entry);
578 SILC_LOG_DEBUG(("Received server information"));
580 /* Check if we have this server cached already. */
581 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
583 SILC_LOG_DEBUG(("Adding new server entry (IDENTIFY)"));
584 server_entry = silc_client_add_server(client, conn, name, info,
587 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
590 silc_client_ref_server(client, conn, server_entry);
592 silc_client_update_server(client, conn, server_entry, name, info);
594 server_entry->internal.resolve_cmd_ident = 0;
596 /* Notify application */
597 silc_client_command_callback(cmd, server_entry, name, info);
598 silc_client_unref_server(client, conn, server_entry);
601 case SILC_ID_CHANNEL:
602 SILC_LOG_DEBUG(("Received channel information"));
604 /* Check if we have this channel cached already. */
605 channel_entry = silc_client_get_channel_by_id(client, conn,
607 if (!channel_entry) {
608 SILC_LOG_DEBUG(("Adding new channel entry (IDENTIFY"));
611 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
615 /* Add new channel entry */
616 channel_entry = silc_client_add_channel(client, conn, name, 0,
618 if (!channel_entry) {
619 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
622 silc_client_ref_channel(client, conn, channel_entry);
625 /* Notify application */
626 silc_client_command_callback(cmd, channel_entry, name, info);
627 silc_client_unref_channel(client, conn, channel_entry);
632 silc_fsm_next(fsm, silc_client_command_reply_processed);
633 return SILC_FSM_CONTINUE;
636 /********************************** NICK ************************************/
638 /* Received reply for command NICK. */
640 SILC_FSM_STATE(silc_client_command_reply_nick)
642 SilcClientCommandContext cmd = fsm_context;
643 SilcClientConnection conn = cmd->conn;
644 SilcClient client = conn->client;
645 SilcCommandPayload payload = state_context;
646 SilcArgumentPayload args = silc_command_get_args(payload);
647 unsigned char *tmp, *nick, *idp;
648 SilcUInt32 len, idp_len;
649 SilcClientID old_client_id;
653 CHECK_STATUS("Cannot set nickname: ");
656 old_client_id = *conn->local_id;
658 /* Take received Client ID */
659 idp = silc_argument_get_arg_type(args, 2, &idp_len);
661 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
664 if (!silc_id_payload_parse_id(idp, idp_len, &id)) {
665 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
669 /* Take the new nickname */
670 nick = silc_argument_get_arg_type(args, 3, &len);
672 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
676 /* Normalize nickname */
677 tmp = silc_identifier_check(nick, len, SILC_STRING_UTF8, 128, NULL);
679 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_NICKNAME);
683 /* Update the client entry */
684 silc_mutex_lock(conn->internal->lock);
685 if (!silc_idcache_update(conn->internal->client_cache,
686 conn->internal->local_entry,
687 &id.u.client_id, tmp, TRUE)) {
689 silc_mutex_unlock(conn->internal->lock);
690 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_NICKNAME);
693 silc_mutex_unlock(conn->internal->lock);
694 memset(conn->local_entry->nickname, 0, sizeof(conn->local_entry->nickname));
695 memcpy(conn->local_entry->nickname, nick, len);
696 conn->local_entry->nickname_normalized = tmp;
697 silc_buffer_enlarge(conn->internal->local_idp, idp_len);
698 silc_buffer_put(conn->internal->local_idp, idp, idp_len);
699 silc_client_nickname_format(client, conn, conn->local_entry);
700 silc_packet_set_ids(conn->stream, SILC_ID_CLIENT, conn->local_id, 0, NULL);
702 /* Notify application */
703 silc_client_command_callback(cmd, conn->local_entry,
704 conn->local_entry->nickname, &old_client_id);
707 silc_fsm_next(fsm, silc_client_command_reply_processed);
708 return SILC_FSM_CONTINUE;
711 /********************************** LIST ************************************/
713 /* Received reply to the LIST command. */
715 SILC_FSM_STATE(silc_client_command_reply_list)
717 SilcClientCommandContext cmd = fsm_context;
718 SilcClientConnection conn = cmd->conn;
719 SilcClient client = conn->client;
720 SilcCommandPayload payload = state_context;
721 SilcArgumentPayload args = silc_command_get_args(payload);
722 unsigned char *tmp, *name, *topic;
723 SilcUInt32 usercount = 0;
724 SilcChannelEntry channel_entry = NULL;
728 CHECK_STATUS("Cannot list channels: ");
730 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
731 /* There were no channels in the network. */
732 silc_client_command_callback(cmd, NULL, NULL, NULL, 0);
733 silc_fsm_next(fsm, silc_client_command_reply_processed);
734 return SILC_FSM_CONTINUE;
739 name = silc_argument_get_arg_type(args, 3, NULL);
741 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
745 topic = silc_argument_get_arg_type(args, 4, NULL);
746 tmp = silc_argument_get_arg_type(args, 5, NULL);
748 SILC_GET32_MSB(usercount, tmp);
750 /* Check whether the channel exists, and add it to cache if it doesn't. */
751 channel_entry = silc_client_get_channel_by_id(client, conn,
753 if (!channel_entry) {
754 /* Add new channel entry */
755 channel_entry = silc_client_add_channel(client, conn, name, 0,
757 if (!channel_entry) {
758 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
761 silc_client_ref_channel(client, conn, channel_entry);
764 /* Notify application */
765 silc_client_command_callback(cmd, channel_entry, name, topic, usercount);
768 silc_client_unref_channel(client, conn, channel_entry);
769 silc_fsm_next(fsm, silc_client_command_reply_processed);
770 return SILC_FSM_CONTINUE;
773 /********************************* TOPIC ************************************/
775 /* Received reply to topic command. */
777 SILC_FSM_STATE(silc_client_command_reply_topic)
779 SilcClientCommandContext cmd = fsm_context;
780 SilcClientConnection conn = cmd->conn;
781 SilcClient client = conn->client;
782 SilcCommandPayload payload = state_context;
783 SilcArgumentPayload args = silc_command_get_args(payload);
784 SilcChannelEntry channel;
790 CHECK_STATUS("Cannot set topic: ");
793 /* Take Channel ID */
794 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
795 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
799 /* Get the channel entry */
800 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
802 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
807 topic = silc_argument_get_arg_type(args, 3, &len);
809 silc_free(channel->topic);
810 channel->topic = silc_memdup(topic, len);
813 /* Notify application */
814 silc_client_command_callback(cmd, channel, channel->topic);
817 silc_fsm_next(fsm, silc_client_command_reply_processed);
818 return SILC_FSM_CONTINUE;
821 /********************************* INVITE ***********************************/
823 /* Received reply to invite command. */
825 SILC_FSM_STATE(silc_client_command_reply_invite)
827 SilcClientCommandContext cmd = fsm_context;
828 SilcClientConnection conn = cmd->conn;
829 SilcClient client = conn->client;
830 SilcCommandPayload payload = state_context;
831 SilcArgumentPayload args = silc_command_get_args(payload);
832 SilcChannelEntry channel;
835 SilcArgumentPayload invite_args = NULL;
839 CHECK_STATUS("Cannot invite: ");
842 /* Take Channel ID */
843 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
844 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
848 /* Get the channel entry */
849 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
851 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
855 /* Get the invite list */
856 tmp = silc_argument_get_arg_type(args, 3, &len);
858 invite_args = silc_argument_list_parse(tmp, len);
860 /* Notify application */
861 silc_client_command_callback(cmd, channel, invite_args);
864 silc_argument_payload_free(invite_args);
867 silc_fsm_next(fsm, silc_client_command_reply_processed);
868 return SILC_FSM_CONTINUE;
871 /********************************** KILL ************************************/
873 /* Received reply to the KILL command. */
875 SILC_FSM_STATE(silc_client_command_reply_kill)
877 SilcClientCommandContext cmd = fsm_context;
878 SilcClientConnection conn = cmd->conn;
879 SilcClient client = conn->client;
880 SilcCommandPayload payload = state_context;
881 SilcArgumentPayload args = silc_command_get_args(payload);
882 SilcClientEntry client_entry;
886 CHECK_STATUS("Cannot kill: ");
889 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
890 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
894 /* Get the client entry, if exists */
895 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
897 /* Notify application */
898 silc_client_command_callback(cmd, client_entry);
900 /* Remove the client from all channels and free it */
902 silc_client_del_client(client, conn, client_entry);
903 silc_client_unref_client(client, conn, client_entry);
907 silc_fsm_next(fsm, silc_client_command_reply_processed);
908 return SILC_FSM_CONTINUE;
911 /********************************** INFO ************************************/
913 /* Received reply to INFO command. We receive the server ID and some
914 information about the server user requested. */
916 SILC_FSM_STATE(silc_client_command_reply_info)
918 SilcClientCommandContext cmd = fsm_context;
919 SilcClientConnection conn = cmd->conn;
920 SilcClient client = conn->client;
921 SilcCommandPayload payload = state_context;
922 SilcArgumentPayload args = silc_command_get_args(payload);
923 SilcServerEntry server;
924 char *server_name, *server_info;
928 CHECK_STATUS("Cannot get info: ");
932 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
933 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
937 /* Get server name */
938 server_name = silc_argument_get_arg_type(args, 3, NULL);
940 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
944 /* Get server info */
945 server_info = silc_argument_get_arg_type(args, 4, NULL);
947 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
951 /* See whether we have this server cached. If not create it. */
952 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
954 SILC_LOG_DEBUG(("Add new server entry (INFO)"));
955 server = silc_client_add_server(client, conn, server_name,
956 server_info, &id.u.server_id);
959 silc_client_ref_server(client, conn, server);
962 /* Notify application */
963 silc_client_command_callback(cmd, server, server->server_name,
964 server->server_info);
965 silc_client_unref_server(client, conn, server);
968 silc_fsm_next(fsm, silc_client_command_reply_processed);
969 return SILC_FSM_CONTINUE;
972 /********************************** STATS ***********************************/
974 /* Received reply to STATS command. */
976 SILC_FSM_STATE(silc_client_command_reply_stats)
978 SilcClientCommandContext cmd = fsm_context;
979 SilcCommandPayload payload = state_context;
980 SilcArgumentPayload args = silc_command_get_args(payload);
981 SilcClientStats stats;
982 unsigned char *buf = NULL;
983 SilcUInt32 buf_len = 0;
988 CHECK_STATUS("Cannot get stats: ");
992 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
993 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
997 /* Get statistics structure */
998 memset(&stats, 0, sizeof(stats));
999 buf = silc_argument_get_arg_type(args, 3, &buf_len);
1001 silc_buffer_set(&b, buf, buf_len);
1002 silc_buffer_unformat(&b,
1003 SILC_STR_UI_INT(&stats.starttime),
1004 SILC_STR_UI_INT(&stats.uptime),
1005 SILC_STR_UI_INT(&stats.my_clients),
1006 SILC_STR_UI_INT(&stats.my_channels),
1007 SILC_STR_UI_INT(&stats.my_server_ops),
1008 SILC_STR_UI_INT(&stats.my_router_ops),
1009 SILC_STR_UI_INT(&stats.cell_clients),
1010 SILC_STR_UI_INT(&stats.cell_channels),
1011 SILC_STR_UI_INT(&stats.cell_servers),
1012 SILC_STR_UI_INT(&stats.clients),
1013 SILC_STR_UI_INT(&stats.channels),
1014 SILC_STR_UI_INT(&stats.servers),
1015 SILC_STR_UI_INT(&stats.routers),
1016 SILC_STR_UI_INT(&stats.server_ops),
1017 SILC_STR_UI_INT(&stats.router_ops),
1021 /* Notify application */
1022 silc_client_command_callback(cmd, &stats);
1025 silc_fsm_next(fsm, silc_client_command_reply_processed);
1026 return SILC_FSM_CONTINUE;
1029 /********************************** PING ************************************/
1031 /* Received reply to PING command. */
1033 SILC_FSM_STATE(silc_client_command_reply_ping)
1035 SilcClientCommandContext cmd = fsm_context;
1036 SilcClientConnection conn = cmd->conn;
1037 SilcClient client = conn->client;
1040 diff = silc_time() - SILC_PTR_TO_64(cmd->context);
1042 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO,
1043 "Ping reply from %s: %d second%s", conn->remote_host,
1044 (int)diff, diff == 1 ? "" : "s");
1046 /* Notify application */
1047 silc_client_command_callback(cmd);
1049 silc_fsm_next(fsm, silc_client_command_reply_processed);
1050 return SILC_FSM_CONTINUE;
1053 /********************************** JOIN ************************************/
1055 /* Continue JOIN command reply processing after resolving unknown users */
1058 silc_client_command_reply_join_resolved(SilcClient client,
1059 SilcClientConnection conn,
1064 SilcClientCommandContext cmd = context;
1065 SilcChannelEntry channel = cmd->context;
1067 channel->internal.resolve_cmd_ident = 0;
1068 silc_client_unref_channel(client, conn, channel);
1070 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1074 /* Received reply for JOIN command. */
1076 SILC_FSM_STATE(silc_client_command_reply_join)
1078 SilcClientCommandContext cmd = fsm_context;
1079 SilcClientConnection conn = cmd->conn;
1080 SilcClient client = conn->client;
1081 SilcCommandPayload payload = state_context;
1082 SilcArgumentPayload args = silc_command_get_args(payload);
1083 SilcChannelEntry channel;
1084 SilcUInt32 mode = 0, len, list_count;
1085 char *topic, *tmp, *channel_name = NULL, *hmac;
1087 SilcBufferStruct client_id_list, client_mode_list, keyp;
1088 SilcHashTableList htl;
1089 SilcDList chpks = NULL;
1094 CHECK_STATUS("Cannot join channel: ");
1097 /* Get channel name */
1098 channel_name = silc_argument_get_arg_type(args, 2, NULL);
1099 if (!channel_name) {
1100 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1104 /* Get Channel ID */
1105 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1106 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1110 /* Check whether we have this channel entry already. */
1111 channel = silc_client_get_channel(client, conn, channel_name);
1113 if (!SILC_ID_CHANNEL_COMPARE(&channel->id, &id.u.channel_id))
1114 silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id);
1116 /* Create new channel entry */
1117 channel = silc_client_add_channel(client, conn, channel_name,
1118 mode, &id.u.channel_id);
1120 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_CHANNEL);
1123 silc_client_ref_channel(client, conn, channel);
1126 /* Get the list count */
1127 tmp = silc_argument_get_arg_type(args, 12, &len);
1129 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1132 SILC_GET32_MSB(list_count, tmp);
1134 /* Get Client ID list */
1135 tmp = silc_argument_get_arg_type(args, 13, &len);
1137 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1140 silc_buffer_set(&client_id_list, tmp, len);
1142 /* Resolve users we do not know about */
1143 if (!cmd->resolved) {
1144 cmd->resolved = TRUE;
1145 cmd->context = channel;
1146 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1147 silc_client_get_clients_by_list(
1148 client, conn, list_count, &client_id_list,
1149 silc_client_command_reply_join_resolved, cmd));
1153 /* Get client mode list */
1154 tmp = silc_argument_get_arg_type(args, 14, &len);
1156 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1159 silc_buffer_set(&client_mode_list, tmp, len);
1161 /* Add clients we received in the reply to the channel */
1162 for (i = 0; i < list_count; i++) {
1166 SilcClientEntry client_entry;
1169 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1171 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1175 SILC_GET32_MSB(mode, client_mode_list.data);
1177 /* Get client entry */
1178 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1182 /* Join client to the channel */
1183 silc_client_add_to_channel(client, conn, channel, client_entry, mode);
1184 silc_client_unref_client(client, conn, client_entry);
1186 if (!silc_buffer_pull(&client_id_list, idp_len))
1188 if (!silc_buffer_pull(&client_mode_list, 4))
1193 hmac = silc_argument_get_arg_type(args, 11, NULL);
1195 if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) {
1197 SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1198 "Cannot join channel: Unsupported HMAC `%s'", hmac);
1199 ERROR_CALLBACK(SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
1204 /* Get channel mode */
1205 tmp = silc_argument_get_arg_type(args, 5, NULL);
1207 SILC_GET32_MSB(mode, tmp);
1208 channel->mode = mode;
1210 /* Get channel key and save it */
1211 tmp = silc_argument_get_arg_type(args, 7, &len);
1213 silc_buffer_set(&keyp, tmp, len);
1214 silc_client_save_channel_key(client, conn, &keyp, channel);
1218 topic = silc_argument_get_arg_type(args, 10, NULL);
1220 silc_free(channel->topic);
1221 channel->topic = silc_memdup(topic, strlen(topic));
1224 /* Get founder key */
1225 tmp = silc_argument_get_arg_type(args, 15, &len);
1227 if (channel->founder_key)
1228 silc_pkcs_public_key_free(channel->founder_key);
1229 channel->founder_key = NULL;
1230 silc_public_key_payload_decode(tmp, len, &channel->founder_key);
1233 /* Get user limit */
1234 tmp = silc_argument_get_arg_type(args, 17, &len);
1235 if (tmp && len == 4)
1236 SILC_GET32_MSB(channel->user_limit, tmp);
1237 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1238 channel->user_limit = 0;
1240 /* Get channel public key list */
1241 tmp = silc_argument_get_arg_type(args, 16, &len);
1243 chpks = silc_argument_list_parse_decoded(tmp, len,
1244 SILC_ARGUMENT_PUBLIC_KEY);
1246 /* Set current channel */
1247 conn->current_channel = channel;
1249 cipher = (channel->internal.channel_key ?
1250 silc_cipher_get_name(channel->internal.channel_key) : NULL);
1251 silc_hash_table_list(channel->user_list, &htl);
1253 /* Notify application */
1254 silc_client_command_callback(cmd, channel_name, channel, mode, &htl,
1255 topic, cipher, hmac, channel->founder_key,
1256 chpks, channel->user_limit);
1259 silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
1260 silc_hash_table_list_reset(&htl);
1261 silc_client_unref_channel(client, conn, channel);
1264 silc_fsm_next(fsm, silc_client_command_reply_processed);
1265 return SILC_FSM_CONTINUE;
1268 /********************************** MOTD ************************************/
1270 /* Received reply for MOTD command */
1272 SILC_FSM_STATE(silc_client_command_reply_motd)
1274 SilcClientCommandContext cmd = fsm_context;
1275 SilcClientConnection conn = cmd->conn;
1276 SilcClient client = conn->client;
1277 SilcCommandPayload payload = state_context;
1278 SilcArgumentPayload args = silc_command_get_args(payload);
1280 char *motd = NULL, *cp, line[256];
1283 CHECK_STATUS("Cannot get motd: ");
1286 if (silc_argument_get_arg_num(args) == 3) {
1287 motd = silc_argument_get_arg_type(args, 3, NULL);
1289 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1296 if (cp[i++] == '\n') {
1297 memset(line, 0, sizeof(line));
1298 silc_strncat(line, sizeof(line), cp, i - 1);
1305 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1314 /* Notify application */
1315 silc_client_command_callback(cmd, motd);
1318 silc_fsm_next(fsm, silc_client_command_reply_processed);
1319 return SILC_FSM_CONTINUE;
1322 /********************************** UMODE ***********************************/
1324 /* Received reply to the UMODE command. Save the current user mode */
1326 SILC_FSM_STATE(silc_client_command_reply_umode)
1328 SilcClientCommandContext cmd = fsm_context;
1329 SilcClientConnection conn = cmd->conn;
1330 SilcCommandPayload payload = state_context;
1331 SilcArgumentPayload args = silc_command_get_args(payload);
1333 SilcUInt32 mode, len;
1336 CHECK_STATUS("Cannot change mode: ");
1339 tmp = silc_argument_get_arg_type(args, 2, &len);
1340 if (!tmp || len != 4) {
1341 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1345 SILC_GET32_MSB(mode, tmp);
1346 conn->local_entry->mode = mode;
1348 /* Notify application */
1349 silc_client_command_callback(cmd, mode);
1352 silc_fsm_next(fsm, silc_client_command_reply_processed);
1353 return SILC_FSM_CONTINUE;
1356 /********************************** CMODE ***********************************/
1358 /* Received reply for CMODE command. */
1360 SILC_FSM_STATE(silc_client_command_reply_cmode)
1362 SilcClientCommandContext cmd = fsm_context;
1363 SilcClientConnection conn = cmd->conn;
1364 SilcClient client = conn->client;
1365 SilcCommandPayload payload = state_context;
1366 SilcArgumentPayload args = silc_command_get_args(payload);
1369 SilcChannelEntry channel;
1371 SilcPublicKey public_key = NULL;
1372 SilcDList channel_pubkeys = NULL;
1376 CHECK_STATUS("Cannot change mode: ");
1379 /* Take Channel ID */
1380 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1381 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1385 /* Get the channel entry */
1386 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1388 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1392 /* Get channel mode */
1393 tmp = silc_argument_get_arg_type(args, 3, &len);
1394 if (!tmp || len != 4) {
1395 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1400 SILC_GET32_MSB(mode, tmp);
1401 channel->mode = mode;
1403 /* Get founder public key */
1404 tmp = silc_argument_get_arg_type(args, 4, &len);
1406 silc_public_key_payload_decode(tmp, len, &public_key);
1408 /* Get user limit */
1409 tmp = silc_argument_get_arg_type(args, 6, &len);
1410 if (tmp && len == 4)
1411 SILC_GET32_MSB(channel->user_limit, tmp);
1412 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1413 channel->user_limit = 0;
1415 /* Get channel public key(s) */
1416 tmp = silc_argument_get_arg_type(args, 5, &len);
1419 silc_argument_list_parse_decoded(tmp, len, SILC_ARGUMENT_PUBLIC_KEY);
1421 /* Notify application */
1422 silc_client_command_callback(cmd, channel, mode, public_key,
1423 channel_pubkeys, channel->user_limit);
1425 silc_argument_list_free(channel_pubkeys, SILC_ARGUMENT_PUBLIC_KEY);
1429 silc_pkcs_public_key_free(public_key);
1430 silc_fsm_next(fsm, silc_client_command_reply_processed);
1431 return SILC_FSM_CONTINUE;
1434 /********************************** CUMODE **********************************/
1436 /* Received reply for CUMODE command */
1438 SILC_FSM_STATE(silc_client_command_reply_cumode)
1440 SilcClientCommandContext cmd = fsm_context;
1441 SilcClientConnection conn = cmd->conn;
1442 SilcClient client = conn->client;
1443 SilcCommandPayload payload = state_context;
1444 SilcArgumentPayload args = silc_command_get_args(payload);
1445 SilcClientEntry client_entry;
1446 SilcChannelEntry channel;
1447 SilcChannelUser chu;
1448 unsigned char *modev;
1449 SilcUInt32 len, mode;
1453 CHECK_STATUS("Cannot change mode: ");
1456 /* Get channel mode */
1457 modev = silc_argument_get_arg_type(args, 2, &len);
1458 if (!modev || len != 4) {
1459 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1462 SILC_GET32_MSB(mode, modev);
1464 /* Take Channel ID */
1465 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1466 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1470 /* Get the channel entry */
1471 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1473 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1478 if (!silc_argument_get_decoded(args, 4, SILC_ARGUMENT_ID, &id, NULL)) {
1479 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1483 /* Get client entry */
1484 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1485 if (!client_entry) {
1486 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1491 chu = silc_client_on_channel(channel, client_entry);
1495 /* Notify application */
1496 silc_client_command_callback(cmd, mode, channel, client_entry);
1498 silc_client_unref_client(client, conn, client_entry);
1501 silc_fsm_next(fsm, silc_client_command_reply_processed);
1502 return SILC_FSM_CONTINUE;
1505 /********************************** KICK ************************************/
1507 SILC_FSM_STATE(silc_client_command_reply_kick)
1509 SilcClientCommandContext cmd = fsm_context;
1510 SilcClientConnection conn = cmd->conn;
1511 SilcClient client = conn->client;
1512 SilcCommandPayload payload = state_context;
1513 SilcArgumentPayload args = silc_command_get_args(payload);
1514 SilcClientEntry client_entry;
1515 SilcChannelEntry channel;
1519 CHECK_STATUS("Cannot kick: ");
1522 /* Take Channel ID */
1523 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1524 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1528 /* Get the channel entry */
1529 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1531 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1536 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1537 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1541 /* Get client entry */
1542 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1543 if (!client_entry) {
1544 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1548 /* Notify application */
1549 silc_client_command_callback(cmd, channel, client_entry);
1551 silc_client_unref_client(client, conn, client_entry);
1554 silc_fsm_next(fsm, silc_client_command_reply_processed);
1555 return SILC_FSM_CONTINUE;
1558 /******************************** SILCOPER **********************************/
1560 SILC_FSM_STATE(silc_client_command_reply_silcoper)
1562 SilcClientCommandContext cmd = fsm_context;
1563 SilcCommandPayload payload = state_context;
1564 SilcArgumentPayload args = silc_command_get_args(payload);
1567 CHECK_STATUS("Cannot change mode: ");
1570 /* Notify application */
1571 silc_client_command_callback(cmd);
1573 silc_fsm_next(fsm, silc_client_command_reply_processed);
1574 return SILC_FSM_CONTINUE;
1577 /********************************** OPER ************************************/
1579 SILC_FSM_STATE(silc_client_command_reply_oper)
1581 SilcClientCommandContext cmd = fsm_context;
1582 SilcCommandPayload payload = state_context;
1583 SilcArgumentPayload args = silc_command_get_args(payload);
1586 CHECK_STATUS("Cannot change mode: ");
1589 /* Notify application */
1590 silc_client_command_callback(cmd);
1592 silc_fsm_next(fsm, silc_client_command_reply_processed);
1593 return SILC_FSM_CONTINUE;
1596 /********************************* DETACH ***********************************/
1598 SILC_FSM_STATE(silc_client_command_reply_detach)
1600 SilcClientCommandContext cmd = fsm_context;
1601 SilcClientConnection conn = cmd->conn;
1602 SilcClient client = conn->client;
1603 SilcCommandPayload payload = state_context;
1604 SilcArgumentPayload args = silc_command_get_args(payload);
1608 CHECK_STATUS("Cannot detach: ");
1611 /* Notify application */
1612 silc_client_command_callback(cmd);
1615 /* Generate the detachment data and deliver it to the client in the
1616 detach client operation */
1617 detach = silc_client_get_detach_data(client, conn);
1619 client->internal->ops->detach(client, conn, silc_buffer_data(detach),
1620 silc_buffer_len(detach));
1621 silc_buffer_free(detach);
1625 silc_fsm_next(fsm, silc_client_command_reply_processed);
1626 return SILC_FSM_CONTINUE;
1629 /********************************** WATCH ***********************************/
1631 SILC_FSM_STATE(silc_client_command_reply_watch)
1633 SilcClientCommandContext cmd = fsm_context;
1634 SilcCommandPayload payload = state_context;
1635 SilcArgumentPayload args = silc_command_get_args(payload);
1638 CHECK_STATUS("Cannot set watch: ");
1641 /* Notify application */
1642 silc_client_command_callback(cmd);
1644 silc_fsm_next(fsm, silc_client_command_reply_processed);
1645 return SILC_FSM_CONTINUE;
1648 /*********************************** BAN ************************************/
1650 SILC_FSM_STATE(silc_client_command_reply_ban)
1652 SilcClientCommandContext cmd = fsm_context;
1653 SilcClientConnection conn = cmd->conn;
1654 SilcClient client = conn->client;
1655 SilcCommandPayload payload = state_context;
1656 SilcArgumentPayload args = silc_command_get_args(payload);
1657 SilcChannelEntry channel;
1660 SilcArgumentPayload invite_args = NULL;
1664 CHECK_STATUS("Cannot set ban: ");
1667 /* Take Channel ID */
1668 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1669 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1673 /* Get the channel entry */
1674 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1676 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1680 /* Get the invite list */
1681 tmp = silc_argument_get_arg_type(args, 3, &len);
1683 invite_args = silc_argument_list_parse(tmp, len);
1685 /* Notify application */
1686 silc_client_command_callback(cmd, channel, invite_args);
1689 silc_argument_payload_free(invite_args);
1692 silc_fsm_next(fsm, silc_client_command_reply_processed);
1693 return SILC_FSM_CONTINUE;
1696 /********************************** LEAVE ***********************************/
1698 /* Reply to LEAVE command. */
1700 SILC_FSM_STATE(silc_client_command_reply_leave)
1702 SilcClientCommandContext cmd = fsm_context;
1703 SilcClientConnection conn = cmd->conn;
1704 SilcClient client = conn->client;
1705 SilcCommandPayload payload = state_context;
1706 SilcArgumentPayload args = silc_command_get_args(payload);
1707 SilcChannelEntry channel;
1711 CHECK_STATUS("Cannot set leave: ");
1714 /* Get Channel ID */
1715 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1716 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1720 /* Get the channel entry */
1721 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1723 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1727 /* Remove us from this channel. */
1728 silc_client_remove_from_channel(client, conn, channel, conn->local_entry);
1730 /* Notify application */
1731 silc_client_command_callback(cmd, channel);
1733 /* Now delete the channel. */
1734 silc_client_del_channel(client, conn, channel);
1737 silc_fsm_next(fsm, silc_client_command_reply_processed);
1738 return SILC_FSM_CONTINUE;
1741 /********************************* USERS ************************************/
1743 /* Continue USERS command reply processing after resolving unknown users */
1746 silc_client_command_reply_users_resolved(SilcClient client,
1747 SilcClientConnection conn,
1752 SilcClientCommandContext cmd = context;
1753 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1757 /* Continue USERS command after resolving unknown channel */
1760 silc_client_command_reply_users_continue(SilcClient client,
1761 SilcClientConnection conn,
1766 SilcClientCommandContext cmd = context;
1769 SilcCommandPayload payload = silc_fsm_get_state_context(&cmd->thread);
1770 SilcArgumentPayload args = silc_command_get_args(payload);
1772 cmd->status = SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID;
1773 ERROR_CALLBACK(cmd->status);
1774 silc_fsm_next(&cmd->thread, silc_client_command_reply_processed);
1777 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1780 /* Reply to USERS command. Received list of client ID's and theirs modes
1781 on the channel we requested. */
1783 SILC_FSM_STATE(silc_client_command_reply_users)
1785 SilcClientCommandContext cmd = fsm_context;
1786 SilcClientConnection conn = cmd->conn;
1787 SilcClient client = conn->client;
1788 SilcCommandPayload payload = state_context;
1789 SilcArgumentPayload args = silc_command_get_args(payload);
1791 SilcUInt32 tmp_len, list_count;
1792 SilcUInt16 idp_len, mode;
1793 SilcHashTableList htl;
1794 SilcBufferStruct client_id_list, client_mode_list;
1795 SilcChannelEntry channel;
1796 SilcClientEntry client_entry;
1801 CHECK_STATUS("Cannot get users: ");
1804 /* Get channel ID */
1805 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1806 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1810 /* Get channel entry */
1811 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1813 /* Resolve the channel from server */
1814 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1815 client, conn, &id.u.channel_id,
1816 silc_client_command_reply_users_continue, cmd));
1820 /* Get the list count */
1821 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1822 if (!tmp || tmp_len != 4) {
1823 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1826 SILC_GET32_MSB(list_count, tmp);
1828 /* Get Client ID list */
1829 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1831 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1834 silc_buffer_set(&client_id_list, tmp, tmp_len);
1836 /* Resolve users we do not know about */
1837 if (!cmd->resolved) {
1838 cmd->resolved = TRUE;
1839 SILC_FSM_CALL(silc_client_get_clients_by_list(
1840 client, conn, list_count, &client_id_list,
1841 silc_client_command_reply_users_resolved, cmd));
1845 /* Get client mode list */
1846 tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
1848 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1851 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1853 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1855 /* Cache the received Client ID's and modes. */
1856 for (i = 0; i < list_count; i++) {
1857 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1859 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1863 SILC_GET32_MSB(mode, client_mode_list.data);
1865 /* Save the client on this channel. Unknown clients are ignored as they
1866 clearly do not exist since the resolving didn't find them. */
1867 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1869 silc_client_add_to_channel(client, conn, channel, client_entry, mode);
1870 silc_client_unref_client(client, conn, client_entry);
1872 if (!silc_buffer_pull(&client_id_list, idp_len))
1874 if (!silc_buffer_pull(&client_mode_list, 4))
1878 /* Notify application */
1879 silc_hash_table_list(channel->user_list, &htl);
1880 silc_client_command_callback(cmd, channel, &htl);
1881 silc_hash_table_list_reset(&htl);
1884 silc_fsm_next(fsm, silc_client_command_reply_processed);
1885 return SILC_FSM_CONTINUE;
1888 /********************************** GETKEY **********************************/
1890 /* Received command reply to GETKEY command. WE've received the remote
1891 client's public key. */
1893 SILC_FSM_STATE(silc_client_command_reply_getkey)
1895 SilcClientCommandContext cmd = fsm_context;
1896 SilcClientConnection conn = cmd->conn;
1897 SilcClient client = conn->client;
1898 SilcCommandPayload payload = state_context;
1899 SilcArgumentPayload args = silc_command_get_args(payload);
1900 SilcClientEntry client_entry;
1901 SilcServerEntry server_entry;
1904 SilcPublicKey public_key;
1908 CHECK_STATUS("Cannot get key: ");
1912 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1913 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1917 /* Get the public key */
1918 tmp = silc_argument_get_arg_type(args, 3, &len);
1920 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1923 if (!silc_public_key_payload_decode(tmp, len, &public_key)) {
1924 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1928 if (id.type == SILC_ID_CLIENT) {
1929 /* Received client's public key */
1930 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1931 if (!client_entry) {
1932 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1936 /* Save fingerprint */
1937 if (!client_entry->fingerprint)
1938 silc_hash_make(conn->internal->sha1hash, tmp + 4, len - 4,
1939 client_entry->fingerprint);
1940 if (!client_entry->public_key) {
1941 client_entry->public_key = public_key;
1945 /* Notify application */
1946 silc_client_command_callback(cmd, SILC_ID_CLIENT, client_entry,
1947 client_entry->public_key);
1948 silc_client_unref_client(client, conn, client_entry);
1949 } else if (id.type == SILC_ID_SERVER) {
1950 /* Received server's public key */
1951 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1952 if (!server_entry) {
1953 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1957 if (!server_entry->public_key) {
1958 server_entry->public_key = public_key;
1962 /* Notify application */
1963 silc_client_command_callback(cmd, SILC_ID_SERVER, server_entry,
1964 server_entry->public_key);
1965 silc_client_unref_server(client, conn, server_entry);
1970 silc_pkcs_public_key_free(public_key);
1971 silc_fsm_next(fsm, silc_client_command_reply_processed);
1972 return SILC_FSM_CONTINUE;
1975 /********************************** SERVICE *********************************/
1977 /* Reply to SERVICE command. */
1978 /* XXX incomplete */
1980 SILC_FSM_STATE(silc_client_command_reply_service)
1982 SilcClientCommandContext cmd = fsm_context;
1983 SilcCommandPayload payload = state_context;
1984 SilcArgumentPayload args = silc_command_get_args(payload);
1986 unsigned char *service_list, *name;
1989 CHECK_STATUS("Cannot get service: ");
1991 /* Get service list */
1992 service_list = silc_argument_get_arg_type(args, 2, &tmp_len);
1994 /* Get requested service name */
1995 name = silc_argument_get_arg_type(args, 3, &tmp_len);
1997 /* Notify application */
1998 silc_client_command_callback(cmd, service_list, name);
2000 silc_fsm_next(fsm, silc_client_command_reply_processed);
2001 return SILC_FSM_CONTINUE;
2004 /*********************************** QUIT ***********************************/
2006 /* QUIT command reply stub */
2008 SILC_FSM_STATE(silc_client_command_reply_quit)
2010 silc_fsm_next(fsm, silc_client_command_reply_processed);
2011 return SILC_FSM_CONTINUE;