5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2006 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
22 #include "silcclient.h"
23 #include "client_internal.h"
25 /************************** Types and definitions ***************************/
27 /* 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);
123 silc_dlist_uninit(clients);
125 /* Continue with the command */
126 SILC_FSM_CALL_CONTINUE(&cmd->thread);
129 /* Register command to client */
132 silc_client_command_register(SilcClient client,
135 SilcFSMStateCallback command_func,
136 SilcFSMStateCallback command_reply_func,
139 SilcClientCommand cmd;
141 cmd = silc_calloc(1, sizeof(*cmd));
143 cmd->command = command_func;
144 cmd->reply = command_reply_func;
145 cmd->name = name ? strdup(name) : NULL;
146 cmd->max_args = max_args;
148 silc_list_add(client->internal->commands, cmd);
153 /* Unregister command from client */
156 silc_client_command_unregister(SilcClient client,
158 SilcFSMStateCallback command_func,
159 SilcFSMStateCallback command_reply_func)
161 SilcClientCommand cmd;
163 silc_list_start(client->internal->commands);
164 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
165 if (cmd->cmd == command && cmd->command == command_func &&
166 cmd->reply == command_reply_func) {
167 silc_list_del(client->internal->commands, cmd);
168 silc_free(cmd->name);
177 /* Finds and returns a pointer to the command list. Return NULL if the
178 command is not found. */
180 static SilcClientCommand silc_client_command_find(SilcClient client,
183 SilcClientCommand cmd;
185 silc_list_start(client->internal->commands);
186 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
187 if (cmd->name && !strcasecmp(cmd->name, name))
194 /* Free command context and its internals */
196 static void silc_client_command_free(SilcClientCommandContext cmd)
200 for (i = 0; i < cmd->argc; i++)
201 silc_free(cmd->argv[i]);
202 silc_free(cmd->argv);
203 silc_free(cmd->argv_lens);
204 silc_free(cmd->argv_types);
208 /* Command thread destructor */
210 static void silc_client_command_destructor(SilcFSMThread thread,
212 void *destructor_context)
214 silc_client_command_free(fsm_context);
217 /* Add a command pending a command reply. Used internally by the library. */
220 silc_client_command_add_pending(SilcClientConnection conn,
221 SilcClientCommandContext cmd,
222 SilcClientCommandReply reply,
225 SilcClientCommandReplyCallback cb;
227 silc_mutex_lock(conn->internal->lock);
229 /* Add pending callback, if defined */
231 cb = silc_calloc(1, sizeof(*cb));
233 silc_mutex_unlock(conn->internal->lock);
237 cb->context = context;
238 silc_list_add(cmd->reply_callbacks, cb);
241 SILC_LOG_DEBUG(("pending: cmd %p, command %d, ident %d", cmd, cmd->cmd,
244 /* Add pending reply */
245 silc_list_add(conn->internal->pending_commands, cmd);
247 silc_mutex_unlock(conn->internal->lock);
252 /* Generic function to send any command. The arguments must be sent already
253 encoded into correct format and in correct order. Arguments come from
254 variable argument list pointer. */
256 static SilcUInt16 silc_client_command_send_vap(SilcClient client,
257 SilcClientConnection conn,
258 SilcClientCommandContext cmd,
260 SilcClientCommandReply reply,
262 SilcUInt32 argc, va_list ap)
266 SILC_LOG_DEBUG(("Send command %s", silc_get_command_name(command)));
269 cmd->cmd_ident = silc_client_cmd_ident(conn);
271 /* Encode command payload */
272 packet = silc_command_payload_encode_vap(command, cmd->cmd_ident, argc, ap);
276 /* Send the command */
277 if (!silc_packet_send(conn->stream, SILC_PACKET_COMMAND, 0,
278 silc_buffer_datalen(packet))) {
279 silc_buffer_free(packet);
283 /* Add the command pending command reply */
284 silc_client_command_add_pending(conn, cmd, reply, reply_context);
286 silc_buffer_free(packet);
288 return cmd->cmd_ident;
291 /* Generic function to send any command. The arguments must be sent already
292 encoded into correct format and in correct order. Arguments come from
296 silc_client_command_send_arg_array(SilcClient client,
297 SilcClientConnection conn,
298 SilcClientCommandContext cmd,
300 SilcClientCommandReply reply,
303 unsigned char **argv,
304 SilcUInt32 *argv_lens,
305 SilcUInt32 *argv_types)
309 SILC_LOG_DEBUG(("Send command %s", silc_get_command_name(command)));
312 cmd->cmd_ident = silc_client_cmd_ident(conn);
314 /* Encode command payload */
315 packet = silc_command_payload_encode(command, argc, argv, argv_lens,
316 argv_types, cmd->cmd_ident);
320 /* Send the command */
321 if (!silc_packet_send(conn->stream, SILC_PACKET_COMMAND, 0,
322 silc_buffer_datalen(packet))) {
323 silc_buffer_free(packet);
327 /* Add the command pending command reply */
328 silc_client_command_add_pending(conn, cmd, reply, reply_context);
330 silc_buffer_free(packet);
332 return cmd->cmd_ident;
335 /* Generic function to send any command. The arguments must be sent already
336 encoded into correct format and in correct order. This is used internally
339 static SilcUInt16 silc_client_command_send_va(SilcClientConnection conn,
340 SilcClientCommandContext cmd,
342 SilcClientCommandReply reply,
344 SilcUInt32 argc, ...)
347 SilcUInt16 cmd_ident;
350 cmd_ident = silc_client_command_send_vap(conn->client, conn, cmd, command,
351 reply, reply_context, argc, ap);
357 /****************************** Command API *********************************/
359 /* Executes a command */
361 SilcUInt16 silc_client_command_call(SilcClient client,
362 SilcClientConnection conn,
363 const char *command_line, ...)
367 unsigned char **argv = NULL;
368 SilcUInt32 *argv_lens = NULL, *argv_types = NULL;
369 SilcClientCommand command;
370 SilcClientCommandContext cmd;
374 client->internal->ops->say(client, NULL, SILC_CLIENT_MESSAGE_ERROR,
375 "You are not connected to a server, please connect to server");
379 /* Parse arguments */
380 va_start(va, command_line);
384 /* Get command name */
385 command_name = silc_memdup(command_line, strcspn(command_line, " "));
389 /* Find command by name */
390 command = silc_client_command_find(client, command_name);
392 silc_free(command_name);
396 /* Parse command line */
397 silc_parse_command_line((char *)command_line, &argv, &argv_lens,
398 &argv_types, &argc, command->max_args);
400 silc_free(command_name);
402 arg = va_arg(va, char *);
406 /* Find command by name */
407 command = silc_client_command_find(client, arg);
412 argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
413 argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) * (argc + 1));
414 argv_types = silc_realloc(argv_types, sizeof(*argv_types) * (argc + 1));
415 if (!argv || !argv_lens || !argv_types)
417 argv[argc] = silc_memdup(arg, strlen(arg));
420 argv_lens[argc] = strlen(arg);
421 argv_types[argc] = argc;
423 arg = va_arg(va, char *);
428 /* Allocate command context */
429 cmd = silc_calloc(1, sizeof(*cmd));
433 cmd->cmd = command->cmd;
436 cmd->argv_lens = argv_lens;
437 cmd->argv_types = argv_types;
438 cmd->cmd_ident = silc_client_cmd_ident(conn);
443 SILC_LOG_DEBUG(("Calling %s command", silc_get_command_name(cmd->cmd)));
444 silc_fsm_thread_init(&cmd->thread, &conn->internal->fsm, cmd,
445 silc_client_command_destructor, NULL, FALSE);
446 silc_fsm_start_sync(&cmd->thread, command->command);
448 return cmd->cmd_ident;
451 /* Generic function to send any command. The arguments must be sent already
452 encoded into correct format and in correct order. */
454 SilcUInt16 silc_client_command_send(SilcClient client,
455 SilcClientConnection conn,
457 SilcClientCommandReply reply,
459 SilcUInt32 argc, ...)
461 SilcClientCommandContext cmd;
467 /* Allocate command context */
468 cmd = silc_calloc(1, sizeof(*cmd));
474 /* Send the command */
477 silc_client_command_send_vap(client, conn, cmd, command, reply,
478 reply_context, argc, ap);
481 if (!cmd->cmd_ident) {
482 silc_client_command_free(cmd);
486 /*** Wait for command reply */
487 silc_fsm_thread_init(&cmd->thread, &conn->internal->fsm, cmd,
488 silc_client_command_destructor, NULL, FALSE);
489 silc_fsm_start_sync(&cmd->thread, silc_client_command_reply_wait);
491 return cmd->cmd_ident;
494 /* Generic function to send any command. The arguments must be sent already
495 encoded into correct format and in correct order. Arguments come from
498 SilcUInt16 silc_client_command_send_argv(SilcClient client,
499 SilcClientConnection conn,
501 SilcClientCommandReply reply,
504 unsigned char **argv,
505 SilcUInt32 *argv_lens,
506 SilcUInt32 *argv_types)
508 SilcClientCommandContext cmd;
513 /* Allocate command context */
514 cmd = silc_calloc(1, sizeof(*cmd));
520 /* Send the command */
522 silc_client_command_send_arg_array(client, conn, cmd, command, reply,
523 reply_context, argc, argv, argv_lens,
525 if (!cmd->cmd_ident) {
526 silc_client_command_free(cmd);
530 /*** Wait for command reply */
531 silc_fsm_thread_init(&cmd->thread, &conn->internal->fsm, cmd,
532 silc_client_command_destructor, NULL, FALSE);
533 silc_fsm_start_sync(&cmd->thread, silc_client_command_reply_wait);
535 return cmd->cmd_ident;
538 /* Attach to a command and command identifier to receive command reply. */
540 SilcBool silc_client_command_pending(SilcClientConnection conn,
543 SilcClientCommandReply reply,
546 SilcClientCommandContext cmd;
547 SilcClientCommandReplyCallback cb;
552 SILC_LOG_DEBUG(("Add pending command reply for ident %d", ident));
554 silc_mutex_lock(conn->internal->lock);
556 /* Find the pending command */
557 silc_list_start(conn->internal->pending_commands);
558 while ((cmd = silc_list_get(conn->internal->pending_commands)))
559 if ((cmd->cmd == command || command == SILC_COMMAND_NONE)
560 && cmd->cmd_ident == ident) {
562 /* Add the callback */
563 cb = silc_calloc(1, sizeof(*cb));
567 cb->context = context;
568 silc_list_add(cmd->reply_callbacks, cb);
571 silc_mutex_unlock(conn->internal->lock);
576 /******************************** WHOIS *************************************/
578 /* Command WHOIS. This command is used to query information about
581 SILC_FSM_STATE(silc_client_command_whois)
583 SilcClientCommandContext cmd = fsm_context;
584 SilcClientConnection conn = cmd->conn;
585 SilcClient client = conn->client;
586 SilcBuffer attrs = NULL;
587 unsigned char count[4], *tmp = NULL;
588 SilcBool details = FALSE, nick = FALSE;
589 unsigned char *pubkey = NULL;
592 /* Given without arguments fetches client's own information */
594 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1, 4,
595 silc_buffer_data(conn->internal->local_idp),
596 silc_buffer_len(conn->internal->local_idp));
598 /* Notify application */
599 COMMAND(SILC_STATUS_OK);
601 /** Wait for command reply */
602 silc_fsm_next(fsm, silc_client_command_reply_wait);
603 return SILC_FSM_CONTINUE;
606 for (i = 1; i < cmd->argc; i++) {
607 if (!strcasecmp(cmd->argv[i], "-details")) {
609 } else if (!strcasecmp(cmd->argv[i], "-pubkey") && cmd->argc > i + 1) {
610 pubkey = cmd->argv[i + 1];
613 /* We assume that the first parameter is the nickname, if it isn't
614 -details or -pubkey. The last parameter should always be the count */
617 } else if (i == cmd->argc - 1) {
618 int c = atoi(cmd->argv[i]);
619 SILC_PUT32_MSB(c, count);
626 /* If pubkey is set, add all attributes to the attrs buffer, except
629 attrs = silc_client_attributes_request(SILC_ATTRIBUTE_USER_INFO,
630 SILC_ATTRIBUTE_SERVICE,
631 SILC_ATTRIBUTE_STATUS_MOOD,
632 SILC_ATTRIBUTE_STATUS_FREETEXT,
633 SILC_ATTRIBUTE_STATUS_MESSAGE,
634 SILC_ATTRIBUTE_PREFERRED_LANGUAGE,
635 SILC_ATTRIBUTE_PREFERRED_CONTACT,
636 SILC_ATTRIBUTE_TIMEZONE,
637 SILC_ATTRIBUTE_GEOLOCATION,
638 SILC_ATTRIBUTE_DEVICE_INFO,
639 SILC_ATTRIBUTE_USER_ICON, 0);
641 attrs = silc_client_attributes_request(0);
646 SilcAttributeObjPk obj;
649 if (!silc_pkcs_load_public_key(pubkey, &pk)) {
650 SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR,
651 "Could not load public key %s, check the filename",
653 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
657 switch (silc_pkcs_get_type(pk)) {
659 obj.type = "silc-rsa";
662 obj.type = "ssh-rsa";
664 case SILC_PKCS_X509V3:
665 obj.type = "x509v3-sign-rsa";
667 case SILC_PKCS_OPENPGP:
668 obj.type = "pgp-sign-rsa";
674 obj.data = silc_pkcs_public_key_encode(pk, &obj.data_len);
676 attrs = silc_attribute_payload_encode(attrs,
677 SILC_ATTRIBUTE_USER_PUBLIC_KEY,
678 SILC_ATTRIBUTE_FLAG_VALID,
683 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
684 3, 1, nick ? cmd->argv[1] : NULL,
685 nick ? cmd->argv_lens[1] : 0,
686 2, tmp ? tmp : NULL, tmp ? 4 : 0,
687 3, silc_buffer_datalen(attrs));
689 /* Notify application */
690 COMMAND(SILC_STATUS_OK);
692 /** Wait for command reply */
693 silc_fsm_next(fsm, silc_client_command_reply_wait);
694 return SILC_FSM_CONTINUE;
697 return SILC_FSM_FINISH;
700 /******************************** WHOWAS ************************************/
702 /* Command WHOWAS. This command is used to query history information about
703 specific user that used to exist in the network. */
705 SILC_FSM_STATE(silc_client_command_whowas)
707 SilcClientCommandContext cmd = fsm_context;
708 SilcClientConnection conn = cmd->conn;
709 unsigned char count[4];
712 if (cmd->argc < 2 || cmd->argc > 3) {
713 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
714 "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
715 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
716 SILC_STATUS_ERR_TOO_MANY_PARAMS));
717 return SILC_FSM_FINISH;
720 if (cmd->argc == 2) {
721 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
722 1, 1, cmd->argv[1], cmd->argv_lens[1]);
724 c = atoi(cmd->argv[2]);
725 SILC_PUT32_MSB(c, count);
726 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
727 2, 1, cmd->argv[1], cmd->argv_lens[1],
728 2, count, sizeof(count));
731 /* Notify application */
732 COMMAND(SILC_STATUS_OK);
734 /** Wait for command reply */
735 silc_fsm_next(fsm, silc_client_command_reply_wait);
736 return SILC_FSM_CONTINUE;
739 /******************************** IDENTIFY **********************************/
741 /* Command IDENTIFY. This command is used to query information about
742 specific user, especially ID's. */
744 SILC_FSM_STATE(silc_client_command_identify)
746 SilcClientCommandContext cmd = fsm_context;
747 SilcClientConnection conn = cmd->conn;
748 unsigned char count[4];
751 if (cmd->argc < 2 || cmd->argc > 3)
752 return SILC_FSM_FINISH;
754 if (cmd->argc == 2) {
755 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
756 1, 1, cmd->argv[1], cmd->argv_lens[1]);
758 c = atoi(cmd->argv[2]);
759 SILC_PUT32_MSB(c, count);
760 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
761 2, 1, cmd->argv[1], cmd->argv_lens[1],
762 4, count, sizeof(count));
765 /** Wait for command reply */
766 silc_fsm_next(fsm, silc_client_command_reply_wait);
767 return SILC_FSM_CONTINUE;
770 /********************************** NICK ************************************/
772 /* Command NICK. Shows current nickname/sets new nickname on current
775 SILC_FSM_STATE(silc_client_command_nick)
777 SilcClientCommandContext cmd = fsm_context;
778 SilcClientConnection conn = cmd->conn;
781 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
782 "Usage: /NICK <nickname>");
783 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
787 if (silc_utf8_strcasecmp(conn->local_entry->nickname, cmd->argv[1]))
790 /* Show current nickname */
793 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
794 "Your nickname is %s on server %s",
795 conn->local_entry->nickname, conn->remote_host);
797 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
798 "Your nickname is %s", conn->local_entry->nickname);
801 COMMAND(SILC_STATUS_OK);
805 if (cmd->argv_lens[1] > 128)
806 cmd->argv_lens[1] = 128;
808 /* Send the NICK command */
809 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
810 1, 1, cmd->argv[1], cmd->argv_lens[1]);
812 /* Notify application */
813 COMMAND(SILC_STATUS_OK);
815 /** Wait for command reply */
816 silc_fsm_next(fsm, silc_client_command_reply_wait);
817 return SILC_FSM_CONTINUE;
820 return SILC_FSM_FINISH;
823 /********************************** LIST ************************************/
825 /* Command LIST. Lists channels on the current server. */
827 SILC_FSM_STATE(silc_client_command_list)
829 SilcClientCommandContext cmd = fsm_context;
830 SilcClientConnection conn = cmd->conn;
831 SilcChannelEntry channel;
832 SilcBuffer idp = NULL;
834 if (cmd->argc == 2) {
835 /* Get the Channel ID of the channel */
836 channel = silc_client_get_channel(conn->client, cmd->conn, cmd->argv[1]);
838 idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
842 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
844 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
845 1, 1, silc_buffer_datalen(idp));
847 silc_buffer_free(idp);
849 /* Notify application */
850 COMMAND(SILC_STATUS_OK);
852 /** Wait for command reply */
853 silc_fsm_next(fsm, silc_client_command_reply_wait);
854 return SILC_FSM_CONTINUE;
857 /********************************** TOPIC ***********************************/
859 /* Command TOPIC. Sets/shows topic on a channel. */
861 SILC_FSM_STATE(silc_client_command_topic)
863 SilcClientCommandContext cmd = fsm_context;
864 SilcClientConnection conn = cmd->conn;
865 SilcChannelEntry channel;
869 if (cmd->argc < 2 || cmd->argc > 3) {
870 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
871 "Usage: /TOPIC <channel> [<topic>]");
872 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
873 SILC_STATUS_ERR_TOO_MANY_PARAMS));
877 if (cmd->argv[1][0] == '*') {
878 if (!conn->current_channel) {
879 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
882 name = conn->current_channel->channel_name;
887 if (!conn->current_channel) {
888 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
892 /* Get the Channel ID of the channel */
893 channel = silc_client_get_channel(conn->client, conn, name);
895 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
899 idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
901 /* Send TOPIC command to the server */
903 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
904 1, silc_buffer_datalen(idp),
905 2, cmd->argv[2], strlen(cmd->argv[2]));
907 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
908 1, silc_buffer_datalen(idp));
910 silc_buffer_free(idp);
912 /* Notify application */
913 COMMAND(SILC_STATUS_OK);
915 /** Wait for command reply */
916 silc_fsm_next(fsm, silc_client_command_reply_wait);
917 return SILC_FSM_CONTINUE;
920 return SILC_FSM_FINISH;
923 /********************************* INVITE ***********************************/
925 /* Command INVITE. Invites specific client to join a channel. This is
926 also used to mange the invite list of the channel. */
928 SILC_FSM_STATE(silc_client_command_invite)
930 SilcClientCommandContext cmd = fsm_context;
931 SilcClientConnection conn = cmd->conn;
932 SilcClient client = conn->client;
933 SilcClientEntry client_entry = NULL;
934 SilcChannelEntry channel;
935 SilcBuffer clidp, chidp, args = NULL;
936 SilcPublicKey pubkey = NULL;
937 SilcDList clients = NULL;
938 char *nickname = NULL, *name;
940 unsigned char action[1];
943 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
944 "Usage: /INVITE <channel> [<nickname>[@server>]"
945 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
946 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
950 if (cmd->argv[1][0] == '*') {
951 if (!conn->current_channel) {
952 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
956 channel = conn->current_channel;
960 channel = silc_client_get_channel(conn->client, conn, name);
962 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
967 /* Parse the typed nickname. */
968 if (cmd->argc == 3) {
969 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
970 if (client->internal->params->nickname_parse)
971 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
973 nickname = strdup(cmd->argv[2]);
975 /* Find client entry */
976 clients = silc_client_get_clients_local(client, conn, nickname,
979 /* Resolve client information */
980 SILC_FSM_CALL(silc_client_get_clients(
981 client, conn, nickname,
983 silc_client_command_resolve_continue,
986 client_entry = silc_dlist_get(clients);
988 if (cmd->argv[2][0] == '+')
993 /* Check if it is public key file to be added to invite list */
994 silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey);
995 invite = cmd->argv[2];
1002 args = silc_buffer_alloc_size(2);
1003 silc_buffer_format(args,
1004 SILC_STR_UI_SHORT(1),
1007 chidp = silc_public_key_payload_encode(pubkey);
1008 args = silc_argument_payload_encode_one(args, silc_buffer_data(chidp),
1009 silc_buffer_len(chidp), 2);
1010 silc_buffer_free(chidp);
1011 silc_pkcs_public_key_free(pubkey);
1013 args = silc_argument_payload_encode_one(args, invite, strlen(invite), 1);
1017 /* Send the command */
1018 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
1020 clidp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT);
1021 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 4,
1022 1, silc_buffer_datalen(chidp),
1023 2, silc_buffer_datalen(clidp),
1024 3, args ? action : NULL, args ? 1 : 0,
1025 4, silc_buffer_datalen(args));
1026 silc_buffer_free(clidp);
1028 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
1029 1, silc_buffer_datalen(chidp),
1030 3, args ? action : NULL, args ? 1 : 0,
1031 4, silc_buffer_datalen(args));
1034 silc_buffer_free(chidp);
1035 silc_buffer_free(args);
1036 silc_free(nickname);
1037 silc_client_list_free(client, conn, clients);
1039 /* Notify application */
1040 COMMAND(SILC_STATUS_OK);
1042 /** Wait for command reply */
1043 silc_fsm_next(fsm, silc_client_command_reply_wait);
1044 return SILC_FSM_CONTINUE;
1047 silc_free(nickname);
1048 return SILC_FSM_FINISH;
1051 /********************************** QUIT ************************************/
1053 /* Close the connection */
1055 SILC_FSM_STATE(silc_client_command_quit_final)
1057 SilcClientCommandContext cmd = fsm_context;
1058 SilcClientConnection conn = cmd->conn;
1059 SilcClient client = conn->client;
1061 /* Notify application */
1062 COMMAND(SILC_STATUS_OK);
1064 /* Call connection callback */
1065 conn->callback(client, conn, SILC_CLIENT_CONN_DISCONNECTED,
1066 0, NULL, conn->callback_context);
1068 /* Signal to close connection */
1069 conn->internal->disconnected = TRUE;
1070 SILC_FSM_SEMA_POST(&conn->internal->wait_event);
1072 return SILC_FSM_FINISH;
1075 /* Command QUIT. Closes connection with current server. */
1077 SILC_FSM_STATE(silc_client_command_quit)
1079 SilcClientCommandContext cmd = fsm_context;
1080 SilcClientConnection conn = cmd->conn;
1083 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1084 1, cmd->argv[1], cmd->argv_lens[1]);
1086 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
1088 /* Sleep for a while */
1091 /* We close the connection with a little timeout */
1092 silc_fsm_next_later(fsm, silc_client_command_quit_final, 2, 0);
1093 return SILC_FSM_WAIT;
1096 /********************************** KILL ************************************/
1099 /* Command KILL. Router operator can use this command to remove an client
1100 fromthe SILC Network. */
1102 SILC_FSM_STATE(silc_client_command_kill)
1104 SilcClientCommandContext cmd = fsm_context;
1105 SilcClientConnection conn = cmd->conn;
1106 SilcClient client = conn->client;
1107 SilcBuffer idp, auth = NULL;
1108 SilcClientEntry target;
1110 char *nickname = NULL, *comment = NULL;
1112 if (cmd->argc < 2) {
1113 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1114 "Usage: /KILL <nickname> [<comment>] [-pubkey]");
1115 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1116 return SILC_FSM_FINISH;
1119 /* Parse the typed nickname. */
1120 if (client->internal->params->nickname_parse)
1121 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
1123 nickname = strdup(cmd->argv[1]);
1125 return SILC_FSM_FINISH;
1127 /* Get the target client */
1128 clients = silc_client_get_clients_local(client, conn, nickname,
1131 /* Resolve client information */
1132 SILC_FSM_CALL(silc_client_get_clients(client, conn, nickname,
1134 silc_client_command_resolve_continue,
1137 target = silc_dlist_get(clients);
1139 if (cmd->argc >= 3) {
1140 if (strcasecmp(cmd->argv[2], "-pubkey"))
1141 comment = cmd->argv[2];
1143 if (!strcasecmp(cmd->argv[2], "-pubkey") ||
1144 (cmd->argc >= 4 && !strcasecmp(cmd->argv[3], "-pubkey"))) {
1145 /* Encode the public key authentication payload */
1146 auth = silc_auth_public_key_auth_generate(conn->public_key,
1149 conn->internal->sha1hash,
1150 &target->id, SILC_ID_CLIENT);
1154 /* Send the KILL command to the server */
1155 idp = silc_id_payload_encode(&target->id, SILC_ID_CLIENT);
1156 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
1157 1, silc_buffer_datalen(idp),
1158 2, comment, comment ? strlen(comment) : 0,
1159 3, silc_buffer_datalen(auth));
1160 silc_buffer_free(idp);
1161 silc_buffer_free(auth);
1162 silc_free(nickname);
1163 silc_client_list_free(client, conn, clients);
1165 /* Notify application */
1166 COMMAND(SILC_STATUS_OK);
1168 /** Wait for command reply */
1169 silc_fsm_next(fsm, silc_client_command_reply_wait);
1170 return SILC_FSM_CONTINUE;
1173 /********************************** INFO ************************************/
1175 /* Command INFO. Request information about specific server. If specific
1176 server is not provided the current server is used. */
1178 SILC_FSM_STATE(silc_client_command_info)
1180 SilcClientCommandContext cmd = fsm_context;
1181 SilcClientConnection conn = cmd->conn;
1183 /* Send the command */
1185 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1186 1, cmd->argv[1], cmd->argv_lens[1]);
1188 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
1190 /* Notify application */
1191 COMMAND(SILC_STATUS_OK);
1193 /** Wait for command reply */
1194 silc_fsm_next(fsm, silc_client_command_reply_wait);
1195 return SILC_FSM_CONTINUE;
1198 /********************************** STATS ***********************************/
1200 /* Command STATS. Shows server and network statistics. */
1202 SILC_FSM_STATE(silc_client_command_stats)
1204 SilcClientCommandContext cmd = fsm_context;
1205 SilcClientConnection conn = cmd->conn;
1207 if (cmd->argc < 2) {
1208 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1209 return SILC_FSM_FINISH;
1212 /* Send the command */
1213 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1214 1, silc_buffer_datalen(conn->internal->
1217 /* Notify application */
1218 COMMAND(SILC_STATUS_OK);
1220 /** Wait for command reply */
1221 silc_fsm_next(fsm, silc_client_command_reply_wait);
1222 return SILC_FSM_CONTINUE;
1225 /********************************** PING ************************************/
1227 /* Command PING. Sends ping to server. */
1229 SILC_FSM_STATE(silc_client_command_ping)
1231 SilcClientCommandContext cmd = fsm_context;
1232 SilcClientConnection conn = cmd->conn;
1234 if (cmd->argc < 2) {
1235 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1236 return SILC_FSM_FINISH;
1239 /* Send the command */
1240 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1241 1, silc_buffer_datalen(conn->internal->
1244 /* Save ping time */
1245 cmd->context = SILC_64_TO_PTR(silc_time());
1247 /* Notify application */
1248 COMMAND(SILC_STATUS_OK);
1250 /** Wait for command reply */
1251 silc_fsm_next(fsm, silc_client_command_reply_wait);
1252 return SILC_FSM_CONTINUE;
1255 /********************************** JOIN ************************************/
1257 /* Command JOIN. Joins to a channel. */
1259 SILC_FSM_STATE(silc_client_command_join)
1261 SilcClientCommandContext cmd = fsm_context;
1262 SilcClientConnection conn = cmd->conn;
1263 SilcChannelEntry channel;
1264 SilcBuffer auth = NULL, cauth = NULL;
1265 char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
1266 int i, passphrase_len = 0;
1268 if (cmd->argc < 2) {
1269 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1273 /* See if we have joined to the requested channel already */
1274 channel = silc_client_get_channel(conn->client, conn, cmd->argv[1]);
1275 if (channel && silc_client_on_channel(channel, conn->local_entry))
1278 if (cmd->argv_lens[1] > 256)
1279 cmd->argv_lens[1] = 256;
1281 name = cmd->argv[1];
1283 for (i = 2; i < cmd->argc; i++) {
1284 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
1285 cipher = cmd->argv[++i];
1286 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
1287 hmac = cmd->argv[++i];
1288 } else if (!strcasecmp(cmd->argv[i], "-founder")) {
1289 auth = silc_auth_public_key_auth_generate(conn->public_key,
1292 conn->internal->sha1hash,
1295 } else if (!strcasecmp(cmd->argv[i], "-auth")) {
1296 SilcPublicKey pubkey = conn->public_key;
1297 SilcPrivateKey privkey = conn->private_key;
1298 unsigned char *pk, pkhash[SILC_HASH_MAXLEN], *pubdata;
1301 if (cmd->argc >= i + 3) {
1303 if (cmd->argc >= i + 4) {
1304 pass = cmd->argv[i + 3];
1307 if (!silc_load_key_pair(cmd->argv[i + 1], cmd->argv[i + 2], pass,
1308 &pubkey, &privkey)) {
1309 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1310 "Could not load key pair, check your arguments");
1311 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1317 pk = silc_pkcs_public_key_encode(pubkey, &pk_len);
1318 silc_hash_make(conn->internal->sha1hash, pk, pk_len, pkhash);
1320 pubdata = silc_rng_get_rn_data(conn->client->rng, 128);
1321 memcpy(pubdata, pkhash, 20);
1322 cauth = silc_auth_public_key_auth_generate_wpub(pubkey, privkey,
1324 conn->internal->sha1hash,
1327 memset(pubdata, 0, 128);
1330 /* Passphrases must be UTF-8 encoded, so encode if it is not */
1331 if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
1332 passphrase_len = silc_utf8_encoded_len(cmd->argv[i],
1333 cmd->argv_lens[i], 0);
1334 pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
1335 passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
1336 0, pu8, passphrase_len);
1339 passphrase = strdup(cmd->argv[i]);
1340 passphrase_len = cmd->argv_lens[i];
1345 /* Send JOIN command to the server */
1346 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 7,
1347 1, name, strlen(name),
1348 2, silc_buffer_datalen(conn->internal->
1350 3, passphrase, passphrase_len,
1351 4, cipher, cipher ? strlen(cipher) : 0,
1352 5, hmac, hmac ? strlen(hmac) : 0,
1353 6, silc_buffer_datalen(auth),
1354 7, silc_buffer_datalen(cauth));
1356 silc_buffer_free(auth);
1357 silc_buffer_free(cauth);
1359 memset(passphrase, 0, strlen(passphrase));
1360 silc_free(passphrase);
1362 /* Notify application */
1363 COMMAND(SILC_STATUS_OK);
1365 /** Wait for command reply */
1366 silc_fsm_next(fsm, silc_client_command_reply_wait);
1367 return SILC_FSM_CONTINUE;
1370 return SILC_FSM_FINISH;
1373 /********************************** MOTD ************************************/
1375 /* MOTD command. Requests motd from server. */
1377 SILC_FSM_STATE(silc_client_command_motd)
1379 SilcClientCommandContext cmd = fsm_context;
1380 SilcClientConnection conn = cmd->conn;
1382 if (cmd->argc < 1 || cmd->argc > 2) {
1383 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1384 "Usage: /MOTD [<server>]");
1385 COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
1386 SILC_STATUS_ERR_TOO_MANY_PARAMS));
1387 return SILC_FSM_FINISH;
1390 /* Send the command */
1392 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1393 1, conn->remote_host,
1394 strlen(conn->remote_host));
1396 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1397 1, cmd->argv[1], cmd->argv_lens[1]);
1399 /* Notify application */
1400 COMMAND(SILC_STATUS_OK);
1402 /** Wait for command reply */
1403 silc_fsm_next(fsm, silc_client_command_reply_wait);
1404 return SILC_FSM_CONTINUE;
1407 /********************************** UMODE ***********************************/
1409 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1410 modes as client cannot set itself server/router operator privileges. */
1412 SILC_FSM_STATE(silc_client_command_umode)
1414 SilcClientCommandContext cmd = fsm_context;
1415 SilcClientConnection conn = cmd->conn;
1416 unsigned char *cp, modebuf[4];
1417 SilcUInt32 mode, add, len;
1420 if (cmd->argc < 2) {
1421 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1422 "Usage: /UMODE +|-<modes>");
1423 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1424 return SILC_FSM_FINISH;
1427 mode = conn->local_entry->mode;
1429 /* Are we adding or removing mode */
1430 if (cmd->argv[1][0] == '-')
1436 cp = cmd->argv[1] + 1;
1438 for (i = 0; i < len; i++) {
1443 mode |= SILC_UMODE_SERVER_OPERATOR;
1444 mode |= SILC_UMODE_ROUTER_OPERATOR;
1445 mode |= SILC_UMODE_GONE;
1446 mode |= SILC_UMODE_INDISPOSED;
1447 mode |= SILC_UMODE_BUSY;
1448 mode |= SILC_UMODE_PAGE;
1449 mode |= SILC_UMODE_HYPER;
1450 mode |= SILC_UMODE_ROBOT;
1451 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1452 mode |= SILC_UMODE_REJECT_WATCHING;
1454 mode = SILC_UMODE_NONE;
1459 mode |= SILC_UMODE_SERVER_OPERATOR;
1461 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1465 mode |= SILC_UMODE_ROUTER_OPERATOR;
1467 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1471 mode |= SILC_UMODE_GONE;
1473 mode &= ~SILC_UMODE_GONE;
1477 mode |= SILC_UMODE_INDISPOSED;
1479 mode &= ~SILC_UMODE_INDISPOSED;
1483 mode |= SILC_UMODE_BUSY;
1485 mode &= ~SILC_UMODE_BUSY;
1489 mode |= SILC_UMODE_PAGE;
1491 mode &= ~SILC_UMODE_PAGE;
1495 mode |= SILC_UMODE_HYPER;
1497 mode &= ~SILC_UMODE_HYPER;
1501 mode |= SILC_UMODE_ROBOT;
1503 mode &= ~SILC_UMODE_ROBOT;
1507 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1509 mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
1513 mode |= SILC_UMODE_REJECT_WATCHING;
1515 mode &= ~SILC_UMODE_REJECT_WATCHING;
1519 mode |= SILC_UMODE_BLOCK_INVITE;
1521 mode &= ~SILC_UMODE_BLOCK_INVITE;
1524 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1525 return SILC_FSM_FINISH;
1530 SILC_PUT32_MSB(mode, modebuf);
1532 /* Send the command */
1533 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
1534 1, silc_buffer_datalen(conn->internal->
1536 2, modebuf, sizeof(modebuf));
1538 /* Notify application */
1539 COMMAND(SILC_STATUS_OK);
1541 /** Wait for command reply */
1542 silc_fsm_next(fsm, silc_client_command_reply_wait);
1543 return SILC_FSM_CONTINUE;
1546 /********************************** CMODE ***********************************/
1548 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1549 can be set several at once. Those modes that require argument must be set
1550 separately (unless set with modes that does not require arguments). */
1552 SILC_FSM_STATE(silc_client_command_cmode)
1554 SilcClientCommandContext cmd = fsm_context;
1555 SilcClientConnection conn = cmd->conn;
1556 SilcClient client = conn->client;
1557 SilcChannelEntry channel;
1558 SilcBuffer chidp, auth = NULL, pk = NULL;
1559 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1560 SilcUInt32 mode, add, type, len, arg_len = 0;
1563 if (cmd->argc < 3) {
1564 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1565 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1566 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1570 if (cmd->argv[1][0] == '*') {
1571 if (!conn->current_channel) {
1572 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1576 channel = conn->current_channel;
1578 name = cmd->argv[1];
1580 channel = silc_client_get_channel(conn->client, conn, name);
1582 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1587 mode = channel->mode;
1589 /* Are we adding or removing mode */
1590 if (cmd->argv[2][0] == '-')
1595 /* Argument type to be sent to server */
1599 cp = cmd->argv[2] + 1;
1601 for (i = 0; i < len; i++) {
1605 mode |= SILC_CHANNEL_MODE_PRIVATE;
1607 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1611 mode |= SILC_CHANNEL_MODE_SECRET;
1613 mode &= ~SILC_CHANNEL_MODE_SECRET;
1617 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1619 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1623 mode |= SILC_CHANNEL_MODE_INVITE;
1625 mode &= ~SILC_CHANNEL_MODE_INVITE;
1629 mode |= SILC_CHANNEL_MODE_TOPIC;
1631 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1635 mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1637 mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1641 mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1643 mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1648 mode |= SILC_CHANNEL_MODE_ULIMIT;
1650 if (cmd->argc < 4) {
1651 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1652 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1653 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1656 ll = atoi(cmd->argv[3]);
1657 SILC_PUT32_MSB(ll, tmp);
1661 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1666 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1668 if (cmd->argc < 4) {
1669 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1670 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1671 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1675 arg_len = cmd->argv_lens[3];
1677 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1682 mode |= SILC_CHANNEL_MODE_CIPHER;
1684 if (cmd->argc < 4) {
1685 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1686 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1687 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1691 arg_len = cmd->argv_lens[3];
1693 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1698 mode |= SILC_CHANNEL_MODE_HMAC;
1700 if (cmd->argc < 4) {
1701 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1702 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1703 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1707 arg_len = cmd->argv_lens[3];
1709 mode &= ~SILC_CHANNEL_MODE_HMAC;
1714 SilcPublicKey pubkey = conn->public_key;
1715 SilcPrivateKey privkey = conn->private_key;
1717 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1720 if (cmd->argc >= 5) {
1723 pass = cmd->argv[5];
1724 if (!silc_load_key_pair(cmd->argv[3], cmd->argv[4], pass,
1725 &pubkey, &privkey)) {
1726 SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1727 "Could not load key pair, check your arguments");
1728 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1733 pk = silc_public_key_payload_encode(pubkey);
1734 auth = silc_auth_public_key_auth_generate(pubkey, privkey,
1736 conn->internal->sha1hash,
1739 arg = silc_buffer_data(auth);
1740 arg_len = silc_buffer_len(auth);
1742 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1748 SilcBool chadd = FALSE;
1749 SilcPublicKey chpk = NULL;
1751 mode |= SILC_CHANNEL_MODE_CHANNEL_AUTH;
1754 if (cmd->argc == 3) {
1755 /* Send empty command to receive the public key list. */
1756 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
1757 silc_client_command_send_va(conn, cmd, SILC_COMMAND_CMODE,
1759 1, silc_buffer_datalen(chidp));
1760 silc_buffer_free(chidp);
1762 /* Notify application */
1763 COMMAND(SILC_STATUS_OK);
1767 if (cmd->argc >= 4) {
1768 auth = silc_buffer_alloc_size(2);
1769 silc_buffer_format(auth,
1770 SILC_STR_UI_SHORT(cmd->argc - 3),
1774 for (k = 3; k < cmd->argc; k++) {
1775 if (cmd->argv[k][0] == '+')
1777 if (!silc_pkcs_load_public_key(cmd->argv[k] + 1, &chpk)) {
1778 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1779 "Could not load public key %s, check the filename",
1781 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1782 silc_buffer_free(auth);
1787 pk = silc_public_key_payload_encode(chpk);
1788 auth = silc_argument_payload_encode_one(auth,
1789 silc_buffer_datalen(pk),
1790 chadd ? 0x00 : 0x01);
1791 silc_pkcs_public_key_free(chpk);
1792 silc_buffer_free(pk);
1797 arg = silc_buffer_data(auth);
1798 arg_len = silc_buffer_len(auth);
1800 mode &= ~SILC_CHANNEL_MODE_CHANNEL_AUTH;
1804 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1810 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
1811 SILC_PUT32_MSB(mode, modebuf);
1813 /* Send the command. We support sending only one mode at once that
1814 requires an argument. */
1816 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 4,
1817 1, silc_buffer_datalen(chidp),
1818 2, modebuf, sizeof(modebuf),
1820 8, silc_buffer_datalen(pk));
1822 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
1823 1, silc_buffer_datalen(chidp),
1824 2, modebuf, sizeof(modebuf));
1827 silc_buffer_free(chidp);
1828 silc_buffer_free(auth);
1829 silc_buffer_free(pk);
1831 /* Notify application */
1832 COMMAND(SILC_STATUS_OK);
1834 /** Wait for command reply */
1835 silc_fsm_next(fsm, silc_client_command_reply_wait);
1836 return SILC_FSM_CONTINUE;
1839 return SILC_FSM_FINISH;
1842 /********************************* CUMODE ***********************************/
1844 /* CUMODE command. Changes client's mode on a channel. */
1846 SILC_FSM_STATE(silc_client_command_cumode)
1848 SilcClientCommandContext cmd = fsm_context;
1849 SilcClientConnection conn = cmd->conn;
1850 SilcClient client = conn->client;
1851 SilcChannelEntry channel;
1852 SilcChannelUser chu;
1853 SilcClientEntry client_entry;
1854 SilcBuffer clidp, chidp, auth = NULL;
1855 SilcDList clients = NULL;
1856 unsigned char *name, *cp, modebuf[4];
1857 SilcUInt32 mode = 0, add, len;
1858 char *nickname = NULL;
1861 if (cmd->argc < 4) {
1862 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1863 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1864 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1868 if (cmd->argv[1][0] == '*') {
1869 if (!conn->current_channel) {
1870 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1874 channel = conn->current_channel;
1876 name = cmd->argv[1];
1878 channel = silc_client_get_channel(conn->client, conn, name);
1880 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1885 /* Parse the typed nickname. */
1886 if (client->internal->params->nickname_parse)
1887 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1889 nickname = strdup(cmd->argv[3]);
1891 /* Find client entry */
1892 clients = silc_client_get_clients_local(client, conn, nickname,
1895 /* Resolve client information */
1896 SILC_FSM_CALL(silc_client_get_clients(client, conn, nickname, cmd->argv[3],
1897 silc_client_command_resolve_continue,
1900 client_entry = silc_dlist_get(clients);
1902 /* Get the current mode */
1903 chu = silc_client_on_channel(channel, client_entry);
1907 /* Are we adding or removing mode */
1908 if (cmd->argv[2][0] == '-')
1914 cp = cmd->argv[2] + 1;
1916 for (i = 0; i < len; i++) {
1920 mode |= SILC_CHANNEL_UMODE_CHANFO;
1921 mode |= SILC_CHANNEL_UMODE_CHANOP;
1922 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1923 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1924 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1926 mode = SILC_CHANNEL_UMODE_NONE;
1931 SilcPublicKey pubkey = conn->public_key;
1932 SilcPrivateKey privkey = conn->private_key;
1934 if (cmd->argc >= 6) {
1937 pass = cmd->argv[6];
1938 if (!silc_load_key_pair(cmd->argv[4], cmd->argv[5], pass,
1939 &pubkey, &privkey)) {
1940 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1941 "Could not load key pair, check your arguments");
1942 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1947 auth = silc_auth_public_key_auth_generate(pubkey, privkey,
1949 conn->internal->sha1hash,
1952 mode |= SILC_CHANNEL_UMODE_CHANFO;
1954 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1959 mode |= SILC_CHANNEL_UMODE_CHANOP;
1961 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1965 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1967 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1971 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1973 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1977 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1979 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1983 mode |= SILC_CHANNEL_UMODE_QUIET;
1985 mode &= ~SILC_CHANNEL_UMODE_QUIET;
1988 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1994 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
1995 SILC_PUT32_MSB(mode, modebuf);
1996 clidp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT);
1998 /* Send the command packet. We support sending only one mode at once
1999 that requires an argument. */
2000 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, auth ? 4 : 3,
2001 1, silc_buffer_datalen(chidp),
2003 3, silc_buffer_datalen(clidp),
2004 4, silc_buffer_datalen(auth));
2006 silc_buffer_free(chidp);
2007 silc_buffer_free(clidp);
2009 silc_buffer_free(auth);
2010 silc_free(nickname);
2011 silc_client_list_free(client, conn, clients);
2013 /* Notify application */
2014 COMMAND(SILC_STATUS_OK);
2016 /** Wait for command reply */
2017 silc_fsm_next(fsm, silc_client_command_reply_wait);
2018 return SILC_FSM_CONTINUE;
2021 silc_client_list_free(client, conn, clients);
2022 silc_free(nickname);
2023 return SILC_FSM_FINISH;
2026 /********************************** KICK ************************************/
2028 /* KICK command. Kicks a client out of channel. */
2030 SILC_FSM_STATE(silc_client_command_kick)
2032 SilcClientCommandContext cmd = fsm_context;
2033 SilcClientConnection conn = cmd->conn;
2034 SilcClient client = conn->client;
2035 SilcChannelEntry channel;
2036 SilcBuffer idp, idp2;
2037 SilcClientEntry target;
2038 SilcDList clients = NULL;
2040 char *nickname = NULL;
2042 if (cmd->argc < 3) {
2043 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2044 "Usage: /KICK <channel> <nickname> [<comment>]");
2045 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2049 if (cmd->argv[1][0] == '*') {
2050 if (!conn->current_channel) {
2051 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2054 name = conn->current_channel->channel_name;
2056 name = cmd->argv[1];
2059 if (!conn->current_channel) {
2060 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2064 /* Get the Channel ID of the channel */
2065 channel = silc_client_get_channel(conn->client, conn, name);
2067 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2071 /* Parse the typed nickname. */
2072 if (client->internal->params->nickname_parse)
2073 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
2075 nickname = strdup(cmd->argv[2]);
2077 /* Get the target client */
2078 clients = silc_client_get_clients_local(client, conn, nickname,
2081 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2082 "No such client: %s", cmd->argv[2]);
2083 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2086 target = silc_dlist_get(clients);
2088 /* Send KICK command to the server */
2089 idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
2090 idp2 = silc_id_payload_encode(&target->id, SILC_ID_CLIENT);
2092 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
2093 1, silc_buffer_datalen(idp),
2094 2, silc_buffer_datalen(idp2));
2096 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
2097 1, silc_buffer_datalen(idp),
2098 2, silc_buffer_datalen(idp2),
2099 3, cmd->argv[3], strlen(cmd->argv[3]));
2101 silc_buffer_free(idp);
2102 silc_buffer_free(idp2);
2103 silc_free(nickname);
2104 silc_client_list_free(client, conn, clients);
2106 /* Notify application */
2107 COMMAND(SILC_STATUS_OK);
2109 /** Wait for command reply */
2110 silc_fsm_next(fsm, silc_client_command_reply_wait);
2111 return SILC_FSM_CONTINUE;
2114 silc_free(nickname);
2115 return SILC_FSM_FINISH;
2118 /***************************** OPER & SILCOPER ******************************/
2121 unsigned char *passphrase;
2122 SilcUInt32 passphrase_len;
2123 } *SilcClientCommandOper;
2125 /* Ask passphrase callback */
2127 static void silc_client_command_oper_cb(unsigned char *data,
2128 SilcUInt32 data_len, void *context)
2130 SilcClientCommandContext cmd = context;
2131 SilcClientCommandOper oper = cmd->context;
2133 if (data && data_len)
2134 oper->passphrase = silc_memdup(data, data_len);
2135 oper->passphrase_len = data_len;
2138 SILC_FSM_CALL_CONTINUE(&cmd->thread);
2141 /* Send OPER/SILCOPER command */
2143 SILC_FSM_STATE(silc_client_command_oper_send)
2145 SilcClientCommandContext cmd = fsm_context;
2146 SilcClientConnection conn = cmd->conn;
2147 SilcClientCommandOper oper = cmd->context;
2150 if (!oper || !oper->passphrase) {
2151 /* Encode the public key authentication payload */
2152 auth = silc_auth_public_key_auth_generate(conn->public_key,
2155 conn->internal->hash,
2159 /* Encode the password authentication payload */
2160 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
2161 oper->passphrase, oper->passphrase_len);
2164 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
2165 1, cmd->argv[1], strlen(cmd->argv[1]),
2166 2, silc_buffer_datalen(auth));
2168 silc_buffer_clear(auth);
2169 silc_buffer_free(auth);
2171 silc_free(oper->passphrase);
2175 /* Notify application */
2176 COMMAND(SILC_STATUS_OK);
2178 /** Wait for command reply */
2179 silc_fsm_next(fsm, silc_client_command_reply_wait);
2180 return SILC_FSM_CONTINUE;
2183 /* OPER command. Used to obtain server operator privileges. */
2185 SILC_FSM_STATE(silc_client_command_oper)
2187 SilcClientCommandContext cmd = fsm_context;
2188 SilcClientConnection conn = cmd->conn;
2189 SilcClientCommandOper oper;
2191 if (cmd->argc < 2) {
2192 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2193 "Usage: /OPER <username> [-pubkey]");
2194 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2195 return SILC_FSM_FINISH;
2198 /* Get passphrase */
2199 if (cmd->argc < 3) {
2200 oper = silc_calloc(1, sizeof(*oper));
2202 return SILC_FSM_FINISH;
2203 cmd->context = oper;
2204 SILC_FSM_CALL(conn->client->internal->
2205 ops->ask_passphrase(conn->client, conn,
2206 silc_client_command_oper_cb, cmd));
2209 silc_fsm_next(fsm, silc_client_command_oper_send);
2210 return SILC_FSM_CONTINUE;
2213 /* SILCOPER command. Used to obtain router operator privileges. */
2215 SILC_FSM_STATE(silc_client_command_silcoper)
2217 SilcClientCommandContext cmd = fsm_context;
2218 SilcClientConnection conn = cmd->conn;
2219 SilcClientCommandOper oper;
2221 if (cmd->argc < 2) {
2222 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2223 "Usage: /SILCOPER <username> [-pubkey]");
2224 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2225 return SILC_FSM_FINISH;
2228 /* Get passphrase */
2229 if (cmd->argc < 3) {
2230 oper = silc_calloc(1, sizeof(*oper));
2232 return SILC_FSM_FINISH;
2233 cmd->context = oper;
2234 SILC_FSM_CALL(conn->client->internal->
2235 ops->ask_passphrase(conn->client, conn,
2236 silc_client_command_oper_cb, cmd));
2239 silc_fsm_next(fsm, silc_client_command_oper_send);
2240 return SILC_FSM_CONTINUE;
2243 /*********************************** BAN ************************************/
2245 /* Command BAN. This is used to manage the ban list of the channel. */
2247 SILC_FSM_STATE(silc_client_command_ban)
2249 SilcClientCommandContext cmd = fsm_context;
2250 SilcClientConnection conn = cmd->conn;
2251 SilcChannelEntry channel;
2252 SilcBuffer chidp, args = NULL;
2253 char *name, *ban = NULL;
2254 unsigned char action[1];
2255 SilcPublicKey pubkey = NULL;
2257 if (cmd->argc < 2) {
2258 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2259 "Usage: /BAN <channel> "
2260 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
2261 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2265 if (cmd->argv[1][0] == '*') {
2266 if (!conn->current_channel) {
2267 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2271 channel = conn->current_channel;
2273 name = cmd->argv[1];
2275 channel = silc_client_get_channel(conn->client, conn, name);
2277 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2282 if (cmd->argc == 3) {
2283 if (cmd->argv[2][0] == '+')
2288 /* Check if it is public key file to be added to invite list */
2289 silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey);
2296 args = silc_buffer_alloc_size(2);
2297 silc_buffer_format(args,
2298 SILC_STR_UI_SHORT(1),
2301 chidp = silc_public_key_payload_encode(pubkey);
2302 args = silc_argument_payload_encode_one(args,
2303 silc_buffer_datalen(chidp), 2);
2304 silc_buffer_free(chidp);
2305 silc_pkcs_public_key_free(pubkey);
2307 args = silc_argument_payload_encode_one(args, ban, strlen(ban), 1);
2311 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
2313 /* Send the command */
2314 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
2315 1, silc_buffer_datalen(chidp),
2316 2, args ? action : NULL, args ? 1 : 0,
2317 3, silc_buffer_datalen(args));
2319 silc_buffer_free(chidp);
2320 silc_buffer_free(args);
2322 /* Notify application */
2323 COMMAND(SILC_STATUS_OK);
2325 /** Wait for command reply */
2326 silc_fsm_next(fsm, silc_client_command_reply_wait);
2327 return SILC_FSM_CONTINUE;
2330 return SILC_FSM_FINISH;
2333 /********************************* DETACH ***********************************/
2335 /* Command DETACH. This is used to detach from the server */
2337 SILC_FSM_STATE(silc_client_command_detach)
2339 SilcClientCommandContext cmd = fsm_context;
2340 SilcClientConnection conn = cmd->conn;
2342 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
2344 /* Notify application */
2345 COMMAND(SILC_STATUS_OK);
2347 /** Wait for command reply */
2348 silc_fsm_next(fsm, silc_client_command_reply_wait);
2349 return SILC_FSM_CONTINUE;
2352 /********************************** WATCH ***********************************/
2354 /* Command WATCH. */
2356 SILC_FSM_STATE(silc_client_command_watch)
2358 SilcClientCommandContext cmd = fsm_context;
2359 SilcClientConnection conn = cmd->conn;
2360 SilcBuffer args = NULL;
2362 const char *pubkey = NULL;
2363 SilcBool pubkey_add = TRUE;
2365 if (cmd->argc < 3) {
2366 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2370 if (!strcasecmp(cmd->argv[1], "-add")) {
2372 } else if (!strcasecmp(cmd->argv[1], "-del")) {
2374 } else if (!strcasecmp(cmd->argv[1], "-pubkey") && cmd->argc >= 3) {
2376 pubkey = cmd->argv[2] + 1;
2377 if (cmd->argv[2][0] == '-')
2380 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2388 if (!silc_pkcs_load_public_key(pubkey, &pk)) {
2389 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2390 "Could not load public key %s, check the filename", pubkey);
2391 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2395 args = silc_buffer_alloc_size(2);
2396 silc_buffer_format(args,
2397 SILC_STR_UI_SHORT(1),
2399 buffer = silc_public_key_payload_encode(pk);
2400 args = silc_argument_payload_encode_one(args, silc_buffer_datalen(buffer),
2401 pubkey_add ? 0x00 : 0x01);
2402 silc_buffer_free(buffer);
2403 silc_pkcs_public_key_free(pk);
2406 /* Send the commmand */
2407 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
2408 1, silc_buffer_datalen(conn->internal->
2410 type, pubkey ? args->data : cmd->argv[2],
2411 pubkey ? silc_buffer_len(args) :
2414 silc_buffer_free(args);
2416 /* Notify application */
2417 COMMAND(SILC_STATUS_OK);
2419 /** Wait for command reply */
2420 silc_fsm_next(fsm, silc_client_command_reply_wait);
2421 return SILC_FSM_CONTINUE;
2424 return SILC_FSM_FINISH;
2427 /********************************** LEAVE ***********************************/
2429 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2431 SILC_FSM_STATE(silc_client_command_leave)
2433 SilcClientCommandContext cmd = fsm_context;
2434 SilcClientConnection conn = cmd->conn;
2435 SilcChannelEntry channel;
2439 if (cmd->argc != 2) {
2440 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2441 "Usage: /LEAVE <channel>");
2442 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2446 if (cmd->argv[1][0] == '*') {
2447 if (!conn->current_channel) {
2448 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2451 name = conn->current_channel->channel_name;
2453 name = cmd->argv[1];
2456 /* Get the channel entry */
2457 channel = silc_client_get_channel(conn->client, conn, name);
2459 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2463 idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
2465 /* Send LEAVE command to the server */
2466 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
2467 1, silc_buffer_datalen(idp));
2469 silc_buffer_free(idp);
2471 /* Notify application */
2472 COMMAND(SILC_STATUS_OK);
2474 if (conn->current_channel == channel)
2475 conn->current_channel = NULL;
2477 /** Wait for command reply */
2478 silc_fsm_next(fsm, silc_client_command_reply_wait);
2479 return SILC_FSM_CONTINUE;
2482 return SILC_FSM_FINISH;
2485 /********************************** USERS ***********************************/
2487 /* Command USERS. Requests the USERS of the clients joined on requested
2490 SILC_FSM_STATE(silc_client_command_users)
2492 SilcClientCommandContext cmd = fsm_context;
2493 SilcClientConnection conn = cmd->conn;
2496 if (cmd->argc != 2) {
2497 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2498 "Usage: /USERS <channel>");
2499 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2503 if (cmd->argv[1][0] == '*') {
2504 if (!conn->current_channel) {
2505 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2508 name = conn->current_channel->channel_name;
2510 name = cmd->argv[1];
2513 /* Send USERS command to the server */
2514 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
2515 2, name, strlen(name));
2517 /* Notify application */
2518 COMMAND(SILC_STATUS_OK);
2520 /** Wait for command reply */
2521 silc_fsm_next(fsm, silc_client_command_reply_wait);
2522 return SILC_FSM_CONTINUE;
2525 return SILC_FSM_FINISH;
2528 /********************************* GETKEY ***********************************/
2530 /* Command GETKEY. Used to fetch remote client's public key. */
2532 SILC_FSM_STATE(silc_client_command_getkey)
2534 SilcClientCommandContext cmd = fsm_context;
2535 SilcClientConnection conn = cmd->conn;
2536 SilcClient client = conn->client;
2537 SilcClientEntry client_entry;
2538 SilcServerEntry server_entry;
2540 char *nickname = NULL;
2543 if (cmd->argc < 2) {
2544 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2545 "Usage: /GETKEY <nickname or server name>");
2546 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2547 return SILC_FSM_FINISH;
2550 /* Parse the typed nickname. */
2551 if (client->internal->params->nickname_parse)
2552 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2554 nickname = strdup(cmd->argv[1]);
2556 COMMAND_ERROR(SILC_STATUS_ERR_RESOURCE_LIMIT);
2557 return SILC_FSM_FINISH;
2560 /* Find client entry */
2561 clients = silc_client_get_clients_local(client, conn, nickname,
2564 /* Check whether user requested server */
2565 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2566 if (!server_entry) {
2567 /* No client or server exist with this name, query for both. */
2568 SILC_FSM_CALL(silc_client_command_send(client, conn,
2569 SILC_COMMAND_IDENTIFY,
2570 silc_client_command_continue,
2573 strlen(cmd->argv[1]),
2575 strlen(cmd->argv[1])));
2577 idp = silc_id_payload_encode(&server_entry->id, SILC_ID_SERVER);
2579 client_entry = silc_dlist_get(clients);
2580 idp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT);
2581 silc_client_list_free(client, conn, clients);
2584 /* Send the commmand */
2585 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
2586 1, silc_buffer_datalen(idp));
2588 silc_buffer_free(idp);
2589 silc_free(nickname);
2591 /* Notify application */
2592 COMMAND(SILC_STATUS_OK);
2594 /** Wait for command reply */
2595 silc_fsm_next(fsm, silc_client_command_reply_wait);
2596 return SILC_FSM_CONTINUE;
2599 /********************************* SERVICE **********************************/
2601 /* Command SERVICE. Negotiates service agreement with server. */
2602 /* XXX incomplete */
2604 SILC_FSM_STATE(silc_client_command_service)
2606 SilcClientCommandContext cmd = fsm_context;
2608 SilcClientConnection conn = cmd->conn;
2612 if (cmd->argc < 2) {
2613 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2614 "Usage: /SERVICE [<service name>] [-pubkey]");
2615 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2616 return SILC_FSM_FINISH;
2619 name = cmd->argv[1];
2621 /* Send SERVICE command to the server */
2622 buffer = silc_command_payload_encode_va(SILC_COMMAND_SERVICE,
2623 ++conn->cmd_ident, 1,
2624 1, name, strlen(name));
2625 silc_client_packet_send(conn->client, conn->sock, SILC_PACKET_COMMAND,
2626 NULL, 0, NULL, NULL, buffer->data,
2628 silc_buffer_free(buffer);
2631 /* Notify application */
2632 COMMAND(SILC_STATUS_OK);
2634 /** Wait for command reply */
2635 silc_fsm_next(fsm, silc_client_command_reply_wait);
2636 return SILC_FSM_CONTINUE;
2639 /* Register all default commands provided by the client library for the
2642 void silc_client_commands_register(SilcClient client)
2644 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2647 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 5);
2648 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2649 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2650 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2651 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2652 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2653 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2654 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2655 SILC_CLIENT_CMD(kill, KILL, "KILL", 4);
2656 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2657 SILC_CLIENT_CMD(stats, STATS, "STATS", 0);
2658 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2659 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2660 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2661 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2662 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2663 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 6);
2664 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 9);
2665 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2666 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2667 SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2668 SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
2669 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2670 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2671 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2672 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2673 SILC_CLIENT_CMD(service, SERVICE, "SERVICE", 10);
2676 /* Unregister all commands. */
2678 void silc_client_commands_unregister(SilcClient client)
2680 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2681 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2682 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2683 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2684 SILC_CLIENT_CMDU(list, LIST, "LIST");
2685 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2686 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2687 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2688 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2689 SILC_CLIENT_CMDU(info, INFO, "INFO");
2690 SILC_CLIENT_CMDU(stats, STATS, "STATS");
2691 SILC_CLIENT_CMDU(ping, PING, "PING");
2692 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2693 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2694 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2695 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2696 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2697 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2698 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2699 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2700 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2701 SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2702 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2703 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2704 SILC_CLIENT_CMDU(users, USERS, "USERS");
2705 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2706 SILC_CLIENT_CMDU(service, SERVICE, "SERVICE");
2709 /****************** Client Side Incoming Command Handling *******************/
2711 /* Reply to WHOIS command from server */
2713 static void silc_client_command_process_whois(SilcClient client,
2714 SilcClientConnection conn,
2715 SilcCommandPayload payload,
2716 SilcArgumentPayload args)
2722 SilcBuffer buffer, packet;
2724 SILC_LOG_DEBUG(("Received WHOIS command"));
2726 /* Try to take the Requested Attributes */
2727 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
2731 attrs = silc_attribute_payload_parse(tmp, tmp_len);
2735 /* Process requested attributes */
2736 buffer = silc_client_attributes_process(client, conn, attrs);
2738 silc_attribute_payload_list_free(attrs);
2742 /* Send the attributes back */
2744 silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
2746 silc_command_get_ident(payload),
2747 1, 11, buffer->data, buffer->len);
2748 silc_client_packet_send(client, sock, SILC_PACKET_COMMAND_REPLY,
2749 NULL, 0, NULL, NULL, packet->data,
2751 silc_buffer_free(packet);
2752 silc_buffer_free(buffer);
2756 /* Client is able to receive some command packets even though they are
2757 special case. Server may send WHOIS command to the client to retrieve
2758 Requested Attributes information for WHOIS query the server is
2759 processing. This function currently handles only the WHOIS command,
2760 but if in the future more commands may arrive then this can be made
2761 to support other commands too. */
2763 SILC_FSM_STATE(silc_client_command)
2765 SilcClientConnection conn = fsm_context;
2766 SilcClient client = conn->client;
2767 SilcPacket packet = state_context;
2768 SilcCommandPayload payload;
2769 SilcCommand command;
2770 SilcArgumentPayload args;
2772 /* Get command payload from packet */
2773 payload = silc_command_payload_parse(packet->buffer.data,
2774 silc_buffer_len(&packet->buffer));
2776 SILC_LOG_DEBUG(("Bad command packet"));
2777 return SILC_FSM_FINISH;
2781 args = silc_command_get_args(payload);
2783 /* Get the command */
2784 command = silc_command_get(payload);
2787 case SILC_COMMAND_WHOIS:
2788 /* Ignore everything if requested by application */
2789 if (client->internal->params->ignore_requested_attributes)
2792 silc_client_command_process_whois(client, conn, payload, args);
2799 silc_command_payload_free(payload);
2800 return SILC_FSM_FINISH;