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 */
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));
145 cmd->command = command_func;
146 cmd->reply = command_reply_func;
147 cmd->max_args = max_args;
148 cmd->name = name ? strdup(name) : NULL;
154 silc_list_add(client->internal->commands, cmd);
159 /* Unregister command from client */
162 silc_client_command_unregister(SilcClient client,
164 SilcFSMStateCallback command_func,
165 SilcFSMStateCallback command_reply_func)
167 SilcClientCommand cmd;
169 silc_list_start(client->internal->commands);
170 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
171 if (cmd->cmd == command && cmd->command == command_func &&
172 cmd->reply == command_reply_func) {
173 silc_list_del(client->internal->commands, cmd);
174 silc_free(cmd->name);
183 /* Finds and returns a pointer to the command list. Return NULL if the
184 command is not found. */
186 static SilcClientCommand silc_client_command_find(SilcClient client,
189 SilcClientCommand cmd;
191 silc_list_start(client->internal->commands);
192 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
193 if (cmd->name && !strcasecmp(cmd->name, name))
200 /* Command thread destructor */
202 static void silc_client_command_destructor(SilcFSMThread thread,
204 void *destructor_context)
206 SilcClientCommandContext cmd = fsm_context;
207 SilcClientConnection conn = cmd->conn;
209 /* Removes commands that aren't waiting for reply but are waiting
210 for something. They may not have been removed yet. */
211 silc_list_del(conn->internal->pending_commands, cmd);
213 silc_client_command_free(cmd);
216 /* Add a command pending a command reply. Used internally by the library. */
219 silc_client_command_add_pending(SilcClientConnection conn,
220 SilcClientCommandContext cmd,
221 SilcClientCommandReply reply,
224 SilcClientCommandReplyCallback cb;
226 silc_mutex_lock(conn->internal->lock);
228 /* Add pending callback, if defined */
230 cb = silc_calloc(1, sizeof(*cb));
232 silc_mutex_unlock(conn->internal->lock);
236 cb->context = context;
237 silc_list_add(cmd->reply_callbacks, cb);
240 /* Add pending reply */
241 silc_list_add(conn->internal->pending_commands, cmd);
243 silc_mutex_unlock(conn->internal->lock);
248 /* Generic function to send any command. The arguments must be sent already
249 encoded into correct format and in correct order. Arguments come from
250 variable argument list pointer. */
252 static SilcUInt16 silc_client_command_send_vap(SilcClient client,
253 SilcClientConnection conn,
254 SilcClientCommandContext cmd,
256 SilcClientCommandReply reply,
258 SilcUInt32 argc, va_list ap)
262 SILC_LOG_DEBUG(("Send command %s", silc_get_command_name(command)));
264 if (conn->internal->disconnected)
268 cmd->cmd_ident = silc_client_cmd_ident(conn);
270 /* Encode command payload */
271 packet = silc_command_payload_encode_vap(command, cmd->cmd_ident, argc, ap);
275 /* Send the command */
276 if (!silc_packet_send(conn->stream, SILC_PACKET_COMMAND, 0,
277 silc_buffer_datalen(packet))) {
278 silc_buffer_free(packet);
282 /* Add the command pending command reply */
283 silc_client_command_add_pending(conn, cmd, reply, reply_context);
285 silc_buffer_free(packet);
287 return cmd->cmd_ident;
290 /* Generic function to send any command. The arguments must be sent already
291 encoded into correct format and in correct order. Arguments come from
295 silc_client_command_send_arg_array(SilcClient client,
296 SilcClientConnection conn,
297 SilcClientCommandContext cmd,
299 SilcClientCommandReply reply,
302 unsigned char **argv,
303 SilcUInt32 *argv_lens,
304 SilcUInt32 *argv_types)
308 SILC_LOG_DEBUG(("Send command %s", silc_get_command_name(command)));
310 if (conn->internal->disconnected)
314 cmd->cmd_ident = silc_client_cmd_ident(conn);
316 /* Encode command payload */
317 packet = silc_command_payload_encode(command, argc, argv, argv_lens,
318 argv_types, cmd->cmd_ident);
322 /* Send the command */
323 if (!silc_packet_send(conn->stream, SILC_PACKET_COMMAND, 0,
324 silc_buffer_datalen(packet))) {
325 silc_buffer_free(packet);
329 /* Add the command pending command reply */
330 silc_client_command_add_pending(conn, cmd, reply, reply_context);
332 silc_buffer_free(packet);
334 return cmd->cmd_ident;
337 /* Generic function to send any command. The arguments must be sent already
338 encoded into correct format and in correct order. This is used internally
341 static SilcUInt16 silc_client_command_send_va(SilcClientConnection conn,
342 SilcClientCommandContext cmd,
344 SilcClientCommandReply reply,
346 SilcUInt32 argc, ...)
349 SilcUInt16 cmd_ident;
352 cmd_ident = silc_client_command_send_vap(conn->client, conn, cmd, command,
353 reply, reply_context, argc, ap);
359 /****************************** Command API *********************************/
361 /* Free command context and its internals */
363 void silc_client_command_free(SilcClientCommandContext cmd)
365 SilcClientCommandReplyCallback cb;
368 for (i = 0; i < cmd->argc; i++)
369 silc_free(cmd->argv[i]);
370 silc_free(cmd->argv);
371 silc_free(cmd->argv_lens);
372 silc_free(cmd->argv_types);
374 silc_list_start(cmd->reply_callbacks);
375 while ((cb = silc_list_get(cmd->reply_callbacks)))
381 /* Executes a command */
383 SilcUInt16 silc_client_command_call(SilcClient client,
384 SilcClientConnection conn,
385 const char *command_line, ...)
389 unsigned char **argv = NULL;
390 SilcUInt32 *argv_lens = NULL, *argv_types = NULL;
391 SilcClientCommand command;
392 SilcClientCommandContext cmd;
396 client->internal->ops->say(client, NULL, SILC_CLIENT_MESSAGE_ERROR,
397 "You are not connected to a server, please connect to server");
401 /* Parse arguments */
402 va_start(va, command_line);
406 /* Get command name */
407 command_name = silc_memdup(command_line, strcspn(command_line, " "));
411 /* Find command by name */
412 command = silc_client_command_find(client, command_name);
414 silc_free(command_name);
418 /* Parse command line */
419 silc_parse_command_line((char *)command_line, &argv, &argv_lens,
420 &argv_types, &argc, command->max_args);
422 silc_free(command_name);
424 arg = va_arg(va, char *);
428 /* Find command by name */
429 command = silc_client_command_find(client, arg);
434 argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
435 argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) * (argc + 1));
436 argv_types = silc_realloc(argv_types, sizeof(*argv_types) * (argc + 1));
437 if (!argv || !argv_lens || !argv_types)
439 argv[argc] = silc_memdup(arg, strlen(arg));
442 argv_lens[argc] = strlen(arg);
443 argv_types[argc] = argc;
445 arg = va_arg(va, char *);
450 /* Allocate command context */
451 cmd = silc_calloc(1, sizeof(*cmd));
455 cmd->cmd = command->cmd;
458 cmd->argv_lens = argv_lens;
459 cmd->argv_types = argv_types;
460 cmd->cmd_ident = silc_client_cmd_ident(conn);
463 silc_list_init(cmd->reply_callbacks,
464 struct SilcClientCommandReplyCallbackStruct, next);
467 SILC_LOG_DEBUG(("Calling %s command", silc_get_command_name(cmd->cmd)));
468 silc_fsm_thread_init(&cmd->thread, &conn->internal->fsm, cmd,
469 silc_client_command_destructor, NULL, FALSE);
470 silc_fsm_start_sync(&cmd->thread, command->command);
472 return cmd->cmd_ident;
475 /* Generic function to send any command. The arguments must be sent already
476 encoded into correct format and in correct order. */
478 SilcUInt16 silc_client_command_send(SilcClient client,
479 SilcClientConnection conn,
481 SilcClientCommandReply reply,
483 SilcUInt32 argc, ...)
485 SilcClientCommandContext cmd;
491 /* Allocate command context */
492 cmd = silc_calloc(1, sizeof(*cmd));
497 silc_list_init(cmd->reply_callbacks,
498 struct SilcClientCommandReplyCallbackStruct, next);
500 /* Send the command */
503 silc_client_command_send_vap(client, conn, cmd, command, reply,
504 reply_context, argc, ap);
507 if (!cmd->cmd_ident) {
508 silc_client_command_free(cmd);
512 /*** Wait for command reply */
513 silc_fsm_thread_init(&cmd->thread, &conn->internal->fsm, cmd,
514 silc_client_command_destructor, NULL, FALSE);
515 silc_fsm_start_sync(&cmd->thread, silc_client_command_reply_wait);
517 return cmd->cmd_ident;
520 /* Generic function to send any command. The arguments must be sent already
521 encoded into correct format and in correct order. Arguments come from
524 SilcUInt16 silc_client_command_send_argv(SilcClient client,
525 SilcClientConnection conn,
527 SilcClientCommandReply reply,
530 unsigned char **argv,
531 SilcUInt32 *argv_lens,
532 SilcUInt32 *argv_types)
534 SilcClientCommandContext cmd;
539 /* Allocate command context */
540 cmd = silc_calloc(1, sizeof(*cmd));
546 /* Send the command */
548 silc_client_command_send_arg_array(client, conn, cmd, command, reply,
549 reply_context, argc, argv, argv_lens,
551 if (!cmd->cmd_ident) {
552 silc_client_command_free(cmd);
556 /*** Wait for command reply */
557 silc_fsm_thread_init(&cmd->thread, &conn->internal->fsm, cmd,
558 silc_client_command_destructor, NULL, FALSE);
559 silc_fsm_start_sync(&cmd->thread, silc_client_command_reply_wait);
561 return cmd->cmd_ident;
564 /* Attach to a command and command identifier to receive command reply. */
566 SilcBool silc_client_command_pending(SilcClientConnection conn,
569 SilcClientCommandReply reply,
572 SilcClientCommandContext cmd;
573 SilcClientCommandReplyCallback cb;
578 SILC_LOG_DEBUG(("Add pending command reply for ident %d", ident));
580 silc_mutex_lock(conn->internal->lock);
582 /* Find the pending command */
583 silc_list_start(conn->internal->pending_commands);
584 while ((cmd = silc_list_get(conn->internal->pending_commands)))
585 if ((cmd->cmd == command || command == SILC_COMMAND_NONE)
586 && cmd->cmd_ident == ident) {
588 /* Add the callback */
589 cb = silc_calloc(1, sizeof(*cb));
593 cb->context = context;
594 silc_list_add(cmd->reply_callbacks, cb);
597 silc_mutex_unlock(conn->internal->lock);
602 /******************************** WHOIS *************************************/
604 /* Command WHOIS. This command is used to query information about
607 SILC_FSM_STATE(silc_client_command_whois)
609 SilcClientCommandContext cmd = fsm_context;
610 SilcClientConnection conn = cmd->conn;
611 SilcClient client = conn->client;
612 SilcBuffer attrs = NULL;
613 unsigned char count[4], *tmp = NULL;
614 SilcBool details = FALSE, nick = FALSE;
615 unsigned char *pubkey = NULL;
618 /* Given without arguments fetches client's own information */
620 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1, 4,
621 silc_buffer_data(conn->internal->local_idp),
622 silc_buffer_len(conn->internal->local_idp));
624 /* Notify application */
625 COMMAND(SILC_STATUS_OK);
627 /** Wait for command reply */
628 silc_fsm_next(fsm, silc_client_command_reply_wait);
632 for (i = 1; i < cmd->argc; i++) {
633 if (!strcasecmp(cmd->argv[i], "-details")) {
635 } else if (!strcasecmp(cmd->argv[i], "-pubkey") && cmd->argc > i + 1) {
636 pubkey = cmd->argv[i + 1];
639 /* We assume that the first parameter is the nickname, if it isn't
640 -details or -pubkey. The last parameter should always be the count */
643 } else if (i == cmd->argc - 1) {
644 int c = atoi(cmd->argv[i]);
645 SILC_PUT32_MSB(c, count);
652 /* If pubkey is set, add all attributes to the attrs buffer, except
655 attrs = silc_client_attributes_request(SILC_ATTRIBUTE_USER_INFO,
656 SILC_ATTRIBUTE_SERVICE,
657 SILC_ATTRIBUTE_STATUS_MOOD,
658 SILC_ATTRIBUTE_STATUS_FREETEXT,
659 SILC_ATTRIBUTE_STATUS_MESSAGE,
660 SILC_ATTRIBUTE_PREFERRED_LANGUAGE,
661 SILC_ATTRIBUTE_PREFERRED_CONTACT,
662 SILC_ATTRIBUTE_TIMEZONE,
663 SILC_ATTRIBUTE_GEOLOCATION,
664 SILC_ATTRIBUTE_DEVICE_INFO,
665 SILC_ATTRIBUTE_USER_ICON, 0);
667 attrs = silc_client_attributes_request(0);
672 SilcAttributeObjPk obj;
675 if (!silc_pkcs_load_public_key(pubkey, &pk)) {
676 SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR,
677 "Could not load public key %s, check the filename",
679 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
683 switch (silc_pkcs_get_type(pk)) {
685 obj.type = "silc-rsa";
688 obj.type = "ssh-rsa";
690 case SILC_PKCS_X509V3:
691 obj.type = "x509v3-sign-rsa";
693 case SILC_PKCS_OPENPGP:
694 obj.type = "pgp-sign-rsa";
700 obj.data = silc_pkcs_public_key_encode(pk, &obj.data_len);
702 attrs = silc_attribute_payload_encode(attrs,
703 SILC_ATTRIBUTE_USER_PUBLIC_KEY,
704 SILC_ATTRIBUTE_FLAG_VALID,
709 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
710 3, 1, nick ? cmd->argv[1] : NULL,
711 nick ? cmd->argv_lens[1] : 0,
712 2, tmp ? tmp : NULL, tmp ? 4 : 0,
713 3, silc_buffer_datalen(attrs));
715 /* Notify application */
716 COMMAND(SILC_STATUS_OK);
718 /** Wait for command reply */
719 silc_fsm_next(fsm, silc_client_command_reply_wait);
726 /******************************** WHOWAS ************************************/
728 /* Command WHOWAS. This command is used to query history information about
729 specific user that used to exist in the network. */
731 SILC_FSM_STATE(silc_client_command_whowas)
733 SilcClientCommandContext cmd = fsm_context;
734 SilcClientConnection conn = cmd->conn;
735 unsigned char count[4];
738 if (cmd->argc < 2 || cmd->argc > 3) {
739 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
740 "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
741 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
742 SILC_STATUS_ERR_TOO_MANY_PARAMS));
746 if (cmd->argc == 2) {
747 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
748 1, 1, cmd->argv[1], cmd->argv_lens[1]);
750 c = atoi(cmd->argv[2]);
751 SILC_PUT32_MSB(c, count);
752 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
753 2, 1, cmd->argv[1], cmd->argv_lens[1],
754 2, count, sizeof(count));
757 /* Notify application */
758 COMMAND(SILC_STATUS_OK);
760 /** Wait for command reply */
761 silc_fsm_next(fsm, silc_client_command_reply_wait);
765 /******************************** IDENTIFY **********************************/
767 /* Command IDENTIFY. This command is used to query information about
768 specific user, especially ID's. */
770 SILC_FSM_STATE(silc_client_command_identify)
772 SilcClientCommandContext cmd = fsm_context;
773 SilcClientConnection conn = cmd->conn;
774 unsigned char count[4];
777 if (cmd->argc < 2 || cmd->argc > 3)
780 if (cmd->argc == 2) {
781 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
782 1, 1, cmd->argv[1], cmd->argv_lens[1]);
784 c = atoi(cmd->argv[2]);
785 SILC_PUT32_MSB(c, count);
786 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
787 2, 1, cmd->argv[1], cmd->argv_lens[1],
788 4, count, sizeof(count));
791 /** Wait for command reply */
792 silc_fsm_next(fsm, silc_client_command_reply_wait);
796 /********************************** NICK ************************************/
798 /* Command NICK. Shows current nickname/sets new nickname on current
801 SILC_FSM_STATE(silc_client_command_nick)
803 SilcClientCommandContext cmd = fsm_context;
804 SilcClientConnection conn = cmd->conn;
807 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
808 "Usage: /NICK <nickname>");
809 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
813 if (silc_utf8_strcasecmp(conn->local_entry->nickname, cmd->argv[1]))
816 /* Show current nickname */
819 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
820 "Your nickname is %s on server %s",
821 conn->local_entry->nickname, conn->remote_host);
823 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
824 "Your nickname is %s", conn->local_entry->nickname);
827 COMMAND(SILC_STATUS_OK);
831 if (cmd->argv_lens[1] > 128)
832 cmd->argv_lens[1] = 128;
834 /* Send the NICK command */
835 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
836 1, 1, cmd->argv[1], cmd->argv_lens[1]);
838 /* Notify application */
839 COMMAND(SILC_STATUS_OK);
841 /** Wait for command reply */
842 silc_fsm_next(fsm, silc_client_command_reply_wait);
849 /********************************** LIST ************************************/
851 /* Command LIST. Lists channels on the current server. */
853 SILC_FSM_STATE(silc_client_command_list)
855 SilcClientCommandContext cmd = fsm_context;
856 SilcClientConnection conn = cmd->conn;
857 SilcChannelEntry channel;
858 SilcBuffer idp = NULL;
860 if (cmd->argc == 2) {
861 /* Get the Channel ID of the channel */
862 channel = silc_client_get_channel(conn->client, cmd->conn, cmd->argv[1]);
864 idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
868 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
870 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
871 1, 1, silc_buffer_datalen(idp));
873 silc_buffer_free(idp);
875 /* Notify application */
876 COMMAND(SILC_STATUS_OK);
878 /** Wait for command reply */
879 silc_fsm_next(fsm, silc_client_command_reply_wait);
883 /********************************** TOPIC ***********************************/
885 /* Command TOPIC. Sets/shows topic on a channel. */
887 SILC_FSM_STATE(silc_client_command_topic)
889 SilcClientCommandContext cmd = fsm_context;
890 SilcClientConnection conn = cmd->conn;
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);
938 /* Notify application */
939 COMMAND(SILC_STATUS_OK);
941 /** Wait for command reply */
942 silc_fsm_next(fsm, silc_client_command_reply_wait);
949 /********************************* INVITE ***********************************/
951 /* Command INVITE. Invites specific client to join a channel. This is
952 also used to mange the invite list of the channel. */
954 SILC_FSM_STATE(silc_client_command_invite)
956 SilcClientCommandContext cmd = fsm_context;
957 SilcClientConnection conn = cmd->conn;
958 SilcClient client = conn->client;
959 SilcClientEntry client_entry = NULL;
960 SilcChannelEntry channel;
961 SilcBuffer clidp, chidp, args = NULL;
962 SilcPublicKey pubkey = NULL;
963 SilcDList clients = NULL;
964 char *nickname = NULL, *name;
966 unsigned char action[1];
969 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
970 "Usage: /INVITE <channel> [<nickname>[@server>]"
971 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
972 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
976 if (cmd->argv[1][0] == '*') {
977 if (!conn->current_channel) {
978 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
982 channel = conn->current_channel;
986 channel = silc_client_get_channel(conn->client, conn, name);
988 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
993 /* Parse the typed nickname. */
994 if (cmd->argc == 3) {
995 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
996 silc_client_nickname_parse(client, conn, cmd->argv[2], &nickname);
998 /* Find client entry */
999 clients = silc_client_get_clients_local(client, conn, nickname,
1002 /* Resolve client information */
1003 SILC_FSM_CALL(silc_client_get_clients(
1004 client, conn, nickname,
1006 silc_client_command_resolve_continue,
1009 client_entry = silc_dlist_get(clients);
1011 if (cmd->argv[2][0] == '+')
1016 /* Check if it is public key file to be added to invite list */
1017 silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey);
1018 invite = cmd->argv[2];
1025 args = silc_buffer_alloc_size(2);
1026 silc_buffer_format(args,
1027 SILC_STR_UI_SHORT(1),
1030 chidp = silc_public_key_payload_encode(pubkey);
1031 args = silc_argument_payload_encode_one(args, silc_buffer_data(chidp),
1032 silc_buffer_len(chidp), 2);
1033 silc_buffer_free(chidp);
1034 silc_pkcs_public_key_free(pubkey);
1036 args = silc_argument_payload_encode_one(args, invite, strlen(invite), 1);
1040 /* Send the command */
1041 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
1043 clidp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT);
1044 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 4,
1045 1, silc_buffer_datalen(chidp),
1046 2, silc_buffer_datalen(clidp),
1047 3, args ? action : NULL, args ? 1 : 0,
1048 4, silc_buffer_datalen(args));
1049 silc_buffer_free(clidp);
1051 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
1052 1, silc_buffer_datalen(chidp),
1053 3, args ? action : NULL, args ? 1 : 0,
1054 4, silc_buffer_datalen(args));
1057 silc_buffer_free(chidp);
1058 silc_buffer_free(args);
1059 silc_free(nickname);
1060 silc_client_list_free(client, conn, clients);
1062 /* Notify application */
1063 COMMAND(SILC_STATUS_OK);
1065 /** Wait for command reply */
1066 silc_fsm_next(fsm, silc_client_command_reply_wait);
1070 silc_free(nickname);
1074 /********************************** QUIT ************************************/
1076 /* Close the connection */
1078 SILC_FSM_STATE(silc_client_command_quit_final)
1080 SilcClientCommandContext cmd = fsm_context;
1081 SilcClientConnection conn = cmd->conn;
1082 SilcClient client = conn->client;
1084 SILC_LOG_DEBUG(("Quitting"));
1086 /* Notify application */
1087 COMMAND(SILC_STATUS_OK);
1089 /* Call connection callback */
1090 if (!conn->internal->callback_called)
1091 conn->callback(client, conn, SILC_CLIENT_CONN_DISCONNECTED,
1092 0, NULL, conn->callback_context);
1093 conn->internal->callback_called = TRUE;
1095 /* Signal to close connection */
1096 if (!conn->internal->disconnected) {
1097 conn->internal->disconnected = TRUE;
1098 SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event);
1104 /* Command QUIT. Closes connection with current server. */
1106 SILC_FSM_STATE(silc_client_command_quit)
1108 SilcClientCommandContext cmd = fsm_context;
1109 SilcClientConnection conn = cmd->conn;
1112 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1113 1, cmd->argv[1], cmd->argv_lens[1]);
1115 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
1117 /* Sleep for a while */
1120 /* We close the connection with a little timeout */
1121 silc_fsm_next_later(fsm, silc_client_command_quit_final, 2, 0);
1125 /********************************** KILL ************************************/
1128 /* Command KILL. Router operator can use this command to remove an client
1129 fromthe SILC Network. */
1131 SILC_FSM_STATE(silc_client_command_kill)
1133 SilcClientCommandContext cmd = fsm_context;
1134 SilcClientConnection conn = cmd->conn;
1135 SilcClient client = conn->client;
1136 SilcBuffer idp, auth = NULL;
1137 SilcClientEntry target;
1139 char *nickname = NULL, *comment = NULL;
1141 if (cmd->argc < 2) {
1142 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1143 "Usage: /KILL <nickname> [<comment>] [-pubkey]");
1144 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1148 /* Parse the typed nickname. */
1149 if (!silc_client_nickname_parse(client, conn, cmd->argv[1], &nickname))
1152 /* Get the target client */
1153 clients = silc_client_get_clients_local(client, conn, nickname,
1156 /* Resolve client information */
1157 SILC_FSM_CALL(silc_client_get_clients(client, conn, nickname,
1159 silc_client_command_resolve_continue,
1162 target = silc_dlist_get(clients);
1164 if (cmd->argc >= 3) {
1165 if (strcasecmp(cmd->argv[2], "-pubkey"))
1166 comment = cmd->argv[2];
1168 if (!strcasecmp(cmd->argv[2], "-pubkey") ||
1169 (cmd->argc >= 4 && !strcasecmp(cmd->argv[3], "-pubkey"))) {
1170 /* Encode the public key authentication payload */
1171 auth = silc_auth_public_key_auth_generate(conn->public_key,
1174 conn->internal->sha1hash,
1175 &target->id, SILC_ID_CLIENT);
1179 /* Send the KILL command to the server */
1180 idp = silc_id_payload_encode(&target->id, SILC_ID_CLIENT);
1181 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
1182 1, silc_buffer_datalen(idp),
1183 2, comment, comment ? strlen(comment) : 0,
1184 3, silc_buffer_datalen(auth));
1185 silc_buffer_free(idp);
1186 silc_buffer_free(auth);
1187 silc_free(nickname);
1188 silc_client_list_free(client, conn, clients);
1190 /* Notify application */
1191 COMMAND(SILC_STATUS_OK);
1193 /** Wait for command reply */
1194 silc_fsm_next(fsm, silc_client_command_reply_wait);
1198 /********************************** INFO ************************************/
1200 /* Command INFO. Request information about specific server. If specific
1201 server is not provided the current server is used. */
1203 SILC_FSM_STATE(silc_client_command_info)
1205 SilcClientCommandContext cmd = fsm_context;
1206 SilcClientConnection conn = cmd->conn;
1208 /* Send the command */
1210 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1211 1, cmd->argv[1], cmd->argv_lens[1]);
1213 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
1215 /* Notify application */
1216 COMMAND(SILC_STATUS_OK);
1218 /** Wait for command reply */
1219 silc_fsm_next(fsm, silc_client_command_reply_wait);
1223 /********************************** STATS ***********************************/
1225 /* Command STATS. Shows server and network statistics. */
1227 SILC_FSM_STATE(silc_client_command_stats)
1229 SilcClientCommandContext cmd = fsm_context;
1230 SilcClientConnection conn = cmd->conn;
1232 /* Send the command */
1233 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1234 1, silc_buffer_datalen(conn->internal->
1237 /* Notify application */
1238 COMMAND(SILC_STATUS_OK);
1240 /** Wait for command reply */
1241 silc_fsm_next(fsm, silc_client_command_reply_wait);
1245 /********************************** PING ************************************/
1247 /* Command PING. Sends ping to server. */
1249 SILC_FSM_STATE(silc_client_command_ping)
1251 SilcClientCommandContext cmd = fsm_context;
1252 SilcClientConnection conn = cmd->conn;
1254 if (cmd->argc < 2) {
1255 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1259 /* Send the command */
1260 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1261 1, silc_buffer_datalen(conn->internal->
1264 /* Save ping time */
1265 cmd->context = SILC_64_TO_PTR(silc_time());
1267 /* Notify application */
1268 COMMAND(SILC_STATUS_OK);
1270 /** Wait for command reply */
1271 silc_fsm_next(fsm, silc_client_command_reply_wait);
1275 /********************************** JOIN ************************************/
1277 /* Command JOIN. Joins to a channel. */
1279 SILC_FSM_STATE(silc_client_command_join)
1281 SilcClientCommandContext cmd = fsm_context;
1282 SilcClientConnection conn = cmd->conn;
1283 SilcChannelEntry channel;
1284 SilcBuffer auth = NULL, cauth = NULL;
1285 char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
1286 int i, passphrase_len = 0;
1288 if (cmd->argc < 2) {
1289 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1293 /* See if we have joined to the requested channel already */
1294 channel = silc_client_get_channel(conn->client, conn, cmd->argv[1]);
1295 if (channel && silc_client_on_channel(channel, conn->local_entry))
1298 if (cmd->argv_lens[1] > 256)
1299 cmd->argv_lens[1] = 256;
1301 name = cmd->argv[1];
1303 for (i = 2; i < cmd->argc; i++) {
1304 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
1305 cipher = cmd->argv[++i];
1306 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
1307 hmac = cmd->argv[++i];
1308 } else if (!strcasecmp(cmd->argv[i], "-founder")) {
1309 auth = silc_auth_public_key_auth_generate(conn->public_key,
1312 conn->internal->sha1hash,
1315 } else if (!strcasecmp(cmd->argv[i], "-auth")) {
1316 SilcPublicKey pubkey = conn->public_key;
1317 SilcPrivateKey privkey = conn->private_key;
1318 unsigned char *pk, pkhash[SILC_HASH_MAXLEN], *pubdata;
1321 if (cmd->argc >= i + 3) {
1323 if (cmd->argc >= i + 4) {
1324 pass = cmd->argv[i + 3];
1327 if (!silc_load_key_pair(cmd->argv[i + 1], cmd->argv[i + 2], pass,
1328 &pubkey, &privkey)) {
1329 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1330 "Could not load key pair, check your arguments");
1331 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1337 pk = silc_pkcs_public_key_encode(pubkey, &pk_len);
1338 silc_hash_make(conn->internal->sha1hash, pk, pk_len, pkhash);
1340 pubdata = silc_rng_get_rn_data(conn->client->rng, 128);
1341 memcpy(pubdata, pkhash, 20);
1342 cauth = silc_auth_public_key_auth_generate_wpub(pubkey, privkey,
1344 conn->internal->sha1hash,
1347 memset(pubdata, 0, 128);
1350 /* Passphrases must be UTF-8 encoded, so encode if it is not */
1351 if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
1352 passphrase_len = silc_utf8_encoded_len(cmd->argv[i],
1353 cmd->argv_lens[i], 0);
1354 pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
1355 passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
1356 0, pu8, passphrase_len);
1359 passphrase = strdup(cmd->argv[i]);
1360 passphrase_len = cmd->argv_lens[i];
1365 /* Send JOIN command to the server */
1366 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 7,
1367 1, name, strlen(name),
1368 2, silc_buffer_datalen(conn->internal->
1370 3, passphrase, passphrase_len,
1371 4, cipher, cipher ? strlen(cipher) : 0,
1372 5, hmac, hmac ? strlen(hmac) : 0,
1373 6, silc_buffer_datalen(auth),
1374 7, silc_buffer_datalen(cauth));
1376 silc_buffer_free(auth);
1377 silc_buffer_free(cauth);
1379 memset(passphrase, 0, strlen(passphrase));
1380 silc_free(passphrase);
1382 /* Notify application */
1383 COMMAND(SILC_STATUS_OK);
1385 /** Wait for command reply */
1386 silc_fsm_next(fsm, silc_client_command_reply_wait);
1393 /********************************** MOTD ************************************/
1395 /* MOTD command. Requests motd from server. */
1397 SILC_FSM_STATE(silc_client_command_motd)
1399 SilcClientCommandContext cmd = fsm_context;
1400 SilcClientConnection conn = cmd->conn;
1402 if (cmd->argc < 1 || cmd->argc > 2) {
1403 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1404 "Usage: /MOTD [<server>]");
1405 COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
1406 SILC_STATUS_ERR_TOO_MANY_PARAMS));
1410 /* Send the command */
1412 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1413 1, conn->remote_host,
1414 strlen(conn->remote_host));
1416 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1417 1, cmd->argv[1], cmd->argv_lens[1]);
1419 /* Notify application */
1420 COMMAND(SILC_STATUS_OK);
1422 /** Wait for command reply */
1423 silc_fsm_next(fsm, silc_client_command_reply_wait);
1427 /********************************** UMODE ***********************************/
1429 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1430 modes as client cannot set itself server/router operator privileges. */
1432 SILC_FSM_STATE(silc_client_command_umode)
1434 SilcClientCommandContext cmd = fsm_context;
1435 SilcClientConnection conn = cmd->conn;
1436 unsigned char *cp, modebuf[4];
1437 SilcUInt32 mode, add, len;
1440 if (cmd->argc < 2) {
1441 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1442 "Usage: /UMODE +|-<modes>");
1443 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1447 mode = conn->local_entry->mode;
1449 /* Are we adding or removing mode */
1450 if (cmd->argv[1][0] == '-')
1456 cp = cmd->argv[1] + 1;
1458 for (i = 0; i < len; i++) {
1463 mode |= SILC_UMODE_SERVER_OPERATOR;
1464 mode |= SILC_UMODE_ROUTER_OPERATOR;
1465 mode |= SILC_UMODE_GONE;
1466 mode |= SILC_UMODE_INDISPOSED;
1467 mode |= SILC_UMODE_BUSY;
1468 mode |= SILC_UMODE_PAGE;
1469 mode |= SILC_UMODE_HYPER;
1470 mode |= SILC_UMODE_ROBOT;
1471 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1472 mode |= SILC_UMODE_REJECT_WATCHING;
1474 mode = SILC_UMODE_NONE;
1479 mode |= SILC_UMODE_SERVER_OPERATOR;
1481 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1485 mode |= SILC_UMODE_ROUTER_OPERATOR;
1487 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1491 mode |= SILC_UMODE_GONE;
1493 mode &= ~SILC_UMODE_GONE;
1497 mode |= SILC_UMODE_INDISPOSED;
1499 mode &= ~SILC_UMODE_INDISPOSED;
1503 mode |= SILC_UMODE_BUSY;
1505 mode &= ~SILC_UMODE_BUSY;
1509 mode |= SILC_UMODE_PAGE;
1511 mode &= ~SILC_UMODE_PAGE;
1515 mode |= SILC_UMODE_HYPER;
1517 mode &= ~SILC_UMODE_HYPER;
1521 mode |= SILC_UMODE_ROBOT;
1523 mode &= ~SILC_UMODE_ROBOT;
1527 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1529 mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
1533 mode |= SILC_UMODE_REJECT_WATCHING;
1535 mode &= ~SILC_UMODE_REJECT_WATCHING;
1539 mode |= SILC_UMODE_BLOCK_INVITE;
1541 mode &= ~SILC_UMODE_BLOCK_INVITE;
1544 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1550 SILC_PUT32_MSB(mode, modebuf);
1552 /* Send the command */
1553 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
1554 1, silc_buffer_datalen(conn->internal->
1556 2, modebuf, sizeof(modebuf));
1558 /* Notify application */
1559 COMMAND(SILC_STATUS_OK);
1561 /** Wait for command reply */
1562 silc_fsm_next(fsm, silc_client_command_reply_wait);
1566 /********************************** CMODE ***********************************/
1568 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1569 can be set several at once. Those modes that require argument must be set
1570 separately (unless set with modes that does not require arguments). */
1572 SILC_FSM_STATE(silc_client_command_cmode)
1574 SilcClientCommandContext cmd = fsm_context;
1575 SilcClientConnection conn = cmd->conn;
1576 SilcClient client = conn->client;
1577 SilcChannelEntry channel;
1578 SilcBuffer chidp, auth = NULL, pk = NULL;
1579 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1580 SilcUInt32 mode, add, type, len, arg_len = 0;
1583 if (cmd->argc < 3) {
1584 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1585 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1586 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1590 if (cmd->argv[1][0] == '*') {
1591 if (!conn->current_channel) {
1592 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1596 channel = conn->current_channel;
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);
1851 /* Notify application */
1852 COMMAND(SILC_STATUS_OK);
1854 /** Wait for command reply */
1855 silc_fsm_next(fsm, silc_client_command_reply_wait);
1862 /********************************* CUMODE ***********************************/
1864 /* CUMODE command. Changes client's mode on a channel. */
1866 SILC_FSM_STATE(silc_client_command_cumode)
1868 SilcClientCommandContext cmd = fsm_context;
1869 SilcClientConnection conn = cmd->conn;
1870 SilcClient client = conn->client;
1871 SilcChannelEntry channel;
1872 SilcChannelUser chu;
1873 SilcClientEntry client_entry;
1874 SilcBuffer clidp, chidp, auth = NULL;
1875 SilcDList clients = NULL;
1876 unsigned char *name, *cp, modebuf[4];
1877 SilcUInt32 mode = 0, add, len;
1878 char *nickname = NULL;
1881 if (cmd->argc < 4) {
1882 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1883 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1884 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1888 if (cmd->argv[1][0] == '*') {
1889 if (!conn->current_channel) {
1890 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1894 channel = conn->current_channel;
1896 name = cmd->argv[1];
1898 channel = silc_client_get_channel(conn->client, conn, name);
1900 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1905 /* Parse the typed nickname. */
1906 silc_client_nickname_parse(client, conn, cmd->argv[3], &nickname);
1908 /* Find client entry */
1909 clients = silc_client_get_clients_local(client, conn, nickname,
1912 /* Resolve client information */
1913 SILC_FSM_CALL(silc_client_get_clients(client, conn, nickname, cmd->argv[3],
1914 silc_client_command_resolve_continue,
1917 client_entry = silc_dlist_get(clients);
1919 /* Get the current mode */
1920 chu = silc_client_on_channel(channel, client_entry);
1924 /* Are we adding or removing mode */
1925 if (cmd->argv[2][0] == '-')
1931 cp = cmd->argv[2] + 1;
1933 for (i = 0; i < len; i++) {
1937 mode |= SILC_CHANNEL_UMODE_CHANFO;
1938 mode |= SILC_CHANNEL_UMODE_CHANOP;
1939 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1940 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1941 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1943 mode = SILC_CHANNEL_UMODE_NONE;
1948 SilcPublicKey pubkey = conn->public_key;
1949 SilcPrivateKey privkey = conn->private_key;
1951 if (cmd->argc >= 6) {
1954 pass = cmd->argv[6];
1955 if (!silc_load_key_pair(cmd->argv[4], cmd->argv[5], pass,
1956 &pubkey, &privkey)) {
1957 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1958 "Could not load key pair, check your arguments");
1959 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1964 auth = silc_auth_public_key_auth_generate(pubkey, privkey,
1966 conn->internal->sha1hash,
1969 mode |= SILC_CHANNEL_UMODE_CHANFO;
1971 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1976 mode |= SILC_CHANNEL_UMODE_CHANOP;
1978 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1982 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1984 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1988 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1990 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1994 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1996 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
2000 mode |= SILC_CHANNEL_UMODE_QUIET;
2002 mode &= ~SILC_CHANNEL_UMODE_QUIET;
2005 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
2011 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
2012 SILC_PUT32_MSB(mode, modebuf);
2013 clidp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT);
2015 /* Send the command packet. We support sending only one mode at once
2016 that requires an argument. */
2017 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, auth ? 4 : 3,
2018 1, silc_buffer_datalen(chidp),
2020 3, silc_buffer_datalen(clidp),
2021 4, silc_buffer_datalen(auth));
2023 silc_buffer_free(chidp);
2024 silc_buffer_free(clidp);
2026 silc_buffer_free(auth);
2027 silc_free(nickname);
2028 silc_client_list_free(client, conn, clients);
2030 /* Notify application */
2031 COMMAND(SILC_STATUS_OK);
2033 /** Wait for command reply */
2034 silc_fsm_next(fsm, silc_client_command_reply_wait);
2038 silc_client_list_free(client, conn, clients);
2039 silc_free(nickname);
2043 /********************************** KICK ************************************/
2045 /* KICK command. Kicks a client out of channel. */
2047 SILC_FSM_STATE(silc_client_command_kick)
2049 SilcClientCommandContext cmd = fsm_context;
2050 SilcClientConnection conn = cmd->conn;
2051 SilcClient client = conn->client;
2052 SilcChannelEntry channel;
2053 SilcBuffer idp, idp2;
2054 SilcClientEntry target;
2055 SilcDList clients = NULL;
2057 char *nickname = NULL;
2059 if (cmd->argc < 3) {
2060 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2061 "Usage: /KICK <channel> <nickname> [<comment>]");
2062 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2066 if (cmd->argv[1][0] == '*') {
2067 if (!conn->current_channel) {
2068 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2071 name = conn->current_channel->channel_name;
2073 name = cmd->argv[1];
2076 if (!conn->current_channel) {
2077 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2081 /* Get the Channel ID of the channel */
2082 channel = silc_client_get_channel(conn->client, conn, name);
2084 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2088 /* Parse the typed nickname. */
2089 silc_client_nickname_parse(client, conn, cmd->argv[2], &nickname);
2091 /* Get the target client */
2092 clients = silc_client_get_clients_local(client, conn, nickname,
2095 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2096 "No such client: %s", cmd->argv[2]);
2097 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2100 target = silc_dlist_get(clients);
2102 /* Send KICK command to the server */
2103 idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
2104 idp2 = silc_id_payload_encode(&target->id, SILC_ID_CLIENT);
2106 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
2107 1, silc_buffer_datalen(idp),
2108 2, silc_buffer_datalen(idp2));
2110 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
2111 1, silc_buffer_datalen(idp),
2112 2, silc_buffer_datalen(idp2),
2113 3, cmd->argv[3], strlen(cmd->argv[3]));
2115 silc_buffer_free(idp);
2116 silc_buffer_free(idp2);
2117 silc_free(nickname);
2118 silc_client_list_free(client, conn, clients);
2120 /* Notify application */
2121 COMMAND(SILC_STATUS_OK);
2123 /** Wait for command reply */
2124 silc_fsm_next(fsm, silc_client_command_reply_wait);
2128 silc_free(nickname);
2132 /***************************** OPER & SILCOPER ******************************/
2135 unsigned char *passphrase;
2136 SilcUInt32 passphrase_len;
2137 } *SilcClientCommandOper;
2139 /* Ask passphrase callback */
2141 static void silc_client_command_oper_cb(unsigned char *data,
2142 SilcUInt32 data_len, void *context)
2144 SilcClientCommandContext cmd = context;
2145 SilcClientCommandOper oper = cmd->context;
2147 if (data && data_len)
2148 oper->passphrase = silc_memdup(data, data_len);
2149 oper->passphrase_len = data_len;
2152 SILC_FSM_CALL_CONTINUE(&cmd->thread);
2155 /* Send OPER/SILCOPER command */
2157 SILC_FSM_STATE(silc_client_command_oper_send)
2159 SilcClientCommandContext cmd = fsm_context;
2160 SilcClientConnection conn = cmd->conn;
2161 SilcClientCommandOper oper = cmd->context;
2164 if (!oper || !oper->passphrase) {
2165 /* Encode the public key authentication payload */
2166 auth = silc_auth_public_key_auth_generate(conn->public_key,
2169 conn->internal->hash,
2173 /* Encode the password authentication payload */
2174 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
2175 oper->passphrase, oper->passphrase_len);
2178 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
2179 1, cmd->argv[1], strlen(cmd->argv[1]),
2180 2, silc_buffer_datalen(auth));
2182 silc_buffer_clear(auth);
2183 silc_buffer_free(auth);
2185 silc_free(oper->passphrase);
2189 /* Notify application */
2190 COMMAND(SILC_STATUS_OK);
2192 /** Wait for command reply */
2193 silc_fsm_next(fsm, silc_client_command_reply_wait);
2197 /* OPER command. Used to obtain server operator privileges. */
2199 SILC_FSM_STATE(silc_client_command_oper)
2201 SilcClientCommandContext cmd = fsm_context;
2202 SilcClientConnection conn = cmd->conn;
2203 SilcClientCommandOper oper;
2205 if (cmd->argc < 2) {
2206 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2207 "Usage: /OPER <username> [-pubkey]");
2208 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2212 /* Get passphrase */
2213 if (cmd->argc < 3) {
2214 oper = silc_calloc(1, sizeof(*oper));
2217 cmd->context = oper;
2218 SILC_FSM_CALL(conn->client->internal->
2219 ops->ask_passphrase(conn->client, conn,
2220 silc_client_command_oper_cb, cmd));
2223 silc_fsm_next(fsm, silc_client_command_oper_send);
2227 /* SILCOPER command. Used to obtain router operator privileges. */
2229 SILC_FSM_STATE(silc_client_command_silcoper)
2231 SilcClientCommandContext cmd = fsm_context;
2232 SilcClientConnection conn = cmd->conn;
2233 SilcClientCommandOper oper;
2235 if (cmd->argc < 2) {
2236 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2237 "Usage: /SILCOPER <username> [-pubkey]");
2238 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2242 /* Get passphrase */
2243 if (cmd->argc < 3) {
2244 oper = silc_calloc(1, sizeof(*oper));
2247 cmd->context = oper;
2248 SILC_FSM_CALL(conn->client->internal->
2249 ops->ask_passphrase(conn->client, conn,
2250 silc_client_command_oper_cb, cmd));
2253 silc_fsm_next(fsm, silc_client_command_oper_send);
2257 /*********************************** BAN ************************************/
2259 /* Command BAN. This is used to manage the ban list of the channel. */
2261 SILC_FSM_STATE(silc_client_command_ban)
2263 SilcClientCommandContext cmd = fsm_context;
2264 SilcClientConnection conn = cmd->conn;
2265 SilcChannelEntry channel;
2266 SilcBuffer chidp, args = NULL;
2267 char *name, *ban = NULL;
2268 unsigned char action[1];
2269 SilcPublicKey pubkey = NULL;
2271 if (cmd->argc < 2) {
2272 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2273 "Usage: /BAN <channel> "
2274 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
2275 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2279 if (cmd->argv[1][0] == '*') {
2280 if (!conn->current_channel) {
2281 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2285 channel = conn->current_channel;
2287 name = cmd->argv[1];
2289 channel = silc_client_get_channel(conn->client, conn, name);
2291 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2296 if (cmd->argc == 3) {
2297 if (cmd->argv[2][0] == '+')
2302 /* Check if it is public key file to be added to invite list */
2303 silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey);
2310 args = silc_buffer_alloc_size(2);
2311 silc_buffer_format(args,
2312 SILC_STR_UI_SHORT(1),
2315 chidp = silc_public_key_payload_encode(pubkey);
2316 args = silc_argument_payload_encode_one(args,
2317 silc_buffer_datalen(chidp), 2);
2318 silc_buffer_free(chidp);
2319 silc_pkcs_public_key_free(pubkey);
2321 args = silc_argument_payload_encode_one(args, ban, strlen(ban), 1);
2325 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
2327 /* Send the command */
2328 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
2329 1, silc_buffer_datalen(chidp),
2330 2, args ? action : NULL, args ? 1 : 0,
2331 3, silc_buffer_datalen(args));
2333 silc_buffer_free(chidp);
2334 silc_buffer_free(args);
2336 /* Notify application */
2337 COMMAND(SILC_STATUS_OK);
2339 /** Wait for command reply */
2340 silc_fsm_next(fsm, silc_client_command_reply_wait);
2347 /********************************* DETACH ***********************************/
2349 /* Command DETACH. This is used to detach from the server */
2351 SILC_FSM_STATE(silc_client_command_detach)
2353 SilcClientCommandContext cmd = fsm_context;
2354 SilcClientConnection conn = cmd->conn;
2356 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
2358 /* Notify application */
2359 COMMAND(SILC_STATUS_OK);
2361 /** Wait for command reply */
2362 silc_fsm_next(fsm, silc_client_command_reply_wait);
2366 /********************************** WATCH ***********************************/
2368 /* Command WATCH. */
2370 SILC_FSM_STATE(silc_client_command_watch)
2372 SilcClientCommandContext cmd = fsm_context;
2373 SilcClientConnection conn = cmd->conn;
2374 SilcBuffer args = NULL;
2376 const char *pubkey = NULL;
2377 SilcBool pubkey_add = TRUE;
2379 if (cmd->argc < 3) {
2380 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2384 if (!strcasecmp(cmd->argv[1], "-add")) {
2386 } else if (!strcasecmp(cmd->argv[1], "-del")) {
2388 } else if (!strcasecmp(cmd->argv[1], "-pubkey") && cmd->argc >= 3) {
2390 pubkey = cmd->argv[2] + 1;
2391 if (cmd->argv[2][0] == '-')
2394 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2402 if (!silc_pkcs_load_public_key(pubkey, &pk)) {
2403 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2404 "Could not load public key %s, check the filename", pubkey);
2405 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2409 args = silc_buffer_alloc_size(2);
2410 silc_buffer_format(args,
2411 SILC_STR_UI_SHORT(1),
2413 buffer = silc_public_key_payload_encode(pk);
2414 args = silc_argument_payload_encode_one(args, silc_buffer_datalen(buffer),
2415 pubkey_add ? 0x00 : 0x01);
2416 silc_buffer_free(buffer);
2417 silc_pkcs_public_key_free(pk);
2420 /* Send the commmand */
2421 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
2422 1, silc_buffer_datalen(conn->internal->
2424 type, pubkey ? args->data : cmd->argv[2],
2425 pubkey ? silc_buffer_len(args) :
2428 silc_buffer_free(args);
2430 /* Notify application */
2431 COMMAND(SILC_STATUS_OK);
2433 /** Wait for command reply */
2434 silc_fsm_next(fsm, silc_client_command_reply_wait);
2441 /********************************** LEAVE ***********************************/
2443 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2445 SILC_FSM_STATE(silc_client_command_leave)
2447 SilcClientCommandContext cmd = fsm_context;
2448 SilcClientConnection conn = cmd->conn;
2449 SilcChannelEntry channel;
2453 if (cmd->argc != 2) {
2454 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2455 "Usage: /LEAVE <channel>");
2456 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2460 if (cmd->argv[1][0] == '*') {
2461 if (!conn->current_channel) {
2462 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2465 name = conn->current_channel->channel_name;
2467 name = cmd->argv[1];
2470 /* Get the channel entry */
2471 channel = silc_client_get_channel(conn->client, conn, name);
2473 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2477 idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
2479 /* Send LEAVE command to the server */
2480 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
2481 1, silc_buffer_datalen(idp));
2483 silc_buffer_free(idp);
2485 /* Notify application */
2486 COMMAND(SILC_STATUS_OK);
2488 if (conn->current_channel == channel)
2489 conn->current_channel = NULL;
2491 /** Wait for command reply */
2492 silc_fsm_next(fsm, silc_client_command_reply_wait);
2499 /********************************** USERS ***********************************/
2501 /* Command USERS. Requests the USERS of the clients joined on requested
2504 SILC_FSM_STATE(silc_client_command_users)
2506 SilcClientCommandContext cmd = fsm_context;
2507 SilcClientConnection conn = cmd->conn;
2510 if (cmd->argc != 2) {
2511 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2512 "Usage: /USERS <channel>");
2513 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2517 if (cmd->argv[1][0] == '*') {
2518 if (!conn->current_channel) {
2519 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2522 name = conn->current_channel->channel_name;
2524 name = cmd->argv[1];
2527 /* Send USERS command to the server */
2528 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
2529 2, name, strlen(name));
2531 /* Notify application */
2532 COMMAND(SILC_STATUS_OK);
2534 /** Wait for command reply */
2535 silc_fsm_next(fsm, silc_client_command_reply_wait);
2542 /********************************* GETKEY ***********************************/
2544 /* Command GETKEY. Used to fetch remote client's public key. */
2546 SILC_FSM_STATE(silc_client_command_getkey)
2548 SilcClientCommandContext cmd = fsm_context;
2549 SilcClientConnection conn = cmd->conn;
2550 SilcClient client = conn->client;
2551 SilcClientEntry client_entry;
2552 SilcServerEntry server_entry;
2554 char *nickname = NULL;
2557 if (cmd->argc < 2) {
2558 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2559 "Usage: /GETKEY <nickname or server name>");
2560 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2564 /* Parse the typed nickname. */
2565 if (!silc_client_nickname_parse(client, conn, cmd->argv[1], &nickname)) {
2566 COMMAND_ERROR(SILC_STATUS_ERR_RESOURCE_LIMIT);
2570 /* Find client entry */
2571 clients = silc_client_get_clients_local(client, conn, nickname,
2574 /* Check whether user requested server */
2575 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2576 if (!server_entry) {
2577 if (cmd->resolved) {
2578 /* Resolving didn't find anything. We should never get here as
2579 errors are handled in the resolving callback. */
2580 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2581 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_SERVER);
2585 /* No client or server exist with this name, query for both. */
2586 cmd->resolved = TRUE;
2587 SILC_FSM_CALL(silc_client_command_send(client, conn,
2588 SILC_COMMAND_IDENTIFY,
2589 silc_client_command_continue,
2592 strlen(cmd->argv[1]),
2594 strlen(cmd->argv[1])));
2597 idp = silc_id_payload_encode(&server_entry->id, SILC_ID_SERVER);
2598 silc_client_unref_server(client, conn, server_entry);
2600 client_entry = silc_dlist_get(clients);
2601 idp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT);
2602 silc_client_list_free(client, conn, clients);
2605 /* Send the commmand */
2606 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
2607 1, silc_buffer_datalen(idp));
2609 silc_buffer_free(idp);
2610 silc_free(nickname);
2612 /* Notify application */
2613 COMMAND(SILC_STATUS_OK);
2615 /** Wait for command reply */
2616 silc_fsm_next(fsm, silc_client_command_reply_wait);
2620 /********************************* SERVICE **********************************/
2622 /* Command SERVICE. Negotiates service agreement with server. */
2623 /* XXX incomplete */
2625 SILC_FSM_STATE(silc_client_command_service)
2627 SilcClientCommandContext cmd = fsm_context;
2629 SilcClientConnection conn = cmd->conn;
2633 if (cmd->argc < 2) {
2634 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2635 "Usage: /SERVICE [<service name>] [-pubkey]");
2636 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2640 name = cmd->argv[1];
2642 /* Send SERVICE command to the server */
2643 buffer = silc_command_payload_encode_va(SILC_COMMAND_SERVICE,
2644 ++conn->cmd_ident, 1,
2645 1, name, strlen(name));
2646 silc_client_packet_send(conn->client, conn->sock, SILC_PACKET_COMMAND,
2647 NULL, 0, NULL, NULL, buffer->data,
2649 silc_buffer_free(buffer);
2652 /* Notify application */
2653 COMMAND(SILC_STATUS_OK);
2655 /** Wait for command reply */
2656 silc_fsm_next(fsm, silc_client_command_reply_wait);
2660 /* Register all default commands provided by the client library for the
2663 void silc_client_commands_register(SilcClient client)
2665 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2668 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 5);
2669 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2670 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2671 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2672 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2673 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2674 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2675 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2676 SILC_CLIENT_CMD(kill, KILL, "KILL", 4);
2677 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2678 SILC_CLIENT_CMD(stats, STATS, "STATS", 0);
2679 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2680 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2681 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2682 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2683 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2684 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 6);
2685 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 9);
2686 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2687 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2688 SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2689 SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
2690 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2691 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2692 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2693 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2694 SILC_CLIENT_CMD(service, SERVICE, "SERVICE", 10);
2697 /* Unregister all commands. */
2699 void silc_client_commands_unregister(SilcClient client)
2701 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2702 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2703 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2704 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2705 SILC_CLIENT_CMDU(list, LIST, "LIST");
2706 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2707 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2708 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2709 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2710 SILC_CLIENT_CMDU(info, INFO, "INFO");
2711 SILC_CLIENT_CMDU(stats, STATS, "STATS");
2712 SILC_CLIENT_CMDU(ping, PING, "PING");
2713 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2714 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2715 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2716 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2717 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2718 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2719 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2720 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2721 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2722 SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2723 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2724 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2725 SILC_CLIENT_CMDU(users, USERS, "USERS");
2726 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2727 SILC_CLIENT_CMDU(service, SERVICE, "SERVICE");
2730 /****************** Client Side Incoming Command Handling *******************/
2732 /* Reply to WHOIS command from server */
2734 static void silc_client_command_process_whois(SilcClient client,
2735 SilcClientConnection conn,
2736 SilcCommandPayload payload,
2737 SilcArgumentPayload args)
2743 SilcBuffer buffer, packet;
2745 SILC_LOG_DEBUG(("Received WHOIS command"));
2747 /* Try to take the Requested Attributes */
2748 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
2752 attrs = silc_attribute_payload_parse(tmp, tmp_len);
2756 /* Process requested attributes */
2757 buffer = silc_client_attributes_process(client, conn, attrs);
2759 silc_attribute_payload_list_free(attrs);
2763 /* Send the attributes back */
2765 silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
2767 silc_command_get_ident(payload),
2768 1, 11, buffer->data, buffer->len);
2769 silc_client_packet_send(client, sock, SILC_PACKET_COMMAND_REPLY,
2770 NULL, 0, NULL, NULL, packet->data,
2772 silc_buffer_free(packet);
2773 silc_buffer_free(buffer);
2777 /* Client is able to receive some command packets even though they are
2778 special case. Server may send WHOIS command to the client to retrieve
2779 Requested Attributes information for WHOIS query the server is
2780 processing. This function currently handles only the WHOIS command,
2781 but if in the future more commands may arrive then this can be made
2782 to support other commands too. */
2784 SILC_FSM_STATE(silc_client_command)
2786 SilcClientConnection conn = fsm_context;
2787 SilcClient client = conn->client;
2788 SilcPacket packet = state_context;
2789 SilcCommandPayload payload;
2790 SilcCommand command;
2791 SilcArgumentPayload args;
2793 /* Get command payload from packet */
2794 payload = silc_command_payload_parse(packet->buffer.data,
2795 silc_buffer_len(&packet->buffer));
2797 SILC_LOG_DEBUG(("Bad command packet"));
2802 args = silc_command_get_args(payload);
2804 /* Get the command */
2805 command = silc_command_get(payload);
2808 case SILC_COMMAND_WHOIS:
2809 /* Ignore everything if requested by application */
2810 if (conn->internal->params.ignore_requested_attributes)
2813 silc_client_command_process_whois(client, conn, payload, args);
2820 silc_command_payload_free(payload);