5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2007 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 /* Command operation that is called at the end of all commands.
28 Usage: COMMAND(status); */
29 #define COMMAND(status) cmd->conn->client->internal->ops->command( \
30 cmd->conn->client, cmd->conn, TRUE, cmd->cmd, (status), cmd->argc, cmd->argv)
32 /* Error to application. Usage: COMMAND_ERROR(status); */
33 #define COMMAND_ERROR(status) \
34 cmd->conn->client->internal->ops->command(cmd->conn->client, \
35 cmd->conn, FALSE, cmd->cmd, (status), cmd->argc, cmd->argv)
37 /* Used to register new command */
38 #define SILC_CLIENT_CMD(func, cmd, name, args) \
39 silc_client_command_register(client, SILC_COMMAND_##cmd, name, \
40 silc_client_command_##func, \
41 silc_client_command_reply_##func, args)
43 /* Used to unregister command */
44 #define SILC_CLIENT_CMDU(func, cmd, name) \
45 silc_client_command_unregister(client, SILC_COMMAND_##cmd, \
46 silc_client_command_##func, \
47 silc_client_command_reply_##func)
49 #define SAY cmd->conn->client->internal->ops->say
51 /************************ Static utility functions **************************/
53 /* Return next available command identifier. */
55 static SilcUInt16 silc_client_cmd_ident(SilcClientConnection conn)
59 cmd_ident = silc_atomic_add_int16(&conn->internal->cmd_ident, 1);
61 cmd_ident = silc_atomic_add_int16(&conn->internal->cmd_ident, 1);
66 /* State to finish command thread after an error in resolving command */
68 SILC_FSM_STATE(silc_client_command_continue_error)
70 /* Destructor will free all resources */
71 return SILC_FSM_FINISH;
74 /* Command reply callback to continue with the execution of a command.
75 This will continue when first successful reply is received, and ignores
76 the rest. On the other hand, if only errors are received it will
77 wait for all errors before continuing. */
79 static SilcBool silc_client_command_continue(SilcClient client,
80 SilcClientConnection conn,
87 SilcClientCommandContext cmd = context;
89 /* Continue immediately when successful reply is received */
90 if (status == SILC_STATUS_OK || !SILC_STATUS_IS_ERROR(error)) {
91 SILC_FSM_CALL_CONTINUE(&cmd->thread);
98 /* Continue after last error is received */
99 if (SILC_STATUS_IS_ERROR(status) ||
100 (status == SILC_STATUS_LIST_END && SILC_STATUS_IS_ERROR(error))) {
101 silc_fsm_next(&cmd->thread, silc_client_command_continue_error);
102 SILC_FSM_CALL_CONTINUE(&cmd->thread);
109 /* Continues after resolving completed. */
111 static void silc_client_command_resolve_continue(SilcClient client,
112 SilcClientConnection conn,
117 SilcClientCommandContext cmd = context;
119 if (status != SILC_STATUS_OK)
120 silc_fsm_next(&cmd->thread, silc_client_command_continue_error);
122 /* Continue with the command */
123 SILC_FSM_CALL_CONTINUE(&cmd->thread);
126 /* Register command to client */
129 silc_client_command_register(SilcClient client,
132 SilcFSMStateCallback command_func,
133 SilcFSMStateCallback command_reply_func,
136 SilcClientCommand cmd;
138 cmd = silc_calloc(1, sizeof(*cmd));
142 cmd->command = command_func;
143 cmd->reply = command_reply_func;
144 cmd->max_args = max_args;
145 cmd->name = name ? strdup(name) : NULL;
151 silc_list_add(client->internal->commands, cmd);
156 /* Unregister command from client */
159 silc_client_command_unregister(SilcClient client,
161 SilcFSMStateCallback command_func,
162 SilcFSMStateCallback command_reply_func)
164 SilcClientCommand cmd;
166 silc_list_start(client->internal->commands);
167 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
168 if (cmd->cmd == command && cmd->command == command_func &&
169 cmd->reply == command_reply_func) {
170 silc_list_del(client->internal->commands, cmd);
171 silc_free(cmd->name);
180 /* Finds and returns a pointer to the command list. Return NULL if the
181 command is not found. */
183 static SilcClientCommand silc_client_command_find(SilcClient client,
186 SilcClientCommand cmd;
188 silc_list_start(client->internal->commands);
189 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
190 if (cmd->name && !strcasecmp(cmd->name, name))
197 /* Command thread destructor */
199 static void silc_client_command_destructor(SilcFSMThread thread,
201 void *destructor_context)
203 SilcClientCommandContext cmd = fsm_context;
204 SilcClientConnection conn = cmd->conn;
206 /* Removes commands that aren't waiting for reply but are waiting
207 for something. They may not have been removed yet. */
208 silc_list_del(conn->internal->pending_commands, cmd);
210 silc_client_command_free(cmd);
213 /* Add a command pending a command reply. Used internally by the library. */
216 silc_client_command_add_pending(SilcClientConnection conn,
217 SilcClientCommandContext cmd,
218 SilcClientCommandReply reply,
221 SilcClientCommandReplyCallback cb;
223 silc_mutex_lock(conn->internal->lock);
225 /* Add pending callback, if defined */
227 cb = silc_calloc(1, sizeof(*cb));
229 silc_mutex_unlock(conn->internal->lock);
233 cb->context = context;
234 silc_list_add(cmd->reply_callbacks, cb);
237 /* Add pending reply */
238 silc_list_add(conn->internal->pending_commands, cmd);
240 silc_mutex_unlock(conn->internal->lock);
245 /* Generic function to send any command. The arguments must be sent already
246 encoded into correct format and in correct order. Arguments come from
247 variable argument list pointer. */
249 static SilcUInt16 silc_client_command_send_vap(SilcClient client,
250 SilcClientConnection conn,
251 SilcClientCommandContext cmd,
253 SilcClientCommandReply reply,
255 SilcUInt32 argc, va_list ap)
259 SILC_LOG_DEBUG(("Send command %s", silc_get_command_name(command)));
261 if (conn->internal->disconnected)
265 cmd->cmd_ident = silc_client_cmd_ident(conn);
267 /* Encode command payload */
268 packet = silc_command_payload_encode_vap(command, cmd->cmd_ident, argc, ap);
272 /* Send the command */
273 if (!silc_packet_send(conn->stream, SILC_PACKET_COMMAND, 0,
274 silc_buffer_datalen(packet))) {
275 silc_buffer_free(packet);
279 /* Add the command pending command reply */
280 silc_client_command_add_pending(conn, cmd, reply, reply_context);
282 silc_buffer_free(packet);
284 return cmd->cmd_ident;
287 /* Generic function to send any command. The arguments must be sent already
288 encoded into correct format and in correct order. Arguments come from
292 silc_client_command_send_arg_array(SilcClient client,
293 SilcClientConnection conn,
294 SilcClientCommandContext cmd,
296 SilcClientCommandReply reply,
299 unsigned char **argv,
300 SilcUInt32 *argv_lens,
301 SilcUInt32 *argv_types)
305 SILC_LOG_DEBUG(("Send command %s", silc_get_command_name(command)));
307 if (conn->internal->disconnected)
311 cmd->cmd_ident = silc_client_cmd_ident(conn);
313 /* Encode command payload */
314 packet = silc_command_payload_encode(command, argc, argv, argv_lens,
315 argv_types, cmd->cmd_ident);
319 /* Send the command */
320 if (!silc_packet_send(conn->stream, SILC_PACKET_COMMAND, 0,
321 silc_buffer_datalen(packet))) {
322 silc_buffer_free(packet);
326 /* Add the command pending command reply */
327 silc_client_command_add_pending(conn, cmd, reply, reply_context);
329 silc_buffer_free(packet);
331 return cmd->cmd_ident;
334 /* Generic function to send any command. The arguments must be sent already
335 encoded into correct format and in correct order. This is used internally
338 static SilcUInt16 silc_client_command_send_va(SilcClientConnection conn,
339 SilcClientCommandContext cmd,
341 SilcClientCommandReply reply,
343 SilcUInt32 argc, ...)
346 SilcUInt16 cmd_ident;
349 cmd_ident = silc_client_command_send_vap(conn->client, conn, cmd, command,
350 reply, reply_context, argc, ap);
356 /****************************** Command API *********************************/
358 /* Free command context and its internals */
360 void silc_client_command_free(SilcClientCommandContext cmd)
362 SilcClientCommandReplyCallback cb;
365 for (i = 0; i < cmd->argc; i++)
366 silc_free(cmd->argv[i]);
367 silc_free(cmd->argv);
368 silc_free(cmd->argv_lens);
369 silc_free(cmd->argv_types);
371 silc_list_start(cmd->reply_callbacks);
372 while ((cb = silc_list_get(cmd->reply_callbacks)))
378 /* Executes a command */
380 SilcUInt16 silc_client_command_call(SilcClient client,
381 SilcClientConnection conn,
382 const char *command_line, ...)
386 unsigned char **argv = NULL;
387 SilcUInt32 *argv_lens = NULL, *argv_types = NULL;
388 SilcClientCommand command;
389 SilcClientCommandContext cmd;
393 client->internal->ops->say(client, NULL, SILC_CLIENT_MESSAGE_ERROR,
394 "You are not connected to a server, please connect to server");
398 /* Parse arguments */
399 va_start(va, command_line);
403 /* Get command name */
404 command_name = silc_memdup(command_line, strcspn(command_line, " "));
408 /* Find command by name */
409 command = silc_client_command_find(client, command_name);
411 silc_free(command_name);
415 /* Parse command line */
416 silc_parse_command_line((char *)command_line, &argv, &argv_lens,
417 &argv_types, &argc, command->max_args);
419 silc_free(command_name);
421 arg = va_arg(va, char *);
425 /* Find command by name */
426 command = silc_client_command_find(client, arg);
431 argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
432 argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) * (argc + 1));
433 argv_types = silc_realloc(argv_types, sizeof(*argv_types) * (argc + 1));
434 if (!argv || !argv_lens || !argv_types)
436 argv[argc] = silc_memdup(arg, strlen(arg));
439 argv_lens[argc] = strlen(arg);
440 argv_types[argc] = argc;
442 arg = va_arg(va, char *);
447 /* Allocate command context */
448 cmd = silc_calloc(1, sizeof(*cmd));
452 cmd->cmd = command->cmd;
455 cmd->argv_lens = argv_lens;
456 cmd->argv_types = argv_types;
457 cmd->cmd_ident = silc_client_cmd_ident(conn);
460 silc_list_init(cmd->reply_callbacks,
461 struct SilcClientCommandReplyCallbackStruct, next);
464 SILC_LOG_DEBUG(("Calling %s command", silc_get_command_name(cmd->cmd)));
465 silc_fsm_thread_init(&cmd->thread, &conn->internal->fsm, cmd,
466 silc_client_command_destructor, NULL, FALSE);
467 silc_fsm_start_sync(&cmd->thread, command->command);
469 return cmd->cmd_ident;
472 /* Generic function to send any command. The arguments must be sent already
473 encoded into correct format and in correct order. */
475 SilcUInt16 silc_client_command_send(SilcClient client,
476 SilcClientConnection conn,
478 SilcClientCommandReply reply,
480 SilcUInt32 argc, ...)
482 SilcClientCommandContext cmd;
488 /* Allocate command context */
489 cmd = silc_calloc(1, sizeof(*cmd));
494 silc_list_init(cmd->reply_callbacks,
495 struct SilcClientCommandReplyCallbackStruct, next);
497 /* Send the command */
500 silc_client_command_send_vap(client, conn, cmd, command, reply,
501 reply_context, argc, ap);
504 if (!cmd->cmd_ident) {
505 silc_client_command_free(cmd);
509 /*** Wait for command reply */
510 silc_fsm_thread_init(&cmd->thread, &conn->internal->fsm, cmd,
511 silc_client_command_destructor, NULL, FALSE);
512 silc_fsm_start_sync(&cmd->thread, silc_client_command_reply_wait);
514 return cmd->cmd_ident;
517 /* Generic function to send any command. The arguments must be sent already
518 encoded into correct format and in correct order. Arguments come from
521 SilcUInt16 silc_client_command_send_argv(SilcClient client,
522 SilcClientConnection conn,
524 SilcClientCommandReply reply,
527 unsigned char **argv,
528 SilcUInt32 *argv_lens,
529 SilcUInt32 *argv_types)
531 SilcClientCommandContext cmd;
536 /* Allocate command context */
537 cmd = silc_calloc(1, sizeof(*cmd));
543 /* Send the command */
545 silc_client_command_send_arg_array(client, conn, cmd, command, reply,
546 reply_context, argc, argv, argv_lens,
548 if (!cmd->cmd_ident) {
549 silc_client_command_free(cmd);
553 /*** Wait for command reply */
554 silc_fsm_thread_init(&cmd->thread, &conn->internal->fsm, cmd,
555 silc_client_command_destructor, NULL, FALSE);
556 silc_fsm_start_sync(&cmd->thread, silc_client_command_reply_wait);
558 return cmd->cmd_ident;
561 /* Attach to a command and command identifier to receive command reply. */
563 SilcBool silc_client_command_pending(SilcClientConnection conn,
566 SilcClientCommandReply reply,
569 SilcClientCommandContext cmd;
570 SilcClientCommandReplyCallback cb;
575 SILC_LOG_DEBUG(("Add pending command reply for ident %d", ident));
577 silc_mutex_lock(conn->internal->lock);
579 /* Find the pending command */
580 silc_list_start(conn->internal->pending_commands);
581 while ((cmd = silc_list_get(conn->internal->pending_commands)))
582 if ((cmd->cmd == command || command == SILC_COMMAND_NONE)
583 && cmd->cmd_ident == ident) {
585 /* Add the callback */
586 cb = silc_calloc(1, sizeof(*cb));
590 cb->context = context;
591 silc_list_add(cmd->reply_callbacks, cb);
594 silc_mutex_unlock(conn->internal->lock);
599 /******************************** WHOIS *************************************/
601 /* Command WHOIS. This command is used to query information about
604 SILC_FSM_STATE(silc_client_command_whois)
606 SilcClientCommandContext cmd = fsm_context;
607 SilcClientConnection conn = cmd->conn;
608 SilcClient client = conn->client;
609 SilcBuffer attrs = NULL;
610 unsigned char count[4], *tmp = NULL;
611 SilcBool details = FALSE, nick = FALSE;
612 unsigned char *pubkey = NULL;
615 /* Given without arguments fetches client's own information */
617 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1, 4,
618 silc_buffer_data(conn->internal->local_idp),
619 silc_buffer_len(conn->internal->local_idp));
621 /* Notify application */
622 COMMAND(SILC_STATUS_OK);
624 /** Wait for command reply */
625 silc_fsm_next(fsm, silc_client_command_reply_wait);
626 return SILC_FSM_CONTINUE;
629 for (i = 1; i < cmd->argc; i++) {
630 if (!strcasecmp(cmd->argv[i], "-details")) {
632 } else if (!strcasecmp(cmd->argv[i], "-pubkey") && cmd->argc > i + 1) {
633 pubkey = cmd->argv[i + 1];
636 /* We assume that the first parameter is the nickname, if it isn't
637 -details or -pubkey. The last parameter should always be the count */
640 } else if (i == cmd->argc - 1) {
641 int c = atoi(cmd->argv[i]);
642 SILC_PUT32_MSB(c, count);
649 /* If pubkey is set, add all attributes to the attrs buffer, except
652 attrs = silc_client_attributes_request(SILC_ATTRIBUTE_USER_INFO,
653 SILC_ATTRIBUTE_SERVICE,
654 SILC_ATTRIBUTE_STATUS_MOOD,
655 SILC_ATTRIBUTE_STATUS_FREETEXT,
656 SILC_ATTRIBUTE_STATUS_MESSAGE,
657 SILC_ATTRIBUTE_PREFERRED_LANGUAGE,
658 SILC_ATTRIBUTE_PREFERRED_CONTACT,
659 SILC_ATTRIBUTE_TIMEZONE,
660 SILC_ATTRIBUTE_GEOLOCATION,
661 SILC_ATTRIBUTE_DEVICE_INFO,
662 SILC_ATTRIBUTE_USER_ICON, 0);
664 attrs = silc_client_attributes_request(0);
669 SilcAttributeObjPk obj;
672 if (!silc_pkcs_load_public_key(pubkey, &pk)) {
673 SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR,
674 "Could not load public key %s, check the filename",
676 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
680 switch (silc_pkcs_get_type(pk)) {
682 obj.type = "silc-rsa";
685 obj.type = "ssh-rsa";
687 case SILC_PKCS_X509V3:
688 obj.type = "x509v3-sign-rsa";
690 case SILC_PKCS_OPENPGP:
691 obj.type = "pgp-sign-rsa";
697 obj.data = silc_pkcs_public_key_encode(pk, &obj.data_len);
699 attrs = silc_attribute_payload_encode(attrs,
700 SILC_ATTRIBUTE_USER_PUBLIC_KEY,
701 SILC_ATTRIBUTE_FLAG_VALID,
706 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
707 3, 1, nick ? cmd->argv[1] : NULL,
708 nick ? cmd->argv_lens[1] : 0,
709 2, tmp ? tmp : NULL, tmp ? 4 : 0,
710 3, silc_buffer_datalen(attrs));
712 /* Notify application */
713 COMMAND(SILC_STATUS_OK);
715 /** Wait for command reply */
716 silc_fsm_next(fsm, silc_client_command_reply_wait);
717 return SILC_FSM_CONTINUE;
720 return SILC_FSM_FINISH;
723 /******************************** WHOWAS ************************************/
725 /* Command WHOWAS. This command is used to query history information about
726 specific user that used to exist in the network. */
728 SILC_FSM_STATE(silc_client_command_whowas)
730 SilcClientCommandContext cmd = fsm_context;
731 SilcClientConnection conn = cmd->conn;
732 unsigned char count[4];
735 if (cmd->argc < 2 || cmd->argc > 3) {
736 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
737 "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
738 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
739 SILC_STATUS_ERR_TOO_MANY_PARAMS));
740 return SILC_FSM_FINISH;
743 if (cmd->argc == 2) {
744 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
745 1, 1, cmd->argv[1], cmd->argv_lens[1]);
747 c = atoi(cmd->argv[2]);
748 SILC_PUT32_MSB(c, count);
749 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
750 2, 1, cmd->argv[1], cmd->argv_lens[1],
751 2, count, sizeof(count));
754 /* Notify application */
755 COMMAND(SILC_STATUS_OK);
757 /** Wait for command reply */
758 silc_fsm_next(fsm, silc_client_command_reply_wait);
759 return SILC_FSM_CONTINUE;
762 /******************************** IDENTIFY **********************************/
764 /* Command IDENTIFY. This command is used to query information about
765 specific user, especially ID's. */
767 SILC_FSM_STATE(silc_client_command_identify)
769 SilcClientCommandContext cmd = fsm_context;
770 SilcClientConnection conn = cmd->conn;
771 unsigned char count[4];
774 if (cmd->argc < 2 || cmd->argc > 3)
775 return SILC_FSM_FINISH;
777 if (cmd->argc == 2) {
778 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
779 1, 1, cmd->argv[1], cmd->argv_lens[1]);
781 c = atoi(cmd->argv[2]);
782 SILC_PUT32_MSB(c, count);
783 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
784 2, 1, cmd->argv[1], cmd->argv_lens[1],
785 4, count, sizeof(count));
788 /** Wait for command reply */
789 silc_fsm_next(fsm, silc_client_command_reply_wait);
790 return SILC_FSM_CONTINUE;
793 /********************************** NICK ************************************/
795 /* Command NICK. Shows current nickname/sets new nickname on current
798 SILC_FSM_STATE(silc_client_command_nick)
800 SilcClientCommandContext cmd = fsm_context;
801 SilcClientConnection conn = cmd->conn;
804 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
805 "Usage: /NICK <nickname>");
806 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
810 if (silc_utf8_strcasecmp(conn->local_entry->nickname, cmd->argv[1]))
813 /* Show current nickname */
816 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
817 "Your nickname is %s on server %s",
818 conn->local_entry->nickname, conn->remote_host);
820 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
821 "Your nickname is %s", conn->local_entry->nickname);
824 COMMAND(SILC_STATUS_OK);
828 if (cmd->argv_lens[1] > 128)
829 cmd->argv_lens[1] = 128;
831 /* Send the NICK command */
832 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
833 1, 1, cmd->argv[1], cmd->argv_lens[1]);
835 /* Notify application */
836 COMMAND(SILC_STATUS_OK);
838 /** Wait for command reply */
839 silc_fsm_next(fsm, silc_client_command_reply_wait);
840 return SILC_FSM_CONTINUE;
843 return SILC_FSM_FINISH;
846 /********************************** LIST ************************************/
848 /* Command LIST. Lists channels on the current server. */
850 SILC_FSM_STATE(silc_client_command_list)
852 SilcClientCommandContext cmd = fsm_context;
853 SilcClientConnection conn = cmd->conn;
854 SilcClient client = conn->client;
855 SilcChannelEntry channel = NULL;
856 SilcBuffer idp = NULL;
858 if (cmd->argc == 2) {
859 /* Get the Channel ID of the channel */
860 channel = silc_client_get_channel(conn->client, cmd->conn, cmd->argv[1]);
862 idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
866 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
868 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
869 1, 1, silc_buffer_datalen(idp));
871 silc_buffer_free(idp);
872 silc_client_unref_channel(client, conn, channel);
874 /* Notify application */
875 COMMAND(SILC_STATUS_OK);
877 /** Wait for command reply */
878 silc_fsm_next(fsm, silc_client_command_reply_wait);
879 return SILC_FSM_CONTINUE;
882 /********************************** TOPIC ***********************************/
884 /* Command TOPIC. Sets/shows topic on a channel. */
886 SILC_FSM_STATE(silc_client_command_topic)
888 SilcClientCommandContext cmd = fsm_context;
889 SilcClientConnection conn = cmd->conn;
890 SilcClient client = conn->client;
891 SilcChannelEntry channel;
895 if (cmd->argc < 2 || cmd->argc > 3) {
896 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
897 "Usage: /TOPIC <channel> [<topic>]");
898 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
899 SILC_STATUS_ERR_TOO_MANY_PARAMS));
903 if (cmd->argv[1][0] == '*') {
904 if (!conn->current_channel) {
905 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
908 name = conn->current_channel->channel_name;
913 if (!conn->current_channel) {
914 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
918 /* Get the Channel ID of the channel */
919 channel = silc_client_get_channel(conn->client, conn, name);
921 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
925 idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
927 /* Send TOPIC command to the server */
929 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
930 1, silc_buffer_datalen(idp),
931 2, cmd->argv[2], strlen(cmd->argv[2]));
933 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
934 1, silc_buffer_datalen(idp));
936 silc_buffer_free(idp);
937 silc_client_unref_channel(client, conn, channel);
939 /* Notify application */
940 COMMAND(SILC_STATUS_OK);
942 /** Wait for command reply */
943 silc_fsm_next(fsm, silc_client_command_reply_wait);
944 return SILC_FSM_CONTINUE;
947 return SILC_FSM_FINISH;
950 /********************************* INVITE ***********************************/
952 /* Command INVITE. Invites specific client to join a channel. This is
953 also used to mange the invite list of the channel. */
955 SILC_FSM_STATE(silc_client_command_invite)
957 SilcClientCommandContext cmd = fsm_context;
958 SilcClientConnection conn = cmd->conn;
959 SilcClient client = conn->client;
960 SilcClientEntry client_entry = NULL;
961 SilcChannelEntry channel = NULL;
962 SilcBuffer clidp, chidp, args = NULL;
963 SilcPublicKey pubkey = NULL;
964 SilcDList clients = NULL;
965 char *nickname = NULL, *name;
967 unsigned char action[1];
970 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
971 "Usage: /INVITE <channel> [<nickname>[@server>]"
972 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
973 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
977 if (cmd->argv[1][0] == '*') {
978 if (!conn->current_channel) {
979 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
983 channel = conn->current_channel;
984 silc_client_ref_channel(client, conn, channel);
988 channel = silc_client_get_channel(conn->client, conn, name);
990 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
995 /* Parse the typed nickname. */
996 if (cmd->argc == 3) {
997 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
998 silc_client_nickname_parse(client, conn, cmd->argv[2], &nickname);
1000 /* Find client entry */
1001 clients = silc_client_get_clients_local(client, conn, nickname,
1004 /* Resolve client information */
1005 SILC_FSM_CALL(silc_client_get_clients(
1006 client, conn, nickname,
1008 silc_client_command_resolve_continue,
1011 client_entry = silc_dlist_get(clients);
1013 if (cmd->argv[2][0] == '+')
1018 /* Check if it is public key file to be added to invite list */
1019 silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey);
1020 invite = cmd->argv[2];
1027 args = silc_buffer_alloc_size(2);
1028 silc_buffer_format(args,
1029 SILC_STR_UI_SHORT(1),
1032 chidp = silc_public_key_payload_encode(pubkey);
1033 args = silc_argument_payload_encode_one(args, silc_buffer_data(chidp),
1034 silc_buffer_len(chidp), 2);
1035 silc_buffer_free(chidp);
1036 silc_pkcs_public_key_free(pubkey);
1038 args = silc_argument_payload_encode_one(args, invite, strlen(invite), 1);
1042 /* Send the command */
1043 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
1045 clidp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT);
1046 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 4,
1047 1, silc_buffer_datalen(chidp),
1048 2, silc_buffer_datalen(clidp),
1049 3, args ? action : NULL, args ? 1 : 0,
1050 4, silc_buffer_datalen(args));
1051 silc_buffer_free(clidp);
1053 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
1054 1, silc_buffer_datalen(chidp),
1055 3, args ? action : NULL, args ? 1 : 0,
1056 4, silc_buffer_datalen(args));
1059 silc_buffer_free(chidp);
1060 silc_buffer_free(args);
1061 silc_free(nickname);
1062 silc_client_list_free(client, conn, clients);
1063 silc_client_unref_channel(client, conn, channel);
1065 /* Notify application */
1066 COMMAND(SILC_STATUS_OK);
1068 /** Wait for command reply */
1069 silc_fsm_next(fsm, silc_client_command_reply_wait);
1070 return SILC_FSM_CONTINUE;
1073 silc_free(nickname);
1074 return SILC_FSM_FINISH;
1077 /********************************** QUIT ************************************/
1079 /* Close the connection */
1081 SILC_FSM_STATE(silc_client_command_quit_final)
1083 SilcClientCommandContext cmd = fsm_context;
1084 SilcClientConnection conn = cmd->conn;
1086 SILC_LOG_DEBUG(("Quitting"));
1088 /* Notify application */
1089 COMMAND(SILC_STATUS_OK);
1091 /* Signal to close connection */
1092 conn->internal->status = SILC_CLIENT_CONN_DISCONNECTED;
1093 if (!conn->internal->disconnected) {
1094 conn->internal->disconnected = TRUE;
1095 SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event);
1098 return SILC_FSM_FINISH;
1101 /* Command QUIT. Closes connection with current server. */
1103 SILC_FSM_STATE(silc_client_command_quit)
1105 SilcClientCommandContext cmd = fsm_context;
1106 SilcClientConnection conn = cmd->conn;
1109 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1110 1, cmd->argv[1], cmd->argv_lens[1]);
1112 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
1114 /* Sleep for a while */
1117 /* We close the connection with a little timeout */
1118 silc_fsm_next_later(fsm, silc_client_command_quit_final, 2, 0);
1119 return SILC_FSM_WAIT;
1122 /********************************** KILL ************************************/
1125 /* Command KILL. Router operator can use this command to remove an client
1126 fromthe SILC Network. */
1128 SILC_FSM_STATE(silc_client_command_kill)
1130 SilcClientCommandContext cmd = fsm_context;
1131 SilcClientConnection conn = cmd->conn;
1132 SilcClient client = conn->client;
1133 SilcBuffer idp, auth = NULL;
1134 SilcClientEntry target;
1136 char *nickname = NULL, *comment = NULL;
1138 if (cmd->argc < 2) {
1139 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1140 "Usage: /KILL <nickname> [<comment>] [-pubkey]");
1141 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1142 return SILC_FSM_FINISH;
1145 /* Parse the typed nickname. */
1146 if (!silc_client_nickname_parse(client, conn, cmd->argv[1], &nickname))
1147 return SILC_FSM_FINISH;
1149 /* Get the target client */
1150 clients = silc_client_get_clients_local(client, conn, nickname,
1153 /* Resolve client information */
1154 SILC_FSM_CALL(silc_client_get_clients(client, conn, nickname,
1156 silc_client_command_resolve_continue,
1159 target = silc_dlist_get(clients);
1161 if (cmd->argc >= 3) {
1162 if (strcasecmp(cmd->argv[2], "-pubkey"))
1163 comment = cmd->argv[2];
1165 if (!strcasecmp(cmd->argv[2], "-pubkey") ||
1166 (cmd->argc >= 4 && !strcasecmp(cmd->argv[3], "-pubkey"))) {
1167 /* Encode the public key authentication payload */
1168 auth = silc_auth_public_key_auth_generate(conn->public_key,
1171 conn->internal->sha1hash,
1172 &target->id, SILC_ID_CLIENT);
1176 /* Send the KILL command to the server */
1177 idp = silc_id_payload_encode(&target->id, SILC_ID_CLIENT);
1178 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
1179 1, silc_buffer_datalen(idp),
1180 2, comment, comment ? strlen(comment) : 0,
1181 3, silc_buffer_datalen(auth));
1182 silc_buffer_free(idp);
1183 silc_buffer_free(auth);
1184 silc_free(nickname);
1185 silc_client_list_free(client, conn, clients);
1187 /* Notify application */
1188 COMMAND(SILC_STATUS_OK);
1190 /** Wait for command reply */
1191 silc_fsm_next(fsm, silc_client_command_reply_wait);
1192 return SILC_FSM_CONTINUE;
1195 /********************************** INFO ************************************/
1197 /* Command INFO. Request information about specific server. If specific
1198 server is not provided the current server is used. */
1200 SILC_FSM_STATE(silc_client_command_info)
1202 SilcClientCommandContext cmd = fsm_context;
1203 SilcClientConnection conn = cmd->conn;
1205 /* Send the command */
1207 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1208 1, cmd->argv[1], cmd->argv_lens[1]);
1210 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
1212 /* Notify application */
1213 COMMAND(SILC_STATUS_OK);
1215 /** Wait for command reply */
1216 silc_fsm_next(fsm, silc_client_command_reply_wait);
1217 return SILC_FSM_CONTINUE;
1220 /********************************** STATS ***********************************/
1222 /* Command STATS. Shows server and network statistics. */
1224 SILC_FSM_STATE(silc_client_command_stats)
1226 SilcClientCommandContext cmd = fsm_context;
1227 SilcClientConnection conn = cmd->conn;
1229 /* Send the command */
1230 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1231 1, silc_buffer_datalen(conn->internal->
1234 /* Notify application */
1235 COMMAND(SILC_STATUS_OK);
1237 /** Wait for command reply */
1238 silc_fsm_next(fsm, silc_client_command_reply_wait);
1239 return SILC_FSM_CONTINUE;
1242 /********************************** PING ************************************/
1244 /* Command PING. Sends ping to server. */
1246 SILC_FSM_STATE(silc_client_command_ping)
1248 SilcClientCommandContext cmd = fsm_context;
1249 SilcClientConnection conn = cmd->conn;
1251 if (cmd->argc < 2) {
1252 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1253 return SILC_FSM_FINISH;
1256 /* Send the command */
1257 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1258 1, silc_buffer_datalen(conn->internal->
1261 /* Save ping time */
1262 cmd->context = SILC_64_TO_PTR(silc_time());
1264 /* Notify application */
1265 COMMAND(SILC_STATUS_OK);
1267 /** Wait for command reply */
1268 silc_fsm_next(fsm, silc_client_command_reply_wait);
1269 return SILC_FSM_CONTINUE;
1272 /********************************** JOIN ************************************/
1274 /* Command JOIN. Joins to a channel. */
1276 SILC_FSM_STATE(silc_client_command_join)
1278 SilcClientCommandContext cmd = fsm_context;
1279 SilcClientConnection conn = cmd->conn;
1280 SilcClient client = conn->client;
1281 SilcChannelEntry channel = NULL;
1282 SilcBuffer auth = NULL, cauth = NULL;
1283 char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
1284 int i, passphrase_len = 0;
1286 if (cmd->argc < 2) {
1287 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1291 /* See if we have joined to the requested channel already */
1292 channel = silc_client_get_channel(conn->client, conn, cmd->argv[1]);
1293 if (channel && silc_client_on_channel(channel, conn->local_entry))
1296 if (cmd->argv_lens[1] > 256)
1297 cmd->argv_lens[1] = 256;
1299 name = cmd->argv[1];
1301 for (i = 2; i < cmd->argc; i++) {
1302 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
1303 cipher = cmd->argv[++i];
1304 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
1305 hmac = cmd->argv[++i];
1306 } else if (!strcasecmp(cmd->argv[i], "-founder")) {
1307 auth = silc_auth_public_key_auth_generate(conn->public_key,
1310 conn->internal->sha1hash,
1313 } else if (!strcasecmp(cmd->argv[i], "-auth")) {
1314 SilcPublicKey pubkey = conn->public_key;
1315 SilcPrivateKey privkey = conn->private_key;
1316 unsigned char *pk, pkhash[SILC_HASH_MAXLEN], *pubdata;
1319 if (cmd->argc >= i + 3) {
1321 if (cmd->argc >= i + 4) {
1322 pass = cmd->argv[i + 3];
1325 if (!silc_load_key_pair(cmd->argv[i + 1], cmd->argv[i + 2], pass,
1326 &pubkey, &privkey)) {
1327 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1328 "Could not load key pair, check your arguments");
1329 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1335 pk = silc_pkcs_public_key_encode(pubkey, &pk_len);
1336 silc_hash_make(conn->internal->sha1hash, pk, pk_len, pkhash);
1338 pubdata = silc_rng_get_rn_data(conn->client->rng, 128);
1339 memcpy(pubdata, pkhash, 20);
1340 cauth = silc_auth_public_key_auth_generate_wpub(pubkey, privkey,
1342 conn->internal->sha1hash,
1345 memset(pubdata, 0, 128);
1348 /* Passphrases must be UTF-8 encoded, so encode if it is not */
1349 if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
1350 passphrase_len = silc_utf8_encoded_len(cmd->argv[i],
1351 cmd->argv_lens[i], 0);
1352 pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
1353 passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
1354 0, pu8, passphrase_len);
1357 passphrase = strdup(cmd->argv[i]);
1358 passphrase_len = cmd->argv_lens[i];
1363 /* Send JOIN command to the server */
1364 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 7,
1365 1, name, strlen(name),
1366 2, silc_buffer_datalen(conn->internal->
1368 3, passphrase, passphrase_len,
1369 4, cipher, cipher ? strlen(cipher) : 0,
1370 5, hmac, hmac ? strlen(hmac) : 0,
1371 6, silc_buffer_datalen(auth),
1372 7, silc_buffer_datalen(cauth));
1374 silc_buffer_free(auth);
1375 silc_buffer_free(cauth);
1377 memset(passphrase, 0, strlen(passphrase));
1378 silc_free(passphrase);
1379 silc_client_unref_channel(client, conn, channel);
1381 /* Notify application */
1382 COMMAND(SILC_STATUS_OK);
1384 /** Wait for command reply */
1385 silc_fsm_next(fsm, silc_client_command_reply_wait);
1386 return SILC_FSM_CONTINUE;
1389 silc_client_unref_channel(client, conn, channel);
1390 return SILC_FSM_FINISH;
1393 /********************************** MOTD ************************************/
1395 /* MOTD command. Requests motd from server. */
1397 SILC_FSM_STATE(silc_client_command_motd)
1399 SilcClientCommandContext cmd = fsm_context;
1400 SilcClientConnection conn = cmd->conn;
1402 if (cmd->argc < 1 || cmd->argc > 2) {
1403 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1404 "Usage: /MOTD [<server>]");
1405 COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
1406 SILC_STATUS_ERR_TOO_MANY_PARAMS));
1407 return SILC_FSM_FINISH;
1410 /* Send the command */
1412 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1413 1, conn->remote_host,
1414 strlen(conn->remote_host));
1416 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1417 1, cmd->argv[1], cmd->argv_lens[1]);
1419 /* Notify application */
1420 COMMAND(SILC_STATUS_OK);
1422 /** Wait for command reply */
1423 silc_fsm_next(fsm, silc_client_command_reply_wait);
1424 return SILC_FSM_CONTINUE;
1427 /********************************** UMODE ***********************************/
1429 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1430 modes as client cannot set itself server/router operator privileges. */
1432 SILC_FSM_STATE(silc_client_command_umode)
1434 SilcClientCommandContext cmd = fsm_context;
1435 SilcClientConnection conn = cmd->conn;
1436 unsigned char *cp, modebuf[4];
1437 SilcUInt32 mode, add, len;
1440 if (cmd->argc < 2) {
1441 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1442 "Usage: /UMODE +|-<modes>");
1443 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1444 return SILC_FSM_FINISH;
1447 mode = conn->local_entry->mode;
1449 /* Are we adding or removing mode */
1450 if (cmd->argv[1][0] == '-')
1456 cp = cmd->argv[1] + 1;
1458 for (i = 0; i < len; i++) {
1463 mode |= SILC_UMODE_SERVER_OPERATOR;
1464 mode |= SILC_UMODE_ROUTER_OPERATOR;
1465 mode |= SILC_UMODE_GONE;
1466 mode |= SILC_UMODE_INDISPOSED;
1467 mode |= SILC_UMODE_BUSY;
1468 mode |= SILC_UMODE_PAGE;
1469 mode |= SILC_UMODE_HYPER;
1470 mode |= SILC_UMODE_ROBOT;
1471 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1472 mode |= SILC_UMODE_REJECT_WATCHING;
1474 mode = SILC_UMODE_NONE;
1479 mode |= SILC_UMODE_SERVER_OPERATOR;
1481 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1485 mode |= SILC_UMODE_ROUTER_OPERATOR;
1487 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1491 mode |= SILC_UMODE_GONE;
1493 mode &= ~SILC_UMODE_GONE;
1497 mode |= SILC_UMODE_INDISPOSED;
1499 mode &= ~SILC_UMODE_INDISPOSED;
1503 mode |= SILC_UMODE_BUSY;
1505 mode &= ~SILC_UMODE_BUSY;
1509 mode |= SILC_UMODE_PAGE;
1511 mode &= ~SILC_UMODE_PAGE;
1515 mode |= SILC_UMODE_HYPER;
1517 mode &= ~SILC_UMODE_HYPER;
1521 mode |= SILC_UMODE_ROBOT;
1523 mode &= ~SILC_UMODE_ROBOT;
1527 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1529 mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
1533 mode |= SILC_UMODE_REJECT_WATCHING;
1535 mode &= ~SILC_UMODE_REJECT_WATCHING;
1539 mode |= SILC_UMODE_BLOCK_INVITE;
1541 mode &= ~SILC_UMODE_BLOCK_INVITE;
1544 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1545 return SILC_FSM_FINISH;
1550 SILC_PUT32_MSB(mode, modebuf);
1552 /* Send the command */
1553 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
1554 1, silc_buffer_datalen(conn->internal->
1556 2, modebuf, sizeof(modebuf));
1558 /* Notify application */
1559 COMMAND(SILC_STATUS_OK);
1561 /** Wait for command reply */
1562 silc_fsm_next(fsm, silc_client_command_reply_wait);
1563 return SILC_FSM_CONTINUE;
1566 /********************************** CMODE ***********************************/
1568 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1569 can be set several at once. Those modes that require argument must be set
1570 separately (unless set with modes that does not require arguments). */
1572 SILC_FSM_STATE(silc_client_command_cmode)
1574 SilcClientCommandContext cmd = fsm_context;
1575 SilcClientConnection conn = cmd->conn;
1576 SilcClient client = conn->client;
1577 SilcChannelEntry channel = NULL;
1578 SilcBuffer chidp, auth = NULL, pk = NULL;
1579 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1580 SilcUInt32 mode, add, type, len, arg_len = 0;
1583 if (cmd->argc < 3) {
1584 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1585 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1586 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1590 if (cmd->argv[1][0] == '*') {
1591 if (!conn->current_channel) {
1592 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1596 channel = conn->current_channel;
1597 silc_client_ref_channel(client, conn, channel);
1599 name = cmd->argv[1];
1601 channel = silc_client_get_channel(conn->client, conn, name);
1603 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1608 mode = channel->mode;
1610 /* Are we adding or removing mode */
1611 if (cmd->argv[2][0] == '-')
1616 /* Argument type to be sent to server */
1620 cp = cmd->argv[2] + 1;
1622 for (i = 0; i < len; i++) {
1626 mode |= SILC_CHANNEL_MODE_PRIVATE;
1628 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1632 mode |= SILC_CHANNEL_MODE_SECRET;
1634 mode &= ~SILC_CHANNEL_MODE_SECRET;
1638 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1640 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1644 mode |= SILC_CHANNEL_MODE_INVITE;
1646 mode &= ~SILC_CHANNEL_MODE_INVITE;
1650 mode |= SILC_CHANNEL_MODE_TOPIC;
1652 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1656 mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1658 mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1662 mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1664 mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1669 mode |= SILC_CHANNEL_MODE_ULIMIT;
1671 if (cmd->argc < 4) {
1672 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1673 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1674 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1677 ll = atoi(cmd->argv[3]);
1678 SILC_PUT32_MSB(ll, tmp);
1682 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1687 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1689 if (cmd->argc < 4) {
1690 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1691 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1692 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1696 arg_len = cmd->argv_lens[3];
1698 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1703 mode |= SILC_CHANNEL_MODE_CIPHER;
1705 if (cmd->argc < 4) {
1706 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1707 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1708 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1712 arg_len = cmd->argv_lens[3];
1714 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1719 mode |= SILC_CHANNEL_MODE_HMAC;
1721 if (cmd->argc < 4) {
1722 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1723 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1724 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1728 arg_len = cmd->argv_lens[3];
1730 mode &= ~SILC_CHANNEL_MODE_HMAC;
1735 SilcPublicKey pubkey = conn->public_key;
1736 SilcPrivateKey privkey = conn->private_key;
1738 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1741 if (cmd->argc >= 5) {
1744 pass = cmd->argv[5];
1745 if (!silc_load_key_pair(cmd->argv[3], cmd->argv[4], pass,
1746 &pubkey, &privkey)) {
1747 SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1748 "Could not load key pair, check your arguments");
1749 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1754 pk = silc_public_key_payload_encode(pubkey);
1755 auth = silc_auth_public_key_auth_generate(pubkey, privkey,
1757 conn->internal->sha1hash,
1760 arg = silc_buffer_data(auth);
1761 arg_len = silc_buffer_len(auth);
1763 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1769 SilcBool chadd = FALSE;
1770 SilcPublicKey chpk = NULL;
1772 mode |= SILC_CHANNEL_MODE_CHANNEL_AUTH;
1775 if (cmd->argc == 3) {
1776 /* Send empty command to receive the public key list. */
1777 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
1778 silc_client_command_send_va(conn, cmd, SILC_COMMAND_CMODE,
1780 1, silc_buffer_datalen(chidp));
1781 silc_buffer_free(chidp);
1783 /* Notify application */
1784 COMMAND(SILC_STATUS_OK);
1788 if (cmd->argc >= 4) {
1789 auth = silc_buffer_alloc_size(2);
1790 silc_buffer_format(auth,
1791 SILC_STR_UI_SHORT(cmd->argc - 3),
1795 for (k = 3; k < cmd->argc; k++) {
1796 if (cmd->argv[k][0] == '+')
1798 if (!silc_pkcs_load_public_key(cmd->argv[k] + 1, &chpk)) {
1799 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1800 "Could not load public key %s, check the filename",
1802 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1803 silc_buffer_free(auth);
1808 pk = silc_public_key_payload_encode(chpk);
1809 auth = silc_argument_payload_encode_one(auth,
1810 silc_buffer_datalen(pk),
1811 chadd ? 0x00 : 0x01);
1812 silc_pkcs_public_key_free(chpk);
1813 silc_buffer_free(pk);
1818 arg = silc_buffer_data(auth);
1819 arg_len = silc_buffer_len(auth);
1821 mode &= ~SILC_CHANNEL_MODE_CHANNEL_AUTH;
1825 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1831 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
1832 SILC_PUT32_MSB(mode, modebuf);
1834 /* Send the command. We support sending only one mode at once that
1835 requires an argument. */
1837 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 4,
1838 1, silc_buffer_datalen(chidp),
1839 2, modebuf, sizeof(modebuf),
1841 8, silc_buffer_datalen(pk));
1843 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
1844 1, silc_buffer_datalen(chidp),
1845 2, modebuf, sizeof(modebuf));
1848 silc_buffer_free(chidp);
1849 silc_buffer_free(auth);
1850 silc_buffer_free(pk);
1851 silc_client_unref_channel(client, conn, channel);
1853 /* Notify application */
1854 COMMAND(SILC_STATUS_OK);
1856 /** Wait for command reply */
1857 silc_fsm_next(fsm, silc_client_command_reply_wait);
1858 return SILC_FSM_CONTINUE;
1861 silc_client_unref_channel(client, conn, channel);
1862 return SILC_FSM_FINISH;
1865 /********************************* CUMODE ***********************************/
1867 /* CUMODE command. Changes client's mode on a channel. */
1869 SILC_FSM_STATE(silc_client_command_cumode)
1871 SilcClientCommandContext cmd = fsm_context;
1872 SilcClientConnection conn = cmd->conn;
1873 SilcClient client = conn->client;
1874 SilcChannelEntry channel = NULL;
1875 SilcChannelUser chu;
1876 SilcClientEntry client_entry;
1877 SilcBuffer clidp, chidp, auth = NULL;
1878 SilcDList clients = NULL;
1879 unsigned char *name, *cp, modebuf[4];
1880 SilcUInt32 mode = 0, add, len;
1881 char *nickname = NULL;
1884 if (cmd->argc < 4) {
1885 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1886 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1887 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1891 if (cmd->argv[1][0] == '*') {
1892 if (!conn->current_channel) {
1893 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1897 channel = conn->current_channel;
1898 silc_client_ref_channel(client, conn, channel);
1900 name = cmd->argv[1];
1902 channel = silc_client_get_channel(conn->client, conn, name);
1904 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1909 /* Parse the typed nickname. */
1910 silc_client_nickname_parse(client, conn, cmd->argv[3], &nickname);
1912 /* Find client entry */
1913 clients = silc_client_get_clients_local(client, conn, nickname,
1916 /* Resolve client information */
1917 SILC_FSM_CALL(silc_client_get_clients(client, conn, nickname, cmd->argv[3],
1918 silc_client_command_resolve_continue,
1921 client_entry = silc_dlist_get(clients);
1923 /* Get the current mode */
1924 chu = silc_client_on_channel(channel, client_entry);
1928 /* Are we adding or removing mode */
1929 if (cmd->argv[2][0] == '-')
1935 cp = cmd->argv[2] + 1;
1937 for (i = 0; i < len; i++) {
1941 mode |= SILC_CHANNEL_UMODE_CHANFO;
1942 mode |= SILC_CHANNEL_UMODE_CHANOP;
1943 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1944 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1945 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1947 mode = SILC_CHANNEL_UMODE_NONE;
1952 SilcPublicKey pubkey = conn->public_key;
1953 SilcPrivateKey privkey = conn->private_key;
1955 if (cmd->argc >= 6) {
1958 pass = cmd->argv[6];
1959 if (!silc_load_key_pair(cmd->argv[4], cmd->argv[5], pass,
1960 &pubkey, &privkey)) {
1961 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1962 "Could not load key pair, check your arguments");
1963 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1968 auth = silc_auth_public_key_auth_generate(pubkey, privkey,
1970 conn->internal->sha1hash,
1973 mode |= SILC_CHANNEL_UMODE_CHANFO;
1975 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1980 mode |= SILC_CHANNEL_UMODE_CHANOP;
1982 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1986 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1988 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1992 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1994 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1998 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
2000 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
2004 mode |= SILC_CHANNEL_UMODE_QUIET;
2006 mode &= ~SILC_CHANNEL_UMODE_QUIET;
2009 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
2015 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
2016 SILC_PUT32_MSB(mode, modebuf);
2017 clidp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT);
2019 /* Send the command packet. We support sending only one mode at once
2020 that requires an argument. */
2021 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, auth ? 4 : 3,
2022 1, silc_buffer_datalen(chidp),
2024 3, silc_buffer_datalen(clidp),
2025 4, silc_buffer_datalen(auth));
2027 silc_buffer_free(chidp);
2028 silc_buffer_free(clidp);
2030 silc_buffer_free(auth);
2031 silc_free(nickname);
2032 silc_client_list_free(client, conn, clients);
2033 silc_client_unref_channel(client, conn, channel);
2035 /* Notify application */
2036 COMMAND(SILC_STATUS_OK);
2038 /** Wait for command reply */
2039 silc_fsm_next(fsm, silc_client_command_reply_wait);
2040 return SILC_FSM_CONTINUE;
2043 silc_client_unref_channel(client, conn, channel);
2044 silc_client_list_free(client, conn, clients);
2045 silc_free(nickname);
2046 return SILC_FSM_FINISH;
2049 /********************************** KICK ************************************/
2051 /* KICK command. Kicks a client out of channel. */
2053 SILC_FSM_STATE(silc_client_command_kick)
2055 SilcClientCommandContext cmd = fsm_context;
2056 SilcClientConnection conn = cmd->conn;
2057 SilcClient client = conn->client;
2058 SilcChannelEntry channel = NULL;
2059 SilcBuffer idp, idp2;
2060 SilcClientEntry target;
2061 SilcDList clients = NULL;
2063 char *nickname = NULL;
2065 if (cmd->argc < 3) {
2066 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2067 "Usage: /KICK <channel> <nickname> [<comment>]");
2068 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2072 if (cmd->argv[1][0] == '*') {
2073 if (!conn->current_channel) {
2074 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2077 name = conn->current_channel->channel_name;
2079 name = cmd->argv[1];
2082 if (!conn->current_channel) {
2083 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2087 /* Get the Channel ID of the channel */
2088 channel = silc_client_get_channel(conn->client, conn, name);
2090 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2094 /* Parse the typed nickname. */
2095 silc_client_nickname_parse(client, conn, cmd->argv[2], &nickname);
2097 /* Get the target client */
2098 clients = silc_client_get_clients_local(client, conn, nickname,
2101 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2102 "No such client: %s", cmd->argv[2]);
2103 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2106 target = silc_dlist_get(clients);
2108 /* Send KICK command to the server */
2109 idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
2110 idp2 = silc_id_payload_encode(&target->id, SILC_ID_CLIENT);
2112 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
2113 1, silc_buffer_datalen(idp),
2114 2, silc_buffer_datalen(idp2));
2116 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
2117 1, silc_buffer_datalen(idp),
2118 2, silc_buffer_datalen(idp2),
2119 3, cmd->argv[3], strlen(cmd->argv[3]));
2121 silc_buffer_free(idp);
2122 silc_buffer_free(idp2);
2123 silc_free(nickname);
2124 silc_client_list_free(client, conn, clients);
2125 silc_client_unref_channel(client, conn, channel);
2127 /* Notify application */
2128 COMMAND(SILC_STATUS_OK);
2130 /** Wait for command reply */
2131 silc_fsm_next(fsm, silc_client_command_reply_wait);
2132 return SILC_FSM_CONTINUE;
2135 silc_client_unref_channel(client, conn, channel);
2136 silc_free(nickname);
2137 return SILC_FSM_FINISH;
2140 /***************************** OPER & SILCOPER ******************************/
2143 unsigned char *passphrase;
2144 SilcUInt32 passphrase_len;
2145 } *SilcClientCommandOper;
2147 /* Ask passphrase callback */
2149 static void silc_client_command_oper_cb(unsigned char *data,
2150 SilcUInt32 data_len, void *context)
2152 SilcClientCommandContext cmd = context;
2153 SilcClientCommandOper oper = cmd->context;
2155 if (data && data_len)
2156 oper->passphrase = silc_memdup(data, data_len);
2157 oper->passphrase_len = data_len;
2160 SILC_FSM_CALL_CONTINUE(&cmd->thread);
2163 /* Send OPER/SILCOPER command */
2165 SILC_FSM_STATE(silc_client_command_oper_send)
2167 SilcClientCommandContext cmd = fsm_context;
2168 SilcClientConnection conn = cmd->conn;
2169 SilcClientCommandOper oper = cmd->context;
2172 if (!oper || !oper->passphrase) {
2173 /* Encode the public key authentication payload */
2174 auth = silc_auth_public_key_auth_generate(conn->public_key,
2177 conn->internal->hash,
2181 /* Encode the password authentication payload */
2182 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
2183 oper->passphrase, oper->passphrase_len);
2186 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
2187 1, cmd->argv[1], strlen(cmd->argv[1]),
2188 2, silc_buffer_datalen(auth));
2190 silc_buffer_clear(auth);
2191 silc_buffer_free(auth);
2193 silc_free(oper->passphrase);
2197 /* Notify application */
2198 COMMAND(SILC_STATUS_OK);
2200 /** Wait for command reply */
2201 silc_fsm_next(fsm, silc_client_command_reply_wait);
2202 return SILC_FSM_CONTINUE;
2205 /* OPER command. Used to obtain server operator privileges. */
2207 SILC_FSM_STATE(silc_client_command_oper)
2209 SilcClientCommandContext cmd = fsm_context;
2210 SilcClientConnection conn = cmd->conn;
2211 SilcClientCommandOper oper;
2213 if (cmd->argc < 2) {
2214 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2215 "Usage: /OPER <username> [-pubkey]");
2216 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2217 return SILC_FSM_FINISH;
2220 /* Get passphrase */
2221 if (cmd->argc < 3) {
2222 oper = silc_calloc(1, sizeof(*oper));
2224 return SILC_FSM_FINISH;
2225 cmd->context = oper;
2226 SILC_FSM_CALL(conn->client->internal->
2227 ops->ask_passphrase(conn->client, conn,
2228 silc_client_command_oper_cb, cmd));
2231 silc_fsm_next(fsm, silc_client_command_oper_send);
2232 return SILC_FSM_CONTINUE;
2235 /* SILCOPER command. Used to obtain router operator privileges. */
2237 SILC_FSM_STATE(silc_client_command_silcoper)
2239 SilcClientCommandContext cmd = fsm_context;
2240 SilcClientConnection conn = cmd->conn;
2241 SilcClientCommandOper oper;
2243 if (cmd->argc < 2) {
2244 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2245 "Usage: /SILCOPER <username> [-pubkey]");
2246 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2247 return SILC_FSM_FINISH;
2250 /* Get passphrase */
2251 if (cmd->argc < 3) {
2252 oper = silc_calloc(1, sizeof(*oper));
2254 return SILC_FSM_FINISH;
2255 cmd->context = oper;
2256 SILC_FSM_CALL(conn->client->internal->
2257 ops->ask_passphrase(conn->client, conn,
2258 silc_client_command_oper_cb, cmd));
2261 silc_fsm_next(fsm, silc_client_command_oper_send);
2262 return SILC_FSM_CONTINUE;
2265 /*********************************** BAN ************************************/
2267 /* Command BAN. This is used to manage the ban list of the channel. */
2269 SILC_FSM_STATE(silc_client_command_ban)
2271 SilcClientCommandContext cmd = fsm_context;
2272 SilcClientConnection conn = cmd->conn;
2273 SilcClient client = conn->client;
2274 SilcChannelEntry channel;
2275 SilcBuffer chidp, args = NULL;
2276 char *name, *ban = NULL;
2277 unsigned char action[1];
2278 SilcPublicKey pubkey = NULL;
2280 if (cmd->argc < 2) {
2281 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2282 "Usage: /BAN <channel> "
2283 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
2284 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2288 if (cmd->argv[1][0] == '*') {
2289 if (!conn->current_channel) {
2290 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2294 channel = conn->current_channel;
2295 silc_client_ref_channel(client, conn, channel);
2297 name = cmd->argv[1];
2299 channel = silc_client_get_channel(conn->client, conn, name);
2301 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2306 if (cmd->argc == 3) {
2307 if (cmd->argv[2][0] == '+')
2312 /* Check if it is public key file to be added to invite list */
2313 silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey);
2320 args = silc_buffer_alloc_size(2);
2321 silc_buffer_format(args,
2322 SILC_STR_UI_SHORT(1),
2325 chidp = silc_public_key_payload_encode(pubkey);
2326 args = silc_argument_payload_encode_one(args,
2327 silc_buffer_datalen(chidp), 2);
2328 silc_buffer_free(chidp);
2329 silc_pkcs_public_key_free(pubkey);
2331 args = silc_argument_payload_encode_one(args, ban, strlen(ban), 1);
2335 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
2337 /* Send the command */
2338 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
2339 1, silc_buffer_datalen(chidp),
2340 2, args ? action : NULL, args ? 1 : 0,
2341 3, silc_buffer_datalen(args));
2343 silc_buffer_free(chidp);
2344 silc_buffer_free(args);
2345 silc_client_unref_channel(client, conn, channel);
2347 /* Notify application */
2348 COMMAND(SILC_STATUS_OK);
2350 /** Wait for command reply */
2351 silc_fsm_next(fsm, silc_client_command_reply_wait);
2352 return SILC_FSM_CONTINUE;
2355 return SILC_FSM_FINISH;
2358 /********************************* DETACH ***********************************/
2360 /* Command DETACH. This is used to detach from the server */
2362 SILC_FSM_STATE(silc_client_command_detach)
2364 SilcClientCommandContext cmd = fsm_context;
2365 SilcClientConnection conn = cmd->conn;
2367 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
2369 /* Notify application */
2370 COMMAND(SILC_STATUS_OK);
2372 /** Wait for command reply */
2373 silc_fsm_next(fsm, silc_client_command_reply_wait);
2374 return SILC_FSM_CONTINUE;
2377 /********************************** WATCH ***********************************/
2379 /* Command WATCH. */
2381 SILC_FSM_STATE(silc_client_command_watch)
2383 SilcClientCommandContext cmd = fsm_context;
2384 SilcClientConnection conn = cmd->conn;
2385 SilcBuffer args = NULL;
2387 const char *pubkey = NULL;
2388 SilcBool pubkey_add = TRUE;
2390 if (cmd->argc < 3) {
2391 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2395 if (!strcasecmp(cmd->argv[1], "-add")) {
2397 } else if (!strcasecmp(cmd->argv[1], "-del")) {
2399 } else if (!strcasecmp(cmd->argv[1], "-pubkey") && cmd->argc >= 3) {
2401 pubkey = cmd->argv[2] + 1;
2402 if (cmd->argv[2][0] == '-')
2405 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2413 if (!silc_pkcs_load_public_key(pubkey, &pk)) {
2414 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2415 "Could not load public key %s, check the filename", pubkey);
2416 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2420 args = silc_buffer_alloc_size(2);
2421 silc_buffer_format(args,
2422 SILC_STR_UI_SHORT(1),
2424 buffer = silc_public_key_payload_encode(pk);
2425 args = silc_argument_payload_encode_one(args, silc_buffer_datalen(buffer),
2426 pubkey_add ? 0x00 : 0x01);
2427 silc_buffer_free(buffer);
2428 silc_pkcs_public_key_free(pk);
2431 /* Send the commmand */
2432 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
2433 1, silc_buffer_datalen(conn->internal->
2435 type, pubkey ? args->data : cmd->argv[2],
2436 pubkey ? silc_buffer_len(args) :
2439 silc_buffer_free(args);
2441 /* Notify application */
2442 COMMAND(SILC_STATUS_OK);
2444 /** Wait for command reply */
2445 silc_fsm_next(fsm, silc_client_command_reply_wait);
2446 return SILC_FSM_CONTINUE;
2449 return SILC_FSM_FINISH;
2452 /********************************** LEAVE ***********************************/
2454 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2456 SILC_FSM_STATE(silc_client_command_leave)
2458 SilcClientCommandContext cmd = fsm_context;
2459 SilcClientConnection conn = cmd->conn;
2460 SilcClient client = conn->client;
2461 SilcChannelEntry channel;
2465 if (cmd->argc != 2) {
2466 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2467 "Usage: /LEAVE <channel>");
2468 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2472 if (cmd->argv[1][0] == '*') {
2473 if (!conn->current_channel) {
2474 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2477 name = conn->current_channel->channel_name;
2479 name = cmd->argv[1];
2482 /* Get the channel entry */
2483 channel = silc_client_get_channel(conn->client, conn, name);
2485 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2489 idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
2491 /* Send LEAVE command to the server */
2492 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
2493 1, silc_buffer_datalen(idp));
2495 silc_buffer_free(idp);
2497 /* Notify application */
2498 COMMAND(SILC_STATUS_OK);
2500 if (conn->current_channel == channel)
2501 conn->current_channel = NULL;
2503 silc_client_unref_channel(client, conn, channel);
2505 /** Wait for command reply */
2506 silc_fsm_next(fsm, silc_client_command_reply_wait);
2507 return SILC_FSM_CONTINUE;
2510 return SILC_FSM_FINISH;
2513 /********************************** USERS ***********************************/
2515 /* Command USERS. Requests the USERS of the clients joined on requested
2518 SILC_FSM_STATE(silc_client_command_users)
2520 SilcClientCommandContext cmd = fsm_context;
2521 SilcClientConnection conn = cmd->conn;
2524 if (cmd->argc != 2) {
2525 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2526 "Usage: /USERS <channel>");
2527 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2531 if (cmd->argv[1][0] == '*') {
2532 if (!conn->current_channel) {
2533 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2536 name = conn->current_channel->channel_name;
2538 name = cmd->argv[1];
2541 /* Send USERS command to the server */
2542 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
2543 2, name, strlen(name));
2545 /* Notify application */
2546 COMMAND(SILC_STATUS_OK);
2548 /** Wait for command reply */
2549 silc_fsm_next(fsm, silc_client_command_reply_wait);
2550 return SILC_FSM_CONTINUE;
2553 return SILC_FSM_FINISH;
2556 /********************************* GETKEY ***********************************/
2558 /* Command GETKEY. Used to fetch remote client's public key. */
2560 SILC_FSM_STATE(silc_client_command_getkey)
2562 SilcClientCommandContext cmd = fsm_context;
2563 SilcClientConnection conn = cmd->conn;
2564 SilcClient client = conn->client;
2565 SilcClientEntry client_entry;
2566 SilcServerEntry server_entry;
2568 char *nickname = NULL;
2571 if (cmd->argc < 2) {
2572 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2573 "Usage: /GETKEY <nickname or server name>");
2574 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2575 return SILC_FSM_FINISH;
2578 /* Parse the typed nickname. */
2579 if (!silc_client_nickname_parse(client, conn, cmd->argv[1], &nickname)) {
2580 COMMAND_ERROR(SILC_STATUS_ERR_RESOURCE_LIMIT);
2581 return SILC_FSM_FINISH;
2584 /* Find client entry */
2585 clients = silc_client_get_clients_local(client, conn, nickname,
2588 /* Check whether user requested server */
2589 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2590 if (!server_entry) {
2591 if (cmd->resolved) {
2592 /* Resolving didn't find anything. We should never get here as
2593 errors are handled in the resolving callback. */
2594 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2595 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_SERVER);
2596 return SILC_FSM_FINISH;
2599 /* No client or server exist with this name, query for both. */
2600 cmd->resolved = TRUE;
2601 SILC_FSM_CALL(silc_client_command_send(client, conn,
2602 SILC_COMMAND_IDENTIFY,
2603 silc_client_command_continue,
2606 strlen(cmd->argv[1]),
2608 strlen(cmd->argv[1])));
2611 idp = silc_id_payload_encode(&server_entry->id, SILC_ID_SERVER);
2612 silc_client_unref_server(client, conn, server_entry);
2614 client_entry = silc_dlist_get(clients);
2615 idp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT);
2616 silc_client_list_free(client, conn, clients);
2619 /* Send the commmand */
2620 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
2621 1, silc_buffer_datalen(idp));
2623 silc_buffer_free(idp);
2624 silc_free(nickname);
2626 /* Notify application */
2627 COMMAND(SILC_STATUS_OK);
2629 /** Wait for command reply */
2630 silc_fsm_next(fsm, silc_client_command_reply_wait);
2631 return SILC_FSM_CONTINUE;
2634 /********************************* SERVICE **********************************/
2636 /* Command SERVICE. Negotiates service agreement with server. */
2637 /* XXX incomplete */
2639 SILC_FSM_STATE(silc_client_command_service)
2641 SilcClientCommandContext cmd = fsm_context;
2643 SilcClientConnection conn = cmd->conn;
2647 if (cmd->argc < 2) {
2648 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2649 "Usage: /SERVICE [<service name>] [-pubkey]");
2650 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2651 return SILC_FSM_FINISH;
2654 name = cmd->argv[1];
2656 /* Send SERVICE command to the server */
2657 buffer = silc_command_payload_encode_va(SILC_COMMAND_SERVICE,
2658 ++conn->cmd_ident, 1,
2659 1, name, strlen(name));
2660 silc_client_packet_send(conn->client, conn->sock, SILC_PACKET_COMMAND,
2661 NULL, 0, NULL, NULL, buffer->data,
2663 silc_buffer_free(buffer);
2666 /* Notify application */
2667 COMMAND(SILC_STATUS_OK);
2669 /** Wait for command reply */
2670 silc_fsm_next(fsm, silc_client_command_reply_wait);
2671 return SILC_FSM_CONTINUE;
2674 /* Register all default commands provided by the client library for the
2677 void silc_client_commands_register(SilcClient client)
2679 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2682 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 5);
2683 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2684 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2685 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2686 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2687 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2688 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2689 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2690 SILC_CLIENT_CMD(kill, KILL, "KILL", 4);
2691 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2692 SILC_CLIENT_CMD(stats, STATS, "STATS", 0);
2693 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2694 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2695 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2696 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2697 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2698 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 6);
2699 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 9);
2700 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2701 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2702 SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2703 SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
2704 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2705 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2706 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2707 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2708 SILC_CLIENT_CMD(service, SERVICE, "SERVICE", 10);
2711 /* Unregister all commands. */
2713 void silc_client_commands_unregister(SilcClient client)
2715 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2716 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2717 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2718 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2719 SILC_CLIENT_CMDU(list, LIST, "LIST");
2720 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2721 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2722 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2723 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2724 SILC_CLIENT_CMDU(info, INFO, "INFO");
2725 SILC_CLIENT_CMDU(stats, STATS, "STATS");
2726 SILC_CLIENT_CMDU(ping, PING, "PING");
2727 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2728 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2729 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2730 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2731 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2732 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2733 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2734 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2735 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2736 SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2737 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2738 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2739 SILC_CLIENT_CMDU(users, USERS, "USERS");
2740 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2741 SILC_CLIENT_CMDU(service, SERVICE, "SERVICE");
2744 /****************** Client Side Incoming Command Handling *******************/
2746 /* Reply to WHOIS command from server */
2748 static void silc_client_command_process_whois(SilcClient client,
2749 SilcClientConnection conn,
2750 SilcCommandPayload payload,
2751 SilcArgumentPayload args)
2757 SilcBuffer buffer, packet;
2759 SILC_LOG_DEBUG(("Received WHOIS command"));
2761 /* Try to take the Requested Attributes */
2762 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
2766 attrs = silc_attribute_payload_parse(tmp, tmp_len);
2770 /* Process requested attributes */
2771 buffer = silc_client_attributes_process(client, conn, attrs);
2773 silc_attribute_payload_list_free(attrs);
2777 /* Send the attributes back */
2779 silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
2781 silc_command_get_ident(payload),
2782 1, 11, buffer->data, buffer->len);
2783 silc_client_packet_send(client, sock, SILC_PACKET_COMMAND_REPLY,
2784 NULL, 0, NULL, NULL, packet->data,
2786 silc_buffer_free(packet);
2787 silc_buffer_free(buffer);
2791 /* Client is able to receive some command packets even though they are
2792 special case. Server may send WHOIS command to the client to retrieve
2793 Requested Attributes information for WHOIS query the server is
2794 processing. This function currently handles only the WHOIS command,
2795 but if in the future more commands may arrive then this can be made
2796 to support other commands too. */
2798 SILC_FSM_STATE(silc_client_command)
2800 SilcClientConnection conn = fsm_context;
2801 SilcClient client = conn->client;
2802 SilcPacket packet = state_context;
2803 SilcCommandPayload payload;
2804 SilcCommand command;
2805 SilcArgumentPayload args;
2807 /* Get command payload from packet */
2808 payload = silc_command_payload_parse(packet->buffer.data,
2809 silc_buffer_len(&packet->buffer));
2811 SILC_LOG_DEBUG(("Bad command packet"));
2812 return SILC_FSM_FINISH;
2816 args = silc_command_get_args(payload);
2818 /* Get the command */
2819 command = silc_command_get(payload);
2822 case SILC_COMMAND_WHOIS:
2823 /* Ignore everything if requested by application */
2824 if (conn->internal->params.ignore_requested_attributes)
2827 silc_client_command_process_whois(client, conn, payload, args);
2834 silc_command_payload_free(payload);
2835 return SILC_FSM_FINISH;