+++ /dev/null
-/*
-
- command.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 1997 - 2007 Pekka Riikonen
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; version 2 of the License.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
-*/
-/* $Id$ */
-
-#include "silc.h"
-#include "silcclient.h"
-#include "client_internal.h"
-
-/************************** Types and definitions ***************************/
-
-/* Command operation that is called at the end of all commands.
- Usage: COMMAND(status); */
-#define COMMAND(status) cmd->conn->client->internal->ops->command( \
- cmd->conn->client, cmd->conn, TRUE, cmd->cmd, (status), cmd->argc, cmd->argv)
-
-/* Error to application. Usage: COMMAND_ERROR(status); */
-#define COMMAND_ERROR(status) \
- cmd->conn->client->internal->ops->command(cmd->conn->client, \
- cmd->conn, FALSE, cmd->cmd, (status), cmd->argc, cmd->argv)
-
-/* Used to register new command */
-#define SILC_CLIENT_CMD(func, cmd, name, args) \
-silc_client_command_register(client, SILC_COMMAND_##cmd, name, \
- silc_client_command_##func, \
- silc_client_command_reply_##func, args)
-
-/* Used to unregister command */
-#define SILC_CLIENT_CMDU(func, cmd, name) \
-silc_client_command_unregister(client, SILC_COMMAND_##cmd, \
- silc_client_command_##func, \
- silc_client_command_reply_##func)
-
-#define SAY cmd->conn->client->internal->ops->say
-
-/************************ Static utility functions **************************/
-
-/* Return next available command identifier. */
-
-static SilcUInt16 silc_client_cmd_ident(SilcClientConnection conn)
-{
- SilcUInt16 cmd_ident;
-
- cmd_ident = silc_atomic_add_int16(&conn->internal->cmd_ident, 1);
- if (!cmd_ident)
- cmd_ident = silc_atomic_add_int16(&conn->internal->cmd_ident, 1);
-
- return cmd_ident;
-}
-
-/* State to finish command thread after an error in resolving command */
-
-SILC_FSM_STATE(silc_client_command_continue_error)
-{
- /* Destructor will free all resources */
- return SILC_FSM_FINISH;
-}
-
-/* Command reply callback to continue with the execution of a command.
- This will continue when first successful reply is received, and ignores
- the rest. On the other hand, if only errors are received it will
- wait for all errors before continuing. */
-
-static SilcBool silc_client_command_continue(SilcClient client,
- SilcClientConnection conn,
- SilcCommand command,
- SilcStatus status,
- SilcStatus error,
- void *context,
- va_list ap)
-{
- SilcClientCommandContext cmd = context;
-
- /* Continue immediately when successful reply is received */
- if (status == SILC_STATUS_OK || !SILC_STATUS_IS_ERROR(error)) {
- SILC_FSM_CALL_CONTINUE(&cmd->thread);
- return FALSE;
- }
-
- /* Error */
- COMMAND_ERROR(error);
-
- /* Continue after last error is received */
- if (SILC_STATUS_IS_ERROR(status) ||
- (status == SILC_STATUS_LIST_END && SILC_STATUS_IS_ERROR(error))) {
- silc_fsm_next(&cmd->thread, silc_client_command_continue_error);
- SILC_FSM_CALL_CONTINUE(&cmd->thread);
- return FALSE;
- }
-
- return TRUE;
-}
-
-/* Continues after resolving completed. */
-
-static void silc_client_command_resolve_continue(SilcClient client,
- SilcClientConnection conn,
- SilcStatus status,
- SilcDList clients,
- void *context)
-{
- SilcClientCommandContext cmd = context;
-
- if (status != SILC_STATUS_OK)
- silc_fsm_next(&cmd->thread, silc_client_command_continue_error);
-
- /* Continue with the command */
- SILC_FSM_CALL_CONTINUE(&cmd->thread);
-}
-
-/* Dummy command callback. Nothing interesting to do here. Use this when
- you just send command but don't care about reply. */
-
-SilcBool silc_client_command_called_dummy(SilcClient client,
- SilcClientConnection conn,
- SilcCommand command,
- SilcStatus status,
- SilcStatus error,
- void *context,
- va_list ap)
-{
- return FALSE;
-}
-
-/* Dummy resolving callback. Nothing interesting to do here. Use this
- when you just resolve entires but don't care about reply. */
-
-void silc_client_command_resolve_dummy(SilcClient client,
- SilcClientConnection conn,
- SilcStatus status,
- SilcDList clients,
- void *context)
-{
- /* Nothing */
-}
-
-/* Register command to client */
-
-static SilcBool
-silc_client_command_register(SilcClient client,
- SilcCommand command,
- const char *name,
- SilcFSMStateCallback command_func,
- SilcFSMStateCallback command_reply_func,
- SilcUInt8 max_args)
-{
- SilcClientCommand cmd;
-
- cmd = silc_calloc(1, sizeof(*cmd));
- if (!cmd)
- return FALSE;
- cmd->cmd = command;
- cmd->command = command_func;
- cmd->reply = command_reply_func;
- cmd->max_args = max_args;
- cmd->name = name ? strdup(name) : NULL;
- if (!cmd->name) {
- silc_free(cmd);
- return FALSE;
- }
-
- silc_list_add(client->internal->commands, cmd);
-
- return TRUE;
-}
-
-/* Unregister command from client */
-
-static SilcBool
-silc_client_command_unregister(SilcClient client,
- SilcCommand command,
- SilcFSMStateCallback command_func,
- SilcFSMStateCallback command_reply_func)
-{
- SilcClientCommand cmd;
-
- silc_list_start(client->internal->commands);
- while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
- if (cmd->cmd == command && cmd->command == command_func &&
- cmd->reply == command_reply_func) {
- silc_list_del(client->internal->commands, cmd);
- silc_free(cmd->name);
- silc_free(cmd);
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-/* Finds and returns a pointer to the command list. Return NULL if the
- command is not found. */
-
-static SilcClientCommand silc_client_command_find(SilcClient client,
- const char *name)
-{
- SilcClientCommand cmd;
-
- silc_list_start(client->internal->commands);
- while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
- if (cmd->name && !strcasecmp(cmd->name, name))
- return cmd;
- }
-
- return NULL;
-}
-
-/* Command thread destructor */
-
-static void silc_client_command_destructor(SilcFSMThread thread,
- void *fsm_context,
- void *destructor_context)
-{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
-
- /* Removes commands that aren't waiting for reply but are waiting
- for something. They may not have been removed yet. */
- silc_list_del(conn->internal->pending_commands, cmd);
-
- silc_client_command_free(cmd);
-}
-
-/* Add a command pending a command reply. Used internally by the library. */
-
-static SilcBool
-silc_client_command_add_pending(SilcClientConnection conn,
- SilcClientCommandContext cmd,
- SilcClientCommandReply reply,
- void *context)
-{
- SilcClientCommandReplyCallback cb;
-
- silc_mutex_lock(conn->internal->lock);
-
- /* Add pending callback, if defined */
- if (reply) {
- cb = silc_calloc(1, sizeof(*cb));
- if (!cb) {
- silc_mutex_unlock(conn->internal->lock);
- return FALSE;
- }
- cb->reply = reply;
- cb->context = context;
- silc_list_add(cmd->reply_callbacks, cb);
- }
-
- /* Add pending reply */
- silc_list_add(conn->internal->pending_commands, cmd);
-
- silc_mutex_unlock(conn->internal->lock);
-
- return TRUE;
-}
-
-/* Generic function to send any command. The arguments must be sent already
- encoded into correct format and in correct order. Arguments come from
- variable argument list pointer. */
-
-static SilcUInt16 silc_client_command_send_vap(SilcClient client,
- SilcClientConnection conn,
- SilcClientCommandContext cmd,
- SilcCommand command,
- SilcClientCommandReply reply,
- void *reply_context,
- SilcUInt32 argc, va_list ap)
-{
- SilcBuffer packet;
-
- SILC_LOG_DEBUG(("Send command %s", silc_get_command_name(command)));
-
- if (conn->internal->disconnected)
- return 0;
-
- if (!cmd->cmd_ident)
- cmd->cmd_ident = silc_client_cmd_ident(conn);
-
- /* Encode command payload */
- packet = silc_command_payload_encode_vap(command, cmd->cmd_ident, argc, ap);
- if (!packet)
- return 0;
-
- /* Send the command */
- if (!silc_packet_send(conn->stream, SILC_PACKET_COMMAND, 0,
- silc_buffer_datalen(packet))) {
- silc_buffer_free(packet);
- return 0;
- }
-
- /* Add the command pending command reply */
- silc_client_command_add_pending(conn, cmd, reply, reply_context);
-
- silc_buffer_free(packet);
-
- return cmd->cmd_ident;
-}
-
-/* Generic function to send any command. The arguments must be sent already
- encoded into correct format and in correct order. Arguments come from
- arrays. */
-
-static SilcUInt16
-silc_client_command_send_arg_array(SilcClient client,
- SilcClientConnection conn,
- SilcClientCommandContext cmd,
- SilcCommand command,
- SilcClientCommandReply reply,
- void *reply_context,
- SilcUInt32 argc,
- unsigned char **argv,
- SilcUInt32 *argv_lens,
- SilcUInt32 *argv_types)
-{
- SilcBuffer packet;
-
- SILC_LOG_DEBUG(("Send command %s", silc_get_command_name(command)));
-
- if (conn->internal->disconnected)
- return 0;
-
- if (!cmd->cmd_ident)
- cmd->cmd_ident = silc_client_cmd_ident(conn);
-
- /* Encode command payload */
- packet = silc_command_payload_encode(command, argc, argv, argv_lens,
- argv_types, cmd->cmd_ident);
- if (!packet)
- return 0;
-
- /* Send the command */
- if (!silc_packet_send(conn->stream, SILC_PACKET_COMMAND, 0,
- silc_buffer_datalen(packet))) {
- silc_buffer_free(packet);
- return 0;
- }
-
- /* Add the command pending command reply */
- silc_client_command_add_pending(conn, cmd, reply, reply_context);
-
- silc_buffer_free(packet);
-
- return cmd->cmd_ident;
-}
-
-/* Generic function to send any command. The arguments must be sent already
- encoded into correct format and in correct order. This is used internally
- by the library. */
-
-static SilcUInt16 silc_client_command_send_va(SilcClientConnection conn,
- SilcClientCommandContext cmd,
- SilcCommand command,
- SilcClientCommandReply reply,
- void *reply_context,
- SilcUInt32 argc, ...)
-{
- va_list ap;
- SilcUInt16 cmd_ident;
-
- va_start(ap, argc);
- cmd_ident = silc_client_command_send_vap(conn->client, conn, cmd, command,
- reply, reply_context, argc, ap);
- va_end(ap);
-
- return cmd_ident;
-}
-
-/****************************** Command API *********************************/
-
-/* Free command context and its internals */
-
-void silc_client_command_free(SilcClientCommandContext cmd)
-{
- SilcClientCommandReplyCallback cb;
- int i;
-
- for (i = 0; i < cmd->argc; i++)
- silc_free(cmd->argv[i]);
- silc_free(cmd->argv);
- silc_free(cmd->argv_lens);
- silc_free(cmd->argv_types);
-
- silc_list_start(cmd->reply_callbacks);
- while ((cb = silc_list_get(cmd->reply_callbacks)))
- silc_free(cb);
-
- silc_free(cmd);
-}
-
-/* Executes a command */
-
-SilcUInt16 silc_client_command_call(SilcClient client,
- SilcClientConnection conn,
- const char *command_line, ...)
-{
- va_list va;
- SilcUInt32 argc = 0;
- unsigned char **argv = NULL;
- SilcUInt32 *argv_lens = NULL, *argv_types = NULL;
- SilcClientCommand command;
- SilcClientCommandContext cmd;
- char *arg;
-
- if (!conn) {
- client->internal->ops->say(client, NULL, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
- "You are not connected to a server, please connect to server");
- return 0;
- }
-
- /* Parse arguments */
- va_start(va, command_line);
- if (command_line) {
- char *command_name;
-
- /* Get command name */
- command_name = silc_memdup(command_line, strcspn(command_line, " "));
- if (!command_name)
- return 0;
-
- /* Find command by name */
- command = silc_client_command_find(client, command_name);
- if (!command) {
- silc_free(command_name);
- return 0;
- }
-
- /* Parse command line */
- silc_parse_command_line((char *)command_line, &argv, &argv_lens,
- &argv_types, &argc, command->max_args);
-
- silc_free(command_name);
- } else {
- arg = va_arg(va, char *);
- if (!arg)
- return 0;
-
- /* Find command by name */
- command = silc_client_command_find(client, arg);
- if (!command)
- return 0;
-
- while (arg) {
- argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
- argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) * (argc + 1));
- argv_types = silc_realloc(argv_types, sizeof(*argv_types) * (argc + 1));
- if (!argv || !argv_lens || !argv_types)
- return 0;
- argv[argc] = silc_memdup(arg, strlen(arg));
- if (!argv[argc])
- return 0;
- argv_lens[argc] = strlen(arg);
- argv_types[argc] = argc;
- argc++;
- arg = va_arg(va, char *);
- }
- }
- va_end(va);
-
- /* Allocate command context */
- cmd = silc_calloc(1, sizeof(*cmd));
- if (!cmd)
- return 0;
- cmd->conn = conn;
- cmd->cmd = command->cmd;
- cmd->argc = argc;
- cmd->argv = argv;
- cmd->argv_lens = argv_lens;
- cmd->argv_types = argv_types;
- cmd->cmd_ident = silc_client_cmd_ident(conn);
- cmd->called = TRUE;
- cmd->verbose = TRUE;
- silc_list_init(cmd->reply_callbacks,
- struct SilcClientCommandReplyCallbackStruct, next);
-
- /*** Call command */
- SILC_LOG_DEBUG(("Calling %s command", silc_get_command_name(cmd->cmd)));
- silc_fsm_thread_init(&cmd->thread, &conn->internal->fsm, cmd,
- silc_client_command_destructor, NULL, FALSE);
- silc_fsm_start_sync(&cmd->thread, command->command);
-
- return cmd->cmd_ident;
-}
-
-/* Generic function to send any command. The arguments must be sent already
- encoded into correct format and in correct order. */
-
-SilcUInt16 silc_client_command_send(SilcClient client,
- SilcClientConnection conn,
- SilcCommand command,
- SilcClientCommandReply reply,
- void *reply_context,
- SilcUInt32 argc, ...)
-{
- SilcClientCommandContext cmd;
- va_list ap;
-
- if (!conn || !reply)
- return 0;
-
- /* Allocate command context */
- cmd = silc_calloc(1, sizeof(*cmd));
- if (!cmd)
- return 0;
- cmd->conn = conn;
- cmd->cmd = command;
- silc_list_init(cmd->reply_callbacks,
- struct SilcClientCommandReplyCallbackStruct, next);
-
- /* Send the command */
- va_start(ap, argc);
- cmd->cmd_ident =
- silc_client_command_send_vap(client, conn, cmd, command, reply,
- reply_context, argc, ap);
- va_end(ap);
-
- if (!cmd->cmd_ident) {
- silc_client_command_free(cmd);
- return 0;
- }
-
- /*** Wait for command reply */
- silc_fsm_thread_init(&cmd->thread, &conn->internal->fsm, cmd,
- silc_client_command_destructor, NULL, FALSE);
- silc_fsm_start_sync(&cmd->thread, silc_client_command_reply_wait);
-
- return cmd->cmd_ident;
-}
-
-/* Generic function to send any command. The arguments must be sent already
- encoded into correct format and in correct order. Arguments come from
- arrays. */
-
-SilcUInt16 silc_client_command_send_argv(SilcClient client,
- SilcClientConnection conn,
- SilcCommand command,
- SilcClientCommandReply reply,
- void *reply_context,
- SilcUInt32 argc,
- unsigned char **argv,
- SilcUInt32 *argv_lens,
- SilcUInt32 *argv_types)
-{
- SilcClientCommandContext cmd;
-
- if (!conn || !reply)
- return 0;
-
- /* Allocate command context */
- cmd = silc_calloc(1, sizeof(*cmd));
- if (!cmd)
- return 0;
- cmd->conn = conn;
- cmd->cmd = command;
-
- /* Send the command */
- cmd->cmd_ident =
- silc_client_command_send_arg_array(client, conn, cmd, command, reply,
- reply_context, argc, argv, argv_lens,
- argv_types);
- if (!cmd->cmd_ident) {
- silc_client_command_free(cmd);
- return 0;
- }
-
- /*** Wait for command reply */
- silc_fsm_thread_init(&cmd->thread, &conn->internal->fsm, cmd,
- silc_client_command_destructor, NULL, FALSE);
- silc_fsm_start_sync(&cmd->thread, silc_client_command_reply_wait);
-
- return cmd->cmd_ident;
-}
-
-/* Attach to a command and command identifier to receive command reply. */
-
-SilcBool silc_client_command_pending(SilcClientConnection conn,
- SilcCommand command,
- SilcUInt16 ident,
- SilcClientCommandReply reply,
- void *context)
-{
- SilcClientCommandContext cmd;
- SilcClientCommandReplyCallback cb;
-
- if (!conn || !reply)
- return FALSE;
-
- SILC_LOG_DEBUG(("Add pending command reply for ident %d", ident));
-
- silc_mutex_lock(conn->internal->lock);
-
- /* Find the pending command */
- silc_list_start(conn->internal->pending_commands);
- while ((cmd = silc_list_get(conn->internal->pending_commands)))
- if ((cmd->cmd == command || command == SILC_COMMAND_NONE)
- && cmd->cmd_ident == ident) {
-
- /* Add the callback */
- cb = silc_calloc(1, sizeof(*cb));
- if (!cb)
- continue;
- cb->reply = reply;
- cb->context = context;
- silc_list_add(cmd->reply_callbacks, cb);
- }
-
- silc_mutex_unlock(conn->internal->lock);
-
- return TRUE;
-}
-
-/******************************** WHOIS *************************************/
-
-/* Command WHOIS. This command is used to query information about
- specific user. */
-
-SILC_FSM_STATE(silc_client_command_whois)
-{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcBuffer attrs = NULL;
- unsigned char count[4], *tmp = NULL;
- SilcBool details = FALSE, nick = FALSE;
- unsigned char *pubkey = NULL;
- char *nickname = NULL;
- int i;
-
- /* Given without arguments fetches client's own information */
- if (cmd->argc < 2) {
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1, 4,
- silc_buffer_data(conn->internal->local_idp),
- silc_buffer_len(conn->internal->local_idp));
-
- /* Notify application */
- COMMAND(SILC_STATUS_OK);
-
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
- }
-
- for (i = 1; i < cmd->argc; i++) {
- if (!strcasecmp(cmd->argv[i], "-details")) {
- details = TRUE;
- } else if (!strcasecmp(cmd->argv[i], "-pubkey") && cmd->argc > i + 1) {
- pubkey = cmd->argv[i + 1];
- i++;
- } else {
- /* We assume that the first parameter is the nickname, if it isn't
- -details or -pubkey. The last parameter should always be the count */
- if (i == 1) {
- nick = TRUE;
- } else if (i == cmd->argc - 1) {
- int c = atoi(cmd->argv[i]);
- SILC_PUT32_MSB(c, count);
- tmp = count;
- }
- }
- }
-
- if (details) {
- /* If pubkey is set, add all attributes to the attrs buffer, except
- public key */
- if (pubkey) {
- attrs = silc_client_attributes_request(SILC_ATTRIBUTE_USER_INFO,
- SILC_ATTRIBUTE_SERVICE,
- SILC_ATTRIBUTE_STATUS_MOOD,
- SILC_ATTRIBUTE_STATUS_FREETEXT,
- SILC_ATTRIBUTE_STATUS_MESSAGE,
- SILC_ATTRIBUTE_PREFERRED_LANGUAGE,
- SILC_ATTRIBUTE_PREFERRED_CONTACT,
- SILC_ATTRIBUTE_TIMEZONE,
- SILC_ATTRIBUTE_GEOLOCATION,
- SILC_ATTRIBUTE_DEVICE_INFO,
- SILC_ATTRIBUTE_USER_ICON, 0);
- } else {
- attrs = silc_client_attributes_request(0);
- }
- }
-
- if (pubkey) {
- SilcAttributeObjPk obj;
- SilcPublicKey pk;
-
- if (!silc_pkcs_load_public_key(pubkey, SILC_PKCS_ANY, &pk)) {
- SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
- "Could not load public key %s, check the filename",
- pubkey);
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
-
- switch (silc_pkcs_get_type(pk)) {
- case SILC_PKCS_SILC:
- obj.type = "silc-rsa";
- break;
- case SILC_PKCS_SSH2:
- obj.type = "ssh-rsa";
- break;
- case SILC_PKCS_X509V3:
- obj.type = "x509v3-sign-rsa";
- break;
- case SILC_PKCS_OPENPGP:
- obj.type = "pgp-sign-rsa";
- break;
- default:
- goto out;
- break;
- }
- obj.data = silc_pkcs_public_key_encode(NULL, pk, &obj.data_len);
-
- attrs = silc_attribute_payload_encode(attrs,
- SILC_ATTRIBUTE_USER_PUBLIC_KEY,
- SILC_ATTRIBUTE_FLAG_VALID,
- &obj, sizeof(obj));
- silc_free(obj.data);
- }
-
- if (nick) {
- if (!silc_client_nickname_parse(client, conn, cmd->argv[1], &nickname))
- goto out;
- }
-
- /* Send command */
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
- 3, 1, nick ? nickname : NULL,
- nick ? strlen(nickname) : 0,
- 2, tmp ? tmp : NULL, tmp ? 4 : 0,
- 3, silc_buffer_datalen(attrs));
- silc_free(nickname);
-
- /* Notify application */
- COMMAND(SILC_STATUS_OK);
-
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
-
- out:
- return SILC_FSM_FINISH;
-}
-
-/******************************** WHOWAS ************************************/
-
-/* Command WHOWAS. This command is used to query history information about
- specific user that used to exist in the network. */
-
-SILC_FSM_STATE(silc_client_command_whowas)
-{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- unsigned char count[4];
- int c;
-
- if (cmd->argc < 2 || cmd->argc > 3) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
- COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
- SILC_STATUS_ERR_TOO_MANY_PARAMS));
- return SILC_FSM_FINISH;
- }
-
- if (cmd->argc == 2) {
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
- 1, 1, cmd->argv[1], cmd->argv_lens[1]);
- } else {
- c = atoi(cmd->argv[2]);
- SILC_PUT32_MSB(c, count);
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
- 2, 1, cmd->argv[1], cmd->argv_lens[1],
- 2, count, sizeof(count));
- }
-
- /* Notify application */
- COMMAND(SILC_STATUS_OK);
-
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
-}
-
-/******************************** IDENTIFY **********************************/
-
-/* Command IDENTIFY. This command is used to query information about
- specific user, especially ID's. */
-
-SILC_FSM_STATE(silc_client_command_identify)
-{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- unsigned char count[4];
- int c;
-
- if (cmd->argc < 2 || cmd->argc > 3)
- return SILC_FSM_FINISH;
-
- if (cmd->argc == 2) {
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
- 1, 1, cmd->argv[1], cmd->argv_lens[1]);
- } else {
- c = atoi(cmd->argv[2]);
- SILC_PUT32_MSB(c, count);
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
- 2, 1, cmd->argv[1], cmd->argv_lens[1],
- 4, count, sizeof(count));
- }
-
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
-}
-
-/********************************** NICK ************************************/
-
-/* Command NICK. Shows current nickname/sets new nickname on current
- window. */
-
-SILC_FSM_STATE(silc_client_command_nick)
-{
- SilcClientCommandContext cmd2, cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
-
- if (cmd->argc < 2) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "Usage: /NICK <nickname>");
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
-
- if (silc_utf8_strcasecmp(conn->local_entry->nickname, cmd->argv[1]))
- goto out;
-
- /* Show current nickname */
- if (cmd->argc < 2) {
- if (cmd->conn) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "Your nickname is %s on server %s",
- conn->local_entry->nickname, conn->remote_host);
- } else {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "Your nickname is %s", conn->local_entry->nickname);
- }
-
- COMMAND(SILC_STATUS_OK);
- goto out;
- }
-
- /* If JOIN command is active, wait for it to finish before sending NICK.
- To avoid problems locally with changing IDs while joining, we do this. */
- silc_mutex_lock(conn->internal->lock);
- silc_list_start(conn->internal->pending_commands);
- while ((cmd2 = silc_list_get(conn->internal->pending_commands))) {
- if (cmd2->cmd == SILC_COMMAND_JOIN) {
- silc_mutex_unlock(conn->internal->lock);
- silc_fsm_next_later(fsm, silc_client_command_nick, 0, 300000);
- return SILC_FSM_WAIT;
- }
- }
- silc_mutex_unlock(conn->internal->lock);
-
- if (cmd->argv_lens[1] > 128)
- cmd->argv_lens[1] = 128;
-
- /* Send the NICK command */
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
- 1, 1, cmd->argv[1], cmd->argv_lens[1]);
-
- /* Notify application */
- COMMAND(SILC_STATUS_OK);
-
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
-
- out:
- return SILC_FSM_FINISH;
-}
-
-/********************************** LIST ************************************/
-
-/* Command LIST. Lists channels on the current server. */
-
-SILC_FSM_STATE(silc_client_command_list)
-{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcChannelEntry channel = NULL;
- SilcBuffer idp = NULL;
-
- if (cmd->argc == 2) {
- /* Get the Channel ID of the channel */
- channel = silc_client_get_channel(conn->client, cmd->conn, cmd->argv[1]);
- if (channel)
- idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
- }
-
- if (!idp)
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
- else
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
- 1, 1, silc_buffer_datalen(idp));
-
- silc_buffer_free(idp);
- silc_client_unref_channel(client, conn, channel);
-
- /* Notify application */
- COMMAND(SILC_STATUS_OK);
-
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
-}
-
-/********************************** TOPIC ***********************************/
-
-/* Command TOPIC. Sets/shows topic on a channel. */
-
-SILC_FSM_STATE(silc_client_command_topic)
-{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcChannelEntry channel;
- SilcBuffer idp;
- char *name, tmp[512];
-
- if (cmd->argc < 2 || cmd->argc > 3) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "Usage: /TOPIC <channel> [<topic>]");
- COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
- SILC_STATUS_ERR_TOO_MANY_PARAMS));
- goto out;
- }
-
- if (cmd->argv[1][0] == '*') {
- if (!conn->current_channel) {
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
- goto out;
- }
-
- if (client->internal->params->full_channel_names)
- silc_snprintf(tmp, sizeof(tmp), conn->current_channel->channel_name);
- else
- silc_snprintf(tmp, sizeof(tmp), "%s%s%s",
- conn->current_channel->channel_name,
- conn->current_channel->server[0] ? "@" : "",
- conn->current_channel->server);
- name = tmp;
- } else {
- name = cmd->argv[1];
- }
-
- if (!conn->current_channel) {
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
- goto out;
- }
-
- /* Get the Channel ID of the channel */
- channel = silc_client_get_channel(conn->client, conn, name);
- if (!channel) {
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
- goto out;
- }
-
- idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
-
- /* Send TOPIC command to the server */
- if (cmd->argc > 2)
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
- 1, silc_buffer_datalen(idp),
- 2, cmd->argv[2], strlen(cmd->argv[2]));
- else
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
- 1, silc_buffer_datalen(idp));
-
- silc_buffer_free(idp);
- silc_client_unref_channel(client, conn, channel);
-
- /* Notify application */
- COMMAND(SILC_STATUS_OK);
-
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
-
- out:
- return SILC_FSM_FINISH;
-}
-
-/********************************* INVITE ***********************************/
-
-/* Command INVITE. Invites specific client to join a channel. This is
- also used to mange the invite list of the channel. */
-
-SILC_FSM_STATE(silc_client_command_invite)
-{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcClientEntry client_entry = NULL;
- SilcChannelEntry channel = NULL;
- SilcBuffer clidp, chidp, args = NULL;
- SilcPublicKey pubkey = NULL;
- SilcDList clients = NULL;
- char *nickname = NULL, *name;
- char *invite = NULL;
- unsigned char action[1];
-
- if (cmd->argc < 2) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "Usage: /INVITE <channel> [<nickname>[@server>]"
- "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
-
- if (cmd->argv[1][0] == '*') {
- if (!conn->current_channel) {
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
- goto out;
- }
-
- channel = conn->current_channel;
- silc_client_ref_channel(client, conn, channel);
- } else {
- name = cmd->argv[1];
-
- channel = silc_client_get_channel(conn->client, conn, name);
- if (!channel) {
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
- goto out;
- }
- }
-
- /* Parse the typed nickname. */
- if (cmd->argc == 3) {
- if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
- if (!silc_client_nickname_parse(client, conn, cmd->argv[2], &nickname)) {
- silc_client_unref_channel(client, conn, channel);
- goto out;
- }
-
- /* Find client entry */
- clients = silc_client_get_clients_local(client, conn, cmd->argv[2],
- FALSE);
- if (!clients)
- /* Resolve client information */
- SILC_FSM_CALL(silc_client_get_clients(
- client, conn, nickname, NULL,
- silc_client_command_resolve_continue,
- cmd));
-
- client_entry = silc_dlist_get(clients);
- } else {
- if (cmd->argv[2][0] == '+')
- action[0] = 0x00;
- else
- action[0] = 0x01;
-
- /* Check if it is public key file to be added to invite list */
- silc_pkcs_load_public_key(cmd->argv[2] + 1, SILC_PKCS_ANY, &pubkey);
- invite = cmd->argv[2];
- if (!pubkey)
- invite++;
- }
- }
-
- if (invite) {
- args = silc_buffer_alloc_size(2);
- silc_buffer_format(args,
- SILC_STR_UI_SHORT(1),
- SILC_STR_END);
- if (pubkey) {
- chidp = silc_public_key_payload_encode(NULL, pubkey);
- args = silc_argument_payload_encode_one(args, silc_buffer_data(chidp),
- silc_buffer_len(chidp), 2);
- silc_buffer_free(chidp);
- silc_pkcs_public_key_free(pubkey);
- } else {
- args = silc_argument_payload_encode_one(args, invite, strlen(invite), 1);
- }
- }
-
- /* Send the command */
- chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
- if (client_entry) {
- clidp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT);
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 4,
- 1, silc_buffer_datalen(chidp),
- 2, silc_buffer_datalen(clidp),
- 3, args ? action : NULL, args ? 1 : 0,
- 4, silc_buffer_datalen(args));
- silc_buffer_free(clidp);
- } else {
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
- 1, silc_buffer_datalen(chidp),
- 3, args ? action : NULL, args ? 1 : 0,
- 4, silc_buffer_datalen(args));
- }
-
- silc_buffer_free(chidp);
- silc_buffer_free(args);
- silc_free(nickname);
- silc_client_list_free(client, conn, clients);
- silc_client_unref_channel(client, conn, channel);
-
- /* Notify application */
- COMMAND(SILC_STATUS_OK);
-
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
-
- out:
- silc_free(nickname);
- return SILC_FSM_FINISH;
-}
-
-/********************************** QUIT ************************************/
-
-/* Close the connection */
-
-SILC_FSM_STATE(silc_client_command_quit_final)
-{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
-
- SILC_LOG_DEBUG(("Quitting"));
-
- /* Notify application */
- COMMAND(SILC_STATUS_OK);
-
- /* Signal to close connection */
- conn->internal->status = SILC_CLIENT_CONN_DISCONNECTED;
- if (!conn->internal->disconnected) {
- conn->internal->disconnected = TRUE;
- SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event);
- }
-
- return SILC_FSM_FINISH;
-}
-
-/* Command QUIT. Closes connection with current server. */
-
-SILC_FSM_STATE(silc_client_command_quit)
-{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
-
- if (cmd->argc > 1)
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
- 1, cmd->argv[1], cmd->argv_lens[1]);
- else
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
-
- /* Sleep for a while */
- sleep(1);
-
- /* We close the connection with a little timeout */
- silc_fsm_next_later(fsm, silc_client_command_quit_final, 2, 0);
- return SILC_FSM_WAIT;
-}
-
-/********************************** KILL ************************************/
-
-/* Signature callback */
-
-static void silc_client_command_kill_signed(const SilcBuffer buffer,
- void *context)
-{
- SilcClientCommandContext cmd = context;
-
- if (!buffer) {
- silc_fsm_finish(&cmd->thread);
- return;
- }
-
- silc_fsm_set_state_context(&cmd->thread, buffer);
- SILC_FSM_CALL_CONTINUE_SYNC(&cmd->thread);
-}
-
-/* Send KILL command */
-
-SILC_FSM_STATE(silc_client_command_kill_send)
-{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcBuffer idp, auth = state_context;
- SilcClientEntry target = cmd->context;
- char *comment = NULL;
-
- if (cmd->argc >= 3)
- if (strcasecmp(cmd->argv[2], "-pubkey"))
- comment = cmd->argv[2];
-
- /* Send the KILL command to the server */
- idp = silc_id_payload_encode(&target->id, SILC_ID_CLIENT);
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
- 1, silc_buffer_datalen(idp),
- 2, comment, comment ? strlen(comment) : 0,
- 3, silc_buffer_datalen(auth));
-
- silc_buffer_free(idp);
- silc_client_unref_client(client, conn, target);
-
- /* Notify application */
- COMMAND(SILC_STATUS_OK);
-
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
-}
-
-/* Command KILL. Router operator can use this command to remove an client
- fromthe SILC Network. */
-
-SILC_FSM_STATE(silc_client_command_kill)
-{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcClientEntry target;
- SilcDList clients;
- char *nickname = NULL;
-
- if (cmd->argc < 2) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "Usage: /KILL <nickname> [<comment>] [-pubkey]");
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- return SILC_FSM_FINISH;
- }
-
- /* Parse the typed nickname. */
- if (!silc_client_nickname_parse(client, conn, cmd->argv[1], &nickname))
- return SILC_FSM_FINISH;
-
- /* Get the target client */
- clients = silc_client_get_clients_local(client, conn, cmd->argv[1], FALSE);
- if (!clients)
- /* Resolve client information */
- SILC_FSM_CALL(silc_client_get_clients(client, conn, nickname, NULL,
- silc_client_command_resolve_continue,
- cmd));
-
- target = silc_dlist_get(clients);
- cmd->context = silc_client_ref_client(client, conn, target);
-
- silc_free(nickname);
- silc_client_list_free(client, conn, clients);
-
- /** Send KILL */
- silc_fsm_next(fsm, silc_client_command_kill_send);
-
- if (cmd->argc >= 3) {
- if (!strcasecmp(cmd->argv[2], "-pubkey") ||
- (cmd->argc >= 4 && !strcasecmp(cmd->argv[3], "-pubkey"))) {
- /* Encode the public key authentication payload */
- SILC_FSM_CALL(silc_auth_public_key_auth_generate(
- conn->public_key,
- conn->private_key,
- conn->client->rng,
- conn->internal->sha1hash,
- &target->id, SILC_ID_CLIENT,
- silc_client_command_kill_signed,
- cmd));
- /* NOT REACHED */
- }
- }
-
- return SILC_FSM_CONTINUE;
-}
-
-/********************************** INFO ************************************/
-
-/* Command INFO. Request information about specific server. If specific
- server is not provided the current server is used. */
-
-SILC_FSM_STATE(silc_client_command_info)
-{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
-
- /* Send the command */
- if (cmd->argc == 2)
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
- 1, cmd->argv[1], cmd->argv_lens[1]);
- else
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
-
- /* Notify application */
- COMMAND(SILC_STATUS_OK);
-
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
-}
-
-/********************************** STATS ***********************************/
-
-/* Command STATS. Shows server and network statistics. */
-
-SILC_FSM_STATE(silc_client_command_stats)
-{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
-
- /* Send the command */
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
- 1, silc_buffer_datalen(conn->internal->
- remote_idp));
-
- /* Notify application */
- COMMAND(SILC_STATUS_OK);
-
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
-}
-
-/********************************** PING ************************************/
-
-/* Command PING. Sends ping to server. */
-
-SILC_FSM_STATE(silc_client_command_ping)
-{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
-
- if (cmd->argc < 2) {
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- return SILC_FSM_FINISH;
- }
-
- /* Send the command */
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
- 1, silc_buffer_datalen(conn->internal->
- remote_idp));
-
- /* Save ping time */
- cmd->context = SILC_64_TO_PTR(silc_time());
-
- /* Notify application */
- COMMAND(SILC_STATUS_OK);
-
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
-}
-
-/********************************** JOIN ************************************/
-
-typedef struct {
- int type;
- SilcBuffer auth;
- SilcBuffer cauth;
-} *SilcClientJoinContext;
-
-/* Signature callback */
-
-static void silc_client_command_join_signed(const SilcBuffer buffer,
- void *context)
-{
- SilcClientCommandContext cmd = context;
- SilcClientJoinContext j = cmd->context;
-
- if (!buffer) {
- silc_fsm_finish(&cmd->thread);
- return;
- }
-
- if (!j->type)
- j->auth = silc_buffer_copy(buffer);
- else
- j->cauth = silc_buffer_copy(buffer);
-
- SILC_FSM_CALL_CONTINUE(&cmd->thread);
-}
-
-/* Command JOIN. Joins to a channel. */
-
-SILC_FSM_STATE(silc_client_command_join)
-{
- SilcClientCommandContext cmd2, cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcChannelEntry channel = NULL;
- SilcClientJoinContext j = cmd->context;
- SilcBuffer auth = NULL, cauth = NULL;
- char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
- int i, passphrase_len = 0;
-
- if (cmd->argc < 2) {
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
-
- /* See if we have joined to the requested channel already */
- channel = silc_client_get_channel(conn->client, conn, cmd->argv[1]);
- if (channel && silc_client_on_channel(channel, conn->local_entry))
- goto out;
-
- /* If NICK command is active, wait for it to finish before sending JOIN.
- To avoid problems locally with changing IDs while joining, we do this. */
- silc_mutex_lock(conn->internal->lock);
- silc_list_start(conn->internal->pending_commands);
- while ((cmd2 = silc_list_get(conn->internal->pending_commands))) {
- if (cmd2->cmd == SILC_COMMAND_NICK) {
- silc_mutex_unlock(conn->internal->lock);
- silc_fsm_next_later(fsm, silc_client_command_join, 0, 300000);
- return SILC_FSM_WAIT;
- }
- }
- silc_mutex_unlock(conn->internal->lock);
-
- if (cmd->argv_lens[1] > 256)
- cmd->argv_lens[1] = 256;
-
- name = cmd->argv[1];
-
- for (i = 2; i < cmd->argc; i++) {
- if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
- cipher = cmd->argv[++i];
- } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
- hmac = cmd->argv[++i];
- } else if (!strcasecmp(cmd->argv[i], "-founder")) {
- if (!j || !j->auth) {
- if (!j) {
- j = silc_calloc(1, sizeof(*j));
- if (!j)
- goto out;
- cmd->context = j;
- }
- j->type = 0;
- silc_free(passphrase);
- silc_client_unref_channel(client, conn, channel);
- SILC_FSM_CALL(silc_auth_public_key_auth_generate(
- conn->public_key,
- conn->private_key,
- conn->client->rng,
- conn->internal->sha1hash,
- conn->local_id,
- SILC_ID_CLIENT,
- silc_client_command_join_signed,
- cmd));
- /* NOT REACHED */
- }
- } else if (!strcasecmp(cmd->argv[i], "-auth")) {
- SilcPublicKey pubkey = conn->public_key;
- SilcPrivateKey privkey = conn->private_key;
- unsigned char *pk, pkhash[SILC_HASH_MAXLEN], pubdata[128];
- SilcUInt32 pk_len;
-
- if (!j || !j->cauth) {
- if (!j) {
- j = silc_calloc(1, sizeof(*j));
- if (!j)
- goto out;
- cmd->context = j;
- }
-
- if (cmd->argc >= i + 3) {
- char *pass = "";
- if (cmd->argc >= i + 4) {
- pass = cmd->argv[i + 3];
- i++;
- }
- if (!silc_load_key_pair(cmd->argv[i + 1], cmd->argv[i + 2], pass,
- &pubkey, &privkey)) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
- "Could not load key pair, check your arguments");
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
- i += 2;
- }
-
- j->type = 1;
- pk = silc_pkcs_public_key_encode(NULL, pubkey, &pk_len);
- silc_hash_make(conn->internal->sha1hash, pk, pk_len, pkhash);
- silc_free(pk);
- silc_rng_get_rn_data(conn->client->rng, sizeof(pubdata), pubdata,
- sizeof(pubdata));
- memcpy(pubdata, pkhash, 20);
- silc_free(passphrase);
- silc_client_unref_channel(client, conn, channel);
- SILC_FSM_CALL(silc_auth_public_key_auth_generate_wpub(
- pubkey, privkey,
- pubdata, sizeof(pubdata),
- conn->internal->sha1hash,
- client->rng,
- conn->local_id,
- SILC_ID_CLIENT,
- silc_client_command_join_signed,
- cmd));
- /* NOT REACHED */
- }
- } else {
- /* Passphrases must be UTF-8 encoded, so encode if it is not */
- if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
- passphrase_len = silc_utf8_encoded_len(cmd->argv[i],
- cmd->argv_lens[i], 0);
- pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
- passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
- 0, pu8, passphrase_len);
- passphrase = pu8;
- } else {
- passphrase = strdup(cmd->argv[i]);
- passphrase_len = cmd->argv_lens[i];
- }
- }
- }
-
- /* Send JOIN command to the server */
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 7,
- 1, name, strlen(name),
- 2, silc_buffer_datalen(conn->internal->
- local_idp),
- 3, passphrase, passphrase_len,
- 4, cipher, cipher ? strlen(cipher) : 0,
- 5, hmac, hmac ? strlen(hmac) : 0,
- 6, silc_buffer_datalen(auth),
- 7, silc_buffer_datalen(cauth));
-
- if (passphrase)
- memset(passphrase, 0, strlen(passphrase));
- silc_free(passphrase);
- silc_client_unref_channel(client, conn, channel);
- if (j) {
- silc_buffer_free(j->auth);
- silc_buffer_free(j->cauth);
- silc_free(j);
- }
-
- /* Notify application */
- COMMAND(SILC_STATUS_OK);
-
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
-
- out:
- silc_client_unref_channel(client, conn, channel);
- return SILC_FSM_FINISH;
-}
-
-/********************************** MOTD ************************************/
-
-/* MOTD command. Requests motd from server. */
-
-SILC_FSM_STATE(silc_client_command_motd)
-{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
-
- if (cmd->argc < 1 || cmd->argc > 2) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "Usage: /MOTD [<server>]");
- COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
- SILC_STATUS_ERR_TOO_MANY_PARAMS));
- return SILC_FSM_FINISH;
- }
-
- /* Send the command */
- if (cmd->argc == 1)
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
- 1, conn->remote_host,
- strlen(conn->remote_host));
- else
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
- 1, cmd->argv[1], cmd->argv_lens[1]);
-
- /* Notify application */
- COMMAND(SILC_STATUS_OK);
-
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
-}
-
-/********************************** UMODE ***********************************/
-
-/* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
- modes as client cannot set itself server/router operator privileges. */
-
-SILC_FSM_STATE(silc_client_command_umode)
-{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- unsigned char *cp, modebuf[4];
- SilcUInt32 mode, add, len;
- int i;
-
- if (cmd->argc < 2) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "Usage: /UMODE +|-<modes>");
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- return SILC_FSM_FINISH;
- }
-
- mode = conn->local_entry->mode;
-
- /* Are we adding or removing mode */
- if (cmd->argv[1][0] == '-')
- add = FALSE;
- else
- add = TRUE;
-
- /* Parse mode */
- cp = cmd->argv[1] + 1;
- len = strlen(cp);
- for (i = 0; i < len; i++) {
- switch(cp[i]) {
- case 'a':
- if (add) {
- mode = 0;
- mode |= SILC_UMODE_SERVER_OPERATOR;
- mode |= SILC_UMODE_ROUTER_OPERATOR;
- mode |= SILC_UMODE_GONE;
- mode |= SILC_UMODE_INDISPOSED;
- mode |= SILC_UMODE_BUSY;
- mode |= SILC_UMODE_PAGE;
- mode |= SILC_UMODE_HYPER;
- mode |= SILC_UMODE_ROBOT;
- mode |= SILC_UMODE_BLOCK_PRIVMSG;
- mode |= SILC_UMODE_REJECT_WATCHING;
- } else {
- mode = SILC_UMODE_NONE;
- }
- break;
- case 's':
- if (add)
- mode |= SILC_UMODE_SERVER_OPERATOR;
- else
- mode &= ~SILC_UMODE_SERVER_OPERATOR;
- break;
- case 'r':
- if (add)
- mode |= SILC_UMODE_ROUTER_OPERATOR;
- else
- mode &= ~SILC_UMODE_ROUTER_OPERATOR;
- break;
- case 'g':
- if (add)
- mode |= SILC_UMODE_GONE;
- else
- mode &= ~SILC_UMODE_GONE;
- break;
- case 'i':
- if (add)
- mode |= SILC_UMODE_INDISPOSED;
- else
- mode &= ~SILC_UMODE_INDISPOSED;
- break;
- case 'b':
- if (add)
- mode |= SILC_UMODE_BUSY;
- else
- mode &= ~SILC_UMODE_BUSY;
- break;
- case 'p':
- if (add)
- mode |= SILC_UMODE_PAGE;
- else
- mode &= ~SILC_UMODE_PAGE;
- break;
- case 'h':
- if (add)
- mode |= SILC_UMODE_HYPER;
- else
- mode &= ~SILC_UMODE_HYPER;
- break;
- case 't':
- if (add)
- mode |= SILC_UMODE_ROBOT;
- else
- mode &= ~SILC_UMODE_ROBOT;
- break;
- case 'P':
- if (add)
- mode |= SILC_UMODE_BLOCK_PRIVMSG;
- else
- mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
- break;
- case 'w':
- if (add)
- mode |= SILC_UMODE_REJECT_WATCHING;
- else
- mode &= ~SILC_UMODE_REJECT_WATCHING;
- break;
- case 'I':
- if (add)
- mode |= SILC_UMODE_BLOCK_INVITE;
- else
- mode &= ~SILC_UMODE_BLOCK_INVITE;
- break;
- default:
- COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
- return SILC_FSM_FINISH;
- break;
- }
- }
-
- SILC_PUT32_MSB(mode, modebuf);
-
- /* Send the command */
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
- 1, silc_buffer_datalen(conn->internal->
- local_idp),
- 2, modebuf, sizeof(modebuf));
-
- /* Notify application */
- COMMAND(SILC_STATUS_OK);
-
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
-}
-
-/********************************** CMODE ***********************************/
-
-/* Signature callback */
-
-static void silc_client_command_cmode_signed(const SilcBuffer buffer,
- void *context)
-{
- SilcClientCommandContext cmd = context;
-
- if (!buffer) {
- silc_fsm_finish(&cmd->thread);
- return;
- }
-
- silc_fsm_set_state_context(&cmd->thread, buffer);
- SILC_FSM_CALL_CONTINUE_SYNC(&cmd->thread);
-}
-
-/* CMODE command. Sets channel mode. Modes that does not require any arguments
- can be set several at once. Those modes that require argument must be set
- separately (unless set with modes that does not require arguments). */
-
-SILC_FSM_STATE(silc_client_command_cmode)
-{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcBuffer auth = state_context;
- SilcChannelEntry channel = NULL;
- SilcBuffer chidp, pk = NULL;
- unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
- SilcUInt32 mode, add, type, len, arg_len = 0;
- int i;
-
- if (cmd->argc < 3) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
-
- if (cmd->argv[1][0] == '*') {
- if (!conn->current_channel) {
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
- goto out;
- }
-
- channel = conn->current_channel;
- silc_client_ref_channel(client, conn, channel);
- } else {
- name = cmd->argv[1];
-
- channel = silc_client_get_channel(conn->client, conn, name);
- if (!channel) {
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
- goto out;
- }
- }
-
- mode = channel->mode;
-
- /* Are we adding or removing mode */
- if (cmd->argv[2][0] == '-')
- add = FALSE;
- else
- add = TRUE;
-
- /* Argument type to be sent to server */
- type = 0;
-
- /* Parse mode */
- cp = cmd->argv[2] + 1;
- len = strlen(cp);
- for (i = 0; i < len; i++) {
- switch(cp[i]) {
- case 'p':
- if (add)
- mode |= SILC_CHANNEL_MODE_PRIVATE;
- else
- mode &= ~SILC_CHANNEL_MODE_PRIVATE;
- break;
- case 's':
- if (add)
- mode |= SILC_CHANNEL_MODE_SECRET;
- else
- mode &= ~SILC_CHANNEL_MODE_SECRET;
- break;
- case 'k':
- if (add)
- mode |= SILC_CHANNEL_MODE_PRIVKEY;
- else
- mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
- break;
- case 'i':
- if (add)
- mode |= SILC_CHANNEL_MODE_INVITE;
- else
- mode &= ~SILC_CHANNEL_MODE_INVITE;
- break;
- case 't':
- if (add)
- mode |= SILC_CHANNEL_MODE_TOPIC;
- else
- mode &= ~SILC_CHANNEL_MODE_TOPIC;
- break;
- case 'm':
- if (add)
- mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
- else
- mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
- break;
- case 'M':
- if (add)
- mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
- else
- mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
- break;
- case 'l':
- if (add) {
- int ll;
- mode |= SILC_CHANNEL_MODE_ULIMIT;
- type = 3;
- if (cmd->argc < 4) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
- ll = atoi(cmd->argv[3]);
- SILC_PUT32_MSB(ll, tmp);
- arg = tmp;
- arg_len = 4;
- } else {
- mode &= ~SILC_CHANNEL_MODE_ULIMIT;
- }
- break;
- case 'a':
- if (add) {
- mode |= SILC_CHANNEL_MODE_PASSPHRASE;
- type = 4;
- if (cmd->argc < 4) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
- arg = cmd->argv[3];
- arg_len = cmd->argv_lens[3];
- } else {
- mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
- }
- break;
- case 'c':
- if (add) {
- mode |= SILC_CHANNEL_MODE_CIPHER;
- type = 5;
- if (cmd->argc < 4) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
- arg = cmd->argv[3];
- arg_len = cmd->argv_lens[3];
- } else {
- mode &= ~SILC_CHANNEL_MODE_CIPHER;
- }
- break;
- case 'h':
- if (add) {
- mode |= SILC_CHANNEL_MODE_HMAC;
- type = 6;
- if (cmd->argc < 4) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
- arg = cmd->argv[3];
- arg_len = cmd->argv_lens[3];
- } else {
- mode &= ~SILC_CHANNEL_MODE_HMAC;
- }
- break;
- case 'f':
- if (add) {
- if (!auth) {
- SilcPublicKey pubkey = conn->public_key;
- SilcPrivateKey privkey = conn->private_key;
-
- mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
- type = 7;
-
- if (cmd->argc >= 5) {
- char *pass = "";
- if (cmd->argc >= 6)
- pass = cmd->argv[5];
- if (!silc_load_key_pair(cmd->argv[3], cmd->argv[4], pass,
- &pubkey, &privkey)) {
- SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
- "Could not load key pair, check your arguments");
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
- }
-
- pk = silc_public_key_payload_encode(NULL, pubkey);
- silc_client_unref_channel(client, conn, channel);
- SILC_FSM_CALL(silc_auth_public_key_auth_generate(
- pubkey, privkey,
- conn->client->rng,
- conn->internal->sha1hash,
- conn->local_id,
- SILC_ID_CLIENT,
- silc_client_command_cmode_signed,
- cmd));
- /* NOT REACHED */
- }
- arg = silc_buffer_data(auth);
- arg_len = silc_buffer_len(auth);
- } else {
- mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
- }
- break;
- case 'C':
- if (add) {
- int k;
- SilcBool chadd = FALSE;
- SilcPublicKey chpk = NULL;
-
- mode |= SILC_CHANNEL_MODE_CHANNEL_AUTH;
- type = 9;
-
- if (cmd->argc == 3) {
- /* Send empty command to receive the public key list. */
- chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
- silc_client_command_send_va(conn, cmd, SILC_COMMAND_CMODE,
- NULL, NULL, 1,
- 1, silc_buffer_datalen(chidp));
- silc_buffer_free(chidp);
- silc_client_unref_channel(client, conn, channel);
-
- /* Notify application */
- COMMAND(SILC_STATUS_OK);
-
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
- }
-
- if (cmd->argc >= 4) {
- auth = silc_buffer_alloc_size(2);
- silc_buffer_format(auth,
- SILC_STR_UI_SHORT(cmd->argc - 3),
- SILC_STR_END);
- }
-
- for (k = 3; k < cmd->argc; k++) {
- if (cmd->argv[k][0] == '+')
- chadd = TRUE;
- if (!silc_pkcs_load_public_key(cmd->argv[k] + 1, SILC_PKCS_ANY,
- &chpk)) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
- "Could not load public key %s, check the filename",
- cmd->argv[k]);
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- silc_buffer_free(auth);
- goto out;
- }
-
- if (chpk) {
- pk = silc_public_key_payload_encode(NULL, chpk);
- auth = silc_argument_payload_encode_one(auth,
- silc_buffer_datalen(pk),
- chadd ? 0x00 : 0x01);
- silc_pkcs_public_key_free(chpk);
- silc_buffer_free(pk);
- pk = NULL;
- }
- }
-
- arg = silc_buffer_data(auth);
- arg_len = silc_buffer_len(auth);
- } else {
- mode &= ~SILC_CHANNEL_MODE_CHANNEL_AUTH;
- }
- break;
- default:
- COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
- goto out;
- break;
- }
- }
-
- chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
- SILC_PUT32_MSB(mode, modebuf);
-
- /* Send the command. We support sending only one mode at once that
- requires an argument. */
- if (type && arg) {
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 4,
- 1, silc_buffer_datalen(chidp),
- 2, modebuf, sizeof(modebuf),
- type, arg, arg_len,
- 8, silc_buffer_datalen(pk));
- } else {
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
- 1, silc_buffer_datalen(chidp),
- 2, modebuf, sizeof(modebuf));
- }
-
- silc_buffer_free(chidp);
- silc_buffer_free(auth);
- silc_buffer_free(pk);
- silc_client_unref_channel(client, conn, channel);
-
- /* Notify application */
- COMMAND(SILC_STATUS_OK);
-
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
-
- out:
- silc_client_unref_channel(client, conn, channel);
- return SILC_FSM_FINISH;
-}
-
-/********************************* CUMODE ***********************************/
-
-/* Signature callback */
-
-static void silc_client_command_cumode_signed(const SilcBuffer buffer,
- void *context)
-{
- SilcClientCommandContext cmd = context;
-
- if (!buffer) {
- silc_fsm_finish(&cmd->thread);
- return;
- }
-
- silc_fsm_set_state_context(&cmd->thread, buffer);
- SILC_FSM_CALL_CONTINUE_SYNC(&cmd->thread);
-}
-
-/* CUMODE command. Changes client's mode on a channel. */
-
-SILC_FSM_STATE(silc_client_command_cumode)
-{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcBuffer auth = state_context;
- SilcChannelEntry channel = NULL;
- SilcChannelUser chu;
- SilcClientEntry client_entry;
- SilcBuffer clidp, chidp;
- SilcDList clients = NULL;
- unsigned char *name, *cp, modebuf[4];
- SilcUInt32 mode = 0, add, len;
- char *nickname = NULL;
- int i;
-
- if (cmd->argc < 4) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
-
- if (cmd->argv[1][0] == '*') {
- if (!conn->current_channel) {
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
- goto out;
- }
-
- channel = conn->current_channel;
- silc_client_ref_channel(client, conn, channel);
- } else {
- name = cmd->argv[1];
-
- channel = silc_client_get_channel(conn->client, conn, name);
- if (!channel) {
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
- goto out;
- }
- }
-
- /* Parse the typed nickname. */
- if (!silc_client_nickname_parse(client, conn, cmd->argv[3], &nickname))
- goto out;
-
- /* Find client entry */
- clients = silc_client_get_clients_local(client, conn, cmd->argv[3], FALSE);
- if (!clients)
- /* Resolve client information */
- SILC_FSM_CALL(silc_client_get_clients(client, conn, nickname, NULL,
- silc_client_command_resolve_continue,
- cmd));
-
- client_entry = silc_dlist_get(clients);
-
- /* Get the current mode */
- chu = silc_client_on_channel(channel, client_entry);
- if (chu)
- mode = chu->mode;
-
- /* Are we adding or removing mode */
- if (cmd->argv[2][0] == '-')
- add = FALSE;
- else
- add = TRUE;
-
- /* Parse mode */
- cp = cmd->argv[2] + 1;
- len = strlen(cp);
- for (i = 0; i < len; i++) {
- switch(cp[i]) {
- case 'a':
- if (add) {
- mode |= SILC_CHANNEL_UMODE_CHANFO;
- mode |= SILC_CHANNEL_UMODE_CHANOP;
- mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
- mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
- mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
- } else {
- mode = SILC_CHANNEL_UMODE_NONE;
- }
- break;
- case 'f':
- if (add) {
- if (!auth) {
- SilcPublicKey pubkey = conn->public_key;
- SilcPrivateKey privkey = conn->private_key;
-
- if (cmd->argc >= 6) {
- char *pass = "";
- if (cmd->argc >= 7)
- pass = cmd->argv[6];
- if (!silc_load_key_pair(cmd->argv[4], cmd->argv[5], pass,
- &pubkey, &privkey)) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
- "Could not load key pair, check your arguments");
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
- }
-
- silc_free(nickname);
- silc_client_list_free(client, conn, clients);
- silc_client_unref_channel(client, conn, channel);
-
- SILC_FSM_CALL(silc_auth_public_key_auth_generate(
- pubkey, privkey,
- conn->client->rng,
- conn->internal->sha1hash,
- conn->local_id,
- SILC_ID_CLIENT,
- silc_client_command_cumode_signed,
- cmd));
- /* NOT REACHED */
- }
-
- mode |= SILC_CHANNEL_UMODE_CHANFO;
- } else {
- mode &= ~SILC_CHANNEL_UMODE_CHANFO;
- }
- break;
- case 'o':
- if (add)
- mode |= SILC_CHANNEL_UMODE_CHANOP;
- else
- mode &= ~SILC_CHANNEL_UMODE_CHANOP;
- break;
- case 'b':
- if (add)
- mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
- else
- mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
- break;
- case 'u':
- if (add)
- mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
- else
- mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
- break;
- case 'r':
- if (add)
- mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
- else
- mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
- break;
- case 'q':
- if (add)
- mode |= SILC_CHANNEL_UMODE_QUIET;
- else
- mode &= ~SILC_CHANNEL_UMODE_QUIET;
- break;
- default:
- COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
- goto out;
- break;
- }
- }
-
- chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
- SILC_PUT32_MSB(mode, modebuf);
- clidp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT);
-
- /* Send the command packet. We support sending only one mode at once
- that requires an argument. */
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, auth ? 4 : 3,
- 1, silc_buffer_datalen(chidp),
- 2, modebuf, 4,
- 3, silc_buffer_datalen(clidp),
- 4, silc_buffer_datalen(auth));
-
- silc_buffer_free(chidp);
- silc_buffer_free(clidp);
- if (auth)
- silc_buffer_free(auth);
- silc_free(nickname);
- silc_client_list_free(client, conn, clients);
- silc_client_unref_channel(client, conn, channel);
-
- /* Notify application */
- COMMAND(SILC_STATUS_OK);
-
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
-
- out:
- silc_client_unref_channel(client, conn, channel);
- silc_client_list_free(client, conn, clients);
- silc_free(nickname);
- return SILC_FSM_FINISH;
-}
-
-/********************************** KICK ************************************/
-
-/* KICK command. Kicks a client out of channel. */
-
-SILC_FSM_STATE(silc_client_command_kick)
-{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcChannelEntry channel = NULL;
- SilcBuffer idp, idp2;
- SilcClientEntry target;
- SilcDList clients = NULL;
- char *name, tmp[512];
-
- if (cmd->argc < 3) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "Usage: /KICK <channel> <nickname> [<comment>]");
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
-
- if (cmd->argv[1][0] == '*') {
- if (!conn->current_channel) {
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
- goto out;
- }
-
- if (client->internal->params->full_channel_names)
- silc_snprintf(tmp, sizeof(tmp), conn->current_channel->channel_name);
- else
- silc_snprintf(tmp, sizeof(tmp), "%s%s%s",
- conn->current_channel->channel_name,
- conn->current_channel->server[0] ? "@" : "",
- conn->current_channel->server);
- name = tmp;
- } else {
- name = cmd->argv[1];
- }
-
- if (!conn->current_channel) {
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
- goto out;
- }
-
- /* Get the Channel ID of the channel */
- channel = silc_client_get_channel(conn->client, conn, name);
- if (!channel) {
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
- goto out;
- }
-
- /* Get the target client */
- clients = silc_client_get_clients_local(client, conn, cmd->argv[2], FALSE);
- if (!clients) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "No such client: %s", cmd->argv[2]);
- COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
- goto out;
- }
- target = silc_dlist_get(clients);
-
- /* Send KICK command to the server */
- idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
- idp2 = silc_id_payload_encode(&target->id, SILC_ID_CLIENT);
- if (cmd->argc == 3)
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
- 1, silc_buffer_datalen(idp),
- 2, silc_buffer_datalen(idp2));
- else
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
- 1, silc_buffer_datalen(idp),
- 2, silc_buffer_datalen(idp2),
- 3, cmd->argv[3], strlen(cmd->argv[3]));
-
- silc_buffer_free(idp);
- silc_buffer_free(idp2);
- silc_client_list_free(client, conn, clients);
- silc_client_unref_channel(client, conn, channel);
-
- /* Notify application */
- COMMAND(SILC_STATUS_OK);
-
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
-
- out:
- silc_client_unref_channel(client, conn, channel);
- return SILC_FSM_FINISH;
-}
-
-/***************************** OPER & SILCOPER ******************************/
-
-typedef struct {
- unsigned char *passphrase;
- SilcUInt32 passphrase_len;
- SilcBuffer auth;
-} *SilcClientCommandOper;
-
-/* Ask passphrase callback */
-
-static void silc_client_command_oper_cb(const unsigned char *data,
- SilcUInt32 data_len, void *context)
-{
- SilcClientCommandContext cmd = context;
- SilcClientCommandOper oper = cmd->context;
-
- if (data && data_len)
- oper->passphrase = silc_memdup(data, data_len);
- oper->passphrase_len = data_len;
-
- /* Continue */
- SILC_FSM_CALL_CONTINUE(&cmd->thread);
-}
-
-static void silc_client_command_oper_sign_cb(const SilcBuffer data,
- void *context)
-{
- SilcClientCommandContext cmd = context;
- SilcClientCommandOper oper = cmd->context;
-
- if (data)
- oper->auth = silc_buffer_copy(data);
-
- /* Continue */
- SILC_FSM_CALL_CONTINUE(&cmd->thread);
-}
-
-/* Send OPER/SILCOPER command */
-
-SILC_FSM_STATE(silc_client_command_oper_send)
-{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcClientCommandOper oper = cmd->context;
- SilcBuffer auth = oper ? oper->auth : NULL;
-
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
- 1, cmd->argv[1], strlen(cmd->argv[1]),
- 2, silc_buffer_datalen(auth));
-
- silc_buffer_clear(auth);
- silc_buffer_free(auth);
- if (oper) {
- silc_free(oper->passphrase);
- silc_free(oper);
- }
-
- /* Notify application */
- COMMAND(SILC_STATUS_OK);
-
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
-}
-
-/* Get authentication data */
-
-SILC_FSM_STATE(silc_client_command_oper_get_auth)
-{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcClientCommandOper oper = cmd->context;
-
- silc_fsm_next(fsm, silc_client_command_oper_send);
-
- if (!oper || !oper->passphrase) {
- /* Encode the public key authentication payload */
- SILC_FSM_CALL(silc_auth_public_key_auth_generate(
- conn->public_key,
- conn->private_key,
- conn->client->rng,
- conn->internal->hash,
- conn->local_id, SILC_ID_CLIENT,
- silc_client_command_oper_sign_cb,
- oper));
- /* NOT REACHED */
- }
-
- /* Encode the password authentication payload */
- oper->auth = silc_auth_payload_encode(NULL, SILC_AUTH_PASSWORD, NULL, 0,
- oper->passphrase, oper->passphrase_len);
-
- return SILC_FSM_CONTINUE;
-}
-
-/* OPER command. Used to obtain server operator privileges. */
-
-SILC_FSM_STATE(silc_client_command_oper)
-{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcClientCommandOper oper;
-
- if (cmd->argc < 2) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "Usage: /OPER <username> [-pubkey]");
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- return SILC_FSM_FINISH;
- }
-
- silc_fsm_next(fsm, silc_client_command_oper_get_auth);
-
- /* Get passphrase */
- if (cmd->argc < 3) {
- oper = silc_calloc(1, sizeof(*oper));
- if (!oper)
- return SILC_FSM_FINISH;
- cmd->context = oper;
- SILC_FSM_CALL(conn->client->internal->
- ops->ask_passphrase(conn->client, conn,
- silc_client_command_oper_cb, cmd));
- }
-
- return SILC_FSM_CONTINUE;
-}
-
-/* SILCOPER command. Used to obtain router operator privileges. */
-
-SILC_FSM_STATE(silc_client_command_silcoper)
-{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcClientCommandOper oper;
-
- if (cmd->argc < 2) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "Usage: /SILCOPER <username> [-pubkey]");
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- return SILC_FSM_FINISH;
- }
-
- silc_fsm_next(fsm, silc_client_command_oper_send);
-
- /* Get passphrase */
- if (cmd->argc < 3) {
- oper = silc_calloc(1, sizeof(*oper));
- if (!oper)
- return SILC_FSM_FINISH;
- cmd->context = oper;
- SILC_FSM_CALL(conn->client->internal->
- ops->ask_passphrase(conn->client, conn,
- silc_client_command_oper_cb, cmd));
- }
-
- return SILC_FSM_CONTINUE;
-}
-
-/*********************************** BAN ************************************/
-
-/* Command BAN. This is used to manage the ban list of the channel. */
-
-SILC_FSM_STATE(silc_client_command_ban)
-{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcChannelEntry channel;
- SilcBuffer chidp, args = NULL;
- char *name, *ban = NULL;
- unsigned char action[1];
- SilcPublicKey pubkey = NULL;
-
- if (cmd->argc < 2) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "Usage: /BAN <channel> "
- "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
-
- if (cmd->argv[1][0] == '*') {
- if (!conn->current_channel) {
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
- goto out;
- }
-
- channel = conn->current_channel;
- silc_client_ref_channel(client, conn, channel);
- } else {
- name = cmd->argv[1];
-
- channel = silc_client_get_channel(conn->client, conn, name);
- if (!channel) {
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
- goto out;
- }
- }
-
- if (cmd->argc == 3) {
- if (cmd->argv[2][0] == '+')
- action[0] = 0x00;
- else
- action[0] = 0x01;
-
- /* Check if it is public key file to be added to invite list */
- silc_pkcs_load_public_key(cmd->argv[2] + 1, SILC_PKCS_ANY, &pubkey);
- ban = cmd->argv[2];
- if (!pubkey)
- ban++;
- }
-
- if (ban) {
- args = silc_buffer_alloc_size(2);
- silc_buffer_format(args,
- SILC_STR_UI_SHORT(1),
- SILC_STR_END);
- if (pubkey) {
- chidp = silc_public_key_payload_encode(NULL, pubkey);
- args = silc_argument_payload_encode_one(args,
- silc_buffer_datalen(chidp), 2);
- silc_buffer_free(chidp);
- silc_pkcs_public_key_free(pubkey);
- } else {
- args = silc_argument_payload_encode_one(args, ban, strlen(ban), 1);
- }
- }
-
- chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
-
- /* Send the command */
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
- 1, silc_buffer_datalen(chidp),
- 2, args ? action : NULL, args ? 1 : 0,
- 3, silc_buffer_datalen(args));
-
- silc_buffer_free(chidp);
- silc_buffer_free(args);
- silc_client_unref_channel(client, conn, channel);
-
- /* Notify application */
- COMMAND(SILC_STATUS_OK);
-
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
-
- out:
- return SILC_FSM_FINISH;
-}
-
-/********************************* DETACH ***********************************/
-
-/* Command DETACH. This is used to detach from the server */
-
-SILC_FSM_STATE(silc_client_command_detach)
-{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
-
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
-
- /* Notify application */
- COMMAND(SILC_STATUS_OK);
-
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
-}
-
-/********************************** WATCH ***********************************/
-
-/* Command WATCH. */
-
-SILC_FSM_STATE(silc_client_command_watch)
-{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcBuffer args = NULL;
- int type = 0;
- const char *pubkey = NULL;
- SilcBool pubkey_add = TRUE;
-
- if (cmd->argc < 3) {
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
-
- if (!strcasecmp(cmd->argv[1], "-add")) {
- type = 2;
- } else if (!strcasecmp(cmd->argv[1], "-del")) {
- type = 3;
- } else if (!strcasecmp(cmd->argv[1], "-pubkey") && cmd->argc >= 3) {
- type = 4;
- pubkey = cmd->argv[2] + 1;
- if (cmd->argv[2][0] == '-')
- pubkey_add = FALSE;
- } else {
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
-
- if (pubkey) {
- SilcPublicKey pk;
- SilcBuffer buffer;
-
- if (!silc_pkcs_load_public_key(pubkey, SILC_PKCS_ANY, &pk)) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
- "Could not load public key %s, check the filename", pubkey);
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
-
- args = silc_buffer_alloc_size(2);
- silc_buffer_format(args,
- SILC_STR_UI_SHORT(1),
- SILC_STR_END);
- buffer = silc_public_key_payload_encode(NULL, pk);
- args = silc_argument_payload_encode_one(args, silc_buffer_datalen(buffer),
- pubkey_add ? 0x00 : 0x01);
- silc_buffer_free(buffer);
- silc_pkcs_public_key_free(pk);
- }
-
- /* If watching by nickname, resolve all users with that nickname so that
- we get their information immediately. */
- if (type == 2)
- silc_client_get_clients(conn->client, conn, cmd->argv[2], NULL,
- silc_client_command_resolve_dummy, NULL);
-
- /* Send the commmand */
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
- 1, silc_buffer_datalen(conn->internal->
- local_idp),
- type, pubkey ? args->data : cmd->argv[2],
- pubkey ? silc_buffer_len(args) :
- cmd->argv_lens[2]);
-
- silc_buffer_free(args);
-
- /* Notify application */
- COMMAND(SILC_STATUS_OK);
-
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
-
- out:
- return SILC_FSM_FINISH;
-}
-
-/********************************** LEAVE ***********************************/
-
-/* LEAVE command. Leaves a channel. Client removes itself from a channel. */
-
-SILC_FSM_STATE(silc_client_command_leave)
-{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcChannelEntry channel;
- SilcBuffer idp;
- char *name, tmp[512];
-
- if (cmd->argc != 2) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "Usage: /LEAVE <channel>");
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
-
- if (cmd->argv[1][0] == '*') {
- if (!conn->current_channel) {
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
- goto out;
- }
-
- if (client->internal->params->full_channel_names)
- silc_snprintf(tmp, sizeof(tmp), conn->current_channel->channel_name);
- else
- silc_snprintf(tmp, sizeof(tmp), "%s%s%s",
- conn->current_channel->channel_name,
- conn->current_channel->server[0] ? "@" : "",
- conn->current_channel->server);
- name = tmp;
- } else {
- name = cmd->argv[1];
- }
-
- /* Get the channel entry */
- channel = silc_client_get_channel(conn->client, conn, name);
- if (!channel) {
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
- goto out;
- }
-
- idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
-
- /* Send LEAVE command to the server */
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
- 1, silc_buffer_datalen(idp));
-
- silc_buffer_free(idp);
-
- /* Notify application */
- COMMAND(SILC_STATUS_OK);
-
- if (conn->current_channel == channel)
- conn->current_channel = NULL;
-
- silc_client_unref_channel(client, conn, channel);
-
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
-
- out:
- return SILC_FSM_FINISH;
-}
-
-/********************************** USERS ***********************************/
-
-/* Command USERS. Requests the USERS of the clients joined on requested
- channel. */
-
-SILC_FSM_STATE(silc_client_command_users)
-{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- char *name, tmp[512];
-
- if (cmd->argc != 2) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "Usage: /USERS <channel>");
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
-
- if (cmd->argv[1][0] == '*') {
- if (!conn->current_channel) {
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
- goto out;
- }
-
- if (conn->client->internal->params->full_channel_names)
- silc_snprintf(tmp, sizeof(tmp), conn->current_channel->channel_name);
- else
- silc_snprintf(tmp, sizeof(tmp), "%s%s%s",
- conn->current_channel->channel_name,
- conn->current_channel->server[0] ? "@" : "",
- conn->current_channel->server);
- name = tmp;
- } else {
- name = cmd->argv[1];
- }
-
- /* Send USERS command to the server */
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
- 2, name, strlen(name));
-
- /* Notify application */
- COMMAND(SILC_STATUS_OK);
-
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
-
- out:
- return SILC_FSM_FINISH;
-}
-
-/********************************* GETKEY ***********************************/
-
-/* Command GETKEY. Used to fetch remote client's public key. */
-
-SILC_FSM_STATE(silc_client_command_getkey)
-{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcClientEntry client_entry;
- SilcServerEntry server_entry;
- SilcDList clients;
- SilcBuffer idp;
-
- if (cmd->argc < 2) {
- client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
- "Usage: /GETKEY <nickname or server name>");
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- return SILC_FSM_FINISH;
- }
-
- /* Find client entry */
- clients = silc_client_get_clients_local(client, conn, cmd->argv[1], FALSE);
- if (!clients) {
- /* Check whether user requested server */
- server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
- if (!server_entry) {
- if (cmd->resolved) {
- /* Resolving didn't find anything. We should never get here as
- errors are handled in the resolving callback. */
- COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
- COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_SERVER);
- return SILC_FSM_FINISH;
- }
-
- /* No client or server exist with this name, query for both. */
- cmd->resolved = TRUE;
- SILC_FSM_CALL(silc_client_command_send(client, conn,
- SILC_COMMAND_IDENTIFY,
- silc_client_command_continue,
- cmd, 2,
- 1, cmd->argv[1],
- strlen(cmd->argv[1]),
- 2, cmd->argv[1],
- strlen(cmd->argv[1])));
- /* NOT REACHED */
- }
- idp = silc_id_payload_encode(&server_entry->id, SILC_ID_SERVER);
- silc_client_unref_server(client, conn, server_entry);
- } else {
- client_entry = silc_dlist_get(clients);
- idp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT);
- silc_client_list_free(client, conn, clients);
- }
-
- /* Send the commmand */
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
- 1, silc_buffer_datalen(idp));
-
- silc_buffer_free(idp);
-
- /* Notify application */
- COMMAND(SILC_STATUS_OK);
-
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
-}
-
-/********************************* SERVICE **********************************/
-
-/* Command SERVICE. Negotiates service agreement with server. */
-/* XXX incomplete */
-
-SILC_FSM_STATE(silc_client_command_service)
-{
- SilcClientCommandContext cmd = fsm_context;
-#if 0
- SilcClientConnection conn = cmd->conn;
- SilcBuffer buffer;
- char *name;
-
- if (cmd->argc < 2) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "Usage: /SERVICE [<service name>] [-pubkey]");
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- return SILC_FSM_FINISH;
- }
-
- name = cmd->argv[1];
-
- /* Send SERVICE command to the server */
- buffer = silc_command_payload_encode_va(SILC_COMMAND_SERVICE,
- ++conn->cmd_ident, 1,
- 1, name, strlen(name));
- silc_client_packet_send(conn->client, conn->sock, SILC_PACKET_COMMAND,
- NULL, 0, NULL, NULL, buffer->data,
- buffer->len, TRUE);
- silc_buffer_free(buffer);
-#endif /* 0 */
-
- /* Notify application */
- COMMAND(SILC_STATUS_OK);
-
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
-}
-
-/* Register all default commands provided by the client library for the
- application. */
-
-void silc_client_commands_register(SilcClient client)
-{
- silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
- next);
-
- SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 5);
- SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
- SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
- SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
- SILC_CLIENT_CMD(list, LIST, "LIST", 2);
- SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
- SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
- SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
- SILC_CLIENT_CMD(kill, KILL, "KILL", 4);
- SILC_CLIENT_CMD(info, INFO, "INFO", 2);
- SILC_CLIENT_CMD(stats, STATS, "STATS", 0);
- SILC_CLIENT_CMD(ping, PING, "PING", 2);
- SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
- SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
- SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
- SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
- SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 6);
- SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 9);
- SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
- SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
- SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
- SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
- SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
- SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
- SILC_CLIENT_CMD(users, USERS, "USERS", 2);
- SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
- SILC_CLIENT_CMD(service, SERVICE, "SERVICE", 10);
-}
-
-/* Unregister all commands. */
-
-void silc_client_commands_unregister(SilcClient client)
-{
- SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
- SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
- SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
- SILC_CLIENT_CMDU(nick, NICK, "NICK");
- SILC_CLIENT_CMDU(list, LIST, "LIST");
- SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
- SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
- SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
- SILC_CLIENT_CMDU(kill, KILL, "KILL");
- SILC_CLIENT_CMDU(info, INFO, "INFO");
- SILC_CLIENT_CMDU(stats, STATS, "STATS");
- SILC_CLIENT_CMDU(ping, PING, "PING");
- SILC_CLIENT_CMDU(oper, OPER, "OPER");
- SILC_CLIENT_CMDU(join, JOIN, "JOIN");
- SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
- SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
- SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
- SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
- SILC_CLIENT_CMDU(kick, KICK, "KICK");
- SILC_CLIENT_CMDU(ban, BAN, "BAN");
- SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
- SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
- SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
- SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
- SILC_CLIENT_CMDU(users, USERS, "USERS");
- SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
- SILC_CLIENT_CMDU(service, SERVICE, "SERVICE");
-}
-
-/****************** Client Side Incoming Command Handling *******************/
-
-typedef struct {
- SilcClientConnection conn;
- SilcUInt16 cmd_ident;
-} *SilcClientProcessWhois;
-
-/* Send reply to WHOIS from server */
-
-static void
-silc_client_command_process_whois_send(SilcBool success,
- const unsigned char *data,
- SilcUInt32 data_len, void *context)
-{
- SilcClientProcessWhois w = context;
- SilcBufferStruct buffer;
- SilcBuffer packet;
-
- if (!data) {
- silc_free(w);
- return;
- }
-
- silc_buffer_set(&buffer, (unsigned char *)data, data_len);
-
- /* Send the attributes back in COMMAND_REPLY packet */
- packet =
- silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
- SILC_STATUS_OK, 0, w->cmd_ident,
- 1, 11, buffer.data,
- silc_buffer_len(&buffer));
- if (!packet) {
- silc_free(w);
- return;
- }
-
- SILC_LOG_DEBUG(("Sending back requested WHOIS attributes"));
-
- silc_packet_send(w->conn->stream, SILC_PACKET_COMMAND_REPLY, 0,
- silc_buffer_datalen(packet));
-
- silc_buffer_free(packet);
- silc_free(w);
-}
-
-/* Process WHOIS command from server */
-
-static void silc_client_command_process_whois(SilcClient client,
- SilcClientConnection conn,
- SilcCommandPayload payload,
- SilcArgumentPayload args)
-{
- SilcClientProcessWhois w;
- SilcDList attrs;
- unsigned char *tmp;
- SilcUInt32 tmp_len;
-
- SILC_LOG_DEBUG(("Received WHOIS command"));
-
- /* Try to take the Requested Attributes */
- tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
- if (!tmp)
- return;
-
- attrs = silc_attribute_payload_parse(tmp, tmp_len);
- if (!attrs)
- return;
-
- w = silc_calloc(1, sizeof(*w));
- if (!w) {
- silc_attribute_payload_list_free(attrs);
- return;
- }
- w->conn = conn;
- w->cmd_ident = silc_command_get_ident(payload);
-
- /* Process requested attributes */
- silc_client_attributes_process(client, conn, attrs,
- silc_client_command_process_whois_send, w);
- silc_attribute_payload_list_free(attrs);
-}
-
-/* Client is able to receive some command packets even though they are
- special case. Server may send WHOIS command to the client to retrieve
- Requested Attributes information for WHOIS query the server is
- processing. This function currently handles only the WHOIS command,
- but if in the future more commands may arrive then this can be made
- to support other commands too. */
-
-SILC_FSM_STATE(silc_client_command)
-{
- SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
- SilcPacket packet = state_context;
- SilcCommandPayload payload;
- SilcCommand command;
- SilcArgumentPayload args;
-
- /* Get command payload from packet */
- payload = silc_command_payload_parse(packet->buffer.data,
- silc_buffer_len(&packet->buffer));
- if (!payload) {
- SILC_LOG_DEBUG(("Bad command packet"));
- return SILC_FSM_FINISH;
- }
-
- /* Get arguments */
- args = silc_command_get_args(payload);
-
- /* Get the command */
- command = silc_command_get(payload);
- switch (command) {
-
- case SILC_COMMAND_WHOIS:
- /* Ignore everything if requested by application */
- if (conn->internal->params.ignore_requested_attributes)
- break;
-
- silc_client_command_process_whois(client, conn, payload, args);
- break;
-
- default:
- break;
- }
-
- silc_command_payload_free(payload);
- return SILC_FSM_FINISH;
-}