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 /* Close connection */
1056 conn->callback(client, conn, SILC_CLIENT_CONN_DISCONNECTED,
1058 // silc_client_close_connection(q->client, q->conn->sock->user_data);
1060 return SILC_FSM_FINISH;
1063 /* Command QUIT. Closes connection with current server. */
1065 SILC_FSM_STATE(silc_client_command_quit)
1067 SilcClientCommandContext cmd = fsm_context;
1068 SilcClientConnection conn = cmd->conn;
1071 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1072 1, cmd->argv[1], cmd->argv_lens[1]);
1074 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
1076 /* Sleep for a while */
1079 /* We close the connection with a little timeout */
1080 silc_fsm_next_later(fsm, silc_client_command_quit_final, 2, 0);
1081 return SILC_FSM_WAIT;
1084 /********************************** KILL ************************************/
1087 /* Command KILL. Router operator can use this command to remove an client
1088 fromthe SILC Network. */
1090 SILC_FSM_STATE(silc_client_command_kill)
1092 SilcClientCommandContext cmd = fsm_context;
1093 SilcClientConnection conn = cmd->conn;
1094 SilcClient client = conn->client;
1095 SilcBuffer idp, auth = NULL;
1096 SilcClientEntry target;
1098 char *nickname = NULL, *comment = NULL;
1100 if (cmd->argc < 2) {
1101 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1102 "Usage: /KILL <nickname> [<comment>] [-pubkey]");
1103 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1104 return SILC_FSM_FINISH;
1107 /* Parse the typed nickname. */
1108 if (client->internal->params->nickname_parse)
1109 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
1111 nickname = strdup(cmd->argv[1]);
1113 return SILC_FSM_FINISH;
1115 /* Get the target client */
1116 clients = silc_client_get_clients_local(client, conn, nickname,
1119 /* Resolve client information */
1120 SILC_FSM_CALL(silc_client_get_clients(client, conn, nickname,
1122 silc_client_command_resolve_continue,
1125 target = silc_dlist_get(clients);
1127 if (cmd->argc >= 3) {
1128 if (strcasecmp(cmd->argv[2], "-pubkey"))
1129 comment = cmd->argv[2];
1131 if (!strcasecmp(cmd->argv[2], "-pubkey") ||
1132 (cmd->argc >= 4 && !strcasecmp(cmd->argv[3], "-pubkey"))) {
1133 /* Encode the public key authentication payload */
1134 auth = silc_auth_public_key_auth_generate(conn->public_key,
1138 &target->id, SILC_ID_CLIENT);
1142 /* Send the KILL command to the server */
1143 idp = silc_id_payload_encode(&target->id, SILC_ID_CLIENT);
1144 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
1145 1, silc_buffer_datalen(idp),
1146 2, comment, comment ? strlen(comment) : 0,
1147 3, silc_buffer_datalen(auth));
1148 silc_buffer_free(idp);
1149 silc_buffer_free(auth);
1150 silc_free(nickname);
1151 silc_client_list_free(client, conn, clients);
1153 /* Notify application */
1154 COMMAND(SILC_STATUS_OK);
1156 /** Wait for command reply */
1157 silc_fsm_next(fsm, silc_client_command_reply_wait);
1158 return SILC_FSM_CONTINUE;
1161 /********************************** INFO ************************************/
1163 /* Command INFO. Request information about specific server. If specific
1164 server is not provided the current server is used. */
1166 SILC_FSM_STATE(silc_client_command_info)
1168 SilcClientCommandContext cmd = fsm_context;
1169 SilcClientConnection conn = cmd->conn;
1171 /* Send the command */
1173 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1174 1, cmd->argv[1], cmd->argv_lens[1]);
1176 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
1178 /* Notify application */
1179 COMMAND(SILC_STATUS_OK);
1181 /** Wait for command reply */
1182 silc_fsm_next(fsm, silc_client_command_reply_wait);
1183 return SILC_FSM_CONTINUE;
1186 /********************************** STATS ***********************************/
1188 /* Command STATS. Shows server and network statistics. */
1190 SILC_FSM_STATE(silc_client_command_stats)
1192 SilcClientCommandContext cmd = fsm_context;
1193 SilcClientConnection conn = cmd->conn;
1195 if (cmd->argc < 2) {
1196 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1197 return SILC_FSM_FINISH;
1200 /* Send the command */
1201 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1202 1, silc_buffer_datalen(conn->remote_idp));
1204 /* Notify application */
1205 COMMAND(SILC_STATUS_OK);
1207 /** Wait for command reply */
1208 silc_fsm_next(fsm, silc_client_command_reply_wait);
1209 return SILC_FSM_CONTINUE;
1212 /********************************** PING ************************************/
1214 /* Command PING. Sends ping to server. */
1216 SILC_FSM_STATE(silc_client_command_ping)
1218 SilcClientCommandContext cmd = fsm_context;
1219 SilcClientConnection conn = cmd->conn;
1221 if (cmd->argc < 2) {
1222 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1223 return SILC_FSM_FINISH;
1226 /* Send the command */
1227 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1228 1, silc_buffer_datalen(conn->remote_idp));
1230 /* Save ping time */
1231 cmd->context = SILC_64_TO_PTR(silc_time());
1233 /* Notify application */
1234 COMMAND(SILC_STATUS_OK);
1236 /** Wait for command reply */
1237 silc_fsm_next(fsm, silc_client_command_reply_wait);
1238 return SILC_FSM_CONTINUE;
1241 /********************************** JOIN ************************************/
1243 /* Command JOIN. Joins to a channel. */
1245 SILC_FSM_STATE(silc_client_command_join)
1247 SilcClientCommandContext cmd = fsm_context;
1248 SilcClientConnection conn = cmd->conn;
1249 SilcChannelEntry channel;
1250 SilcBuffer auth = NULL, cauth = NULL;
1251 char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
1252 int i, passphrase_len = 0;
1254 if (cmd->argc < 2) {
1255 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1259 /* See if we have joined to the requested channel already */
1260 channel = silc_client_get_channel(conn->client, conn, cmd->argv[1]);
1261 if (channel && silc_client_on_channel(channel, conn->local_entry))
1264 if (cmd->argv_lens[1] > 256)
1265 cmd->argv_lens[1] = 256;
1267 name = cmd->argv[1];
1269 for (i = 2; i < cmd->argc; i++) {
1270 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
1271 cipher = cmd->argv[++i];
1272 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
1273 hmac = cmd->argv[++i];
1274 } else if (!strcasecmp(cmd->argv[i], "-founder")) {
1275 auth = silc_auth_public_key_auth_generate(conn->public_key,
1278 conn->client->sha1hash,
1281 } else if (!strcasecmp(cmd->argv[i], "-auth")) {
1282 SilcPublicKey pubkey = conn->public_key;
1283 SilcPrivateKey privkey = conn->private_key;
1284 unsigned char *pk, pkhash[SILC_HASH_MAXLEN], *pubdata;
1287 if (cmd->argc >= i + 3) {
1289 if (cmd->argc >= i + 4) {
1290 pass = cmd->argv[i + 3];
1293 if (!silc_load_key_pair(cmd->argv[i + 1], cmd->argv[i + 2], pass,
1294 &pubkey, &privkey)) {
1295 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1296 "Could not load key pair, check your arguments");
1297 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1303 pk = silc_pkcs_public_key_encode(pubkey, &pk_len);
1304 silc_hash_make(conn->client->sha1hash, pk, pk_len, pkhash);
1306 pubdata = silc_rng_get_rn_data(conn->client->rng, 128);
1307 memcpy(pubdata, pkhash, 20);
1308 cauth = silc_auth_public_key_auth_generate_wpub(pubkey, privkey,
1310 conn->client->sha1hash,
1313 memset(pubdata, 0, 128);
1316 /* Passphrases must be UTF-8 encoded, so encode if it is not */
1317 if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
1318 passphrase_len = silc_utf8_encoded_len(cmd->argv[i],
1319 cmd->argv_lens[i], 0);
1320 pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
1321 passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
1322 0, pu8, passphrase_len);
1325 passphrase = strdup(cmd->argv[i]);
1326 passphrase_len = cmd->argv_lens[i];
1331 /* Send JOIN command to the server */
1332 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 7,
1333 1, name, strlen(name),
1334 2, silc_buffer_datalen(conn->local_idp),
1335 3, passphrase, passphrase_len,
1336 4, cipher, cipher ? strlen(cipher) : 0,
1337 5, hmac, hmac ? strlen(hmac) : 0,
1338 6, silc_buffer_datalen(auth),
1339 7, silc_buffer_datalen(cauth));
1341 silc_buffer_free(auth);
1342 silc_buffer_free(cauth);
1344 memset(passphrase, 0, strlen(passphrase));
1345 silc_free(passphrase);
1347 /* Notify application */
1348 COMMAND(SILC_STATUS_OK);
1350 /** Wait for command reply */
1351 silc_fsm_next(fsm, silc_client_command_reply_wait);
1352 return SILC_FSM_CONTINUE;
1355 return SILC_FSM_FINISH;
1358 /********************************** MOTD ************************************/
1360 /* MOTD command. Requests motd from server. */
1362 SILC_FSM_STATE(silc_client_command_motd)
1364 SilcClientCommandContext cmd = fsm_context;
1365 SilcClientConnection conn = cmd->conn;
1367 if (cmd->argc < 1 || cmd->argc > 2) {
1368 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1369 "Usage: /MOTD [<server>]");
1370 COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
1371 SILC_STATUS_ERR_TOO_MANY_PARAMS));
1372 return SILC_FSM_FINISH;
1375 /* Send the command */
1377 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1378 1, conn->remote_host,
1379 strlen(conn->remote_host));
1381 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1382 1, cmd->argv[1], cmd->argv_lens[1]);
1384 /* Notify application */
1385 COMMAND(SILC_STATUS_OK);
1387 /** Wait for command reply */
1388 silc_fsm_next(fsm, silc_client_command_reply_wait);
1389 return SILC_FSM_CONTINUE;
1392 /********************************** UMODE ***********************************/
1394 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1395 modes as client cannot set itself server/router operator privileges. */
1397 SILC_FSM_STATE(silc_client_command_umode)
1399 SilcClientCommandContext cmd = fsm_context;
1400 SilcClientConnection conn = cmd->conn;
1401 unsigned char *cp, modebuf[4];
1402 SilcUInt32 mode, add, len;
1405 if (cmd->argc < 2) {
1406 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1407 "Usage: /UMODE +|-<modes>");
1408 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1409 return SILC_FSM_FINISH;
1412 mode = conn->local_entry->mode;
1414 /* Are we adding or removing mode */
1415 if (cmd->argv[1][0] == '-')
1421 cp = cmd->argv[1] + 1;
1423 for (i = 0; i < len; i++) {
1428 mode |= SILC_UMODE_SERVER_OPERATOR;
1429 mode |= SILC_UMODE_ROUTER_OPERATOR;
1430 mode |= SILC_UMODE_GONE;
1431 mode |= SILC_UMODE_INDISPOSED;
1432 mode |= SILC_UMODE_BUSY;
1433 mode |= SILC_UMODE_PAGE;
1434 mode |= SILC_UMODE_HYPER;
1435 mode |= SILC_UMODE_ROBOT;
1436 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1437 mode |= SILC_UMODE_REJECT_WATCHING;
1439 mode = SILC_UMODE_NONE;
1444 mode |= SILC_UMODE_SERVER_OPERATOR;
1446 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1450 mode |= SILC_UMODE_ROUTER_OPERATOR;
1452 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1456 mode |= SILC_UMODE_GONE;
1458 mode &= ~SILC_UMODE_GONE;
1462 mode |= SILC_UMODE_INDISPOSED;
1464 mode &= ~SILC_UMODE_INDISPOSED;
1468 mode |= SILC_UMODE_BUSY;
1470 mode &= ~SILC_UMODE_BUSY;
1474 mode |= SILC_UMODE_PAGE;
1476 mode &= ~SILC_UMODE_PAGE;
1480 mode |= SILC_UMODE_HYPER;
1482 mode &= ~SILC_UMODE_HYPER;
1486 mode |= SILC_UMODE_ROBOT;
1488 mode &= ~SILC_UMODE_ROBOT;
1492 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1494 mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
1498 mode |= SILC_UMODE_REJECT_WATCHING;
1500 mode &= ~SILC_UMODE_REJECT_WATCHING;
1504 mode |= SILC_UMODE_BLOCK_INVITE;
1506 mode &= ~SILC_UMODE_BLOCK_INVITE;
1509 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1510 return SILC_FSM_FINISH;
1515 SILC_PUT32_MSB(mode, modebuf);
1517 /* Send the command */
1518 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
1519 1, silc_buffer_datalen(conn->local_idp),
1520 2, modebuf, sizeof(modebuf));
1522 /* Notify application */
1523 COMMAND(SILC_STATUS_OK);
1525 /** Wait for command reply */
1526 silc_fsm_next(fsm, silc_client_command_reply_wait);
1527 return SILC_FSM_CONTINUE;
1530 /********************************** CMODE ***********************************/
1532 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1533 can be set several at once. Those modes that require argument must be set
1534 separately (unless set with modes that does not require arguments). */
1536 SILC_FSM_STATE(silc_client_command_cmode)
1538 SilcClientCommandContext cmd = fsm_context;
1539 SilcClientConnection conn = cmd->conn;
1540 SilcClient client = conn->client;
1541 SilcChannelEntry channel;
1542 SilcBuffer chidp, auth = NULL, pk = NULL;
1543 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1544 SilcUInt32 mode, add, type, len, arg_len = 0;
1547 if (cmd->argc < 3) {
1548 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1549 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1550 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1554 if (cmd->argv[1][0] == '*') {
1555 if (!conn->current_channel) {
1556 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1560 channel = conn->current_channel;
1562 name = cmd->argv[1];
1564 channel = silc_client_get_channel(conn->client, conn, name);
1566 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1571 mode = channel->mode;
1573 /* Are we adding or removing mode */
1574 if (cmd->argv[2][0] == '-')
1579 /* Argument type to be sent to server */
1583 cp = cmd->argv[2] + 1;
1585 for (i = 0; i < len; i++) {
1589 mode |= SILC_CHANNEL_MODE_PRIVATE;
1591 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1595 mode |= SILC_CHANNEL_MODE_SECRET;
1597 mode &= ~SILC_CHANNEL_MODE_SECRET;
1601 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1603 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1607 mode |= SILC_CHANNEL_MODE_INVITE;
1609 mode &= ~SILC_CHANNEL_MODE_INVITE;
1613 mode |= SILC_CHANNEL_MODE_TOPIC;
1615 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1619 mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1621 mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1625 mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1627 mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1632 mode |= SILC_CHANNEL_MODE_ULIMIT;
1634 if (cmd->argc < 4) {
1635 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1636 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1637 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1640 ll = atoi(cmd->argv[3]);
1641 SILC_PUT32_MSB(ll, tmp);
1645 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1650 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1652 if (cmd->argc < 4) {
1653 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1654 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1655 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1659 arg_len = cmd->argv_lens[3];
1661 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1666 mode |= SILC_CHANNEL_MODE_CIPHER;
1668 if (cmd->argc < 4) {
1669 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1670 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1671 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1675 arg_len = cmd->argv_lens[3];
1677 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1682 mode |= SILC_CHANNEL_MODE_HMAC;
1684 if (cmd->argc < 4) {
1685 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1686 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1687 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1691 arg_len = cmd->argv_lens[3];
1693 mode &= ~SILC_CHANNEL_MODE_HMAC;
1698 SilcPublicKey pubkey = conn->public_key;
1699 SilcPrivateKey privkey = conn->private_key;
1701 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1704 if (cmd->argc >= 5) {
1707 pass = cmd->argv[5];
1708 if (!silc_load_key_pair(cmd->argv[3], cmd->argv[4], pass,
1709 &pubkey, &privkey)) {
1710 SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1711 "Could not load key pair, check your arguments");
1712 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1717 pk = silc_public_key_payload_encode(pubkey);
1718 auth = silc_auth_public_key_auth_generate(pubkey, privkey,
1720 conn->client->sha1hash,
1723 arg = silc_buffer_data(auth);
1724 arg_len = silc_buffer_len(auth);
1726 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1732 SilcBool chadd = FALSE;
1733 SilcPublicKey chpk = NULL;
1735 mode |= SILC_CHANNEL_MODE_CHANNEL_AUTH;
1738 if (cmd->argc == 3) {
1739 /* Send empty command to receive the public key list. */
1740 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1741 silc_client_command_send_va(conn, cmd, SILC_COMMAND_CMODE,
1743 1, silc_buffer_datalen(chidp));
1744 silc_buffer_free(chidp);
1746 /* Notify application */
1747 COMMAND(SILC_STATUS_OK);
1751 if (cmd->argc >= 4) {
1752 auth = silc_buffer_alloc_size(2);
1753 silc_buffer_format(auth,
1754 SILC_STR_UI_SHORT(cmd->argc - 3),
1758 for (k = 3; k < cmd->argc; k++) {
1759 if (cmd->argv[k][0] == '+')
1761 if (!silc_pkcs_load_public_key(cmd->argv[k] + 1, &chpk)) {
1762 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1763 "Could not load public key %s, check the filename",
1765 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1766 silc_buffer_free(auth);
1771 pk = silc_public_key_payload_encode(chpk);
1772 auth = silc_argument_payload_encode_one(auth,
1773 silc_buffer_datalen(pk),
1774 chadd ? 0x00 : 0x01);
1775 silc_pkcs_public_key_free(chpk);
1776 silc_buffer_free(pk);
1781 arg = silc_buffer_data(auth);
1782 arg_len = silc_buffer_len(auth);
1784 mode &= ~SILC_CHANNEL_MODE_CHANNEL_AUTH;
1788 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1794 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1795 SILC_PUT32_MSB(mode, modebuf);
1797 /* Send the command. We support sending only one mode at once that
1798 requires an argument. */
1800 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 4,
1801 1, silc_buffer_datalen(chidp),
1802 2, modebuf, sizeof(modebuf),
1804 8, silc_buffer_datalen(pk));
1806 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
1807 1, silc_buffer_datalen(chidp),
1808 2, modebuf, sizeof(modebuf));
1811 silc_buffer_free(chidp);
1812 silc_buffer_free(auth);
1813 silc_buffer_free(pk);
1815 /* Notify application */
1816 COMMAND(SILC_STATUS_OK);
1818 /** Wait for command reply */
1819 silc_fsm_next(fsm, silc_client_command_reply_wait);
1820 return SILC_FSM_CONTINUE;
1823 return SILC_FSM_FINISH;
1826 /********************************* CUMODE ***********************************/
1828 /* CUMODE command. Changes client's mode on a channel. */
1830 SILC_FSM_STATE(silc_client_command_cumode)
1832 SilcClientCommandContext cmd = fsm_context;
1833 SilcClientConnection conn = cmd->conn;
1834 SilcClient client = conn->client;
1835 SilcChannelEntry channel;
1836 SilcChannelUser chu;
1837 SilcClientEntry client_entry;
1838 SilcBuffer clidp, chidp, auth = NULL;
1839 SilcDList clients = NULL;
1840 unsigned char *name, *cp, modebuf[4];
1841 SilcUInt32 mode = 0, add, len;
1842 char *nickname = NULL;
1845 if (cmd->argc < 4) {
1846 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1847 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1848 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1852 if (cmd->argv[1][0] == '*') {
1853 if (!conn->current_channel) {
1854 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1858 channel = conn->current_channel;
1860 name = cmd->argv[1];
1862 channel = silc_client_get_channel(conn->client, conn, name);
1864 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1869 /* Parse the typed nickname. */
1870 if (client->internal->params->nickname_parse)
1871 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1873 nickname = strdup(cmd->argv[3]);
1875 /* Find client entry */
1876 clients = silc_client_get_clients_local(client, conn, nickname,
1879 /* Resolve client information */
1880 SILC_FSM_CALL(silc_client_get_clients(client, conn, nickname, cmd->argv[3],
1881 silc_client_command_resolve_continue,
1884 client_entry = silc_dlist_get(clients);
1886 /* Get the current mode */
1887 chu = silc_client_on_channel(channel, client_entry);
1891 /* Are we adding or removing mode */
1892 if (cmd->argv[2][0] == '-')
1898 cp = cmd->argv[2] + 1;
1900 for (i = 0; i < len; i++) {
1904 mode |= SILC_CHANNEL_UMODE_CHANFO;
1905 mode |= SILC_CHANNEL_UMODE_CHANOP;
1906 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1907 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1908 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1910 mode = SILC_CHANNEL_UMODE_NONE;
1915 SilcPublicKey pubkey = conn->public_key;
1916 SilcPrivateKey privkey = conn->private_key;
1918 if (cmd->argc >= 6) {
1921 pass = cmd->argv[6];
1922 if (!silc_load_key_pair(cmd->argv[4], cmd->argv[5], pass,
1923 &pubkey, &privkey)) {
1924 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1925 "Could not load key pair, check your arguments");
1926 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1931 auth = silc_auth_public_key_auth_generate(pubkey, privkey,
1933 conn->client->sha1hash,
1936 mode |= SILC_CHANNEL_UMODE_CHANFO;
1938 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1943 mode |= SILC_CHANNEL_UMODE_CHANOP;
1945 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1949 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1951 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1955 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1957 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1961 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1963 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1967 mode |= SILC_CHANNEL_UMODE_QUIET;
1969 mode &= ~SILC_CHANNEL_UMODE_QUIET;
1972 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1978 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1979 SILC_PUT32_MSB(mode, modebuf);
1980 clidp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT);
1982 /* Send the command packet. We support sending only one mode at once
1983 that requires an argument. */
1984 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, auth ? 4 : 3,
1985 1, silc_buffer_datalen(chidp),
1987 3, silc_buffer_datalen(clidp),
1988 4, silc_buffer_datalen(auth));
1990 silc_buffer_free(chidp);
1991 silc_buffer_free(clidp);
1993 silc_buffer_free(auth);
1995 /* Notify application */
1996 COMMAND(SILC_STATUS_OK);
1999 silc_client_list_free(client, conn, clients);
2000 silc_free(nickname);
2001 return SILC_FSM_FINISH;
2004 /********************************** KICK ************************************/
2006 /* KICK command. Kicks a client out of channel. */
2008 SILC_FSM_STATE(silc_client_command_kick)
2010 SilcClientCommandContext cmd = fsm_context;
2011 SilcClientConnection conn = cmd->conn;
2012 SilcClient client = conn->client;
2013 SilcChannelEntry channel;
2014 SilcBuffer idp, idp2;
2015 SilcClientEntry target;
2016 SilcDList clients = NULL;
2018 char *nickname = NULL;
2020 if (cmd->argc < 3) {
2021 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2022 "Usage: /KICK <channel> <nickname> [<comment>]");
2023 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2027 if (cmd->argv[1][0] == '*') {
2028 if (!conn->current_channel) {
2029 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2032 name = conn->current_channel->channel_name;
2034 name = cmd->argv[1];
2037 if (!conn->current_channel) {
2038 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2042 /* Get the Channel ID of the channel */
2043 channel = silc_client_get_channel(conn->client, conn, name);
2045 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2049 /* Parse the typed nickname. */
2050 if (client->internal->params->nickname_parse)
2051 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
2053 nickname = strdup(cmd->argv[2]);
2055 /* Get the target client */
2056 clients = silc_client_get_clients_local(client, conn, nickname,
2059 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2060 "No such client: %s", cmd->argv[2]);
2061 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2064 target = silc_dlist_get(clients);
2066 /* Send KICK command to the server */
2067 idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2068 idp2 = silc_id_payload_encode(&target->id, SILC_ID_CLIENT);
2070 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
2071 1, silc_buffer_datalen(idp),
2072 2, silc_buffer_datalen(idp2));
2074 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
2075 1, silc_buffer_datalen(idp),
2076 2, silc_buffer_datalen(idp2),
2077 3, cmd->argv[3], strlen(cmd->argv[3]));
2079 silc_buffer_free(idp);
2080 silc_buffer_free(idp2);
2081 silc_free(nickname);
2082 silc_client_list_free(client, conn, clients);
2084 /* Notify application */
2085 COMMAND(SILC_STATUS_OK);
2087 /** Wait for command reply */
2088 silc_fsm_next(fsm, silc_client_command_reply_wait);
2089 return SILC_FSM_CONTINUE;
2092 silc_free(nickname);
2093 return SILC_FSM_FINISH;
2096 /***************************** OPER & SILCOPER ******************************/
2099 unsigned char *passphrase;
2100 SilcUInt32 passphrase_len;
2101 } *SilcClientCommandOper;
2103 /* Ask passphrase callback */
2105 static void silc_client_command_oper_cb(unsigned char *data,
2106 SilcUInt32 data_len, void *context)
2108 SilcClientCommandContext cmd = context;
2109 SilcClientCommandOper oper = cmd->context;
2111 if (data && data_len)
2112 oper->passphrase = silc_memdup(data, data_len);
2113 oper->passphrase_len = data_len;
2116 SILC_FSM_CALL_CONTINUE(&cmd->thread);
2119 /* Send OPER/SILCOPER command */
2121 SILC_FSM_STATE(silc_client_command_oper_send)
2123 SilcClientCommandContext cmd = fsm_context;
2124 SilcClientConnection conn = cmd->conn;
2125 SilcClientCommandOper oper = cmd->context;
2128 if (!oper || !oper->passphrase) {
2129 /* Encode the public key authentication payload */
2130 auth = silc_auth_public_key_auth_generate(conn->public_key,
2133 conn->internal->hash,
2137 /* Encode the password authentication payload */
2138 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
2139 oper->passphrase, oper->passphrase_len);
2142 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
2143 1, cmd->argv[1], strlen(cmd->argv[1]),
2144 2, silc_buffer_datalen(auth));
2146 silc_buffer_clear(auth);
2147 silc_buffer_free(auth);
2149 silc_free(oper->passphrase);
2153 /* Notify application */
2154 COMMAND(SILC_STATUS_OK);
2156 /** Wait for command reply */
2157 silc_fsm_next(fsm, silc_client_command_reply_wait);
2158 return SILC_FSM_CONTINUE;
2161 /* OPER command. Used to obtain server operator privileges. */
2163 SILC_FSM_STATE(silc_client_command_oper)
2165 SilcClientCommandContext cmd = fsm_context;
2166 SilcClientConnection conn = cmd->conn;
2167 SilcClientCommandOper oper;
2169 if (cmd->argc < 2) {
2170 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2171 "Usage: /OPER <username> [-pubkey]");
2172 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2173 return SILC_FSM_FINISH;
2176 /* Get passphrase */
2177 if (cmd->argc < 3) {
2178 oper = silc_calloc(1, sizeof(*oper));
2180 return SILC_FSM_FINISH;
2181 cmd->context = oper;
2182 SILC_FSM_CALL(conn->client->internal->
2183 ops->ask_passphrase(conn->client, conn,
2184 silc_client_command_oper_cb, cmd));
2187 silc_fsm_next(fsm, silc_client_command_oper_send);
2188 return SILC_FSM_CONTINUE;
2191 /* SILCOPER command. Used to obtain router operator privileges. */
2193 SILC_FSM_STATE(silc_client_command_silcoper)
2195 SilcClientCommandContext cmd = fsm_context;
2196 SilcClientConnection conn = cmd->conn;
2197 SilcClientCommandOper oper;
2199 if (cmd->argc < 2) {
2200 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2201 "Usage: /SILCOPER <username> [-pubkey]");
2202 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2203 return SILC_FSM_FINISH;
2206 /* Get passphrase */
2207 if (cmd->argc < 3) {
2208 oper = silc_calloc(1, sizeof(*oper));
2210 return SILC_FSM_FINISH;
2211 cmd->context = oper;
2212 SILC_FSM_CALL(conn->client->internal->
2213 ops->ask_passphrase(conn->client, conn,
2214 silc_client_command_oper_cb, cmd));
2217 silc_fsm_next(fsm, silc_client_command_oper_send);
2218 return SILC_FSM_CONTINUE;
2221 /*********************************** BAN ************************************/
2223 /* Command BAN. This is used to manage the ban list of the channel. */
2225 SILC_FSM_STATE(silc_client_command_ban)
2227 SilcClientCommandContext cmd = fsm_context;
2228 SilcClientConnection conn = cmd->conn;
2229 SilcChannelEntry channel;
2230 SilcBuffer chidp, args = NULL;
2231 char *name, *ban = NULL;
2232 unsigned char action[1];
2233 SilcPublicKey pubkey = NULL;
2235 if (cmd->argc < 2) {
2236 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2237 "Usage: /BAN <channel> "
2238 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
2239 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2243 if (cmd->argv[1][0] == '*') {
2244 if (!conn->current_channel) {
2245 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2249 channel = conn->current_channel;
2251 name = cmd->argv[1];
2253 channel = silc_client_get_channel(conn->client, conn, name);
2255 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2260 if (cmd->argc == 3) {
2261 if (cmd->argv[2][0] == '+')
2266 /* Check if it is public key file to be added to invite list */
2267 silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey);
2274 args = silc_buffer_alloc_size(2);
2275 silc_buffer_format(args,
2276 SILC_STR_UI_SHORT(1),
2279 chidp = silc_public_key_payload_encode(pubkey);
2280 args = silc_argument_payload_encode_one(args,
2281 silc_buffer_datalen(chidp), 2);
2282 silc_buffer_free(chidp);
2283 silc_pkcs_public_key_free(pubkey);
2285 args = silc_argument_payload_encode_one(args, ban, strlen(ban), 1);
2289 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2291 /* Send the command */
2292 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
2293 1, silc_buffer_datalen(chidp),
2294 2, args ? action : NULL, args ? 1 : 0,
2295 3, silc_buffer_datalen(args));
2297 silc_buffer_free(chidp);
2298 silc_buffer_free(args);
2300 /* Notify application */
2301 COMMAND(SILC_STATUS_OK);
2303 /** Wait for command reply */
2304 silc_fsm_next(fsm, silc_client_command_reply_wait);
2305 return SILC_FSM_CONTINUE;
2308 return SILC_FSM_FINISH;
2311 /********************************* DETACH ***********************************/
2313 /* Command DETACH. This is used to detach from the server */
2315 SILC_FSM_STATE(silc_client_command_detach)
2317 SilcClientCommandContext cmd = fsm_context;
2318 SilcClientConnection conn = cmd->conn;
2320 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
2322 /* Notify application */
2323 COMMAND(SILC_STATUS_OK);
2325 /** Wait for command reply */
2326 silc_fsm_next(fsm, silc_client_command_reply_wait);
2327 return SILC_FSM_CONTINUE;
2330 /********************************** WATCH ***********************************/
2332 /* Command WATCH. */
2334 SILC_FSM_STATE(silc_client_command_watch)
2336 SilcClientCommandContext cmd = fsm_context;
2337 SilcClientConnection conn = cmd->conn;
2338 SilcBuffer args = NULL;
2340 const char *pubkey = NULL;
2341 SilcBool pubkey_add = TRUE;
2343 if (cmd->argc < 3) {
2344 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2348 if (!strcasecmp(cmd->argv[1], "-add")) {
2350 } else if (!strcasecmp(cmd->argv[1], "-del")) {
2352 } else if (!strcasecmp(cmd->argv[1], "-pubkey") && cmd->argc >= 3) {
2354 pubkey = cmd->argv[2] + 1;
2355 if (cmd->argv[2][0] == '-')
2358 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2366 if (!silc_pkcs_load_public_key(pubkey, &pk)) {
2367 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2368 "Could not load public key %s, check the filename", pubkey);
2369 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2373 args = silc_buffer_alloc_size(2);
2374 silc_buffer_format(args,
2375 SILC_STR_UI_SHORT(1),
2377 buffer = silc_public_key_payload_encode(pk);
2378 args = silc_argument_payload_encode_one(args, silc_buffer_datalen(buffer),
2379 pubkey_add ? 0x00 : 0x01);
2380 silc_buffer_free(buffer);
2381 silc_pkcs_public_key_free(pk);
2384 /* Send the commmand */
2385 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
2386 1, silc_buffer_datalen(conn->local_idp),
2387 type, pubkey ? args->data : cmd->argv[2],
2388 pubkey ? silc_buffer_len(args) :
2391 silc_buffer_free(args);
2393 /* Notify application */
2394 COMMAND(SILC_STATUS_OK);
2396 /** Wait for command reply */
2397 silc_fsm_next(fsm, silc_client_command_reply_wait);
2398 return SILC_FSM_CONTINUE;
2401 return SILC_FSM_FINISH;
2404 /********************************** LEAVE ***********************************/
2406 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2408 SILC_FSM_STATE(silc_client_command_leave)
2410 SilcClientCommandContext cmd = fsm_context;
2411 SilcClientConnection conn = cmd->conn;
2412 SilcChannelEntry channel;
2416 if (cmd->argc != 2) {
2417 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2418 "Usage: /LEAVE <channel>");
2419 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2423 if (cmd->argv[1][0] == '*') {
2424 if (!conn->current_channel) {
2425 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2428 name = conn->current_channel->channel_name;
2430 name = cmd->argv[1];
2433 /* Get the channel entry */
2434 channel = silc_client_get_channel(conn->client, conn, name);
2436 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2440 idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2442 /* Send LEAVE command to the server */
2443 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
2444 1, silc_buffer_datalen(idp));
2446 silc_buffer_free(idp);
2448 /* Notify application */
2449 COMMAND(SILC_STATUS_OK);
2451 if (conn->current_channel == channel)
2452 conn->current_channel = NULL;
2454 /** Wait for command reply */
2455 silc_fsm_next(fsm, silc_client_command_reply_wait);
2456 return SILC_FSM_CONTINUE;
2459 return SILC_FSM_FINISH;
2462 /********************************** USERS ***********************************/
2464 /* Command USERS. Requests the USERS of the clients joined on requested
2467 SILC_FSM_STATE(silc_client_command_users)
2469 SilcClientCommandContext cmd = fsm_context;
2470 SilcClientConnection conn = cmd->conn;
2473 if (cmd->argc != 2) {
2474 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2475 "Usage: /USERS <channel>");
2476 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2480 if (cmd->argv[1][0] == '*') {
2481 if (!conn->current_channel) {
2482 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2485 name = conn->current_channel->channel_name;
2487 name = cmd->argv[1];
2490 /* Send USERS command to the server */
2491 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
2492 2, name, strlen(name));
2494 /* Notify application */
2495 COMMAND(SILC_STATUS_OK);
2497 /** Wait for command reply */
2498 silc_fsm_next(fsm, silc_client_command_reply_wait);
2499 return SILC_FSM_CONTINUE;
2502 return SILC_FSM_FINISH;
2505 /********************************* GETKEY ***********************************/
2507 /* Command GETKEY. Used to fetch remote client's public key. */
2509 SILC_FSM_STATE(silc_client_command_getkey)
2511 SilcClientCommandContext cmd = fsm_context;
2512 SilcClientConnection conn = cmd->conn;
2513 SilcClient client = conn->client;
2514 SilcClientEntry client_entry;
2515 SilcServerEntry server_entry;
2517 char *nickname = NULL;
2520 if (cmd->argc < 2) {
2521 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2522 "Usage: /GETKEY <nickname or server name>");
2523 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2524 return SILC_FSM_FINISH;
2527 /* Parse the typed nickname. */
2528 if (client->internal->params->nickname_parse)
2529 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2531 nickname = strdup(cmd->argv[1]);
2533 return SILC_FSM_FINISH;
2535 /* Find client entry */
2536 clients = silc_client_get_clients_local(client, conn, nickname,
2539 /* Check whether user requested server */
2540 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2541 if (!server_entry) {
2542 /* No client or server exist with this name, query for both. */
2543 SILC_FSM_CALL(silc_client_command_send(client, conn,
2544 SILC_COMMAND_IDENTIFY,
2545 silc_client_command_continue,
2548 strlen(cmd->argv[1]),
2550 strlen(cmd->argv[1])));
2552 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2554 client_entry = silc_dlist_get(clients);
2555 idp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT);
2556 silc_client_list_free(client, conn, clients);
2559 /* Send the commmand */
2560 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
2561 1, silc_buffer_datalen(idp));
2563 silc_buffer_free(idp);
2564 silc_free(nickname);
2566 /* Notify application */
2567 COMMAND(SILC_STATUS_OK);
2569 /** Wait for command reply */
2570 silc_fsm_next(fsm, silc_client_command_reply_wait);
2571 return SILC_FSM_CONTINUE;
2574 /********************************* SERVICE **********************************/
2576 /* Command SERVICE. Negotiates service agreement with server. */
2577 /* XXX incomplete */
2579 SILC_FSM_STATE(silc_client_command_service)
2581 SilcClientCommandContext cmd = fsm_context;
2583 SilcClientConnection conn = cmd->conn;
2587 if (cmd->argc < 2) {
2588 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2589 "Usage: /SERVICE [<service name>] [-pubkey]");
2590 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2591 return SILC_FSM_FINISH;
2594 name = cmd->argv[1];
2596 /* Send SERVICE command to the server */
2597 buffer = silc_command_payload_encode_va(SILC_COMMAND_SERVICE,
2598 ++conn->cmd_ident, 1,
2599 1, name, strlen(name));
2600 silc_client_packet_send(conn->client, conn->sock, SILC_PACKET_COMMAND,
2601 NULL, 0, NULL, NULL, buffer->data,
2603 silc_buffer_free(buffer);
2606 /* Notify application */
2607 COMMAND(SILC_STATUS_OK);
2609 /** Wait for command reply */
2610 silc_fsm_next(fsm, silc_client_command_reply_wait);
2611 return SILC_FSM_CONTINUE;
2614 /* Register all default commands provided by the client library for the
2617 void silc_client_commands_register(SilcClient client)
2619 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2622 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 5);
2623 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2624 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2625 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2626 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2627 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2628 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2629 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2630 SILC_CLIENT_CMD(kill, KILL, "KILL", 4);
2631 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2632 SILC_CLIENT_CMD(stats, STATS, "STATS", 0);
2633 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2634 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2635 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2636 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2637 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2638 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 6);
2639 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 9);
2640 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2641 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2642 SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2643 SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
2644 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2645 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2646 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2647 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2648 SILC_CLIENT_CMD(service, SERVICE, "SERVICE", 10);
2651 /* Unregister all commands. */
2653 void silc_client_commands_unregister(SilcClient client)
2655 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2656 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2657 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2658 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2659 SILC_CLIENT_CMDU(list, LIST, "LIST");
2660 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2661 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2662 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2663 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2664 SILC_CLIENT_CMDU(info, INFO, "INFO");
2665 SILC_CLIENT_CMDU(stats, STATS, "STATS");
2666 SILC_CLIENT_CMDU(ping, PING, "PING");
2667 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2668 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2669 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2670 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2671 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2672 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2673 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2674 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2675 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2676 SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2677 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2678 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2679 SILC_CLIENT_CMDU(users, USERS, "USERS");
2680 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2681 SILC_CLIENT_CMDU(service, SERVICE, "SERVICE");
2684 /****************** Client Side Incoming Command Handling *******************/
2686 /* Reply to WHOIS command from server */
2688 static void silc_client_command_process_whois(SilcClient client,
2689 SilcClientConnection conn,
2690 SilcCommandPayload payload,
2691 SilcArgumentPayload args)
2697 SilcBuffer buffer, packet;
2699 SILC_LOG_DEBUG(("Received WHOIS command"));
2701 /* Try to take the Requested Attributes */
2702 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
2706 attrs = silc_attribute_payload_parse(tmp, tmp_len);
2710 /* Process requested attributes */
2711 buffer = silc_client_attributes_process(client, conn, attrs);
2713 silc_attribute_payload_list_free(attrs);
2717 /* Send the attributes back */
2719 silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
2721 silc_command_get_ident(payload),
2722 1, 11, buffer->data, buffer->len);
2723 silc_client_packet_send(client, sock, SILC_PACKET_COMMAND_REPLY,
2724 NULL, 0, NULL, NULL, packet->data,
2726 silc_buffer_free(packet);
2727 silc_buffer_free(buffer);
2731 /* Client is able to receive some command packets even though they are
2732 special case. Server may send WHOIS command to the client to retrieve
2733 Requested Attributes information for WHOIS query the server is
2734 processing. This function currently handles only the WHOIS command,
2735 but if in the future more commands may arrive then this can be made
2736 to support other commands too. */
2738 SILC_FSM_STATE(silc_client_command)
2740 SilcClientConnection conn = fsm_context;
2741 SilcClient client = conn->client;
2742 SilcPacket packet = state_context;
2743 SilcCommandPayload payload;
2744 SilcCommand command;
2745 SilcArgumentPayload args;
2747 /* Get command payload from packet */
2748 payload = silc_command_payload_parse(packet->buffer.data,
2749 silc_buffer_len(&packet->buffer));
2751 /** Bad command payload */
2752 SILC_LOG_DEBUG(("Bad command packet"));
2753 silc_fsm_next(fsm, silc_client_connection_st_packet);
2754 return SILC_FSM_CONTINUE;
2758 args = silc_command_get_args(payload);
2760 /* Get the command */
2761 command = silc_command_get(payload);
2764 case SILC_COMMAND_WHOIS:
2765 /* Ignore everything if requested by application */
2766 if (client->internal->params->ignore_requested_attributes)
2769 silc_client_command_process_whois(client, conn, payload, args);
2776 silc_command_payload_free(payload);
2778 /** Packet processed */
2779 silc_fsm_next(fsm, silc_client_connection_st_packet);
2780 return SILC_FSM_CONTINUE;