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 4, silc_buffer_datalen(conn->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->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,
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->remote_idp));
1207 /* Notify application */
1208 COMMAND(SILC_STATUS_OK);
1210 /** Wait for command reply */
1211 silc_fsm_next(fsm, silc_client_command_reply_wait);
1212 return SILC_FSM_CONTINUE;
1215 /********************************** PING ************************************/
1217 /* Command PING. Sends ping to server. */
1219 SILC_FSM_STATE(silc_client_command_ping)
1221 SilcClientCommandContext cmd = fsm_context;
1222 SilcClientConnection conn = cmd->conn;
1224 if (cmd->argc < 2) {
1225 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1226 return SILC_FSM_FINISH;
1229 /* Send the command */
1230 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1231 1, silc_buffer_datalen(conn->remote_idp));
1233 /* Save ping time */
1234 cmd->context = SILC_64_TO_PTR(silc_time());
1236 /* Notify application */
1237 COMMAND(SILC_STATUS_OK);
1239 /** Wait for command reply */
1240 silc_fsm_next(fsm, silc_client_command_reply_wait);
1241 return SILC_FSM_CONTINUE;
1244 /********************************** JOIN ************************************/
1246 /* Command JOIN. Joins to a channel. */
1248 SILC_FSM_STATE(silc_client_command_join)
1250 SilcClientCommandContext cmd = fsm_context;
1251 SilcClientConnection conn = cmd->conn;
1252 SilcChannelEntry channel;
1253 SilcBuffer auth = NULL, cauth = NULL;
1254 char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
1255 int i, passphrase_len = 0;
1257 if (cmd->argc < 2) {
1258 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1262 /* See if we have joined to the requested channel already */
1263 channel = silc_client_get_channel(conn->client, conn, cmd->argv[1]);
1264 if (channel && silc_client_on_channel(channel, conn->local_entry))
1267 if (cmd->argv_lens[1] > 256)
1268 cmd->argv_lens[1] = 256;
1270 name = cmd->argv[1];
1272 for (i = 2; i < cmd->argc; i++) {
1273 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
1274 cipher = cmd->argv[++i];
1275 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
1276 hmac = cmd->argv[++i];
1277 } else if (!strcasecmp(cmd->argv[i], "-founder")) {
1278 auth = silc_auth_public_key_auth_generate(conn->public_key,
1281 conn->client->sha1hash,
1284 } else if (!strcasecmp(cmd->argv[i], "-auth")) {
1285 SilcPublicKey pubkey = conn->public_key;
1286 SilcPrivateKey privkey = conn->private_key;
1287 unsigned char *pk, pkhash[SILC_HASH_MAXLEN], *pubdata;
1290 if (cmd->argc >= i + 3) {
1292 if (cmd->argc >= i + 4) {
1293 pass = cmd->argv[i + 3];
1296 if (!silc_load_key_pair(cmd->argv[i + 1], cmd->argv[i + 2], pass,
1297 &pubkey, &privkey)) {
1298 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1299 "Could not load key pair, check your arguments");
1300 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1306 pk = silc_pkcs_public_key_encode(pubkey, &pk_len);
1307 silc_hash_make(conn->client->sha1hash, pk, pk_len, pkhash);
1309 pubdata = silc_rng_get_rn_data(conn->client->rng, 128);
1310 memcpy(pubdata, pkhash, 20);
1311 cauth = silc_auth_public_key_auth_generate_wpub(pubkey, privkey,
1313 conn->client->sha1hash,
1316 memset(pubdata, 0, 128);
1319 /* Passphrases must be UTF-8 encoded, so encode if it is not */
1320 if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
1321 passphrase_len = silc_utf8_encoded_len(cmd->argv[i],
1322 cmd->argv_lens[i], 0);
1323 pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
1324 passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
1325 0, pu8, passphrase_len);
1328 passphrase = strdup(cmd->argv[i]);
1329 passphrase_len = cmd->argv_lens[i];
1334 /* Send JOIN command to the server */
1335 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 7,
1336 1, name, strlen(name),
1337 2, silc_buffer_datalen(conn->local_idp),
1338 3, passphrase, passphrase_len,
1339 4, cipher, cipher ? strlen(cipher) : 0,
1340 5, hmac, hmac ? strlen(hmac) : 0,
1341 6, silc_buffer_datalen(auth),
1342 7, silc_buffer_datalen(cauth));
1344 silc_buffer_free(auth);
1345 silc_buffer_free(cauth);
1347 memset(passphrase, 0, strlen(passphrase));
1348 silc_free(passphrase);
1350 /* Notify application */
1351 COMMAND(SILC_STATUS_OK);
1353 /** Wait for command reply */
1354 silc_fsm_next(fsm, silc_client_command_reply_wait);
1355 return SILC_FSM_CONTINUE;
1358 return SILC_FSM_FINISH;
1361 /********************************** MOTD ************************************/
1363 /* MOTD command. Requests motd from server. */
1365 SILC_FSM_STATE(silc_client_command_motd)
1367 SilcClientCommandContext cmd = fsm_context;
1368 SilcClientConnection conn = cmd->conn;
1370 if (cmd->argc < 1 || cmd->argc > 2) {
1371 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1372 "Usage: /MOTD [<server>]");
1373 COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
1374 SILC_STATUS_ERR_TOO_MANY_PARAMS));
1375 return SILC_FSM_FINISH;
1378 /* Send the command */
1380 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1381 1, conn->remote_host,
1382 strlen(conn->remote_host));
1384 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1385 1, cmd->argv[1], cmd->argv_lens[1]);
1387 /* Notify application */
1388 COMMAND(SILC_STATUS_OK);
1390 /** Wait for command reply */
1391 silc_fsm_next(fsm, silc_client_command_reply_wait);
1392 return SILC_FSM_CONTINUE;
1395 /********************************** UMODE ***********************************/
1397 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1398 modes as client cannot set itself server/router operator privileges. */
1400 SILC_FSM_STATE(silc_client_command_umode)
1402 SilcClientCommandContext cmd = fsm_context;
1403 SilcClientConnection conn = cmd->conn;
1404 unsigned char *cp, modebuf[4];
1405 SilcUInt32 mode, add, len;
1408 if (cmd->argc < 2) {
1409 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1410 "Usage: /UMODE +|-<modes>");
1411 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1412 return SILC_FSM_FINISH;
1415 mode = conn->local_entry->mode;
1417 /* Are we adding or removing mode */
1418 if (cmd->argv[1][0] == '-')
1424 cp = cmd->argv[1] + 1;
1426 for (i = 0; i < len; i++) {
1431 mode |= SILC_UMODE_SERVER_OPERATOR;
1432 mode |= SILC_UMODE_ROUTER_OPERATOR;
1433 mode |= SILC_UMODE_GONE;
1434 mode |= SILC_UMODE_INDISPOSED;
1435 mode |= SILC_UMODE_BUSY;
1436 mode |= SILC_UMODE_PAGE;
1437 mode |= SILC_UMODE_HYPER;
1438 mode |= SILC_UMODE_ROBOT;
1439 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1440 mode |= SILC_UMODE_REJECT_WATCHING;
1442 mode = SILC_UMODE_NONE;
1447 mode |= SILC_UMODE_SERVER_OPERATOR;
1449 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1453 mode |= SILC_UMODE_ROUTER_OPERATOR;
1455 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1459 mode |= SILC_UMODE_GONE;
1461 mode &= ~SILC_UMODE_GONE;
1465 mode |= SILC_UMODE_INDISPOSED;
1467 mode &= ~SILC_UMODE_INDISPOSED;
1471 mode |= SILC_UMODE_BUSY;
1473 mode &= ~SILC_UMODE_BUSY;
1477 mode |= SILC_UMODE_PAGE;
1479 mode &= ~SILC_UMODE_PAGE;
1483 mode |= SILC_UMODE_HYPER;
1485 mode &= ~SILC_UMODE_HYPER;
1489 mode |= SILC_UMODE_ROBOT;
1491 mode &= ~SILC_UMODE_ROBOT;
1495 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1497 mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
1501 mode |= SILC_UMODE_REJECT_WATCHING;
1503 mode &= ~SILC_UMODE_REJECT_WATCHING;
1507 mode |= SILC_UMODE_BLOCK_INVITE;
1509 mode &= ~SILC_UMODE_BLOCK_INVITE;
1512 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1513 return SILC_FSM_FINISH;
1518 SILC_PUT32_MSB(mode, modebuf);
1520 /* Send the command */
1521 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
1522 1, silc_buffer_datalen(conn->local_idp),
1523 2, modebuf, sizeof(modebuf));
1525 /* Notify application */
1526 COMMAND(SILC_STATUS_OK);
1528 /** Wait for command reply */
1529 silc_fsm_next(fsm, silc_client_command_reply_wait);
1530 return SILC_FSM_CONTINUE;
1533 /********************************** CMODE ***********************************/
1535 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1536 can be set several at once. Those modes that require argument must be set
1537 separately (unless set with modes that does not require arguments). */
1539 SILC_FSM_STATE(silc_client_command_cmode)
1541 SilcClientCommandContext cmd = fsm_context;
1542 SilcClientConnection conn = cmd->conn;
1543 SilcClient client = conn->client;
1544 SilcChannelEntry channel;
1545 SilcBuffer chidp, auth = NULL, pk = NULL;
1546 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1547 SilcUInt32 mode, add, type, len, arg_len = 0;
1550 if (cmd->argc < 3) {
1551 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1552 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1553 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1557 if (cmd->argv[1][0] == '*') {
1558 if (!conn->current_channel) {
1559 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1563 channel = conn->current_channel;
1565 name = cmd->argv[1];
1567 channel = silc_client_get_channel(conn->client, conn, name);
1569 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1574 mode = channel->mode;
1576 /* Are we adding or removing mode */
1577 if (cmd->argv[2][0] == '-')
1582 /* Argument type to be sent to server */
1586 cp = cmd->argv[2] + 1;
1588 for (i = 0; i < len; i++) {
1592 mode |= SILC_CHANNEL_MODE_PRIVATE;
1594 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1598 mode |= SILC_CHANNEL_MODE_SECRET;
1600 mode &= ~SILC_CHANNEL_MODE_SECRET;
1604 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1606 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1610 mode |= SILC_CHANNEL_MODE_INVITE;
1612 mode &= ~SILC_CHANNEL_MODE_INVITE;
1616 mode |= SILC_CHANNEL_MODE_TOPIC;
1618 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1622 mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1624 mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1628 mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1630 mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1635 mode |= SILC_CHANNEL_MODE_ULIMIT;
1637 if (cmd->argc < 4) {
1638 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1639 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1640 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1643 ll = atoi(cmd->argv[3]);
1644 SILC_PUT32_MSB(ll, tmp);
1648 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1653 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1655 if (cmd->argc < 4) {
1656 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1657 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1658 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1662 arg_len = cmd->argv_lens[3];
1664 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1669 mode |= SILC_CHANNEL_MODE_CIPHER;
1671 if (cmd->argc < 4) {
1672 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1673 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1674 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1678 arg_len = cmd->argv_lens[3];
1680 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1685 mode |= SILC_CHANNEL_MODE_HMAC;
1687 if (cmd->argc < 4) {
1688 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1689 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1690 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1694 arg_len = cmd->argv_lens[3];
1696 mode &= ~SILC_CHANNEL_MODE_HMAC;
1701 SilcPublicKey pubkey = conn->public_key;
1702 SilcPrivateKey privkey = conn->private_key;
1704 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1707 if (cmd->argc >= 5) {
1710 pass = cmd->argv[5];
1711 if (!silc_load_key_pair(cmd->argv[3], cmd->argv[4], pass,
1712 &pubkey, &privkey)) {
1713 SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1714 "Could not load key pair, check your arguments");
1715 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1720 pk = silc_public_key_payload_encode(pubkey);
1721 auth = silc_auth_public_key_auth_generate(pubkey, privkey,
1723 conn->client->sha1hash,
1726 arg = silc_buffer_data(auth);
1727 arg_len = silc_buffer_len(auth);
1729 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1735 SilcBool chadd = FALSE;
1736 SilcPublicKey chpk = NULL;
1738 mode |= SILC_CHANNEL_MODE_CHANNEL_AUTH;
1741 if (cmd->argc == 3) {
1742 /* Send empty command to receive the public key list. */
1743 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
1744 silc_client_command_send_va(conn, cmd, SILC_COMMAND_CMODE,
1746 1, silc_buffer_datalen(chidp));
1747 silc_buffer_free(chidp);
1749 /* Notify application */
1750 COMMAND(SILC_STATUS_OK);
1754 if (cmd->argc >= 4) {
1755 auth = silc_buffer_alloc_size(2);
1756 silc_buffer_format(auth,
1757 SILC_STR_UI_SHORT(cmd->argc - 3),
1761 for (k = 3; k < cmd->argc; k++) {
1762 if (cmd->argv[k][0] == '+')
1764 if (!silc_pkcs_load_public_key(cmd->argv[k] + 1, &chpk)) {
1765 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1766 "Could not load public key %s, check the filename",
1768 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1769 silc_buffer_free(auth);
1774 pk = silc_public_key_payload_encode(chpk);
1775 auth = silc_argument_payload_encode_one(auth,
1776 silc_buffer_datalen(pk),
1777 chadd ? 0x00 : 0x01);
1778 silc_pkcs_public_key_free(chpk);
1779 silc_buffer_free(pk);
1784 arg = silc_buffer_data(auth);
1785 arg_len = silc_buffer_len(auth);
1787 mode &= ~SILC_CHANNEL_MODE_CHANNEL_AUTH;
1791 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1797 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
1798 SILC_PUT32_MSB(mode, modebuf);
1800 /* Send the command. We support sending only one mode at once that
1801 requires an argument. */
1803 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 4,
1804 1, silc_buffer_datalen(chidp),
1805 2, modebuf, sizeof(modebuf),
1807 8, silc_buffer_datalen(pk));
1809 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
1810 1, silc_buffer_datalen(chidp),
1811 2, modebuf, sizeof(modebuf));
1814 silc_buffer_free(chidp);
1815 silc_buffer_free(auth);
1816 silc_buffer_free(pk);
1818 /* Notify application */
1819 COMMAND(SILC_STATUS_OK);
1821 /** Wait for command reply */
1822 silc_fsm_next(fsm, silc_client_command_reply_wait);
1823 return SILC_FSM_CONTINUE;
1826 return SILC_FSM_FINISH;
1829 /********************************* CUMODE ***********************************/
1831 /* CUMODE command. Changes client's mode on a channel. */
1833 SILC_FSM_STATE(silc_client_command_cumode)
1835 SilcClientCommandContext cmd = fsm_context;
1836 SilcClientConnection conn = cmd->conn;
1837 SilcClient client = conn->client;
1838 SilcChannelEntry channel;
1839 SilcChannelUser chu;
1840 SilcClientEntry client_entry;
1841 SilcBuffer clidp, chidp, auth = NULL;
1842 SilcDList clients = NULL;
1843 unsigned char *name, *cp, modebuf[4];
1844 SilcUInt32 mode = 0, add, len;
1845 char *nickname = NULL;
1848 if (cmd->argc < 4) {
1849 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1850 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1851 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1855 if (cmd->argv[1][0] == '*') {
1856 if (!conn->current_channel) {
1857 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1861 channel = conn->current_channel;
1863 name = cmd->argv[1];
1865 channel = silc_client_get_channel(conn->client, conn, name);
1867 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1872 /* Parse the typed nickname. */
1873 if (client->internal->params->nickname_parse)
1874 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1876 nickname = strdup(cmd->argv[3]);
1878 /* Find client entry */
1879 clients = silc_client_get_clients_local(client, conn, nickname,
1882 /* Resolve client information */
1883 SILC_FSM_CALL(silc_client_get_clients(client, conn, nickname, cmd->argv[3],
1884 silc_client_command_resolve_continue,
1887 client_entry = silc_dlist_get(clients);
1889 /* Get the current mode */
1890 chu = silc_client_on_channel(channel, client_entry);
1894 /* Are we adding or removing mode */
1895 if (cmd->argv[2][0] == '-')
1901 cp = cmd->argv[2] + 1;
1903 for (i = 0; i < len; i++) {
1907 mode |= SILC_CHANNEL_UMODE_CHANFO;
1908 mode |= SILC_CHANNEL_UMODE_CHANOP;
1909 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1910 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1911 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1913 mode = SILC_CHANNEL_UMODE_NONE;
1918 SilcPublicKey pubkey = conn->public_key;
1919 SilcPrivateKey privkey = conn->private_key;
1921 if (cmd->argc >= 6) {
1924 pass = cmd->argv[6];
1925 if (!silc_load_key_pair(cmd->argv[4], cmd->argv[5], pass,
1926 &pubkey, &privkey)) {
1927 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1928 "Could not load key pair, check your arguments");
1929 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1934 auth = silc_auth_public_key_auth_generate(pubkey, privkey,
1936 conn->client->sha1hash,
1939 mode |= SILC_CHANNEL_UMODE_CHANFO;
1941 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1946 mode |= SILC_CHANNEL_UMODE_CHANOP;
1948 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1952 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1954 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1958 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1960 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1964 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1966 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1970 mode |= SILC_CHANNEL_UMODE_QUIET;
1972 mode &= ~SILC_CHANNEL_UMODE_QUIET;
1975 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1981 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
1982 SILC_PUT32_MSB(mode, modebuf);
1983 clidp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT);
1985 /* Send the command packet. We support sending only one mode at once
1986 that requires an argument. */
1987 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, auth ? 4 : 3,
1988 1, silc_buffer_datalen(chidp),
1990 3, silc_buffer_datalen(clidp),
1991 4, silc_buffer_datalen(auth));
1993 silc_buffer_free(chidp);
1994 silc_buffer_free(clidp);
1996 silc_buffer_free(auth);
1997 silc_free(nickname);
1998 silc_client_list_free(client, conn, clients);
2000 /* Notify application */
2001 COMMAND(SILC_STATUS_OK);
2003 /** Wait for command reply */
2004 silc_fsm_next(fsm, silc_client_command_reply_wait);
2005 return SILC_FSM_CONTINUE;
2008 silc_client_list_free(client, conn, clients);
2009 silc_free(nickname);
2010 return SILC_FSM_FINISH;
2013 /********************************** KICK ************************************/
2015 /* KICK command. Kicks a client out of channel. */
2017 SILC_FSM_STATE(silc_client_command_kick)
2019 SilcClientCommandContext cmd = fsm_context;
2020 SilcClientConnection conn = cmd->conn;
2021 SilcClient client = conn->client;
2022 SilcChannelEntry channel;
2023 SilcBuffer idp, idp2;
2024 SilcClientEntry target;
2025 SilcDList clients = NULL;
2027 char *nickname = NULL;
2029 if (cmd->argc < 3) {
2030 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2031 "Usage: /KICK <channel> <nickname> [<comment>]");
2032 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2036 if (cmd->argv[1][0] == '*') {
2037 if (!conn->current_channel) {
2038 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2041 name = conn->current_channel->channel_name;
2043 name = cmd->argv[1];
2046 if (!conn->current_channel) {
2047 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2051 /* Get the Channel ID of the channel */
2052 channel = silc_client_get_channel(conn->client, conn, name);
2054 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2058 /* Parse the typed nickname. */
2059 if (client->internal->params->nickname_parse)
2060 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
2062 nickname = strdup(cmd->argv[2]);
2064 /* Get the target client */
2065 clients = silc_client_get_clients_local(client, conn, nickname,
2068 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2069 "No such client: %s", cmd->argv[2]);
2070 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2073 target = silc_dlist_get(clients);
2075 /* Send KICK command to the server */
2076 idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
2077 idp2 = silc_id_payload_encode(&target->id, SILC_ID_CLIENT);
2079 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
2080 1, silc_buffer_datalen(idp),
2081 2, silc_buffer_datalen(idp2));
2083 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
2084 1, silc_buffer_datalen(idp),
2085 2, silc_buffer_datalen(idp2),
2086 3, cmd->argv[3], strlen(cmd->argv[3]));
2088 silc_buffer_free(idp);
2089 silc_buffer_free(idp2);
2090 silc_free(nickname);
2091 silc_client_list_free(client, conn, clients);
2093 /* Notify application */
2094 COMMAND(SILC_STATUS_OK);
2096 /** Wait for command reply */
2097 silc_fsm_next(fsm, silc_client_command_reply_wait);
2098 return SILC_FSM_CONTINUE;
2101 silc_free(nickname);
2102 return SILC_FSM_FINISH;
2105 /***************************** OPER & SILCOPER ******************************/
2108 unsigned char *passphrase;
2109 SilcUInt32 passphrase_len;
2110 } *SilcClientCommandOper;
2112 /* Ask passphrase callback */
2114 static void silc_client_command_oper_cb(unsigned char *data,
2115 SilcUInt32 data_len, void *context)
2117 SilcClientCommandContext cmd = context;
2118 SilcClientCommandOper oper = cmd->context;
2120 if (data && data_len)
2121 oper->passphrase = silc_memdup(data, data_len);
2122 oper->passphrase_len = data_len;
2125 SILC_FSM_CALL_CONTINUE(&cmd->thread);
2128 /* Send OPER/SILCOPER command */
2130 SILC_FSM_STATE(silc_client_command_oper_send)
2132 SilcClientCommandContext cmd = fsm_context;
2133 SilcClientConnection conn = cmd->conn;
2134 SilcClientCommandOper oper = cmd->context;
2137 if (!oper || !oper->passphrase) {
2138 /* Encode the public key authentication payload */
2139 auth = silc_auth_public_key_auth_generate(conn->public_key,
2142 conn->internal->hash,
2146 /* Encode the password authentication payload */
2147 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
2148 oper->passphrase, oper->passphrase_len);
2151 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
2152 1, cmd->argv[1], strlen(cmd->argv[1]),
2153 2, silc_buffer_datalen(auth));
2155 silc_buffer_clear(auth);
2156 silc_buffer_free(auth);
2158 silc_free(oper->passphrase);
2162 /* Notify application */
2163 COMMAND(SILC_STATUS_OK);
2165 /** Wait for command reply */
2166 silc_fsm_next(fsm, silc_client_command_reply_wait);
2167 return SILC_FSM_CONTINUE;
2170 /* OPER command. Used to obtain server operator privileges. */
2172 SILC_FSM_STATE(silc_client_command_oper)
2174 SilcClientCommandContext cmd = fsm_context;
2175 SilcClientConnection conn = cmd->conn;
2176 SilcClientCommandOper oper;
2178 if (cmd->argc < 2) {
2179 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2180 "Usage: /OPER <username> [-pubkey]");
2181 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2182 return SILC_FSM_FINISH;
2185 /* Get passphrase */
2186 if (cmd->argc < 3) {
2187 oper = silc_calloc(1, sizeof(*oper));
2189 return SILC_FSM_FINISH;
2190 cmd->context = oper;
2191 SILC_FSM_CALL(conn->client->internal->
2192 ops->ask_passphrase(conn->client, conn,
2193 silc_client_command_oper_cb, cmd));
2196 silc_fsm_next(fsm, silc_client_command_oper_send);
2197 return SILC_FSM_CONTINUE;
2200 /* SILCOPER command. Used to obtain router operator privileges. */
2202 SILC_FSM_STATE(silc_client_command_silcoper)
2204 SilcClientCommandContext cmd = fsm_context;
2205 SilcClientConnection conn = cmd->conn;
2206 SilcClientCommandOper oper;
2208 if (cmd->argc < 2) {
2209 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2210 "Usage: /SILCOPER <username> [-pubkey]");
2211 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2212 return SILC_FSM_FINISH;
2215 /* Get passphrase */
2216 if (cmd->argc < 3) {
2217 oper = silc_calloc(1, sizeof(*oper));
2219 return SILC_FSM_FINISH;
2220 cmd->context = oper;
2221 SILC_FSM_CALL(conn->client->internal->
2222 ops->ask_passphrase(conn->client, conn,
2223 silc_client_command_oper_cb, cmd));
2226 silc_fsm_next(fsm, silc_client_command_oper_send);
2227 return SILC_FSM_CONTINUE;
2230 /*********************************** BAN ************************************/
2232 /* Command BAN. This is used to manage the ban list of the channel. */
2234 SILC_FSM_STATE(silc_client_command_ban)
2236 SilcClientCommandContext cmd = fsm_context;
2237 SilcClientConnection conn = cmd->conn;
2238 SilcChannelEntry channel;
2239 SilcBuffer chidp, args = NULL;
2240 char *name, *ban = NULL;
2241 unsigned char action[1];
2242 SilcPublicKey pubkey = NULL;
2244 if (cmd->argc < 2) {
2245 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2246 "Usage: /BAN <channel> "
2247 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
2248 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2252 if (cmd->argv[1][0] == '*') {
2253 if (!conn->current_channel) {
2254 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2258 channel = conn->current_channel;
2260 name = cmd->argv[1];
2262 channel = silc_client_get_channel(conn->client, conn, name);
2264 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2269 if (cmd->argc == 3) {
2270 if (cmd->argv[2][0] == '+')
2275 /* Check if it is public key file to be added to invite list */
2276 silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey);
2283 args = silc_buffer_alloc_size(2);
2284 silc_buffer_format(args,
2285 SILC_STR_UI_SHORT(1),
2288 chidp = silc_public_key_payload_encode(pubkey);
2289 args = silc_argument_payload_encode_one(args,
2290 silc_buffer_datalen(chidp), 2);
2291 silc_buffer_free(chidp);
2292 silc_pkcs_public_key_free(pubkey);
2294 args = silc_argument_payload_encode_one(args, ban, strlen(ban), 1);
2298 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
2300 /* Send the command */
2301 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
2302 1, silc_buffer_datalen(chidp),
2303 2, args ? action : NULL, args ? 1 : 0,
2304 3, silc_buffer_datalen(args));
2306 silc_buffer_free(chidp);
2307 silc_buffer_free(args);
2309 /* Notify application */
2310 COMMAND(SILC_STATUS_OK);
2312 /** Wait for command reply */
2313 silc_fsm_next(fsm, silc_client_command_reply_wait);
2314 return SILC_FSM_CONTINUE;
2317 return SILC_FSM_FINISH;
2320 /********************************* DETACH ***********************************/
2322 /* Command DETACH. This is used to detach from the server */
2324 SILC_FSM_STATE(silc_client_command_detach)
2326 SilcClientCommandContext cmd = fsm_context;
2327 SilcClientConnection conn = cmd->conn;
2329 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
2331 /* Notify application */
2332 COMMAND(SILC_STATUS_OK);
2334 /** Wait for command reply */
2335 silc_fsm_next(fsm, silc_client_command_reply_wait);
2336 return SILC_FSM_CONTINUE;
2339 /********************************** WATCH ***********************************/
2341 /* Command WATCH. */
2343 SILC_FSM_STATE(silc_client_command_watch)
2345 SilcClientCommandContext cmd = fsm_context;
2346 SilcClientConnection conn = cmd->conn;
2347 SilcBuffer args = NULL;
2349 const char *pubkey = NULL;
2350 SilcBool pubkey_add = TRUE;
2352 if (cmd->argc < 3) {
2353 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2357 if (!strcasecmp(cmd->argv[1], "-add")) {
2359 } else if (!strcasecmp(cmd->argv[1], "-del")) {
2361 } else if (!strcasecmp(cmd->argv[1], "-pubkey") && cmd->argc >= 3) {
2363 pubkey = cmd->argv[2] + 1;
2364 if (cmd->argv[2][0] == '-')
2367 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2375 if (!silc_pkcs_load_public_key(pubkey, &pk)) {
2376 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2377 "Could not load public key %s, check the filename", pubkey);
2378 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2382 args = silc_buffer_alloc_size(2);
2383 silc_buffer_format(args,
2384 SILC_STR_UI_SHORT(1),
2386 buffer = silc_public_key_payload_encode(pk);
2387 args = silc_argument_payload_encode_one(args, silc_buffer_datalen(buffer),
2388 pubkey_add ? 0x00 : 0x01);
2389 silc_buffer_free(buffer);
2390 silc_pkcs_public_key_free(pk);
2393 /* Send the commmand */
2394 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
2395 1, silc_buffer_datalen(conn->local_idp),
2396 type, pubkey ? args->data : cmd->argv[2],
2397 pubkey ? silc_buffer_len(args) :
2400 silc_buffer_free(args);
2402 /* Notify application */
2403 COMMAND(SILC_STATUS_OK);
2405 /** Wait for command reply */
2406 silc_fsm_next(fsm, silc_client_command_reply_wait);
2407 return SILC_FSM_CONTINUE;
2410 return SILC_FSM_FINISH;
2413 /********************************** LEAVE ***********************************/
2415 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2417 SILC_FSM_STATE(silc_client_command_leave)
2419 SilcClientCommandContext cmd = fsm_context;
2420 SilcClientConnection conn = cmd->conn;
2421 SilcChannelEntry channel;
2425 if (cmd->argc != 2) {
2426 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2427 "Usage: /LEAVE <channel>");
2428 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2432 if (cmd->argv[1][0] == '*') {
2433 if (!conn->current_channel) {
2434 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2437 name = conn->current_channel->channel_name;
2439 name = cmd->argv[1];
2442 /* Get the channel entry */
2443 channel = silc_client_get_channel(conn->client, conn, name);
2445 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2449 idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
2451 /* Send LEAVE command to the server */
2452 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
2453 1, silc_buffer_datalen(idp));
2455 silc_buffer_free(idp);
2457 /* Notify application */
2458 COMMAND(SILC_STATUS_OK);
2460 if (conn->current_channel == channel)
2461 conn->current_channel = NULL;
2463 /** Wait for command reply */
2464 silc_fsm_next(fsm, silc_client_command_reply_wait);
2465 return SILC_FSM_CONTINUE;
2468 return SILC_FSM_FINISH;
2471 /********************************** USERS ***********************************/
2473 /* Command USERS. Requests the USERS of the clients joined on requested
2476 SILC_FSM_STATE(silc_client_command_users)
2478 SilcClientCommandContext cmd = fsm_context;
2479 SilcClientConnection conn = cmd->conn;
2482 if (cmd->argc != 2) {
2483 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2484 "Usage: /USERS <channel>");
2485 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2489 if (cmd->argv[1][0] == '*') {
2490 if (!conn->current_channel) {
2491 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2494 name = conn->current_channel->channel_name;
2496 name = cmd->argv[1];
2499 /* Send USERS command to the server */
2500 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
2501 2, name, strlen(name));
2503 /* Notify application */
2504 COMMAND(SILC_STATUS_OK);
2506 /** Wait for command reply */
2507 silc_fsm_next(fsm, silc_client_command_reply_wait);
2508 return SILC_FSM_CONTINUE;
2511 return SILC_FSM_FINISH;
2514 /********************************* GETKEY ***********************************/
2516 /* Command GETKEY. Used to fetch remote client's public key. */
2518 SILC_FSM_STATE(silc_client_command_getkey)
2520 SilcClientCommandContext cmd = fsm_context;
2521 SilcClientConnection conn = cmd->conn;
2522 SilcClient client = conn->client;
2523 SilcClientEntry client_entry;
2524 SilcServerEntry server_entry;
2526 char *nickname = NULL;
2529 if (cmd->argc < 2) {
2530 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2531 "Usage: /GETKEY <nickname or server name>");
2532 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2533 return SILC_FSM_FINISH;
2536 /* Parse the typed nickname. */
2537 if (client->internal->params->nickname_parse)
2538 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2540 nickname = strdup(cmd->argv[1]);
2542 COMMAND_ERROR(SILC_STATUS_ERR_RESOURCE_LIMIT);
2543 return SILC_FSM_FINISH;
2546 /* Find client entry */
2547 clients = silc_client_get_clients_local(client, conn, nickname,
2550 /* Check whether user requested server */
2551 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2552 if (!server_entry) {
2553 /* No client or server exist with this name, query for both. */
2554 SILC_FSM_CALL(silc_client_command_send(client, conn,
2555 SILC_COMMAND_IDENTIFY,
2556 silc_client_command_continue,
2559 strlen(cmd->argv[1]),
2561 strlen(cmd->argv[1])));
2563 idp = silc_id_payload_encode(&server_entry->id, SILC_ID_SERVER);
2565 client_entry = silc_dlist_get(clients);
2566 idp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT);
2567 silc_client_list_free(client, conn, clients);
2570 /* Send the commmand */
2571 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
2572 1, silc_buffer_datalen(idp));
2574 silc_buffer_free(idp);
2575 silc_free(nickname);
2577 /* Notify application */
2578 COMMAND(SILC_STATUS_OK);
2580 /** Wait for command reply */
2581 silc_fsm_next(fsm, silc_client_command_reply_wait);
2582 return SILC_FSM_CONTINUE;
2585 /********************************* SERVICE **********************************/
2587 /* Command SERVICE. Negotiates service agreement with server. */
2588 /* XXX incomplete */
2590 SILC_FSM_STATE(silc_client_command_service)
2592 SilcClientCommandContext cmd = fsm_context;
2594 SilcClientConnection conn = cmd->conn;
2598 if (cmd->argc < 2) {
2599 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2600 "Usage: /SERVICE [<service name>] [-pubkey]");
2601 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2602 return SILC_FSM_FINISH;
2605 name = cmd->argv[1];
2607 /* Send SERVICE command to the server */
2608 buffer = silc_command_payload_encode_va(SILC_COMMAND_SERVICE,
2609 ++conn->cmd_ident, 1,
2610 1, name, strlen(name));
2611 silc_client_packet_send(conn->client, conn->sock, SILC_PACKET_COMMAND,
2612 NULL, 0, NULL, NULL, buffer->data,
2614 silc_buffer_free(buffer);
2617 /* Notify application */
2618 COMMAND(SILC_STATUS_OK);
2620 /** Wait for command reply */
2621 silc_fsm_next(fsm, silc_client_command_reply_wait);
2622 return SILC_FSM_CONTINUE;
2625 /* Register all default commands provided by the client library for the
2628 void silc_client_commands_register(SilcClient client)
2630 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2633 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 5);
2634 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2635 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2636 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2637 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2638 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2639 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2640 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2641 SILC_CLIENT_CMD(kill, KILL, "KILL", 4);
2642 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2643 SILC_CLIENT_CMD(stats, STATS, "STATS", 0);
2644 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2645 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2646 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2647 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2648 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2649 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 6);
2650 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 9);
2651 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2652 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2653 SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2654 SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
2655 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2656 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2657 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2658 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2659 SILC_CLIENT_CMD(service, SERVICE, "SERVICE", 10);
2662 /* Unregister all commands. */
2664 void silc_client_commands_unregister(SilcClient client)
2666 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2667 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2668 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2669 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2670 SILC_CLIENT_CMDU(list, LIST, "LIST");
2671 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2672 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2673 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2674 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2675 SILC_CLIENT_CMDU(info, INFO, "INFO");
2676 SILC_CLIENT_CMDU(stats, STATS, "STATS");
2677 SILC_CLIENT_CMDU(ping, PING, "PING");
2678 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2679 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2680 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2681 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2682 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2683 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2684 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2685 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2686 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2687 SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2688 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2689 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2690 SILC_CLIENT_CMDU(users, USERS, "USERS");
2691 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2692 SILC_CLIENT_CMDU(service, SERVICE, "SERVICE");
2695 /****************** Client Side Incoming Command Handling *******************/
2697 /* Reply to WHOIS command from server */
2699 static void silc_client_command_process_whois(SilcClient client,
2700 SilcClientConnection conn,
2701 SilcCommandPayload payload,
2702 SilcArgumentPayload args)
2708 SilcBuffer buffer, packet;
2710 SILC_LOG_DEBUG(("Received WHOIS command"));
2712 /* Try to take the Requested Attributes */
2713 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
2717 attrs = silc_attribute_payload_parse(tmp, tmp_len);
2721 /* Process requested attributes */
2722 buffer = silc_client_attributes_process(client, conn, attrs);
2724 silc_attribute_payload_list_free(attrs);
2728 /* Send the attributes back */
2730 silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
2732 silc_command_get_ident(payload),
2733 1, 11, buffer->data, buffer->len);
2734 silc_client_packet_send(client, sock, SILC_PACKET_COMMAND_REPLY,
2735 NULL, 0, NULL, NULL, packet->data,
2737 silc_buffer_free(packet);
2738 silc_buffer_free(buffer);
2742 /* Client is able to receive some command packets even though they are
2743 special case. Server may send WHOIS command to the client to retrieve
2744 Requested Attributes information for WHOIS query the server is
2745 processing. This function currently handles only the WHOIS command,
2746 but if in the future more commands may arrive then this can be made
2747 to support other commands too. */
2749 SILC_FSM_STATE(silc_client_command)
2751 SilcClientConnection conn = fsm_context;
2752 SilcClient client = conn->client;
2753 SilcPacket packet = state_context;
2754 SilcCommandPayload payload;
2755 SilcCommand command;
2756 SilcArgumentPayload args;
2758 /* Get command payload from packet */
2759 payload = silc_command_payload_parse(packet->buffer.data,
2760 silc_buffer_len(&packet->buffer));
2762 SILC_LOG_DEBUG(("Bad command packet"));
2763 return SILC_FSM_FINISH;
2767 args = silc_command_get_args(payload);
2769 /* Get the command */
2770 command = silc_command_get(payload);
2773 case SILC_COMMAND_WHOIS:
2774 /* Ignore everything if requested by application */
2775 if (client->internal->params->ignore_requested_attributes)
2778 silc_client_command_process_whois(client, conn, payload, args);
2785 silc_command_payload_free(payload);
2786 return SILC_FSM_FINISH;