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(conn->client, conn, SILC_COMMAND_WHOIS,
593 silc_buffer_datalen(conn->internal->local_idp));
597 for (i = 1; i < cmd->argc; i++) {
598 if (!strcasecmp(cmd->argv[i], "-details")) {
600 } else if (!strcasecmp(cmd->argv[i], "-pubkey") && cmd->argc > i + 1) {
601 pubkey = cmd->argv[i + 1];
604 /* We assume that the first parameter is the nickname, if it isn't
605 -details or -pubkey. The last parameter should always be the count */
608 } else if (i == cmd->argc - 1) {
609 int c = atoi(cmd->argv[i]);
610 SILC_PUT32_MSB(c, count);
617 /* If pubkey is set, add all attributes to the attrs buffer, except
620 attrs = silc_client_attributes_request(SILC_ATTRIBUTE_USER_INFO,
621 SILC_ATTRIBUTE_SERVICE,
622 SILC_ATTRIBUTE_STATUS_MOOD,
623 SILC_ATTRIBUTE_STATUS_FREETEXT,
624 SILC_ATTRIBUTE_STATUS_MESSAGE,
625 SILC_ATTRIBUTE_PREFERRED_LANGUAGE,
626 SILC_ATTRIBUTE_PREFERRED_CONTACT,
627 SILC_ATTRIBUTE_TIMEZONE,
628 SILC_ATTRIBUTE_GEOLOCATION,
629 SILC_ATTRIBUTE_DEVICE_INFO,
630 SILC_ATTRIBUTE_USER_ICON, 0);
632 attrs = silc_client_attributes_request(0);
637 SilcAttributeObjPk obj;
640 if (!silc_pkcs_load_public_key(pubkey, &pk)) {
641 SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR,
642 "Could not load public key %s, check the filename",
644 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
648 switch (silc_pkcs_get_type(pk)) {
650 obj.type = "silc-rsa";
653 obj.type = "ssh-rsa";
655 case SILC_PKCS_X509V3:
656 obj.type = "x509v3-sign-rsa";
658 case SILC_PKCS_OPENPGP:
659 obj.type = "pgp-sign-rsa";
665 obj.data = silc_pkcs_public_key_encode(pk, &obj.data_len);
667 attrs = silc_attribute_payload_encode(attrs,
668 SILC_ATTRIBUTE_USER_PUBLIC_KEY,
669 SILC_ATTRIBUTE_FLAG_VALID,
674 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
675 3, 1, nick ? cmd->argv[1] : NULL,
676 nick ? cmd->argv_lens[1] : 0,
677 2, tmp ? tmp : NULL, tmp ? 4 : 0,
678 3, silc_buffer_datalen(attrs));
680 /* Notify application */
681 COMMAND(SILC_STATUS_OK);
683 /** Wait for command reply */
684 silc_fsm_next(fsm, silc_client_command_reply_wait);
685 return SILC_FSM_CONTINUE;
688 return SILC_FSM_FINISH;
691 /******************************** WHOWAS ************************************/
693 /* Command WHOWAS. This command is used to query history information about
694 specific user that used to exist in the network. */
696 SILC_FSM_STATE(silc_client_command_whowas)
698 SilcClientCommandContext cmd = fsm_context;
699 SilcClientConnection conn = cmd->conn;
700 unsigned char count[4];
703 if (cmd->argc < 2 || cmd->argc > 3) {
704 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
705 "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
706 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
707 SILC_STATUS_ERR_TOO_MANY_PARAMS));
708 return SILC_FSM_FINISH;
711 if (cmd->argc == 2) {
712 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
713 1, 1, cmd->argv[1], cmd->argv_lens[1]);
715 c = atoi(cmd->argv[2]);
716 SILC_PUT32_MSB(c, count);
717 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
718 2, 1, cmd->argv[1], cmd->argv_lens[1],
719 2, count, sizeof(count));
722 /* Notify application */
723 COMMAND(SILC_STATUS_OK);
725 /** Wait for command reply */
726 silc_fsm_next(fsm, silc_client_command_reply_wait);
727 return SILC_FSM_CONTINUE;
730 /******************************** IDENTIFY **********************************/
732 /* Command IDENTIFY. This command is used to query information about
733 specific user, especially ID's. */
735 SILC_FSM_STATE(silc_client_command_identify)
737 SilcClientCommandContext cmd = fsm_context;
738 SilcClientConnection conn = cmd->conn;
739 unsigned char count[4];
742 if (cmd->argc < 2 || cmd->argc > 3)
743 return SILC_FSM_FINISH;
745 if (cmd->argc == 2) {
746 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
747 1, 1, cmd->argv[1], cmd->argv_lens[1]);
749 c = atoi(cmd->argv[2]);
750 SILC_PUT32_MSB(c, count);
751 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
752 2, 1, cmd->argv[1], cmd->argv_lens[1],
753 4, count, sizeof(count));
756 /** Wait for command reply */
757 silc_fsm_next(fsm, silc_client_command_reply_wait);
758 return SILC_FSM_CONTINUE;
761 /********************************** NICK ************************************/
763 /* Command NICK. Shows current nickname/sets new nickname on current
766 SILC_FSM_STATE(silc_client_command_nick)
768 SilcClientCommandContext cmd = fsm_context;
769 SilcClientConnection conn = cmd->conn;
772 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
773 "Usage: /NICK <nickname>");
774 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
778 if (silc_utf8_strcasecmp(conn->local_entry->nickname, cmd->argv[1]))
781 /* Show current nickname */
784 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
785 "Your nickname is %s on server %s",
786 conn->local_entry->nickname, conn->remote_host);
788 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
789 "Your nickname is %s", conn->local_entry->nickname);
792 COMMAND(SILC_STATUS_OK);
796 if (cmd->argv_lens[1] > 128)
797 cmd->argv_lens[1] = 128;
799 /* Send the NICK command */
800 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
801 1, 1, cmd->argv[1], cmd->argv_lens[1]);
803 /* Notify application */
804 COMMAND(SILC_STATUS_OK);
806 /** Wait for command reply */
807 silc_fsm_next(fsm, silc_client_command_reply_wait);
808 return SILC_FSM_CONTINUE;
811 return SILC_FSM_FINISH;
814 /********************************** LIST ************************************/
816 /* Command LIST. Lists channels on the current server. */
818 SILC_FSM_STATE(silc_client_command_list)
820 SilcClientCommandContext cmd = fsm_context;
821 SilcClientConnection conn = cmd->conn;
822 SilcChannelEntry channel;
823 SilcBuffer idp = NULL;
825 if (cmd->argc == 2) {
826 /* Get the Channel ID of the channel */
827 channel = silc_client_get_channel(conn->client, cmd->conn, cmd->argv[1]);
829 idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
833 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
835 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
836 1, 1, silc_buffer_datalen(idp));
838 silc_buffer_free(idp);
840 /* Notify application */
841 COMMAND(SILC_STATUS_OK);
843 /** Wait for command reply */
844 silc_fsm_next(fsm, silc_client_command_reply_wait);
845 return SILC_FSM_CONTINUE;
848 /********************************** TOPIC ***********************************/
850 /* Command TOPIC. Sets/shows topic on a channel. */
852 SILC_FSM_STATE(silc_client_command_topic)
854 SilcClientCommandContext cmd = fsm_context;
855 SilcClientConnection conn = cmd->conn;
856 SilcChannelEntry channel;
860 if (cmd->argc < 2 || cmd->argc > 3) {
861 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
862 "Usage: /TOPIC <channel> [<topic>]");
863 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
864 SILC_STATUS_ERR_TOO_MANY_PARAMS));
868 if (cmd->argv[1][0] == '*') {
869 if (!conn->current_channel) {
870 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
873 name = conn->current_channel->channel_name;
878 if (!conn->current_channel) {
879 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
883 /* Get the Channel ID of the channel */
884 channel = silc_client_get_channel(conn->client, conn, name);
886 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
890 idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
892 /* Send TOPIC command to the server */
894 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
895 1, silc_buffer_datalen(idp),
896 2, cmd->argv[2], strlen(cmd->argv[2]));
898 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
899 1, silc_buffer_datalen(idp));
901 silc_buffer_free(idp);
903 /* Notify application */
904 COMMAND(SILC_STATUS_OK);
906 /** Wait for command reply */
907 silc_fsm_next(fsm, silc_client_command_reply_wait);
908 return SILC_FSM_CONTINUE;
911 return SILC_FSM_FINISH;
914 /********************************* INVITE ***********************************/
916 /* Command INVITE. Invites specific client to join a channel. This is
917 also used to mange the invite list of the channel. */
919 SILC_FSM_STATE(silc_client_command_invite)
921 SilcClientCommandContext cmd = fsm_context;
922 SilcClientConnection conn = cmd->conn;
923 SilcClient client = conn->client;
924 SilcClientEntry client_entry = NULL;
925 SilcChannelEntry channel;
926 SilcBuffer clidp, chidp, args = NULL;
927 SilcPublicKey pubkey = NULL;
928 SilcDList clients = NULL;
929 char *nickname = NULL, *name;
931 unsigned char action[1];
934 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
935 "Usage: /INVITE <channel> [<nickname>[@server>]"
936 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
937 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
941 if (cmd->argv[1][0] == '*') {
942 if (!conn->current_channel) {
943 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
947 channel = conn->current_channel;
951 channel = silc_client_get_channel(conn->client, conn, name);
953 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
958 /* Parse the typed nickname. */
959 if (cmd->argc == 3) {
960 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
961 if (client->internal->params->nickname_parse)
962 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
964 nickname = strdup(cmd->argv[2]);
966 /* Find client entry */
967 clients = silc_client_get_clients_local(client, conn, nickname,
970 /* Resolve client information */
971 SILC_FSM_CALL(silc_client_get_clients(
972 client, conn, nickname,
974 silc_client_command_resolve_continue,
977 client_entry = silc_dlist_get(clients);
979 if (cmd->argv[2][0] == '+')
984 /* Check if it is public key file to be added to invite list */
985 silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey);
986 invite = cmd->argv[2];
993 args = silc_buffer_alloc_size(2);
994 silc_buffer_format(args,
995 SILC_STR_UI_SHORT(1),
998 chidp = silc_public_key_payload_encode(pubkey);
999 args = silc_argument_payload_encode_one(args, silc_buffer_data(chidp),
1000 silc_buffer_len(chidp), 2);
1001 silc_buffer_free(chidp);
1002 silc_pkcs_public_key_free(pubkey);
1004 args = silc_argument_payload_encode_one(args, invite, strlen(invite), 1);
1008 /* Send the command */
1009 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
1011 clidp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT);
1012 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 4,
1013 1, silc_buffer_datalen(chidp),
1014 2, silc_buffer_datalen(clidp),
1015 3, args ? action : NULL, args ? 1 : 0,
1016 4, silc_buffer_datalen(args));
1017 silc_buffer_free(clidp);
1019 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
1020 1, silc_buffer_datalen(chidp),
1021 3, args ? action : NULL, args ? 1 : 0,
1022 4, silc_buffer_datalen(args));
1025 silc_buffer_free(chidp);
1026 silc_buffer_free(args);
1027 silc_free(nickname);
1028 silc_client_list_free(client, conn, clients);
1030 /* Notify application */
1031 COMMAND(SILC_STATUS_OK);
1033 /** Wait for command reply */
1034 silc_fsm_next(fsm, silc_client_command_reply_wait);
1035 return SILC_FSM_CONTINUE;
1038 silc_free(nickname);
1039 return SILC_FSM_FINISH;
1042 /********************************** QUIT ************************************/
1044 /* Close the connection */
1046 SILC_FSM_STATE(silc_client_command_quit_final)
1048 SilcClientCommandContext cmd = fsm_context;
1049 SilcClientConnection conn = cmd->conn;
1050 SilcClient client = conn->client;
1052 /* Notify application */
1053 COMMAND(SILC_STATUS_OK);
1055 /* Call connection callback */
1056 conn->callback(client, conn, SILC_CLIENT_CONN_DISCONNECTED,
1057 0, NULL, conn->callback_context);
1059 /* Signal to close connection */
1060 conn->internal->disconnected = TRUE;
1061 SILC_FSM_SEMA_POST(&conn->internal->wait_event);
1063 return SILC_FSM_FINISH;
1066 /* Command QUIT. Closes connection with current server. */
1068 SILC_FSM_STATE(silc_client_command_quit)
1070 SilcClientCommandContext cmd = fsm_context;
1071 SilcClientConnection conn = cmd->conn;
1074 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1075 1, cmd->argv[1], cmd->argv_lens[1]);
1077 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
1079 /* Sleep for a while */
1082 /* We close the connection with a little timeout */
1083 silc_fsm_next_later(fsm, silc_client_command_quit_final, 2, 0);
1084 return SILC_FSM_WAIT;
1087 /********************************** KILL ************************************/
1090 /* Command KILL. Router operator can use this command to remove an client
1091 fromthe SILC Network. */
1093 SILC_FSM_STATE(silc_client_command_kill)
1095 SilcClientCommandContext cmd = fsm_context;
1096 SilcClientConnection conn = cmd->conn;
1097 SilcClient client = conn->client;
1098 SilcBuffer idp, auth = NULL;
1099 SilcClientEntry target;
1101 char *nickname = NULL, *comment = NULL;
1103 if (cmd->argc < 2) {
1104 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1105 "Usage: /KILL <nickname> [<comment>] [-pubkey]");
1106 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1107 return SILC_FSM_FINISH;
1110 /* Parse the typed nickname. */
1111 if (client->internal->params->nickname_parse)
1112 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
1114 nickname = strdup(cmd->argv[1]);
1116 return SILC_FSM_FINISH;
1118 /* Get the target client */
1119 clients = silc_client_get_clients_local(client, conn, nickname,
1122 /* Resolve client information */
1123 SILC_FSM_CALL(silc_client_get_clients(client, conn, nickname,
1125 silc_client_command_resolve_continue,
1128 target = silc_dlist_get(clients);
1130 if (cmd->argc >= 3) {
1131 if (strcasecmp(cmd->argv[2], "-pubkey"))
1132 comment = cmd->argv[2];
1134 if (!strcasecmp(cmd->argv[2], "-pubkey") ||
1135 (cmd->argc >= 4 && !strcasecmp(cmd->argv[3], "-pubkey"))) {
1136 /* Encode the public key authentication payload */
1137 auth = silc_auth_public_key_auth_generate(conn->public_key,
1140 conn->internal->sha1hash,
1141 &target->id, SILC_ID_CLIENT);
1145 /* Send the KILL command to the server */
1146 idp = silc_id_payload_encode(&target->id, SILC_ID_CLIENT);
1147 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
1148 1, silc_buffer_datalen(idp),
1149 2, comment, comment ? strlen(comment) : 0,
1150 3, silc_buffer_datalen(auth));
1151 silc_buffer_free(idp);
1152 silc_buffer_free(auth);
1153 silc_free(nickname);
1154 silc_client_list_free(client, conn, clients);
1156 /* Notify application */
1157 COMMAND(SILC_STATUS_OK);
1159 /** Wait for command reply */
1160 silc_fsm_next(fsm, silc_client_command_reply_wait);
1161 return SILC_FSM_CONTINUE;
1164 /********************************** INFO ************************************/
1166 /* Command INFO. Request information about specific server. If specific
1167 server is not provided the current server is used. */
1169 SILC_FSM_STATE(silc_client_command_info)
1171 SilcClientCommandContext cmd = fsm_context;
1172 SilcClientConnection conn = cmd->conn;
1174 /* Send the command */
1176 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1177 1, cmd->argv[1], cmd->argv_lens[1]);
1179 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
1181 /* Notify application */
1182 COMMAND(SILC_STATUS_OK);
1184 /** Wait for command reply */
1185 silc_fsm_next(fsm, silc_client_command_reply_wait);
1186 return SILC_FSM_CONTINUE;
1189 /********************************** STATS ***********************************/
1191 /* Command STATS. Shows server and network statistics. */
1193 SILC_FSM_STATE(silc_client_command_stats)
1195 SilcClientCommandContext cmd = fsm_context;
1196 SilcClientConnection conn = cmd->conn;
1198 if (cmd->argc < 2) {
1199 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1200 return SILC_FSM_FINISH;
1203 /* Send the command */
1204 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1205 1, silc_buffer_datalen(conn->internal->
1208 /* Notify application */
1209 COMMAND(SILC_STATUS_OK);
1211 /** Wait for command reply */
1212 silc_fsm_next(fsm, silc_client_command_reply_wait);
1213 return SILC_FSM_CONTINUE;
1216 /********************************** PING ************************************/
1218 /* Command PING. Sends ping to server. */
1220 SILC_FSM_STATE(silc_client_command_ping)
1222 SilcClientCommandContext cmd = fsm_context;
1223 SilcClientConnection conn = cmd->conn;
1225 if (cmd->argc < 2) {
1226 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1227 return SILC_FSM_FINISH;
1230 /* Send the command */
1231 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1232 1, silc_buffer_datalen(conn->internal->
1235 /* Save ping time */
1236 cmd->context = SILC_64_TO_PTR(silc_time());
1238 /* Notify application */
1239 COMMAND(SILC_STATUS_OK);
1241 /** Wait for command reply */
1242 silc_fsm_next(fsm, silc_client_command_reply_wait);
1243 return SILC_FSM_CONTINUE;
1246 /********************************** JOIN ************************************/
1248 /* Command JOIN. Joins to a channel. */
1250 SILC_FSM_STATE(silc_client_command_join)
1252 SilcClientCommandContext cmd = fsm_context;
1253 SilcClientConnection conn = cmd->conn;
1254 SilcChannelEntry channel;
1255 SilcBuffer auth = NULL, cauth = NULL;
1256 char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
1257 int i, passphrase_len = 0;
1259 if (cmd->argc < 2) {
1260 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1264 /* See if we have joined to the requested channel already */
1265 channel = silc_client_get_channel(conn->client, conn, cmd->argv[1]);
1266 if (channel && silc_client_on_channel(channel, conn->local_entry))
1269 if (cmd->argv_lens[1] > 256)
1270 cmd->argv_lens[1] = 256;
1272 name = cmd->argv[1];
1274 for (i = 2; i < cmd->argc; i++) {
1275 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
1276 cipher = cmd->argv[++i];
1277 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
1278 hmac = cmd->argv[++i];
1279 } else if (!strcasecmp(cmd->argv[i], "-founder")) {
1280 auth = silc_auth_public_key_auth_generate(conn->public_key,
1283 conn->internal->sha1hash,
1286 } else if (!strcasecmp(cmd->argv[i], "-auth")) {
1287 SilcPublicKey pubkey = conn->public_key;
1288 SilcPrivateKey privkey = conn->private_key;
1289 unsigned char *pk, pkhash[SILC_HASH_MAXLEN], *pubdata;
1292 if (cmd->argc >= i + 3) {
1294 if (cmd->argc >= i + 4) {
1295 pass = cmd->argv[i + 3];
1298 if (!silc_load_key_pair(cmd->argv[i + 1], cmd->argv[i + 2], pass,
1299 &pubkey, &privkey)) {
1300 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1301 "Could not load key pair, check your arguments");
1302 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1308 pk = silc_pkcs_public_key_encode(pubkey, &pk_len);
1309 silc_hash_make(conn->internal->sha1hash, pk, pk_len, pkhash);
1311 pubdata = silc_rng_get_rn_data(conn->client->rng, 128);
1312 memcpy(pubdata, pkhash, 20);
1313 cauth = silc_auth_public_key_auth_generate_wpub(pubkey, privkey,
1315 conn->internal->sha1hash,
1318 memset(pubdata, 0, 128);
1321 /* Passphrases must be UTF-8 encoded, so encode if it is not */
1322 if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
1323 passphrase_len = silc_utf8_encoded_len(cmd->argv[i],
1324 cmd->argv_lens[i], 0);
1325 pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
1326 passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
1327 0, pu8, passphrase_len);
1330 passphrase = strdup(cmd->argv[i]);
1331 passphrase_len = cmd->argv_lens[i];
1336 /* Send JOIN command to the server */
1337 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 7,
1338 1, name, strlen(name),
1339 2, silc_buffer_datalen(conn->internal->
1341 3, passphrase, passphrase_len,
1342 4, cipher, cipher ? strlen(cipher) : 0,
1343 5, hmac, hmac ? strlen(hmac) : 0,
1344 6, silc_buffer_datalen(auth),
1345 7, silc_buffer_datalen(cauth));
1347 silc_buffer_free(auth);
1348 silc_buffer_free(cauth);
1350 memset(passphrase, 0, strlen(passphrase));
1351 silc_free(passphrase);
1353 /* Notify application */
1354 COMMAND(SILC_STATUS_OK);
1356 /** Wait for command reply */
1357 silc_fsm_next(fsm, silc_client_command_reply_wait);
1358 return SILC_FSM_CONTINUE;
1361 return SILC_FSM_FINISH;
1364 /********************************** MOTD ************************************/
1366 /* MOTD command. Requests motd from server. */
1368 SILC_FSM_STATE(silc_client_command_motd)
1370 SilcClientCommandContext cmd = fsm_context;
1371 SilcClientConnection conn = cmd->conn;
1373 if (cmd->argc < 1 || cmd->argc > 2) {
1374 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1375 "Usage: /MOTD [<server>]");
1376 COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
1377 SILC_STATUS_ERR_TOO_MANY_PARAMS));
1378 return SILC_FSM_FINISH;
1381 /* Send the command */
1383 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1384 1, conn->remote_host,
1385 strlen(conn->remote_host));
1387 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1388 1, cmd->argv[1], cmd->argv_lens[1]);
1390 /* Notify application */
1391 COMMAND(SILC_STATUS_OK);
1393 /** Wait for command reply */
1394 silc_fsm_next(fsm, silc_client_command_reply_wait);
1395 return SILC_FSM_CONTINUE;
1398 /********************************** UMODE ***********************************/
1400 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1401 modes as client cannot set itself server/router operator privileges. */
1403 SILC_FSM_STATE(silc_client_command_umode)
1405 SilcClientCommandContext cmd = fsm_context;
1406 SilcClientConnection conn = cmd->conn;
1407 unsigned char *cp, modebuf[4];
1408 SilcUInt32 mode, add, len;
1411 if (cmd->argc < 2) {
1412 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1413 "Usage: /UMODE +|-<modes>");
1414 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1415 return SILC_FSM_FINISH;
1418 mode = conn->local_entry->mode;
1420 /* Are we adding or removing mode */
1421 if (cmd->argv[1][0] == '-')
1427 cp = cmd->argv[1] + 1;
1429 for (i = 0; i < len; i++) {
1434 mode |= SILC_UMODE_SERVER_OPERATOR;
1435 mode |= SILC_UMODE_ROUTER_OPERATOR;
1436 mode |= SILC_UMODE_GONE;
1437 mode |= SILC_UMODE_INDISPOSED;
1438 mode |= SILC_UMODE_BUSY;
1439 mode |= SILC_UMODE_PAGE;
1440 mode |= SILC_UMODE_HYPER;
1441 mode |= SILC_UMODE_ROBOT;
1442 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1443 mode |= SILC_UMODE_REJECT_WATCHING;
1445 mode = SILC_UMODE_NONE;
1450 mode |= SILC_UMODE_SERVER_OPERATOR;
1452 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1456 mode |= SILC_UMODE_ROUTER_OPERATOR;
1458 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1462 mode |= SILC_UMODE_GONE;
1464 mode &= ~SILC_UMODE_GONE;
1468 mode |= SILC_UMODE_INDISPOSED;
1470 mode &= ~SILC_UMODE_INDISPOSED;
1474 mode |= SILC_UMODE_BUSY;
1476 mode &= ~SILC_UMODE_BUSY;
1480 mode |= SILC_UMODE_PAGE;
1482 mode &= ~SILC_UMODE_PAGE;
1486 mode |= SILC_UMODE_HYPER;
1488 mode &= ~SILC_UMODE_HYPER;
1492 mode |= SILC_UMODE_ROBOT;
1494 mode &= ~SILC_UMODE_ROBOT;
1498 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1500 mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
1504 mode |= SILC_UMODE_REJECT_WATCHING;
1506 mode &= ~SILC_UMODE_REJECT_WATCHING;
1510 mode |= SILC_UMODE_BLOCK_INVITE;
1512 mode &= ~SILC_UMODE_BLOCK_INVITE;
1515 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1516 return SILC_FSM_FINISH;
1521 SILC_PUT32_MSB(mode, modebuf);
1523 /* Send the command */
1524 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
1525 1, silc_buffer_datalen(conn->internal->
1527 2, modebuf, sizeof(modebuf));
1529 /* Notify application */
1530 COMMAND(SILC_STATUS_OK);
1532 /** Wait for command reply */
1533 silc_fsm_next(fsm, silc_client_command_reply_wait);
1534 return SILC_FSM_CONTINUE;
1537 /********************************** CMODE ***********************************/
1539 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1540 can be set several at once. Those modes that require argument must be set
1541 separately (unless set with modes that does not require arguments). */
1543 SILC_FSM_STATE(silc_client_command_cmode)
1545 SilcClientCommandContext cmd = fsm_context;
1546 SilcClientConnection conn = cmd->conn;
1547 SilcClient client = conn->client;
1548 SilcChannelEntry channel;
1549 SilcBuffer chidp, auth = NULL, pk = NULL;
1550 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1551 SilcUInt32 mode, add, type, len, arg_len = 0;
1554 if (cmd->argc < 3) {
1555 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1556 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1557 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1561 if (cmd->argv[1][0] == '*') {
1562 if (!conn->current_channel) {
1563 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1567 channel = conn->current_channel;
1569 name = cmd->argv[1];
1571 channel = silc_client_get_channel(conn->client, conn, name);
1573 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1578 mode = channel->mode;
1580 /* Are we adding or removing mode */
1581 if (cmd->argv[2][0] == '-')
1586 /* Argument type to be sent to server */
1590 cp = cmd->argv[2] + 1;
1592 for (i = 0; i < len; i++) {
1596 mode |= SILC_CHANNEL_MODE_PRIVATE;
1598 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1602 mode |= SILC_CHANNEL_MODE_SECRET;
1604 mode &= ~SILC_CHANNEL_MODE_SECRET;
1608 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1610 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1614 mode |= SILC_CHANNEL_MODE_INVITE;
1616 mode &= ~SILC_CHANNEL_MODE_INVITE;
1620 mode |= SILC_CHANNEL_MODE_TOPIC;
1622 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1626 mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1628 mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1632 mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1634 mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1639 mode |= SILC_CHANNEL_MODE_ULIMIT;
1641 if (cmd->argc < 4) {
1642 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1643 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1644 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1647 ll = atoi(cmd->argv[3]);
1648 SILC_PUT32_MSB(ll, tmp);
1652 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1657 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1659 if (cmd->argc < 4) {
1660 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1661 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1662 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1666 arg_len = cmd->argv_lens[3];
1668 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1673 mode |= SILC_CHANNEL_MODE_CIPHER;
1675 if (cmd->argc < 4) {
1676 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1677 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1678 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1682 arg_len = cmd->argv_lens[3];
1684 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1689 mode |= SILC_CHANNEL_MODE_HMAC;
1691 if (cmd->argc < 4) {
1692 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1693 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1694 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1698 arg_len = cmd->argv_lens[3];
1700 mode &= ~SILC_CHANNEL_MODE_HMAC;
1705 SilcPublicKey pubkey = conn->public_key;
1706 SilcPrivateKey privkey = conn->private_key;
1708 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1711 if (cmd->argc >= 5) {
1714 pass = cmd->argv[5];
1715 if (!silc_load_key_pair(cmd->argv[3], cmd->argv[4], pass,
1716 &pubkey, &privkey)) {
1717 SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1718 "Could not load key pair, check your arguments");
1719 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1724 pk = silc_public_key_payload_encode(pubkey);
1725 auth = silc_auth_public_key_auth_generate(pubkey, privkey,
1727 conn->internal->sha1hash,
1730 arg = silc_buffer_data(auth);
1731 arg_len = silc_buffer_len(auth);
1733 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1739 SilcBool chadd = FALSE;
1740 SilcPublicKey chpk = NULL;
1742 mode |= SILC_CHANNEL_MODE_CHANNEL_AUTH;
1745 if (cmd->argc == 3) {
1746 /* Send empty command to receive the public key list. */
1747 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
1748 silc_client_command_send_va(conn, cmd, SILC_COMMAND_CMODE,
1750 1, silc_buffer_datalen(chidp));
1751 silc_buffer_free(chidp);
1753 /* Notify application */
1754 COMMAND(SILC_STATUS_OK);
1758 if (cmd->argc >= 4) {
1759 auth = silc_buffer_alloc_size(2);
1760 silc_buffer_format(auth,
1761 SILC_STR_UI_SHORT(cmd->argc - 3),
1765 for (k = 3; k < cmd->argc; k++) {
1766 if (cmd->argv[k][0] == '+')
1768 if (!silc_pkcs_load_public_key(cmd->argv[k] + 1, &chpk)) {
1769 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1770 "Could not load public key %s, check the filename",
1772 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1773 silc_buffer_free(auth);
1778 pk = silc_public_key_payload_encode(chpk);
1779 auth = silc_argument_payload_encode_one(auth,
1780 silc_buffer_datalen(pk),
1781 chadd ? 0x00 : 0x01);
1782 silc_pkcs_public_key_free(chpk);
1783 silc_buffer_free(pk);
1788 arg = silc_buffer_data(auth);
1789 arg_len = silc_buffer_len(auth);
1791 mode &= ~SILC_CHANNEL_MODE_CHANNEL_AUTH;
1795 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1801 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
1802 SILC_PUT32_MSB(mode, modebuf);
1804 /* Send the command. We support sending only one mode at once that
1805 requires an argument. */
1807 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 4,
1808 1, silc_buffer_datalen(chidp),
1809 2, modebuf, sizeof(modebuf),
1811 8, silc_buffer_datalen(pk));
1813 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
1814 1, silc_buffer_datalen(chidp),
1815 2, modebuf, sizeof(modebuf));
1818 silc_buffer_free(chidp);
1819 silc_buffer_free(auth);
1820 silc_buffer_free(pk);
1822 /* Notify application */
1823 COMMAND(SILC_STATUS_OK);
1825 /** Wait for command reply */
1826 silc_fsm_next(fsm, silc_client_command_reply_wait);
1827 return SILC_FSM_CONTINUE;
1830 return SILC_FSM_FINISH;
1833 /********************************* CUMODE ***********************************/
1835 /* CUMODE command. Changes client's mode on a channel. */
1837 SILC_FSM_STATE(silc_client_command_cumode)
1839 SilcClientCommandContext cmd = fsm_context;
1840 SilcClientConnection conn = cmd->conn;
1841 SilcClient client = conn->client;
1842 SilcChannelEntry channel;
1843 SilcChannelUser chu;
1844 SilcClientEntry client_entry;
1845 SilcBuffer clidp, chidp, auth = NULL;
1846 SilcDList clients = NULL;
1847 unsigned char *name, *cp, modebuf[4];
1848 SilcUInt32 mode = 0, add, len;
1849 char *nickname = NULL;
1852 if (cmd->argc < 4) {
1853 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1854 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1855 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1859 if (cmd->argv[1][0] == '*') {
1860 if (!conn->current_channel) {
1861 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1865 channel = conn->current_channel;
1867 name = cmd->argv[1];
1869 channel = silc_client_get_channel(conn->client, conn, name);
1871 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1876 /* Parse the typed nickname. */
1877 if (client->internal->params->nickname_parse)
1878 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1880 nickname = strdup(cmd->argv[3]);
1882 /* Find client entry */
1883 clients = silc_client_get_clients_local(client, conn, nickname,
1886 /* Resolve client information */
1887 SILC_FSM_CALL(silc_client_get_clients(client, conn, nickname, cmd->argv[3],
1888 silc_client_command_resolve_continue,
1891 client_entry = silc_dlist_get(clients);
1893 /* Get the current mode */
1894 chu = silc_client_on_channel(channel, client_entry);
1898 /* Are we adding or removing mode */
1899 if (cmd->argv[2][0] == '-')
1905 cp = cmd->argv[2] + 1;
1907 for (i = 0; i < len; i++) {
1911 mode |= SILC_CHANNEL_UMODE_CHANFO;
1912 mode |= SILC_CHANNEL_UMODE_CHANOP;
1913 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1914 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1915 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1917 mode = SILC_CHANNEL_UMODE_NONE;
1922 SilcPublicKey pubkey = conn->public_key;
1923 SilcPrivateKey privkey = conn->private_key;
1925 if (cmd->argc >= 6) {
1928 pass = cmd->argv[6];
1929 if (!silc_load_key_pair(cmd->argv[4], cmd->argv[5], pass,
1930 &pubkey, &privkey)) {
1931 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1932 "Could not load key pair, check your arguments");
1933 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1938 auth = silc_auth_public_key_auth_generate(pubkey, privkey,
1940 conn->internal->sha1hash,
1943 mode |= SILC_CHANNEL_UMODE_CHANFO;
1945 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1950 mode |= SILC_CHANNEL_UMODE_CHANOP;
1952 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1956 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1958 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1962 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1964 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1968 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1970 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1974 mode |= SILC_CHANNEL_UMODE_QUIET;
1976 mode &= ~SILC_CHANNEL_UMODE_QUIET;
1979 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1985 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
1986 SILC_PUT32_MSB(mode, modebuf);
1987 clidp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT);
1989 /* Send the command packet. We support sending only one mode at once
1990 that requires an argument. */
1991 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, auth ? 4 : 3,
1992 1, silc_buffer_datalen(chidp),
1994 3, silc_buffer_datalen(clidp),
1995 4, silc_buffer_datalen(auth));
1997 silc_buffer_free(chidp);
1998 silc_buffer_free(clidp);
2000 silc_buffer_free(auth);
2001 silc_free(nickname);
2002 silc_client_list_free(client, conn, clients);
2004 /* Notify application */
2005 COMMAND(SILC_STATUS_OK);
2007 /** Wait for command reply */
2008 silc_fsm_next(fsm, silc_client_command_reply_wait);
2009 return SILC_FSM_CONTINUE;
2012 silc_client_list_free(client, conn, clients);
2013 silc_free(nickname);
2014 return SILC_FSM_FINISH;
2017 /********************************** KICK ************************************/
2019 /* KICK command. Kicks a client out of channel. */
2021 SILC_FSM_STATE(silc_client_command_kick)
2023 SilcClientCommandContext cmd = fsm_context;
2024 SilcClientConnection conn = cmd->conn;
2025 SilcClient client = conn->client;
2026 SilcChannelEntry channel;
2027 SilcBuffer idp, idp2;
2028 SilcClientEntry target;
2029 SilcDList clients = NULL;
2031 char *nickname = NULL;
2033 if (cmd->argc < 3) {
2034 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2035 "Usage: /KICK <channel> <nickname> [<comment>]");
2036 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2040 if (cmd->argv[1][0] == '*') {
2041 if (!conn->current_channel) {
2042 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2045 name = conn->current_channel->channel_name;
2047 name = cmd->argv[1];
2050 if (!conn->current_channel) {
2051 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2055 /* Get the Channel ID of the channel */
2056 channel = silc_client_get_channel(conn->client, conn, name);
2058 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2062 /* Parse the typed nickname. */
2063 if (client->internal->params->nickname_parse)
2064 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
2066 nickname = strdup(cmd->argv[2]);
2068 /* Get the target client */
2069 clients = silc_client_get_clients_local(client, conn, nickname,
2072 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2073 "No such client: %s", cmd->argv[2]);
2074 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2077 target = silc_dlist_get(clients);
2079 /* Send KICK command to the server */
2080 idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
2081 idp2 = silc_id_payload_encode(&target->id, SILC_ID_CLIENT);
2083 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
2084 1, silc_buffer_datalen(idp),
2085 2, silc_buffer_datalen(idp2));
2087 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
2088 1, silc_buffer_datalen(idp),
2089 2, silc_buffer_datalen(idp2),
2090 3, cmd->argv[3], strlen(cmd->argv[3]));
2092 silc_buffer_free(idp);
2093 silc_buffer_free(idp2);
2094 silc_free(nickname);
2095 silc_client_list_free(client, conn, clients);
2097 /* Notify application */
2098 COMMAND(SILC_STATUS_OK);
2100 /** Wait for command reply */
2101 silc_fsm_next(fsm, silc_client_command_reply_wait);
2102 return SILC_FSM_CONTINUE;
2105 silc_free(nickname);
2106 return SILC_FSM_FINISH;
2109 /***************************** OPER & SILCOPER ******************************/
2112 unsigned char *passphrase;
2113 SilcUInt32 passphrase_len;
2114 } *SilcClientCommandOper;
2116 /* Ask passphrase callback */
2118 static void silc_client_command_oper_cb(unsigned char *data,
2119 SilcUInt32 data_len, void *context)
2121 SilcClientCommandContext cmd = context;
2122 SilcClientCommandOper oper = cmd->context;
2124 if (data && data_len)
2125 oper->passphrase = silc_memdup(data, data_len);
2126 oper->passphrase_len = data_len;
2129 SILC_FSM_CALL_CONTINUE(&cmd->thread);
2132 /* Send OPER/SILCOPER command */
2134 SILC_FSM_STATE(silc_client_command_oper_send)
2136 SilcClientCommandContext cmd = fsm_context;
2137 SilcClientConnection conn = cmd->conn;
2138 SilcClientCommandOper oper = cmd->context;
2141 if (!oper || !oper->passphrase) {
2142 /* Encode the public key authentication payload */
2143 auth = silc_auth_public_key_auth_generate(conn->public_key,
2146 conn->internal->hash,
2150 /* Encode the password authentication payload */
2151 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
2152 oper->passphrase, oper->passphrase_len);
2155 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
2156 1, cmd->argv[1], strlen(cmd->argv[1]),
2157 2, silc_buffer_datalen(auth));
2159 silc_buffer_clear(auth);
2160 silc_buffer_free(auth);
2162 silc_free(oper->passphrase);
2166 /* Notify application */
2167 COMMAND(SILC_STATUS_OK);
2169 /** Wait for command reply */
2170 silc_fsm_next(fsm, silc_client_command_reply_wait);
2171 return SILC_FSM_CONTINUE;
2174 /* OPER command. Used to obtain server operator privileges. */
2176 SILC_FSM_STATE(silc_client_command_oper)
2178 SilcClientCommandContext cmd = fsm_context;
2179 SilcClientConnection conn = cmd->conn;
2180 SilcClientCommandOper oper;
2182 if (cmd->argc < 2) {
2183 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2184 "Usage: /OPER <username> [-pubkey]");
2185 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2186 return SILC_FSM_FINISH;
2189 /* Get passphrase */
2190 if (cmd->argc < 3) {
2191 oper = silc_calloc(1, sizeof(*oper));
2193 return SILC_FSM_FINISH;
2194 cmd->context = oper;
2195 SILC_FSM_CALL(conn->client->internal->
2196 ops->ask_passphrase(conn->client, conn,
2197 silc_client_command_oper_cb, cmd));
2200 silc_fsm_next(fsm, silc_client_command_oper_send);
2201 return SILC_FSM_CONTINUE;
2204 /* SILCOPER command. Used to obtain router operator privileges. */
2206 SILC_FSM_STATE(silc_client_command_silcoper)
2208 SilcClientCommandContext cmd = fsm_context;
2209 SilcClientConnection conn = cmd->conn;
2210 SilcClientCommandOper oper;
2212 if (cmd->argc < 2) {
2213 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2214 "Usage: /SILCOPER <username> [-pubkey]");
2215 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2216 return SILC_FSM_FINISH;
2219 /* Get passphrase */
2220 if (cmd->argc < 3) {
2221 oper = silc_calloc(1, sizeof(*oper));
2223 return SILC_FSM_FINISH;
2224 cmd->context = oper;
2225 SILC_FSM_CALL(conn->client->internal->
2226 ops->ask_passphrase(conn->client, conn,
2227 silc_client_command_oper_cb, cmd));
2230 silc_fsm_next(fsm, silc_client_command_oper_send);
2231 return SILC_FSM_CONTINUE;
2234 /*********************************** BAN ************************************/
2236 /* Command BAN. This is used to manage the ban list of the channel. */
2238 SILC_FSM_STATE(silc_client_command_ban)
2240 SilcClientCommandContext cmd = fsm_context;
2241 SilcClientConnection conn = cmd->conn;
2242 SilcChannelEntry channel;
2243 SilcBuffer chidp, args = NULL;
2244 char *name, *ban = NULL;
2245 unsigned char action[1];
2246 SilcPublicKey pubkey = NULL;
2248 if (cmd->argc < 2) {
2249 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2250 "Usage: /BAN <channel> "
2251 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
2252 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2256 if (cmd->argv[1][0] == '*') {
2257 if (!conn->current_channel) {
2258 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2262 channel = conn->current_channel;
2264 name = cmd->argv[1];
2266 channel = silc_client_get_channel(conn->client, conn, name);
2268 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2273 if (cmd->argc == 3) {
2274 if (cmd->argv[2][0] == '+')
2279 /* Check if it is public key file to be added to invite list */
2280 silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey);
2287 args = silc_buffer_alloc_size(2);
2288 silc_buffer_format(args,
2289 SILC_STR_UI_SHORT(1),
2292 chidp = silc_public_key_payload_encode(pubkey);
2293 args = silc_argument_payload_encode_one(args,
2294 silc_buffer_datalen(chidp), 2);
2295 silc_buffer_free(chidp);
2296 silc_pkcs_public_key_free(pubkey);
2298 args = silc_argument_payload_encode_one(args, ban, strlen(ban), 1);
2302 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
2304 /* Send the command */
2305 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
2306 1, silc_buffer_datalen(chidp),
2307 2, args ? action : NULL, args ? 1 : 0,
2308 3, silc_buffer_datalen(args));
2310 silc_buffer_free(chidp);
2311 silc_buffer_free(args);
2313 /* Notify application */
2314 COMMAND(SILC_STATUS_OK);
2316 /** Wait for command reply */
2317 silc_fsm_next(fsm, silc_client_command_reply_wait);
2318 return SILC_FSM_CONTINUE;
2321 return SILC_FSM_FINISH;
2324 /********************************* DETACH ***********************************/
2326 /* Command DETACH. This is used to detach from the server */
2328 SILC_FSM_STATE(silc_client_command_detach)
2330 SilcClientCommandContext cmd = fsm_context;
2331 SilcClientConnection conn = cmd->conn;
2333 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
2335 /* Notify application */
2336 COMMAND(SILC_STATUS_OK);
2338 /** Wait for command reply */
2339 silc_fsm_next(fsm, silc_client_command_reply_wait);
2340 return SILC_FSM_CONTINUE;
2343 /********************************** WATCH ***********************************/
2345 /* Command WATCH. */
2347 SILC_FSM_STATE(silc_client_command_watch)
2349 SilcClientCommandContext cmd = fsm_context;
2350 SilcClientConnection conn = cmd->conn;
2351 SilcBuffer args = NULL;
2353 const char *pubkey = NULL;
2354 SilcBool pubkey_add = TRUE;
2356 if (cmd->argc < 3) {
2357 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2361 if (!strcasecmp(cmd->argv[1], "-add")) {
2363 } else if (!strcasecmp(cmd->argv[1], "-del")) {
2365 } else if (!strcasecmp(cmd->argv[1], "-pubkey") && cmd->argc >= 3) {
2367 pubkey = cmd->argv[2] + 1;
2368 if (cmd->argv[2][0] == '-')
2371 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2379 if (!silc_pkcs_load_public_key(pubkey, &pk)) {
2380 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2381 "Could not load public key %s, check the filename", pubkey);
2382 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2386 args = silc_buffer_alloc_size(2);
2387 silc_buffer_format(args,
2388 SILC_STR_UI_SHORT(1),
2390 buffer = silc_public_key_payload_encode(pk);
2391 args = silc_argument_payload_encode_one(args, silc_buffer_datalen(buffer),
2392 pubkey_add ? 0x00 : 0x01);
2393 silc_buffer_free(buffer);
2394 silc_pkcs_public_key_free(pk);
2397 /* Send the commmand */
2398 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
2399 1, silc_buffer_datalen(conn->internal->
2401 type, pubkey ? args->data : cmd->argv[2],
2402 pubkey ? silc_buffer_len(args) :
2405 silc_buffer_free(args);
2407 /* Notify application */
2408 COMMAND(SILC_STATUS_OK);
2410 /** Wait for command reply */
2411 silc_fsm_next(fsm, silc_client_command_reply_wait);
2412 return SILC_FSM_CONTINUE;
2415 return SILC_FSM_FINISH;
2418 /********************************** LEAVE ***********************************/
2420 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2422 SILC_FSM_STATE(silc_client_command_leave)
2424 SilcClientCommandContext cmd = fsm_context;
2425 SilcClientConnection conn = cmd->conn;
2426 SilcChannelEntry channel;
2430 if (cmd->argc != 2) {
2431 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2432 "Usage: /LEAVE <channel>");
2433 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2437 if (cmd->argv[1][0] == '*') {
2438 if (!conn->current_channel) {
2439 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2442 name = conn->current_channel->channel_name;
2444 name = cmd->argv[1];
2447 /* Get the channel entry */
2448 channel = silc_client_get_channel(conn->client, conn, name);
2450 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2454 idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
2456 /* Send LEAVE command to the server */
2457 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
2458 1, silc_buffer_datalen(idp));
2460 silc_buffer_free(idp);
2462 /* Notify application */
2463 COMMAND(SILC_STATUS_OK);
2465 if (conn->current_channel == channel)
2466 conn->current_channel = NULL;
2468 /** Wait for command reply */
2469 silc_fsm_next(fsm, silc_client_command_reply_wait);
2470 return SILC_FSM_CONTINUE;
2473 return SILC_FSM_FINISH;
2476 /********************************** USERS ***********************************/
2478 /* Command USERS. Requests the USERS of the clients joined on requested
2481 SILC_FSM_STATE(silc_client_command_users)
2483 SilcClientCommandContext cmd = fsm_context;
2484 SilcClientConnection conn = cmd->conn;
2487 if (cmd->argc != 2) {
2488 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2489 "Usage: /USERS <channel>");
2490 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2494 if (cmd->argv[1][0] == '*') {
2495 if (!conn->current_channel) {
2496 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2499 name = conn->current_channel->channel_name;
2501 name = cmd->argv[1];
2504 /* Send USERS command to the server */
2505 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
2506 2, name, strlen(name));
2508 /* Notify application */
2509 COMMAND(SILC_STATUS_OK);
2511 /** Wait for command reply */
2512 silc_fsm_next(fsm, silc_client_command_reply_wait);
2513 return SILC_FSM_CONTINUE;
2516 return SILC_FSM_FINISH;
2519 /********************************* GETKEY ***********************************/
2521 /* Command GETKEY. Used to fetch remote client's public key. */
2523 SILC_FSM_STATE(silc_client_command_getkey)
2525 SilcClientCommandContext cmd = fsm_context;
2526 SilcClientConnection conn = cmd->conn;
2527 SilcClient client = conn->client;
2528 SilcClientEntry client_entry;
2529 SilcServerEntry server_entry;
2531 char *nickname = NULL;
2534 if (cmd->argc < 2) {
2535 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2536 "Usage: /GETKEY <nickname or server name>");
2537 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2538 return SILC_FSM_FINISH;
2541 /* Parse the typed nickname. */
2542 if (client->internal->params->nickname_parse)
2543 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2545 nickname = strdup(cmd->argv[1]);
2547 COMMAND_ERROR(SILC_STATUS_ERR_RESOURCE_LIMIT);
2548 return SILC_FSM_FINISH;
2551 /* Find client entry */
2552 clients = silc_client_get_clients_local(client, conn, nickname,
2555 /* Check whether user requested server */
2556 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2557 if (!server_entry) {
2558 /* No client or server exist with this name, query for both. */
2559 SILC_FSM_CALL(silc_client_command_send(client, conn,
2560 SILC_COMMAND_IDENTIFY,
2561 silc_client_command_continue,
2564 strlen(cmd->argv[1]),
2566 strlen(cmd->argv[1])));
2568 idp = silc_id_payload_encode(&server_entry->id, SILC_ID_SERVER);
2570 client_entry = silc_dlist_get(clients);
2571 idp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT);
2572 silc_client_list_free(client, conn, clients);
2575 /* Send the commmand */
2576 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
2577 1, silc_buffer_datalen(idp));
2579 silc_buffer_free(idp);
2580 silc_free(nickname);
2582 /* Notify application */
2583 COMMAND(SILC_STATUS_OK);
2585 /** Wait for command reply */
2586 silc_fsm_next(fsm, silc_client_command_reply_wait);
2587 return SILC_FSM_CONTINUE;
2590 /********************************* SERVICE **********************************/
2592 /* Command SERVICE. Negotiates service agreement with server. */
2593 /* XXX incomplete */
2595 SILC_FSM_STATE(silc_client_command_service)
2597 SilcClientCommandContext cmd = fsm_context;
2599 SilcClientConnection conn = cmd->conn;
2603 if (cmd->argc < 2) {
2604 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2605 "Usage: /SERVICE [<service name>] [-pubkey]");
2606 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2607 return SILC_FSM_FINISH;
2610 name = cmd->argv[1];
2612 /* Send SERVICE command to the server */
2613 buffer = silc_command_payload_encode_va(SILC_COMMAND_SERVICE,
2614 ++conn->cmd_ident, 1,
2615 1, name, strlen(name));
2616 silc_client_packet_send(conn->client, conn->sock, SILC_PACKET_COMMAND,
2617 NULL, 0, NULL, NULL, buffer->data,
2619 silc_buffer_free(buffer);
2622 /* Notify application */
2623 COMMAND(SILC_STATUS_OK);
2625 /** Wait for command reply */
2626 silc_fsm_next(fsm, silc_client_command_reply_wait);
2627 return SILC_FSM_CONTINUE;
2630 /* Register all default commands provided by the client library for the
2633 void silc_client_commands_register(SilcClient client)
2635 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2638 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 5);
2639 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2640 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2641 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2642 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2643 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2644 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2645 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2646 SILC_CLIENT_CMD(kill, KILL, "KILL", 4);
2647 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2648 SILC_CLIENT_CMD(stats, STATS, "STATS", 0);
2649 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2650 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2651 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2652 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2653 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2654 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 6);
2655 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 9);
2656 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2657 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2658 SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2659 SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
2660 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2661 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2662 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2663 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2664 SILC_CLIENT_CMD(service, SERVICE, "SERVICE", 10);
2667 /* Unregister all commands. */
2669 void silc_client_commands_unregister(SilcClient client)
2671 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2672 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2673 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2674 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2675 SILC_CLIENT_CMDU(list, LIST, "LIST");
2676 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2677 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2678 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2679 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2680 SILC_CLIENT_CMDU(info, INFO, "INFO");
2681 SILC_CLIENT_CMDU(stats, STATS, "STATS");
2682 SILC_CLIENT_CMDU(ping, PING, "PING");
2683 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2684 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2685 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2686 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2687 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2688 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2689 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2690 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2691 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2692 SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2693 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2694 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2695 SILC_CLIENT_CMDU(users, USERS, "USERS");
2696 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2697 SILC_CLIENT_CMDU(service, SERVICE, "SERVICE");
2700 /****************** Client Side Incoming Command Handling *******************/
2702 /* Reply to WHOIS command from server */
2704 static void silc_client_command_process_whois(SilcClient client,
2705 SilcClientConnection conn,
2706 SilcCommandPayload payload,
2707 SilcArgumentPayload args)
2713 SilcBuffer buffer, packet;
2715 SILC_LOG_DEBUG(("Received WHOIS command"));
2717 /* Try to take the Requested Attributes */
2718 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
2722 attrs = silc_attribute_payload_parse(tmp, tmp_len);
2726 /* Process requested attributes */
2727 buffer = silc_client_attributes_process(client, conn, attrs);
2729 silc_attribute_payload_list_free(attrs);
2733 /* Send the attributes back */
2735 silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
2737 silc_command_get_ident(payload),
2738 1, 11, buffer->data, buffer->len);
2739 silc_client_packet_send(client, sock, SILC_PACKET_COMMAND_REPLY,
2740 NULL, 0, NULL, NULL, packet->data,
2742 silc_buffer_free(packet);
2743 silc_buffer_free(buffer);
2747 /* Client is able to receive some command packets even though they are
2748 special case. Server may send WHOIS command to the client to retrieve
2749 Requested Attributes information for WHOIS query the server is
2750 processing. This function currently handles only the WHOIS command,
2751 but if in the future more commands may arrive then this can be made
2752 to support other commands too. */
2754 SILC_FSM_STATE(silc_client_command)
2756 SilcClientConnection conn = fsm_context;
2757 SilcClient client = conn->client;
2758 SilcPacket packet = state_context;
2759 SilcCommandPayload payload;
2760 SilcCommand command;
2761 SilcArgumentPayload args;
2763 /* Get command payload from packet */
2764 payload = silc_command_payload_parse(packet->buffer.data,
2765 silc_buffer_len(&packet->buffer));
2767 SILC_LOG_DEBUG(("Bad command packet"));
2768 return SILC_FSM_FINISH;
2772 args = silc_command_get_args(payload);
2774 /* Get the command */
2775 command = silc_command_get(payload);
2778 case SILC_COMMAND_WHOIS:
2779 /* Ignore everything if requested by application */
2780 if (client->internal->params->ignore_requested_attributes)
2783 silc_client_command_process_whois(client, conn, payload, args);
2790 silc_command_payload_free(payload);
2791 return SILC_FSM_FINISH;