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));
145 cmd->command = command_func;
146 cmd->reply = command_reply_func;
147 cmd->max_args = max_args;
148 cmd->name = name ? strdup(name) : NULL;
154 silc_list_add(client->internal->commands, cmd);
159 /* Unregister command from client */
162 silc_client_command_unregister(SilcClient client,
164 SilcFSMStateCallback command_func,
165 SilcFSMStateCallback command_reply_func)
167 SilcClientCommand cmd;
169 silc_list_start(client->internal->commands);
170 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
171 if (cmd->cmd == command && cmd->command == command_func &&
172 cmd->reply == command_reply_func) {
173 silc_list_del(client->internal->commands, cmd);
174 silc_free(cmd->name);
183 /* Finds and returns a pointer to the command list. Return NULL if the
184 command is not found. */
186 static SilcClientCommand silc_client_command_find(SilcClient client,
189 SilcClientCommand cmd;
191 silc_list_start(client->internal->commands);
192 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
193 if (cmd->name && !strcasecmp(cmd->name, name))
200 /* Command thread destructor */
202 static void silc_client_command_destructor(SilcFSMThread thread,
204 void *destructor_context)
206 SilcClientCommandContext cmd = fsm_context;
207 SilcClientConnection conn = cmd->conn;
209 /* Removes commands that aren't waiting for reply but are waiting
210 for something. They may not have been removed yet. */
211 silc_list_del(conn->internal->pending_commands, cmd);
213 silc_client_command_free(cmd);
216 /* Add a command pending a command reply. Used internally by the library. */
219 silc_client_command_add_pending(SilcClientConnection conn,
220 SilcClientCommandContext cmd,
221 SilcClientCommandReply reply,
224 SilcClientCommandReplyCallback cb;
226 silc_mutex_lock(conn->internal->lock);
228 /* Add pending callback, if defined */
230 cb = silc_calloc(1, sizeof(*cb));
232 silc_mutex_unlock(conn->internal->lock);
236 cb->context = context;
237 silc_list_add(cmd->reply_callbacks, cb);
240 /* Add pending reply */
241 silc_list_add(conn->internal->pending_commands, cmd);
243 silc_mutex_unlock(conn->internal->lock);
248 /* Generic function to send any command. The arguments must be sent already
249 encoded into correct format and in correct order. Arguments come from
250 variable argument list pointer. */
252 static SilcUInt16 silc_client_command_send_vap(SilcClient client,
253 SilcClientConnection conn,
254 SilcClientCommandContext cmd,
256 SilcClientCommandReply reply,
258 SilcUInt32 argc, va_list ap)
262 SILC_LOG_DEBUG(("Send command %s", silc_get_command_name(command)));
264 if (conn->internal->disconnected)
268 cmd->cmd_ident = silc_client_cmd_ident(conn);
270 /* Encode command payload */
271 packet = silc_command_payload_encode_vap(command, cmd->cmd_ident, argc, ap);
275 /* Send the command */
276 if (!silc_packet_send(conn->stream, SILC_PACKET_COMMAND, 0,
277 silc_buffer_datalen(packet))) {
278 silc_buffer_free(packet);
282 /* Add the command pending command reply */
283 silc_client_command_add_pending(conn, cmd, reply, reply_context);
285 silc_buffer_free(packet);
287 return cmd->cmd_ident;
290 /* Generic function to send any command. The arguments must be sent already
291 encoded into correct format and in correct order. Arguments come from
295 silc_client_command_send_arg_array(SilcClient client,
296 SilcClientConnection conn,
297 SilcClientCommandContext cmd,
299 SilcClientCommandReply reply,
302 unsigned char **argv,
303 SilcUInt32 *argv_lens,
304 SilcUInt32 *argv_types)
308 SILC_LOG_DEBUG(("Send command %s", silc_get_command_name(command)));
310 if (conn->internal->disconnected)
314 cmd->cmd_ident = silc_client_cmd_ident(conn);
316 /* Encode command payload */
317 packet = silc_command_payload_encode(command, argc, argv, argv_lens,
318 argv_types, cmd->cmd_ident);
322 /* Send the command */
323 if (!silc_packet_send(conn->stream, SILC_PACKET_COMMAND, 0,
324 silc_buffer_datalen(packet))) {
325 silc_buffer_free(packet);
329 /* Add the command pending command reply */
330 silc_client_command_add_pending(conn, cmd, reply, reply_context);
332 silc_buffer_free(packet);
334 return cmd->cmd_ident;
337 /* Generic function to send any command. The arguments must be sent already
338 encoded into correct format and in correct order. This is used internally
341 static SilcUInt16 silc_client_command_send_va(SilcClientConnection conn,
342 SilcClientCommandContext cmd,
344 SilcClientCommandReply reply,
346 SilcUInt32 argc, ...)
349 SilcUInt16 cmd_ident;
352 cmd_ident = silc_client_command_send_vap(conn->client, conn, cmd, command,
353 reply, reply_context, argc, ap);
359 /****************************** Command API *********************************/
361 /* Free command context and its internals */
363 void silc_client_command_free(SilcClientCommandContext cmd)
365 SilcClientCommandReplyCallback cb;
368 for (i = 0; i < cmd->argc; i++)
369 silc_free(cmd->argv[i]);
370 silc_free(cmd->argv);
371 silc_free(cmd->argv_lens);
372 silc_free(cmd->argv_types);
374 silc_list_start(cmd->reply_callbacks);
375 while ((cb = silc_list_get(cmd->reply_callbacks)))
381 /* Executes a command */
383 SilcUInt16 silc_client_command_call(SilcClient client,
384 SilcClientConnection conn,
385 const char *command_line, ...)
389 unsigned char **argv = NULL;
390 SilcUInt32 *argv_lens = NULL, *argv_types = NULL;
391 SilcClientCommand command;
392 SilcClientCommandContext cmd;
396 client->internal->ops->say(client, NULL, SILC_CLIENT_MESSAGE_ERROR,
397 "You are not connected to a server, please connect to server");
401 /* Parse arguments */
402 va_start(va, command_line);
406 /* Get command name */
407 command_name = silc_memdup(command_line, strcspn(command_line, " "));
411 /* Find command by name */
412 command = silc_client_command_find(client, command_name);
414 silc_free(command_name);
418 /* Parse command line */
419 silc_parse_command_line((char *)command_line, &argv, &argv_lens,
420 &argv_types, &argc, command->max_args);
422 silc_free(command_name);
424 arg = va_arg(va, char *);
428 /* Find command by name */
429 command = silc_client_command_find(client, arg);
434 argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
435 argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) * (argc + 1));
436 argv_types = silc_realloc(argv_types, sizeof(*argv_types) * (argc + 1));
437 if (!argv || !argv_lens || !argv_types)
439 argv[argc] = silc_memdup(arg, strlen(arg));
442 argv_lens[argc] = strlen(arg);
443 argv_types[argc] = argc;
445 arg = va_arg(va, char *);
450 /* Allocate command context */
451 cmd = silc_calloc(1, sizeof(*cmd));
455 cmd->cmd = command->cmd;
458 cmd->argv_lens = argv_lens;
459 cmd->argv_types = argv_types;
460 cmd->cmd_ident = silc_client_cmd_ident(conn);
463 silc_list_init(cmd->reply_callbacks,
464 struct SilcClientCommandReplyCallbackStruct, next);
467 SILC_LOG_DEBUG(("Calling %s command", silc_get_command_name(cmd->cmd)));
468 silc_fsm_thread_init(&cmd->thread, &conn->internal->fsm, cmd,
469 silc_client_command_destructor, NULL, FALSE);
470 silc_fsm_start_sync(&cmd->thread, command->command);
472 return cmd->cmd_ident;
475 /* Generic function to send any command. The arguments must be sent already
476 encoded into correct format and in correct order. */
478 SilcUInt16 silc_client_command_send(SilcClient client,
479 SilcClientConnection conn,
481 SilcClientCommandReply reply,
483 SilcUInt32 argc, ...)
485 SilcClientCommandContext cmd;
491 /* Allocate command context */
492 cmd = silc_calloc(1, sizeof(*cmd));
497 silc_list_init(cmd->reply_callbacks,
498 struct SilcClientCommandReplyCallbackStruct, next);
500 /* Send the command */
503 silc_client_command_send_vap(client, conn, cmd, command, reply,
504 reply_context, argc, ap);
507 if (!cmd->cmd_ident) {
508 silc_client_command_free(cmd);
512 /*** Wait for command reply */
513 silc_fsm_thread_init(&cmd->thread, &conn->internal->fsm, cmd,
514 silc_client_command_destructor, NULL, FALSE);
515 silc_fsm_start_sync(&cmd->thread, silc_client_command_reply_wait);
517 return cmd->cmd_ident;
520 /* Generic function to send any command. The arguments must be sent already
521 encoded into correct format and in correct order. Arguments come from
524 SilcUInt16 silc_client_command_send_argv(SilcClient client,
525 SilcClientConnection conn,
527 SilcClientCommandReply reply,
530 unsigned char **argv,
531 SilcUInt32 *argv_lens,
532 SilcUInt32 *argv_types)
534 SilcClientCommandContext cmd;
539 /* Allocate command context */
540 cmd = silc_calloc(1, sizeof(*cmd));
546 /* Send the command */
548 silc_client_command_send_arg_array(client, conn, cmd, command, reply,
549 reply_context, argc, argv, argv_lens,
551 if (!cmd->cmd_ident) {
552 silc_client_command_free(cmd);
556 /*** Wait for command reply */
557 silc_fsm_thread_init(&cmd->thread, &conn->internal->fsm, cmd,
558 silc_client_command_destructor, NULL, FALSE);
559 silc_fsm_start_sync(&cmd->thread, silc_client_command_reply_wait);
561 return cmd->cmd_ident;
564 /* Attach to a command and command identifier to receive command reply. */
566 SilcBool silc_client_command_pending(SilcClientConnection conn,
569 SilcClientCommandReply reply,
572 SilcClientCommandContext cmd;
573 SilcClientCommandReplyCallback cb;
578 SILC_LOG_DEBUG(("Add pending command reply for ident %d", ident));
580 silc_mutex_lock(conn->internal->lock);
582 /* Find the pending command */
583 silc_list_start(conn->internal->pending_commands);
584 while ((cmd = silc_list_get(conn->internal->pending_commands)))
585 if ((cmd->cmd == command || command == SILC_COMMAND_NONE)
586 && cmd->cmd_ident == ident) {
588 /* Add the callback */
589 cb = silc_calloc(1, sizeof(*cb));
593 cb->context = context;
594 silc_list_add(cmd->reply_callbacks, cb);
597 silc_mutex_unlock(conn->internal->lock);
602 /******************************** WHOIS *************************************/
604 /* Command WHOIS. This command is used to query information about
607 SILC_FSM_STATE(silc_client_command_whois)
609 SilcClientCommandContext cmd = fsm_context;
610 SilcClientConnection conn = cmd->conn;
611 SilcClient client = conn->client;
612 SilcBuffer attrs = NULL;
613 unsigned char count[4], *tmp = NULL;
614 SilcBool details = FALSE, nick = FALSE;
615 unsigned char *pubkey = NULL;
618 /* Given without arguments fetches client's own information */
620 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1, 4,
621 silc_buffer_data(conn->internal->local_idp),
622 silc_buffer_len(conn->internal->local_idp));
624 /* Notify application */
625 COMMAND(SILC_STATUS_OK);
627 /** Wait for command reply */
628 silc_fsm_next(fsm, silc_client_command_reply_wait);
629 return SILC_FSM_CONTINUE;
632 for (i = 1; i < cmd->argc; i++) {
633 if (!strcasecmp(cmd->argv[i], "-details")) {
635 } else if (!strcasecmp(cmd->argv[i], "-pubkey") && cmd->argc > i + 1) {
636 pubkey = cmd->argv[i + 1];
639 /* We assume that the first parameter is the nickname, if it isn't
640 -details or -pubkey. The last parameter should always be the count */
643 } else if (i == cmd->argc - 1) {
644 int c = atoi(cmd->argv[i]);
645 SILC_PUT32_MSB(c, count);
652 /* If pubkey is set, add all attributes to the attrs buffer, except
655 attrs = silc_client_attributes_request(SILC_ATTRIBUTE_USER_INFO,
656 SILC_ATTRIBUTE_SERVICE,
657 SILC_ATTRIBUTE_STATUS_MOOD,
658 SILC_ATTRIBUTE_STATUS_FREETEXT,
659 SILC_ATTRIBUTE_STATUS_MESSAGE,
660 SILC_ATTRIBUTE_PREFERRED_LANGUAGE,
661 SILC_ATTRIBUTE_PREFERRED_CONTACT,
662 SILC_ATTRIBUTE_TIMEZONE,
663 SILC_ATTRIBUTE_GEOLOCATION,
664 SILC_ATTRIBUTE_DEVICE_INFO,
665 SILC_ATTRIBUTE_USER_ICON, 0);
667 attrs = silc_client_attributes_request(0);
672 SilcAttributeObjPk obj;
675 if (!silc_pkcs_load_public_key(pubkey, &pk)) {
676 SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR,
677 "Could not load public key %s, check the filename",
679 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
683 switch (silc_pkcs_get_type(pk)) {
685 obj.type = "silc-rsa";
688 obj.type = "ssh-rsa";
690 case SILC_PKCS_X509V3:
691 obj.type = "x509v3-sign-rsa";
693 case SILC_PKCS_OPENPGP:
694 obj.type = "pgp-sign-rsa";
700 obj.data = silc_pkcs_public_key_encode(pk, &obj.data_len);
702 attrs = silc_attribute_payload_encode(attrs,
703 SILC_ATTRIBUTE_USER_PUBLIC_KEY,
704 SILC_ATTRIBUTE_FLAG_VALID,
709 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
710 3, 1, nick ? cmd->argv[1] : NULL,
711 nick ? cmd->argv_lens[1] : 0,
712 2, tmp ? tmp : NULL, tmp ? 4 : 0,
713 3, silc_buffer_datalen(attrs));
715 /* Notify application */
716 COMMAND(SILC_STATUS_OK);
718 /** Wait for command reply */
719 silc_fsm_next(fsm, silc_client_command_reply_wait);
720 return SILC_FSM_CONTINUE;
723 return SILC_FSM_FINISH;
726 /******************************** WHOWAS ************************************/
728 /* Command WHOWAS. This command is used to query history information about
729 specific user that used to exist in the network. */
731 SILC_FSM_STATE(silc_client_command_whowas)
733 SilcClientCommandContext cmd = fsm_context;
734 SilcClientConnection conn = cmd->conn;
735 unsigned char count[4];
738 if (cmd->argc < 2 || cmd->argc > 3) {
739 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
740 "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
741 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
742 SILC_STATUS_ERR_TOO_MANY_PARAMS));
743 return SILC_FSM_FINISH;
746 if (cmd->argc == 2) {
747 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
748 1, 1, cmd->argv[1], cmd->argv_lens[1]);
750 c = atoi(cmd->argv[2]);
751 SILC_PUT32_MSB(c, count);
752 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
753 2, 1, cmd->argv[1], cmd->argv_lens[1],
754 2, count, sizeof(count));
757 /* Notify application */
758 COMMAND(SILC_STATUS_OK);
760 /** Wait for command reply */
761 silc_fsm_next(fsm, silc_client_command_reply_wait);
762 return SILC_FSM_CONTINUE;
765 /******************************** IDENTIFY **********************************/
767 /* Command IDENTIFY. This command is used to query information about
768 specific user, especially ID's. */
770 SILC_FSM_STATE(silc_client_command_identify)
772 SilcClientCommandContext cmd = fsm_context;
773 SilcClientConnection conn = cmd->conn;
774 unsigned char count[4];
777 if (cmd->argc < 2 || cmd->argc > 3)
778 return SILC_FSM_FINISH;
780 if (cmd->argc == 2) {
781 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
782 1, 1, cmd->argv[1], cmd->argv_lens[1]);
784 c = atoi(cmd->argv[2]);
785 SILC_PUT32_MSB(c, count);
786 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
787 2, 1, cmd->argv[1], cmd->argv_lens[1],
788 4, count, sizeof(count));
791 /** Wait for command reply */
792 silc_fsm_next(fsm, silc_client_command_reply_wait);
793 return SILC_FSM_CONTINUE;
796 /********************************** NICK ************************************/
798 /* Command NICK. Shows current nickname/sets new nickname on current
801 SILC_FSM_STATE(silc_client_command_nick)
803 SilcClientCommandContext cmd = fsm_context;
804 SilcClientConnection conn = cmd->conn;
807 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
808 "Usage: /NICK <nickname>");
809 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
813 if (silc_utf8_strcasecmp(conn->local_entry->nickname, cmd->argv[1]))
816 /* Show current nickname */
819 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
820 "Your nickname is %s on server %s",
821 conn->local_entry->nickname, conn->remote_host);
823 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
824 "Your nickname is %s", conn->local_entry->nickname);
827 COMMAND(SILC_STATUS_OK);
831 if (cmd->argv_lens[1] > 128)
832 cmd->argv_lens[1] = 128;
834 /* Send the NICK command */
835 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
836 1, 1, cmd->argv[1], cmd->argv_lens[1]);
838 /* Notify application */
839 COMMAND(SILC_STATUS_OK);
841 /** Wait for command reply */
842 silc_fsm_next(fsm, silc_client_command_reply_wait);
843 return SILC_FSM_CONTINUE;
846 return SILC_FSM_FINISH;
849 /********************************** LIST ************************************/
851 /* Command LIST. Lists channels on the current server. */
853 SILC_FSM_STATE(silc_client_command_list)
855 SilcClientCommandContext cmd = fsm_context;
856 SilcClientConnection conn = cmd->conn;
857 SilcChannelEntry channel;
858 SilcBuffer idp = NULL;
860 if (cmd->argc == 2) {
861 /* Get the Channel ID of the channel */
862 channel = silc_client_get_channel(conn->client, cmd->conn, cmd->argv[1]);
864 idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
868 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
870 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
871 1, 1, silc_buffer_datalen(idp));
873 silc_buffer_free(idp);
875 /* Notify application */
876 COMMAND(SILC_STATUS_OK);
878 /** Wait for command reply */
879 silc_fsm_next(fsm, silc_client_command_reply_wait);
880 return SILC_FSM_CONTINUE;
883 /********************************** TOPIC ***********************************/
885 /* Command TOPIC. Sets/shows topic on a channel. */
887 SILC_FSM_STATE(silc_client_command_topic)
889 SilcClientCommandContext cmd = fsm_context;
890 SilcClientConnection conn = cmd->conn;
891 SilcChannelEntry channel;
895 if (cmd->argc < 2 || cmd->argc > 3) {
896 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
897 "Usage: /TOPIC <channel> [<topic>]");
898 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
899 SILC_STATUS_ERR_TOO_MANY_PARAMS));
903 if (cmd->argv[1][0] == '*') {
904 if (!conn->current_channel) {
905 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
908 name = conn->current_channel->channel_name;
913 if (!conn->current_channel) {
914 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
918 /* Get the Channel ID of the channel */
919 channel = silc_client_get_channel(conn->client, conn, name);
921 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
925 idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
927 /* Send TOPIC command to the server */
929 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
930 1, silc_buffer_datalen(idp),
931 2, cmd->argv[2], strlen(cmd->argv[2]));
933 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
934 1, silc_buffer_datalen(idp));
936 silc_buffer_free(idp);
938 /* Notify application */
939 COMMAND(SILC_STATUS_OK);
941 /** Wait for command reply */
942 silc_fsm_next(fsm, silc_client_command_reply_wait);
943 return SILC_FSM_CONTINUE;
946 return SILC_FSM_FINISH;
949 /********************************* INVITE ***********************************/
951 /* Command INVITE. Invites specific client to join a channel. This is
952 also used to mange the invite list of the channel. */
954 SILC_FSM_STATE(silc_client_command_invite)
956 SilcClientCommandContext cmd = fsm_context;
957 SilcClientConnection conn = cmd->conn;
958 SilcClient client = conn->client;
959 SilcClientEntry client_entry = NULL;
960 SilcChannelEntry channel;
961 SilcBuffer clidp, chidp, args = NULL;
962 SilcPublicKey pubkey = NULL;
963 SilcDList clients = NULL;
964 char *nickname = NULL, *name;
966 unsigned char action[1];
969 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
970 "Usage: /INVITE <channel> [<nickname>[@server>]"
971 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
972 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
976 if (cmd->argv[1][0] == '*') {
977 if (!conn->current_channel) {
978 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
982 channel = conn->current_channel;
986 channel = silc_client_get_channel(conn->client, conn, name);
988 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
993 /* Parse the typed nickname. */
994 if (cmd->argc == 3) {
995 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
996 if (client->internal->params->nickname_parse)
997 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
999 nickname = strdup(cmd->argv[2]);
1001 /* Find client entry */
1002 clients = silc_client_get_clients_local(client, conn, nickname,
1005 /* Resolve client information */
1006 SILC_FSM_CALL(silc_client_get_clients(
1007 client, conn, nickname,
1009 silc_client_command_resolve_continue,
1012 client_entry = silc_dlist_get(clients);
1014 if (cmd->argv[2][0] == '+')
1019 /* Check if it is public key file to be added to invite list */
1020 silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey);
1021 invite = cmd->argv[2];
1028 args = silc_buffer_alloc_size(2);
1029 silc_buffer_format(args,
1030 SILC_STR_UI_SHORT(1),
1033 chidp = silc_public_key_payload_encode(pubkey);
1034 args = silc_argument_payload_encode_one(args, silc_buffer_data(chidp),
1035 silc_buffer_len(chidp), 2);
1036 silc_buffer_free(chidp);
1037 silc_pkcs_public_key_free(pubkey);
1039 args = silc_argument_payload_encode_one(args, invite, strlen(invite), 1);
1043 /* Send the command */
1044 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
1046 clidp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT);
1047 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 4,
1048 1, silc_buffer_datalen(chidp),
1049 2, silc_buffer_datalen(clidp),
1050 3, args ? action : NULL, args ? 1 : 0,
1051 4, silc_buffer_datalen(args));
1052 silc_buffer_free(clidp);
1054 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
1055 1, silc_buffer_datalen(chidp),
1056 3, args ? action : NULL, args ? 1 : 0,
1057 4, silc_buffer_datalen(args));
1060 silc_buffer_free(chidp);
1061 silc_buffer_free(args);
1062 silc_free(nickname);
1063 silc_client_list_free(client, conn, clients);
1065 /* Notify application */
1066 COMMAND(SILC_STATUS_OK);
1068 /** Wait for command reply */
1069 silc_fsm_next(fsm, silc_client_command_reply_wait);
1070 return SILC_FSM_CONTINUE;
1073 silc_free(nickname);
1074 return SILC_FSM_FINISH;
1077 /********************************** QUIT ************************************/
1079 /* Close the connection */
1081 SILC_FSM_STATE(silc_client_command_quit_final)
1083 SilcClientCommandContext cmd = fsm_context;
1084 SilcClientConnection conn = cmd->conn;
1085 SilcClient client = conn->client;
1087 SILC_LOG_DEBUG(("Quitting"));
1089 /* Notify application */
1090 COMMAND(SILC_STATUS_OK);
1092 /* Call connection callback */
1093 if (!conn->internal->callback_called)
1094 conn->callback(client, conn, SILC_CLIENT_CONN_DISCONNECTED,
1095 0, NULL, conn->callback_context);
1096 conn->internal->callback_called = TRUE;
1098 /* Signal to close connection */
1099 if (!conn->internal->disconnected) {
1100 conn->internal->disconnected = TRUE;
1101 SILC_FSM_SEMA_POST(&conn->internal->wait_event);
1104 return SILC_FSM_FINISH;
1107 /* Command QUIT. Closes connection with current server. */
1109 SILC_FSM_STATE(silc_client_command_quit)
1111 SilcClientCommandContext cmd = fsm_context;
1112 SilcClientConnection conn = cmd->conn;
1115 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1116 1, cmd->argv[1], cmd->argv_lens[1]);
1118 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
1120 /* Sleep for a while */
1123 /* We close the connection with a little timeout */
1124 silc_fsm_next_later(fsm, silc_client_command_quit_final, 2, 0);
1125 return SILC_FSM_WAIT;
1128 /********************************** KILL ************************************/
1131 /* Command KILL. Router operator can use this command to remove an client
1132 fromthe SILC Network. */
1134 SILC_FSM_STATE(silc_client_command_kill)
1136 SilcClientCommandContext cmd = fsm_context;
1137 SilcClientConnection conn = cmd->conn;
1138 SilcClient client = conn->client;
1139 SilcBuffer idp, auth = NULL;
1140 SilcClientEntry target;
1142 char *nickname = NULL, *comment = NULL;
1144 if (cmd->argc < 2) {
1145 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1146 "Usage: /KILL <nickname> [<comment>] [-pubkey]");
1147 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1148 return SILC_FSM_FINISH;
1151 /* Parse the typed nickname. */
1152 if (client->internal->params->nickname_parse)
1153 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
1155 nickname = strdup(cmd->argv[1]);
1157 return SILC_FSM_FINISH;
1159 /* Get the target client */
1160 clients = silc_client_get_clients_local(client, conn, nickname,
1163 /* Resolve client information */
1164 SILC_FSM_CALL(silc_client_get_clients(client, conn, nickname,
1166 silc_client_command_resolve_continue,
1169 target = silc_dlist_get(clients);
1171 if (cmd->argc >= 3) {
1172 if (strcasecmp(cmd->argv[2], "-pubkey"))
1173 comment = cmd->argv[2];
1175 if (!strcasecmp(cmd->argv[2], "-pubkey") ||
1176 (cmd->argc >= 4 && !strcasecmp(cmd->argv[3], "-pubkey"))) {
1177 /* Encode the public key authentication payload */
1178 auth = silc_auth_public_key_auth_generate(conn->public_key,
1181 conn->internal->sha1hash,
1182 &target->id, SILC_ID_CLIENT);
1186 /* Send the KILL command to the server */
1187 idp = silc_id_payload_encode(&target->id, SILC_ID_CLIENT);
1188 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
1189 1, silc_buffer_datalen(idp),
1190 2, comment, comment ? strlen(comment) : 0,
1191 3, silc_buffer_datalen(auth));
1192 silc_buffer_free(idp);
1193 silc_buffer_free(auth);
1194 silc_free(nickname);
1195 silc_client_list_free(client, conn, clients);
1197 /* Notify application */
1198 COMMAND(SILC_STATUS_OK);
1200 /** Wait for command reply */
1201 silc_fsm_next(fsm, silc_client_command_reply_wait);
1202 return SILC_FSM_CONTINUE;
1205 /********************************** INFO ************************************/
1207 /* Command INFO. Request information about specific server. If specific
1208 server is not provided the current server is used. */
1210 SILC_FSM_STATE(silc_client_command_info)
1212 SilcClientCommandContext cmd = fsm_context;
1213 SilcClientConnection conn = cmd->conn;
1215 /* Send the command */
1217 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1218 1, cmd->argv[1], cmd->argv_lens[1]);
1220 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
1222 /* Notify application */
1223 COMMAND(SILC_STATUS_OK);
1225 /** Wait for command reply */
1226 silc_fsm_next(fsm, silc_client_command_reply_wait);
1227 return SILC_FSM_CONTINUE;
1230 /********************************** STATS ***********************************/
1232 /* Command STATS. Shows server and network statistics. */
1234 SILC_FSM_STATE(silc_client_command_stats)
1236 SilcClientCommandContext cmd = fsm_context;
1237 SilcClientConnection conn = cmd->conn;
1239 /* Send the command */
1240 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1241 1, silc_buffer_datalen(conn->internal->
1244 /* Notify application */
1245 COMMAND(SILC_STATUS_OK);
1247 /** Wait for command reply */
1248 silc_fsm_next(fsm, silc_client_command_reply_wait);
1249 return SILC_FSM_CONTINUE;
1252 /********************************** PING ************************************/
1254 /* Command PING. Sends ping to server. */
1256 SILC_FSM_STATE(silc_client_command_ping)
1258 SilcClientCommandContext cmd = fsm_context;
1259 SilcClientConnection conn = cmd->conn;
1261 if (cmd->argc < 2) {
1262 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1263 return SILC_FSM_FINISH;
1266 /* Send the command */
1267 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1268 1, silc_buffer_datalen(conn->internal->
1271 /* Save ping time */
1272 cmd->context = SILC_64_TO_PTR(silc_time());
1274 /* Notify application */
1275 COMMAND(SILC_STATUS_OK);
1277 /** Wait for command reply */
1278 silc_fsm_next(fsm, silc_client_command_reply_wait);
1279 return SILC_FSM_CONTINUE;
1282 /********************************** JOIN ************************************/
1284 /* Command JOIN. Joins to a channel. */
1286 SILC_FSM_STATE(silc_client_command_join)
1288 SilcClientCommandContext cmd = fsm_context;
1289 SilcClientConnection conn = cmd->conn;
1290 SilcChannelEntry channel;
1291 SilcBuffer auth = NULL, cauth = NULL;
1292 char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
1293 int i, passphrase_len = 0;
1295 if (cmd->argc < 2) {
1296 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1300 /* See if we have joined to the requested channel already */
1301 channel = silc_client_get_channel(conn->client, conn, cmd->argv[1]);
1302 if (channel && silc_client_on_channel(channel, conn->local_entry))
1305 if (cmd->argv_lens[1] > 256)
1306 cmd->argv_lens[1] = 256;
1308 name = cmd->argv[1];
1310 for (i = 2; i < cmd->argc; i++) {
1311 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
1312 cipher = cmd->argv[++i];
1313 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
1314 hmac = cmd->argv[++i];
1315 } else if (!strcasecmp(cmd->argv[i], "-founder")) {
1316 auth = silc_auth_public_key_auth_generate(conn->public_key,
1319 conn->internal->sha1hash,
1322 } else if (!strcasecmp(cmd->argv[i], "-auth")) {
1323 SilcPublicKey pubkey = conn->public_key;
1324 SilcPrivateKey privkey = conn->private_key;
1325 unsigned char *pk, pkhash[SILC_HASH_MAXLEN], *pubdata;
1328 if (cmd->argc >= i + 3) {
1330 if (cmd->argc >= i + 4) {
1331 pass = cmd->argv[i + 3];
1334 if (!silc_load_key_pair(cmd->argv[i + 1], cmd->argv[i + 2], pass,
1335 &pubkey, &privkey)) {
1336 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1337 "Could not load key pair, check your arguments");
1338 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1344 pk = silc_pkcs_public_key_encode(pubkey, &pk_len);
1345 silc_hash_make(conn->internal->sha1hash, pk, pk_len, pkhash);
1347 pubdata = silc_rng_get_rn_data(conn->client->rng, 128);
1348 memcpy(pubdata, pkhash, 20);
1349 cauth = silc_auth_public_key_auth_generate_wpub(pubkey, privkey,
1351 conn->internal->sha1hash,
1354 memset(pubdata, 0, 128);
1357 /* Passphrases must be UTF-8 encoded, so encode if it is not */
1358 if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
1359 passphrase_len = silc_utf8_encoded_len(cmd->argv[i],
1360 cmd->argv_lens[i], 0);
1361 pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
1362 passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
1363 0, pu8, passphrase_len);
1366 passphrase = strdup(cmd->argv[i]);
1367 passphrase_len = cmd->argv_lens[i];
1372 /* Send JOIN command to the server */
1373 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 7,
1374 1, name, strlen(name),
1375 2, silc_buffer_datalen(conn->internal->
1377 3, passphrase, passphrase_len,
1378 4, cipher, cipher ? strlen(cipher) : 0,
1379 5, hmac, hmac ? strlen(hmac) : 0,
1380 6, silc_buffer_datalen(auth),
1381 7, silc_buffer_datalen(cauth));
1383 silc_buffer_free(auth);
1384 silc_buffer_free(cauth);
1386 memset(passphrase, 0, strlen(passphrase));
1387 silc_free(passphrase);
1389 /* Notify application */
1390 COMMAND(SILC_STATUS_OK);
1392 /** Wait for command reply */
1393 silc_fsm_next(fsm, silc_client_command_reply_wait);
1394 return SILC_FSM_CONTINUE;
1397 return SILC_FSM_FINISH;
1400 /********************************** MOTD ************************************/
1402 /* MOTD command. Requests motd from server. */
1404 SILC_FSM_STATE(silc_client_command_motd)
1406 SilcClientCommandContext cmd = fsm_context;
1407 SilcClientConnection conn = cmd->conn;
1409 if (cmd->argc < 1 || cmd->argc > 2) {
1410 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1411 "Usage: /MOTD [<server>]");
1412 COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
1413 SILC_STATUS_ERR_TOO_MANY_PARAMS));
1414 return SILC_FSM_FINISH;
1417 /* Send the command */
1419 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1420 1, conn->remote_host,
1421 strlen(conn->remote_host));
1423 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1424 1, cmd->argv[1], cmd->argv_lens[1]);
1426 /* Notify application */
1427 COMMAND(SILC_STATUS_OK);
1429 /** Wait for command reply */
1430 silc_fsm_next(fsm, silc_client_command_reply_wait);
1431 return SILC_FSM_CONTINUE;
1434 /********************************** UMODE ***********************************/
1436 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1437 modes as client cannot set itself server/router operator privileges. */
1439 SILC_FSM_STATE(silc_client_command_umode)
1441 SilcClientCommandContext cmd = fsm_context;
1442 SilcClientConnection conn = cmd->conn;
1443 unsigned char *cp, modebuf[4];
1444 SilcUInt32 mode, add, len;
1447 if (cmd->argc < 2) {
1448 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1449 "Usage: /UMODE +|-<modes>");
1450 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1451 return SILC_FSM_FINISH;
1454 mode = conn->local_entry->mode;
1456 /* Are we adding or removing mode */
1457 if (cmd->argv[1][0] == '-')
1463 cp = cmd->argv[1] + 1;
1465 for (i = 0; i < len; i++) {
1470 mode |= SILC_UMODE_SERVER_OPERATOR;
1471 mode |= SILC_UMODE_ROUTER_OPERATOR;
1472 mode |= SILC_UMODE_GONE;
1473 mode |= SILC_UMODE_INDISPOSED;
1474 mode |= SILC_UMODE_BUSY;
1475 mode |= SILC_UMODE_PAGE;
1476 mode |= SILC_UMODE_HYPER;
1477 mode |= SILC_UMODE_ROBOT;
1478 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1479 mode |= SILC_UMODE_REJECT_WATCHING;
1481 mode = SILC_UMODE_NONE;
1486 mode |= SILC_UMODE_SERVER_OPERATOR;
1488 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1492 mode |= SILC_UMODE_ROUTER_OPERATOR;
1494 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1498 mode |= SILC_UMODE_GONE;
1500 mode &= ~SILC_UMODE_GONE;
1504 mode |= SILC_UMODE_INDISPOSED;
1506 mode &= ~SILC_UMODE_INDISPOSED;
1510 mode |= SILC_UMODE_BUSY;
1512 mode &= ~SILC_UMODE_BUSY;
1516 mode |= SILC_UMODE_PAGE;
1518 mode &= ~SILC_UMODE_PAGE;
1522 mode |= SILC_UMODE_HYPER;
1524 mode &= ~SILC_UMODE_HYPER;
1528 mode |= SILC_UMODE_ROBOT;
1530 mode &= ~SILC_UMODE_ROBOT;
1534 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1536 mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
1540 mode |= SILC_UMODE_REJECT_WATCHING;
1542 mode &= ~SILC_UMODE_REJECT_WATCHING;
1546 mode |= SILC_UMODE_BLOCK_INVITE;
1548 mode &= ~SILC_UMODE_BLOCK_INVITE;
1551 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1552 return SILC_FSM_FINISH;
1557 SILC_PUT32_MSB(mode, modebuf);
1559 /* Send the command */
1560 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
1561 1, silc_buffer_datalen(conn->internal->
1563 2, modebuf, sizeof(modebuf));
1565 /* Notify application */
1566 COMMAND(SILC_STATUS_OK);
1568 /** Wait for command reply */
1569 silc_fsm_next(fsm, silc_client_command_reply_wait);
1570 return SILC_FSM_CONTINUE;
1573 /********************************** CMODE ***********************************/
1575 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1576 can be set several at once. Those modes that require argument must be set
1577 separately (unless set with modes that does not require arguments). */
1579 SILC_FSM_STATE(silc_client_command_cmode)
1581 SilcClientCommandContext cmd = fsm_context;
1582 SilcClientConnection conn = cmd->conn;
1583 SilcClient client = conn->client;
1584 SilcChannelEntry channel;
1585 SilcBuffer chidp, auth = NULL, pk = NULL;
1586 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1587 SilcUInt32 mode, add, type, len, arg_len = 0;
1590 if (cmd->argc < 3) {
1591 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1592 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1593 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1597 if (cmd->argv[1][0] == '*') {
1598 if (!conn->current_channel) {
1599 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1603 channel = conn->current_channel;
1605 name = cmd->argv[1];
1607 channel = silc_client_get_channel(conn->client, conn, name);
1609 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1614 mode = channel->mode;
1616 /* Are we adding or removing mode */
1617 if (cmd->argv[2][0] == '-')
1622 /* Argument type to be sent to server */
1626 cp = cmd->argv[2] + 1;
1628 for (i = 0; i < len; i++) {
1632 mode |= SILC_CHANNEL_MODE_PRIVATE;
1634 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1638 mode |= SILC_CHANNEL_MODE_SECRET;
1640 mode &= ~SILC_CHANNEL_MODE_SECRET;
1644 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1646 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1650 mode |= SILC_CHANNEL_MODE_INVITE;
1652 mode &= ~SILC_CHANNEL_MODE_INVITE;
1656 mode |= SILC_CHANNEL_MODE_TOPIC;
1658 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1662 mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1664 mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1668 mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1670 mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1675 mode |= SILC_CHANNEL_MODE_ULIMIT;
1677 if (cmd->argc < 4) {
1678 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1679 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1680 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1683 ll = atoi(cmd->argv[3]);
1684 SILC_PUT32_MSB(ll, tmp);
1688 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1693 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1695 if (cmd->argc < 4) {
1696 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1697 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1698 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1702 arg_len = cmd->argv_lens[3];
1704 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1709 mode |= SILC_CHANNEL_MODE_CIPHER;
1711 if (cmd->argc < 4) {
1712 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1713 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1714 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1718 arg_len = cmd->argv_lens[3];
1720 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1725 mode |= SILC_CHANNEL_MODE_HMAC;
1727 if (cmd->argc < 4) {
1728 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1729 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1730 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1734 arg_len = cmd->argv_lens[3];
1736 mode &= ~SILC_CHANNEL_MODE_HMAC;
1741 SilcPublicKey pubkey = conn->public_key;
1742 SilcPrivateKey privkey = conn->private_key;
1744 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1747 if (cmd->argc >= 5) {
1750 pass = cmd->argv[5];
1751 if (!silc_load_key_pair(cmd->argv[3], cmd->argv[4], pass,
1752 &pubkey, &privkey)) {
1753 SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1754 "Could not load key pair, check your arguments");
1755 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1760 pk = silc_public_key_payload_encode(pubkey);
1761 auth = silc_auth_public_key_auth_generate(pubkey, privkey,
1763 conn->internal->sha1hash,
1766 arg = silc_buffer_data(auth);
1767 arg_len = silc_buffer_len(auth);
1769 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1775 SilcBool chadd = FALSE;
1776 SilcPublicKey chpk = NULL;
1778 mode |= SILC_CHANNEL_MODE_CHANNEL_AUTH;
1781 if (cmd->argc == 3) {
1782 /* Send empty command to receive the public key list. */
1783 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
1784 silc_client_command_send_va(conn, cmd, SILC_COMMAND_CMODE,
1786 1, silc_buffer_datalen(chidp));
1787 silc_buffer_free(chidp);
1789 /* Notify application */
1790 COMMAND(SILC_STATUS_OK);
1794 if (cmd->argc >= 4) {
1795 auth = silc_buffer_alloc_size(2);
1796 silc_buffer_format(auth,
1797 SILC_STR_UI_SHORT(cmd->argc - 3),
1801 for (k = 3; k < cmd->argc; k++) {
1802 if (cmd->argv[k][0] == '+')
1804 if (!silc_pkcs_load_public_key(cmd->argv[k] + 1, &chpk)) {
1805 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1806 "Could not load public key %s, check the filename",
1808 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1809 silc_buffer_free(auth);
1814 pk = silc_public_key_payload_encode(chpk);
1815 auth = silc_argument_payload_encode_one(auth,
1816 silc_buffer_datalen(pk),
1817 chadd ? 0x00 : 0x01);
1818 silc_pkcs_public_key_free(chpk);
1819 silc_buffer_free(pk);
1824 arg = silc_buffer_data(auth);
1825 arg_len = silc_buffer_len(auth);
1827 mode &= ~SILC_CHANNEL_MODE_CHANNEL_AUTH;
1831 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1837 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
1838 SILC_PUT32_MSB(mode, modebuf);
1840 /* Send the command. We support sending only one mode at once that
1841 requires an argument. */
1843 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 4,
1844 1, silc_buffer_datalen(chidp),
1845 2, modebuf, sizeof(modebuf),
1847 8, silc_buffer_datalen(pk));
1849 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
1850 1, silc_buffer_datalen(chidp),
1851 2, modebuf, sizeof(modebuf));
1854 silc_buffer_free(chidp);
1855 silc_buffer_free(auth);
1856 silc_buffer_free(pk);
1858 /* Notify application */
1859 COMMAND(SILC_STATUS_OK);
1861 /** Wait for command reply */
1862 silc_fsm_next(fsm, silc_client_command_reply_wait);
1863 return SILC_FSM_CONTINUE;
1866 return SILC_FSM_FINISH;
1869 /********************************* CUMODE ***********************************/
1871 /* CUMODE command. Changes client's mode on a channel. */
1873 SILC_FSM_STATE(silc_client_command_cumode)
1875 SilcClientCommandContext cmd = fsm_context;
1876 SilcClientConnection conn = cmd->conn;
1877 SilcClient client = conn->client;
1878 SilcChannelEntry channel;
1879 SilcChannelUser chu;
1880 SilcClientEntry client_entry;
1881 SilcBuffer clidp, chidp, auth = NULL;
1882 SilcDList clients = NULL;
1883 unsigned char *name, *cp, modebuf[4];
1884 SilcUInt32 mode = 0, add, len;
1885 char *nickname = NULL;
1888 if (cmd->argc < 4) {
1889 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
1890 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1891 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1895 if (cmd->argv[1][0] == '*') {
1896 if (!conn->current_channel) {
1897 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1901 channel = conn->current_channel;
1903 name = cmd->argv[1];
1905 channel = silc_client_get_channel(conn->client, conn, name);
1907 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1912 /* Parse the typed nickname. */
1913 if (client->internal->params->nickname_parse)
1914 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1916 nickname = strdup(cmd->argv[3]);
1918 /* Find client entry */
1919 clients = silc_client_get_clients_local(client, conn, nickname,
1922 /* Resolve client information */
1923 SILC_FSM_CALL(silc_client_get_clients(client, conn, nickname, cmd->argv[3],
1924 silc_client_command_resolve_continue,
1927 client_entry = silc_dlist_get(clients);
1929 /* Get the current mode */
1930 chu = silc_client_on_channel(channel, client_entry);
1934 /* Are we adding or removing mode */
1935 if (cmd->argv[2][0] == '-')
1941 cp = cmd->argv[2] + 1;
1943 for (i = 0; i < len; i++) {
1947 mode |= SILC_CHANNEL_UMODE_CHANFO;
1948 mode |= SILC_CHANNEL_UMODE_CHANOP;
1949 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1950 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1951 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1953 mode = SILC_CHANNEL_UMODE_NONE;
1958 SilcPublicKey pubkey = conn->public_key;
1959 SilcPrivateKey privkey = conn->private_key;
1961 if (cmd->argc >= 6) {
1964 pass = cmd->argv[6];
1965 if (!silc_load_key_pair(cmd->argv[4], cmd->argv[5], pass,
1966 &pubkey, &privkey)) {
1967 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1968 "Could not load key pair, check your arguments");
1969 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1974 auth = silc_auth_public_key_auth_generate(pubkey, privkey,
1976 conn->internal->sha1hash,
1979 mode |= SILC_CHANNEL_UMODE_CHANFO;
1981 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1986 mode |= SILC_CHANNEL_UMODE_CHANOP;
1988 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1992 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1994 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1998 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
2000 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
2004 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
2006 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
2010 mode |= SILC_CHANNEL_UMODE_QUIET;
2012 mode &= ~SILC_CHANNEL_UMODE_QUIET;
2015 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
2021 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
2022 SILC_PUT32_MSB(mode, modebuf);
2023 clidp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT);
2025 /* Send the command packet. We support sending only one mode at once
2026 that requires an argument. */
2027 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, auth ? 4 : 3,
2028 1, silc_buffer_datalen(chidp),
2030 3, silc_buffer_datalen(clidp),
2031 4, silc_buffer_datalen(auth));
2033 silc_buffer_free(chidp);
2034 silc_buffer_free(clidp);
2036 silc_buffer_free(auth);
2037 silc_free(nickname);
2038 silc_client_list_free(client, conn, clients);
2040 /* Notify application */
2041 COMMAND(SILC_STATUS_OK);
2043 /** Wait for command reply */
2044 silc_fsm_next(fsm, silc_client_command_reply_wait);
2045 return SILC_FSM_CONTINUE;
2048 silc_client_list_free(client, conn, clients);
2049 silc_free(nickname);
2050 return SILC_FSM_FINISH;
2053 /********************************** KICK ************************************/
2055 /* KICK command. Kicks a client out of channel. */
2057 SILC_FSM_STATE(silc_client_command_kick)
2059 SilcClientCommandContext cmd = fsm_context;
2060 SilcClientConnection conn = cmd->conn;
2061 SilcClient client = conn->client;
2062 SilcChannelEntry channel;
2063 SilcBuffer idp, idp2;
2064 SilcClientEntry target;
2065 SilcDList clients = NULL;
2067 char *nickname = NULL;
2069 if (cmd->argc < 3) {
2070 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2071 "Usage: /KICK <channel> <nickname> [<comment>]");
2072 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2076 if (cmd->argv[1][0] == '*') {
2077 if (!conn->current_channel) {
2078 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2081 name = conn->current_channel->channel_name;
2083 name = cmd->argv[1];
2086 if (!conn->current_channel) {
2087 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2091 /* Get the Channel ID of the channel */
2092 channel = silc_client_get_channel(conn->client, conn, name);
2094 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2098 /* Parse the typed nickname. */
2099 if (client->internal->params->nickname_parse)
2100 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
2102 nickname = strdup(cmd->argv[2]);
2104 /* Get the target client */
2105 clients = silc_client_get_clients_local(client, conn, nickname,
2108 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2109 "No such client: %s", cmd->argv[2]);
2110 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2113 target = silc_dlist_get(clients);
2115 /* Send KICK command to the server */
2116 idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
2117 idp2 = silc_id_payload_encode(&target->id, SILC_ID_CLIENT);
2119 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
2120 1, silc_buffer_datalen(idp),
2121 2, silc_buffer_datalen(idp2));
2123 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
2124 1, silc_buffer_datalen(idp),
2125 2, silc_buffer_datalen(idp2),
2126 3, cmd->argv[3], strlen(cmd->argv[3]));
2128 silc_buffer_free(idp);
2129 silc_buffer_free(idp2);
2130 silc_free(nickname);
2131 silc_client_list_free(client, conn, clients);
2133 /* Notify application */
2134 COMMAND(SILC_STATUS_OK);
2136 /** Wait for command reply */
2137 silc_fsm_next(fsm, silc_client_command_reply_wait);
2138 return SILC_FSM_CONTINUE;
2141 silc_free(nickname);
2142 return SILC_FSM_FINISH;
2145 /***************************** OPER & SILCOPER ******************************/
2148 unsigned char *passphrase;
2149 SilcUInt32 passphrase_len;
2150 } *SilcClientCommandOper;
2152 /* Ask passphrase callback */
2154 static void silc_client_command_oper_cb(unsigned char *data,
2155 SilcUInt32 data_len, void *context)
2157 SilcClientCommandContext cmd = context;
2158 SilcClientCommandOper oper = cmd->context;
2160 if (data && data_len)
2161 oper->passphrase = silc_memdup(data, data_len);
2162 oper->passphrase_len = data_len;
2165 SILC_FSM_CALL_CONTINUE(&cmd->thread);
2168 /* Send OPER/SILCOPER command */
2170 SILC_FSM_STATE(silc_client_command_oper_send)
2172 SilcClientCommandContext cmd = fsm_context;
2173 SilcClientConnection conn = cmd->conn;
2174 SilcClientCommandOper oper = cmd->context;
2177 if (!oper || !oper->passphrase) {
2178 /* Encode the public key authentication payload */
2179 auth = silc_auth_public_key_auth_generate(conn->public_key,
2182 conn->internal->hash,
2186 /* Encode the password authentication payload */
2187 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
2188 oper->passphrase, oper->passphrase_len);
2191 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
2192 1, cmd->argv[1], strlen(cmd->argv[1]),
2193 2, silc_buffer_datalen(auth));
2195 silc_buffer_clear(auth);
2196 silc_buffer_free(auth);
2198 silc_free(oper->passphrase);
2202 /* Notify application */
2203 COMMAND(SILC_STATUS_OK);
2205 /** Wait for command reply */
2206 silc_fsm_next(fsm, silc_client_command_reply_wait);
2207 return SILC_FSM_CONTINUE;
2210 /* OPER command. Used to obtain server operator privileges. */
2212 SILC_FSM_STATE(silc_client_command_oper)
2214 SilcClientCommandContext cmd = fsm_context;
2215 SilcClientConnection conn = cmd->conn;
2216 SilcClientCommandOper oper;
2218 if (cmd->argc < 2) {
2219 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2220 "Usage: /OPER <username> [-pubkey]");
2221 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2222 return SILC_FSM_FINISH;
2225 /* Get passphrase */
2226 if (cmd->argc < 3) {
2227 oper = silc_calloc(1, sizeof(*oper));
2229 return SILC_FSM_FINISH;
2230 cmd->context = oper;
2231 SILC_FSM_CALL(conn->client->internal->
2232 ops->ask_passphrase(conn->client, conn,
2233 silc_client_command_oper_cb, cmd));
2236 silc_fsm_next(fsm, silc_client_command_oper_send);
2237 return SILC_FSM_CONTINUE;
2240 /* SILCOPER command. Used to obtain router operator privileges. */
2242 SILC_FSM_STATE(silc_client_command_silcoper)
2244 SilcClientCommandContext cmd = fsm_context;
2245 SilcClientConnection conn = cmd->conn;
2246 SilcClientCommandOper oper;
2248 if (cmd->argc < 2) {
2249 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2250 "Usage: /SILCOPER <username> [-pubkey]");
2251 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2252 return SILC_FSM_FINISH;
2255 /* Get passphrase */
2256 if (cmd->argc < 3) {
2257 oper = silc_calloc(1, sizeof(*oper));
2259 return SILC_FSM_FINISH;
2260 cmd->context = oper;
2261 SILC_FSM_CALL(conn->client->internal->
2262 ops->ask_passphrase(conn->client, conn,
2263 silc_client_command_oper_cb, cmd));
2266 silc_fsm_next(fsm, silc_client_command_oper_send);
2267 return SILC_FSM_CONTINUE;
2270 /*********************************** BAN ************************************/
2272 /* Command BAN. This is used to manage the ban list of the channel. */
2274 SILC_FSM_STATE(silc_client_command_ban)
2276 SilcClientCommandContext cmd = fsm_context;
2277 SilcClientConnection conn = cmd->conn;
2278 SilcChannelEntry channel;
2279 SilcBuffer chidp, args = NULL;
2280 char *name, *ban = NULL;
2281 unsigned char action[1];
2282 SilcPublicKey pubkey = NULL;
2284 if (cmd->argc < 2) {
2285 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2286 "Usage: /BAN <channel> "
2287 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
2288 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2292 if (cmd->argv[1][0] == '*') {
2293 if (!conn->current_channel) {
2294 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2298 channel = conn->current_channel;
2300 name = cmd->argv[1];
2302 channel = silc_client_get_channel(conn->client, conn, name);
2304 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2309 if (cmd->argc == 3) {
2310 if (cmd->argv[2][0] == '+')
2315 /* Check if it is public key file to be added to invite list */
2316 silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey);
2323 args = silc_buffer_alloc_size(2);
2324 silc_buffer_format(args,
2325 SILC_STR_UI_SHORT(1),
2328 chidp = silc_public_key_payload_encode(pubkey);
2329 args = silc_argument_payload_encode_one(args,
2330 silc_buffer_datalen(chidp), 2);
2331 silc_buffer_free(chidp);
2332 silc_pkcs_public_key_free(pubkey);
2334 args = silc_argument_payload_encode_one(args, ban, strlen(ban), 1);
2338 chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
2340 /* Send the command */
2341 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
2342 1, silc_buffer_datalen(chidp),
2343 2, args ? action : NULL, args ? 1 : 0,
2344 3, silc_buffer_datalen(args));
2346 silc_buffer_free(chidp);
2347 silc_buffer_free(args);
2349 /* Notify application */
2350 COMMAND(SILC_STATUS_OK);
2352 /** Wait for command reply */
2353 silc_fsm_next(fsm, silc_client_command_reply_wait);
2354 return SILC_FSM_CONTINUE;
2357 return SILC_FSM_FINISH;
2360 /********************************* DETACH ***********************************/
2362 /* Command DETACH. This is used to detach from the server */
2364 SILC_FSM_STATE(silc_client_command_detach)
2366 SilcClientCommandContext cmd = fsm_context;
2367 SilcClientConnection conn = cmd->conn;
2369 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
2371 /* Notify application */
2372 COMMAND(SILC_STATUS_OK);
2374 /** Wait for command reply */
2375 silc_fsm_next(fsm, silc_client_command_reply_wait);
2376 return SILC_FSM_CONTINUE;
2379 /********************************** WATCH ***********************************/
2381 /* Command WATCH. */
2383 SILC_FSM_STATE(silc_client_command_watch)
2385 SilcClientCommandContext cmd = fsm_context;
2386 SilcClientConnection conn = cmd->conn;
2387 SilcBuffer args = NULL;
2389 const char *pubkey = NULL;
2390 SilcBool pubkey_add = TRUE;
2392 if (cmd->argc < 3) {
2393 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2397 if (!strcasecmp(cmd->argv[1], "-add")) {
2399 } else if (!strcasecmp(cmd->argv[1], "-del")) {
2401 } else if (!strcasecmp(cmd->argv[1], "-pubkey") && cmd->argc >= 3) {
2403 pubkey = cmd->argv[2] + 1;
2404 if (cmd->argv[2][0] == '-')
2407 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2415 if (!silc_pkcs_load_public_key(pubkey, &pk)) {
2416 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2417 "Could not load public key %s, check the filename", pubkey);
2418 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2422 args = silc_buffer_alloc_size(2);
2423 silc_buffer_format(args,
2424 SILC_STR_UI_SHORT(1),
2426 buffer = silc_public_key_payload_encode(pk);
2427 args = silc_argument_payload_encode_one(args, silc_buffer_datalen(buffer),
2428 pubkey_add ? 0x00 : 0x01);
2429 silc_buffer_free(buffer);
2430 silc_pkcs_public_key_free(pk);
2433 /* Send the commmand */
2434 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
2435 1, silc_buffer_datalen(conn->internal->
2437 type, pubkey ? args->data : cmd->argv[2],
2438 pubkey ? silc_buffer_len(args) :
2441 silc_buffer_free(args);
2443 /* Notify application */
2444 COMMAND(SILC_STATUS_OK);
2446 /** Wait for command reply */
2447 silc_fsm_next(fsm, silc_client_command_reply_wait);
2448 return SILC_FSM_CONTINUE;
2451 return SILC_FSM_FINISH;
2454 /********************************** LEAVE ***********************************/
2456 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2458 SILC_FSM_STATE(silc_client_command_leave)
2460 SilcClientCommandContext cmd = fsm_context;
2461 SilcClientConnection conn = cmd->conn;
2462 SilcChannelEntry channel;
2466 if (cmd->argc != 2) {
2467 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2468 "Usage: /LEAVE <channel>");
2469 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2473 if (cmd->argv[1][0] == '*') {
2474 if (!conn->current_channel) {
2475 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2478 name = conn->current_channel->channel_name;
2480 name = cmd->argv[1];
2483 /* Get the channel entry */
2484 channel = silc_client_get_channel(conn->client, conn, name);
2486 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2490 idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
2492 /* Send LEAVE command to the server */
2493 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
2494 1, silc_buffer_datalen(idp));
2496 silc_buffer_free(idp);
2498 /* Notify application */
2499 COMMAND(SILC_STATUS_OK);
2501 if (conn->current_channel == channel)
2502 conn->current_channel = NULL;
2504 /** Wait for command reply */
2505 silc_fsm_next(fsm, silc_client_command_reply_wait);
2506 return SILC_FSM_CONTINUE;
2509 return SILC_FSM_FINISH;
2512 /********************************** USERS ***********************************/
2514 /* Command USERS. Requests the USERS of the clients joined on requested
2517 SILC_FSM_STATE(silc_client_command_users)
2519 SilcClientCommandContext cmd = fsm_context;
2520 SilcClientConnection conn = cmd->conn;
2523 if (cmd->argc != 2) {
2524 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2525 "Usage: /USERS <channel>");
2526 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2530 if (cmd->argv[1][0] == '*') {
2531 if (!conn->current_channel) {
2532 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2535 name = conn->current_channel->channel_name;
2537 name = cmd->argv[1];
2540 /* Send USERS command to the server */
2541 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
2542 2, name, strlen(name));
2544 /* Notify application */
2545 COMMAND(SILC_STATUS_OK);
2547 /** Wait for command reply */
2548 silc_fsm_next(fsm, silc_client_command_reply_wait);
2549 return SILC_FSM_CONTINUE;
2552 return SILC_FSM_FINISH;
2555 /********************************* GETKEY ***********************************/
2557 /* Command GETKEY. Used to fetch remote client's public key. */
2559 SILC_FSM_STATE(silc_client_command_getkey)
2561 SilcClientCommandContext cmd = fsm_context;
2562 SilcClientConnection conn = cmd->conn;
2563 SilcClient client = conn->client;
2564 SilcClientEntry client_entry;
2565 SilcServerEntry server_entry;
2567 char *nickname = NULL;
2570 if (cmd->argc < 2) {
2571 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2572 "Usage: /GETKEY <nickname or server name>");
2573 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2574 return SILC_FSM_FINISH;
2577 /* Parse the typed nickname. */
2578 if (client->internal->params->nickname_parse)
2579 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2581 nickname = strdup(cmd->argv[1]);
2583 COMMAND_ERROR(SILC_STATUS_ERR_RESOURCE_LIMIT);
2584 return SILC_FSM_FINISH;
2587 /* Find client entry */
2588 clients = silc_client_get_clients_local(client, conn, nickname,
2591 /* Check whether user requested server */
2592 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2593 if (!server_entry) {
2594 if (cmd->resolved) {
2595 /* Resolving didn't find anything. We should never get here as
2596 errors are handled in the resolving callback. */
2597 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2598 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_SERVER);
2599 return SILC_FSM_FINISH;
2602 /* No client or server exist with this name, query for both. */
2603 cmd->resolved = TRUE;
2604 SILC_FSM_CALL(silc_client_command_send(client, conn,
2605 SILC_COMMAND_IDENTIFY,
2606 silc_client_command_continue,
2609 strlen(cmd->argv[1]),
2611 strlen(cmd->argv[1])));
2614 idp = silc_id_payload_encode(&server_entry->id, SILC_ID_SERVER);
2615 silc_client_unref_server(client, conn, server_entry);
2617 client_entry = silc_dlist_get(clients);
2618 idp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT);
2619 silc_client_list_free(client, conn, clients);
2622 /* Send the commmand */
2623 silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
2624 1, silc_buffer_datalen(idp));
2626 silc_buffer_free(idp);
2627 silc_free(nickname);
2629 /* Notify application */
2630 COMMAND(SILC_STATUS_OK);
2632 /** Wait for command reply */
2633 silc_fsm_next(fsm, silc_client_command_reply_wait);
2634 return SILC_FSM_CONTINUE;
2637 /********************************* SERVICE **********************************/
2639 /* Command SERVICE. Negotiates service agreement with server. */
2640 /* XXX incomplete */
2642 SILC_FSM_STATE(silc_client_command_service)
2644 SilcClientCommandContext cmd = fsm_context;
2646 SilcClientConnection conn = cmd->conn;
2650 if (cmd->argc < 2) {
2651 SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
2652 "Usage: /SERVICE [<service name>] [-pubkey]");
2653 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2654 return SILC_FSM_FINISH;
2657 name = cmd->argv[1];
2659 /* Send SERVICE command to the server */
2660 buffer = silc_command_payload_encode_va(SILC_COMMAND_SERVICE,
2661 ++conn->cmd_ident, 1,
2662 1, name, strlen(name));
2663 silc_client_packet_send(conn->client, conn->sock, SILC_PACKET_COMMAND,
2664 NULL, 0, NULL, NULL, buffer->data,
2666 silc_buffer_free(buffer);
2669 /* Notify application */
2670 COMMAND(SILC_STATUS_OK);
2672 /** Wait for command reply */
2673 silc_fsm_next(fsm, silc_client_command_reply_wait);
2674 return SILC_FSM_CONTINUE;
2677 /* Register all default commands provided by the client library for the
2680 void silc_client_commands_register(SilcClient client)
2682 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2685 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 5);
2686 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2687 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2688 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2689 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2690 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2691 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2692 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2693 SILC_CLIENT_CMD(kill, KILL, "KILL", 4);
2694 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2695 SILC_CLIENT_CMD(stats, STATS, "STATS", 0);
2696 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2697 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2698 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2699 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2700 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2701 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 6);
2702 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 9);
2703 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2704 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2705 SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2706 SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
2707 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2708 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2709 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2710 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2711 SILC_CLIENT_CMD(service, SERVICE, "SERVICE", 10);
2714 /* Unregister all commands. */
2716 void silc_client_commands_unregister(SilcClient client)
2718 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2719 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2720 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2721 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2722 SILC_CLIENT_CMDU(list, LIST, "LIST");
2723 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2724 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2725 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2726 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2727 SILC_CLIENT_CMDU(info, INFO, "INFO");
2728 SILC_CLIENT_CMDU(stats, STATS, "STATS");
2729 SILC_CLIENT_CMDU(ping, PING, "PING");
2730 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2731 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2732 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2733 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2734 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2735 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2736 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2737 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2738 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2739 SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2740 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2741 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2742 SILC_CLIENT_CMDU(users, USERS, "USERS");
2743 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2744 SILC_CLIENT_CMDU(service, SERVICE, "SERVICE");
2747 /****************** Client Side Incoming Command Handling *******************/
2749 /* Reply to WHOIS command from server */
2751 static void silc_client_command_process_whois(SilcClient client,
2752 SilcClientConnection conn,
2753 SilcCommandPayload payload,
2754 SilcArgumentPayload args)
2760 SilcBuffer buffer, packet;
2762 SILC_LOG_DEBUG(("Received WHOIS command"));
2764 /* Try to take the Requested Attributes */
2765 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
2769 attrs = silc_attribute_payload_parse(tmp, tmp_len);
2773 /* Process requested attributes */
2774 buffer = silc_client_attributes_process(client, conn, attrs);
2776 silc_attribute_payload_list_free(attrs);
2780 /* Send the attributes back */
2782 silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
2784 silc_command_get_ident(payload),
2785 1, 11, buffer->data, buffer->len);
2786 silc_client_packet_send(client, sock, SILC_PACKET_COMMAND_REPLY,
2787 NULL, 0, NULL, NULL, packet->data,
2789 silc_buffer_free(packet);
2790 silc_buffer_free(buffer);
2794 /* Client is able to receive some command packets even though they are
2795 special case. Server may send WHOIS command to the client to retrieve
2796 Requested Attributes information for WHOIS query the server is
2797 processing. This function currently handles only the WHOIS command,
2798 but if in the future more commands may arrive then this can be made
2799 to support other commands too. */
2801 SILC_FSM_STATE(silc_client_command)
2803 SilcClientConnection conn = fsm_context;
2804 SilcClient client = conn->client;
2805 SilcPacket packet = state_context;
2806 SilcCommandPayload payload;
2807 SilcCommand command;
2808 SilcArgumentPayload args;
2810 /* Get command payload from packet */
2811 payload = silc_command_payload_parse(packet->buffer.data,
2812 silc_buffer_len(&packet->buffer));
2814 SILC_LOG_DEBUG(("Bad command packet"));
2815 return SILC_FSM_FINISH;
2819 args = silc_command_get_args(payload);
2821 /* Get the command */
2822 command = silc_command_get(payload);
2825 case SILC_COMMAND_WHOIS:
2826 /* Ignore everything if requested by application */
2827 if (client->internal->params->ignore_requested_attributes)
2830 silc_client_command_process_whois(client, conn, payload, args);
2837 silc_command_payload_free(payload);
2838 return SILC_FSM_FINISH;