X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilcclient%2Fcommand.c;h=935e5fd03c6186c5c2209ac40effb67ecb90c6f9;hb=40f8443d8d3a6577336ee66d18e04d9ac4d956bb;hp=ed6a49e21ad963858a6351a80d674b29206b1a8d;hpb=1e3f9fcb3a19ffd75561b4448cc1db7f75e21f41;p=silc.git diff --git a/lib/silcclient/command.c b/lib/silcclient/command.c index ed6a49e2..935e5fd0 100644 --- a/lib/silcclient/command.c +++ b/lib/silcclient/command.c @@ -1,10 +1,10 @@ /* - command.c + command.c Author: Pekka Riikonen - Copyright (C) 1997 - 2002 Pekka Riikonen + Copyright (C) 1997 - 2005 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 @@ -18,15 +18,15 @@ */ /* $Id$ */ -#include "silcincludes.h" +#include "silc.h" #include "silcclient.h" #include "client_internal.h" #define SILC_NOT_CONNECTED(x, c) \ x->internal->ops->say((x), (c), SILC_CLIENT_MESSAGE_ERROR, \ - "You are not connected to a server, use /SERVER to connect"); + "You are not connected to a server, please connect to server"); -/* Command operation that is called at the end of all commands. +/* Command operation that is called at the end of all commands. Usage: COMMAND(status); */ #define COMMAND(status) cmd->client->internal->ops->command(cmd->client, \ cmd->conn, cmd, TRUE, cmd->command->cmd, (status)) @@ -53,8 +53,8 @@ void silc_client_command_send(SilcClient client, SilcClientConnection conn, va_start(ap, argc); packet = silc_command_payload_encode_vap(command, ident, argc, ap); - silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND, - NULL, 0, NULL, NULL, packet->data, + silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND, + NULL, 0, NULL, NULL, packet->data, packet->len, TRUE); silc_buffer_free(packet); } @@ -80,7 +80,7 @@ SilcClientCommand silc_client_command_find(SilcClient client, /* Executes a command */ -bool silc_client_command_call(SilcClient client, +SilcBool silc_client_command_call(SilcClient client, SilcClientConnection conn, const char *command_line, ...) { @@ -147,7 +147,7 @@ bool silc_client_command_call(SilcClient client, ctx->argv = argv; ctx->argv_lens = argv_lens; ctx->argv_types = argv_types; - + /* Call the command */ cmd->command(ctx, NULL); @@ -211,7 +211,7 @@ void silc_client_command_pending_del(SilcClientConnection conn, SilcClientCommandPendingCallbacks silc_client_command_pending_check(SilcClientConnection conn, SilcClientCommandReplyContext ctx, - SilcCommand command, + SilcCommand command, SilcUInt16 ident, SilcUInt32 *callbacks_count) { @@ -276,7 +276,7 @@ SilcClientCommandContext silc_client_command_dup(SilcClientCommandContext ctx) return ctx; } -/* Command WHOIS. This command is used to query information about +/* Command WHOIS. This command is used to query information about specific user. */ SILC_CLIENT_CMD_FUNC(whois) @@ -285,6 +285,9 @@ SILC_CLIENT_CMD_FUNC(whois) SilcClientConnection conn = cmd->conn; SilcBuffer buffer, attrs = NULL; unsigned char count[4], *tmp = NULL; + int i; + SilcBool details = FALSE, nick = FALSE; + unsigned char *pubkey = NULL; if (!cmd->conn) { SILC_NOT_CONNECTED(cmd->client, cmd->conn); @@ -295,35 +298,82 @@ SILC_CLIENT_CMD_FUNC(whois) /* Given without arguments fetches client's own information */ if (cmd->argc < 2) { buffer = silc_id_payload_encode(cmd->conn->local_id, SILC_ID_CLIENT); - silc_client_command_send(cmd->client, cmd->conn, SILC_COMMAND_WHOIS, + silc_client_command_send(cmd->client, cmd->conn, SILC_COMMAND_WHOIS, ++conn->cmd_ident, 1, 4, buffer->data, buffer->len); silc_buffer_free(buffer); goto out; } - if (cmd->argc == 2) { - buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS, - ++conn->cmd_ident, 1, - 1, cmd->argv[1], - cmd->argv_lens[1]); - } else { - if (!strcasecmp(cmd->argv[2], "-details")) + 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, 0); + } else { attrs = silc_client_attributes_request(0); + } + } - if (!attrs || cmd->argc > 3) { - int c = atoi(cmd->argc > 3 ? cmd->argv[3] : cmd->argv[2]); - SILC_PUT32_MSB(c, count); - tmp = count; + if (pubkey) { + SilcAttributeObjPk obj; + SilcPublicKey pk; + + if (!silc_pkcs_load_public_key(pubkey, &pk, SILC_PKCS_FILE_PEM)) { + if (!silc_pkcs_load_public_key(pubkey, &pk, SILC_PKCS_FILE_BIN)) { + SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, + "Could not load public key %s, check the filename", + pubkey); + COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); + goto out; + } } - buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS, - ++conn->cmd_ident, 3, - 1, cmd->argv[1], cmd->argv_lens[1], - 2, tmp ? tmp : NULL, tmp ? 4 : 0, - 3, attrs ? attrs->data : NULL, - attrs ? attrs->len : 0); + obj.type = "silc-rsa"; + obj.data = silc_pkcs_public_key_encode(pk, &obj.data_len); + + attrs = silc_attribute_payload_encode(attrs, + SILC_ATTRIBUTE_USER_PUBLIC_KEY, + SILC_ATTRIBUTE_FLAG_VALID, + &obj, sizeof(obj)); } + + buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS, + ++conn->cmd_ident, 3, + 1, nick ? cmd->argv[1] : NULL, + nick ? cmd->argv_lens[1] : 0, + 2, tmp ? tmp : NULL, tmp ? 4 : 0, + 3, attrs ? attrs->data : NULL, + attrs ? attrs->len : 0); + silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND, NULL, 0, NULL, NULL, buffer->data, buffer->len, TRUE); @@ -353,7 +403,7 @@ SILC_CLIENT_CMD_FUNC(whowas) } if (cmd->argc < 2 || cmd->argc > 3) { - SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, + SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Usage: /WHOWAS [@] []"); COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS : SILC_STATUS_ERR_TOO_MANY_PARAMS)); @@ -363,7 +413,7 @@ SILC_CLIENT_CMD_FUNC(whowas) if (cmd->argc == 2) { buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOWAS, ++conn->cmd_ident, 1, - 1, cmd->argv[1], + 1, cmd->argv[1], cmd->argv_lens[1]); } else { int c = atoi(cmd->argv[2]); @@ -386,8 +436,8 @@ SILC_CLIENT_CMD_FUNC(whowas) silc_client_command_free(cmd); } -/* Command IDENTIFY. This command is used to query information about - specific user, especially ID's. +/* Command IDENTIFY. This command is used to query information about + specific user, especially ID's. NOTE: This command is used only internally by the client library and application MUST NOT call this command directly. */ @@ -409,7 +459,7 @@ SILC_CLIENT_CMD_FUNC(identify) goto out; if (cmd->argc == 2) { - buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY, + buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY, ++conn->cmd_ident, 1, 1, cmd->argv[1], cmd->argv_lens[1]); @@ -417,7 +467,7 @@ SILC_CLIENT_CMD_FUNC(identify) int c = atoi(cmd->argv[2]); memset(count, 0, sizeof(count)); SILC_PUT32_MSB(c, count); - buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY, + buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY, ++conn->cmd_ident, 2, 1, cmd->argv[1], cmd->argv_lens[1], @@ -449,23 +499,23 @@ SILC_CLIENT_CMD_FUNC(nick) } if (cmd->argc < 2) { - SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, + SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Usage: /NICK "); COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } - if (!strcmp(conn->nickname, cmd->argv[1])) + if (silc_utf8_strcasecmp(conn->nickname, cmd->argv[1])) goto out; /* Show current nickname */ if (cmd->argc < 2) { if (cmd->conn) { - SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, - "Your nickname is %s on server %s", + SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, + "Your nickname is %s on server %s", conn->nickname, conn->remote_host); } else { - SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, + SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Your nickname is %s", conn->nickname); } @@ -479,7 +529,7 @@ SILC_CLIENT_CMD_FUNC(nick) /* Send the NICK command */ buffer = silc_command_payload_encode(SILC_COMMAND_NICK, 1, &cmd->argv[1], - &cmd->argv_lens[1], + &cmd->argv_lens[1], &cmd->argv_types[1], ++cmd->conn->cmd_ident); silc_client_packet_send(cmd->client, cmd->conn->sock, @@ -497,10 +547,8 @@ SILC_CLIENT_CMD_FUNC(list) { SilcClientCommandContext cmd = (SilcClientCommandContext)context; SilcClientConnection conn = cmd->conn; - SilcIDCacheEntry id_cache = NULL; SilcChannelEntry channel; SilcBuffer buffer, idp = NULL; - char *name; if (!cmd->conn) { SILC_NOT_CONNECTED(cmd->client, cmd->conn); @@ -509,21 +557,17 @@ SILC_CLIENT_CMD_FUNC(list) } if (cmd->argc == 2) { - name = cmd->argv[1]; - /* Get the Channel ID of the channel */ - if (silc_idcache_find_by_name_one(conn->internal->channel_cache, - name, &id_cache)) { - channel = (SilcChannelEntry)id_cache->context; - idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL); - } + channel = silc_client_get_channel(cmd->client, cmd->conn, cmd->argv[1]); + if (channel) + idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL); } if (!idp) - buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST, + buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST, ++conn->cmd_ident, 0); else - buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST, + buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST, ++conn->cmd_ident, 1, 1, idp->data, idp->len); @@ -547,7 +591,6 @@ SILC_CLIENT_CMD_FUNC(topic) { SilcClientCommandContext cmd = (SilcClientCommandContext)context; SilcClientConnection conn = cmd->conn; - SilcIDCacheEntry id_cache = NULL; SilcChannelEntry channel; SilcBuffer buffer, idp; char *name; @@ -582,27 +625,25 @@ SILC_CLIENT_CMD_FUNC(topic) } /* Get the Channel ID of the channel */ - if (!silc_idcache_find_by_name_one(conn->internal->channel_cache, - name, &id_cache)) { + channel = silc_client_get_channel(cmd->client, conn, name); + if (!channel) { COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL); goto out; } - channel = (SilcChannelEntry)id_cache->context; - /* Send TOPIC command to the server */ - idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL); + idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL); if (cmd->argc > 2) - buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC, - ++conn->cmd_ident, 2, + buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC, + ++conn->cmd_ident, 2, 1, idp->data, idp->len, - 2, cmd->argv[2], + 2, cmd->argv[2], strlen(cmd->argv[2])); else - buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC, + buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC, ++conn->cmd_ident, 1, 1, idp->data, idp->len); - silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, + silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 0, NULL, NULL, buffer->data, buffer->len, TRUE); silc_buffer_free(buffer); silc_buffer_free(idp); @@ -624,10 +665,11 @@ SILC_CLIENT_CMD_FUNC(invite) SilcClientConnection conn = cmd->conn; SilcClientEntry client_entry = NULL; SilcChannelEntry channel; - SilcBuffer buffer, clidp, chidp; - SilcUInt32 type = 0; + SilcBuffer buffer, clidp, chidp, args = NULL; + SilcPublicKey pubkey = NULL; char *nickname = NULL, *name; char *invite = NULL; + unsigned char action[1]; if (!cmd->conn) { SILC_NOT_CONNECTED(cmd->client, cmd->conn); @@ -669,30 +711,53 @@ SILC_CLIENT_CMD_FUNC(invite) nickname = strdup(cmd->argv[2]); /* Find client entry */ - client_entry = silc_idlist_get_client(client, conn, nickname, + client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[2], TRUE); if (!client_entry) { if (cmd->pending) { COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK); goto out; } - + /* Client entry not found, it was requested thus mark this to be pending command. */ - silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, + silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident, - silc_client_command_invite, + silc_client_command_invite, silc_client_command_dup(cmd)); cmd->pending = 1; goto out; } } else { - invite = cmd->argv[2]; - invite++; if (cmd->argv[2][0] == '+') - type = 3; + action[0] = 0x00; else - type = 4; + action[0] = 0x01; + + /* Check if it is public key file to be added to invite list */ + if (!silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey, + SILC_PKCS_FILE_PEM)) + silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey, + SILC_PKCS_FILE_BIN); + 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_pkcs_public_key_payload_encode(pubkey); + args = silc_argument_payload_encode_one(args, chidp->data, + chidp->len, 2); + silc_buffer_free(chidp); + silc_pkcs_public_key_free(pubkey); + } else { + args = silc_argument_payload_encode_one(args, invite, strlen(invite), 1); } } @@ -700,25 +765,30 @@ SILC_CLIENT_CMD_FUNC(invite) chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL); if (client_entry) { clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT); - buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE, - ++conn->cmd_ident, 3, + buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE, + ++conn->cmd_ident, 4, 1, chidp->data, chidp->len, 2, clidp->data, clidp->len, - type, invite, invite ? - strlen(invite) : 0); + 3, args ? action : NULL, + args ? 1 : 0, + 4, args ? args->data : NULL, + args ? args->len : 0); silc_buffer_free(clidp); } else { - buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE, - ++conn->cmd_ident, 2, + buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE, + ++conn->cmd_ident, 3, 1, chidp->data, chidp->len, - type, invite, invite ? - strlen(invite) : 0); + 3, args ? action : NULL, + args ? 1 : 0, + 4, args ? args->data : NULL, + args ? args->len : 0); } - silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, + silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 0, NULL, NULL, buffer->data, buffer->len, TRUE); silc_buffer_free(buffer); silc_buffer_free(chidp); + silc_buffer_free(args); /* Notify application */ COMMAND(SILC_STATUS_OK); @@ -745,7 +815,7 @@ SILC_TASK_CALLBACK(silc_client_command_quit_cb) } /* Command QUIT. Closes connection with current server. */ - + SILC_CLIENT_CMD_FUNC(quit) { SilcClientCommandContext cmd = (SilcClientCommandContext)context; @@ -759,14 +829,16 @@ SILC_CLIENT_CMD_FUNC(quit) } if (cmd->argc > 1) - buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1, + buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1, &cmd->argv[1], &cmd->argv_lens[1], - &cmd->argv_types[1], 0); + &cmd->argv_types[1], + ++cmd->conn->cmd_ident); else buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0, - NULL, NULL, NULL, 0); - silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND, - NULL, 0, NULL, NULL, + NULL, NULL, NULL, + ++cmd->conn->cmd_ident); + silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND, + NULL, 0, NULL, NULL, buffer->data, buffer->len, TRUE); silc_buffer_free(buffer); @@ -798,7 +870,7 @@ SILC_TASK_CALLBACK(silc_client_command_kill_remove_later) SilcClientConnection conn = cmd->conn; SilcClientEntry target; char *nickname = NULL; - + /* Parse the typed nickname. */ if (client->internal->params->nickname_parse) client->internal->params->nickname_parse(cmd->argv[1], &nickname); @@ -806,7 +878,7 @@ SILC_TASK_CALLBACK(silc_client_command_kill_remove_later) nickname = strdup(cmd->argv[1]); /* Get the target client */ - target = silc_idlist_get_client(cmd->client, conn, nickname, + target = silc_idlist_get_client(cmd->client, conn, nickname, cmd->argv[1], FALSE); if (target) /* Remove the client from all channels and free it */ @@ -822,7 +894,7 @@ SILC_TASK_CALLBACK(silc_client_command_kill_remove_later) SILC_CLIENT_CMD_FUNC(kill_remove) { SilcClientCommandContext cmd = (SilcClientCommandContext)context; - SilcClientCommandReplyContext reply = + SilcClientCommandReplyContext reply = (SilcClientCommandReplyContext)context2; SilcStatus status; @@ -857,7 +929,7 @@ SILC_CLIENT_CMD_FUNC(kill) } if (cmd->argc < 2) { - SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, + SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Usage: /KILL [] [-pubkey]"); COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; @@ -870,7 +942,7 @@ SILC_CLIENT_CMD_FUNC(kill) nickname = strdup(cmd->argv[1]); /* Get the target client */ - target = silc_idlist_get_client(cmd->client, conn, nickname, + target = silc_idlist_get_client(cmd->client, conn, nickname, cmd->argv[1], TRUE); if (!target) { if (cmd->pending) { @@ -880,9 +952,9 @@ SILC_CLIENT_CMD_FUNC(kill) /* Client entry not found, it was requested thus mark this to be pending command. */ - silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, - conn->cmd_ident, - silc_client_command_kill, + silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, + conn->cmd_ident, + silc_client_command_kill, silc_client_command_dup(cmd)); cmd->pending = 1; goto out; @@ -906,8 +978,8 @@ SILC_CLIENT_CMD_FUNC(kill) /* Send the KILL command to the server */ idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT); buffer = - silc_command_payload_encode_va(SILC_COMMAND_KILL, - ++conn->cmd_ident, 3, + silc_command_payload_encode_va(SILC_COMMAND_KILL, + ++conn->cmd_ident, 3, 1, idp->data, idp->len, 2, comment, comment ? strlen(comment) : 0, 3, auth ? auth->data : NULL, @@ -953,12 +1025,13 @@ SILC_CLIENT_CMD_FUNC(info) /* Send the command */ if (name) - buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1, + buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, + ++conn->cmd_ident, 1, 1, name, strlen(name)); else buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0, - NULL, NULL, NULL, 0); - silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, + NULL, NULL, NULL, ++conn->cmd_ident); + silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 0, NULL, NULL, buffer->data, buffer->len, TRUE); silc_buffer_free(buffer); if (name) @@ -985,13 +1058,13 @@ SILC_CLIENT_CMD_FUNC(stats) goto out; } - idp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER); - + idp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER); + /* Send the command */ buffer = silc_command_payload_encode_va(SILC_COMMAND_STATS, ++conn->cmd_ident, 1, SILC_ID_SERVER, idp->data, idp->len); - silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, + silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 0, NULL, NULL, buffer->data, buffer->len, TRUE); silc_buffer_free(buffer); silc_buffer_free(idp); @@ -1003,7 +1076,7 @@ SILC_CLIENT_CMD_FUNC(stats) silc_client_command_free(cmd); } -/* Command PING. Sends ping to server. This is used to test the +/* Command PING. Sends ping to server. This is used to test the communication channel. */ SILC_CLIENT_CMD_FUNC(ping) @@ -1020,12 +1093,13 @@ SILC_CLIENT_CMD_FUNC(ping) goto out; } - idp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER); + idp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER); /* Send the command */ - buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1, + buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, + ++conn->cmd_ident, 1, 1, idp->data, idp->len); - silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, + silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 0, NULL, NULL, buffer->data, buffer->len, TRUE); silc_buffer_free(buffer); silc_buffer_free(idp); @@ -1057,7 +1131,7 @@ SILC_CLIENT_CMD_FUNC(ping) conn->internal->ping[i].dest_name = strdup(conn->remote_host); conn->internal->ping_count++; } - + /* Notify application */ COMMAND(SILC_STATUS_OK); @@ -1072,7 +1146,7 @@ SILC_CLIENT_CMD_FUNC(join) SilcClientCommandContext cmd = (SilcClientCommandContext)context; SilcClientConnection conn = cmd->conn; SilcChannelEntry channel; - SilcBuffer buffer, idp, auth = NULL; + SilcBuffer buffer, idp, auth = NULL, cauth = NULL; char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL; int i, passphrase_len = 0; @@ -1086,7 +1160,7 @@ SILC_CLIENT_CMD_FUNC(join) 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(cmd->client, conn, cmd->argv[1]); if (channel && silc_client_on_channel(channel, conn->local_entry)) @@ -1109,15 +1183,48 @@ SILC_CLIENT_CMD_FUNC(join) } else if (!strcasecmp(cmd->argv[i], "-founder")) { auth = silc_auth_public_key_auth_generate(cmd->client->public_key, cmd->client->private_key, - cmd->client->rng, + cmd->client->rng, cmd->client->sha1hash, conn->local_id, SILC_ID_CLIENT); - i++; + } else if (!strcasecmp(cmd->argv[i], "-auth")) { + SilcPublicKey pubkey = cmd->client->public_key; + SilcPrivateKey privkey = cmd->client->private_key; + unsigned char *pk, pkhash[SILC_HASH_MAXLEN], *pubdata; + SilcUInt32 pk_len; + + 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, + NULL, &pubkey, &privkey)) { + SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, + "Could not load key pair, check your arguments"); + COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); + goto out; + } + i += 2; + } + + pk = silc_pkcs_public_key_encode(pubkey, &pk_len); + silc_hash_make(cmd->client->sha1hash, pk, pk_len, pkhash); + silc_free(pk); + pubdata = silc_rng_get_rn_data(cmd->client->rng, 128); + memcpy(pubdata, pkhash, 20); + cauth = silc_auth_public_key_auth_generate_wpub(pubkey, privkey, + pubdata, 128, + cmd->client->sha1hash, + conn->local_id, + SILC_ID_CLIENT); + memset(pubdata, 0, 128); + silc_free(pubdata); } 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], + 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], @@ -1132,20 +1239,24 @@ SILC_CLIENT_CMD_FUNC(join) /* Send JOIN command to the server */ buffer = - silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 6, + silc_command_payload_encode_va(SILC_COMMAND_JOIN, ++conn->cmd_ident, 7, 1, name, strlen(name), 2, idp->data, idp->len, 3, passphrase, passphrase_len, 4, cipher, cipher ? strlen(cipher) : 0, 5, hmac, hmac ? strlen(hmac) : 0, 6, auth ? auth->data : NULL, - auth ? auth->len : 0); - silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, + auth ? auth->len : 0, + 7, cauth ? cauth->data : NULL, + cauth ? cauth->len : 0); + silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 0, NULL, NULL, buffer->data, buffer->len, TRUE); silc_buffer_free(buffer); silc_buffer_free(idp); - if (auth) - silc_buffer_free(auth); + silc_buffer_free(auth); + silc_buffer_free(cauth); + if (passphrase) + memset(passphrase, 0, strlen(passphrase)); silc_free(passphrase); /* Notify application */ @@ -1179,14 +1290,16 @@ SILC_CLIENT_CMD_FUNC(motd) /* Send TOPIC command to the server */ if (cmd->argc == 1) - buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1, - 1, conn->remote_host, + buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, + ++conn->cmd_ident, 1, + 1, conn->remote_host, strlen(conn->remote_host)); else - buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1, - 1, cmd->argv[1], + buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, + ++conn->cmd_ident, 1, + 1, cmd->argv[1], cmd->argv_lens[1]); - silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, + silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 0, NULL, NULL, buffer->data, buffer->len, TRUE); silc_buffer_free(buffer); @@ -1216,7 +1329,7 @@ SILC_CLIENT_CMD_FUNC(umode) } if (cmd->argc < 2) { - SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, + SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Usage: /UMODE +|-"); COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; @@ -1330,11 +1443,11 @@ SILC_CLIENT_CMD_FUNC(umode) /* Send the command packet. We support sending only one mode at once that requires an argument. */ - buffer = - silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2, - 1, idp->data, idp->len, + buffer = + silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2, + 1, idp->data, idp->len, 2, modebuf, sizeof(modebuf)); - silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, + silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 0, NULL, NULL, buffer->data, buffer->len, TRUE); silc_buffer_free(buffer); silc_buffer_free(idp); @@ -1355,7 +1468,7 @@ SILC_CLIENT_CMD_FUNC(cmode) SilcClientCommandContext cmd = (SilcClientCommandContext)context; SilcClientConnection conn = cmd->conn; SilcChannelEntry channel; - SilcBuffer buffer, chidp, auth = NULL; + SilcBuffer buffer, chidp, auth = NULL, pk = NULL; unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL; SilcUInt32 mode, add, type, len, arg_len = 0; int i; @@ -1367,7 +1480,7 @@ SILC_CLIENT_CMD_FUNC(cmode) } if (cmd->argc < 3) { - SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, + SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Usage: /CMODE +|- [{ }]"); COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; @@ -1454,7 +1567,7 @@ SILC_CLIENT_CMD_FUNC(cmode) mode |= SILC_CHANNEL_MODE_ULIMIT; type = 3; if (cmd->argc < 4) { - SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, + SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Usage: /CMODE +|- [{ }]"); COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; @@ -1472,7 +1585,7 @@ SILC_CLIENT_CMD_FUNC(cmode) mode |= SILC_CHANNEL_MODE_PASSPHRASE; type = 4; if (cmd->argc < 4) { - SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, + SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Usage: /CMODE +|- [{ }]"); COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; @@ -1488,7 +1601,7 @@ SILC_CLIENT_CMD_FUNC(cmode) mode |= SILC_CHANNEL_MODE_CIPHER; type = 5; if (cmd->argc < 4) { - SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, + SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Usage: /CMODE +|- [{ }]"); COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; @@ -1504,7 +1617,7 @@ SILC_CLIENT_CMD_FUNC(cmode) mode |= SILC_CHANNEL_MODE_HMAC; type = 6; if (cmd->argc < 4) { - SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, + SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Usage: /CMODE +|- [{ }]"); COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; @@ -1517,11 +1630,28 @@ SILC_CLIENT_CMD_FUNC(cmode) break; case 'f': if (add) { + SilcPublicKey pubkey = cmd->client->public_key; + SilcPrivateKey privkey = cmd->client->private_key; + mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH; type = 7; - auth = silc_auth_public_key_auth_generate(cmd->client->public_key, - cmd->client->private_key, - cmd->client->rng, + + 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, + NULL, &pubkey, &privkey)) { + SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, + "Could not load key pair, check your arguments"); + COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); + goto out; + } + } + + pk = silc_pkcs_public_key_payload_encode(pubkey); + auth = silc_auth_public_key_auth_generate(pubkey, privkey, + cmd->client->rng, cmd->client->sha1hash, conn->local_id, SILC_ID_CLIENT); @@ -1531,6 +1661,65 @@ SILC_CLIENT_CMD_FUNC(cmode) 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(cmd->client, conn, SILC_COMMAND_CMODE, + 0, 1, 1, chidp->data, chidp->len); + silc_buffer_free(chidp); + + /* Notify application */ + COMMAND(SILC_STATUS_OK); + goto out; + } + + 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, &chpk, + SILC_PKCS_FILE_PEM)) + if (!silc_pkcs_load_public_key(cmd->argv[k] + 1, &chpk, + SILC_PKCS_FILE_BIN)) { + SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_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_pkcs_public_key_payload_encode(chpk); + auth = silc_argument_payload_encode_one(auth, pk->data, pk->len, + chadd ? 0x00 : 0x01); + silc_pkcs_public_key_free(chpk); + silc_buffer_free(pk); + pk = NULL; + } + } + + arg = auth->data; + arg_len = auth->len; + } else { + mode &= ~SILC_CHANNEL_MODE_CHANNEL_AUTH; + } + break; default: COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE); goto out; @@ -1544,24 +1733,26 @@ SILC_CLIENT_CMD_FUNC(cmode) /* Send the command packet. We support sending only one mode at once that requires an argument. */ if (type && arg) { - buffer = - silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3, - 1, chidp->data, chidp->len, + buffer = + silc_command_payload_encode_va(SILC_COMMAND_CMODE, ++conn->cmd_ident, 4, + 1, chidp->data, chidp->len, 2, modebuf, sizeof(modebuf), - type, arg, arg_len); + type, arg, arg_len, + 8, pk ? pk->data : NULL, + pk ? pk->len : 0); } else { - buffer = - silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2, - 1, chidp->data, chidp->len, + buffer = + silc_command_payload_encode_va(SILC_COMMAND_CMODE, ++conn->cmd_ident, 2, + 1, chidp->data, chidp->len, 2, modebuf, sizeof(modebuf)); } - silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, + silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 0, NULL, NULL, buffer->data, buffer->len, TRUE); silc_buffer_free(buffer); silc_buffer_free(chidp); - if (auth) - silc_buffer_free(auth); + silc_buffer_free(auth); + silc_buffer_free(pk); /* Notify application */ COMMAND(SILC_STATUS_OK); @@ -1593,7 +1784,7 @@ SILC_CLIENT_CMD_FUNC(cumode) } if (cmd->argc < 4) { - SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, + SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Usage: /CUMODE +|- [@]"); COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; @@ -1633,14 +1824,14 @@ SILC_CLIENT_CMD_FUNC(cumode) /* Client entry not found, it was requested thus mark this to be pending command. */ - silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, - conn->cmd_ident, - silc_client_command_cumode, + silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, + conn->cmd_ident, + silc_client_command_cumode, silc_client_command_dup(cmd)); cmd->pending = 1; goto out; } - + /* Get the current mode */ chu = silc_client_on_channel(channel, client_entry); if (chu) @@ -1670,8 +1861,23 @@ SILC_CLIENT_CMD_FUNC(cumode) break; case 'f': if (add) { - auth = silc_auth_public_key_auth_generate(cmd->client->public_key, - cmd->client->private_key, + SilcPublicKey pubkey = cmd->client->public_key; + SilcPrivateKey privkey = cmd->client->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, + NULL, &pubkey, &privkey)) { + SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, + "Could not load key pair, check your arguments"); + COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); + goto out; + } + } + + auth = silc_auth_public_key_auth_generate(pubkey, privkey, cmd->client->rng, cmd->client->sha1hash, conn->local_id, @@ -1724,22 +1930,23 @@ SILC_CLIENT_CMD_FUNC(cumode) /* Send the command packet. We support sending only one mode at once that requires an argument. */ - buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, - auth ? 4 : 3, - 1, chidp->data, chidp->len, + buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, + ++conn->cmd_ident, + auth ? 4 : 3, + 1, chidp->data, chidp->len, 2, modebuf, 4, 3, clidp->data, clidp->len, - 4, auth ? auth->data : NULL, + 4, auth ? auth->data : NULL, auth ? auth->len : 0); - - silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, + + silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 0, NULL, NULL, buffer->data, buffer->len, TRUE); silc_buffer_free(buffer); silc_buffer_free(chidp); silc_buffer_free(clidp); if (auth) silc_buffer_free(auth); - + /* Notify application */ COMMAND(SILC_STATUS_OK); @@ -1755,7 +1962,6 @@ SILC_CLIENT_CMD_FUNC(kick) SilcClientCommandContext cmd = (SilcClientCommandContext)context; SilcClient client = cmd->client; SilcClientConnection conn = cmd->conn; - SilcIDCacheEntry id_cache = NULL; SilcChannelEntry channel; SilcBuffer buffer, idp, idp2; SilcClientEntry target; @@ -1769,7 +1975,7 @@ SILC_CLIENT_CMD_FUNC(kick) } if (cmd->argc < 3) { - SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, + SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Usage: /KICK []"); COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; @@ -1791,14 +1997,12 @@ SILC_CLIENT_CMD_FUNC(kick) } /* Get the Channel ID of the channel */ - if (!silc_idcache_find_by_name_one(conn->internal->channel_cache, - name, &id_cache)) { + channel = silc_client_get_channel(cmd->client, conn, name); + if (!channel) { COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL); goto out; } - channel = (SilcChannelEntry)id_cache->context; - /* Parse the typed nickname. */ if (client->internal->params->nickname_parse) client->internal->params->nickname_parse(cmd->argv[2], &nickname); @@ -1806,27 +2010,29 @@ SILC_CLIENT_CMD_FUNC(kick) nickname = strdup(cmd->argv[2]); /* Get the target client */ - target = silc_idlist_get_client(cmd->client, conn, nickname, + target = silc_idlist_get_client(cmd->client, conn, nickname, cmd->argv[2], FALSE); if (!target) { - SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, + SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "No such client: %s", cmd->argv[2]); COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK); goto out; } /* Send KICK command to the server */ - idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL); + idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL); idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT); if (cmd->argc == 3) - buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2, + buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, + ++conn->cmd_ident, 2, 1, idp->data, idp->len, 2, idp2->data, idp2->len); else - buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3, + buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, + ++conn->cmd_ident, 3, 1, idp->data, idp->len, 2, idp2->data, idp2->len, - 3, cmd->argv[3], + 3, cmd->argv[3], strlen(cmd->argv[3])); silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 0, NULL, NULL, buffer->data, buffer->len, TRUE); @@ -1863,8 +2069,9 @@ static void silc_client_command_oper_send(unsigned char *data, data, data_len); } - buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2, - 1, cmd->argv[1], + buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, + ++conn->cmd_ident, 2, + 1, cmd->argv[1], strlen(cmd->argv[1]), 2, auth ? auth->data : NULL, auth ? auth->len : 0); @@ -1872,6 +2079,7 @@ static void silc_client_command_oper_send(unsigned char *data, 0, NULL, NULL, buffer->data, buffer->len, TRUE); silc_buffer_free(buffer); + silc_buffer_clear(auth); silc_buffer_free(auth); /* Notify application */ @@ -1892,7 +2100,7 @@ SILC_CLIENT_CMD_FUNC(oper) } if (cmd->argc < 2) { - SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, + SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Usage: /OPER [-pubkey]"); COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; @@ -1913,7 +2121,7 @@ SILC_CLIENT_CMD_FUNC(oper) } static void silc_client_command_silcoper_send(unsigned char *data, - SilcUInt32 data_len, + SilcUInt32 data_len, void *context) { SilcClientCommandContext cmd = (SilcClientCommandContext)context; @@ -1934,8 +2142,9 @@ static void silc_client_command_silcoper_send(unsigned char *data, data, data_len); } - buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2, - 1, cmd->argv[1], + buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, + ++conn->cmd_ident, 2, + 1, cmd->argv[1], strlen(cmd->argv[1]), 2, auth ? auth->data : NULL, auth ? auth->len : 0); @@ -1943,6 +2152,7 @@ static void silc_client_command_silcoper_send(unsigned char *data, 0, NULL, NULL, buffer->data, buffer->len, TRUE); silc_buffer_free(buffer); + silc_buffer_clear(auth); silc_buffer_free(auth); /* Notify application */ @@ -1963,7 +2173,7 @@ SILC_CLIENT_CMD_FUNC(silcoper) } if (cmd->argc < 2) { - SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, + SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Usage: /SILCOPER [-pubkey]"); COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; @@ -1990,9 +2200,10 @@ SILC_CLIENT_CMD_FUNC(ban) SilcClientCommandContext cmd = (SilcClientCommandContext)context; SilcClientConnection conn = cmd->conn; SilcChannelEntry channel; - SilcBuffer buffer, chidp; - int type = 0; + SilcBuffer buffer, chidp, args = NULL; char *name, *ban = NULL; + unsigned char action[1]; + SilcPublicKey pubkey = NULL; if (!cmd->conn) { SILC_NOT_CONNECTED(cmd->client, cmd->conn); @@ -2001,7 +2212,7 @@ SILC_CLIENT_CMD_FUNC(ban) } if (cmd->argc < 2) { - SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, + SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Usage: /BAN " "[+|-[[@[![@hostname>]]]]]"); COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); @@ -2027,25 +2238,51 @@ SILC_CLIENT_CMD_FUNC(ban) if (cmd->argc == 3) { if (cmd->argv[2][0] == '+') - type = 2; + action[0] = 0x00; else - type = 3; + action[0] = 0x01; + /* Check if it is public key file to be added to invite list */ + if (!silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey, + SILC_PKCS_FILE_PEM)) + silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey, + SILC_PKCS_FILE_BIN); ban = cmd->argv[2]; - ban++; + 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_pkcs_public_key_payload_encode(pubkey); + args = silc_argument_payload_encode_one(args, chidp->data, + chidp->len, 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 */ - buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, - ++conn->cmd_ident, 2, + buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, + ++conn->cmd_ident, 3, 1, chidp->data, chidp->len, - type, ban, ban ? strlen(ban) : 0); - silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, + 2, args ? action : NULL, + args ? 1 : 0, + 3, args ? args->data : NULL, + args ? args->len : 0); + silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 0, NULL, NULL, buffer->data, buffer->len, TRUE); silc_buffer_free(buffer); silc_buffer_free(chidp); + silc_buffer_free(args); /* Notify application */ COMMAND(SILC_STATUS_OK); @@ -2070,7 +2307,7 @@ SILC_CLIENT_CMD_FUNC(detach) buffer = silc_command_payload_encode_va(SILC_COMMAND_DETACH, ++conn->cmd_ident, 0); - silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, + silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 0, NULL, NULL, buffer->data, buffer->len, TRUE); silc_buffer_free(buffer); @@ -2087,8 +2324,10 @@ SILC_CLIENT_CMD_FUNC(watch) { SilcClientCommandContext cmd = (SilcClientCommandContext)context; SilcClientConnection conn = cmd->conn; - SilcBuffer buffer, idp = NULL; + SilcBuffer buffer, idp = NULL, args = NULL; int type = 0; + const char *pubkey = NULL; + SilcBool pubkey_add = TRUE; if (!cmd->conn) { SILC_NOT_CONNECTED(cmd->client, cmd->conn); @@ -2107,19 +2346,51 @@ SILC_CLIENT_CMD_FUNC(watch) 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; } - buffer = silc_command_payload_encode_va(SILC_COMMAND_WATCH, + if (pubkey) { + SilcPublicKey pk; + + if (!silc_pkcs_load_public_key(pubkey, &pk, SILC_PKCS_FILE_PEM)) { + if (!silc_pkcs_load_public_key(pubkey, &pk, SILC_PKCS_FILE_BIN)) { + SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_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_pkcs_public_key_payload_encode(pk); + args = silc_argument_payload_encode_one(args, buffer->data, buffer->len, + pubkey_add ? 0x00 : 0x01); + silc_buffer_free(buffer); + silc_pkcs_public_key_free(pk); + } + + buffer = silc_command_payload_encode_va(SILC_COMMAND_WATCH, ++conn->cmd_ident, 2, 1, idp->data, idp->len, - type, cmd->argv[2], + type, + pubkey ? args->data : cmd->argv[2], + pubkey ? args->len : cmd->argv_lens[2]); - silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, + silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 0, NULL, NULL, buffer->data, buffer->len, TRUE); silc_buffer_free(buffer); + silc_buffer_free(args); /* Notify application */ COMMAND(SILC_STATUS_OK); @@ -2137,7 +2408,6 @@ SILC_CLIENT_CMD_FUNC(leave) SilcClientCommandContext cmd = (SilcClientCommandContext)context; SilcClientConnection conn = cmd->conn; SilcChannelEntry channel; - SilcChannelUser chu; SilcBuffer buffer, idp; char *name; @@ -2148,7 +2418,7 @@ SILC_CLIENT_CMD_FUNC(leave) } if (cmd->argc != 2) { - SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, + SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Usage: /LEAVE "); COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; @@ -2171,19 +2441,12 @@ SILC_CLIENT_CMD_FUNC(leave) goto out; } - /* Remove us from channel */ - chu = silc_client_on_channel(channel, conn->local_entry); - if (chu) { - silc_hash_table_del(chu->client->channels, chu->channel); - silc_hash_table_del(chu->channel->user_list, chu->client); - silc_free(chu); - } - /* Send LEAVE command to the server */ idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL); - buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1, + buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, + ++conn->cmd_ident, 1, 1, idp->data, idp->len); - silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, + silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 0, NULL, NULL, buffer->data, buffer->len, TRUE); silc_buffer_free(buffer); silc_buffer_free(idp); @@ -2194,8 +2457,6 @@ SILC_CLIENT_CMD_FUNC(leave) if (conn->current_channel == channel) conn->current_channel = NULL; - silc_client_del_channel(cmd->client, cmd->conn, channel); - out: silc_client_command_free(cmd); } @@ -2217,7 +2478,7 @@ SILC_CLIENT_CMD_FUNC(users) } if (cmd->argc != 2) { - SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, + SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Usage: /USERS "); COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; @@ -2234,11 +2495,11 @@ SILC_CLIENT_CMD_FUNC(users) } /* Send USERS command to the server */ - buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS, - ++conn->cmd_ident, 1, + buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS, + ++conn->cmd_ident, 1, 2, name, strlen(name)); - silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, - NULL, 0, NULL, NULL, buffer->data, + silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, + NULL, 0, NULL, NULL, buffer->data, buffer->len, TRUE); silc_buffer_free(buffer); @@ -2270,7 +2531,7 @@ SILC_CLIENT_CMD_FUNC(getkey) } if (cmd->argc < 2) { - client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO, + client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO, "Usage: /GETKEY "); COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; @@ -2297,14 +2558,14 @@ SILC_CLIENT_CMD_FUNC(getkey) if (!cmd->pending) { /* This will send the IDENTIFY command for nickname */ silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE); - silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, - conn->cmd_ident, - silc_client_command_getkey, + silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, + conn->cmd_ident, + silc_client_command_getkey, silc_client_command_dup(cmd)); cmd->pending = 1; goto out; } else { - SilcClientCommandReplyContext reply = + SilcClientCommandReplyContext reply = (SilcClientCommandReplyContext)context2; SilcStatus error; @@ -2312,16 +2573,16 @@ SILC_CLIENT_CMD_FUNC(getkey) silc_command_get_status(reply->payload, NULL, &error); if (error == SILC_STATUS_ERR_NO_SUCH_NICK) { /* This sends the IDENTIFY command to resolve the server. */ - silc_client_command_register(client, SILC_COMMAND_IDENTIFY, + silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL, silc_client_command_reply_identify_i, 0, ++conn->cmd_ident); silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY, - conn->cmd_ident, 1, + conn->cmd_ident, 1, 2, cmd->argv[1], cmd->argv_lens[1]); - silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, - conn->cmd_ident, - silc_client_command_getkey, + silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, + conn->cmd_ident, + silc_client_command_getkey, silc_client_command_dup(cmd)); goto out; } @@ -2329,9 +2590,9 @@ SILC_CLIENT_CMD_FUNC(getkey) /* If server was not found, then we've resolved both nickname and server and did not find anybody. */ if (error == SILC_STATUS_ERR_NO_SUCH_SERVER) { - SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s", + SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s", silc_get_status_message(SILC_STATUS_ERR_NO_SUCH_NICK)); - SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s", + SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s", silc_get_status_message(error)); COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK); goto out; @@ -2347,9 +2608,10 @@ SILC_CLIENT_CMD_FUNC(getkey) idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT); } - buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1, + buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, + ++conn->cmd_ident, 1, 1, idp->data, idp->len); - silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, + silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 0, NULL, NULL, buffer->data, buffer->len, TRUE); silc_buffer_free(buffer); silc_buffer_free(idp); @@ -2362,20 +2624,61 @@ SILC_CLIENT_CMD_FUNC(getkey) silc_client_command_free(cmd); } +/* Command SERVICE. Negotiates service agreement with server. */ +/* XXX incomplete */ + +SILC_CLIENT_CMD_FUNC(service) +{ + SilcClientCommandContext cmd = (SilcClientCommandContext)context; + SilcClientConnection conn = cmd->conn; + SilcBuffer buffer; + char *name; + + if (!cmd->conn) { + SILC_NOT_CONNECTED(cmd->client, cmd->conn); + COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED); + goto out; + } + + if (cmd->argc < 2) { + SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, + "Usage: /SERVICE [] [-pubkey]"); + COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); + goto out; + } + + 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(cmd->client, conn->sock, SILC_PACKET_COMMAND, + NULL, 0, NULL, NULL, buffer->data, + buffer->len, TRUE); + silc_buffer_free(buffer); + + /* Notify application */ + COMMAND(SILC_STATUS_OK); + + out: + silc_client_command_free(cmd); +} + /* Register a new command indicated by the `command' to the SILC client. The `name' is optional command name. If provided the command may be searched using the silc_client_command_find by that name. The `command_function' is the function to be called when the command is executed, and the `command_reply_function' is the function to be - called after the server has sent reply back to the command. + called after the server has sent reply back to the command. The `ident' is optional identifier for the command. If non-zero the `command_reply_function' for the command type `command' will be - called only if the command reply sent by server includes the + called only if the command reply sent by server includes the command identifier `ident'. Application usually does not need it and set it to zero value. */ -bool silc_client_command_register(SilcClient client, +SilcBool silc_client_command_register(SilcClient client, SilcCommand command, const char *name, SilcCommandCb command_function, @@ -2402,7 +2705,7 @@ bool silc_client_command_register(SilcClient client, `command_function' and command reply function `command_reply_function'. Returns TRUE if the command was found and unregistered. */ -bool silc_client_command_unregister(SilcClient client, +SilcBool silc_client_command_unregister(SilcClient client, SilcCommand command, SilcCommandCb command_function, SilcCommandCb command_reply_function, @@ -2444,7 +2747,7 @@ SILC_CLIENT_CMD_FUNC(connect) } if (cmd->argc < 2) { - SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, + SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Usage: /CONNECT []"); COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; @@ -2456,13 +2759,15 @@ SILC_CLIENT_CMD_FUNC(connect) } if (cmd->argc == 3) - buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 2, - 1, cmd->argv[1], + buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, + ++conn->cmd_ident, 2, + 1, cmd->argv[1], strlen(cmd->argv[1]), 2, port, 4); else - buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 1, - 1, cmd->argv[1], + buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, + ++conn->cmd_ident, 1, + 1, cmd->argv[1], strlen(cmd->argv[1])); silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 0, NULL, NULL, buffer->data, buffer->len, TRUE); @@ -2477,7 +2782,7 @@ SILC_CLIENT_CMD_FUNC(connect) /* CLOSE command. Close server connection to the remote server */ - + SILC_CLIENT_CMD_FUNC(close) { SilcClientCommandContext cmd = (SilcClientCommandContext)context; @@ -2493,7 +2798,7 @@ SILC_CLIENT_CMD_FUNC(close) } if (cmd->argc < 2) { - SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, + SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Usage: /CLOSE []"); COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; @@ -2505,13 +2810,15 @@ SILC_CLIENT_CMD_FUNC(close) } if (cmd->argc == 3) - buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 2, - 1, cmd->argv[1], + buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, + ++conn->cmd_ident, 2, + 1, cmd->argv[1], strlen(cmd->argv[1]), 2, port, 4); else - buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 1, - 1, cmd->argv[1], + buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, + ++conn->cmd_ident, 1, + 1, cmd->argv[1], strlen(cmd->argv[1])); silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 0, NULL, NULL, buffer->data, buffer->len, TRUE); @@ -2523,7 +2830,7 @@ SILC_CLIENT_CMD_FUNC(close) out: silc_client_command_free(cmd); } - + /* SHUTDOWN command. Shutdowns the server. */ SILC_CLIENT_CMD_FUNC(shutdown) @@ -2537,7 +2844,7 @@ SILC_CLIENT_CMD_FUNC(shutdown) } /* Send the command */ - silc_client_command_send(cmd->client, cmd->conn, + silc_client_command_send(cmd->client, cmd->conn, SILC_COMMAND_PRIV_SHUTDOWN, 0, 0); /* Notify application */ @@ -2552,10 +2859,10 @@ SILC_CLIENT_CMD_FUNC(shutdown) void silc_client_commands_register(SilcClient client) { - silc_list_init(client->internal->commands, struct SilcClientCommandStruct, + silc_list_init(client->internal->commands, struct SilcClientCommandStruct, next); - SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 3); + 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); @@ -2571,8 +2878,8 @@ void silc_client_commands_register(SilcClient client) 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", 4); - SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 5); + 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); @@ -2581,6 +2888,7 @@ void silc_client_commands_register(SilcClient client) 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); SILC_CLIENT_CMD(connect, PRIV_CONNECT, "CONNECT", 3); SILC_CLIENT_CMD(close, PRIV_CLOSE, "CLOSE", 3); @@ -2617,6 +2925,7 @@ void silc_client_commands_unregister(SilcClient client) SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE"); SILC_CLIENT_CMDU(users, USERS, "USERS"); SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY"); + SILC_CLIENT_CMDU(service, SERVICE, "SERVICE"); SILC_CLIENT_CMDU(connect, PRIV_CONNECT, "CONNECT"); SILC_CLIENT_CMDU(close, PRIV_CLOSE, "CLOSE"); @@ -2656,7 +2965,7 @@ void silc_client_command_process(SilcClient client, /* Get arguments */ args = silc_command_get_args(payload); - + /* Get the command */ command = silc_command_get(payload); switch (command) { @@ -2711,7 +3020,7 @@ void silc_client_command_process_whois(SilcClient client, silc_command_get_ident(payload), 1, 11, buffer->data, buffer->len); silc_client_packet_send(client, sock, SILC_PACKET_COMMAND_REPLY, - NULL, 0, NULL, NULL, packet->data, + NULL, 0, NULL, NULL, packet->data, packet->len, TRUE); silc_buffer_free(packet); silc_buffer_free(buffer);