+Mon Jan 21 19:07:53 EET 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * Removed the SilcClientCommandDestructor from the client
+ libary, it is not needed anymore. Affected files are
+ lib/silcclient/silcapi.h, command[_reply].[ch],
+ client_notify, idlist.c.
+
+ * Fixed GETKEY command to first resolve client, and then
+ resolve the server only if the client was not found, instead
+ of resolving both at the same time. Affected file is
+ lib/silcclient/command.c.
+
+ * Added silc_client_start_key_exchange_cb and lookup the
+ remote hostname and IP address before starting the key
+ exchange with server. The affected file is
+ lib/silcclient/client.c.
+
+ * The server's public key is now saved using the IP address
+ of the server and not the servername for the filename.
+ The hostname public key filename is checked as an fall back
+ method if the IP address based filename is not found.
+
+ Fixed the GETKEY command to save the fetched server key
+ in correct filename.
+
+ Print the remote server's hostname now when new key is
+ received during connection process. Affected file is
+ irssi/src/silc/core/client_ops.c.
+
+ * Return always our own public key to the client if it asks
+ for it with GETKEY command. Affected file silcd/command.c.
+
+ * Removed the use_auto_addr variable from default config
+ file since it was in wrong section. Affected file is
+ irssi/src/config.
+
+ * Fixed TOPIC_CHANGE notification to not route it when it
+ was sent using silc_server_send_notify_to_channel function.
+ Affected file silcd/command.c.
+
+ * Fixed silc_server_send_notify_kicked to send the kicker's
+ Client ID also, it was missing. Affected files are
+ silcd/command.c, silcd/packet_send.[ch].
+
Thu Jan 17 18:59:11 EET 2002 Pekka Riikonen <priikone@silcnet.org>
* Do not save client history information in SERVER_SIGNOFF.
TODO/bugs in Irssi SILC client
==============================
- o GETKEY server will save the serverkey to the same filename as the
- connected server and thus destroys the key.
-
- o GETKEY server will show first, "there is no such nickname".
-
o Add local command to switch the channel's private key when channel has
several private keys. Currently sending channel messages with many
keys is not possible because changing the key is not possible by the
o Remove the assert from silc_client_file_send.
- o Having @ in nickname will crash the client after changing the nickname
- back without the @.
-
o The PRIVATE_MESSAGE_KEY packet is not handled (it is implemented
though). This should be added and perhaps new client operation
should be added to notify application that it was received and
set the key only if application wishes to set (accept the key) it.
- o should /nick nick and /nick Nick cause the Nick to be Nick@host becase
- it used to be nick??
-
o When changing own nickname and there exists a same nickname the library
can give the client now nickname in format nick@host. This is new
behaviour and maybe should be removed. The changer should always
get the one it wants and not have the formatted nickname.
- o Remove the command destructor all together from the client, it is
- not needed and its usage is buggy when the context is registered
- to multiple pending commands.
-
o Additions to do after protocol version 1.1:
o Fix the NICK_CHANGE notify handling not to create new entry
o removing other's modes on channel seems to be possible due to some
cumode bug.
- o Topic notifications seem to go double times occasionally to a channel.
-
o Add hashed passwords to silcd.conf file.
o Backup router related issues
payload MAC and not alone by packet MAC. To be included in protocol
version 1.1.
+ 8. Remove the administrative commands from the protocol all together.
+ It does not make sense for the protocol to define how a server is
+ reconnected or shutdown, since they are implementation and
+ configuration issues. Besides protocol provides only limited set of
+ administrative commands and cannot define all that one could imagine.
+ To be included in protocol version 1.1.
+
TODO After 1.0
==============
use_msgs_window = "no";
autocreate_windows = "no";
autocreate_query_level = "none";
- use_auto_addr = "no";
};
"fe-text" = { topicbar = "no"; mail_counter = "yes"; indent = "8"; };
};
static void
silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
- SilcSocketType conn_type, unsigned char *pk,
- uint32 pk_len, SilcSKEPKType pk_type,
+ const char *name, SilcSocketType conn_type,
+ unsigned char *pk, uint32 pk_len,
+ SilcSKEPKType pk_type,
SilcVerifyPublicKey completion, void *context);
void silc_say(SilcClient client, SilcClientConnection conn,
unsigned char *pk;
uint32 pk_len;
GetkeyContext getkey;
+ char *name;
if (!success)
return;
getkey->client = client;
getkey->conn = conn;
getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
-
- silc_verify_public_key_internal(client, conn,
+
+ name = (id_type == SILC_ID_CLIENT ?
+ ((SilcClientEntry)entry)->nickname :
+ ((SilcServerEntry)entry)->server_name);
+
+ silc_verify_public_key_internal(client, conn, name,
(id_type == SILC_ID_CLIENT ?
SILC_SOCKET_TYPE_CLIENT :
SILC_SOCKET_TYPE_SERVER),
va_end(vp);
}
-/* Internal routine to verify public key. If the `completion' is provided
- it will be called to indicate whether public was verified or not. */
-
typedef struct {
SilcClient client;
SilcClientConnection conn;
char *filename;
char *entity;
+ char *entity_name;
unsigned char *pk;
uint32 pk_len;
SilcSKEPKType pk_type;
verify->completion(FALSE, verify->context);
printformat_module("fe-common/silc", NULL, NULL,
- MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD, verify->entity);
+ MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
+ verify->entity_name ? verify->entity_name :
+ verify->entity);
}
silc_free(verify->filename);
silc_free(verify->entity);
+ silc_free(verify->entity_name);
silc_free(verify->pk);
silc_free(verify);
}
+/* Internal routine to verify public key. If the `completion' is provided
+ it will be called to indicate whether public was verified or not. For
+ server/router public key this will check for filename that includes the
+ remote host's IP address and remote host's hostname. */
+
static void
silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
- SilcSocketType conn_type, unsigned char *pk,
- uint32 pk_len, SilcSKEPKType pk_type,
+ const char *name, SilcSocketType conn_type,
+ unsigned char *pk, uint32 pk_len,
+ SilcSKEPKType pk_type,
SilcVerifyPublicKey completion, void *context)
{
int i;
- char file[256], filename[256], *fingerprint, *babbleprint, *format;
+ char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
+ char *fingerprint, *babbleprint, *format;
struct passwd *pw;
struct stat st;
char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
}
memset(filename, 0, sizeof(filename));
+ memset(filename2, 0, sizeof(filename2));
memset(file, 0, sizeof(file));
if (conn_type == SILC_SOCKET_TYPE_SERVER ||
conn_type == SILC_SOCKET_TYPE_ROUTER) {
- snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
- conn->sock->ip, conn->sock->port);
- snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
- pw->pw_dir, entity, file);
+ if (!name) {
+ snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
+ conn->sock->ip, conn->sock->port);
+ snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
+ pw->pw_dir, entity, file);
+
+ snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
+ conn->sock->hostname, conn->sock->port);
+ snprintf(filename2, sizeof(filename2) - 1, "%s/.silc/%skeys/%s",
+ pw->pw_dir, entity, file);
+
+ ipf = filename;
+ hostf = filename2;
+ } else {
+ snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
+ name, conn->sock->port);
+ snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
+ pw->pw_dir, entity, file);
+
+ ipf = filename;
+ }
} else {
/* Replace all whitespaces with `_'. */
fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
pw->pw_dir, entity, file);
silc_free(fingerprint);
+
+ ipf = filename;
}
/* Take fingerprint of the public key */
verify = silc_calloc(1, sizeof(*verify));
verify->client = client;
verify->conn = conn;
- verify->filename = strdup(filename);
+ verify->filename = strdup(ipf);
verify->entity = strdup(entity);
+ verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
+ (name ? strdup(name) : strdup(conn->sock->hostname))
+ : NULL);
verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
memcpy(verify->pk, pk, pk_len);
verify->pk_len = pk_len;
verify->context = context;
/* Check whether this key already exists */
- if (stat(filename, &st) < 0) {
+ if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
/* Key does not exist, ask user to verify the key and save it */
printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
- SILCTXT_PUBKEY_RECEIVED, entity);
+ SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
+ verify->entity_name : entity);
printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
unsigned char *encpk;
uint32 encpk_len;
- /* Load the key file */
- if (!silc_pkcs_load_public_key(filename, &public_key,
- SILC_PKCS_FILE_PEM))
- if (!silc_pkcs_load_public_key(filename, &public_key,
- SILC_PKCS_FILE_BIN)) {
- printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
- SILCTXT_PUBKEY_RECEIVED, entity);
- printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
- SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
- printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
- SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
- printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
- SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
- format = format_get_text("fe-common/silc", NULL, NULL, NULL,
- SILCTXT_PUBKEY_ACCEPT_ANYWAY);
- keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
- format, 0, verify);
- g_free(format);
- silc_free(fingerprint);
- return;
- }
-
+ /* Load the key file, try for both IP filename and hostname filename */
+ if (!silc_pkcs_load_public_key(ipf, &public_key,
+ SILC_PKCS_FILE_PEM) &&
+ !silc_pkcs_load_public_key(ipf, &public_key,
+ SILC_PKCS_FILE_BIN) &&
+ (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
+ SILC_PKCS_FILE_PEM) &&
+ !silc_pkcs_load_public_key(hostf, &public_key,
+ SILC_PKCS_FILE_BIN)))) {
+ printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
+ SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
+ verify->entity_name : entity);
+ printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
+ SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
+ printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
+ SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
+ printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
+ SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
+ format = format_get_text("fe-common/silc", NULL, NULL, NULL,
+ SILCTXT_PUBKEY_ACCEPT_ANYWAY);
+ keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
+ format, 0, verify);
+ g_free(format);
+ silc_free(fingerprint);
+ return;
+ }
+
/* Encode the key data */
encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
if (!encpk) {
printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
- SILCTXT_PUBKEY_RECEIVED, entity);
+ SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
+ verify->entity_name : entity);
printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
/* Compare the keys */
if (memcmp(encpk, pk, encpk_len)) {
printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
- SILCTXT_PUBKEY_RECEIVED, entity);
+ SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
+ verify->entity_name : entity);
printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
uint32 pk_len, SilcSKEPKType pk_type,
SilcVerifyPublicKey completion, void *context)
{
- silc_verify_public_key_internal(client, conn, conn_type, pk,
+ silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
pk_len, pk_type,
completion, context);
}
server->conn = conn;
fd = g_io_channel_unix_get_fd(net_sendbuffer_handle(server->handle));
- if (!silc_client_start_key_exchange(silc_client, conn, fd)) {
- /* some internal error occured */
- server_disconnect(SERVER(server));
- signal_stop();
- return;
- }
+ silc_client_start_key_exchange(silc_client, conn, fd);
server->isnickflag = isnickflag_func;
server->ischannel = ischannel_func;
idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
/* Send notify about topic change to all clients on the channel */
- silc_server_send_notify_to_channel(server, NULL, channel, TRUE,
+ silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
SILC_NOTIFY_TYPE_TOPIC_SET, 2,
idp->data, idp->len,
channel->topic, strlen(channel->topic));
silc_server_send_notify_kicked(server, server->router->connection,
server->server_type == SILC_ROUTER ?
TRUE : FALSE, channel,
- target_client->id, comment);
+ target_client->id, client->id, comment);
if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
/* Re-generate channel key */
uint32 tmp_len, pklen;
SilcBuffer pk = NULL;
SilcIdType id_type;
+ SilcPublicKey public_key;
SILC_LOG_DEBUG(("Start"));
/* The client is locally connected, just get the public key and
send it back. If they key does not exist then do not send it,
send just OK reply */
- if (!client->data.public_key) {
+ public_key = client->data.public_key;
+ if (!public_key) {
pkdata = NULL;
pklen = 0;
} else {
- tmp = silc_pkcs_public_key_encode(client->data.public_key, &tmp_len);
+ tmp = silc_pkcs_public_key_encode(public_key, &tmp_len);
pk = silc_buffer_alloc(4 + tmp_len);
silc_buffer_pull_tail(pk, SILC_BUFFER_END(pk));
silc_buffer_format(pk,
}
/* If they key does not exist then do not send it, send just OK reply */
- if (!server_entry->data.public_key) {
+ public_key = (!server_entry->data.public_key ?
+ (server_entry == server->id_entry ? server->public_key :
+ NULL) : server_entry->data.public_key);
+ if (!public_key) {
pkdata = NULL;
pklen = 0;
} else {
- tmp = silc_pkcs_public_key_encode(server_entry->data.public_key,
- &tmp_len);
+ tmp = silc_pkcs_public_key_encode(public_key, &tmp_len);
pk = silc_buffer_alloc(4 + tmp_len);
silc_buffer_pull_tail(pk, SILC_BUFFER_END(pk));
silc_buffer_format(pk,
bool broadcast,
SilcChannelEntry channel,
SilcClientID *client_id,
+ SilcClientID *kicker,
char *comment)
{
- SilcBuffer idp;
+ SilcBuffer idp1;
+ SilcBuffer idp2;
- idp = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+ idp1 = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+ idp2 = silc_id_payload_encode((void *)kicker, SILC_ID_CLIENT);
silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id,
- SILC_ID_CHANNEL, SILC_NOTIFY_TYPE_KICKED,
- comment ? 2 : 1, idp->data, idp->len,
- comment, comment ? strlen(comment) : 0);
- silc_buffer_free(idp);
+ SILC_ID_CHANNEL, SILC_NOTIFY_TYPE_KICKED, 3,
+ idp1->data, idp1->len,
+ comment, comment ? strlen(comment) : 0,
+ idp2->data, idp2->len);
+ silc_buffer_free(idp1);
+ silc_buffer_free(idp2);
}
/* Send KILLED notify type. This tells that the `client_id' client was
bool broadcast,
SilcChannelEntry channel,
SilcClientID *client_id,
+ SilcClientID *kicker,
char *comment);
void silc_server_send_notify_killed(SilcServer server,
SilcSocketConnection sock,
return sock;
}
-/* Start SILC Key Exchange (SKE) protocol to negotiate shared secret
- key material between client and server. This function can be called
- directly if application is performing its own connecting and does not
- use the connecting provided by this library. This function is normally
- used only if the application performed the connecting outside the library.
- The library however may use this internally. */
+/* Socket hostname and IP lookup callback that is called before actually
+ starting the key exchange. The lookup is called from the function
+ silc_client_start_key_exchange. */
-bool silc_client_start_key_exchange(SilcClient client,
- SilcClientConnection conn,
- int fd)
+static void silc_client_start_key_exchange_cb(SilcSocketConnection sock,
+ void *context)
{
+ SilcClientConnection conn = (SilcClientConnection)context;
+ SilcClient client = conn->client;
SilcProtocol protocol;
SilcClientKEInternalContext *proto_ctx;
- void *context;
-
- /* Allocate new socket connection object */
- silc_socket_alloc(fd, SILC_SOCKET_TYPE_SERVER, (void *)conn, &conn->sock);
- /* Sometimes when doing quick reconnects the new socket may be same as
- the old one and there might be pending stuff for the old socket.
- If new one is same then those pending sutff might cause problems.
- Make sure they do not do that. */
- silc_schedule_task_del_by_fd(client->schedule, fd);
-
- conn->nickname = (client->nickname ? strdup(client->nickname) :
- strdup(client->username));
- conn->sock->hostname = strdup(conn->remote_host);
- conn->sock->ip = strdup(conn->remote_host);
+ if (!conn->sock->hostname)
+ conn->sock->hostname = strdup(conn->remote_host);
+ if (!conn->sock->ip)
+ conn->sock->ip = strdup(conn->remote_host);
conn->sock->port = conn->remote_port;
/* Allocate internal Key Exchange context. This is sent to the
if (!protocol) {
client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
"Error: Could not start key exchange protocol");
- return FALSE;
+ silc_net_close_connection(conn->sock->sock);
+ client->internal->ops->connect(client, conn, FALSE);
+ return;
}
conn->sock->protocol = protocol;
be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
later when outgoing data is available. */
context = (void *)client;
- SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(fd);
+ SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(conn->sock->sock);
/* Execute the protocol */
silc_protocol_execute(protocol, client->schedule, 0, 0);
- return TRUE;
+}
+
+/* Start SILC Key Exchange (SKE) protocol to negotiate shared secret
+ key material between client and server. This function can be called
+ directly if application is performing its own connecting and does not
+ use the connecting provided by this library. This function is normally
+ used only if the application performed the connecting outside the library.
+ The library however may use this internally. */
+
+void silc_client_start_key_exchange(SilcClient client,
+ SilcClientConnection conn,
+ int fd)
+{
+ /* Allocate new socket connection object */
+ silc_socket_alloc(fd, SILC_SOCKET_TYPE_SERVER, (void *)conn, &conn->sock);
+
+ /* Sometimes when doing quick reconnects the new socket may be same as
+ the old one and there might be pending stuff for the old socket.
+ If new one is same then those pending sutff might cause problems.
+ Make sure they do not do that. */
+ silc_schedule_task_del_by_fd(client->schedule, fd);
+
+ conn->nickname = (client->nickname ? strdup(client->nickname) :
+ strdup(client->username));
+
+ /* Resolve the remote hostname and IP address for our socket connection */
+ silc_socket_host_lookup(conn->sock, FALSE, silc_client_start_key_exchange_cb,
+ conn, client->schedule);
}
/* Callback called when error has occurred during connecting to the server.
silc_schedule_task_del(client->schedule, ctx->task);
silc_free(ctx);
- if (!silc_client_start_key_exchange(client, conn, fd)) {
- silc_net_close_connection(fd);
- client->internal->ops->connect(client, conn, FALSE);
- }
+ silc_client_start_key_exchange(client, conn, fd);
}
/* Second part of the connecting to the server. This executed
SilcCommandStatus status;
unsigned char *tmp = silc_argument_get_arg_type(reply->args, 1, NULL);
SILC_GET16_MSB(status, tmp);
- if (status != SILC_STATUS_OK) {
- silc_socket_free(res->sock);
- return;
- }
+ if (status != SILC_STATUS_OK)
+ goto out;
}
silc_client_notify_by_server(res->context, res->sock, res->packet);
- silc_socket_free(res->sock);
-}
-
-/* Destructor for the pending command callback */
-static void silc_client_notify_by_server_destructor(void *context)
-{
- SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
+ out:
+ silc_socket_free(res->sock);
silc_packet_context_free(res->packet);
silc_free(res);
}
silc_client_command_send(client, conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1, 3, idp->data, idp->len);
silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
- silc_client_notify_by_server_destructor,
silc_client_notify_by_server_pending, res);
silc_buffer_free(idp);
}
void silc_client_command_pending(SilcClientConnection conn,
SilcCommand reply_cmd,
uint16 ident,
- SilcClientPendingDestructor destructor,
SilcCommandCb callback,
void *context)
{
reply->ident = ident;
reply->context = context;
reply->callback = callback;
- reply->destructor = destructor;
silc_dlist_add(conn->pending_commands, reply);
}
if (r->reply_cmd == command && r->ident == ident) {
ctx->context = r->context;
ctx->callback = r->callback;
- ctx->destructor = r->destructor;
ctx->ident = ident;
return TRUE;
}
return ctx;
}
-/* Pending command destructor. */
-
-static void silc_client_command_destructor(void *context)
-{
- silc_client_command_free((SilcClientCommandContext)context);
-}
-
/* Command WHOIS. This command is used to query information about
specific user. */
if there were no errors returned by the server. */
silc_client_command_pending(conn, SILC_COMMAND_NICK,
cmd->conn->cmd_ident,
- silc_client_command_destructor,
silc_client_command_nick_change,
silc_client_command_dup(cmd));
cmd->pending = TRUE;
- return;
out:
silc_client_command_free(cmd);
pending command. */
silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
conn->cmd_ident,
- silc_client_command_destructor,
silc_client_command_invite,
silc_client_command_dup(cmd));
cmd->pending = 1;
- return;
+ goto out;
}
} else {
invite = cmd->argv[2];
pending command. */
silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
conn->cmd_ident,
- silc_client_command_destructor,
silc_client_command_kill,
silc_client_command_dup(cmd));
cmd->pending = 1;
- return;
+ goto out;
}
/* Send the KILL command to the server */
/* Register a pending callback that will actually remove the killed
client from our cache. */
silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident,
- NULL, silc_client_command_kill_remove,
+ silc_client_command_kill_remove,
silc_client_command_dup(cmd));
out:
pending command. */
silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
conn->cmd_ident,
- silc_client_command_destructor,
silc_client_command_cumode,
silc_client_command_dup(cmd));
cmd->pending = 1;
- return;
+ goto out;
}
/* Get the current mode */
char *nickname = NULL;
SilcBuffer idp, buffer;
+ SILC_LOG_DEBUG(("Start"));
+
if (!cmd->conn) {
SILC_NOT_CONNECTED(cmd->client, cmd->conn);
COMMAND_ERROR;
goto out;
}
- if (cmd->pending) {
- SilcClientCommandReplyContext reply =
- (SilcClientCommandReplyContext)context2;
- SilcCommandStatus status;
- unsigned char *tmp = silc_argument_get_arg_type(reply->args, 1, NULL);
- SILC_GET16_MSB(status, tmp);
-
- if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
- status == SILC_STATUS_ERR_NO_SUCH_SERVER) {
- SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
- silc_client_command_status_message(status));
- COMMAND_ERROR;
- goto out;
- }
- }
-
/* Parse the typed nickname. */
if (client->internal->params->nickname_parse)
client->internal->params->nickname_parse(cmd->argv[1], &nickname);
server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
if (!server_entry) {
- if (cmd->pending) {
+ /* No. what ever user wants we don't have it, so resolve it. We
+ will first try to resolve the client, and if that fails then
+ we'll try to resolve the server. */
+
+ 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_dup(cmd));
+ cmd->pending = 1;
+ goto out;
+ } else {
+ SilcClientCommandReplyContext reply =
+ (SilcClientCommandReplyContext)context2;
+ SilcCommandStatus status;
+ unsigned char *tmp = silc_argument_get_arg_type(reply->args, 1, NULL);
+ SILC_GET16_MSB(status, tmp);
+
+ /* If nickname was not found, then resolve the server. */
+ if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
+ /* This sends the IDENTIFY command to resolve the server. */
+ 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,
+ 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_dup(cmd));
+ goto out;
+ }
+
+ /* If server was not found, then we've resolved both nickname and
+ server and did not find anybody. */
+ if (status == SILC_STATUS_ERR_NO_SUCH_SERVER) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
+ silc_client_command_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
+ silc_client_command_status_message(status));
+ COMMAND_ERROR;
+ goto out;
+ }
+
COMMAND_ERROR;
goto out;
}
-
- /* No. what ever user wants we don't have it, so resolve it. We
- will try to resolve both client and server, one of them is
- bound to be wrong. */
-
- /* This will send the IDENTIFY command */
- 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_destructor,
- silc_client_command_getkey,
- silc_client_command_dup(cmd));
-
- /* This sends the IDENTIFY command to resolve the server. */
- 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,
- 2, cmd->argv[1], cmd->argv_lens[1]);
- silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
- conn->cmd_ident, NULL,
- silc_client_command_getkey,
- silc_client_command_dup(cmd));
-
- cmd->pending = 1;
- silc_free(nickname);
- return;
}
idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
typedef struct SilcClientCommandPendingStruct {
SilcCommand reply_cmd;
SilcCommandCb callback;
- SilcClientPendingDestructor destructor;
void *context;
uint16 ident;
struct SilcClientCommandPendingStruct *next;
void silc_client_command_##func(void *context, void *context2)
/* Executed pending command callback */
-#define SILC_CLIENT_PENDING_EXEC(ctx, cmd) \
-do { \
- if ((ctx)->callback) \
- (*ctx->callback)(ctx->context, ctx); \
-} while(0)
-
-/* Execute destructor for pending command */
-#define SILC_CLIENT_PENDING_DESTRUCTOR(ctx, cmd) \
+#define SILC_CLIENT_PENDING_EXEC(ctx, cmd) \
do { \
+ if ((ctx)->callback) \
+ (*ctx->callback)(ctx->context, ctx); \
silc_client_command_pending_del((ctx)->sock->user_data, (cmd), \
(ctx)->ident); \
- if (ctx->destructor) \
- (*ctx->destructor)(ctx->context); \
} while(0)
bool silc_client_command_register(SilcClient client,
{ STAT(NO_SUCH_NICK), "There was no such nickname" },
{ STAT(NO_SUCH_CHANNEL), "There was no such channel" },
- { STAT(NO_SUCH_SERVER), "No such server" },
+ { STAT(NO_SUCH_SERVER), "There was no such server" },
{ STAT(TOO_MANY_TARGETS), "Duplicate recipients. No message delivered" },
{ STAT(NO_RECIPIENT), "No recipient given" },
{ STAT(UNKNOWN_COMMAND), "Unknown command" },
out:
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
- SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
/* If we received notify for invalid ID we'll remove the ID if we
have it cached. */
out:
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
- SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOWAS);
silc_client_command_reply_free(cmd);
}
out:
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
- SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_IDENTIFY);
/* If we received notify for invalid ID we'll remove the ID if we
have it cached. */
/* Notify application */
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
COMMAND_REPLY((ARGS, conn->local_entry));
- SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_NICK);
silc_client_command_reply_free(cmd);
return;
out:
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
- SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_NICK);
silc_client_command_reply_free(cmd);
}
out:
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
- SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LIST);
silc_client_command_reply_free(cmd);
}
out:
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
- SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
silc_client_command_reply_free(cmd);
}
out:
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
- SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
silc_client_command_reply_free(cmd);
}
out:
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
- SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KILL);
silc_client_command_reply_free(cmd);
}
out:
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
- SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
silc_free(server_id);
silc_client_command_reply_free(cmd);
}
out:
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
- SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_PING);
silc_client_command_reply_free(cmd);
}
out:
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
- SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
silc_client_command_reply_free(cmd);
if (keyp)
out:
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
- SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
silc_client_command_reply_free(cmd);
}
out:
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
- SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_UMODE);
silc_client_command_reply_free(cmd);
}
out:
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
- SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
silc_client_command_reply_free(cmd);
}
out:
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
- SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
silc_client_command_reply_free(cmd);
}
out:
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
- SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
silc_client_command_reply_free(cmd);
}
out:
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
- SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SILCOPER);
silc_client_command_reply_free(cmd);
}
out:
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
- SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_OPER);
silc_client_command_reply_free(cmd);
}
out:
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
- SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CONNECT);
silc_client_command_reply_free(cmd);
}
out:
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
- SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_BAN);
silc_client_command_reply_free(cmd);
}
out:
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
- SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
silc_client_command_reply_free(cmd);
}
out:
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
- SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SHUTDOWN);
silc_client_command_reply_free(cmd);
}
out:
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
- SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
silc_client_command_reply_free(cmd);
}
information we will reprocess this command reply by re-calling this
USERS command reply callback. */
silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
- NULL, silc_client_command_reply_users, cmd);
+ silc_client_command_reply_users, cmd);
return;
} else {
channel = (SilcChannelEntry)id_cache->context;
command reply we will reprocess this command reply by re-calling this
USERS command reply callback. */
silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
- NULL, silc_client_command_reply_users, cmd);
+ silc_client_command_reply_users, cmd);
silc_buffer_free(res_cmd);
if (channel_id)
out:
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
- SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
silc_client_command_reply_free(cmd);
silc_free(channel_id);
if (client_id_list)
SILC_GET16_MSB(type, tmp + 2);
pk = tmp + 4;
- if (type != SILC_SKE_PK_TYPE_SILC) {
- COMMAND_REPLY_ERROR;
- goto out;
- }
-
- if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key)) {
- COMMAND_REPLY_ERROR;
- goto out;
- }
+ if (type == SILC_SKE_PK_TYPE_SILC)
+ if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
+ public_key = NULL;
}
id_type = silc_id_payload_get_type(idp);
out:
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
- SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_GETKEY);
if (idp)
silc_id_payload_free(idp);
if (public_key)
out:
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
- SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
/* If we received notify for invalid ID we'll remove the ID if we
have it cached. */
out:
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
- SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_IDENTIFY);
/* If we received notify for invalid ID we'll remove the ID if we
have it cached. */
out:
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
- SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
silc_free(server_id);
silc_client_command_reply_free(cmd);
}
SilcPacketContext *packet;
/* If defined this executes the pending command. */
- SilcClientPendingDestructor destructor;
SilcCommandCb callback;
void *context;
uint16 ident;
void *context;
char *nickname;
char *server;
- bool found;
} *GetClientInternal;
SILC_CLIENT_CMD_FUNC(get_client_callback)
i->nickname, i->server,
&clients_count);
if (clients) {
- i->completion(i->client, i->conn, clients,
- clients_count, i->context);
- i->found = TRUE;
+ i->completion(i->client, i->conn, clients, clients_count, i->context);
silc_free(clients);
- }
-}
-
-static void silc_client_get_client_destructor(void *context)
-{
- GetClientInternal i = (GetClientInternal)context;
-
- if (i->found == FALSE)
+ } else {
i->completion(i->client, i->conn, NULL, 0, i->context);
+ }
silc_free(i->nickname);
silc_free(i->server);
/* Add pending callback */
silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
- silc_client_get_client_destructor,
silc_client_command_get_client_callback,
(void *)i);
SilcBuffer client_id_list;
SilcGetClientCallback completion;
void *context;
- int found;
} *GetClientsByListInternal;
SILC_CLIENT_CMD_FUNC(get_clients_list_callback)
SilcBuffer client_id_list = i->client_id_list;
SilcClientEntry *clients = NULL;
uint32 clients_count = 0;
+ bool found = FALSE;
int c;
SILC_LOG_DEBUG(("Start"));
(clients_count + 1));
clients[clients_count] = (SilcClientEntry)id_cache->context;
clients_count++;
- i->found = TRUE;
+ found = TRUE;
}
silc_free(client_id);
silc_buffer_pull(client_id_list, idp_len);
}
- if (i->found) {
+ if (found) {
i->completion(i->client, i->conn, clients, clients_count, i->context);
silc_free(clients);
- }
-}
-
-static void silc_client_get_clients_list_destructor(void *context)
-{
- GetClientsByListInternal i = (GetClientsByListInternal)context;
-
- SILC_LOG_DEBUG(("Start"));
-
- if (i->found == FALSE)
+ } else {
i->completion(i->client, i->conn, NULL, 0, i->context);
+ }
if (i->client_id_list)
silc_buffer_free(i->client_id_list);
/* Process the applications request after reply has been received */
silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
- silc_client_get_clients_list_destructor,
silc_client_command_get_clients_list_callback,
(void *)in);
SilcClientID *client_id;
SilcGetClientCallback completion;
void *context;
- int found;
} *GetClientByIDInternal;
SILC_CLIENT_CMD_FUNC(get_client_by_id_callback)
SilcClientEntry entry;
/* Get the client */
- entry = silc_client_get_client_by_id(i->client, i->conn,
- i->client_id);
- if (entry) {
+ entry = silc_client_get_client_by_id(i->client, i->conn, i->client_id);
+ if (entry)
i->completion(i->client, i->conn, &entry, 1, i->context);
- i->found = TRUE;
- }
-}
-
-static void silc_client_get_client_by_id_destructor(void *context)
-{
- GetClientByIDInternal i = (GetClientByIDInternal)context;
-
- if (i->found == FALSE)
+ else
i->completion(i->client, i->conn, NULL, 0, i->context);
- if (i->client_id)
- silc_free(i->client_id);
+ silc_free(i->client_id);
silc_free(i);
}
/* Add pending callback */
silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
- silc_client_get_client_by_id_destructor,
silc_client_command_get_client_by_id_callback,
(void *)i);
}
SilcChannelID *channel_id;
SilcGetChannelCallback completion;
void *context;
- int found;
} *GetChannelByIDInternal;
SILC_CLIENT_CMD_FUNC(get_channel_by_id_callback)
SILC_LOG_DEBUG(("Start"));
/* Get the channel */
- entry = silc_client_get_channel_by_id(i->client, i->conn,
- i->channel_id);
+ entry = silc_client_get_channel_by_id(i->client, i->conn, i->channel_id);
if (entry) {
i->completion(i->client, i->conn, &entry, 1, i->context);
- i->found = TRUE;
- }
-}
-
-static void silc_client_get_channel_by_id_destructor(void *context)
-{
- GetChannelByIDInternal i = (GetChannelByIDInternal)context;
-
- if (i->found == FALSE)
+ } else {
i->completion(i->client, i->conn, NULL, 0, i->context);
+ }
silc_free(i->channel_id);
silc_free(i);
/* Add pending callback */
silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
- silc_client_get_channel_by_id_destructor,
silc_client_command_get_channel_by_id_callback,
(void *)i);
}
*
* SYNOPSIS
*
- * int silc_client_start_key_exchange(SilcClient client,
- * SilcClientConnection conn,
- * int fd);
+ * void silc_client_start_key_exchange(SilcClient client,
+ * SilcClientConnection conn,
+ * int fd);
*
* DESCRIPTION
*
* if the key exchange could not be started.
*
***/
-bool silc_client_start_key_exchange(SilcClient client,
+void silc_client_start_key_exchange(SilcClient client,
SilcClientConnection conn,
int fd);
SilcCommand command, uint16 ident,
uint32 argc, ...);
-/****f* silcclient/SilcClientAPI/SilcClientPendingDestructor
- *
- * SYNOPSIS
- *
- * typedef void (*SilcClientPendingDestructor)(void *context);
- *
- * DESCRIPTION
- *
- * Pending Command callback destructor. This is called after calling the
- * pending callback or if error occurs while processing the pending command.
- * If error occurs then the callback won't be called at all, and only this
- * destructor is called. The `context' is the context given for the function
- * silc_client_command_pending.
- *
- ***/
-typedef void (*SilcClientPendingDestructor)(void *context);
-
/****f* silcclient/SilcClientAPI/silc_client_command_pending
*
* SYNOPSIS
* void silc_client_command_pending(SilcClientConnection conn,
* SilcCommand reply_cmd,
* uint16 ident,
- * SilcClientPendingDestructor destructor,
* SilcCommandCb callback,
* void *context);
*
void silc_client_command_pending(SilcClientConnection conn,
SilcCommand reply_cmd,
uint16 ident,
- SilcClientPendingDestructor destructor,
SilcCommandCb callback,
void *context);
*
* DESCRIPTION
*
- * Asynchronouosly resolves the IP address of the hostname indicated
+ * Asynchronously resolves the IP address of the hostname indicated
* by the `host'. This function returns immediately, and the
* `completion' callback will be called after the resolving is
* completed.
*
* DESCRIPTION
*
- * Asynchronouosly resolves the hostname for the IP address indicated
+ * Asynchronously resolves the hostname for the IP address indicated
* by the `addr'. This function returns immediately, and the
* `completion' callback will be called after the resolving is
* completed.