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 ************************************/
1124 /* Command KILL. Router operator can use this command to remove an client
1125 fromthe SILC Network. */
1127 SILC_FSM_STATE(silc_client_command_kill)
1129 SilcClientCommandContext cmd = fsm_context;
1130 SilcClientConnection conn = cmd->conn;
1131 SilcClient client = conn->client;
1132 SilcBuffer idp, auth = NULL;
1133 SilcClientEntry target;
1135 char *nickname = NULL, *comment = NULL;
1137 if (cmd->argc < 2) {
1138 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1139 "Usage: /KILL <nickname> [<comment>] [-pubkey]");
1140 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1141 return SILC_FSM_FINISH;
1144 /* Parse the typed nickname. */
1145 if (!silc_client_nickname_parse(client, conn, cmd->argv[1], &nickname))
1146 return SILC_FSM_FINISH;
1148 /* Get the target client */
1149 clients = silc_client_get_clients_local(client, conn, nickname,
1152 /* Resolve client information */
1153 SILC_FSM_CALL(silc_client_get_clients(client, conn, nickname,
1155 silc_client_command_resolve_continue,
1158 target = silc_dlist_get(clients);
1160 if (cmd->argc >= 3) {
1161 if (strcasecmp(cmd->argv[2], "-pubkey"))
1162 comment = cmd->argv[2];
1164 if (!strcasecmp(cmd->argv[2], "-pubkey") ||
1165 (cmd->argc >= 4 && !strcasecmp(cmd->argv[3], "-pubkey"))) {
1166 /* Encode the public key authentication payload */
1167 auth = silc_auth_public_key_auth_generate(conn->public_key,
1170 conn->internal->sha1hash,
1171 &target->id, SILC_ID_CLIENT);
1175 /* Send the KILL command to the server */
1176 idp = silc_id_payload_encode(&target->id, SILC_ID_CLIENT);
1177 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
1178 1, silc_buffer_datalen(idp),
1179 2, comment, comment ? strlen(comment) : 0,
1180 3, silc_buffer_datalen(auth));
1181 silc_buffer_free(idp);
1182 silc_buffer_free(auth);
1183 silc_free(nickname);
1184 silc_client_list_free(client, conn, clients);
1186 /* Notify application */
1187 COMMAND(SILC_STATUS_OK);
1189 /** Wait for command reply */
1190 silc_fsm_next(fsm, silc_client_command_reply_wait);
1191 return SILC_FSM_CONTINUE;
1194 /********************************** INFO ************************************/
1196 /* Command INFO. Request information about specific server. If specific
1197 server is not provided the current server is used. */
1199 SILC_FSM_STATE(silc_client_command_info)
1201 SilcClientCommandContext cmd = fsm_context;
1202 SilcClientConnection conn = cmd->conn;
1204 /* Send the command */
1206 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1207 1, cmd->argv[1], cmd->argv_lens[1]);
1209 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
1211 /* Notify application */
1212 COMMAND(SILC_STATUS_OK);
1214 /** Wait for command reply */
1215 silc_fsm_next(fsm, silc_client_command_reply_wait);
1216 return SILC_FSM_CONTINUE;
1219 /********************************** STATS ***********************************/
1221 /* Command STATS. Shows server and network statistics. */
1223 SILC_FSM_STATE(silc_client_command_stats)
1225 SilcClientCommandContext cmd = fsm_context;
1226 SilcClientConnection conn = cmd->conn;
1228 /* Send the command */
1229 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1230 1, silc_buffer_datalen(conn->internal->
1233 /* Notify application */
1234 COMMAND(SILC_STATUS_OK);
1236 /** Wait for command reply */
1237 silc_fsm_next(fsm, silc_client_command_reply_wait);
1238 return SILC_FSM_CONTINUE;
1241 /********************************** PING ************************************/
1243 /* Command PING. Sends ping to server. */
1245 SILC_FSM_STATE(silc_client_command_ping)
1247 SilcClientCommandContext cmd = fsm_context;
1248 SilcClientConnection conn = cmd->conn;
1250 if (cmd->argc < 2) {
1251 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1252 return SILC_FSM_FINISH;
1255 /* Send the command */
1256 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1257 1, silc_buffer_datalen(conn->internal->
1260 /* Save ping time */
1261 cmd->context = SILC_64_TO_PTR(silc_time());
1263 /* Notify application */
1264 COMMAND(SILC_STATUS_OK);
1266 /** Wait for command reply */
1267 silc_fsm_next(fsm, silc_client_command_reply_wait);
1268 return SILC_FSM_CONTINUE;
1271 /********************************** JOIN ************************************/
1273 /* Command JOIN. Joins to a channel. */
1275 SILC_FSM_STATE(silc_client_command_join)
1277 SilcClientCommandContext cmd = fsm_context;
1278 SilcClientConnection conn = cmd->conn;
1279 SilcClient client = conn->client;
1280 SilcChannelEntry channel = NULL;
1281 SilcBuffer auth = NULL, cauth = NULL;
1282 char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
1283 int i, passphrase_len = 0;
1285 if (cmd->argc < 2) {
1286 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1290 /* See if we have joined to the requested channel already */
1291 channel = silc_client_get_channel(conn->client, conn, cmd->argv[1]);
1292 if (channel && silc_client_on_channel(channel, conn->local_entry))
1295 if (cmd->argv_lens[1] > 256)
1296 cmd->argv_lens[1] = 256;
1298 name = cmd->argv[1];
1300 for (i = 2; i < cmd->argc; i++) {
1301 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
1302 cipher = cmd->argv[++i];
1303 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
1304 hmac = cmd->argv[++i];
1305 } else if (!strcasecmp(cmd->argv[i], "-founder")) {
1306 auth = silc_auth_public_key_auth_generate(conn->public_key,
1309 conn->internal->sha1hash,
1312 } else if (!strcasecmp(cmd->argv[i], "-auth")) {
1313 SilcPublicKey pubkey = conn->public_key;
1314 SilcPrivateKey privkey = conn->private_key;
1315 unsigned char *pk, pkhash[SILC_HASH_MAXLEN], *pubdata;
1318 if (cmd->argc >= i + 3) {
1320 if (cmd->argc >= i + 4) {
1321 pass = cmd->argv[i + 3];
1324 if (!silc_load_key_pair(cmd->argv[i + 1], cmd->argv[i + 2], pass,
1325 &pubkey, &privkey)) {
1326 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1327 "Could not load key pair, check your arguments");
1328 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1334 pk = silc_pkcs_public_key_encode(pubkey, &pk_len);
1335 silc_hash_make(conn->internal->sha1hash, pk, pk_len, pkhash);
1337 pubdata = silc_rng_get_rn_data(conn->client->rng, 128);
1338 memcpy(pubdata, pkhash, 20);
1339 cauth = silc_auth_public_key_auth_generate_wpub(pubkey, privkey,
1341 conn->internal->sha1hash,
1344 memset(pubdata, 0, 128);
1347 /* Passphrases must be UTF-8 encoded, so encode if it is not */
1348 if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
1349 passphrase_len = silc_utf8_encoded_len(cmd->argv[i],
1350 cmd->argv_lens[i], 0);
1351 pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
1352 passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
1353 0, pu8, passphrase_len);
1356 passphrase = strdup(cmd->argv[i]);
1357 passphrase_len = cmd->argv_lens[i];
1362 /* Send JOIN command to the server */
1363 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 7,
1364 1, name, strlen(name),
1365 2, silc_buffer_datalen(conn->internal->
1367 3, passphrase, passphrase_len,
1368 4, cipher, cipher ? strlen(cipher) : 0,
1369 5, hmac, hmac ? strlen(hmac) : 0,
1370 6, silc_buffer_datalen(auth),
1371 7, silc_buffer_datalen(cauth));
1373 silc_buffer_free(auth);
1374 silc_buffer_free(cauth);
1376 memset(passphrase, 0, strlen(passphrase));
1377 silc_free(passphrase);
1378 silc_client_unref_channel(client, conn, channel);
1380 /* Notify application */
1381 COMMAND(SILC_STATUS_OK);
1383 /** Wait for command reply */
1384 silc_fsm_next(fsm, silc_client_command_reply_wait);
1385 return SILC_FSM_CONTINUE;
1388 silc_client_unref_channel(client, conn, channel);
1389 return SILC_FSM_FINISH;
1392 /********************************** MOTD ************************************/
1394 /* MOTD command. Requests motd from server. */
1396 SILC_FSM_STATE(silc_client_command_motd)
1398 SilcClientCommandContext cmd = fsm_context;
1399 SilcClientConnection conn = cmd->conn;
1401 if (cmd->argc < 1 || cmd->argc > 2) {
1402 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1403 "Usage: /MOTD [<server>]");
1404 COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
1405 SILC_STATUS_ERR_TOO_MANY_PARAMS));
1406 return SILC_FSM_FINISH;
1409 /* Send the command */
1411 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1412 1, conn->remote_host,
1413 strlen(conn->remote_host));
1415 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1416 1, cmd->argv[1], cmd->argv_lens[1]);
1418 /* Notify application */
1419 COMMAND(SILC_STATUS_OK);
1421 /** Wait for command reply */
1422 silc_fsm_next(fsm, silc_client_command_reply_wait);
1423 return SILC_FSM_CONTINUE;
1426 /********************************** UMODE ***********************************/
1428 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1429 modes as client cannot set itself server/router operator privileges. */
1431 SILC_FSM_STATE(silc_client_command_umode)
1433 SilcClientCommandContext cmd = fsm_context;
1434 SilcClientConnection conn = cmd->conn;
1435 unsigned char *cp, modebuf[4];
1436 SilcUInt32 mode, add, len;
1439 if (cmd->argc < 2) {
1440 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1441 "Usage: /UMODE +|-<modes>");
1442 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1443 return SILC_FSM_FINISH;
1446 mode = conn->local_entry->mode;
1448 /* Are we adding or removing mode */
1449 if (cmd->argv[1][0] == '-')
1455 cp = cmd->argv[1] + 1;
1457 for (i = 0; i < len; i++) {
1462 mode |= SILC_UMODE_SERVER_OPERATOR;
1463 mode |= SILC_UMODE_ROUTER_OPERATOR;
1464 mode |= SILC_UMODE_GONE;
1465 mode |= SILC_UMODE_INDISPOSED;
1466 mode |= SILC_UMODE_BUSY;
1467 mode |= SILC_UMODE_PAGE;
1468 mode |= SILC_UMODE_HYPER;
1469 mode |= SILC_UMODE_ROBOT;
1470 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1471 mode |= SILC_UMODE_REJECT_WATCHING;
1473 mode = SILC_UMODE_NONE;
1478 mode |= SILC_UMODE_SERVER_OPERATOR;
1480 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1484 mode |= SILC_UMODE_ROUTER_OPERATOR;
1486 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1490 mode |= SILC_UMODE_GONE;
1492 mode &= ~SILC_UMODE_GONE;
1496 mode |= SILC_UMODE_INDISPOSED;
1498 mode &= ~SILC_UMODE_INDISPOSED;
1502 mode |= SILC_UMODE_BUSY;
1504 mode &= ~SILC_UMODE_BUSY;
1508 mode |= SILC_UMODE_PAGE;
1510 mode &= ~SILC_UMODE_PAGE;
1514 mode |= SILC_UMODE_HYPER;
1516 mode &= ~SILC_UMODE_HYPER;
1520 mode |= SILC_UMODE_ROBOT;
1522 mode &= ~SILC_UMODE_ROBOT;
1526 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1528 mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
1532 mode |= SILC_UMODE_REJECT_WATCHING;
1534 mode &= ~SILC_UMODE_REJECT_WATCHING;
1538 mode |= SILC_UMODE_BLOCK_INVITE;
1540 mode &= ~SILC_UMODE_BLOCK_INVITE;
1543 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1544 return SILC_FSM_FINISH;
1549 SILC_PUT32_MSB(mode, modebuf);
1551 /* Send the command */
1552 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
1553 1, silc_buffer_datalen(conn->internal->
1555 2, modebuf, sizeof(modebuf));
1557 /* Notify application */
1558 COMMAND(SILC_STATUS_OK);
1560 /** Wait for command reply */
1561 silc_fsm_next(fsm, silc_client_command_reply_wait);
1562 return SILC_FSM_CONTINUE;
1565 /********************************** CMODE ***********************************/
1567 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1568 can be set several at once. Those modes that require argument must be set
1569 separately (unless set with modes that does not require arguments). */
1571 SILC_FSM_STATE(silc_client_command_cmode)
1573 SilcClientCommandContext cmd = fsm_context;
1574 SilcClientConnection conn = cmd->conn;
1575 SilcClient client = conn->client;
1576 SilcChannelEntry channel = NULL;
1577 SilcBuffer chidp, auth = NULL, pk = NULL;
1578 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1579 SilcUInt32 mode, add, type, len, arg_len = 0;
1582 if (cmd->argc < 3) {
1583 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1584 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1585 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1589 if (cmd->argv[1][0] == '*') {
1590 if (!conn->current_channel) {
1591 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1595 channel = conn->current_channel;
1596 silc_client_ref_channel(client, conn, channel);
1598 name = cmd->argv[1];
1600 channel = silc_client_get_channel(conn->client, conn, name);
1602 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1607 mode = channel->mode;
1609 /* Are we adding or removing mode */
1610 if (cmd->argv[2][0] == '-')
1615 /* Argument type to be sent to server */
1619 cp = cmd->argv[2] + 1;
1621 for (i = 0; i < len; i++) {
1625 mode |= SILC_CHANNEL_MODE_PRIVATE;
1627 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1631 mode |= SILC_CHANNEL_MODE_SECRET;
1633 mode &= ~SILC_CHANNEL_MODE_SECRET;
1637 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1639 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1643 mode |= SILC_CHANNEL_MODE_INVITE;
1645 mode &= ~SILC_CHANNEL_MODE_INVITE;
1649 mode |= SILC_CHANNEL_MODE_TOPIC;
1651 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1655 mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1657 mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1661 mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1663 mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1668 mode |= SILC_CHANNEL_MODE_ULIMIT;
1670 if (cmd->argc < 4) {
1671 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1672 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1673 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1676 ll = atoi(cmd->argv[3]);
1677 SILC_PUT32_MSB(ll, tmp);
1681 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1686 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1688 if (cmd->argc < 4) {
1689 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1690 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1691 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1695 arg_len = cmd->argv_lens[3];
1697 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1702 mode |= SILC_CHANNEL_MODE_CIPHER;
1704 if (cmd->argc < 4) {
1705 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1706 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1707 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1711 arg_len = cmd->argv_lens[3];
1713 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1718 mode |= SILC_CHANNEL_MODE_HMAC;
1720 if (cmd->argc < 4) {
1721 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1722 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1723 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1727 arg_len = cmd->argv_lens[3];
1729 mode &= ~SILC_CHANNEL_MODE_HMAC;
1734 SilcPublicKey pubkey = conn->public_key;
1735 SilcPrivateKey privkey = conn->private_key;
1737 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1740 if (cmd->argc >= 5) {
1743 pass = cmd->argv[5];
1744 if (!silc_load_key_pair(cmd->argv[3], cmd->argv[4], pass,
1745 &pubkey, &privkey)) {
1746 SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1747 "Could not load key pair, check your arguments");
1748 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1753 pk = silc_public_key_payload_encode(pubkey);
1754 auth = silc_auth_public_key_auth_generate(pubkey, privkey,
1756 conn->internal->sha1hash,
1759 arg = silc_buffer_data(auth);
1760 arg_len = silc_buffer_len(auth);
1762 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1768 SilcBool chadd = FALSE;
1769 SilcPublicKey chpk = NULL;
1771 mode |= SILC_CHANNEL_MODE_CHANNEL_AUTH;
1774 if (cmd->argc == 3) {
1775 /* Send empty command to receive the public key list. */
1776 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
1777 silc_client_command_send_va(conn, cmd, SILC_COMMAND_CMODE,
1779 1, silc_buffer_datalen(chidp));
1780 silc_buffer_free(chidp);
1782 /* Notify application */
1783 COMMAND(SILC_STATUS_OK);
1787 if (cmd->argc >= 4) {
1788 auth = silc_buffer_alloc_size(2);
1789 silc_buffer_format(auth,
1790 SILC_STR_UI_SHORT(cmd->argc - 3),
1794 for (k = 3; k < cmd->argc; k++) {
1795 if (cmd->argv[k][0] == '+')
1797 if (!silc_pkcs_load_public_key(cmd->argv[k] + 1, &chpk)) {
1798 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1799 "Could not load public key %s, check the filename",
1801 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1802 silc_buffer_free(auth);
1807 pk = silc_public_key_payload_encode(chpk);
1808 auth = silc_argument_payload_encode_one(auth,
1809 silc_buffer_datalen(pk),
1810 chadd ? 0x00 : 0x01);
1811 silc_pkcs_public_key_free(chpk);
1812 silc_buffer_free(pk);
1817 arg = silc_buffer_data(auth);
1818 arg_len = silc_buffer_len(auth);
1820 mode &= ~SILC_CHANNEL_MODE_CHANNEL_AUTH;
1824 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1830 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
1831 SILC_PUT32_MSB(mode, modebuf);
1833 /* Send the command. We support sending only one mode at once that
1834 requires an argument. */
1836 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 4,
1837 1, silc_buffer_datalen(chidp),
1838 2, modebuf, sizeof(modebuf),
1840 8, silc_buffer_datalen(pk));
1842 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
1843 1, silc_buffer_datalen(chidp),
1844 2, modebuf, sizeof(modebuf));
1847 silc_buffer_free(chidp);
1848 silc_buffer_free(auth);
1849 silc_buffer_free(pk);
1850 silc_client_unref_channel(client, conn, channel);
1852 /* Notify application */
1853 COMMAND(SILC_STATUS_OK);
1855 /** Wait for command reply */
1856 silc_fsm_next(fsm, silc_client_command_reply_wait);
1857 return SILC_FSM_CONTINUE;
1860 silc_client_unref_channel(client, conn, channel);
1861 return SILC_FSM_FINISH;
1864 /********************************* CUMODE ***********************************/
1866 /* CUMODE command. Changes client's mode on a channel. */
1868 SILC_FSM_STATE(silc_client_command_cumode)
1870 SilcClientCommandContext cmd = fsm_context;
1871 SilcClientConnection conn = cmd->conn;
1872 SilcClient client = conn->client;
1873 SilcChannelEntry channel = NULL;
1874 SilcChannelUser chu;
1875 SilcClientEntry client_entry;
1876 SilcBuffer clidp, chidp, auth = NULL;
1877 SilcDList clients = NULL;
1878 unsigned char *name, *cp, modebuf[4];
1879 SilcUInt32 mode = 0, add, len;
1880 char *nickname = NULL;
1883 if (cmd->argc < 4) {
1884 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1885 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1886 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1890 if (cmd->argv[1][0] == '*') {
1891 if (!conn->current_channel) {
1892 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1896 channel = conn->current_channel;
1897 silc_client_ref_channel(client, conn, channel);
1899 name = cmd->argv[1];
1901 channel = silc_client_get_channel(conn->client, conn, name);
1903 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1908 /* Parse the typed nickname. */
1909 silc_client_nickname_parse(client, conn, cmd->argv[3], &nickname);
1911 /* Find client entry */
1912 clients = silc_client_get_clients_local(client, conn, nickname,
1915 /* Resolve client information */
1916 SILC_FSM_CALL(silc_client_get_clients(client, conn, nickname, cmd->argv[3],
1917 silc_client_command_resolve_continue,
1920 client_entry = silc_dlist_get(clients);
1922 /* Get the current mode */
1923 chu = silc_client_on_channel(channel, client_entry);
1927 /* Are we adding or removing mode */
1928 if (cmd->argv[2][0] == '-')
1934 cp = cmd->argv[2] + 1;
1936 for (i = 0; i < len; i++) {
1940 mode |= SILC_CHANNEL_UMODE_CHANFO;
1941 mode |= SILC_CHANNEL_UMODE_CHANOP;
1942 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1943 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1944 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1946 mode = SILC_CHANNEL_UMODE_NONE;
1951 SilcPublicKey pubkey = conn->public_key;
1952 SilcPrivateKey privkey = conn->private_key;
1954 if (cmd->argc >= 6) {
1957 pass = cmd->argv[6];
1958 if (!silc_load_key_pair(cmd->argv[4], cmd->argv[5], pass,
1959 &pubkey, &privkey)) {
1960 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1961 "Could not load key pair, check your arguments");
1962 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1967 auth = silc_auth_public_key_auth_generate(pubkey, privkey,
1969 conn->internal->sha1hash,
1972 mode |= SILC_CHANNEL_UMODE_CHANFO;
1974 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1979 mode |= SILC_CHANNEL_UMODE_CHANOP;
1981 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1985 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1987 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1991 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1993 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1997 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1999 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
2003 mode |= SILC_CHANNEL_UMODE_QUIET;
2005 mode &= ~SILC_CHANNEL_UMODE_QUIET;
2008 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
2014 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
2015 SILC_PUT32_MSB(mode, modebuf);
2016 clidp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT);
2018 /* Send the command packet. We support sending only one mode at once
2019 that requires an argument. */
2020 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, auth ? 4 : 3,
2021 1, silc_buffer_datalen(chidp),
2023 3, silc_buffer_datalen(clidp),
2024 4, silc_buffer_datalen(auth));
2026 silc_buffer_free(chidp);
2027 silc_buffer_free(clidp);
2029 silc_buffer_free(auth);
2030 silc_free(nickname);
2031 silc_client_list_free(client, conn, clients);
2032 silc_client_unref_channel(client, conn, channel);
2034 /* Notify application */
2035 COMMAND(SILC_STATUS_OK);
2037 /** Wait for command reply */
2038 silc_fsm_next(fsm, silc_client_command_reply_wait);
2039 return SILC_FSM_CONTINUE;
2042 silc_client_unref_channel(client, conn, channel);
2043 silc_client_list_free(client, conn, clients);
2044 silc_free(nickname);
2045 return SILC_FSM_FINISH;
2048 /********************************** KICK ************************************/
2050 /* KICK command. Kicks a client out of channel. */
2052 SILC_FSM_STATE(silc_client_command_kick)
2054 SilcClientCommandContext cmd = fsm_context;
2055 SilcClientConnection conn = cmd->conn;
2056 SilcClient client = conn->client;
2057 SilcChannelEntry channel = NULL;
2058 SilcBuffer idp, idp2;
2059 SilcClientEntry target;
2060 SilcDList clients = NULL;
2062 char *nickname = NULL;
2064 if (cmd->argc < 3) {
2065 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2066 "Usage: /KICK <channel> <nickname> [<comment>]");
2067 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2071 if (cmd->argv[1][0] == '*') {
2072 if (!conn->current_channel) {
2073 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2076 name = conn->current_channel->channel_name;
2078 name = cmd->argv[1];
2081 if (!conn->current_channel) {
2082 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2086 /* Get the Channel ID of the channel */
2087 channel = silc_client_get_channel(conn->client, conn, name);
2089 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2093 /* Parse the typed nickname. */
2094 silc_client_nickname_parse(client, conn, cmd->argv[2], &nickname);
2096 /* Get the target client */
2097 clients = silc_client_get_clients_local(client, conn, nickname,
2100 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2101 "No such client: %s", cmd->argv[2]);
2102 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2105 target = silc_dlist_get(clients);
2107 /* Send KICK command to the server */
2108 idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
2109 idp2 = silc_id_payload_encode(&target->id, SILC_ID_CLIENT);
2111 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
2112 1, silc_buffer_datalen(idp),
2113 2, silc_buffer_datalen(idp2));
2115 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
2116 1, silc_buffer_datalen(idp),
2117 2, silc_buffer_datalen(idp2),
2118 3, cmd->argv[3], strlen(cmd->argv[3]));
2120 silc_buffer_free(idp);
2121 silc_buffer_free(idp2);
2122 silc_free(nickname);
2123 silc_client_list_free(client, conn, clients);
2124 silc_client_unref_channel(client, conn, channel);
2126 /* Notify application */
2127 COMMAND(SILC_STATUS_OK);
2129 /** Wait for command reply */
2130 silc_fsm_next(fsm, silc_client_command_reply_wait);
2131 return SILC_FSM_CONTINUE;
2134 silc_client_unref_channel(client, conn, channel);
2135 silc_free(nickname);
2136 return SILC_FSM_FINISH;
2139 /***************************** OPER & SILCOPER ******************************/
2142 unsigned char *passphrase;
2143 SilcUInt32 passphrase_len;
2144 } *SilcClientCommandOper;
2146 /* Ask passphrase callback */
2148 static void silc_client_command_oper_cb(unsigned char *data,
2149 SilcUInt32 data_len, void *context)
2151 SilcClientCommandContext cmd = context;
2152 SilcClientCommandOper oper = cmd->context;
2154 if (data && data_len)
2155 oper->passphrase = silc_memdup(data, data_len);
2156 oper->passphrase_len = data_len;
2159 SILC_FSM_CALL_CONTINUE(&cmd->thread);
2162 /* Send OPER/SILCOPER command */
2164 SILC_FSM_STATE(silc_client_command_oper_send)
2166 SilcClientCommandContext cmd = fsm_context;
2167 SilcClientConnection conn = cmd->conn;
2168 SilcClientCommandOper oper = cmd->context;
2171 if (!oper || !oper->passphrase) {
2172 /* Encode the public key authentication payload */
2173 auth = silc_auth_public_key_auth_generate(conn->public_key,
2176 conn->internal->hash,
2180 /* Encode the password authentication payload */
2181 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
2182 oper->passphrase, oper->passphrase_len);
2185 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
2186 1, cmd->argv[1], strlen(cmd->argv[1]),
2187 2, silc_buffer_datalen(auth));
2189 silc_buffer_clear(auth);
2190 silc_buffer_free(auth);
2192 silc_free(oper->passphrase);
2196 /* Notify application */
2197 COMMAND(SILC_STATUS_OK);
2199 /** Wait for command reply */
2200 silc_fsm_next(fsm, silc_client_command_reply_wait);
2201 return SILC_FSM_CONTINUE;
2204 /* OPER command. Used to obtain server operator privileges. */
2206 SILC_FSM_STATE(silc_client_command_oper)
2208 SilcClientCommandContext cmd = fsm_context;
2209 SilcClientConnection conn = cmd->conn;
2210 SilcClientCommandOper oper;
2212 if (cmd->argc < 2) {
2213 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2214 "Usage: /OPER <username> [-pubkey]");
2215 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2216 return SILC_FSM_FINISH;
2219 /* Get passphrase */
2220 if (cmd->argc < 3) {
2221 oper = silc_calloc(1, sizeof(*oper));
2223 return SILC_FSM_FINISH;
2224 cmd->context = oper;
2225 SILC_FSM_CALL(conn->client->internal->
2226 ops->ask_passphrase(conn->client, conn,
2227 silc_client_command_oper_cb, cmd));
2230 silc_fsm_next(fsm, silc_client_command_oper_send);
2231 return SILC_FSM_CONTINUE;
2234 /* SILCOPER command. Used to obtain router operator privileges. */
2236 SILC_FSM_STATE(silc_client_command_silcoper)
2238 SilcClientCommandContext cmd = fsm_context;
2239 SilcClientConnection conn = cmd->conn;
2240 SilcClientCommandOper oper;
2242 if (cmd->argc < 2) {
2243 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2244 "Usage: /SILCOPER <username> [-pubkey]");
2245 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2246 return SILC_FSM_FINISH;
2249 /* Get passphrase */
2250 if (cmd->argc < 3) {
2251 oper = silc_calloc(1, sizeof(*oper));
2253 return SILC_FSM_FINISH;
2254 cmd->context = oper;
2255 SILC_FSM_CALL(conn->client->internal->
2256 ops->ask_passphrase(conn->client, conn,
2257 silc_client_command_oper_cb, cmd));
2260 silc_fsm_next(fsm, silc_client_command_oper_send);
2261 return SILC_FSM_CONTINUE;
2264 /*********************************** BAN ************************************/
2266 /* Command BAN. This is used to manage the ban list of the channel. */
2268 SILC_FSM_STATE(silc_client_command_ban)
2270 SilcClientCommandContext cmd = fsm_context;
2271 SilcClientConnection conn = cmd->conn;
2272 SilcClient client = conn->client;
2273 SilcChannelEntry channel;
2274 SilcBuffer chidp, args = NULL;
2275 char *name, *ban = NULL;
2276 unsigned char action[1];
2277 SilcPublicKey pubkey = NULL;
2279 if (cmd->argc < 2) {
2280 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2281 "Usage: /BAN <channel> "
2282 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
2283 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2287 if (cmd->argv[1][0] == '*') {
2288 if (!conn->current_channel) {
2289 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2293 channel = conn->current_channel;
2294 silc_client_ref_channel(client, conn, channel);
2296 name = cmd->argv[1];
2298 channel = silc_client_get_channel(conn->client, conn, name);
2300 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2305 if (cmd->argc == 3) {
2306 if (cmd->argv[2][0] == '+')
2311 /* Check if it is public key file to be added to invite list */
2312 silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey);
2319 args = silc_buffer_alloc_size(2);
2320 silc_buffer_format(args,
2321 SILC_STR_UI_SHORT(1),
2324 chidp = silc_public_key_payload_encode(pubkey);
2325 args = silc_argument_payload_encode_one(args,
2326 silc_buffer_datalen(chidp), 2);
2327 silc_buffer_free(chidp);
2328 silc_pkcs_public_key_free(pubkey);
2330 args = silc_argument_payload_encode_one(args, ban, strlen(ban), 1);
2334 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
2336 /* Send the command */
2337 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
2338 1, silc_buffer_datalen(chidp),
2339 2, args ? action : NULL, args ? 1 : 0,
2340 3, silc_buffer_datalen(args));
2342 silc_buffer_free(chidp);
2343 silc_buffer_free(args);
2344 silc_client_unref_channel(client, conn, channel);
2346 /* Notify application */
2347 COMMAND(SILC_STATUS_OK);
2349 /** Wait for command reply */
2350 silc_fsm_next(fsm, silc_client_command_reply_wait);
2351 return SILC_FSM_CONTINUE;
2354 return SILC_FSM_FINISH;
2357 /********************************* DETACH ***********************************/
2359 /* Command DETACH. This is used to detach from the server */
2361 SILC_FSM_STATE(silc_client_command_detach)
2363 SilcClientCommandContext cmd = fsm_context;
2364 SilcClientConnection conn = cmd->conn;
2366 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
2368 /* Notify application */
2369 COMMAND(SILC_STATUS_OK);
2371 /** Wait for command reply */
2372 silc_fsm_next(fsm, silc_client_command_reply_wait);
2373 return SILC_FSM_CONTINUE;
2376 /********************************** WATCH ***********************************/
2378 /* Command WATCH. */
2380 SILC_FSM_STATE(silc_client_command_watch)
2382 SilcClientCommandContext cmd = fsm_context;
2383 SilcClientConnection conn = cmd->conn;
2384 SilcBuffer args = NULL;
2386 const char *pubkey = NULL;
2387 SilcBool pubkey_add = TRUE;
2389 if (cmd->argc < 3) {
2390 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2394 if (!strcasecmp(cmd->argv[1], "-add")) {
2396 } else if (!strcasecmp(cmd->argv[1], "-del")) {
2398 } else if (!strcasecmp(cmd->argv[1], "-pubkey") && cmd->argc >= 3) {
2400 pubkey = cmd->argv[2] + 1;
2401 if (cmd->argv[2][0] == '-')
2404 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2412 if (!silc_pkcs_load_public_key(pubkey, &pk)) {
2413 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2414 "Could not load public key %s, check the filename", pubkey);
2415 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2419 args = silc_buffer_alloc_size(2);
2420 silc_buffer_format(args,
2421 SILC_STR_UI_SHORT(1),
2423 buffer = silc_public_key_payload_encode(pk);
2424 args = silc_argument_payload_encode_one(args, silc_buffer_datalen(buffer),
2425 pubkey_add ? 0x00 : 0x01);
2426 silc_buffer_free(buffer);
2427 silc_pkcs_public_key_free(pk);
2430 /* Send the commmand */
2431 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
2432 1, silc_buffer_datalen(conn->internal->
2434 type, pubkey ? args->data : cmd->argv[2],
2435 pubkey ? silc_buffer_len(args) :
2438 silc_buffer_free(args);
2440 /* Notify application */
2441 COMMAND(SILC_STATUS_OK);
2443 /** Wait for command reply */
2444 silc_fsm_next(fsm, silc_client_command_reply_wait);
2445 return SILC_FSM_CONTINUE;
2448 return SILC_FSM_FINISH;
2451 /********************************** LEAVE ***********************************/
2453 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2455 SILC_FSM_STATE(silc_client_command_leave)
2457 SilcClientCommandContext cmd = fsm_context;
2458 SilcClientConnection conn = cmd->conn;
2459 SilcClient client = conn->client;
2460 SilcChannelEntry channel;
2464 if (cmd->argc != 2) {
2465 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2466 "Usage: /LEAVE <channel>");
2467 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2471 if (cmd->argv[1][0] == '*') {
2472 if (!conn->current_channel) {
2473 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2476 name = conn->current_channel->channel_name;
2478 name = cmd->argv[1];
2481 /* Get the channel entry */
2482 channel = silc_client_get_channel(conn->client, conn, name);
2484 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2488 idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
2490 /* Send LEAVE command to the server */
2491 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
2492 1, silc_buffer_datalen(idp));
2494 silc_buffer_free(idp);
2496 /* Notify application */
2497 COMMAND(SILC_STATUS_OK);
2499 if (conn->current_channel == channel)
2500 conn->current_channel = NULL;
2502 silc_client_unref_channel(client, conn, channel);
2504 /** Wait for command reply */
2505 silc_fsm_next(fsm, silc_client_command_reply_wait);
2506 return SILC_FSM_CONTINUE;
2509 return SILC_FSM_FINISH;
2512 /********************************** USERS ***********************************/
2514 /* Command USERS. Requests the USERS of the clients joined on requested
2517 SILC_FSM_STATE(silc_client_command_users)
2519 SilcClientCommandContext cmd = fsm_context;
2520 SilcClientConnection conn = cmd->conn;
2523 if (cmd->argc != 2) {
2524 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2525 "Usage: /USERS <channel>");
2526 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2530 if (cmd->argv[1][0] == '*') {
2531 if (!conn->current_channel) {
2532 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2535 name = conn->current_channel->channel_name;
2537 name = cmd->argv[1];
2540 /* Send USERS command to the server */
2541 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
2542 2, name, strlen(name));
2544 /* Notify application */
2545 COMMAND(SILC_STATUS_OK);
2547 /** Wait for command reply */
2548 silc_fsm_next(fsm, silc_client_command_reply_wait);
2549 return SILC_FSM_CONTINUE;
2552 return SILC_FSM_FINISH;
2555 /********************************* GETKEY ***********************************/
2557 /* Command GETKEY. Used to fetch remote client's public key. */
2559 SILC_FSM_STATE(silc_client_command_getkey)
2561 SilcClientCommandContext cmd = fsm_context;
2562 SilcClientConnection conn = cmd->conn;
2563 SilcClient client = conn->client;
2564 SilcClientEntry client_entry;
2565 SilcServerEntry server_entry;
2567 char *nickname = NULL;
2570 if (cmd->argc < 2) {
2571 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2572 "Usage: /GETKEY <nickname or server name>");
2573 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2574 return SILC_FSM_FINISH;
2577 /* Parse the typed nickname. */
2578 if (!silc_client_nickname_parse(client, conn, cmd->argv[1], &nickname)) {
2579 COMMAND_ERROR(SILC_STATUS_ERR_RESOURCE_LIMIT);
2580 return SILC_FSM_FINISH;
2583 /* Find client entry */
2584 clients = silc_client_get_clients_local(client, conn, nickname,
2587 /* Check whether user requested server */
2588 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2589 if (!server_entry) {
2590 if (cmd->resolved) {
2591 /* Resolving didn't find anything. We should never get here as
2592 errors are handled in the resolving callback. */
2593 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2594 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_SERVER);
2595 return SILC_FSM_FINISH;
2598 /* No client or server exist with this name, query for both. */
2599 cmd->resolved = TRUE;
2600 SILC_FSM_CALL(silc_client_command_send(client, conn,
2601 SILC_COMMAND_IDENTIFY,
2602 silc_client_command_continue,
2605 strlen(cmd->argv[1]),
2607 strlen(cmd->argv[1])));
2610 idp = silc_id_payload_encode(&server_entry->id, SILC_ID_SERVER);
2611 silc_client_unref_server(client, conn, server_entry);
2613 client_entry = silc_dlist_get(clients);
2614 idp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT);
2615 silc_client_list_free(client, conn, clients);
2618 /* Send the commmand */
2619 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
2620 1, silc_buffer_datalen(idp));
2622 silc_buffer_free(idp);
2623 silc_free(nickname);
2625 /* Notify application */
2626 COMMAND(SILC_STATUS_OK);
2628 /** Wait for command reply */
2629 silc_fsm_next(fsm, silc_client_command_reply_wait);
2630 return SILC_FSM_CONTINUE;
2633 /********************************* SERVICE **********************************/
2635 /* Command SERVICE. Negotiates service agreement with server. */
2636 /* XXX incomplete */
2638 SILC_FSM_STATE(silc_client_command_service)
2640 SilcClientCommandContext cmd = fsm_context;
2642 SilcClientConnection conn = cmd->conn;
2646 if (cmd->argc < 2) {
2647 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2648 "Usage: /SERVICE [<service name>] [-pubkey]");
2649 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2650 return SILC_FSM_FINISH;
2653 name = cmd->argv[1];
2655 /* Send SERVICE command to the server */
2656 buffer = silc_command_payload_encode_va(SILC_COMMAND_SERVICE,
2657 ++conn->cmd_ident, 1,
2658 1, name, strlen(name));
2659 silc_client_packet_send(conn->client, conn->sock, SILC_PACKET_COMMAND,
2660 NULL, 0, NULL, NULL, buffer->data,
2662 silc_buffer_free(buffer);
2665 /* Notify application */
2666 COMMAND(SILC_STATUS_OK);
2668 /** Wait for command reply */
2669 silc_fsm_next(fsm, silc_client_command_reply_wait);
2670 return SILC_FSM_CONTINUE;
2673 /* Register all default commands provided by the client library for the
2676 void silc_client_commands_register(SilcClient client)
2678 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2681 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 5);
2682 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2683 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2684 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2685 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2686 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2687 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2688 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2689 SILC_CLIENT_CMD(kill, KILL, "KILL", 4);
2690 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2691 SILC_CLIENT_CMD(stats, STATS, "STATS", 0);
2692 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2693 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2694 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2695 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2696 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2697 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 6);
2698 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 9);
2699 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2700 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2701 SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2702 SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
2703 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2704 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2705 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2706 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2707 SILC_CLIENT_CMD(service, SERVICE, "SERVICE", 10);
2710 /* Unregister all commands. */
2712 void silc_client_commands_unregister(SilcClient client)
2714 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2715 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2716 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2717 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2718 SILC_CLIENT_CMDU(list, LIST, "LIST");
2719 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2720 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2721 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2722 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2723 SILC_CLIENT_CMDU(info, INFO, "INFO");
2724 SILC_CLIENT_CMDU(stats, STATS, "STATS");
2725 SILC_CLIENT_CMDU(ping, PING, "PING");
2726 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2727 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2728 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2729 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2730 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2731 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2732 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2733 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2734 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2735 SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2736 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2737 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2738 SILC_CLIENT_CMDU(users, USERS, "USERS");
2739 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2740 SILC_CLIENT_CMDU(service, SERVICE, "SERVICE");
2743 /****************** Client Side Incoming Command Handling *******************/
2745 /* Reply to WHOIS command from server */
2747 static void silc_client_command_process_whois(SilcClient client,
2748 SilcClientConnection conn,
2749 SilcCommandPayload payload,
2750 SilcArgumentPayload args)
2756 SilcBuffer buffer, packet;
2758 SILC_LOG_DEBUG(("Received WHOIS command"));
2760 /* Try to take the Requested Attributes */
2761 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
2765 attrs = silc_attribute_payload_parse(tmp, tmp_len);
2769 /* Process requested attributes */
2770 buffer = silc_client_attributes_process(client, conn, attrs);
2772 silc_attribute_payload_list_free(attrs);
2776 /* Send the attributes back */
2778 silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
2780 silc_command_get_ident(payload),
2781 1, 11, buffer->data, buffer->len);
2782 silc_client_packet_send(client, sock, SILC_PACKET_COMMAND_REPLY,
2783 NULL, 0, NULL, NULL, packet->data,
2785 silc_buffer_free(packet);
2786 silc_buffer_free(buffer);
2790 /* Client is able to receive some command packets even though they are
2791 special case. Server may send WHOIS command to the client to retrieve
2792 Requested Attributes information for WHOIS query the server is
2793 processing. This function currently handles only the WHOIS command,
2794 but if in the future more commands may arrive then this can be made
2795 to support other commands too. */
2797 SILC_FSM_STATE(silc_client_command)
2799 SilcClientConnection conn = fsm_context;
2800 SilcClient client = conn->client;
2801 SilcPacket packet = state_context;
2802 SilcCommandPayload payload;
2803 SilcCommand command;
2804 SilcArgumentPayload args;
2806 /* Get command payload from packet */
2807 payload = silc_command_payload_parse(packet->buffer.data,
2808 silc_buffer_len(&packet->buffer));
2810 SILC_LOG_DEBUG(("Bad command packet"));
2811 return SILC_FSM_FINISH;
2815 args = silc_command_get_args(payload);
2817 /* Get the command */
2818 command = silc_command_get(payload);
2821 case SILC_COMMAND_WHOIS:
2822 /* Ignore everything if requested by application */
2823 if (conn->internal->params.ignore_requested_attributes)
2826 silc_client_command_process_whois(client, conn, payload, args);
2833 silc_command_payload_free(payload);
2834 return SILC_FSM_FINISH;