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 if (cmd->argc < 2) {
1205 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1206 return SILC_FSM_FINISH;
1209 /* Send the command */
1210 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1211 1, silc_buffer_datalen(conn->internal->
1214 /* Notify application */
1215 COMMAND(SILC_STATUS_OK);
1217 /** Wait for command reply */
1218 silc_fsm_next(fsm, silc_client_command_reply_wait);
1219 return SILC_FSM_CONTINUE;
1222 /********************************** PING ************************************/
1224 /* Command PING. Sends ping to server. */
1226 SILC_FSM_STATE(silc_client_command_ping)
1228 SilcClientCommandContext cmd = fsm_context;
1229 SilcClientConnection conn = cmd->conn;
1231 if (cmd->argc < 2) {
1232 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1233 return SILC_FSM_FINISH;
1236 /* Send the command */
1237 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1238 1, silc_buffer_datalen(conn->internal->
1241 /* Save ping time */
1242 cmd->context = SILC_64_TO_PTR(silc_time());
1244 /* Notify application */
1245 COMMAND(SILC_STATUS_OK);
1247 /** Wait for command reply */
1248 silc_fsm_next(fsm, silc_client_command_reply_wait);
1249 return SILC_FSM_CONTINUE;
1252 /********************************** JOIN ************************************/
1254 /* Command JOIN. Joins to a channel. */
1256 SILC_FSM_STATE(silc_client_command_join)
1258 SilcClientCommandContext cmd = fsm_context;
1259 SilcClientConnection conn = cmd->conn;
1260 SilcChannelEntry channel;
1261 SilcBuffer auth = NULL, cauth = NULL;
1262 char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
1263 int i, passphrase_len = 0;
1265 if (cmd->argc < 2) {
1266 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1270 /* See if we have joined to the requested channel already */
1271 channel = silc_client_get_channel(conn->client, conn, cmd->argv[1]);
1272 if (channel && silc_client_on_channel(channel, conn->local_entry))
1275 if (cmd->argv_lens[1] > 256)
1276 cmd->argv_lens[1] = 256;
1278 name = cmd->argv[1];
1280 for (i = 2; i < cmd->argc; i++) {
1281 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
1282 cipher = cmd->argv[++i];
1283 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
1284 hmac = cmd->argv[++i];
1285 } else if (!strcasecmp(cmd->argv[i], "-founder")) {
1286 auth = silc_auth_public_key_auth_generate(conn->public_key,
1289 conn->internal->sha1hash,
1292 } else if (!strcasecmp(cmd->argv[i], "-auth")) {
1293 SilcPublicKey pubkey = conn->public_key;
1294 SilcPrivateKey privkey = conn->private_key;
1295 unsigned char *pk, pkhash[SILC_HASH_MAXLEN], *pubdata;
1298 if (cmd->argc >= i + 3) {
1300 if (cmd->argc >= i + 4) {
1301 pass = cmd->argv[i + 3];
1304 if (!silc_load_key_pair(cmd->argv[i + 1], cmd->argv[i + 2], pass,
1305 &pubkey, &privkey)) {
1306 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1307 "Could not load key pair, check your arguments");
1308 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1314 pk = silc_pkcs_public_key_encode(pubkey, &pk_len);
1315 silc_hash_make(conn->internal->sha1hash, pk, pk_len, pkhash);
1317 pubdata = silc_rng_get_rn_data(conn->client->rng, 128);
1318 memcpy(pubdata, pkhash, 20);
1319 cauth = silc_auth_public_key_auth_generate_wpub(pubkey, privkey,
1321 conn->internal->sha1hash,
1324 memset(pubdata, 0, 128);
1327 /* Passphrases must be UTF-8 encoded, so encode if it is not */
1328 if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
1329 passphrase_len = silc_utf8_encoded_len(cmd->argv[i],
1330 cmd->argv_lens[i], 0);
1331 pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
1332 passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
1333 0, pu8, passphrase_len);
1336 passphrase = strdup(cmd->argv[i]);
1337 passphrase_len = cmd->argv_lens[i];
1342 /* Send JOIN command to the server */
1343 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 7,
1344 1, name, strlen(name),
1345 2, silc_buffer_datalen(conn->internal->
1347 3, passphrase, passphrase_len,
1348 4, cipher, cipher ? strlen(cipher) : 0,
1349 5, hmac, hmac ? strlen(hmac) : 0,
1350 6, silc_buffer_datalen(auth),
1351 7, silc_buffer_datalen(cauth));
1353 silc_buffer_free(auth);
1354 silc_buffer_free(cauth);
1356 memset(passphrase, 0, strlen(passphrase));
1357 silc_free(passphrase);
1359 /* Notify application */
1360 COMMAND(SILC_STATUS_OK);
1362 /** Wait for command reply */
1363 silc_fsm_next(fsm, silc_client_command_reply_wait);
1364 return SILC_FSM_CONTINUE;
1367 return SILC_FSM_FINISH;
1370 /********************************** MOTD ************************************/
1372 /* MOTD command. Requests motd from server. */
1374 SILC_FSM_STATE(silc_client_command_motd)
1376 SilcClientCommandContext cmd = fsm_context;
1377 SilcClientConnection conn = cmd->conn;
1379 if (cmd->argc < 1 || cmd->argc > 2) {
1380 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1381 "Usage: /MOTD [<server>]");
1382 COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
1383 SILC_STATUS_ERR_TOO_MANY_PARAMS));
1384 return SILC_FSM_FINISH;
1387 /* Send the command */
1389 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1390 1, conn->remote_host,
1391 strlen(conn->remote_host));
1393 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1394 1, cmd->argv[1], cmd->argv_lens[1]);
1396 /* Notify application */
1397 COMMAND(SILC_STATUS_OK);
1399 /** Wait for command reply */
1400 silc_fsm_next(fsm, silc_client_command_reply_wait);
1401 return SILC_FSM_CONTINUE;
1404 /********************************** UMODE ***********************************/
1406 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1407 modes as client cannot set itself server/router operator privileges. */
1409 SILC_FSM_STATE(silc_client_command_umode)
1411 SilcClientCommandContext cmd = fsm_context;
1412 SilcClientConnection conn = cmd->conn;
1413 unsigned char *cp, modebuf[4];
1414 SilcUInt32 mode, add, len;
1417 if (cmd->argc < 2) {
1418 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1419 "Usage: /UMODE +|-<modes>");
1420 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1421 return SILC_FSM_FINISH;
1424 mode = conn->local_entry->mode;
1426 /* Are we adding or removing mode */
1427 if (cmd->argv[1][0] == '-')
1433 cp = cmd->argv[1] + 1;
1435 for (i = 0; i < len; i++) {
1440 mode |= SILC_UMODE_SERVER_OPERATOR;
1441 mode |= SILC_UMODE_ROUTER_OPERATOR;
1442 mode |= SILC_UMODE_GONE;
1443 mode |= SILC_UMODE_INDISPOSED;
1444 mode |= SILC_UMODE_BUSY;
1445 mode |= SILC_UMODE_PAGE;
1446 mode |= SILC_UMODE_HYPER;
1447 mode |= SILC_UMODE_ROBOT;
1448 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1449 mode |= SILC_UMODE_REJECT_WATCHING;
1451 mode = SILC_UMODE_NONE;
1456 mode |= SILC_UMODE_SERVER_OPERATOR;
1458 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1462 mode |= SILC_UMODE_ROUTER_OPERATOR;
1464 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1468 mode |= SILC_UMODE_GONE;
1470 mode &= ~SILC_UMODE_GONE;
1474 mode |= SILC_UMODE_INDISPOSED;
1476 mode &= ~SILC_UMODE_INDISPOSED;
1480 mode |= SILC_UMODE_BUSY;
1482 mode &= ~SILC_UMODE_BUSY;
1486 mode |= SILC_UMODE_PAGE;
1488 mode &= ~SILC_UMODE_PAGE;
1492 mode |= SILC_UMODE_HYPER;
1494 mode &= ~SILC_UMODE_HYPER;
1498 mode |= SILC_UMODE_ROBOT;
1500 mode &= ~SILC_UMODE_ROBOT;
1504 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1506 mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
1510 mode |= SILC_UMODE_REJECT_WATCHING;
1512 mode &= ~SILC_UMODE_REJECT_WATCHING;
1516 mode |= SILC_UMODE_BLOCK_INVITE;
1518 mode &= ~SILC_UMODE_BLOCK_INVITE;
1521 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1522 return SILC_FSM_FINISH;
1527 SILC_PUT32_MSB(mode, modebuf);
1529 /* Send the command */
1530 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
1531 1, silc_buffer_datalen(conn->internal->
1533 2, modebuf, sizeof(modebuf));
1535 /* Notify application */
1536 COMMAND(SILC_STATUS_OK);
1538 /** Wait for command reply */
1539 silc_fsm_next(fsm, silc_client_command_reply_wait);
1540 return SILC_FSM_CONTINUE;
1543 /********************************** CMODE ***********************************/
1545 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1546 can be set several at once. Those modes that require argument must be set
1547 separately (unless set with modes that does not require arguments). */
1549 SILC_FSM_STATE(silc_client_command_cmode)
1551 SilcClientCommandContext cmd = fsm_context;
1552 SilcClientConnection conn = cmd->conn;
1553 SilcClient client = conn->client;
1554 SilcChannelEntry channel;
1555 SilcBuffer chidp, auth = NULL, pk = NULL;
1556 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1557 SilcUInt32 mode, add, type, len, arg_len = 0;
1560 if (cmd->argc < 3) {
1561 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1562 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1563 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1567 if (cmd->argv[1][0] == '*') {
1568 if (!conn->current_channel) {
1569 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1573 channel = conn->current_channel;
1575 name = cmd->argv[1];
1577 channel = silc_client_get_channel(conn->client, conn, name);
1579 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1584 mode = channel->mode;
1586 /* Are we adding or removing mode */
1587 if (cmd->argv[2][0] == '-')
1592 /* Argument type to be sent to server */
1596 cp = cmd->argv[2] + 1;
1598 for (i = 0; i < len; i++) {
1602 mode |= SILC_CHANNEL_MODE_PRIVATE;
1604 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1608 mode |= SILC_CHANNEL_MODE_SECRET;
1610 mode &= ~SILC_CHANNEL_MODE_SECRET;
1614 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1616 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1620 mode |= SILC_CHANNEL_MODE_INVITE;
1622 mode &= ~SILC_CHANNEL_MODE_INVITE;
1626 mode |= SILC_CHANNEL_MODE_TOPIC;
1628 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1632 mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1634 mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1638 mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1640 mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1645 mode |= SILC_CHANNEL_MODE_ULIMIT;
1647 if (cmd->argc < 4) {
1648 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1649 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1650 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1653 ll = atoi(cmd->argv[3]);
1654 SILC_PUT32_MSB(ll, tmp);
1658 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1663 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1665 if (cmd->argc < 4) {
1666 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1667 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1668 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1672 arg_len = cmd->argv_lens[3];
1674 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1679 mode |= SILC_CHANNEL_MODE_CIPHER;
1681 if (cmd->argc < 4) {
1682 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1683 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1684 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1688 arg_len = cmd->argv_lens[3];
1690 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1695 mode |= SILC_CHANNEL_MODE_HMAC;
1697 if (cmd->argc < 4) {
1698 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1699 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1700 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1704 arg_len = cmd->argv_lens[3];
1706 mode &= ~SILC_CHANNEL_MODE_HMAC;
1711 SilcPublicKey pubkey = conn->public_key;
1712 SilcPrivateKey privkey = conn->private_key;
1714 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1717 if (cmd->argc >= 5) {
1720 pass = cmd->argv[5];
1721 if (!silc_load_key_pair(cmd->argv[3], cmd->argv[4], pass,
1722 &pubkey, &privkey)) {
1723 SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1724 "Could not load key pair, check your arguments");
1725 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1730 pk = silc_public_key_payload_encode(pubkey);
1731 auth = silc_auth_public_key_auth_generate(pubkey, privkey,
1733 conn->internal->sha1hash,
1736 arg = silc_buffer_data(auth);
1737 arg_len = silc_buffer_len(auth);
1739 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1745 SilcBool chadd = FALSE;
1746 SilcPublicKey chpk = NULL;
1748 mode |= SILC_CHANNEL_MODE_CHANNEL_AUTH;
1751 if (cmd->argc == 3) {
1752 /* Send empty command to receive the public key list. */
1753 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
1754 silc_client_command_send_va(conn, cmd, SILC_COMMAND_CMODE,
1756 1, silc_buffer_datalen(chidp));
1757 silc_buffer_free(chidp);
1759 /* Notify application */
1760 COMMAND(SILC_STATUS_OK);
1764 if (cmd->argc >= 4) {
1765 auth = silc_buffer_alloc_size(2);
1766 silc_buffer_format(auth,
1767 SILC_STR_UI_SHORT(cmd->argc - 3),
1771 for (k = 3; k < cmd->argc; k++) {
1772 if (cmd->argv[k][0] == '+')
1774 if (!silc_pkcs_load_public_key(cmd->argv[k] + 1, &chpk)) {
1775 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1776 "Could not load public key %s, check the filename",
1778 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1779 silc_buffer_free(auth);
1784 pk = silc_public_key_payload_encode(chpk);
1785 auth = silc_argument_payload_encode_one(auth,
1786 silc_buffer_datalen(pk),
1787 chadd ? 0x00 : 0x01);
1788 silc_pkcs_public_key_free(chpk);
1789 silc_buffer_free(pk);
1794 arg = silc_buffer_data(auth);
1795 arg_len = silc_buffer_len(auth);
1797 mode &= ~SILC_CHANNEL_MODE_CHANNEL_AUTH;
1801 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1807 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
1808 SILC_PUT32_MSB(mode, modebuf);
1810 /* Send the command. We support sending only one mode at once that
1811 requires an argument. */
1813 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 4,
1814 1, silc_buffer_datalen(chidp),
1815 2, modebuf, sizeof(modebuf),
1817 8, silc_buffer_datalen(pk));
1819 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
1820 1, silc_buffer_datalen(chidp),
1821 2, modebuf, sizeof(modebuf));
1824 silc_buffer_free(chidp);
1825 silc_buffer_free(auth);
1826 silc_buffer_free(pk);
1828 /* Notify application */
1829 COMMAND(SILC_STATUS_OK);
1831 /** Wait for command reply */
1832 silc_fsm_next(fsm, silc_client_command_reply_wait);
1833 return SILC_FSM_CONTINUE;
1836 return SILC_FSM_FINISH;
1839 /********************************* CUMODE ***********************************/
1841 /* CUMODE command. Changes client's mode on a channel. */
1843 SILC_FSM_STATE(silc_client_command_cumode)
1845 SilcClientCommandContext cmd = fsm_context;
1846 SilcClientConnection conn = cmd->conn;
1847 SilcClient client = conn->client;
1848 SilcChannelEntry channel;
1849 SilcChannelUser chu;
1850 SilcClientEntry client_entry;
1851 SilcBuffer clidp, chidp, auth = NULL;
1852 SilcDList clients = NULL;
1853 unsigned char *name, *cp, modebuf[4];
1854 SilcUInt32 mode = 0, add, len;
1855 char *nickname = NULL;
1858 if (cmd->argc < 4) {
1859 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1860 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1861 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1865 if (cmd->argv[1][0] == '*') {
1866 if (!conn->current_channel) {
1867 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1871 channel = conn->current_channel;
1873 name = cmd->argv[1];
1875 channel = silc_client_get_channel(conn->client, conn, name);
1877 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1882 /* Parse the typed nickname. */
1883 if (client->internal->params->nickname_parse)
1884 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1886 nickname = strdup(cmd->argv[3]);
1888 /* Find client entry */
1889 clients = silc_client_get_clients_local(client, conn, nickname,
1892 /* Resolve client information */
1893 SILC_FSM_CALL(silc_client_get_clients(client, conn, nickname, cmd->argv[3],
1894 silc_client_command_resolve_continue,
1897 client_entry = silc_dlist_get(clients);
1899 /* Get the current mode */
1900 chu = silc_client_on_channel(channel, client_entry);
1904 /* Are we adding or removing mode */
1905 if (cmd->argv[2][0] == '-')
1911 cp = cmd->argv[2] + 1;
1913 for (i = 0; i < len; i++) {
1917 mode |= SILC_CHANNEL_UMODE_CHANFO;
1918 mode |= SILC_CHANNEL_UMODE_CHANOP;
1919 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1920 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1921 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1923 mode = SILC_CHANNEL_UMODE_NONE;
1928 SilcPublicKey pubkey = conn->public_key;
1929 SilcPrivateKey privkey = conn->private_key;
1931 if (cmd->argc >= 6) {
1934 pass = cmd->argv[6];
1935 if (!silc_load_key_pair(cmd->argv[4], cmd->argv[5], pass,
1936 &pubkey, &privkey)) {
1937 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1938 "Could not load key pair, check your arguments");
1939 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1944 auth = silc_auth_public_key_auth_generate(pubkey, privkey,
1946 conn->internal->sha1hash,
1949 mode |= SILC_CHANNEL_UMODE_CHANFO;
1951 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1956 mode |= SILC_CHANNEL_UMODE_CHANOP;
1958 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1962 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1964 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1968 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1970 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1974 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1976 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1980 mode |= SILC_CHANNEL_UMODE_QUIET;
1982 mode &= ~SILC_CHANNEL_UMODE_QUIET;
1985 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1991 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
1992 SILC_PUT32_MSB(mode, modebuf);
1993 clidp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT);
1995 /* Send the command packet. We support sending only one mode at once
1996 that requires an argument. */
1997 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, auth ? 4 : 3,
1998 1, silc_buffer_datalen(chidp),
2000 3, silc_buffer_datalen(clidp),
2001 4, silc_buffer_datalen(auth));
2003 silc_buffer_free(chidp);
2004 silc_buffer_free(clidp);
2006 silc_buffer_free(auth);
2007 silc_free(nickname);
2008 silc_client_list_free(client, conn, clients);
2010 /* Notify application */
2011 COMMAND(SILC_STATUS_OK);
2013 /** Wait for command reply */
2014 silc_fsm_next(fsm, silc_client_command_reply_wait);
2015 return SILC_FSM_CONTINUE;
2018 silc_client_list_free(client, conn, clients);
2019 silc_free(nickname);
2020 return SILC_FSM_FINISH;
2023 /********************************** KICK ************************************/
2025 /* KICK command. Kicks a client out of channel. */
2027 SILC_FSM_STATE(silc_client_command_kick)
2029 SilcClientCommandContext cmd = fsm_context;
2030 SilcClientConnection conn = cmd->conn;
2031 SilcClient client = conn->client;
2032 SilcChannelEntry channel;
2033 SilcBuffer idp, idp2;
2034 SilcClientEntry target;
2035 SilcDList clients = NULL;
2037 char *nickname = NULL;
2039 if (cmd->argc < 3) {
2040 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2041 "Usage: /KICK <channel> <nickname> [<comment>]");
2042 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2046 if (cmd->argv[1][0] == '*') {
2047 if (!conn->current_channel) {
2048 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2051 name = conn->current_channel->channel_name;
2053 name = cmd->argv[1];
2056 if (!conn->current_channel) {
2057 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2061 /* Get the Channel ID of the channel */
2062 channel = silc_client_get_channel(conn->client, conn, name);
2064 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2068 /* Parse the typed nickname. */
2069 if (client->internal->params->nickname_parse)
2070 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
2072 nickname = strdup(cmd->argv[2]);
2074 /* Get the target client */
2075 clients = silc_client_get_clients_local(client, conn, nickname,
2078 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2079 "No such client: %s", cmd->argv[2]);
2080 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2083 target = silc_dlist_get(clients);
2085 /* Send KICK command to the server */
2086 idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
2087 idp2 = silc_id_payload_encode(&target->id, SILC_ID_CLIENT);
2089 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
2090 1, silc_buffer_datalen(idp),
2091 2, silc_buffer_datalen(idp2));
2093 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
2094 1, silc_buffer_datalen(idp),
2095 2, silc_buffer_datalen(idp2),
2096 3, cmd->argv[3], strlen(cmd->argv[3]));
2098 silc_buffer_free(idp);
2099 silc_buffer_free(idp2);
2100 silc_free(nickname);
2101 silc_client_list_free(client, conn, clients);
2103 /* Notify application */
2104 COMMAND(SILC_STATUS_OK);
2106 /** Wait for command reply */
2107 silc_fsm_next(fsm, silc_client_command_reply_wait);
2108 return SILC_FSM_CONTINUE;
2111 silc_free(nickname);
2112 return SILC_FSM_FINISH;
2115 /***************************** OPER & SILCOPER ******************************/
2118 unsigned char *passphrase;
2119 SilcUInt32 passphrase_len;
2120 } *SilcClientCommandOper;
2122 /* Ask passphrase callback */
2124 static void silc_client_command_oper_cb(unsigned char *data,
2125 SilcUInt32 data_len, void *context)
2127 SilcClientCommandContext cmd = context;
2128 SilcClientCommandOper oper = cmd->context;
2130 if (data && data_len)
2131 oper->passphrase = silc_memdup(data, data_len);
2132 oper->passphrase_len = data_len;
2135 SILC_FSM_CALL_CONTINUE(&cmd->thread);
2138 /* Send OPER/SILCOPER command */
2140 SILC_FSM_STATE(silc_client_command_oper_send)
2142 SilcClientCommandContext cmd = fsm_context;
2143 SilcClientConnection conn = cmd->conn;
2144 SilcClientCommandOper oper = cmd->context;
2147 if (!oper || !oper->passphrase) {
2148 /* Encode the public key authentication payload */
2149 auth = silc_auth_public_key_auth_generate(conn->public_key,
2152 conn->internal->hash,
2156 /* Encode the password authentication payload */
2157 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
2158 oper->passphrase, oper->passphrase_len);
2161 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
2162 1, cmd->argv[1], strlen(cmd->argv[1]),
2163 2, silc_buffer_datalen(auth));
2165 silc_buffer_clear(auth);
2166 silc_buffer_free(auth);
2168 silc_free(oper->passphrase);
2172 /* Notify application */
2173 COMMAND(SILC_STATUS_OK);
2175 /** Wait for command reply */
2176 silc_fsm_next(fsm, silc_client_command_reply_wait);
2177 return SILC_FSM_CONTINUE;
2180 /* OPER command. Used to obtain server operator privileges. */
2182 SILC_FSM_STATE(silc_client_command_oper)
2184 SilcClientCommandContext cmd = fsm_context;
2185 SilcClientConnection conn = cmd->conn;
2186 SilcClientCommandOper oper;
2188 if (cmd->argc < 2) {
2189 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2190 "Usage: /OPER <username> [-pubkey]");
2191 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2192 return SILC_FSM_FINISH;
2195 /* Get passphrase */
2196 if (cmd->argc < 3) {
2197 oper = silc_calloc(1, sizeof(*oper));
2199 return SILC_FSM_FINISH;
2200 cmd->context = oper;
2201 SILC_FSM_CALL(conn->client->internal->
2202 ops->ask_passphrase(conn->client, conn,
2203 silc_client_command_oper_cb, cmd));
2206 silc_fsm_next(fsm, silc_client_command_oper_send);
2207 return SILC_FSM_CONTINUE;
2210 /* SILCOPER command. Used to obtain router operator privileges. */
2212 SILC_FSM_STATE(silc_client_command_silcoper)
2214 SilcClientCommandContext cmd = fsm_context;
2215 SilcClientConnection conn = cmd->conn;
2216 SilcClientCommandOper oper;
2218 if (cmd->argc < 2) {
2219 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2220 "Usage: /SILCOPER <username> [-pubkey]");
2221 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2222 return SILC_FSM_FINISH;
2225 /* Get passphrase */
2226 if (cmd->argc < 3) {
2227 oper = silc_calloc(1, sizeof(*oper));
2229 return SILC_FSM_FINISH;
2230 cmd->context = oper;
2231 SILC_FSM_CALL(conn->client->internal->
2232 ops->ask_passphrase(conn->client, conn,
2233 silc_client_command_oper_cb, cmd));
2236 silc_fsm_next(fsm, silc_client_command_oper_send);
2237 return SILC_FSM_CONTINUE;
2240 /*********************************** BAN ************************************/
2242 /* Command BAN. This is used to manage the ban list of the channel. */
2244 SILC_FSM_STATE(silc_client_command_ban)
2246 SilcClientCommandContext cmd = fsm_context;
2247 SilcClientConnection conn = cmd->conn;
2248 SilcChannelEntry channel;
2249 SilcBuffer chidp, args = NULL;
2250 char *name, *ban = NULL;
2251 unsigned char action[1];
2252 SilcPublicKey pubkey = NULL;
2254 if (cmd->argc < 2) {
2255 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2256 "Usage: /BAN <channel> "
2257 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
2258 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2262 if (cmd->argv[1][0] == '*') {
2263 if (!conn->current_channel) {
2264 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2268 channel = conn->current_channel;
2270 name = cmd->argv[1];
2272 channel = silc_client_get_channel(conn->client, conn, name);
2274 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2279 if (cmd->argc == 3) {
2280 if (cmd->argv[2][0] == '+')
2285 /* Check if it is public key file to be added to invite list */
2286 silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey);
2293 args = silc_buffer_alloc_size(2);
2294 silc_buffer_format(args,
2295 SILC_STR_UI_SHORT(1),
2298 chidp = silc_public_key_payload_encode(pubkey);
2299 args = silc_argument_payload_encode_one(args,
2300 silc_buffer_datalen(chidp), 2);
2301 silc_buffer_free(chidp);
2302 silc_pkcs_public_key_free(pubkey);
2304 args = silc_argument_payload_encode_one(args, ban, strlen(ban), 1);
2308 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
2310 /* Send the command */
2311 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
2312 1, silc_buffer_datalen(chidp),
2313 2, args ? action : NULL, args ? 1 : 0,
2314 3, silc_buffer_datalen(args));
2316 silc_buffer_free(chidp);
2317 silc_buffer_free(args);
2319 /* Notify application */
2320 COMMAND(SILC_STATUS_OK);
2322 /** Wait for command reply */
2323 silc_fsm_next(fsm, silc_client_command_reply_wait);
2324 return SILC_FSM_CONTINUE;
2327 return SILC_FSM_FINISH;
2330 /********************************* DETACH ***********************************/
2332 /* Command DETACH. This is used to detach from the server */
2334 SILC_FSM_STATE(silc_client_command_detach)
2336 SilcClientCommandContext cmd = fsm_context;
2337 SilcClientConnection conn = cmd->conn;
2339 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
2341 /* Notify application */
2342 COMMAND(SILC_STATUS_OK);
2344 /** Wait for command reply */
2345 silc_fsm_next(fsm, silc_client_command_reply_wait);
2346 return SILC_FSM_CONTINUE;
2349 /********************************** WATCH ***********************************/
2351 /* Command WATCH. */
2353 SILC_FSM_STATE(silc_client_command_watch)
2355 SilcClientCommandContext cmd = fsm_context;
2356 SilcClientConnection conn = cmd->conn;
2357 SilcBuffer args = NULL;
2359 const char *pubkey = NULL;
2360 SilcBool pubkey_add = TRUE;
2362 if (cmd->argc < 3) {
2363 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2367 if (!strcasecmp(cmd->argv[1], "-add")) {
2369 } else if (!strcasecmp(cmd->argv[1], "-del")) {
2371 } else if (!strcasecmp(cmd->argv[1], "-pubkey") && cmd->argc >= 3) {
2373 pubkey = cmd->argv[2] + 1;
2374 if (cmd->argv[2][0] == '-')
2377 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2385 if (!silc_pkcs_load_public_key(pubkey, &pk)) {
2386 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2387 "Could not load public key %s, check the filename", pubkey);
2388 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2392 args = silc_buffer_alloc_size(2);
2393 silc_buffer_format(args,
2394 SILC_STR_UI_SHORT(1),
2396 buffer = silc_public_key_payload_encode(pk);
2397 args = silc_argument_payload_encode_one(args, silc_buffer_datalen(buffer),
2398 pubkey_add ? 0x00 : 0x01);
2399 silc_buffer_free(buffer);
2400 silc_pkcs_public_key_free(pk);
2403 /* Send the commmand */
2404 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
2405 1, silc_buffer_datalen(conn->internal->
2407 type, pubkey ? args->data : cmd->argv[2],
2408 pubkey ? silc_buffer_len(args) :
2411 silc_buffer_free(args);
2413 /* Notify application */
2414 COMMAND(SILC_STATUS_OK);
2416 /** Wait for command reply */
2417 silc_fsm_next(fsm, silc_client_command_reply_wait);
2418 return SILC_FSM_CONTINUE;
2421 return SILC_FSM_FINISH;
2424 /********************************** LEAVE ***********************************/
2426 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2428 SILC_FSM_STATE(silc_client_command_leave)
2430 SilcClientCommandContext cmd = fsm_context;
2431 SilcClientConnection conn = cmd->conn;
2432 SilcChannelEntry channel;
2436 if (cmd->argc != 2) {
2437 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2438 "Usage: /LEAVE <channel>");
2439 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2443 if (cmd->argv[1][0] == '*') {
2444 if (!conn->current_channel) {
2445 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2448 name = conn->current_channel->channel_name;
2450 name = cmd->argv[1];
2453 /* Get the channel entry */
2454 channel = silc_client_get_channel(conn->client, conn, name);
2456 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2460 idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
2462 /* Send LEAVE command to the server */
2463 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
2464 1, silc_buffer_datalen(idp));
2466 silc_buffer_free(idp);
2468 /* Notify application */
2469 COMMAND(SILC_STATUS_OK);
2471 if (conn->current_channel == channel)
2472 conn->current_channel = NULL;
2474 /** Wait for command reply */
2475 silc_fsm_next(fsm, silc_client_command_reply_wait);
2476 return SILC_FSM_CONTINUE;
2479 return SILC_FSM_FINISH;
2482 /********************************** USERS ***********************************/
2484 /* Command USERS. Requests the USERS of the clients joined on requested
2487 SILC_FSM_STATE(silc_client_command_users)
2489 SilcClientCommandContext cmd = fsm_context;
2490 SilcClientConnection conn = cmd->conn;
2493 if (cmd->argc != 2) {
2494 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2495 "Usage: /USERS <channel>");
2496 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2500 if (cmd->argv[1][0] == '*') {
2501 if (!conn->current_channel) {
2502 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2505 name = conn->current_channel->channel_name;
2507 name = cmd->argv[1];
2510 /* Send USERS command to the server */
2511 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
2512 2, name, strlen(name));
2514 /* Notify application */
2515 COMMAND(SILC_STATUS_OK);
2517 /** Wait for command reply */
2518 silc_fsm_next(fsm, silc_client_command_reply_wait);
2519 return SILC_FSM_CONTINUE;
2522 return SILC_FSM_FINISH;
2525 /********************************* GETKEY ***********************************/
2527 /* Command GETKEY. Used to fetch remote client's public key. */
2529 SILC_FSM_STATE(silc_client_command_getkey)
2531 SilcClientCommandContext cmd = fsm_context;
2532 SilcClientConnection conn = cmd->conn;
2533 SilcClient client = conn->client;
2534 SilcClientEntry client_entry;
2535 SilcServerEntry server_entry;
2537 char *nickname = NULL;
2540 if (cmd->argc < 2) {
2541 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2542 "Usage: /GETKEY <nickname or server name>");
2543 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2544 return SILC_FSM_FINISH;
2547 /* Parse the typed nickname. */
2548 if (client->internal->params->nickname_parse)
2549 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2551 nickname = strdup(cmd->argv[1]);
2553 COMMAND_ERROR(SILC_STATUS_ERR_RESOURCE_LIMIT);
2554 return SILC_FSM_FINISH;
2557 /* Find client entry */
2558 clients = silc_client_get_clients_local(client, conn, nickname,
2561 /* Check whether user requested server */
2562 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2563 if (!server_entry) {
2564 /* No client or server exist with this name, query for both. */
2565 SILC_FSM_CALL(silc_client_command_send(client, conn,
2566 SILC_COMMAND_IDENTIFY,
2567 silc_client_command_continue,
2570 strlen(cmd->argv[1]),
2572 strlen(cmd->argv[1])));
2574 idp = silc_id_payload_encode(&server_entry->id, SILC_ID_SERVER);
2576 client_entry = silc_dlist_get(clients);
2577 idp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT);
2578 silc_client_list_free(client, conn, clients);
2581 /* Send the commmand */
2582 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
2583 1, silc_buffer_datalen(idp));
2585 silc_buffer_free(idp);
2586 silc_free(nickname);
2588 /* Notify application */
2589 COMMAND(SILC_STATUS_OK);
2591 /** Wait for command reply */
2592 silc_fsm_next(fsm, silc_client_command_reply_wait);
2593 return SILC_FSM_CONTINUE;
2596 /********************************* SERVICE **********************************/
2598 /* Command SERVICE. Negotiates service agreement with server. */
2599 /* XXX incomplete */
2601 SILC_FSM_STATE(silc_client_command_service)
2603 SilcClientCommandContext cmd = fsm_context;
2605 SilcClientConnection conn = cmd->conn;
2609 if (cmd->argc < 2) {
2610 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2611 "Usage: /SERVICE [<service name>] [-pubkey]");
2612 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2613 return SILC_FSM_FINISH;
2616 name = cmd->argv[1];
2618 /* Send SERVICE command to the server */
2619 buffer = silc_command_payload_encode_va(SILC_COMMAND_SERVICE,
2620 ++conn->cmd_ident, 1,
2621 1, name, strlen(name));
2622 silc_client_packet_send(conn->client, conn->sock, SILC_PACKET_COMMAND,
2623 NULL, 0, NULL, NULL, buffer->data,
2625 silc_buffer_free(buffer);
2628 /* Notify application */
2629 COMMAND(SILC_STATUS_OK);
2631 /** Wait for command reply */
2632 silc_fsm_next(fsm, silc_client_command_reply_wait);
2633 return SILC_FSM_CONTINUE;
2636 /* Register all default commands provided by the client library for the
2639 void silc_client_commands_register(SilcClient client)
2641 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2644 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 5);
2645 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2646 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2647 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2648 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2649 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2650 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2651 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2652 SILC_CLIENT_CMD(kill, KILL, "KILL", 4);
2653 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2654 SILC_CLIENT_CMD(stats, STATS, "STATS", 0);
2655 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2656 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2657 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2658 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2659 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2660 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 6);
2661 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 9);
2662 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2663 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2664 SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2665 SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
2666 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2667 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2668 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2669 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2670 SILC_CLIENT_CMD(service, SERVICE, "SERVICE", 10);
2673 /* Unregister all commands. */
2675 void silc_client_commands_unregister(SilcClient client)
2677 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2678 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2679 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2680 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2681 SILC_CLIENT_CMDU(list, LIST, "LIST");
2682 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2683 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2684 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2685 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2686 SILC_CLIENT_CMDU(info, INFO, "INFO");
2687 SILC_CLIENT_CMDU(stats, STATS, "STATS");
2688 SILC_CLIENT_CMDU(ping, PING, "PING");
2689 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2690 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2691 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2692 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2693 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2694 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2695 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2696 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2697 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2698 SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2699 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2700 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2701 SILC_CLIENT_CMDU(users, USERS, "USERS");
2702 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2703 SILC_CLIENT_CMDU(service, SERVICE, "SERVICE");
2706 /****************** Client Side Incoming Command Handling *******************/
2708 /* Reply to WHOIS command from server */
2710 static void silc_client_command_process_whois(SilcClient client,
2711 SilcClientConnection conn,
2712 SilcCommandPayload payload,
2713 SilcArgumentPayload args)
2719 SilcBuffer buffer, packet;
2721 SILC_LOG_DEBUG(("Received WHOIS command"));
2723 /* Try to take the Requested Attributes */
2724 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
2728 attrs = silc_attribute_payload_parse(tmp, tmp_len);
2732 /* Process requested attributes */
2733 buffer = silc_client_attributes_process(client, conn, attrs);
2735 silc_attribute_payload_list_free(attrs);
2739 /* Send the attributes back */
2741 silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
2743 silc_command_get_ident(payload),
2744 1, 11, buffer->data, buffer->len);
2745 silc_client_packet_send(client, sock, SILC_PACKET_COMMAND_REPLY,
2746 NULL, 0, NULL, NULL, packet->data,
2748 silc_buffer_free(packet);
2749 silc_buffer_free(buffer);
2753 /* Client is able to receive some command packets even though they are
2754 special case. Server may send WHOIS command to the client to retrieve
2755 Requested Attributes information for WHOIS query the server is
2756 processing. This function currently handles only the WHOIS command,
2757 but if in the future more commands may arrive then this can be made
2758 to support other commands too. */
2760 SILC_FSM_STATE(silc_client_command)
2762 SilcClientConnection conn = fsm_context;
2763 SilcClient client = conn->client;
2764 SilcPacket packet = state_context;
2765 SilcCommandPayload payload;
2766 SilcCommand command;
2767 SilcArgumentPayload args;
2769 /* Get command payload from packet */
2770 payload = silc_command_payload_parse(packet->buffer.data,
2771 silc_buffer_len(&packet->buffer));
2773 SILC_LOG_DEBUG(("Bad command packet"));
2774 return SILC_FSM_FINISH;
2778 args = silc_command_get_args(payload);
2780 /* Get the command */
2781 command = silc_command_get(payload);
2784 case SILC_COMMAND_WHOIS:
2785 /* Ignore everything if requested by application */
2786 if (client->internal->params->ignore_requested_attributes)
2789 silc_client_command_process_whois(client, conn, payload, args);
2796 silc_command_payload_free(payload);
2797 return SILC_FSM_FINISH;