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 /* Add pending reply */
242 silc_list_add(conn->internal->pending_commands, cmd);
244 silc_mutex_unlock(conn->internal->lock);
249 /* Generic function to send any command. The arguments must be sent already
250 encoded into correct format and in correct order. Arguments come from
251 variable argument list pointer. */
253 static SilcUInt16 silc_client_command_send_vap(SilcClient client,
254 SilcClientConnection conn,
255 SilcClientCommandContext cmd,
257 SilcClientCommandReply reply,
259 SilcUInt32 argc, va_list ap)
263 SILC_LOG_DEBUG(("Send command %s", silc_get_command_name(command)));
266 cmd->cmd_ident = silc_client_cmd_ident(conn);
268 /* Encode command payload */
269 packet = silc_command_payload_encode_vap(command, cmd->cmd_ident, argc, ap);
273 /* Send the command */
274 if (!silc_packet_send(conn->stream, SILC_PACKET_COMMAND, 0,
275 silc_buffer_datalen(packet))) {
276 silc_buffer_free(packet);
280 /* Add the command pending command reply */
281 silc_client_command_add_pending(conn, cmd, reply, reply_context);
283 silc_buffer_free(packet);
285 return cmd->cmd_ident;
288 /* Generic function to send any command. The arguments must be sent already
289 encoded into correct format and in correct order. Arguments come from
293 silc_client_command_send_arg_array(SilcClient client,
294 SilcClientConnection conn,
295 SilcClientCommandContext cmd,
297 SilcClientCommandReply reply,
300 unsigned char **argv,
301 SilcUInt32 *argv_lens,
302 SilcUInt32 *argv_types)
306 SILC_LOG_DEBUG(("Send command %s", silc_get_command_name(command)));
309 cmd->cmd_ident = silc_client_cmd_ident(conn);
311 /* Encode command payload */
312 packet = silc_command_payload_encode(command, argc, argv, argv_lens,
313 argv_types, cmd->cmd_ident);
317 /* Send the command */
318 if (!silc_packet_send(conn->stream, SILC_PACKET_COMMAND, 0,
319 silc_buffer_datalen(packet))) {
320 silc_buffer_free(packet);
324 /* Add the command pending command reply */
325 silc_client_command_add_pending(conn, cmd, reply, reply_context);
327 silc_buffer_free(packet);
329 return cmd->cmd_ident;
332 /* Generic function to send any command. The arguments must be sent already
333 encoded into correct format and in correct order. This is used internally
336 static SilcUInt16 silc_client_command_send_va(SilcClientConnection conn,
337 SilcClientCommandContext cmd,
339 SilcClientCommandReply reply,
341 SilcUInt32 argc, ...)
344 SilcUInt16 cmd_ident;
347 cmd_ident = silc_client_command_send_vap(conn->client, conn, cmd, command,
348 reply, reply_context, argc, ap);
354 /****************************** Command API *********************************/
356 /* Executes a command */
358 SilcUInt16 silc_client_command_call(SilcClient client,
359 SilcClientConnection conn,
360 const char *command_line, ...)
364 unsigned char **argv = NULL;
365 SilcUInt32 *argv_lens = NULL, *argv_types = NULL;
366 SilcClientCommand command;
367 SilcClientCommandContext cmd;
371 client->internal->ops->say(client, NULL, SILC_CLIENT_MESSAGE_ERROR,
372 "You are not connected to a server, please connect to server");
376 /* Parse arguments */
377 va_start(va, command_line);
381 /* Get command name */
382 command_name = silc_memdup(command_line, strcspn(command_line, " "));
386 /* Find command by name */
387 command = silc_client_command_find(client, command_name);
389 silc_free(command_name);
393 /* Parse command line */
394 silc_parse_command_line((char *)command_line, &argv, &argv_lens,
395 &argv_types, &argc, command->max_args);
397 silc_free(command_name);
399 arg = va_arg(va, char *);
403 /* Find command by name */
404 command = silc_client_command_find(client, arg);
409 argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
410 argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) * (argc + 1));
411 argv_types = silc_realloc(argv_types, sizeof(*argv_types) * (argc + 1));
412 if (!argv || !argv_lens || !argv_types)
414 argv[argc] = silc_memdup(arg, strlen(arg));
417 argv_lens[argc] = strlen(arg);
418 argv_types[argc] = argc;
420 arg = va_arg(va, char *);
425 /* Allocate command context */
426 cmd = silc_calloc(1, sizeof(*cmd));
430 cmd->cmd = command->cmd;
433 cmd->argv_lens = argv_lens;
434 cmd->argv_types = argv_types;
435 cmd->cmd_ident = silc_client_cmd_ident(conn);
440 SILC_LOG_DEBUG(("Calling %s command", silc_get_command_name(cmd->cmd)));
441 silc_fsm_thread_init(&cmd->thread, &conn->internal->fsm, cmd,
442 silc_client_command_destructor, NULL, FALSE);
443 silc_fsm_start_sync(&cmd->thread, command->command);
445 return cmd->cmd_ident;
448 /* Generic function to send any command. The arguments must be sent already
449 encoded into correct format and in correct order. */
451 SilcUInt16 silc_client_command_send(SilcClient client,
452 SilcClientConnection conn,
454 SilcClientCommandReply reply,
456 SilcUInt32 argc, ...)
458 SilcClientCommandContext cmd;
464 /* Allocate command context */
465 cmd = silc_calloc(1, sizeof(*cmd));
471 /* Send the command */
474 silc_client_command_send_vap(client, conn, cmd, command, reply,
475 reply_context, argc, ap);
478 if (!cmd->cmd_ident) {
479 silc_client_command_free(cmd);
483 /*** Wait for command reply */
484 silc_fsm_thread_init(&cmd->thread, &conn->internal->fsm, cmd,
485 silc_client_command_destructor, NULL, FALSE);
486 silc_fsm_start_sync(&cmd->thread, silc_client_command_reply_wait);
488 return cmd->cmd_ident;
491 /* Generic function to send any command. The arguments must be sent already
492 encoded into correct format and in correct order. Arguments come from
495 SilcUInt16 silc_client_command_send_argv(SilcClient client,
496 SilcClientConnection conn,
498 SilcClientCommandReply reply,
501 unsigned char **argv,
502 SilcUInt32 *argv_lens,
503 SilcUInt32 *argv_types)
505 SilcClientCommandContext cmd;
510 /* Allocate command context */
511 cmd = silc_calloc(1, sizeof(*cmd));
517 /* Send the command */
519 silc_client_command_send_arg_array(client, conn, cmd, command, reply,
520 reply_context, argc, argv, argv_lens,
522 if (!cmd->cmd_ident) {
523 silc_client_command_free(cmd);
527 /*** Wait for command reply */
528 silc_fsm_thread_init(&cmd->thread, &conn->internal->fsm, cmd,
529 silc_client_command_destructor, NULL, FALSE);
530 silc_fsm_start_sync(&cmd->thread, silc_client_command_reply_wait);
532 return cmd->cmd_ident;
535 /* Attach to a command and command identifier to receive command reply. */
537 SilcBool silc_client_command_pending(SilcClientConnection conn,
540 SilcClientCommandReply reply,
543 SilcClientCommandContext cmd;
544 SilcClientCommandReplyCallback cb;
549 SILC_LOG_DEBUG(("Add pending command reply for ident %d", ident));
551 silc_mutex_lock(conn->internal->lock);
553 /* Find the pending command */
554 silc_list_start(conn->internal->pending_commands);
555 while ((cmd = silc_list_get(conn->internal->pending_commands)))
556 if ((cmd->cmd == command || command == SILC_COMMAND_NONE)
557 && cmd->cmd_ident == ident) {
559 /* Add the callback */
560 cb = silc_calloc(1, sizeof(*cb));
564 cb->context = context;
565 silc_list_add(cmd->reply_callbacks, cb);
568 silc_mutex_unlock(conn->internal->lock);
573 /******************************** WHOIS *************************************/
575 /* Command WHOIS. This command is used to query information about
578 SILC_FSM_STATE(silc_client_command_whois)
580 SilcClientCommandContext cmd = fsm_context;
581 SilcClientConnection conn = cmd->conn;
582 SilcClient client = conn->client;
583 SilcBuffer attrs = NULL;
584 unsigned char count[4], *tmp = NULL;
585 SilcBool details = FALSE, nick = FALSE;
586 unsigned char *pubkey = NULL;
589 /* Given without arguments fetches client's own information */
591 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1, 4,
592 silc_buffer_data(conn->internal->local_idp),
593 silc_buffer_len(conn->internal->local_idp));
595 /* Notify application */
596 COMMAND(SILC_STATUS_OK);
598 /** Wait for command reply */
599 silc_fsm_next(fsm, silc_client_command_reply_wait);
600 return SILC_FSM_CONTINUE;
603 for (i = 1; i < cmd->argc; i++) {
604 if (!strcasecmp(cmd->argv[i], "-details")) {
606 } else if (!strcasecmp(cmd->argv[i], "-pubkey") && cmd->argc > i + 1) {
607 pubkey = cmd->argv[i + 1];
610 /* We assume that the first parameter is the nickname, if it isn't
611 -details or -pubkey. The last parameter should always be the count */
614 } else if (i == cmd->argc - 1) {
615 int c = atoi(cmd->argv[i]);
616 SILC_PUT32_MSB(c, count);
623 /* If pubkey is set, add all attributes to the attrs buffer, except
626 attrs = silc_client_attributes_request(SILC_ATTRIBUTE_USER_INFO,
627 SILC_ATTRIBUTE_SERVICE,
628 SILC_ATTRIBUTE_STATUS_MOOD,
629 SILC_ATTRIBUTE_STATUS_FREETEXT,
630 SILC_ATTRIBUTE_STATUS_MESSAGE,
631 SILC_ATTRIBUTE_PREFERRED_LANGUAGE,
632 SILC_ATTRIBUTE_PREFERRED_CONTACT,
633 SILC_ATTRIBUTE_TIMEZONE,
634 SILC_ATTRIBUTE_GEOLOCATION,
635 SILC_ATTRIBUTE_DEVICE_INFO,
636 SILC_ATTRIBUTE_USER_ICON, 0);
638 attrs = silc_client_attributes_request(0);
643 SilcAttributeObjPk obj;
646 if (!silc_pkcs_load_public_key(pubkey, &pk)) {
647 SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR,
648 "Could not load public key %s, check the filename",
650 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
654 switch (silc_pkcs_get_type(pk)) {
656 obj.type = "silc-rsa";
659 obj.type = "ssh-rsa";
661 case SILC_PKCS_X509V3:
662 obj.type = "x509v3-sign-rsa";
664 case SILC_PKCS_OPENPGP:
665 obj.type = "pgp-sign-rsa";
671 obj.data = silc_pkcs_public_key_encode(pk, &obj.data_len);
673 attrs = silc_attribute_payload_encode(attrs,
674 SILC_ATTRIBUTE_USER_PUBLIC_KEY,
675 SILC_ATTRIBUTE_FLAG_VALID,
680 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
681 3, 1, nick ? cmd->argv[1] : NULL,
682 nick ? cmd->argv_lens[1] : 0,
683 2, tmp ? tmp : NULL, tmp ? 4 : 0,
684 3, silc_buffer_datalen(attrs));
686 /* Notify application */
687 COMMAND(SILC_STATUS_OK);
689 /** Wait for command reply */
690 silc_fsm_next(fsm, silc_client_command_reply_wait);
691 return SILC_FSM_CONTINUE;
694 return SILC_FSM_FINISH;
697 /******************************** WHOWAS ************************************/
699 /* Command WHOWAS. This command is used to query history information about
700 specific user that used to exist in the network. */
702 SILC_FSM_STATE(silc_client_command_whowas)
704 SilcClientCommandContext cmd = fsm_context;
705 SilcClientConnection conn = cmd->conn;
706 unsigned char count[4];
709 if (cmd->argc < 2 || cmd->argc > 3) {
710 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
711 "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
712 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
713 SILC_STATUS_ERR_TOO_MANY_PARAMS));
714 return SILC_FSM_FINISH;
717 if (cmd->argc == 2) {
718 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
719 1, 1, cmd->argv[1], cmd->argv_lens[1]);
721 c = atoi(cmd->argv[2]);
722 SILC_PUT32_MSB(c, count);
723 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
724 2, 1, cmd->argv[1], cmd->argv_lens[1],
725 2, count, sizeof(count));
728 /* Notify application */
729 COMMAND(SILC_STATUS_OK);
731 /** Wait for command reply */
732 silc_fsm_next(fsm, silc_client_command_reply_wait);
733 return SILC_FSM_CONTINUE;
736 /******************************** IDENTIFY **********************************/
738 /* Command IDENTIFY. This command is used to query information about
739 specific user, especially ID's. */
741 SILC_FSM_STATE(silc_client_command_identify)
743 SilcClientCommandContext cmd = fsm_context;
744 SilcClientConnection conn = cmd->conn;
745 unsigned char count[4];
748 if (cmd->argc < 2 || cmd->argc > 3)
749 return SILC_FSM_FINISH;
751 if (cmd->argc == 2) {
752 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
753 1, 1, cmd->argv[1], cmd->argv_lens[1]);
755 c = atoi(cmd->argv[2]);
756 SILC_PUT32_MSB(c, count);
757 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
758 2, 1, cmd->argv[1], cmd->argv_lens[1],
759 4, count, sizeof(count));
762 /** Wait for command reply */
763 silc_fsm_next(fsm, silc_client_command_reply_wait);
764 return SILC_FSM_CONTINUE;
767 /********************************** NICK ************************************/
769 /* Command NICK. Shows current nickname/sets new nickname on current
772 SILC_FSM_STATE(silc_client_command_nick)
774 SilcClientCommandContext cmd = fsm_context;
775 SilcClientConnection conn = cmd->conn;
778 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
779 "Usage: /NICK <nickname>");
780 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
784 if (silc_utf8_strcasecmp(conn->local_entry->nickname, cmd->argv[1]))
787 /* Show current nickname */
790 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
791 "Your nickname is %s on server %s",
792 conn->local_entry->nickname, conn->remote_host);
794 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
795 "Your nickname is %s", conn->local_entry->nickname);
798 COMMAND(SILC_STATUS_OK);
802 if (cmd->argv_lens[1] > 128)
803 cmd->argv_lens[1] = 128;
805 /* Send the NICK command */
806 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
807 1, 1, cmd->argv[1], cmd->argv_lens[1]);
809 /* Notify application */
810 COMMAND(SILC_STATUS_OK);
812 /** Wait for command reply */
813 silc_fsm_next(fsm, silc_client_command_reply_wait);
814 return SILC_FSM_CONTINUE;
817 return SILC_FSM_FINISH;
820 /********************************** LIST ************************************/
822 /* Command LIST. Lists channels on the current server. */
824 SILC_FSM_STATE(silc_client_command_list)
826 SilcClientCommandContext cmd = fsm_context;
827 SilcClientConnection conn = cmd->conn;
828 SilcChannelEntry channel;
829 SilcBuffer idp = NULL;
831 if (cmd->argc == 2) {
832 /* Get the Channel ID of the channel */
833 channel = silc_client_get_channel(conn->client, cmd->conn, cmd->argv[1]);
835 idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
839 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
841 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
842 1, 1, silc_buffer_datalen(idp));
844 silc_buffer_free(idp);
846 /* Notify application */
847 COMMAND(SILC_STATUS_OK);
849 /** Wait for command reply */
850 silc_fsm_next(fsm, silc_client_command_reply_wait);
851 return SILC_FSM_CONTINUE;
854 /********************************** TOPIC ***********************************/
856 /* Command TOPIC. Sets/shows topic on a channel. */
858 SILC_FSM_STATE(silc_client_command_topic)
860 SilcClientCommandContext cmd = fsm_context;
861 SilcClientConnection conn = cmd->conn;
862 SilcChannelEntry channel;
866 if (cmd->argc < 2 || cmd->argc > 3) {
867 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
868 "Usage: /TOPIC <channel> [<topic>]");
869 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
870 SILC_STATUS_ERR_TOO_MANY_PARAMS));
874 if (cmd->argv[1][0] == '*') {
875 if (!conn->current_channel) {
876 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
879 name = conn->current_channel->channel_name;
884 if (!conn->current_channel) {
885 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
889 /* Get the Channel ID of the channel */
890 channel = silc_client_get_channel(conn->client, conn, name);
892 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
896 idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
898 /* Send TOPIC command to the server */
900 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
901 1, silc_buffer_datalen(idp),
902 2, cmd->argv[2], strlen(cmd->argv[2]));
904 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
905 1, silc_buffer_datalen(idp));
907 silc_buffer_free(idp);
909 /* Notify application */
910 COMMAND(SILC_STATUS_OK);
912 /** Wait for command reply */
913 silc_fsm_next(fsm, silc_client_command_reply_wait);
914 return SILC_FSM_CONTINUE;
917 return SILC_FSM_FINISH;
920 /********************************* INVITE ***********************************/
922 /* Command INVITE. Invites specific client to join a channel. This is
923 also used to mange the invite list of the channel. */
925 SILC_FSM_STATE(silc_client_command_invite)
927 SilcClientCommandContext cmd = fsm_context;
928 SilcClientConnection conn = cmd->conn;
929 SilcClient client = conn->client;
930 SilcClientEntry client_entry = NULL;
931 SilcChannelEntry channel;
932 SilcBuffer clidp, chidp, args = NULL;
933 SilcPublicKey pubkey = NULL;
934 SilcDList clients = NULL;
935 char *nickname = NULL, *name;
937 unsigned char action[1];
940 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
941 "Usage: /INVITE <channel> [<nickname>[@server>]"
942 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
943 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
947 if (cmd->argv[1][0] == '*') {
948 if (!conn->current_channel) {
949 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
953 channel = conn->current_channel;
957 channel = silc_client_get_channel(conn->client, conn, name);
959 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
964 /* Parse the typed nickname. */
965 if (cmd->argc == 3) {
966 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
967 if (client->internal->params->nickname_parse)
968 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
970 nickname = strdup(cmd->argv[2]);
972 /* Find client entry */
973 clients = silc_client_get_clients_local(client, conn, nickname,
976 /* Resolve client information */
977 SILC_FSM_CALL(silc_client_get_clients(
978 client, conn, nickname,
980 silc_client_command_resolve_continue,
983 client_entry = silc_dlist_get(clients);
985 if (cmd->argv[2][0] == '+')
990 /* Check if it is public key file to be added to invite list */
991 silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey);
992 invite = cmd->argv[2];
999 args = silc_buffer_alloc_size(2);
1000 silc_buffer_format(args,
1001 SILC_STR_UI_SHORT(1),
1004 chidp = silc_public_key_payload_encode(pubkey);
1005 args = silc_argument_payload_encode_one(args, silc_buffer_data(chidp),
1006 silc_buffer_len(chidp), 2);
1007 silc_buffer_free(chidp);
1008 silc_pkcs_public_key_free(pubkey);
1010 args = silc_argument_payload_encode_one(args, invite, strlen(invite), 1);
1014 /* Send the command */
1015 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
1017 clidp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT);
1018 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 4,
1019 1, silc_buffer_datalen(chidp),
1020 2, silc_buffer_datalen(clidp),
1021 3, args ? action : NULL, args ? 1 : 0,
1022 4, silc_buffer_datalen(args));
1023 silc_buffer_free(clidp);
1025 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
1026 1, silc_buffer_datalen(chidp),
1027 3, args ? action : NULL, args ? 1 : 0,
1028 4, silc_buffer_datalen(args));
1031 silc_buffer_free(chidp);
1032 silc_buffer_free(args);
1033 silc_free(nickname);
1034 silc_client_list_free(client, conn, clients);
1036 /* Notify application */
1037 COMMAND(SILC_STATUS_OK);
1039 /** Wait for command reply */
1040 silc_fsm_next(fsm, silc_client_command_reply_wait);
1041 return SILC_FSM_CONTINUE;
1044 silc_free(nickname);
1045 return SILC_FSM_FINISH;
1048 /********************************** QUIT ************************************/
1050 /* Close the connection */
1052 SILC_FSM_STATE(silc_client_command_quit_final)
1054 SilcClientCommandContext cmd = fsm_context;
1055 SilcClientConnection conn = cmd->conn;
1056 SilcClient client = conn->client;
1058 /* Notify application */
1059 COMMAND(SILC_STATUS_OK);
1061 /* Call connection callback */
1062 conn->callback(client, conn, SILC_CLIENT_CONN_DISCONNECTED,
1063 0, NULL, conn->callback_context);
1065 /* Signal to close connection */
1066 conn->internal->disconnected = TRUE;
1067 SILC_FSM_SEMA_POST(&conn->internal->wait_event);
1069 return SILC_FSM_FINISH;
1072 /* Command QUIT. Closes connection with current server. */
1074 SILC_FSM_STATE(silc_client_command_quit)
1076 SilcClientCommandContext cmd = fsm_context;
1077 SilcClientConnection conn = cmd->conn;
1080 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1081 1, cmd->argv[1], cmd->argv_lens[1]);
1083 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
1085 /* Sleep for a while */
1088 /* We close the connection with a little timeout */
1089 silc_fsm_next_later(fsm, silc_client_command_quit_final, 2, 0);
1090 return SILC_FSM_WAIT;
1093 /********************************** KILL ************************************/
1096 /* Command KILL. Router operator can use this command to remove an client
1097 fromthe SILC Network. */
1099 SILC_FSM_STATE(silc_client_command_kill)
1101 SilcClientCommandContext cmd = fsm_context;
1102 SilcClientConnection conn = cmd->conn;
1103 SilcClient client = conn->client;
1104 SilcBuffer idp, auth = NULL;
1105 SilcClientEntry target;
1107 char *nickname = NULL, *comment = NULL;
1109 if (cmd->argc < 2) {
1110 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1111 "Usage: /KILL <nickname> [<comment>] [-pubkey]");
1112 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1113 return SILC_FSM_FINISH;
1116 /* Parse the typed nickname. */
1117 if (client->internal->params->nickname_parse)
1118 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
1120 nickname = strdup(cmd->argv[1]);
1122 return SILC_FSM_FINISH;
1124 /* Get the target client */
1125 clients = silc_client_get_clients_local(client, conn, nickname,
1128 /* Resolve client information */
1129 SILC_FSM_CALL(silc_client_get_clients(client, conn, nickname,
1131 silc_client_command_resolve_continue,
1134 target = silc_dlist_get(clients);
1136 if (cmd->argc >= 3) {
1137 if (strcasecmp(cmd->argv[2], "-pubkey"))
1138 comment = cmd->argv[2];
1140 if (!strcasecmp(cmd->argv[2], "-pubkey") ||
1141 (cmd->argc >= 4 && !strcasecmp(cmd->argv[3], "-pubkey"))) {
1142 /* Encode the public key authentication payload */
1143 auth = silc_auth_public_key_auth_generate(conn->public_key,
1146 conn->internal->sha1hash,
1147 &target->id, SILC_ID_CLIENT);
1151 /* Send the KILL command to the server */
1152 idp = silc_id_payload_encode(&target->id, SILC_ID_CLIENT);
1153 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
1154 1, silc_buffer_datalen(idp),
1155 2, comment, comment ? strlen(comment) : 0,
1156 3, silc_buffer_datalen(auth));
1157 silc_buffer_free(idp);
1158 silc_buffer_free(auth);
1159 silc_free(nickname);
1160 silc_client_list_free(client, conn, clients);
1162 /* Notify application */
1163 COMMAND(SILC_STATUS_OK);
1165 /** Wait for command reply */
1166 silc_fsm_next(fsm, silc_client_command_reply_wait);
1167 return SILC_FSM_CONTINUE;
1170 /********************************** INFO ************************************/
1172 /* Command INFO. Request information about specific server. If specific
1173 server is not provided the current server is used. */
1175 SILC_FSM_STATE(silc_client_command_info)
1177 SilcClientCommandContext cmd = fsm_context;
1178 SilcClientConnection conn = cmd->conn;
1180 /* Send the command */
1182 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1183 1, cmd->argv[1], cmd->argv_lens[1]);
1185 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
1187 /* Notify application */
1188 COMMAND(SILC_STATUS_OK);
1190 /** Wait for command reply */
1191 silc_fsm_next(fsm, silc_client_command_reply_wait);
1192 return SILC_FSM_CONTINUE;
1195 /********************************** STATS ***********************************/
1197 /* Command STATS. Shows server and network statistics. */
1199 SILC_FSM_STATE(silc_client_command_stats)
1201 SilcClientCommandContext cmd = fsm_context;
1202 SilcClientConnection conn = cmd->conn;
1204 /* Send the command */
1205 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1206 1, silc_buffer_datalen(conn->internal->
1209 /* Notify application */
1210 COMMAND(SILC_STATUS_OK);
1212 /** Wait for command reply */
1213 silc_fsm_next(fsm, silc_client_command_reply_wait);
1214 return SILC_FSM_CONTINUE;
1217 /********************************** PING ************************************/
1219 /* Command PING. Sends ping to server. */
1221 SILC_FSM_STATE(silc_client_command_ping)
1223 SilcClientCommandContext cmd = fsm_context;
1224 SilcClientConnection conn = cmd->conn;
1226 if (cmd->argc < 2) {
1227 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1228 return SILC_FSM_FINISH;
1231 /* Send the command */
1232 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1233 1, silc_buffer_datalen(conn->internal->
1236 /* Save ping time */
1237 cmd->context = SILC_64_TO_PTR(silc_time());
1239 /* Notify application */
1240 COMMAND(SILC_STATUS_OK);
1242 /** Wait for command reply */
1243 silc_fsm_next(fsm, silc_client_command_reply_wait);
1244 return SILC_FSM_CONTINUE;
1247 /********************************** JOIN ************************************/
1249 /* Command JOIN. Joins to a channel. */
1251 SILC_FSM_STATE(silc_client_command_join)
1253 SilcClientCommandContext cmd = fsm_context;
1254 SilcClientConnection conn = cmd->conn;
1255 SilcChannelEntry channel;
1256 SilcBuffer auth = NULL, cauth = NULL;
1257 char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
1258 int i, passphrase_len = 0;
1260 if (cmd->argc < 2) {
1261 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1265 /* See if we have joined to the requested channel already */
1266 channel = silc_client_get_channel(conn->client, conn, cmd->argv[1]);
1267 if (channel && silc_client_on_channel(channel, conn->local_entry))
1270 if (cmd->argv_lens[1] > 256)
1271 cmd->argv_lens[1] = 256;
1273 name = cmd->argv[1];
1275 for (i = 2; i < cmd->argc; i++) {
1276 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
1277 cipher = cmd->argv[++i];
1278 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
1279 hmac = cmd->argv[++i];
1280 } else if (!strcasecmp(cmd->argv[i], "-founder")) {
1281 auth = silc_auth_public_key_auth_generate(conn->public_key,
1284 conn->internal->sha1hash,
1287 } else if (!strcasecmp(cmd->argv[i], "-auth")) {
1288 SilcPublicKey pubkey = conn->public_key;
1289 SilcPrivateKey privkey = conn->private_key;
1290 unsigned char *pk, pkhash[SILC_HASH_MAXLEN], *pubdata;
1293 if (cmd->argc >= i + 3) {
1295 if (cmd->argc >= i + 4) {
1296 pass = cmd->argv[i + 3];
1299 if (!silc_load_key_pair(cmd->argv[i + 1], cmd->argv[i + 2], pass,
1300 &pubkey, &privkey)) {
1301 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1302 "Could not load key pair, check your arguments");
1303 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1309 pk = silc_pkcs_public_key_encode(pubkey, &pk_len);
1310 silc_hash_make(conn->internal->sha1hash, pk, pk_len, pkhash);
1312 pubdata = silc_rng_get_rn_data(conn->client->rng, 128);
1313 memcpy(pubdata, pkhash, 20);
1314 cauth = silc_auth_public_key_auth_generate_wpub(pubkey, privkey,
1316 conn->internal->sha1hash,
1319 memset(pubdata, 0, 128);
1322 /* Passphrases must be UTF-8 encoded, so encode if it is not */
1323 if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
1324 passphrase_len = silc_utf8_encoded_len(cmd->argv[i],
1325 cmd->argv_lens[i], 0);
1326 pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
1327 passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
1328 0, pu8, passphrase_len);
1331 passphrase = strdup(cmd->argv[i]);
1332 passphrase_len = cmd->argv_lens[i];
1337 /* Send JOIN command to the server */
1338 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 7,
1339 1, name, strlen(name),
1340 2, silc_buffer_datalen(conn->internal->
1342 3, passphrase, passphrase_len,
1343 4, cipher, cipher ? strlen(cipher) : 0,
1344 5, hmac, hmac ? strlen(hmac) : 0,
1345 6, silc_buffer_datalen(auth),
1346 7, silc_buffer_datalen(cauth));
1348 silc_buffer_free(auth);
1349 silc_buffer_free(cauth);
1351 memset(passphrase, 0, strlen(passphrase));
1352 silc_free(passphrase);
1354 /* Notify application */
1355 COMMAND(SILC_STATUS_OK);
1357 /** Wait for command reply */
1358 silc_fsm_next(fsm, silc_client_command_reply_wait);
1359 return SILC_FSM_CONTINUE;
1362 return SILC_FSM_FINISH;
1365 /********************************** MOTD ************************************/
1367 /* MOTD command. Requests motd from server. */
1369 SILC_FSM_STATE(silc_client_command_motd)
1371 SilcClientCommandContext cmd = fsm_context;
1372 SilcClientConnection conn = cmd->conn;
1374 if (cmd->argc < 1 || cmd->argc > 2) {
1375 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1376 "Usage: /MOTD [<server>]");
1377 COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
1378 SILC_STATUS_ERR_TOO_MANY_PARAMS));
1379 return SILC_FSM_FINISH;
1382 /* Send the command */
1384 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1385 1, conn->remote_host,
1386 strlen(conn->remote_host));
1388 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1389 1, cmd->argv[1], cmd->argv_lens[1]);
1391 /* Notify application */
1392 COMMAND(SILC_STATUS_OK);
1394 /** Wait for command reply */
1395 silc_fsm_next(fsm, silc_client_command_reply_wait);
1396 return SILC_FSM_CONTINUE;
1399 /********************************** UMODE ***********************************/
1401 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1402 modes as client cannot set itself server/router operator privileges. */
1404 SILC_FSM_STATE(silc_client_command_umode)
1406 SilcClientCommandContext cmd = fsm_context;
1407 SilcClientConnection conn = cmd->conn;
1408 unsigned char *cp, modebuf[4];
1409 SilcUInt32 mode, add, len;
1412 if (cmd->argc < 2) {
1413 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1414 "Usage: /UMODE +|-<modes>");
1415 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1416 return SILC_FSM_FINISH;
1419 mode = conn->local_entry->mode;
1421 /* Are we adding or removing mode */
1422 if (cmd->argv[1][0] == '-')
1428 cp = cmd->argv[1] + 1;
1430 for (i = 0; i < len; i++) {
1435 mode |= SILC_UMODE_SERVER_OPERATOR;
1436 mode |= SILC_UMODE_ROUTER_OPERATOR;
1437 mode |= SILC_UMODE_GONE;
1438 mode |= SILC_UMODE_INDISPOSED;
1439 mode |= SILC_UMODE_BUSY;
1440 mode |= SILC_UMODE_PAGE;
1441 mode |= SILC_UMODE_HYPER;
1442 mode |= SILC_UMODE_ROBOT;
1443 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1444 mode |= SILC_UMODE_REJECT_WATCHING;
1446 mode = SILC_UMODE_NONE;
1451 mode |= SILC_UMODE_SERVER_OPERATOR;
1453 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1457 mode |= SILC_UMODE_ROUTER_OPERATOR;
1459 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1463 mode |= SILC_UMODE_GONE;
1465 mode &= ~SILC_UMODE_GONE;
1469 mode |= SILC_UMODE_INDISPOSED;
1471 mode &= ~SILC_UMODE_INDISPOSED;
1475 mode |= SILC_UMODE_BUSY;
1477 mode &= ~SILC_UMODE_BUSY;
1481 mode |= SILC_UMODE_PAGE;
1483 mode &= ~SILC_UMODE_PAGE;
1487 mode |= SILC_UMODE_HYPER;
1489 mode &= ~SILC_UMODE_HYPER;
1493 mode |= SILC_UMODE_ROBOT;
1495 mode &= ~SILC_UMODE_ROBOT;
1499 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1501 mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
1505 mode |= SILC_UMODE_REJECT_WATCHING;
1507 mode &= ~SILC_UMODE_REJECT_WATCHING;
1511 mode |= SILC_UMODE_BLOCK_INVITE;
1513 mode &= ~SILC_UMODE_BLOCK_INVITE;
1516 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1517 return SILC_FSM_FINISH;
1522 SILC_PUT32_MSB(mode, modebuf);
1524 /* Send the command */
1525 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
1526 1, silc_buffer_datalen(conn->internal->
1528 2, modebuf, sizeof(modebuf));
1530 /* Notify application */
1531 COMMAND(SILC_STATUS_OK);
1533 /** Wait for command reply */
1534 silc_fsm_next(fsm, silc_client_command_reply_wait);
1535 return SILC_FSM_CONTINUE;
1538 /********************************** CMODE ***********************************/
1540 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1541 can be set several at once. Those modes that require argument must be set
1542 separately (unless set with modes that does not require arguments). */
1544 SILC_FSM_STATE(silc_client_command_cmode)
1546 SilcClientCommandContext cmd = fsm_context;
1547 SilcClientConnection conn = cmd->conn;
1548 SilcClient client = conn->client;
1549 SilcChannelEntry channel;
1550 SilcBuffer chidp, auth = NULL, pk = NULL;
1551 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1552 SilcUInt32 mode, add, type, len, arg_len = 0;
1555 if (cmd->argc < 3) {
1556 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1557 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1558 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1562 if (cmd->argv[1][0] == '*') {
1563 if (!conn->current_channel) {
1564 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1568 channel = conn->current_channel;
1570 name = cmd->argv[1];
1572 channel = silc_client_get_channel(conn->client, conn, name);
1574 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1579 mode = channel->mode;
1581 /* Are we adding or removing mode */
1582 if (cmd->argv[2][0] == '-')
1587 /* Argument type to be sent to server */
1591 cp = cmd->argv[2] + 1;
1593 for (i = 0; i < len; i++) {
1597 mode |= SILC_CHANNEL_MODE_PRIVATE;
1599 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1603 mode |= SILC_CHANNEL_MODE_SECRET;
1605 mode &= ~SILC_CHANNEL_MODE_SECRET;
1609 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1611 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1615 mode |= SILC_CHANNEL_MODE_INVITE;
1617 mode &= ~SILC_CHANNEL_MODE_INVITE;
1621 mode |= SILC_CHANNEL_MODE_TOPIC;
1623 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1627 mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1629 mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1633 mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1635 mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1640 mode |= SILC_CHANNEL_MODE_ULIMIT;
1642 if (cmd->argc < 4) {
1643 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1644 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1645 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1648 ll = atoi(cmd->argv[3]);
1649 SILC_PUT32_MSB(ll, tmp);
1653 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1658 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1660 if (cmd->argc < 4) {
1661 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1662 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1663 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1667 arg_len = cmd->argv_lens[3];
1669 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1674 mode |= SILC_CHANNEL_MODE_CIPHER;
1676 if (cmd->argc < 4) {
1677 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1678 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1679 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1683 arg_len = cmd->argv_lens[3];
1685 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1690 mode |= SILC_CHANNEL_MODE_HMAC;
1692 if (cmd->argc < 4) {
1693 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1694 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1695 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1699 arg_len = cmd->argv_lens[3];
1701 mode &= ~SILC_CHANNEL_MODE_HMAC;
1706 SilcPublicKey pubkey = conn->public_key;
1707 SilcPrivateKey privkey = conn->private_key;
1709 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1712 if (cmd->argc >= 5) {
1715 pass = cmd->argv[5];
1716 if (!silc_load_key_pair(cmd->argv[3], cmd->argv[4], pass,
1717 &pubkey, &privkey)) {
1718 SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1719 "Could not load key pair, check your arguments");
1720 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1725 pk = silc_public_key_payload_encode(pubkey);
1726 auth = silc_auth_public_key_auth_generate(pubkey, privkey,
1728 conn->internal->sha1hash,
1731 arg = silc_buffer_data(auth);
1732 arg_len = silc_buffer_len(auth);
1734 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1740 SilcBool chadd = FALSE;
1741 SilcPublicKey chpk = NULL;
1743 mode |= SILC_CHANNEL_MODE_CHANNEL_AUTH;
1746 if (cmd->argc == 3) {
1747 /* Send empty command to receive the public key list. */
1748 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
1749 silc_client_command_send_va(conn, cmd, SILC_COMMAND_CMODE,
1751 1, silc_buffer_datalen(chidp));
1752 silc_buffer_free(chidp);
1754 /* Notify application */
1755 COMMAND(SILC_STATUS_OK);
1759 if (cmd->argc >= 4) {
1760 auth = silc_buffer_alloc_size(2);
1761 silc_buffer_format(auth,
1762 SILC_STR_UI_SHORT(cmd->argc - 3),
1766 for (k = 3; k < cmd->argc; k++) {
1767 if (cmd->argv[k][0] == '+')
1769 if (!silc_pkcs_load_public_key(cmd->argv[k] + 1, &chpk)) {
1770 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1771 "Could not load public key %s, check the filename",
1773 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1774 silc_buffer_free(auth);
1779 pk = silc_public_key_payload_encode(chpk);
1780 auth = silc_argument_payload_encode_one(auth,
1781 silc_buffer_datalen(pk),
1782 chadd ? 0x00 : 0x01);
1783 silc_pkcs_public_key_free(chpk);
1784 silc_buffer_free(pk);
1789 arg = silc_buffer_data(auth);
1790 arg_len = silc_buffer_len(auth);
1792 mode &= ~SILC_CHANNEL_MODE_CHANNEL_AUTH;
1796 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1802 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
1803 SILC_PUT32_MSB(mode, modebuf);
1805 /* Send the command. We support sending only one mode at once that
1806 requires an argument. */
1808 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 4,
1809 1, silc_buffer_datalen(chidp),
1810 2, modebuf, sizeof(modebuf),
1812 8, silc_buffer_datalen(pk));
1814 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
1815 1, silc_buffer_datalen(chidp),
1816 2, modebuf, sizeof(modebuf));
1819 silc_buffer_free(chidp);
1820 silc_buffer_free(auth);
1821 silc_buffer_free(pk);
1823 /* Notify application */
1824 COMMAND(SILC_STATUS_OK);
1826 /** Wait for command reply */
1827 silc_fsm_next(fsm, silc_client_command_reply_wait);
1828 return SILC_FSM_CONTINUE;
1831 return SILC_FSM_FINISH;
1834 /********************************* CUMODE ***********************************/
1836 /* CUMODE command. Changes client's mode on a channel. */
1838 SILC_FSM_STATE(silc_client_command_cumode)
1840 SilcClientCommandContext cmd = fsm_context;
1841 SilcClientConnection conn = cmd->conn;
1842 SilcClient client = conn->client;
1843 SilcChannelEntry channel;
1844 SilcChannelUser chu;
1845 SilcClientEntry client_entry;
1846 SilcBuffer clidp, chidp, auth = NULL;
1847 SilcDList clients = NULL;
1848 unsigned char *name, *cp, modebuf[4];
1849 SilcUInt32 mode = 0, add, len;
1850 char *nickname = NULL;
1853 if (cmd->argc < 4) {
1854 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1855 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1856 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1860 if (cmd->argv[1][0] == '*') {
1861 if (!conn->current_channel) {
1862 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1866 channel = conn->current_channel;
1868 name = cmd->argv[1];
1870 channel = silc_client_get_channel(conn->client, conn, name);
1872 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1877 /* Parse the typed nickname. */
1878 if (client->internal->params->nickname_parse)
1879 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1881 nickname = strdup(cmd->argv[3]);
1883 /* Find client entry */
1884 clients = silc_client_get_clients_local(client, conn, nickname,
1887 /* Resolve client information */
1888 SILC_FSM_CALL(silc_client_get_clients(client, conn, nickname, cmd->argv[3],
1889 silc_client_command_resolve_continue,
1892 client_entry = silc_dlist_get(clients);
1894 /* Get the current mode */
1895 chu = silc_client_on_channel(channel, client_entry);
1899 /* Are we adding or removing mode */
1900 if (cmd->argv[2][0] == '-')
1906 cp = cmd->argv[2] + 1;
1908 for (i = 0; i < len; i++) {
1912 mode |= SILC_CHANNEL_UMODE_CHANFO;
1913 mode |= SILC_CHANNEL_UMODE_CHANOP;
1914 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1915 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1916 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1918 mode = SILC_CHANNEL_UMODE_NONE;
1923 SilcPublicKey pubkey = conn->public_key;
1924 SilcPrivateKey privkey = conn->private_key;
1926 if (cmd->argc >= 6) {
1929 pass = cmd->argv[6];
1930 if (!silc_load_key_pair(cmd->argv[4], cmd->argv[5], pass,
1931 &pubkey, &privkey)) {
1932 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1933 "Could not load key pair, check your arguments");
1934 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1939 auth = silc_auth_public_key_auth_generate(pubkey, privkey,
1941 conn->internal->sha1hash,
1944 mode |= SILC_CHANNEL_UMODE_CHANFO;
1946 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1951 mode |= SILC_CHANNEL_UMODE_CHANOP;
1953 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1957 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1959 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1963 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1965 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1969 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1971 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1975 mode |= SILC_CHANNEL_UMODE_QUIET;
1977 mode &= ~SILC_CHANNEL_UMODE_QUIET;
1980 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1986 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
1987 SILC_PUT32_MSB(mode, modebuf);
1988 clidp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT);
1990 /* Send the command packet. We support sending only one mode at once
1991 that requires an argument. */
1992 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, auth ? 4 : 3,
1993 1, silc_buffer_datalen(chidp),
1995 3, silc_buffer_datalen(clidp),
1996 4, silc_buffer_datalen(auth));
1998 silc_buffer_free(chidp);
1999 silc_buffer_free(clidp);
2001 silc_buffer_free(auth);
2002 silc_free(nickname);
2003 silc_client_list_free(client, conn, clients);
2005 /* Notify application */
2006 COMMAND(SILC_STATUS_OK);
2008 /** Wait for command reply */
2009 silc_fsm_next(fsm, silc_client_command_reply_wait);
2010 return SILC_FSM_CONTINUE;
2013 silc_client_list_free(client, conn, clients);
2014 silc_free(nickname);
2015 return SILC_FSM_FINISH;
2018 /********************************** KICK ************************************/
2020 /* KICK command. Kicks a client out of channel. */
2022 SILC_FSM_STATE(silc_client_command_kick)
2024 SilcClientCommandContext cmd = fsm_context;
2025 SilcClientConnection conn = cmd->conn;
2026 SilcClient client = conn->client;
2027 SilcChannelEntry channel;
2028 SilcBuffer idp, idp2;
2029 SilcClientEntry target;
2030 SilcDList clients = NULL;
2032 char *nickname = NULL;
2034 if (cmd->argc < 3) {
2035 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2036 "Usage: /KICK <channel> <nickname> [<comment>]");
2037 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2041 if (cmd->argv[1][0] == '*') {
2042 if (!conn->current_channel) {
2043 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2046 name = conn->current_channel->channel_name;
2048 name = cmd->argv[1];
2051 if (!conn->current_channel) {
2052 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2056 /* Get the Channel ID of the channel */
2057 channel = silc_client_get_channel(conn->client, conn, name);
2059 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2063 /* Parse the typed nickname. */
2064 if (client->internal->params->nickname_parse)
2065 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
2067 nickname = strdup(cmd->argv[2]);
2069 /* Get the target client */
2070 clients = silc_client_get_clients_local(client, conn, nickname,
2073 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2074 "No such client: %s", cmd->argv[2]);
2075 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2078 target = silc_dlist_get(clients);
2080 /* Send KICK command to the server */
2081 idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
2082 idp2 = silc_id_payload_encode(&target->id, SILC_ID_CLIENT);
2084 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
2085 1, silc_buffer_datalen(idp),
2086 2, silc_buffer_datalen(idp2));
2088 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
2089 1, silc_buffer_datalen(idp),
2090 2, silc_buffer_datalen(idp2),
2091 3, cmd->argv[3], strlen(cmd->argv[3]));
2093 silc_buffer_free(idp);
2094 silc_buffer_free(idp2);
2095 silc_free(nickname);
2096 silc_client_list_free(client, conn, clients);
2098 /* Notify application */
2099 COMMAND(SILC_STATUS_OK);
2101 /** Wait for command reply */
2102 silc_fsm_next(fsm, silc_client_command_reply_wait);
2103 return SILC_FSM_CONTINUE;
2106 silc_free(nickname);
2107 return SILC_FSM_FINISH;
2110 /***************************** OPER & SILCOPER ******************************/
2113 unsigned char *passphrase;
2114 SilcUInt32 passphrase_len;
2115 } *SilcClientCommandOper;
2117 /* Ask passphrase callback */
2119 static void silc_client_command_oper_cb(unsigned char *data,
2120 SilcUInt32 data_len, void *context)
2122 SilcClientCommandContext cmd = context;
2123 SilcClientCommandOper oper = cmd->context;
2125 if (data && data_len)
2126 oper->passphrase = silc_memdup(data, data_len);
2127 oper->passphrase_len = data_len;
2130 SILC_FSM_CALL_CONTINUE(&cmd->thread);
2133 /* Send OPER/SILCOPER command */
2135 SILC_FSM_STATE(silc_client_command_oper_send)
2137 SilcClientCommandContext cmd = fsm_context;
2138 SilcClientConnection conn = cmd->conn;
2139 SilcClientCommandOper oper = cmd->context;
2142 if (!oper || !oper->passphrase) {
2143 /* Encode the public key authentication payload */
2144 auth = silc_auth_public_key_auth_generate(conn->public_key,
2147 conn->internal->hash,
2151 /* Encode the password authentication payload */
2152 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
2153 oper->passphrase, oper->passphrase_len);
2156 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
2157 1, cmd->argv[1], strlen(cmd->argv[1]),
2158 2, silc_buffer_datalen(auth));
2160 silc_buffer_clear(auth);
2161 silc_buffer_free(auth);
2163 silc_free(oper->passphrase);
2167 /* Notify application */
2168 COMMAND(SILC_STATUS_OK);
2170 /** Wait for command reply */
2171 silc_fsm_next(fsm, silc_client_command_reply_wait);
2172 return SILC_FSM_CONTINUE;
2175 /* OPER command. Used to obtain server operator privileges. */
2177 SILC_FSM_STATE(silc_client_command_oper)
2179 SilcClientCommandContext cmd = fsm_context;
2180 SilcClientConnection conn = cmd->conn;
2181 SilcClientCommandOper oper;
2183 if (cmd->argc < 2) {
2184 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2185 "Usage: /OPER <username> [-pubkey]");
2186 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2187 return SILC_FSM_FINISH;
2190 /* Get passphrase */
2191 if (cmd->argc < 3) {
2192 oper = silc_calloc(1, sizeof(*oper));
2194 return SILC_FSM_FINISH;
2195 cmd->context = oper;
2196 SILC_FSM_CALL(conn->client->internal->
2197 ops->ask_passphrase(conn->client, conn,
2198 silc_client_command_oper_cb, cmd));
2201 silc_fsm_next(fsm, silc_client_command_oper_send);
2202 return SILC_FSM_CONTINUE;
2205 /* SILCOPER command. Used to obtain router operator privileges. */
2207 SILC_FSM_STATE(silc_client_command_silcoper)
2209 SilcClientCommandContext cmd = fsm_context;
2210 SilcClientConnection conn = cmd->conn;
2211 SilcClientCommandOper oper;
2213 if (cmd->argc < 2) {
2214 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2215 "Usage: /SILCOPER <username> [-pubkey]");
2216 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2217 return SILC_FSM_FINISH;
2220 /* Get passphrase */
2221 if (cmd->argc < 3) {
2222 oper = silc_calloc(1, sizeof(*oper));
2224 return SILC_FSM_FINISH;
2225 cmd->context = oper;
2226 SILC_FSM_CALL(conn->client->internal->
2227 ops->ask_passphrase(conn->client, conn,
2228 silc_client_command_oper_cb, cmd));
2231 silc_fsm_next(fsm, silc_client_command_oper_send);
2232 return SILC_FSM_CONTINUE;
2235 /*********************************** BAN ************************************/
2237 /* Command BAN. This is used to manage the ban list of the channel. */
2239 SILC_FSM_STATE(silc_client_command_ban)
2241 SilcClientCommandContext cmd = fsm_context;
2242 SilcClientConnection conn = cmd->conn;
2243 SilcChannelEntry channel;
2244 SilcBuffer chidp, args = NULL;
2245 char *name, *ban = NULL;
2246 unsigned char action[1];
2247 SilcPublicKey pubkey = NULL;
2249 if (cmd->argc < 2) {
2250 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2251 "Usage: /BAN <channel> "
2252 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
2253 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2257 if (cmd->argv[1][0] == '*') {
2258 if (!conn->current_channel) {
2259 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2263 channel = conn->current_channel;
2265 name = cmd->argv[1];
2267 channel = silc_client_get_channel(conn->client, conn, name);
2269 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2274 if (cmd->argc == 3) {
2275 if (cmd->argv[2][0] == '+')
2280 /* Check if it is public key file to be added to invite list */
2281 silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey);
2288 args = silc_buffer_alloc_size(2);
2289 silc_buffer_format(args,
2290 SILC_STR_UI_SHORT(1),
2293 chidp = silc_public_key_payload_encode(pubkey);
2294 args = silc_argument_payload_encode_one(args,
2295 silc_buffer_datalen(chidp), 2);
2296 silc_buffer_free(chidp);
2297 silc_pkcs_public_key_free(pubkey);
2299 args = silc_argument_payload_encode_one(args, ban, strlen(ban), 1);
2303 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
2305 /* Send the command */
2306 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
2307 1, silc_buffer_datalen(chidp),
2308 2, args ? action : NULL, args ? 1 : 0,
2309 3, silc_buffer_datalen(args));
2311 silc_buffer_free(chidp);
2312 silc_buffer_free(args);
2314 /* Notify application */
2315 COMMAND(SILC_STATUS_OK);
2317 /** Wait for command reply */
2318 silc_fsm_next(fsm, silc_client_command_reply_wait);
2319 return SILC_FSM_CONTINUE;
2322 return SILC_FSM_FINISH;
2325 /********************************* DETACH ***********************************/
2327 /* Command DETACH. This is used to detach from the server */
2329 SILC_FSM_STATE(silc_client_command_detach)
2331 SilcClientCommandContext cmd = fsm_context;
2332 SilcClientConnection conn = cmd->conn;
2334 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
2336 /* Notify application */
2337 COMMAND(SILC_STATUS_OK);
2339 /** Wait for command reply */
2340 silc_fsm_next(fsm, silc_client_command_reply_wait);
2341 return SILC_FSM_CONTINUE;
2344 /********************************** WATCH ***********************************/
2346 /* Command WATCH. */
2348 SILC_FSM_STATE(silc_client_command_watch)
2350 SilcClientCommandContext cmd = fsm_context;
2351 SilcClientConnection conn = cmd->conn;
2352 SilcBuffer args = NULL;
2354 const char *pubkey = NULL;
2355 SilcBool pubkey_add = TRUE;
2357 if (cmd->argc < 3) {
2358 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2362 if (!strcasecmp(cmd->argv[1], "-add")) {
2364 } else if (!strcasecmp(cmd->argv[1], "-del")) {
2366 } else if (!strcasecmp(cmd->argv[1], "-pubkey") && cmd->argc >= 3) {
2368 pubkey = cmd->argv[2] + 1;
2369 if (cmd->argv[2][0] == '-')
2372 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2380 if (!silc_pkcs_load_public_key(pubkey, &pk)) {
2381 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2382 "Could not load public key %s, check the filename", pubkey);
2383 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2387 args = silc_buffer_alloc_size(2);
2388 silc_buffer_format(args,
2389 SILC_STR_UI_SHORT(1),
2391 buffer = silc_public_key_payload_encode(pk);
2392 args = silc_argument_payload_encode_one(args, silc_buffer_datalen(buffer),
2393 pubkey_add ? 0x00 : 0x01);
2394 silc_buffer_free(buffer);
2395 silc_pkcs_public_key_free(pk);
2398 /* Send the commmand */
2399 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
2400 1, silc_buffer_datalen(conn->internal->
2402 type, pubkey ? args->data : cmd->argv[2],
2403 pubkey ? silc_buffer_len(args) :
2406 silc_buffer_free(args);
2408 /* Notify application */
2409 COMMAND(SILC_STATUS_OK);
2411 /** Wait for command reply */
2412 silc_fsm_next(fsm, silc_client_command_reply_wait);
2413 return SILC_FSM_CONTINUE;
2416 return SILC_FSM_FINISH;
2419 /********************************** LEAVE ***********************************/
2421 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2423 SILC_FSM_STATE(silc_client_command_leave)
2425 SilcClientCommandContext cmd = fsm_context;
2426 SilcClientConnection conn = cmd->conn;
2427 SilcChannelEntry channel;
2431 if (cmd->argc != 2) {
2432 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2433 "Usage: /LEAVE <channel>");
2434 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2438 if (cmd->argv[1][0] == '*') {
2439 if (!conn->current_channel) {
2440 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2443 name = conn->current_channel->channel_name;
2445 name = cmd->argv[1];
2448 /* Get the channel entry */
2449 channel = silc_client_get_channel(conn->client, conn, name);
2451 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2455 idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
2457 /* Send LEAVE command to the server */
2458 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
2459 1, silc_buffer_datalen(idp));
2461 silc_buffer_free(idp);
2463 /* Notify application */
2464 COMMAND(SILC_STATUS_OK);
2466 if (conn->current_channel == channel)
2467 conn->current_channel = NULL;
2469 /** Wait for command reply */
2470 silc_fsm_next(fsm, silc_client_command_reply_wait);
2471 return SILC_FSM_CONTINUE;
2474 return SILC_FSM_FINISH;
2477 /********************************** USERS ***********************************/
2479 /* Command USERS. Requests the USERS of the clients joined on requested
2482 SILC_FSM_STATE(silc_client_command_users)
2484 SilcClientCommandContext cmd = fsm_context;
2485 SilcClientConnection conn = cmd->conn;
2488 if (cmd->argc != 2) {
2489 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2490 "Usage: /USERS <channel>");
2491 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2495 if (cmd->argv[1][0] == '*') {
2496 if (!conn->current_channel) {
2497 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2500 name = conn->current_channel->channel_name;
2502 name = cmd->argv[1];
2505 /* Send USERS command to the server */
2506 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
2507 2, name, strlen(name));
2509 /* Notify application */
2510 COMMAND(SILC_STATUS_OK);
2512 /** Wait for command reply */
2513 silc_fsm_next(fsm, silc_client_command_reply_wait);
2514 return SILC_FSM_CONTINUE;
2517 return SILC_FSM_FINISH;
2520 /********************************* GETKEY ***********************************/
2522 /* Command GETKEY. Used to fetch remote client's public key. */
2524 SILC_FSM_STATE(silc_client_command_getkey)
2526 SilcClientCommandContext cmd = fsm_context;
2527 SilcClientConnection conn = cmd->conn;
2528 SilcClient client = conn->client;
2529 SilcClientEntry client_entry;
2530 SilcServerEntry server_entry;
2532 char *nickname = NULL;
2535 if (cmd->argc < 2) {
2536 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2537 "Usage: /GETKEY <nickname or server name>");
2538 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2539 return SILC_FSM_FINISH;
2542 /* Parse the typed nickname. */
2543 if (client->internal->params->nickname_parse)
2544 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2546 nickname = strdup(cmd->argv[1]);
2548 COMMAND_ERROR(SILC_STATUS_ERR_RESOURCE_LIMIT);
2549 return SILC_FSM_FINISH;
2552 /* Find client entry */
2553 clients = silc_client_get_clients_local(client, conn, nickname,
2556 /* Check whether user requested server */
2557 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2558 if (!server_entry) {
2559 if (cmd->resolved) {
2560 /* Resolving didn't find anything. We should never get here as
2561 errors are handled in the resolving callback. */
2562 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2563 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_SERVER);
2564 return SILC_FSM_FINISH;
2567 /* No client or server exist with this name, query for both. */
2568 cmd->resolved = TRUE;
2569 SILC_FSM_CALL(silc_client_command_send(client, conn,
2570 SILC_COMMAND_IDENTIFY,
2571 silc_client_command_continue,
2574 strlen(cmd->argv[1]),
2576 strlen(cmd->argv[1])));
2579 idp = silc_id_payload_encode(&server_entry->id, SILC_ID_SERVER);
2581 client_entry = silc_dlist_get(clients);
2582 idp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT);
2583 silc_client_list_free(client, conn, clients);
2586 /* Send the commmand */
2587 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
2588 1, silc_buffer_datalen(idp));
2590 silc_buffer_free(idp);
2591 silc_free(nickname);
2593 /* Notify application */
2594 COMMAND(SILC_STATUS_OK);
2596 /** Wait for command reply */
2597 silc_fsm_next(fsm, silc_client_command_reply_wait);
2598 return SILC_FSM_CONTINUE;
2601 /********************************* SERVICE **********************************/
2603 /* Command SERVICE. Negotiates service agreement with server. */
2604 /* XXX incomplete */
2606 SILC_FSM_STATE(silc_client_command_service)
2608 SilcClientCommandContext cmd = fsm_context;
2610 SilcClientConnection conn = cmd->conn;
2614 if (cmd->argc < 2) {
2615 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2616 "Usage: /SERVICE [<service name>] [-pubkey]");
2617 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2618 return SILC_FSM_FINISH;
2621 name = cmd->argv[1];
2623 /* Send SERVICE command to the server */
2624 buffer = silc_command_payload_encode_va(SILC_COMMAND_SERVICE,
2625 ++conn->cmd_ident, 1,
2626 1, name, strlen(name));
2627 silc_client_packet_send(conn->client, conn->sock, SILC_PACKET_COMMAND,
2628 NULL, 0, NULL, NULL, buffer->data,
2630 silc_buffer_free(buffer);
2633 /* Notify application */
2634 COMMAND(SILC_STATUS_OK);
2636 /** Wait for command reply */
2637 silc_fsm_next(fsm, silc_client_command_reply_wait);
2638 return SILC_FSM_CONTINUE;
2641 /* Register all default commands provided by the client library for the
2644 void silc_client_commands_register(SilcClient client)
2646 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2649 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 5);
2650 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2651 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2652 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2653 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2654 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2655 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2656 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2657 SILC_CLIENT_CMD(kill, KILL, "KILL", 4);
2658 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2659 SILC_CLIENT_CMD(stats, STATS, "STATS", 0);
2660 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2661 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2662 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2663 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2664 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2665 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 6);
2666 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 9);
2667 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2668 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2669 SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2670 SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
2671 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2672 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2673 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2674 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2675 SILC_CLIENT_CMD(service, SERVICE, "SERVICE", 10);
2678 /* Unregister all commands. */
2680 void silc_client_commands_unregister(SilcClient client)
2682 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2683 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2684 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2685 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2686 SILC_CLIENT_CMDU(list, LIST, "LIST");
2687 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2688 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2689 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2690 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2691 SILC_CLIENT_CMDU(info, INFO, "INFO");
2692 SILC_CLIENT_CMDU(stats, STATS, "STATS");
2693 SILC_CLIENT_CMDU(ping, PING, "PING");
2694 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2695 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2696 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2697 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2698 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2699 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2700 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2701 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2702 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2703 SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2704 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2705 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2706 SILC_CLIENT_CMDU(users, USERS, "USERS");
2707 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2708 SILC_CLIENT_CMDU(service, SERVICE, "SERVICE");
2711 /****************** Client Side Incoming Command Handling *******************/
2713 /* Reply to WHOIS command from server */
2715 static void silc_client_command_process_whois(SilcClient client,
2716 SilcClientConnection conn,
2717 SilcCommandPayload payload,
2718 SilcArgumentPayload args)
2724 SilcBuffer buffer, packet;
2726 SILC_LOG_DEBUG(("Received WHOIS command"));
2728 /* Try to take the Requested Attributes */
2729 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
2733 attrs = silc_attribute_payload_parse(tmp, tmp_len);
2737 /* Process requested attributes */
2738 buffer = silc_client_attributes_process(client, conn, attrs);
2740 silc_attribute_payload_list_free(attrs);
2744 /* Send the attributes back */
2746 silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
2748 silc_command_get_ident(payload),
2749 1, 11, buffer->data, buffer->len);
2750 silc_client_packet_send(client, sock, SILC_PACKET_COMMAND_REPLY,
2751 NULL, 0, NULL, NULL, packet->data,
2753 silc_buffer_free(packet);
2754 silc_buffer_free(buffer);
2758 /* Client is able to receive some command packets even though they are
2759 special case. Server may send WHOIS command to the client to retrieve
2760 Requested Attributes information for WHOIS query the server is
2761 processing. This function currently handles only the WHOIS command,
2762 but if in the future more commands may arrive then this can be made
2763 to support other commands too. */
2765 SILC_FSM_STATE(silc_client_command)
2767 SilcClientConnection conn = fsm_context;
2768 SilcClient client = conn->client;
2769 SilcPacket packet = state_context;
2770 SilcCommandPayload payload;
2771 SilcCommand command;
2772 SilcArgumentPayload args;
2774 /* Get command payload from packet */
2775 payload = silc_command_payload_parse(packet->buffer.data,
2776 silc_buffer_len(&packet->buffer));
2778 SILC_LOG_DEBUG(("Bad command packet"));
2779 return SILC_FSM_FINISH;
2783 args = silc_command_get_args(payload);
2785 /* Get the command */
2786 command = silc_command_get(payload);
2789 case SILC_COMMAND_WHOIS:
2790 /* Ignore everything if requested by application */
2791 if (client->internal->params->ignore_requested_attributes)
2794 silc_client_command_process_whois(client, conn, payload, args);
2801 silc_command_payload_free(payload);
2802 return SILC_FSM_FINISH;