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); \
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); \
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;
77 /* Default reply callback */
80 cmd->conn->client->internal->ops->command_reply(
81 cmd->conn->client, cmd->conn, cmd->cmd, cmd->status,
87 list = cmd->reply_callbacks;
88 silc_list_start(list);
89 while ((cb = silc_list_get(list)))
90 if (!cb->do_not_call) {
92 cb->do_not_call = !cb->reply(cmd->conn->client, cmd->conn, cmd->cmd,
93 cmd->status, cmd->error, cb->context, cp);
100 /* Handles common error status types. */
102 static void silc_client_command_process_error(SilcClientCommandContext cmd,
103 SilcCommandPayload payload,
106 SilcClient client = cmd->conn->client;
107 SilcClientConnection conn = cmd->conn;
108 SilcArgumentPayload args = silc_command_get_args(payload);
111 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
112 SilcClientEntry client_entry;
114 /* Remove unknown client entry from cache */
115 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
118 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
120 silc_client_remove_from_channels(client, conn, client_entry);
121 silc_client_del_client(client, conn, client_entry);
122 silc_client_unref_client(client, conn, client_entry);
127 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID) {
128 SilcChannelEntry channel;
130 /* Remove unknown client entry from cache */
131 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
134 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
136 silc_client_empty_channel(client, conn, channel);
137 silc_client_del_channel(client, conn, channel);
138 silc_client_unref_channel(client, conn, channel);
143 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_SERVER_ID) {
144 SilcServerEntry server_entry;
146 /* Remove unknown client entry from cache */
147 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
150 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
152 silc_client_del_server(client, conn, server_entry);
153 silc_client_unref_server(client, conn, server_entry);
159 /***************************** Command Reply ********************************/
161 /* Process received command reply packet */
163 SILC_FSM_STATE(silc_client_command_reply)
165 SilcClientConnection conn = fsm_context;
166 SilcPacket packet = state_context;
167 SilcClientCommandContext cmd;
168 SilcCommandPayload payload;
170 SilcUInt16 cmd_ident;
172 /* Get command reply payload from packet */
173 payload = silc_command_payload_parse(silc_buffer_datalen(&packet->buffer));
174 silc_packet_free(packet);
176 SILC_LOG_DEBUG(("Bad command reply packet"));
180 cmd_ident = silc_command_get_ident(payload);
181 command = silc_command_get(payload);
183 /* Find the command pending reply */
184 silc_mutex_lock(conn->internal->lock);
185 silc_list_start(conn->internal->pending_commands);
186 while ((cmd = silc_list_get(conn->internal->pending_commands))) {
187 if ((cmd->cmd == command || cmd->cmd == SILC_COMMAND_NONE)
188 && cmd->cmd_ident == cmd_ident) {
189 silc_list_del(conn->internal->pending_commands, cmd);
193 silc_mutex_unlock(conn->internal->lock);
196 SILC_LOG_DEBUG(("Unknown command reply %s, ident %d",
197 silc_get_command_name(command), cmd_ident));
198 silc_command_payload_free(payload);
202 /* Signal command thread that command reply has arrived */
203 silc_fsm_set_state_context(&cmd->thread, payload);
204 silc_fsm_next(&cmd->thread, silc_client_command_reply_process);
205 silc_fsm_continue_sync(&cmd->thread);
210 /* Wait here for command reply to arrive from remote host */
212 SILC_FSM_STATE(silc_client_command_reply_wait)
214 SilcClientCommandContext cmd = fsm_context;
216 SILC_LOG_DEBUG(("Wait for command reply"));
218 /** Wait for command reply */
219 silc_fsm_set_state_context(fsm, NULL);
220 silc_fsm_next_later(fsm, silc_client_command_reply_timeout,
221 cmd->cmd != SILC_COMMAND_PING ? 25 : 60, 0);
225 /* Timeout occurred while waiting command reply */
227 SILC_FSM_STATE(silc_client_command_reply_timeout)
229 SilcClientCommandContext cmd = fsm_context;
230 SilcClientConnection conn = cmd->conn;
231 SilcArgumentPayload args = NULL;
233 if (conn->internal->disconnected) {
234 SILC_LOG_DEBUG(("Command %s canceled", silc_get_command_name(cmd->cmd)));
235 silc_list_del(conn->internal->pending_commands, cmd);
239 SILC_LOG_DEBUG(("Command %s timeout", silc_get_command_name(cmd->cmd)));
241 /* Timeout, reply not received in timely fashion */
242 silc_list_del(conn->internal->pending_commands, cmd);
243 ERROR_CALLBACK(SILC_STATUS_ERR_TIMEDOUT);
247 /* Process received command reply payload */
249 SILC_FSM_STATE(silc_client_command_reply_process)
251 SilcClientCommandContext cmd = fsm_context;
252 SilcCommandPayload payload = state_context;
254 silc_command_get_status(payload, &cmd->status, &cmd->error);
257 case SILC_COMMAND_WHOIS:
259 silc_fsm_next(fsm, silc_client_command_reply_whois);
261 case SILC_COMMAND_WHOWAS:
263 silc_fsm_next(fsm, silc_client_command_reply_whowas);
265 case SILC_COMMAND_IDENTIFY:
267 silc_fsm_next(fsm, silc_client_command_reply_identify);
269 case SILC_COMMAND_NICK:
271 silc_fsm_next(fsm, silc_client_command_reply_nick);
273 case SILC_COMMAND_LIST:
275 silc_fsm_next(fsm, silc_client_command_reply_list);
277 case SILC_COMMAND_TOPIC:
279 silc_fsm_next(fsm, silc_client_command_reply_topic);
281 case SILC_COMMAND_INVITE:
283 silc_fsm_next(fsm, silc_client_command_reply_invite);
285 case SILC_COMMAND_QUIT:
287 silc_fsm_next(fsm, silc_client_command_reply_quit);
289 case SILC_COMMAND_KILL:
291 silc_fsm_next(fsm, silc_client_command_reply_kill);
293 case SILC_COMMAND_INFO:
295 silc_fsm_next(fsm, silc_client_command_reply_info);
297 case SILC_COMMAND_STATS:
299 silc_fsm_next(fsm, silc_client_command_reply_stats);
301 case SILC_COMMAND_PING:
303 silc_fsm_next(fsm, silc_client_command_reply_ping);
305 case SILC_COMMAND_OPER:
307 silc_fsm_next(fsm, silc_client_command_reply_oper);
309 case SILC_COMMAND_JOIN:
311 silc_fsm_next(fsm, silc_client_command_reply_join);
313 case SILC_COMMAND_MOTD:
315 silc_fsm_next(fsm, silc_client_command_reply_motd);
317 case SILC_COMMAND_UMODE:
319 silc_fsm_next(fsm, silc_client_command_reply_umode);
321 case SILC_COMMAND_CMODE:
323 silc_fsm_next(fsm, silc_client_command_reply_cmode);
325 case SILC_COMMAND_CUMODE:
327 silc_fsm_next(fsm, silc_client_command_reply_cumode);
329 case SILC_COMMAND_KICK:
331 silc_fsm_next(fsm, silc_client_command_reply_kick);
333 case SILC_COMMAND_BAN:
335 silc_fsm_next(fsm, silc_client_command_reply_ban);
337 case SILC_COMMAND_DETACH:
339 silc_fsm_next(fsm, silc_client_command_reply_detach);
341 case SILC_COMMAND_WATCH:
343 silc_fsm_next(fsm, silc_client_command_reply_watch);
345 case SILC_COMMAND_SILCOPER:
347 silc_fsm_next(fsm, silc_client_command_reply_silcoper);
349 case SILC_COMMAND_LEAVE:
351 silc_fsm_next(fsm, silc_client_command_reply_leave);
353 case SILC_COMMAND_USERS:
355 silc_fsm_next(fsm, silc_client_command_reply_users);
357 case SILC_COMMAND_GETKEY:
359 silc_fsm_next(fsm, silc_client_command_reply_getkey);
361 case SILC_COMMAND_SERVICE:
363 silc_fsm_next(fsm, silc_client_command_reply_service);
372 /* Completes command reply processing */
374 SILC_FSM_STATE(silc_client_command_reply_processed)
376 SilcClientCommandContext cmd = fsm_context;
377 SilcClientConnection conn = cmd->conn;
378 SilcCommandPayload payload = state_context;
380 silc_command_payload_free(payload);
382 if (cmd->status == SILC_STATUS_OK || cmd->status == SILC_STATUS_LIST_END ||
383 SILC_STATUS_IS_ERROR(cmd->status))
386 /* Add back to pending command reply list */
387 silc_mutex_lock(conn->internal->lock);
388 cmd->resolved = FALSE;
389 silc_list_add(conn->internal->pending_commands, cmd);
390 silc_mutex_unlock(conn->internal->lock);
392 /** Wait more command payloads */
393 silc_fsm_next(fsm, silc_client_command_reply_wait);
397 /******************************** WHOIS *************************************/
399 /* Received reply for WHOIS command. */
401 SILC_FSM_STATE(silc_client_command_reply_whois)
403 SilcClientCommandContext cmd = fsm_context;
404 SilcClientConnection conn = cmd->conn;
405 SilcClient client = conn->client;
406 SilcCommandPayload payload = state_context;
407 SilcArgumentPayload args = silc_command_get_args(payload);
408 SilcClientEntry client_entry = NULL;
409 SilcUInt32 idle = 0, mode = 0, fingerprint_len, len, *umodes = NULL;
410 SilcBufferStruct channels, ch_user_modes;
411 SilcBool has_channels = FALSE;
412 SilcDList channel_list = NULL;
414 char *nickname = NULL, *username = NULL, *realname = NULL;
415 unsigned char *fingerprint, *tmp;
417 CHECK_STATUS("WHOIS: ");
421 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
422 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
427 nickname = silc_argument_get_arg_type(args, 3, NULL);
428 username = silc_argument_get_arg_type(args, 4, NULL);
429 realname = silc_argument_get_arg_type(args, 5, NULL);
430 if (!nickname || !username || !realname) {
431 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
435 /* Get joined channel list */
436 memset(&channels, 0, sizeof(channels));
437 tmp = silc_argument_get_arg_type(args, 6, &len);
440 silc_buffer_set(&channels, tmp, len);
442 /* Get channel user mode list */
443 tmp = silc_argument_get_arg_type(args, 10, &len);
445 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
448 silc_buffer_set(&ch_user_modes, tmp, len);
452 tmp = silc_argument_get_arg_type(args, 7, &len);
454 SILC_GET32_MSB(mode, tmp);
457 tmp = silc_argument_get_arg_type(args, 8, &len);
459 SILC_GET32_MSB(idle, tmp);
461 /* Get fingerprint */
462 fingerprint = silc_argument_get_arg_type(args, 9, &fingerprint_len);
464 /* Check if we have this client cached already. */
465 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
467 SILC_LOG_DEBUG(("Adding new client entry (WHOIS)"));
469 silc_client_add_client(client, conn, nickname, username, realname,
470 &id.u.client_id, mode);
472 ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
475 silc_client_ref_client(client, conn, client_entry);
477 silc_client_update_client(client, conn, client_entry,
478 nickname, username, realname, mode);
481 if (fingerprint && fingerprint_len == sizeof(client_entry->fingerprint))
482 memcpy(client_entry->fingerprint, fingerprint, fingerprint_len);
484 /* Get user attributes */
485 tmp = silc_argument_get_arg_type(args, 11, &len);
487 if (client_entry->attrs)
488 silc_attribute_payload_list_free(client_entry->attrs);
489 client_entry->attrs = silc_attribute_payload_parse(tmp, len);
492 /* Parse channel and channel user mode list */
494 channel_list = silc_channel_payload_parse_list(silc_buffer_data(&channels),
495 silc_buffer_len(&channels));
497 silc_get_mode_list(&ch_user_modes, silc_dlist_count(channel_list),
501 /* Notify application */
502 silc_client_command_callback(cmd, client_entry, nickname, username,
503 realname, channel_list, mode, idle, fingerprint,
504 umodes, client_entry->attrs);
506 silc_client_unref_client(client, conn, client_entry);
508 silc_dlist_uninit(channel_list);
513 silc_fsm_next(fsm, silc_client_command_reply_processed);
517 /******************************** WHOWAS ************************************/
519 /* Received reply for WHOWAS command. */
521 SILC_FSM_STATE(silc_client_command_reply_whowas)
523 SilcClientCommandContext cmd = fsm_context;
524 SilcClientConnection conn = cmd->conn;
525 SilcClient client = conn->client;
526 SilcCommandPayload payload = state_context;
527 SilcArgumentPayload args = silc_command_get_args(payload);
528 SilcClientEntry client_entry = NULL;
530 char *nickname, *username;
531 char *realname = NULL;
533 CHECK_STATUS("WHOWAS: ");
537 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
538 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
542 /* Get the client entry */
543 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
546 nickname = silc_argument_get_arg_type(args, 3, NULL);
547 username = silc_argument_get_arg_type(args, 4, NULL);
548 realname = silc_argument_get_arg_type(args, 5, NULL);
549 if (!nickname || !username) {
550 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
554 /* Notify application. We don't save any history information to any
555 cache. Just pass the data to the application. */
556 silc_client_command_callback(cmd, client_entry, nickname, username,
560 silc_client_unref_client(client, conn, client_entry);
561 silc_fsm_next(fsm, silc_client_command_reply_processed);
565 /******************************** IDENTIFY **********************************/
567 /* Received reply for IDENTIFY command. */
569 SILC_FSM_STATE(silc_client_command_reply_identify)
571 SilcClientCommandContext cmd = fsm_context;
572 SilcClientConnection conn = cmd->conn;
573 SilcClient client = conn->client;
574 SilcCommandPayload payload = state_context;
575 SilcArgumentPayload args = silc_command_get_args(payload);
576 SilcClientEntry client_entry;
577 SilcServerEntry server_entry;
578 SilcChannelEntry channel_entry;
581 char *name = NULL, *info = NULL;
583 CHECK_STATUS("IDENTIFY: ");
587 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
588 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
593 name = silc_argument_get_arg_type(args, 3, &len);
594 info = silc_argument_get_arg_type(args, 4, &len);
598 SILC_LOG_DEBUG(("Received client information"));
600 /* Check if we have this client cached already. */
601 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
603 SILC_LOG_DEBUG(("Adding new client entry (IDENTIFY)"));
605 silc_client_add_client(client, conn, name, info, NULL,
608 ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
611 silc_client_ref_client(client, conn, client_entry);
613 silc_client_update_client(client, conn, client_entry,
614 name, info, NULL, 0);
617 /* Notify application */
618 silc_client_command_callback(cmd, client_entry, name, info);
619 silc_client_unref_client(client, conn, client_entry);
623 SILC_LOG_DEBUG(("Received server information"));
625 /* Check if we have this server cached already. */
626 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
628 SILC_LOG_DEBUG(("Adding new server entry (IDENTIFY)"));
629 server_entry = silc_client_add_server(client, conn, name, info,
632 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
635 silc_client_ref_server(client, conn, server_entry);
637 silc_client_update_server(client, conn, server_entry, name, info);
639 server_entry->internal.resolve_cmd_ident = 0;
641 /* Notify application */
642 silc_client_command_callback(cmd, server_entry, name, info);
643 silc_client_unref_server(client, conn, server_entry);
646 case SILC_ID_CHANNEL:
647 SILC_LOG_DEBUG(("Received channel information"));
649 /* Check if we have this channel cached already. */
650 channel_entry = silc_client_get_channel_by_id(client, conn,
652 if (!channel_entry) {
653 SILC_LOG_DEBUG(("Adding new channel entry (IDENTIFY)"));
656 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
660 /* Add new channel entry */
661 channel_entry = silc_client_add_channel(client, conn, name, 0,
663 if (!channel_entry) {
664 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
667 silc_client_ref_channel(client, conn, channel_entry);
670 /* Notify application */
671 silc_client_command_callback(cmd, channel_entry, name, info);
672 silc_client_unref_channel(client, conn, channel_entry);
677 silc_fsm_next(fsm, silc_client_command_reply_processed);
681 /********************************** NICK ************************************/
683 /* Received reply for command NICK. */
685 SILC_FSM_STATE(silc_client_command_reply_nick)
687 SilcClientCommandContext cmd = fsm_context;
688 SilcClientConnection conn = cmd->conn;
689 SilcClient client = conn->client;
690 SilcCommandPayload payload = state_context;
691 SilcArgumentPayload args = silc_command_get_args(payload);
692 unsigned char *nick, *idp;
693 SilcUInt32 len, idp_len;
694 SilcClientID old_client_id;
698 CHECK_STATUS("Cannot set nickname: ");
701 /* Take received Client ID */
702 idp = silc_argument_get_arg_type(args, 2, &idp_len);
704 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
707 if (!silc_id_payload_parse_id(idp, idp_len, &id)) {
708 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
712 /* Take the new nickname */
713 nick = silc_argument_get_arg_type(args, 3, &len);
715 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
719 /* Change the nickname */
720 old_client_id = *conn->local_id;
721 if (!silc_client_change_nickname(client, conn, conn->local_entry,
722 nick, &id.u.client_id, idp, idp_len)) {
723 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_NICKNAME);
727 /* Notify application */
728 silc_client_command_callback(cmd, conn->local_entry,
729 conn->local_entry->nickname, &old_client_id);
732 silc_fsm_next(fsm, silc_client_command_reply_processed);
736 /********************************** LIST ************************************/
738 /* Received reply to the LIST command. */
740 SILC_FSM_STATE(silc_client_command_reply_list)
742 SilcClientCommandContext cmd = fsm_context;
743 SilcClientConnection conn = cmd->conn;
744 SilcClient client = conn->client;
745 SilcCommandPayload payload = state_context;
746 SilcArgumentPayload args = silc_command_get_args(payload);
747 unsigned char *tmp, *name, *topic;
748 SilcUInt32 usercount = 0;
749 SilcChannelEntry channel_entry = NULL;
753 CHECK_STATUS("Cannot list channels: ");
755 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
756 /* There were no channels in the network. */
757 silc_client_command_callback(cmd, NULL, NULL, NULL, 0);
758 silc_fsm_next(fsm, silc_client_command_reply_processed);
764 name = silc_argument_get_arg_type(args, 3, NULL);
766 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
770 topic = silc_argument_get_arg_type(args, 4, NULL);
771 tmp = silc_argument_get_arg_type(args, 5, NULL);
773 SILC_GET32_MSB(usercount, tmp);
775 /* Check whether the channel exists, and add it to cache if it doesn't. */
776 channel_entry = silc_client_get_channel_by_id(client, conn,
778 if (!channel_entry) {
779 /* Add new channel entry */
780 channel_entry = silc_client_add_channel(client, conn, name, 0,
782 if (!channel_entry) {
783 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
786 silc_client_ref_channel(client, conn, channel_entry);
789 /* Notify application */
790 silc_client_command_callback(cmd, channel_entry, name, topic, usercount);
793 silc_client_unref_channel(client, conn, channel_entry);
794 silc_fsm_next(fsm, silc_client_command_reply_processed);
798 /********************************* TOPIC ************************************/
800 /* Received reply to topic command. */
802 SILC_FSM_STATE(silc_client_command_reply_topic)
804 SilcClientCommandContext cmd = fsm_context;
805 SilcClientConnection conn = cmd->conn;
806 SilcClient client = conn->client;
807 SilcCommandPayload payload = state_context;
808 SilcArgumentPayload args = silc_command_get_args(payload);
809 SilcChannelEntry channel;
815 CHECK_STATUS("Cannot set topic: ");
818 /* Take Channel ID */
819 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
820 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
824 /* Get the channel entry */
825 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
827 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
832 topic = silc_argument_get_arg_type(args, 3, &len);
834 silc_free(channel->topic);
835 channel->topic = silc_memdup(topic, len);
838 /* Notify application */
839 silc_client_command_callback(cmd, channel, channel->topic);
842 silc_fsm_next(fsm, silc_client_command_reply_processed);
846 /********************************* INVITE ***********************************/
848 /* Received reply to invite command. */
850 SILC_FSM_STATE(silc_client_command_reply_invite)
852 SilcClientCommandContext cmd = fsm_context;
853 SilcClientConnection conn = cmd->conn;
854 SilcClient client = conn->client;
855 SilcCommandPayload payload = state_context;
856 SilcArgumentPayload args = silc_command_get_args(payload);
857 SilcChannelEntry channel;
860 SilcArgumentPayload invite_args = NULL;
864 CHECK_STATUS("Cannot invite: ");
867 /* Take Channel ID */
868 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
869 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
873 /* Get the channel entry */
874 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
876 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
880 /* Get the invite list */
881 tmp = silc_argument_get_arg_type(args, 3, &len);
883 invite_args = silc_argument_list_parse(tmp, len);
885 /* Notify application */
886 silc_client_command_callback(cmd, channel, invite_args);
889 silc_argument_payload_free(invite_args);
892 silc_fsm_next(fsm, silc_client_command_reply_processed);
896 /********************************** KILL ************************************/
898 /* Received reply to the KILL command. */
900 SILC_FSM_STATE(silc_client_command_reply_kill)
902 SilcClientCommandContext cmd = fsm_context;
903 SilcClientConnection conn = cmd->conn;
904 SilcClient client = conn->client;
905 SilcCommandPayload payload = state_context;
906 SilcArgumentPayload args = silc_command_get_args(payload);
907 SilcClientEntry client_entry;
911 CHECK_STATUS("Cannot kill: ");
914 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
915 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
919 /* Get the client entry, if exists */
920 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
922 /* Notify application */
923 silc_client_command_callback(cmd, client_entry);
925 /* Remove the client from all channels and free it */
927 silc_client_remove_from_channels(client, conn, client_entry);
928 silc_client_del_client(client, conn, client_entry);
929 silc_client_unref_client(client, conn, client_entry);
933 silc_fsm_next(fsm, silc_client_command_reply_processed);
937 /********************************** INFO ************************************/
939 /* Received reply to INFO command. We receive the server ID and some
940 information about the server user requested. */
942 SILC_FSM_STATE(silc_client_command_reply_info)
944 SilcClientCommandContext cmd = fsm_context;
945 SilcClientConnection conn = cmd->conn;
946 SilcClient client = conn->client;
947 SilcCommandPayload payload = state_context;
948 SilcArgumentPayload args = silc_command_get_args(payload);
949 SilcServerEntry server;
950 char *server_name, *server_info;
954 CHECK_STATUS("Cannot get info: ");
958 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
959 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
963 /* Get server name */
964 server_name = silc_argument_get_arg_type(args, 3, NULL);
966 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
970 /* Get server info */
971 server_info = silc_argument_get_arg_type(args, 4, NULL);
973 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
977 /* See whether we have this server cached. If not create it. */
978 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
980 SILC_LOG_DEBUG(("Add new server entry (INFO)"));
981 server = silc_client_add_server(client, conn, server_name,
982 server_info, &id.u.server_id);
985 silc_client_ref_server(client, conn, server);
988 /* Notify application */
989 silc_client_command_callback(cmd, server, server->server_name,
990 server->server_info);
991 silc_client_unref_server(client, conn, server);
994 silc_fsm_next(fsm, silc_client_command_reply_processed);
998 /********************************** STATS ***********************************/
1000 /* Received reply to STATS command. */
1002 SILC_FSM_STATE(silc_client_command_reply_stats)
1004 SilcClientCommandContext cmd = fsm_context;
1005 SilcCommandPayload payload = state_context;
1006 SilcArgumentPayload args = silc_command_get_args(payload);
1007 SilcClientStats stats;
1008 unsigned char *buf = NULL;
1009 SilcUInt32 buf_len = 0;
1014 CHECK_STATUS("Cannot get stats: ");
1018 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1019 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1023 /* Get statistics structure */
1024 memset(&stats, 0, sizeof(stats));
1025 buf = silc_argument_get_arg_type(args, 3, &buf_len);
1027 silc_buffer_set(&b, buf, buf_len);
1028 silc_buffer_unformat(&b,
1029 SILC_STR_UI_INT(&stats.starttime),
1030 SILC_STR_UI_INT(&stats.uptime),
1031 SILC_STR_UI_INT(&stats.my_clients),
1032 SILC_STR_UI_INT(&stats.my_channels),
1033 SILC_STR_UI_INT(&stats.my_server_ops),
1034 SILC_STR_UI_INT(&stats.my_router_ops),
1035 SILC_STR_UI_INT(&stats.cell_clients),
1036 SILC_STR_UI_INT(&stats.cell_channels),
1037 SILC_STR_UI_INT(&stats.cell_servers),
1038 SILC_STR_UI_INT(&stats.clients),
1039 SILC_STR_UI_INT(&stats.channels),
1040 SILC_STR_UI_INT(&stats.servers),
1041 SILC_STR_UI_INT(&stats.routers),
1042 SILC_STR_UI_INT(&stats.server_ops),
1043 SILC_STR_UI_INT(&stats.router_ops),
1047 /* Notify application */
1048 silc_client_command_callback(cmd, &stats);
1051 silc_fsm_next(fsm, silc_client_command_reply_processed);
1055 /********************************** PING ************************************/
1057 /* Received reply to PING command. */
1059 SILC_FSM_STATE(silc_client_command_reply_ping)
1061 SilcClientCommandContext cmd = fsm_context;
1062 SilcClientConnection conn = cmd->conn;
1063 SilcClient client = conn->client;
1066 diff = silc_time() - SILC_PTR_TO_64(cmd->context);
1068 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO,
1069 "Ping reply from %s: %d second%s", conn->remote_host,
1070 (int)diff, diff == 1 ? "" : "s");
1072 /* Notify application */
1073 silc_client_command_callback(cmd);
1075 silc_fsm_next(fsm, silc_client_command_reply_processed);
1079 /********************************** JOIN ************************************/
1081 /* Continue JOIN command reply processing after resolving unknown users */
1084 silc_client_command_reply_join_resolved(SilcClient client,
1085 SilcClientConnection conn,
1090 SilcClientCommandContext cmd = context;
1091 SilcChannelEntry channel = cmd->context;
1093 channel->internal.resolve_cmd_ident = 0;
1094 silc_client_unref_channel(client, conn, channel);
1096 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1100 /* Received reply for JOIN command. */
1102 SILC_FSM_STATE(silc_client_command_reply_join)
1104 SilcClientCommandContext cmd = fsm_context;
1105 SilcClientConnection conn = cmd->conn;
1106 SilcClient client = conn->client;
1107 SilcCommandPayload payload = state_context;
1108 SilcArgumentPayload args = silc_command_get_args(payload);
1109 SilcChannelEntry channel;
1110 SilcUInt32 mode = 0, len, list_count;
1111 char *topic, *tmp, *channel_name = NULL, *hmac;
1113 SilcBufferStruct client_id_list, client_mode_list, keyp;
1114 SilcHashTableList htl;
1119 CHECK_STATUS("Cannot join channel: ");
1122 /* Get channel name */
1123 channel_name = silc_argument_get_arg_type(args, 2, NULL);
1124 if (!channel_name) {
1125 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1129 /* Get Channel ID */
1130 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1131 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1135 /* Check whether we have this channel entry already. */
1136 channel = silc_client_get_channel(client, conn, channel_name);
1138 if (!SILC_ID_CHANNEL_COMPARE(&channel->id, &id.u.channel_id))
1139 silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id);
1141 /* Create new channel entry */
1142 channel = silc_client_add_channel(client, conn, channel_name,
1143 mode, &id.u.channel_id);
1145 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_CHANNEL);
1148 silc_client_ref_channel(client, conn, channel);
1151 /* Get the list count */
1152 tmp = silc_argument_get_arg_type(args, 12, &len);
1154 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1157 SILC_GET32_MSB(list_count, tmp);
1159 /* Get Client ID list */
1160 tmp = silc_argument_get_arg_type(args, 13, &len);
1162 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1165 silc_buffer_set(&client_id_list, tmp, len);
1167 /* Resolve users we do not know about */
1168 if (!cmd->resolved) {
1169 cmd->resolved = TRUE;
1170 cmd->context = channel;
1171 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1172 silc_client_get_clients_by_list(
1173 client, conn, list_count, &client_id_list,
1174 silc_client_command_reply_join_resolved, cmd));
1178 /* Get client mode list */
1179 tmp = silc_argument_get_arg_type(args, 14, &len);
1181 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1184 silc_buffer_set(&client_mode_list, tmp, len);
1186 /* Add clients we received in the reply to the channel */
1187 for (i = 0; i < list_count; i++) {
1191 SilcClientEntry client_entry;
1194 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1196 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1200 SILC_GET32_MSB(mode, client_mode_list.data);
1202 /* Get client entry */
1203 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1207 /* Join client to the channel */
1208 silc_client_add_to_channel(client, conn, channel, client_entry, mode);
1209 silc_client_unref_client(client, conn, client_entry);
1211 if (!silc_buffer_pull(&client_id_list, idp_len))
1213 if (!silc_buffer_pull(&client_mode_list, 4))
1218 hmac = silc_argument_get_arg_type(args, 11, NULL);
1220 if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) {
1222 SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1223 "Cannot join channel: Unsupported HMAC `%s'", hmac);
1224 ERROR_CALLBACK(SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
1229 /* Get channel mode */
1230 tmp = silc_argument_get_arg_type(args, 5, NULL);
1232 SILC_GET32_MSB(mode, tmp);
1233 channel->mode = mode;
1235 /* Get channel key and save it */
1236 tmp = silc_argument_get_arg_type(args, 7, &len);
1238 silc_buffer_set(&keyp, tmp, len);
1239 silc_client_save_channel_key(client, conn, &keyp, channel);
1243 topic = silc_argument_get_arg_type(args, 10, NULL);
1245 silc_free(channel->topic);
1246 channel->topic = silc_memdup(topic, strlen(topic));
1249 /* Get founder key */
1250 tmp = silc_argument_get_arg_type(args, 15, &len);
1252 if (channel->founder_key)
1253 silc_pkcs_public_key_free(channel->founder_key);
1254 channel->founder_key = NULL;
1255 silc_public_key_payload_decode(tmp, len, &channel->founder_key);
1258 /* Get user limit */
1259 tmp = silc_argument_get_arg_type(args, 17, &len);
1260 if (tmp && len == 4)
1261 SILC_GET32_MSB(channel->user_limit, tmp);
1262 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1263 channel->user_limit = 0;
1265 /* Get channel public key list */
1266 tmp = silc_argument_get_arg_type(args, 16, &len);
1268 channel->channel_pubkeys =
1269 silc_argument_list_parse_decoded(tmp, len, SILC_ARGUMENT_PUBLIC_KEY);
1271 /* Set current channel */
1272 conn->current_channel = channel;
1274 cipher = (channel->internal.channel_key ?
1275 silc_cipher_get_name(channel->internal.channel_key) : NULL);
1276 silc_hash_table_list(channel->user_list, &htl);
1278 /* Notify application */
1279 silc_client_command_callback(cmd, channel_name, channel, mode, &htl,
1280 topic, cipher, hmac, channel->founder_key,
1281 channel->channel_pubkeys, channel->user_limit);
1283 silc_hash_table_list_reset(&htl);
1284 silc_client_unref_channel(client, conn, channel);
1287 silc_fsm_next(fsm, silc_client_command_reply_processed);
1291 /********************************** MOTD ************************************/
1293 /* Received reply for MOTD command */
1295 SILC_FSM_STATE(silc_client_command_reply_motd)
1297 SilcClientCommandContext cmd = fsm_context;
1298 SilcClientConnection conn = cmd->conn;
1299 SilcClient client = conn->client;
1300 SilcCommandPayload payload = state_context;
1301 SilcArgumentPayload args = silc_command_get_args(payload);
1303 char *motd = NULL, *cp, line[256];
1306 CHECK_STATUS("Cannot get motd: ");
1309 if (silc_argument_get_arg_num(args) == 3) {
1310 motd = silc_argument_get_arg_type(args, 3, NULL);
1312 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1319 if (cp[i++] == '\n') {
1320 memset(line, 0, sizeof(line));
1321 silc_strncat(line, sizeof(line), cp, i - 1);
1328 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1337 /* Notify application */
1338 silc_client_command_callback(cmd, motd);
1341 silc_fsm_next(fsm, silc_client_command_reply_processed);
1345 /********************************** UMODE ***********************************/
1347 /* Received reply to the UMODE command. Save the current user mode */
1349 SILC_FSM_STATE(silc_client_command_reply_umode)
1351 SilcClientCommandContext cmd = fsm_context;
1352 SilcClientConnection conn = cmd->conn;
1353 SilcCommandPayload payload = state_context;
1354 SilcArgumentPayload args = silc_command_get_args(payload);
1356 SilcUInt32 mode, len;
1359 CHECK_STATUS("Cannot change mode: ");
1362 tmp = silc_argument_get_arg_type(args, 2, &len);
1363 if (!tmp || len != 4) {
1364 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1368 SILC_GET32_MSB(mode, tmp);
1369 conn->local_entry->mode = mode;
1371 /* Notify application */
1372 silc_client_command_callback(cmd, mode);
1375 silc_fsm_next(fsm, silc_client_command_reply_processed);
1379 /********************************** CMODE ***********************************/
1381 /* Received reply for CMODE command. */
1383 SILC_FSM_STATE(silc_client_command_reply_cmode)
1385 SilcClientCommandContext cmd = fsm_context;
1386 SilcClientConnection conn = cmd->conn;
1387 SilcClient client = conn->client;
1388 SilcCommandPayload payload = state_context;
1389 SilcArgumentPayload args = silc_command_get_args(payload);
1392 SilcChannelEntry channel;
1394 SilcPublicKey public_key = NULL;
1395 SilcDList channel_pubkeys = NULL;
1399 CHECK_STATUS("Cannot change mode: ");
1402 /* Take Channel ID */
1403 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1404 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1408 /* Get the channel entry */
1409 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1411 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1415 /* Get channel mode */
1416 tmp = silc_argument_get_arg_type(args, 3, &len);
1417 if (!tmp || len != 4) {
1418 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1423 SILC_GET32_MSB(mode, tmp);
1424 channel->mode = mode;
1426 /* Get founder public key */
1427 tmp = silc_argument_get_arg_type(args, 4, &len);
1429 silc_public_key_payload_decode(tmp, len, &public_key);
1431 /* Get user limit */
1432 tmp = silc_argument_get_arg_type(args, 6, &len);
1433 if (tmp && len == 4)
1434 SILC_GET32_MSB(channel->user_limit, tmp);
1435 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1436 channel->user_limit = 0;
1438 /* Get channel public key(s) */
1439 tmp = silc_argument_get_arg_type(args, 5, &len);
1442 silc_argument_list_parse_decoded(tmp, len, SILC_ARGUMENT_PUBLIC_KEY);
1444 /* Notify application */
1445 silc_client_command_callback(cmd, channel, mode, public_key,
1446 channel_pubkeys, channel->user_limit);
1448 silc_argument_list_free(channel_pubkeys, SILC_ARGUMENT_PUBLIC_KEY);
1452 silc_pkcs_public_key_free(public_key);
1453 silc_fsm_next(fsm, silc_client_command_reply_processed);
1457 /********************************** CUMODE **********************************/
1459 /* Received reply for CUMODE command */
1461 SILC_FSM_STATE(silc_client_command_reply_cumode)
1463 SilcClientCommandContext cmd = fsm_context;
1464 SilcClientConnection conn = cmd->conn;
1465 SilcClient client = conn->client;
1466 SilcCommandPayload payload = state_context;
1467 SilcArgumentPayload args = silc_command_get_args(payload);
1468 SilcClientEntry client_entry;
1469 SilcChannelEntry channel;
1470 SilcChannelUser chu;
1471 unsigned char *modev;
1472 SilcUInt32 len, mode;
1476 CHECK_STATUS("Cannot change mode: ");
1479 /* Get channel mode */
1480 modev = silc_argument_get_arg_type(args, 2, &len);
1481 if (!modev || len != 4) {
1482 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1485 SILC_GET32_MSB(mode, modev);
1487 /* Take Channel ID */
1488 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1489 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1493 /* Get the channel entry */
1494 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1496 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1501 if (!silc_argument_get_decoded(args, 4, SILC_ARGUMENT_ID, &id, NULL)) {
1502 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1506 /* Get client entry */
1507 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1508 if (!client_entry) {
1509 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1514 chu = silc_client_on_channel(channel, client_entry);
1518 /* Notify application */
1519 silc_client_command_callback(cmd, mode, channel, client_entry);
1521 silc_client_unref_client(client, conn, client_entry);
1524 silc_fsm_next(fsm, silc_client_command_reply_processed);
1528 /********************************** KICK ************************************/
1530 SILC_FSM_STATE(silc_client_command_reply_kick)
1532 SilcClientCommandContext cmd = fsm_context;
1533 SilcClientConnection conn = cmd->conn;
1534 SilcClient client = conn->client;
1535 SilcCommandPayload payload = state_context;
1536 SilcArgumentPayload args = silc_command_get_args(payload);
1537 SilcClientEntry client_entry;
1538 SilcChannelEntry channel;
1542 CHECK_STATUS("Cannot kick: ");
1545 /* Take Channel ID */
1546 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1547 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1551 /* Get the channel entry */
1552 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1554 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1559 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1560 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1564 /* Get client entry */
1565 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1566 if (!client_entry) {
1567 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1571 /* Notify application */
1572 silc_client_command_callback(cmd, channel, client_entry);
1574 silc_client_unref_client(client, conn, client_entry);
1577 silc_fsm_next(fsm, silc_client_command_reply_processed);
1581 /******************************** SILCOPER **********************************/
1583 SILC_FSM_STATE(silc_client_command_reply_silcoper)
1585 SilcClientCommandContext cmd = fsm_context;
1586 SilcCommandPayload payload = state_context;
1587 SilcArgumentPayload args = silc_command_get_args(payload);
1590 CHECK_STATUS("Cannot change mode: ");
1593 /* Notify application */
1594 silc_client_command_callback(cmd);
1596 silc_fsm_next(fsm, silc_client_command_reply_processed);
1600 /********************************** OPER ************************************/
1602 SILC_FSM_STATE(silc_client_command_reply_oper)
1604 SilcClientCommandContext cmd = fsm_context;
1605 SilcCommandPayload payload = state_context;
1606 SilcArgumentPayload args = silc_command_get_args(payload);
1609 CHECK_STATUS("Cannot change mode: ");
1612 /* Notify application */
1613 silc_client_command_callback(cmd);
1615 silc_fsm_next(fsm, silc_client_command_reply_processed);
1619 /********************************* DETACH ***********************************/
1621 SILC_FSM_STATE(silc_client_command_reply_detach)
1623 SilcClientCommandContext cmd = fsm_context;
1624 SilcClientConnection conn = cmd->conn;
1625 SilcClient client = conn->client;
1626 SilcCommandPayload payload = state_context;
1627 SilcArgumentPayload args = silc_command_get_args(payload);
1631 CHECK_STATUS("Cannot detach: ");
1634 /* Get detachment data */
1635 detach = silc_client_get_detach_data(client, conn);
1637 ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
1641 /* Notify application */
1642 silc_client_command_callback(cmd, detach);
1643 silc_buffer_free(detach);
1646 silc_fsm_next(fsm, silc_client_command_reply_processed);
1650 /********************************** WATCH ***********************************/
1652 SILC_FSM_STATE(silc_client_command_reply_watch)
1654 SilcClientCommandContext cmd = fsm_context;
1655 SilcCommandPayload payload = state_context;
1656 SilcArgumentPayload args = silc_command_get_args(payload);
1659 CHECK_STATUS("Cannot set watch: ");
1662 /* Notify application */
1663 silc_client_command_callback(cmd);
1665 silc_fsm_next(fsm, silc_client_command_reply_processed);
1669 /*********************************** BAN ************************************/
1671 SILC_FSM_STATE(silc_client_command_reply_ban)
1673 SilcClientCommandContext cmd = fsm_context;
1674 SilcClientConnection conn = cmd->conn;
1675 SilcClient client = conn->client;
1676 SilcCommandPayload payload = state_context;
1677 SilcArgumentPayload args = silc_command_get_args(payload);
1678 SilcChannelEntry channel;
1681 SilcArgumentPayload invite_args = NULL;
1685 CHECK_STATUS("Cannot set ban: ");
1688 /* Take Channel ID */
1689 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1690 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1694 /* Get the channel entry */
1695 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1697 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1701 /* Get the invite list */
1702 tmp = silc_argument_get_arg_type(args, 3, &len);
1704 invite_args = silc_argument_list_parse(tmp, len);
1706 /* Notify application */
1707 silc_client_command_callback(cmd, channel, invite_args);
1710 silc_argument_payload_free(invite_args);
1713 silc_fsm_next(fsm, silc_client_command_reply_processed);
1717 /********************************** LEAVE ***********************************/
1719 /* Reply to LEAVE command. */
1721 SILC_FSM_STATE(silc_client_command_reply_leave)
1723 SilcClientCommandContext cmd = fsm_context;
1724 SilcClientConnection conn = cmd->conn;
1725 SilcClient client = conn->client;
1726 SilcCommandPayload payload = state_context;
1727 SilcArgumentPayload args = silc_command_get_args(payload);
1728 SilcChannelEntry channel;
1732 CHECK_STATUS("Cannot set leave: ");
1735 /* Get Channel ID */
1736 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1737 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1741 /* Get the channel entry */
1742 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1744 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1748 /* Remove us from this channel. */
1749 silc_client_remove_from_channel(client, conn, channel, conn->local_entry);
1751 /* Notify application */
1752 silc_client_command_callback(cmd, channel);
1754 /* Now delete the channel. */
1755 silc_client_empty_channel(client, conn, channel);
1756 silc_client_del_channel(client, conn, channel);
1759 silc_fsm_next(fsm, silc_client_command_reply_processed);
1763 /********************************* USERS ************************************/
1765 /* Continue USERS command reply processing after resolving unknown users */
1768 silc_client_command_reply_users_resolved(SilcClient client,
1769 SilcClientConnection conn,
1774 SilcClientCommandContext cmd = context;
1775 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1779 /* Continue USERS command after resolving unknown channel */
1782 silc_client_command_reply_users_continue(SilcClient client,
1783 SilcClientConnection conn,
1788 SilcClientCommandContext cmd = context;
1791 SilcCommandPayload payload = silc_fsm_get_state_context(&cmd->thread);
1792 SilcArgumentPayload args = silc_command_get_args(payload);
1794 cmd->status = SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID;
1795 ERROR_CALLBACK(cmd->status);
1796 silc_fsm_next(&cmd->thread, silc_client_command_reply_processed);
1799 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1802 /* Reply to USERS command. Received list of client ID's and theirs modes
1803 on the channel we requested. */
1805 SILC_FSM_STATE(silc_client_command_reply_users)
1807 SilcClientCommandContext cmd = fsm_context;
1808 SilcClientConnection conn = cmd->conn;
1809 SilcClient client = conn->client;
1810 SilcCommandPayload payload = state_context;
1811 SilcArgumentPayload args = silc_command_get_args(payload);
1813 SilcUInt32 tmp_len, list_count;
1814 SilcUInt16 idp_len, mode;
1815 SilcHashTableList htl;
1816 SilcBufferStruct client_id_list, client_mode_list;
1817 SilcChannelEntry channel;
1818 SilcClientEntry client_entry;
1823 CHECK_STATUS("Cannot get users: ");
1826 /* Get channel ID */
1827 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1828 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1832 /* Get channel entry */
1833 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1835 /* Resolve the channel from server */
1836 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1837 client, conn, &id.u.channel_id,
1838 silc_client_command_reply_users_continue, cmd));
1842 /* Get the list count */
1843 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1844 if (!tmp || tmp_len != 4) {
1845 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1848 SILC_GET32_MSB(list_count, tmp);
1850 /* Get Client ID list */
1851 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1853 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1856 silc_buffer_set(&client_id_list, tmp, tmp_len);
1858 /* Resolve users we do not know about */
1859 if (!cmd->resolved) {
1860 cmd->resolved = TRUE;
1861 SILC_FSM_CALL(silc_client_get_clients_by_list(
1862 client, conn, list_count, &client_id_list,
1863 silc_client_command_reply_users_resolved, cmd));
1867 /* Get client mode list */
1868 tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
1870 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1873 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1875 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1877 /* Cache the received Client ID's and modes. */
1878 for (i = 0; i < list_count; i++) {
1879 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1881 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1885 SILC_GET32_MSB(mode, client_mode_list.data);
1887 /* Save the client on this channel. Unknown clients are ignored as they
1888 clearly do not exist since the resolving didn't find them. */
1889 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1891 silc_client_add_to_channel(client, conn, channel, client_entry, mode);
1892 silc_client_unref_client(client, conn, client_entry);
1894 if (!silc_buffer_pull(&client_id_list, idp_len))
1896 if (!silc_buffer_pull(&client_mode_list, 4))
1900 /* Notify application */
1901 silc_hash_table_list(channel->user_list, &htl);
1902 silc_client_command_callback(cmd, channel, &htl);
1903 silc_hash_table_list_reset(&htl);
1906 silc_fsm_next(fsm, silc_client_command_reply_processed);
1910 /********************************** GETKEY **********************************/
1912 /* Received command reply to GETKEY command. WE've received the remote
1913 client's public key. */
1915 SILC_FSM_STATE(silc_client_command_reply_getkey)
1917 SilcClientCommandContext cmd = fsm_context;
1918 SilcClientConnection conn = cmd->conn;
1919 SilcClient client = conn->client;
1920 SilcCommandPayload payload = state_context;
1921 SilcArgumentPayload args = silc_command_get_args(payload);
1922 SilcClientEntry client_entry;
1923 SilcServerEntry server_entry;
1926 SilcPublicKey public_key;
1930 CHECK_STATUS("Cannot get key: ");
1934 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1935 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1939 /* Get the public key */
1940 tmp = silc_argument_get_arg_type(args, 3, &len);
1942 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1945 if (!silc_public_key_payload_decode(tmp, len, &public_key)) {
1946 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1950 if (id.type == SILC_ID_CLIENT) {
1951 /* Received client's public key */
1952 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1953 if (!client_entry) {
1954 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1958 /* Save fingerprint */
1959 if (!client_entry->fingerprint)
1960 silc_hash_make(conn->internal->sha1hash, tmp + 4, len - 4,
1961 client_entry->fingerprint);
1962 if (!client_entry->public_key) {
1963 client_entry->public_key = public_key;
1967 /* Notify application */
1968 silc_client_command_callback(cmd, SILC_ID_CLIENT, client_entry,
1969 client_entry->public_key);
1970 silc_client_unref_client(client, conn, client_entry);
1971 } else if (id.type == SILC_ID_SERVER) {
1972 /* Received server's public key */
1973 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1974 if (!server_entry) {
1975 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1979 if (!server_entry->public_key) {
1980 server_entry->public_key = public_key;
1984 /* Notify application */
1985 silc_client_command_callback(cmd, SILC_ID_SERVER, server_entry,
1986 server_entry->public_key);
1987 silc_client_unref_server(client, conn, server_entry);
1992 silc_pkcs_public_key_free(public_key);
1993 silc_fsm_next(fsm, silc_client_command_reply_processed);
1997 /********************************** SERVICE *********************************/
1999 /* Reply to SERVICE command. */
2000 /* XXX incomplete */
2002 SILC_FSM_STATE(silc_client_command_reply_service)
2004 SilcClientCommandContext cmd = fsm_context;
2005 SilcCommandPayload payload = state_context;
2006 SilcArgumentPayload args = silc_command_get_args(payload);
2008 unsigned char *service_list, *name;
2011 CHECK_STATUS("Cannot get service: ");
2013 /* Get service list */
2014 service_list = silc_argument_get_arg_type(args, 2, &tmp_len);
2016 /* Get requested service name */
2017 name = silc_argument_get_arg_type(args, 3, &tmp_len);
2019 /* Notify application */
2020 silc_client_command_callback(cmd, service_list, name);
2022 silc_fsm_next(fsm, silc_client_command_reply_processed);
2026 /*********************************** QUIT ***********************************/
2028 /* QUIT command reply stub */
2030 SILC_FSM_STATE(silc_client_command_reply_quit)
2032 silc_fsm_next(fsm, silc_client_command_reply_processed);