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;
1085 SilcClient client = conn->client;
1087 SILC_LOG_DEBUG(("Quitting"));
1089 /* Notify application */
1090 COMMAND(SILC_STATUS_OK);
1092 /* Call connection callback */
1093 if (!conn->internal->callback_called)
1094 conn->callback(client, conn, SILC_CLIENT_CONN_DISCONNECTED,
1095 0, NULL, conn->callback_context);
1096 conn->internal->callback_called = TRUE;
1098 /* Signal to close connection */
1099 if (!conn->internal->disconnected) {
1100 conn->internal->disconnected = TRUE;
1101 SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event);
1104 return SILC_FSM_FINISH;
1107 /* Command QUIT. Closes connection with current server. */
1109 SILC_FSM_STATE(silc_client_command_quit)
1111 SilcClientCommandContext cmd = fsm_context;
1112 SilcClientConnection conn = cmd->conn;
1115 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1116 1, cmd->argv[1], cmd->argv_lens[1]);
1118 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
1120 /* Sleep for a while */
1123 /* We close the connection with a little timeout */
1124 silc_fsm_next_later(fsm, silc_client_command_quit_final, 2, 0);
1125 return SILC_FSM_WAIT;
1128 /********************************** KILL ************************************/
1131 /* Command KILL. Router operator can use this command to remove an client
1132 fromthe SILC Network. */
1134 SILC_FSM_STATE(silc_client_command_kill)
1136 SilcClientCommandContext cmd = fsm_context;
1137 SilcClientConnection conn = cmd->conn;
1138 SilcClient client = conn->client;
1139 SilcBuffer idp, auth = NULL;
1140 SilcClientEntry target;
1142 char *nickname = NULL, *comment = NULL;
1144 if (cmd->argc < 2) {
1145 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1146 "Usage: /KILL <nickname> [<comment>] [-pubkey]");
1147 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1148 return SILC_FSM_FINISH;
1151 /* Parse the typed nickname. */
1152 if (!silc_client_nickname_parse(client, conn, cmd->argv[1], &nickname))
1153 return SILC_FSM_FINISH;
1155 /* Get the target client */
1156 clients = silc_client_get_clients_local(client, conn, nickname,
1159 /* Resolve client information */
1160 SILC_FSM_CALL(silc_client_get_clients(client, conn, nickname,
1162 silc_client_command_resolve_continue,
1165 target = silc_dlist_get(clients);
1167 if (cmd->argc >= 3) {
1168 if (strcasecmp(cmd->argv[2], "-pubkey"))
1169 comment = cmd->argv[2];
1171 if (!strcasecmp(cmd->argv[2], "-pubkey") ||
1172 (cmd->argc >= 4 && !strcasecmp(cmd->argv[3], "-pubkey"))) {
1173 /* Encode the public key authentication payload */
1174 auth = silc_auth_public_key_auth_generate(conn->public_key,
1177 conn->internal->sha1hash,
1178 &target->id, SILC_ID_CLIENT);
1182 /* Send the KILL command to the server */
1183 idp = silc_id_payload_encode(&target->id, SILC_ID_CLIENT);
1184 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
1185 1, silc_buffer_datalen(idp),
1186 2, comment, comment ? strlen(comment) : 0,
1187 3, silc_buffer_datalen(auth));
1188 silc_buffer_free(idp);
1189 silc_buffer_free(auth);
1190 silc_free(nickname);
1191 silc_client_list_free(client, conn, clients);
1193 /* Notify application */
1194 COMMAND(SILC_STATUS_OK);
1196 /** Wait for command reply */
1197 silc_fsm_next(fsm, silc_client_command_reply_wait);
1198 return SILC_FSM_CONTINUE;
1201 /********************************** INFO ************************************/
1203 /* Command INFO. Request information about specific server. If specific
1204 server is not provided the current server is used. */
1206 SILC_FSM_STATE(silc_client_command_info)
1208 SilcClientCommandContext cmd = fsm_context;
1209 SilcClientConnection conn = cmd->conn;
1211 /* Send the command */
1213 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1214 1, cmd->argv[1], cmd->argv_lens[1]);
1216 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
1218 /* Notify application */
1219 COMMAND(SILC_STATUS_OK);
1221 /** Wait for command reply */
1222 silc_fsm_next(fsm, silc_client_command_reply_wait);
1223 return SILC_FSM_CONTINUE;
1226 /********************************** STATS ***********************************/
1228 /* Command STATS. Shows server and network statistics. */
1230 SILC_FSM_STATE(silc_client_command_stats)
1232 SilcClientCommandContext cmd = fsm_context;
1233 SilcClientConnection conn = cmd->conn;
1235 /* Send the command */
1236 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1237 1, silc_buffer_datalen(conn->internal->
1240 /* Notify application */
1241 COMMAND(SILC_STATUS_OK);
1243 /** Wait for command reply */
1244 silc_fsm_next(fsm, silc_client_command_reply_wait);
1245 return SILC_FSM_CONTINUE;
1248 /********************************** PING ************************************/
1250 /* Command PING. Sends ping to server. */
1252 SILC_FSM_STATE(silc_client_command_ping)
1254 SilcClientCommandContext cmd = fsm_context;
1255 SilcClientConnection conn = cmd->conn;
1257 if (cmd->argc < 2) {
1258 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1259 return SILC_FSM_FINISH;
1262 /* Send the command */
1263 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1264 1, silc_buffer_datalen(conn->internal->
1267 /* Save ping time */
1268 cmd->context = SILC_64_TO_PTR(silc_time());
1270 /* Notify application */
1271 COMMAND(SILC_STATUS_OK);
1273 /** Wait for command reply */
1274 silc_fsm_next(fsm, silc_client_command_reply_wait);
1275 return SILC_FSM_CONTINUE;
1278 /********************************** JOIN ************************************/
1280 /* Command JOIN. Joins to a channel. */
1282 SILC_FSM_STATE(silc_client_command_join)
1284 SilcClientCommandContext cmd = fsm_context;
1285 SilcClientConnection conn = cmd->conn;
1286 SilcClient client = conn->client;
1287 SilcChannelEntry channel = NULL;
1288 SilcBuffer auth = NULL, cauth = NULL;
1289 char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
1290 int i, passphrase_len = 0;
1292 if (cmd->argc < 2) {
1293 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1297 /* See if we have joined to the requested channel already */
1298 channel = silc_client_get_channel(conn->client, conn, cmd->argv[1]);
1299 if (channel && silc_client_on_channel(channel, conn->local_entry))
1302 if (cmd->argv_lens[1] > 256)
1303 cmd->argv_lens[1] = 256;
1305 name = cmd->argv[1];
1307 for (i = 2; i < cmd->argc; i++) {
1308 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
1309 cipher = cmd->argv[++i];
1310 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
1311 hmac = cmd->argv[++i];
1312 } else if (!strcasecmp(cmd->argv[i], "-founder")) {
1313 auth = silc_auth_public_key_auth_generate(conn->public_key,
1316 conn->internal->sha1hash,
1319 } else if (!strcasecmp(cmd->argv[i], "-auth")) {
1320 SilcPublicKey pubkey = conn->public_key;
1321 SilcPrivateKey privkey = conn->private_key;
1322 unsigned char *pk, pkhash[SILC_HASH_MAXLEN], *pubdata;
1325 if (cmd->argc >= i + 3) {
1327 if (cmd->argc >= i + 4) {
1328 pass = cmd->argv[i + 3];
1331 if (!silc_load_key_pair(cmd->argv[i + 1], cmd->argv[i + 2], pass,
1332 &pubkey, &privkey)) {
1333 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1334 "Could not load key pair, check your arguments");
1335 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1341 pk = silc_pkcs_public_key_encode(pubkey, &pk_len);
1342 silc_hash_make(conn->internal->sha1hash, pk, pk_len, pkhash);
1344 pubdata = silc_rng_get_rn_data(conn->client->rng, 128);
1345 memcpy(pubdata, pkhash, 20);
1346 cauth = silc_auth_public_key_auth_generate_wpub(pubkey, privkey,
1348 conn->internal->sha1hash,
1351 memset(pubdata, 0, 128);
1354 /* Passphrases must be UTF-8 encoded, so encode if it is not */
1355 if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
1356 passphrase_len = silc_utf8_encoded_len(cmd->argv[i],
1357 cmd->argv_lens[i], 0);
1358 pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
1359 passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
1360 0, pu8, passphrase_len);
1363 passphrase = strdup(cmd->argv[i]);
1364 passphrase_len = cmd->argv_lens[i];
1369 /* Send JOIN command to the server */
1370 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 7,
1371 1, name, strlen(name),
1372 2, silc_buffer_datalen(conn->internal->
1374 3, passphrase, passphrase_len,
1375 4, cipher, cipher ? strlen(cipher) : 0,
1376 5, hmac, hmac ? strlen(hmac) : 0,
1377 6, silc_buffer_datalen(auth),
1378 7, silc_buffer_datalen(cauth));
1380 silc_buffer_free(auth);
1381 silc_buffer_free(cauth);
1383 memset(passphrase, 0, strlen(passphrase));
1384 silc_free(passphrase);
1385 silc_client_unref_channel(client, conn, channel);
1387 /* Notify application */
1388 COMMAND(SILC_STATUS_OK);
1390 /** Wait for command reply */
1391 silc_fsm_next(fsm, silc_client_command_reply_wait);
1392 return SILC_FSM_CONTINUE;
1395 silc_client_unref_channel(client, conn, channel);
1396 return SILC_FSM_FINISH;
1399 /********************************** MOTD ************************************/
1401 /* MOTD command. Requests motd from server. */
1403 SILC_FSM_STATE(silc_client_command_motd)
1405 SilcClientCommandContext cmd = fsm_context;
1406 SilcClientConnection conn = cmd->conn;
1408 if (cmd->argc < 1 || cmd->argc > 2) {
1409 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1410 "Usage: /MOTD [<server>]");
1411 COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
1412 SILC_STATUS_ERR_TOO_MANY_PARAMS));
1413 return SILC_FSM_FINISH;
1416 /* Send the command */
1418 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1419 1, conn->remote_host,
1420 strlen(conn->remote_host));
1422 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1423 1, cmd->argv[1], cmd->argv_lens[1]);
1425 /* Notify application */
1426 COMMAND(SILC_STATUS_OK);
1428 /** Wait for command reply */
1429 silc_fsm_next(fsm, silc_client_command_reply_wait);
1430 return SILC_FSM_CONTINUE;
1433 /********************************** UMODE ***********************************/
1435 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1436 modes as client cannot set itself server/router operator privileges. */
1438 SILC_FSM_STATE(silc_client_command_umode)
1440 SilcClientCommandContext cmd = fsm_context;
1441 SilcClientConnection conn = cmd->conn;
1442 unsigned char *cp, modebuf[4];
1443 SilcUInt32 mode, add, len;
1446 if (cmd->argc < 2) {
1447 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1448 "Usage: /UMODE +|-<modes>");
1449 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1450 return SILC_FSM_FINISH;
1453 mode = conn->local_entry->mode;
1455 /* Are we adding or removing mode */
1456 if (cmd->argv[1][0] == '-')
1462 cp = cmd->argv[1] + 1;
1464 for (i = 0; i < len; i++) {
1469 mode |= SILC_UMODE_SERVER_OPERATOR;
1470 mode |= SILC_UMODE_ROUTER_OPERATOR;
1471 mode |= SILC_UMODE_GONE;
1472 mode |= SILC_UMODE_INDISPOSED;
1473 mode |= SILC_UMODE_BUSY;
1474 mode |= SILC_UMODE_PAGE;
1475 mode |= SILC_UMODE_HYPER;
1476 mode |= SILC_UMODE_ROBOT;
1477 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1478 mode |= SILC_UMODE_REJECT_WATCHING;
1480 mode = SILC_UMODE_NONE;
1485 mode |= SILC_UMODE_SERVER_OPERATOR;
1487 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1491 mode |= SILC_UMODE_ROUTER_OPERATOR;
1493 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1497 mode |= SILC_UMODE_GONE;
1499 mode &= ~SILC_UMODE_GONE;
1503 mode |= SILC_UMODE_INDISPOSED;
1505 mode &= ~SILC_UMODE_INDISPOSED;
1509 mode |= SILC_UMODE_BUSY;
1511 mode &= ~SILC_UMODE_BUSY;
1515 mode |= SILC_UMODE_PAGE;
1517 mode &= ~SILC_UMODE_PAGE;
1521 mode |= SILC_UMODE_HYPER;
1523 mode &= ~SILC_UMODE_HYPER;
1527 mode |= SILC_UMODE_ROBOT;
1529 mode &= ~SILC_UMODE_ROBOT;
1533 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1535 mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
1539 mode |= SILC_UMODE_REJECT_WATCHING;
1541 mode &= ~SILC_UMODE_REJECT_WATCHING;
1545 mode |= SILC_UMODE_BLOCK_INVITE;
1547 mode &= ~SILC_UMODE_BLOCK_INVITE;
1550 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1551 return SILC_FSM_FINISH;
1556 SILC_PUT32_MSB(mode, modebuf);
1558 /* Send the command */
1559 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
1560 1, silc_buffer_datalen(conn->internal->
1562 2, modebuf, sizeof(modebuf));
1564 /* Notify application */
1565 COMMAND(SILC_STATUS_OK);
1567 /** Wait for command reply */
1568 silc_fsm_next(fsm, silc_client_command_reply_wait);
1569 return SILC_FSM_CONTINUE;
1572 /********************************** CMODE ***********************************/
1574 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1575 can be set several at once. Those modes that require argument must be set
1576 separately (unless set with modes that does not require arguments). */
1578 SILC_FSM_STATE(silc_client_command_cmode)
1580 SilcClientCommandContext cmd = fsm_context;
1581 SilcClientConnection conn = cmd->conn;
1582 SilcClient client = conn->client;
1583 SilcChannelEntry channel = NULL;
1584 SilcBuffer chidp, auth = NULL, pk = NULL;
1585 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1586 SilcUInt32 mode, add, type, len, arg_len = 0;
1589 if (cmd->argc < 3) {
1590 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1591 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1592 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1596 if (cmd->argv[1][0] == '*') {
1597 if (!conn->current_channel) {
1598 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1602 channel = conn->current_channel;
1603 silc_client_ref_channel(client, conn, channel);
1605 name = cmd->argv[1];
1607 channel = silc_client_get_channel(conn->client, conn, name);
1609 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1614 mode = channel->mode;
1616 /* Are we adding or removing mode */
1617 if (cmd->argv[2][0] == '-')
1622 /* Argument type to be sent to server */
1626 cp = cmd->argv[2] + 1;
1628 for (i = 0; i < len; i++) {
1632 mode |= SILC_CHANNEL_MODE_PRIVATE;
1634 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1638 mode |= SILC_CHANNEL_MODE_SECRET;
1640 mode &= ~SILC_CHANNEL_MODE_SECRET;
1644 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1646 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1650 mode |= SILC_CHANNEL_MODE_INVITE;
1652 mode &= ~SILC_CHANNEL_MODE_INVITE;
1656 mode |= SILC_CHANNEL_MODE_TOPIC;
1658 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1662 mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1664 mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1668 mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1670 mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1675 mode |= SILC_CHANNEL_MODE_ULIMIT;
1677 if (cmd->argc < 4) {
1678 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1679 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1680 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1683 ll = atoi(cmd->argv[3]);
1684 SILC_PUT32_MSB(ll, tmp);
1688 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1693 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1695 if (cmd->argc < 4) {
1696 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1697 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1698 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1702 arg_len = cmd->argv_lens[3];
1704 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1709 mode |= SILC_CHANNEL_MODE_CIPHER;
1711 if (cmd->argc < 4) {
1712 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1713 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1714 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1718 arg_len = cmd->argv_lens[3];
1720 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1725 mode |= SILC_CHANNEL_MODE_HMAC;
1727 if (cmd->argc < 4) {
1728 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1729 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1730 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1734 arg_len = cmd->argv_lens[3];
1736 mode &= ~SILC_CHANNEL_MODE_HMAC;
1741 SilcPublicKey pubkey = conn->public_key;
1742 SilcPrivateKey privkey = conn->private_key;
1744 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1747 if (cmd->argc >= 5) {
1750 pass = cmd->argv[5];
1751 if (!silc_load_key_pair(cmd->argv[3], cmd->argv[4], pass,
1752 &pubkey, &privkey)) {
1753 SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1754 "Could not load key pair, check your arguments");
1755 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1760 pk = silc_public_key_payload_encode(pubkey);
1761 auth = silc_auth_public_key_auth_generate(pubkey, privkey,
1763 conn->internal->sha1hash,
1766 arg = silc_buffer_data(auth);
1767 arg_len = silc_buffer_len(auth);
1769 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1775 SilcBool chadd = FALSE;
1776 SilcPublicKey chpk = NULL;
1778 mode |= SILC_CHANNEL_MODE_CHANNEL_AUTH;
1781 if (cmd->argc == 3) {
1782 /* Send empty command to receive the public key list. */
1783 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
1784 silc_client_command_send_va(conn, cmd, SILC_COMMAND_CMODE,
1786 1, silc_buffer_datalen(chidp));
1787 silc_buffer_free(chidp);
1789 /* Notify application */
1790 COMMAND(SILC_STATUS_OK);
1794 if (cmd->argc >= 4) {
1795 auth = silc_buffer_alloc_size(2);
1796 silc_buffer_format(auth,
1797 SILC_STR_UI_SHORT(cmd->argc - 3),
1801 for (k = 3; k < cmd->argc; k++) {
1802 if (cmd->argv[k][0] == '+')
1804 if (!silc_pkcs_load_public_key(cmd->argv[k] + 1, &chpk)) {
1805 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1806 "Could not load public key %s, check the filename",
1808 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1809 silc_buffer_free(auth);
1814 pk = silc_public_key_payload_encode(chpk);
1815 auth = silc_argument_payload_encode_one(auth,
1816 silc_buffer_datalen(pk),
1817 chadd ? 0x00 : 0x01);
1818 silc_pkcs_public_key_free(chpk);
1819 silc_buffer_free(pk);
1824 arg = silc_buffer_data(auth);
1825 arg_len = silc_buffer_len(auth);
1827 mode &= ~SILC_CHANNEL_MODE_CHANNEL_AUTH;
1831 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1837 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
1838 SILC_PUT32_MSB(mode, modebuf);
1840 /* Send the command. We support sending only one mode at once that
1841 requires an argument. */
1843 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 4,
1844 1, silc_buffer_datalen(chidp),
1845 2, modebuf, sizeof(modebuf),
1847 8, silc_buffer_datalen(pk));
1849 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
1850 1, silc_buffer_datalen(chidp),
1851 2, modebuf, sizeof(modebuf));
1854 silc_buffer_free(chidp);
1855 silc_buffer_free(auth);
1856 silc_buffer_free(pk);
1857 silc_client_unref_channel(client, conn, channel);
1859 /* Notify application */
1860 COMMAND(SILC_STATUS_OK);
1862 /** Wait for command reply */
1863 silc_fsm_next(fsm, silc_client_command_reply_wait);
1864 return SILC_FSM_CONTINUE;
1867 silc_client_unref_channel(client, conn, channel);
1868 return SILC_FSM_FINISH;
1871 /********************************* CUMODE ***********************************/
1873 /* CUMODE command. Changes client's mode on a channel. */
1875 SILC_FSM_STATE(silc_client_command_cumode)
1877 SilcClientCommandContext cmd = fsm_context;
1878 SilcClientConnection conn = cmd->conn;
1879 SilcClient client = conn->client;
1880 SilcChannelEntry channel = NULL;
1881 SilcChannelUser chu;
1882 SilcClientEntry client_entry;
1883 SilcBuffer clidp, chidp, auth = NULL;
1884 SilcDList clients = NULL;
1885 unsigned char *name, *cp, modebuf[4];
1886 SilcUInt32 mode = 0, add, len;
1887 char *nickname = NULL;
1890 if (cmd->argc < 4) {
1891 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1892 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1893 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1897 if (cmd->argv[1][0] == '*') {
1898 if (!conn->current_channel) {
1899 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1903 channel = conn->current_channel;
1904 silc_client_ref_channel(client, conn, channel);
1906 name = cmd->argv[1];
1908 channel = silc_client_get_channel(conn->client, conn, name);
1910 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1915 /* Parse the typed nickname. */
1916 silc_client_nickname_parse(client, conn, cmd->argv[3], &nickname);
1918 /* Find client entry */
1919 clients = silc_client_get_clients_local(client, conn, nickname,
1922 /* Resolve client information */
1923 SILC_FSM_CALL(silc_client_get_clients(client, conn, nickname, cmd->argv[3],
1924 silc_client_command_resolve_continue,
1927 client_entry = silc_dlist_get(clients);
1929 /* Get the current mode */
1930 chu = silc_client_on_channel(channel, client_entry);
1934 /* Are we adding or removing mode */
1935 if (cmd->argv[2][0] == '-')
1941 cp = cmd->argv[2] + 1;
1943 for (i = 0; i < len; i++) {
1947 mode |= SILC_CHANNEL_UMODE_CHANFO;
1948 mode |= SILC_CHANNEL_UMODE_CHANOP;
1949 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1950 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1951 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1953 mode = SILC_CHANNEL_UMODE_NONE;
1958 SilcPublicKey pubkey = conn->public_key;
1959 SilcPrivateKey privkey = conn->private_key;
1961 if (cmd->argc >= 6) {
1964 pass = cmd->argv[6];
1965 if (!silc_load_key_pair(cmd->argv[4], cmd->argv[5], pass,
1966 &pubkey, &privkey)) {
1967 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1968 "Could not load key pair, check your arguments");
1969 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1974 auth = silc_auth_public_key_auth_generate(pubkey, privkey,
1976 conn->internal->sha1hash,
1979 mode |= SILC_CHANNEL_UMODE_CHANFO;
1981 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1986 mode |= SILC_CHANNEL_UMODE_CHANOP;
1988 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1992 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1994 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1998 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
2000 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
2004 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
2006 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
2010 mode |= SILC_CHANNEL_UMODE_QUIET;
2012 mode &= ~SILC_CHANNEL_UMODE_QUIET;
2015 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
2021 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
2022 SILC_PUT32_MSB(mode, modebuf);
2023 clidp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT);
2025 /* Send the command packet. We support sending only one mode at once
2026 that requires an argument. */
2027 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, auth ? 4 : 3,
2028 1, silc_buffer_datalen(chidp),
2030 3, silc_buffer_datalen(clidp),
2031 4, silc_buffer_datalen(auth));
2033 silc_buffer_free(chidp);
2034 silc_buffer_free(clidp);
2036 silc_buffer_free(auth);
2037 silc_free(nickname);
2038 silc_client_list_free(client, conn, clients);
2039 silc_client_unref_channel(client, conn, channel);
2041 /* Notify application */
2042 COMMAND(SILC_STATUS_OK);
2044 /** Wait for command reply */
2045 silc_fsm_next(fsm, silc_client_command_reply_wait);
2046 return SILC_FSM_CONTINUE;
2049 silc_client_unref_channel(client, conn, channel);
2050 silc_client_list_free(client, conn, clients);
2051 silc_free(nickname);
2052 return SILC_FSM_FINISH;
2055 /********************************** KICK ************************************/
2057 /* KICK command. Kicks a client out of channel. */
2059 SILC_FSM_STATE(silc_client_command_kick)
2061 SilcClientCommandContext cmd = fsm_context;
2062 SilcClientConnection conn = cmd->conn;
2063 SilcClient client = conn->client;
2064 SilcChannelEntry channel = NULL;
2065 SilcBuffer idp, idp2;
2066 SilcClientEntry target;
2067 SilcDList clients = NULL;
2069 char *nickname = NULL;
2071 if (cmd->argc < 3) {
2072 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2073 "Usage: /KICK <channel> <nickname> [<comment>]");
2074 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2078 if (cmd->argv[1][0] == '*') {
2079 if (!conn->current_channel) {
2080 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2083 name = conn->current_channel->channel_name;
2085 name = cmd->argv[1];
2088 if (!conn->current_channel) {
2089 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2093 /* Get the Channel ID of the channel */
2094 channel = silc_client_get_channel(conn->client, conn, name);
2096 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2100 /* Parse the typed nickname. */
2101 silc_client_nickname_parse(client, conn, cmd->argv[2], &nickname);
2103 /* Get the target client */
2104 clients = silc_client_get_clients_local(client, conn, nickname,
2107 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2108 "No such client: %s", cmd->argv[2]);
2109 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2112 target = silc_dlist_get(clients);
2114 /* Send KICK command to the server */
2115 idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
2116 idp2 = silc_id_payload_encode(&target->id, SILC_ID_CLIENT);
2118 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
2119 1, silc_buffer_datalen(idp),
2120 2, silc_buffer_datalen(idp2));
2122 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
2123 1, silc_buffer_datalen(idp),
2124 2, silc_buffer_datalen(idp2),
2125 3, cmd->argv[3], strlen(cmd->argv[3]));
2127 silc_buffer_free(idp);
2128 silc_buffer_free(idp2);
2129 silc_free(nickname);
2130 silc_client_list_free(client, conn, clients);
2131 silc_client_unref_channel(client, conn, channel);
2133 /* Notify application */
2134 COMMAND(SILC_STATUS_OK);
2136 /** Wait for command reply */
2137 silc_fsm_next(fsm, silc_client_command_reply_wait);
2138 return SILC_FSM_CONTINUE;
2141 silc_client_unref_channel(client, conn, channel);
2142 silc_free(nickname);
2143 return SILC_FSM_FINISH;
2146 /***************************** OPER & SILCOPER ******************************/
2149 unsigned char *passphrase;
2150 SilcUInt32 passphrase_len;
2151 } *SilcClientCommandOper;
2153 /* Ask passphrase callback */
2155 static void silc_client_command_oper_cb(unsigned char *data,
2156 SilcUInt32 data_len, void *context)
2158 SilcClientCommandContext cmd = context;
2159 SilcClientCommandOper oper = cmd->context;
2161 if (data && data_len)
2162 oper->passphrase = silc_memdup(data, data_len);
2163 oper->passphrase_len = data_len;
2166 SILC_FSM_CALL_CONTINUE(&cmd->thread);
2169 /* Send OPER/SILCOPER command */
2171 SILC_FSM_STATE(silc_client_command_oper_send)
2173 SilcClientCommandContext cmd = fsm_context;
2174 SilcClientConnection conn = cmd->conn;
2175 SilcClientCommandOper oper = cmd->context;
2178 if (!oper || !oper->passphrase) {
2179 /* Encode the public key authentication payload */
2180 auth = silc_auth_public_key_auth_generate(conn->public_key,
2183 conn->internal->hash,
2187 /* Encode the password authentication payload */
2188 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
2189 oper->passphrase, oper->passphrase_len);
2192 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
2193 1, cmd->argv[1], strlen(cmd->argv[1]),
2194 2, silc_buffer_datalen(auth));
2196 silc_buffer_clear(auth);
2197 silc_buffer_free(auth);
2199 silc_free(oper->passphrase);
2203 /* Notify application */
2204 COMMAND(SILC_STATUS_OK);
2206 /** Wait for command reply */
2207 silc_fsm_next(fsm, silc_client_command_reply_wait);
2208 return SILC_FSM_CONTINUE;
2211 /* OPER command. Used to obtain server operator privileges. */
2213 SILC_FSM_STATE(silc_client_command_oper)
2215 SilcClientCommandContext cmd = fsm_context;
2216 SilcClientConnection conn = cmd->conn;
2217 SilcClientCommandOper oper;
2219 if (cmd->argc < 2) {
2220 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2221 "Usage: /OPER <username> [-pubkey]");
2222 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2223 return SILC_FSM_FINISH;
2226 /* Get passphrase */
2227 if (cmd->argc < 3) {
2228 oper = silc_calloc(1, sizeof(*oper));
2230 return SILC_FSM_FINISH;
2231 cmd->context = oper;
2232 SILC_FSM_CALL(conn->client->internal->
2233 ops->ask_passphrase(conn->client, conn,
2234 silc_client_command_oper_cb, cmd));
2237 silc_fsm_next(fsm, silc_client_command_oper_send);
2238 return SILC_FSM_CONTINUE;
2241 /* SILCOPER command. Used to obtain router operator privileges. */
2243 SILC_FSM_STATE(silc_client_command_silcoper)
2245 SilcClientCommandContext cmd = fsm_context;
2246 SilcClientConnection conn = cmd->conn;
2247 SilcClientCommandOper oper;
2249 if (cmd->argc < 2) {
2250 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2251 "Usage: /SILCOPER <username> [-pubkey]");
2252 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2253 return SILC_FSM_FINISH;
2256 /* Get passphrase */
2257 if (cmd->argc < 3) {
2258 oper = silc_calloc(1, sizeof(*oper));
2260 return SILC_FSM_FINISH;
2261 cmd->context = oper;
2262 SILC_FSM_CALL(conn->client->internal->
2263 ops->ask_passphrase(conn->client, conn,
2264 silc_client_command_oper_cb, cmd));
2267 silc_fsm_next(fsm, silc_client_command_oper_send);
2268 return SILC_FSM_CONTINUE;
2271 /*********************************** BAN ************************************/
2273 /* Command BAN. This is used to manage the ban list of the channel. */
2275 SILC_FSM_STATE(silc_client_command_ban)
2277 SilcClientCommandContext cmd = fsm_context;
2278 SilcClientConnection conn = cmd->conn;
2279 SilcClient client = conn->client;
2280 SilcChannelEntry channel;
2281 SilcBuffer chidp, args = NULL;
2282 char *name, *ban = NULL;
2283 unsigned char action[1];
2284 SilcPublicKey pubkey = NULL;
2286 if (cmd->argc < 2) {
2287 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2288 "Usage: /BAN <channel> "
2289 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
2290 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2294 if (cmd->argv[1][0] == '*') {
2295 if (!conn->current_channel) {
2296 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2300 channel = conn->current_channel;
2301 silc_client_ref_channel(client, conn, channel);
2303 name = cmd->argv[1];
2305 channel = silc_client_get_channel(conn->client, conn, name);
2307 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2312 if (cmd->argc == 3) {
2313 if (cmd->argv[2][0] == '+')
2318 /* Check if it is public key file to be added to invite list */
2319 silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey);
2326 args = silc_buffer_alloc_size(2);
2327 silc_buffer_format(args,
2328 SILC_STR_UI_SHORT(1),
2331 chidp = silc_public_key_payload_encode(pubkey);
2332 args = silc_argument_payload_encode_one(args,
2333 silc_buffer_datalen(chidp), 2);
2334 silc_buffer_free(chidp);
2335 silc_pkcs_public_key_free(pubkey);
2337 args = silc_argument_payload_encode_one(args, ban, strlen(ban), 1);
2341 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
2343 /* Send the command */
2344 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
2345 1, silc_buffer_datalen(chidp),
2346 2, args ? action : NULL, args ? 1 : 0,
2347 3, silc_buffer_datalen(args));
2349 silc_buffer_free(chidp);
2350 silc_buffer_free(args);
2351 silc_client_unref_channel(client, conn, channel);
2353 /* Notify application */
2354 COMMAND(SILC_STATUS_OK);
2356 /** Wait for command reply */
2357 silc_fsm_next(fsm, silc_client_command_reply_wait);
2358 return SILC_FSM_CONTINUE;
2361 return SILC_FSM_FINISH;
2364 /********************************* DETACH ***********************************/
2366 /* Command DETACH. This is used to detach from the server */
2368 SILC_FSM_STATE(silc_client_command_detach)
2370 SilcClientCommandContext cmd = fsm_context;
2371 SilcClientConnection conn = cmd->conn;
2373 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
2375 /* Notify application */
2376 COMMAND(SILC_STATUS_OK);
2378 /** Wait for command reply */
2379 silc_fsm_next(fsm, silc_client_command_reply_wait);
2380 return SILC_FSM_CONTINUE;
2383 /********************************** WATCH ***********************************/
2385 /* Command WATCH. */
2387 SILC_FSM_STATE(silc_client_command_watch)
2389 SilcClientCommandContext cmd = fsm_context;
2390 SilcClientConnection conn = cmd->conn;
2391 SilcBuffer args = NULL;
2393 const char *pubkey = NULL;
2394 SilcBool pubkey_add = TRUE;
2396 if (cmd->argc < 3) {
2397 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2401 if (!strcasecmp(cmd->argv[1], "-add")) {
2403 } else if (!strcasecmp(cmd->argv[1], "-del")) {
2405 } else if (!strcasecmp(cmd->argv[1], "-pubkey") && cmd->argc >= 3) {
2407 pubkey = cmd->argv[2] + 1;
2408 if (cmd->argv[2][0] == '-')
2411 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2419 if (!silc_pkcs_load_public_key(pubkey, &pk)) {
2420 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2421 "Could not load public key %s, check the filename", pubkey);
2422 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2426 args = silc_buffer_alloc_size(2);
2427 silc_buffer_format(args,
2428 SILC_STR_UI_SHORT(1),
2430 buffer = silc_public_key_payload_encode(pk);
2431 args = silc_argument_payload_encode_one(args, silc_buffer_datalen(buffer),
2432 pubkey_add ? 0x00 : 0x01);
2433 silc_buffer_free(buffer);
2434 silc_pkcs_public_key_free(pk);
2437 /* Send the commmand */
2438 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
2439 1, silc_buffer_datalen(conn->internal->
2441 type, pubkey ? args->data : cmd->argv[2],
2442 pubkey ? silc_buffer_len(args) :
2445 silc_buffer_free(args);
2447 /* Notify application */
2448 COMMAND(SILC_STATUS_OK);
2450 /** Wait for command reply */
2451 silc_fsm_next(fsm, silc_client_command_reply_wait);
2452 return SILC_FSM_CONTINUE;
2455 return SILC_FSM_FINISH;
2458 /********************************** LEAVE ***********************************/
2460 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2462 SILC_FSM_STATE(silc_client_command_leave)
2464 SilcClientCommandContext cmd = fsm_context;
2465 SilcClientConnection conn = cmd->conn;
2466 SilcClient client = conn->client;
2467 SilcChannelEntry channel;
2471 if (cmd->argc != 2) {
2472 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2473 "Usage: /LEAVE <channel>");
2474 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2478 if (cmd->argv[1][0] == '*') {
2479 if (!conn->current_channel) {
2480 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2483 name = conn->current_channel->channel_name;
2485 name = cmd->argv[1];
2488 /* Get the channel entry */
2489 channel = silc_client_get_channel(conn->client, conn, name);
2491 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2495 idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
2497 /* Send LEAVE command to the server */
2498 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
2499 1, silc_buffer_datalen(idp));
2501 silc_buffer_free(idp);
2503 /* Notify application */
2504 COMMAND(SILC_STATUS_OK);
2506 if (conn->current_channel == channel)
2507 conn->current_channel = NULL;
2509 silc_client_unref_channel(client, conn, channel);
2511 /** Wait for command reply */
2512 silc_fsm_next(fsm, silc_client_command_reply_wait);
2513 return SILC_FSM_CONTINUE;
2516 return SILC_FSM_FINISH;
2519 /********************************** USERS ***********************************/
2521 /* Command USERS. Requests the USERS of the clients joined on requested
2524 SILC_FSM_STATE(silc_client_command_users)
2526 SilcClientCommandContext cmd = fsm_context;
2527 SilcClientConnection conn = cmd->conn;
2530 if (cmd->argc != 2) {
2531 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2532 "Usage: /USERS <channel>");
2533 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2537 if (cmd->argv[1][0] == '*') {
2538 if (!conn->current_channel) {
2539 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2542 name = conn->current_channel->channel_name;
2544 name = cmd->argv[1];
2547 /* Send USERS command to the server */
2548 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
2549 2, name, strlen(name));
2551 /* Notify application */
2552 COMMAND(SILC_STATUS_OK);
2554 /** Wait for command reply */
2555 silc_fsm_next(fsm, silc_client_command_reply_wait);
2556 return SILC_FSM_CONTINUE;
2559 return SILC_FSM_FINISH;
2562 /********************************* GETKEY ***********************************/
2564 /* Command GETKEY. Used to fetch remote client's public key. */
2566 SILC_FSM_STATE(silc_client_command_getkey)
2568 SilcClientCommandContext cmd = fsm_context;
2569 SilcClientConnection conn = cmd->conn;
2570 SilcClient client = conn->client;
2571 SilcClientEntry client_entry;
2572 SilcServerEntry server_entry;
2574 char *nickname = NULL;
2577 if (cmd->argc < 2) {
2578 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2579 "Usage: /GETKEY <nickname or server name>");
2580 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2581 return SILC_FSM_FINISH;
2584 /* Parse the typed nickname. */
2585 if (!silc_client_nickname_parse(client, conn, cmd->argv[1], &nickname)) {
2586 COMMAND_ERROR(SILC_STATUS_ERR_RESOURCE_LIMIT);
2587 return SILC_FSM_FINISH;
2590 /* Find client entry */
2591 clients = silc_client_get_clients_local(client, conn, nickname,
2594 /* Check whether user requested server */
2595 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2596 if (!server_entry) {
2597 if (cmd->resolved) {
2598 /* Resolving didn't find anything. We should never get here as
2599 errors are handled in the resolving callback. */
2600 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2601 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_SERVER);
2602 return SILC_FSM_FINISH;
2605 /* No client or server exist with this name, query for both. */
2606 cmd->resolved = TRUE;
2607 SILC_FSM_CALL(silc_client_command_send(client, conn,
2608 SILC_COMMAND_IDENTIFY,
2609 silc_client_command_continue,
2612 strlen(cmd->argv[1]),
2614 strlen(cmd->argv[1])));
2617 idp = silc_id_payload_encode(&server_entry->id, SILC_ID_SERVER);
2618 silc_client_unref_server(client, conn, server_entry);
2620 client_entry = silc_dlist_get(clients);
2621 idp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT);
2622 silc_client_list_free(client, conn, clients);
2625 /* Send the commmand */
2626 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
2627 1, silc_buffer_datalen(idp));
2629 silc_buffer_free(idp);
2630 silc_free(nickname);
2632 /* Notify application */
2633 COMMAND(SILC_STATUS_OK);
2635 /** Wait for command reply */
2636 silc_fsm_next(fsm, silc_client_command_reply_wait);
2637 return SILC_FSM_CONTINUE;
2640 /********************************* SERVICE **********************************/
2642 /* Command SERVICE. Negotiates service agreement with server. */
2643 /* XXX incomplete */
2645 SILC_FSM_STATE(silc_client_command_service)
2647 SilcClientCommandContext cmd = fsm_context;
2649 SilcClientConnection conn = cmd->conn;
2653 if (cmd->argc < 2) {
2654 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2655 "Usage: /SERVICE [<service name>] [-pubkey]");
2656 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2657 return SILC_FSM_FINISH;
2660 name = cmd->argv[1];
2662 /* Send SERVICE command to the server */
2663 buffer = silc_command_payload_encode_va(SILC_COMMAND_SERVICE,
2664 ++conn->cmd_ident, 1,
2665 1, name, strlen(name));
2666 silc_client_packet_send(conn->client, conn->sock, SILC_PACKET_COMMAND,
2667 NULL, 0, NULL, NULL, buffer->data,
2669 silc_buffer_free(buffer);
2672 /* Notify application */
2673 COMMAND(SILC_STATUS_OK);
2675 /** Wait for command reply */
2676 silc_fsm_next(fsm, silc_client_command_reply_wait);
2677 return SILC_FSM_CONTINUE;
2680 /* Register all default commands provided by the client library for the
2683 void silc_client_commands_register(SilcClient client)
2685 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2688 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 5);
2689 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2690 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2691 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2692 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2693 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2694 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2695 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2696 SILC_CLIENT_CMD(kill, KILL, "KILL", 4);
2697 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2698 SILC_CLIENT_CMD(stats, STATS, "STATS", 0);
2699 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2700 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2701 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2702 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2703 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2704 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 6);
2705 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 9);
2706 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2707 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2708 SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2709 SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
2710 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2711 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2712 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2713 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2714 SILC_CLIENT_CMD(service, SERVICE, "SERVICE", 10);
2717 /* Unregister all commands. */
2719 void silc_client_commands_unregister(SilcClient client)
2721 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2722 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2723 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2724 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2725 SILC_CLIENT_CMDU(list, LIST, "LIST");
2726 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2727 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2728 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2729 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2730 SILC_CLIENT_CMDU(info, INFO, "INFO");
2731 SILC_CLIENT_CMDU(stats, STATS, "STATS");
2732 SILC_CLIENT_CMDU(ping, PING, "PING");
2733 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2734 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2735 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2736 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2737 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2738 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2739 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2740 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2741 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2742 SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2743 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2744 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2745 SILC_CLIENT_CMDU(users, USERS, "USERS");
2746 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2747 SILC_CLIENT_CMDU(service, SERVICE, "SERVICE");
2750 /****************** Client Side Incoming Command Handling *******************/
2752 /* Reply to WHOIS command from server */
2754 static void silc_client_command_process_whois(SilcClient client,
2755 SilcClientConnection conn,
2756 SilcCommandPayload payload,
2757 SilcArgumentPayload args)
2763 SilcBuffer buffer, packet;
2765 SILC_LOG_DEBUG(("Received WHOIS command"));
2767 /* Try to take the Requested Attributes */
2768 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
2772 attrs = silc_attribute_payload_parse(tmp, tmp_len);
2776 /* Process requested attributes */
2777 buffer = silc_client_attributes_process(client, conn, attrs);
2779 silc_attribute_payload_list_free(attrs);
2783 /* Send the attributes back */
2785 silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
2787 silc_command_get_ident(payload),
2788 1, 11, buffer->data, buffer->len);
2789 silc_client_packet_send(client, sock, SILC_PACKET_COMMAND_REPLY,
2790 NULL, 0, NULL, NULL, packet->data,
2792 silc_buffer_free(packet);
2793 silc_buffer_free(buffer);
2797 /* Client is able to receive some command packets even though they are
2798 special case. Server may send WHOIS command to the client to retrieve
2799 Requested Attributes information for WHOIS query the server is
2800 processing. This function currently handles only the WHOIS command,
2801 but if in the future more commands may arrive then this can be made
2802 to support other commands too. */
2804 SILC_FSM_STATE(silc_client_command)
2806 SilcClientConnection conn = fsm_context;
2807 SilcClient client = conn->client;
2808 SilcPacket packet = state_context;
2809 SilcCommandPayload payload;
2810 SilcCommand command;
2811 SilcArgumentPayload args;
2813 /* Get command payload from packet */
2814 payload = silc_command_payload_parse(packet->buffer.data,
2815 silc_buffer_len(&packet->buffer));
2817 SILC_LOG_DEBUG(("Bad command packet"));
2818 return SILC_FSM_FINISH;
2822 args = silc_command_get_args(payload);
2824 /* Get the command */
2825 command = silc_command_get(payload);
2828 case SILC_COMMAND_WHOIS:
2829 /* Ignore everything if requested by application */
2830 if (conn->internal->params.ignore_requested_attributes)
2833 silc_client_command_process_whois(client, conn, payload, args);
2840 silc_command_payload_free(payload);
2841 return SILC_FSM_FINISH;