+Sun Dec 9 19:18:41 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed the IDENTIFY command reply sending to chech better valid
+ clients. It was possible to send incomplete list of replies.
+ Affected file silcd/command.c.
+
+Sat Dec 8 15:58:31 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Added silc_client_command[s]_[un]register functions now to
+ dynamically register the commands in client library. Removed
+ the static table of commands. This allows the client library
+ to call commands without causing the application to know about
+ what commands library has called.
+
+ Removed the INFO command reply kludge to detect when the command
+ was called by library. Now library use its own command reply
+ function for INFO command.
+
+ Added function silc_client_command_call to call a command.
+ Application can use it to call command, not access the structure
+ directly.
+
+ Now all commands that are sent by the client library (not
+ explicitly sent by application) use own command reply functions.
+
+ Affected files around lib/silcclient/ and in
+ irssi/src/silc/core/.
+
+ * Fixed the WHOIS command reply sending to chech better valid
+ clients. It was possible to send incomplete list of replies.
+
+ Fixed the WHOIS and IDENTIFY to send the request to router
+ if normal server did not do it and did not find any results.
+
+ Affected file silcd/command.c.
+
+Thu Dec 6 17:21:06 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Moved the internal data from SilcClient context into its
+ own file, not accesible to application. Affected files
+ lib/silcclient/client.h and lib/silcclient/client_internal.h,
+ and other files in client library.
+
+Thu Dec 6 10:37:55 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Added doc/examples installation target in Makefile.am.pre.
+ A patch by salo.
+
+Tue Dec 4 17:43:19 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * If NO_SUCH_CLIENT_ID notify is received for WHOIS or IDENTIFY
+ commands the found client entry will be removed from the
+ cache, after notifying application about the error. Affected
+ file lib/silcclient/command_reply.c.
+
+ * Changed the /MSG to check for exact nickname user gave, and
+ not let `nick' match `nick@host' if it is only one found. Now,
+ user must type the exact nickname (like nick@host2) even if
+ there are no more than one same nicks found. This is to avoid
+ a possibility of sending nickname to wrong nickname since
+ `nick' could match `nick@host'. Affected file is
+ irssi/src/core/silc-servers.c.
+
Mon Dec 3 18:49:45 EET 2001 Pekka Riikonen <priikone@silcnet.org>
* Do not print "you are now server operator" or similar when
few options that you might want to use. Please refer to the rest of this
file for more generic installation instructions.
---with-gmp=PATH
+`--with-gmp=PATH'
If you wish to use GMP library for arbitrary precision arithmetic
library instead of using the MPI library included in the package, you can
give the --with-gmp=PATH option to the `configure'. The PATH is the path
to the GMP library in your system.
---disable-asm
+`--disable-asm'
If you have trouble compiling the assembler optimized code in the
package or does not want to use them, you can give the --disable-asm
option to the `configure' script. This will assure that assembler
optimized code is not compiled in.
---enable-debug
+`--enable-debug'
If you would like to enable the debugging for the compiled programs
you can give this option to the `configure'.
---disable-threads
+`--disable-threads'
If you do not want to compile the programs with multi threads support
you can give --disable-threads option. In this case all compiled programs
will work in single thread only.
---enable-ipv6
+`--enable-ipv6'
The `configure' will attempt to check for IPv6 support in your system.
However, if it fails, but you still want to compile in the IPv6 support
#
# Makefile.am
#
-# Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+# Author: Pekka Riikonen <priikone@silcnet.org>
#
# Copyright (C) 2000 - 2001 Pekka Riikonen
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
+# the Free Software Foundation; version 2 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
$(INSTALL_DATA) $(srcdir)/INSTALL $(docdir)/
$(INSTALL_DATA) $(srcdir)/TODO $(docdir)/
+examples-install:
+ -mkdir -p $(docdir)/examples/
+ $(INSTALL_DATA) $(srcdir)/doc/examples/README $(docdir)/examples/
+ $(INSTALL_DATA) $(srcdir)/doc/examples/silc* $(docdir)/examples/
+ $(INSTALL_DATA) $(srcdir)/doc/examples/cell* $(docdir)/examples/
+
etc-install:
-@if test '!' -f $(etcdir)/silcd.conf ; then \
$(INSTALL_DATA) $(srcdir)/doc/example_silcd.conf \
if SILC_DIST_CLIENT
install-data-hook: install-dirs sim-install doc-install etc-install
else
-install-data-hook: install-dirs generate-server-key sim-install doc-install etc-install
+install-data-hook: install-dirs generate-server-key sim-install doc-install examples-install etc-install
endif
TODO/bugs In SILC Client Library
================================
- o Process the NO_SUCH_CLIENT_ID for WHOIS and IDENTIFY, since it can
- be received for example after sending MSG to non-existent client.
- It actually should be done always when it is received and the old
- entry should be removed.
-
- Doing this now however causes that /msg nick might give "no such nick"
- for the first time, and then after the entry is removed /msg nick
- may actually to go any nick client, which is not desired behaviour.
- The /msg must be fixed to use the specific nickname user typed
- (nick must not match nick@host).
+ o N/A
TODO/bugs In SILC Server
than on Unix. Do it with threads on WIN32. The function works but
is not actually async currently.
- o Do not let the silcdefs.h lay around in distributions.
+
+TODO in SILC Protocol
+=====================
+
+ o Add "request parameters" or similar to the WHOIS command, which can
+ be used to request various parameters (something not returned by
+ standard WHOIS command) about clients (info that could be fetched
+ even from clients). Additional specification (or appendix) should
+ be done to define the payload and the parameters. It could be used
+ to make the WHOIS command support various search conditions as well.
+ This would be the way to extend the WHOIS command to support various
+ new features without always making the command incompatible to previous
+ version. To be included in protocol version 1.1.
+
+ o Re-define the Status Payload: it is now 16 bits, split it into two
+ 8 bits fields. First field includes status types from 0 - 9 and
+ 10 - n *if* it is not an list of errors. If it is list of errors then
+ the first field includes 1, 2 and/or 3, and the second field includes
+ the error status 10 - n. This way it is possible to send multiple
+ errors (list of errors) and we have a way to tell the receiver that
+ there will be other errors as well. The second field is used only
+ if there is list of errors. If normal status, or normal (single)
+ error status the second field is set to zero, and must be ignored.
+ Hence, the status works same way as now except for list of errors.
+ To be included in protocol version 1.1.
+
+ o Define that WHOIS and IDENTIFY commands must send list of errors
+ if multiple Client ID (or Channel ID and Server ID for IDENTIFY) was
+ requested and was not found. Each unfound entry must cause an error
+ command reply to the sender. Also define that errors must be sent
+ *after* sending successfully found entries (this way receiver may
+ ignore them). To be included in protocol version 1.1.
TODO After 1.0
silc_free(client_id);
}
}
+ break;
}
if (!success)
{
SilcClientEntry client_entry;
- /* Identify command is used only internally by the client library
- but it still might send some interesting stuff for user interface
- so let's print errors. */
-
if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
/* Print the unknown nick for user */
unsigned char *tmp =
silc_free(client_id);
}
}
+ break;
}
+
+ break;
}
- break;
case SILC_COMMAND_WHOWAS:
{
char *nickname = NULL;
if (!clients_count) {
- printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Unknown nick: %s", rec->nick);
+ printtext(NULL, NULL, MSGLEVEL_CLIENTERROR,
+ "%s: There is no such client", rec->nick);
} else {
if (clients_count > 1) {
silc_parse_userfqdn(rec->nick, &nickname, NULL);
nickname, rec->nick,
&clients_count);
if (!clients) {
- printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Unknown nick: %s",
- rec->nick);
+ printtext(NULL, NULL, MSGLEVEL_CLIENTERROR,
+ "%s: There is no such client", rec->nick);
silc_free(nickname);
goto out;
}
target = clients[0];
+ /* Still check for exact math for nickname, this compares the
+ real (formatted) nickname and the nick (maybe formatted) that
+ use gave. This is to assure that `nick' does not match
+ `nick@host'. */
+ if (strcasecmp(rec->nick, clients[0]->nickname)) {
+ printtext(NULL, NULL, MSGLEVEL_CLIENTERROR,
+ "%s: There is no such client", rec->nick);
+ goto out;
+ }
+
/* Send the private message */
silc_client_send_private_message(client, conn, target, 0,
rec->msg, strlen(rec->msg),
unsigned char **argv;
uint32 *argv_lens, *argv_types;
char *data, *tmpcmd;
- SilcClientCommand *cmd;
+ SilcClientCommand cmd;
SilcClientCommandContext ctx;
g_return_if_fail(server != NULL);
tmpcmd = g_strdup(command);
g_strup(tmpcmd);
- cmd = silc_client_command_find(tmpcmd);
+ cmd = silc_client_command_find(silc_client, tmpcmd);
g_free(tmpcmd);
if (cmd == NULL)
return;
ctx->argv_types = argv_types;
/* Execute command */
- (*cmd->cb)(ctx, NULL);
+ silc_client_command_call(cmd, ctx);
}
/* Generic command function to call any SILC command directly. */
SilcCommand command,
SilcCommandStatus status,
uint32 arg_type,
- unsigned char *arg,
+ const unsigned char *arg,
uint32 arg_len);
static bool
silc_server_command_pending_error_check(SilcServerCommandContext cmd,
SilcCommand command,
SilcCommandStatus status,
uint32 arg_type,
- unsigned char *arg,
+ const unsigned char *arg,
uint32 arg_len)
{
SilcBuffer buffer;
silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
SilcClientEntry *clients,
uint32 clients_count,
- int count)
+ int count,
+ const char *nickname,
+ SilcClientID **client_ids)
{
SilcServer server = cmd->server;
char *tmp;
- int i, k, len;
+ int i, k, len, valid_count;
SilcBuffer packet, idp, channels;
SilcClientEntry entry;
SilcCommandStatus status;
unsigned char *fingerprint;
SilcSocketConnection hsock;
- len = 0;
- for (i = 0; i < clients_count; i++)
+ /* Process only valid clients and ignore those that are not registered. */
+ valid_count = 0;
+ for (i = 0; i < clients_count; i++) {
if (clients[i]->data.status & SILC_IDLIST_STATUS_REGISTERED)
- len++;
+ valid_count++;
+ else
+ clients[i] = NULL;
+ }
- if (len == 0 && clients_count) {
- entry = clients[0];
- if (entry->nickname) {
+ if (!valid_count) {
+ /* No valid clients found, send error reply */
+ if (nickname) {
silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
SILC_STATUS_ERR_NO_SUCH_NICK,
- 3, entry->nickname,
- strlen(entry->nickname));
- } else {
- SilcBuffer idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
+ 3, nickname, strlen(nickname));
+ } else if (client_ids && client_ids[0]) {
+ SilcBuffer idp = silc_id_payload_encode(client_ids[0], SILC_ID_CLIENT);
silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
2, idp->data, idp->len);
silc_buffer_free(idp);
}
-
return;
}
- status = SILC_STATUS_OK;
- if (len > 1)
+ /* Start processing found clients. */
+ if (valid_count > 1)
status = SILC_STATUS_LIST_START;
+ else
+ status = SILC_STATUS_OK;
for (i = 0, k = 0; i < clients_count; i++) {
entry = clients[i];
+ if (!entry)
+ continue;
- if (!(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
- if (clients_count == 1) {
- if (entry->nickname) {
- silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
- SILC_STATUS_ERR_NO_SUCH_NICK,
- 3, entry->nickname,
- strlen(entry->nickname));
- } else {
- SilcBuffer idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
- silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
- SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
- 2, idp->data, idp->len);
- silc_buffer_free(idp);
- }
- }
+#if 1
+ /* XXX REMOVE */
+ /* Sanity check, however these should never fail. However, as
+ this sanity check has been added here they have failed. */
+ if (!entry->nickname || !entry->username || !entry->userinfo) {
+ SILC_LOG_ERROR(("********* if (!entry->nickname || !entry->username "
+ "|| !entry->userinfo) triggered: should have not!"));
continue;
}
+#endif
if (k >= 1)
status = SILC_STATUS_LIST_ITEM;
-
- if (clients_count > 1 && k == clients_count - 1)
+ if (valid_count > 1 && k == valid_count - 1)
status = SILC_STATUS_LIST_END;
-
if (count && k - 1 == count)
status = SILC_STATUS_LIST_END;
- if (count && k - 1 > count)
- break;
-
- /* Sanity check, however these should never fail. However, as
- this sanity check has been added here they have failed. */
- if (!entry->nickname || !entry->username || !entry->userinfo)
- continue;
-
/* Send WHOIS reply */
idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
tmp = silc_argument_get_first_arg(cmd->args, NULL);
}
}
+static void
+silc_server_command_whois_send_router(SilcServerCommandContext cmd)
+{
+ SilcServer server = cmd->server;
+ SilcBuffer tmpbuf;
+ uint16 old_ident;
+
+ old_ident = silc_command_get_ident(cmd->payload);
+ silc_command_set_ident(cmd->payload, ++server->cmd_ident);
+ tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+
+ /* Send WHOIS command to our router */
+ silc_server_packet_send(server, (SilcSocketConnection)
+ server->router->connection,
+ SILC_PACKET_COMMAND, cmd->packet->flags,
+ tmpbuf->data, tmpbuf->len, TRUE);
+
+ /* Reprocess this packet after received reply from router */
+ silc_server_command_pending(server, SILC_COMMAND_WHOIS,
+ silc_command_get_ident(cmd->payload),
+ silc_server_command_destructor,
+ silc_server_command_whois,
+ silc_server_command_dup(cmd));
+ cmd->pending = TRUE;
+ silc_command_set_ident(cmd->payload, old_ident);
+ silc_buffer_free(tmpbuf);
+}
+
static int
silc_server_command_whois_process(SilcServerCommandContext cmd)
{
Since nicknames can be expanded into many clients we need to send it
to router. If the WHOIS included only client ID's we will check them
first locally since we just might have them. */
- if (nick && !client_id_count &&
- cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
- server->server_type == SILC_SERVER && !cmd->pending &&
+ if (nick && !client_id_count && cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
+ server->server_type == SILC_SERVER && !cmd->pending &&
!server->standalone) {
- SilcBuffer tmpbuf;
- uint16 old_ident;
-
- old_ident = silc_command_get_ident(cmd->payload);
- silc_command_set_ident(cmd->payload, ++server->cmd_ident);
- tmpbuf = silc_command_payload_encode_payload(cmd->payload);
-
- /* Send WHOIS command to our router */
- silc_server_packet_send(server, (SilcSocketConnection)
- server->router->connection,
- SILC_PACKET_COMMAND, cmd->packet->flags,
- tmpbuf->data, tmpbuf->len, TRUE);
-
- /* Reprocess this packet after received reply from router */
- silc_server_command_pending(server, SILC_COMMAND_WHOIS,
- silc_command_get_ident(cmd->payload),
- silc_server_command_destructor,
- silc_server_command_whois,
- silc_server_command_dup(cmd));
- cmd->pending = TRUE;
-
- silc_command_set_ident(cmd->payload, old_ident);
-
- silc_buffer_free(tmpbuf);
+ silc_server_command_whois_send_router(cmd);
ret = -1;
goto out;
}
clients = silc_realloc(clients, sizeof(*clients) *
(clients_count + 1));
clients[clients_count++] = entry;
+ } else {
+ /* If we are normal server and did not send the request first to router
+ do it now, since we do not have the Client ID information. */
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
+ server->server_type == SILC_SERVER && !cmd->pending &&
+ !server->standalone) {
+ silc_server_command_whois_send_router(cmd);
+ ret = -1;
+ goto out;
+ }
}
}
} else {
+ /* Find by nickname */
if (!silc_idlist_get_clients_by_hash(server->local_list,
nick, server->md5hash,
&clients, &clients_count))
}
if (!clients) {
+ /* If we are normal server and did not send the request first to router
+ do it now, since we do not have the information. */
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
+ server->server_type == SILC_SERVER && !cmd->pending &&
+ !server->standalone) {
+ silc_server_command_whois_send_router(cmd);
+ ret = -1;
+ goto out;
+ }
+
/* Such client(s) really does not exist in the SILC network. */
if (!client_id_count) {
silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
/* Send the command reply */
silc_server_command_whois_send_reply(cmd, clients, clients_count,
- count);
+ count, nick, client_id);
out:
if (client_id_count) {
/* We will take only clients that are not valid anymore. They are the
ones that are not registered anymore but still have a ID. They
have disconnected us, and thus valid for WHOWAS. */
- if (entry->data.status & SILC_IDLIST_STATUS_REGISTERED)
- continue;
- if (entry->id == NULL)
+ if (entry->data.status & SILC_IDLIST_STATUS_REGISTERED || !entry->id)
continue;
if (count && i - 1 == count)
if (clients_count > 2)
status = SILC_STATUS_LIST_ITEM;
-
if (clients_count > 1 && i == clients_count - 1)
status = SILC_STATUS_LIST_END;
/* Sanity check, however these should never fail. However, as
this sanity check has been added here they have failed. */
- if (!entry->nickname || !entry->username)
+ if (!entry->nickname || !entry->username || !entry->userinfo) {
+ SILC_LOG_ERROR(("********* if (!entry->nickname || !entry->username "
+ "|| !entry->userinfo) triggered: should have not!"));
continue;
+ }
+
+#if 1
+ /* XXX REMOVE */
+ /* Sanity check, however these should never fail. However, as
+ this sanity check has been added here they have failed. */
+ if (!entry->nickname || !entry->username) {
+ SILC_LOG_ERROR(("********* if (!entry->nickname || !entry->username) "
+ "triggered: should have not!"));
+ continue;
+ }
+#endif
/* Send WHOWAS reply */
idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
tmp = silc_argument_get_first_arg(cmd->args, NULL);
-
memset(uh, 0, sizeof(uh));
memset(nh, 0, sizeof(nh));
******************************************************************************/
-static bool
+static void
+silc_server_command_identify_send_router(SilcServerCommandContext cmd)
+{
+ SilcServer server = cmd->server;
+ SilcBuffer tmpbuf;
+ uint16 old_ident;
+
+ old_ident = silc_command_get_ident(cmd->payload);
+ silc_command_set_ident(cmd->payload, ++server->cmd_ident);
+ tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+
+ /* Send IDENTIFY command to our router */
+ silc_server_packet_send(server, (SilcSocketConnection)
+ server->router->connection,
+ SILC_PACKET_COMMAND, cmd->packet->flags,
+ tmpbuf->data, tmpbuf->len, TRUE);
+
+ /* Reprocess this packet after received reply from router */
+ silc_server_command_pending(server, SILC_COMMAND_IDENTIFY,
+ silc_command_get_ident(cmd->payload),
+ silc_server_command_destructor,
+ silc_server_command_identify,
+ silc_server_command_dup(cmd));
+ cmd->pending = TRUE;
+ silc_command_set_ident(cmd->payload, old_ident);
+ silc_buffer_free(tmpbuf);
+}
+
+static int
silc_server_command_identify_parse(SilcServerCommandContext cmd,
SilcClientEntry **clients,
uint32 *clients_count,
uint32 *servers_count,
SilcChannelEntry **channels,
uint32 *channels_count,
- uint32 *count,
- bool *names)
+ uint32 *count)
{
SilcServer server = cmd->server;
unsigned char *tmp;
tmp = silc_argument_get_arg_type(cmd->args, 5, &len);
if (!tmp) {
/* No ID, get the names. */
- *names = TRUE;
+
+ /* If we are normal server and have not resolved information from
+ router yet, do so now. */
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
+ server->server_type == SILC_SERVER && !cmd->pending &&
+ !server->standalone) {
+ silc_server_command_identify_send_router(cmd);
+ return -1;
+ }
/* Try to get nickname@server. */
tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
silc_free(nick_server);
if (!(*clients)) {
+ /* the nickname does not exist, send error reply */
silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
SILC_STATUS_ERR_NO_SUCH_NICK,
3, tmp, strlen(tmp));
- return FALSE;
+ return 0;
}
}
}
if (!(*servers)) {
+ /* the server does not exist, send error reply */
silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
SILC_STATUS_ERR_NO_SUCH_SERVER,
3, tmp, strlen(tmp));
- return FALSE;
+ return 0;
}
}
}
if (!(*channels)) {
+ /* The channel does not exist, send error reply */
silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
SILC_STATUS_ERR_NO_SUCH_CHANNEL,
3, tmp, strlen(tmp));
- return FALSE;
+ return 0;
}
}
if (!(*clients) && !(*servers) && !(*channels)) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- return FALSE;
+ return 0;
}
} else {
/* Command includes ID, we must use that. Also check whether the command
has more than one ID set - take them all. */
- *names = FALSE;
/* Take all ID's from the command packet */
for (i = 0; i < argc; i++) {
silc_free(*clients);
silc_free(*servers);
silc_free(*channels);
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- return FALSE;
+ silc_server_command_send_status_reply(
+ cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ return 0;
}
id = silc_id_payload_get_id(idp);
(*clients_count + 1));
(*clients)[(*clients_count)++] = (SilcClientEntry)entry;
} else {
- silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
+ /* If we are normal server and have not resolved information from
+ router yet, do so now. */
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
+ server->server_type == SILC_SERVER && !cmd->pending &&
+ !server->standalone) {
+ silc_server_command_identify_send_router(cmd);
+ silc_free(*clients);
+ silc_free(*servers);
+ silc_free(*channels);
+ return -1;
+ } else {
+ silc_server_command_send_status_data(
+ cmd, SILC_COMMAND_IDENTIFY,
SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
- 2, tmp, len);
- error = TRUE;
+ 2, tmp, len);
+ error = TRUE;
+ }
}
break;
(*servers_count + 1));
(*servers)[(*servers_count)++] = (SilcServerEntry)entry;
} else {
- silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
- SILC_STATUS_ERR_NO_SUCH_SERVER_ID,
- 2, tmp, len);
- error = TRUE;
+ /* If we are normal server and have not resolved information from
+ router yet, do so now. */
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
+ server->server_type == SILC_SERVER && !cmd->pending &&
+ !server->standalone) {
+ silc_server_command_identify_send_router(cmd);
+ silc_free(*clients);
+ silc_free(*servers);
+ silc_free(*channels);
+ return -1;
+ } else {
+ silc_server_command_send_status_data(
+ cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_SERVER_ID,
+ 2, tmp, len);
+ error = TRUE;
+ }
}
break;
(*channels_count + 1));
(*channels)[(*channels_count)++] = (SilcChannelEntry)entry;
} else {
- silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
- SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
- 2, tmp, len);
- error = TRUE;
+ /* If we are normal server and have not resolved information from
+ router yet, do so now. */
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
+ server->server_type == SILC_SERVER && !cmd->pending &&
+ !server->standalone) {
+ silc_server_command_identify_send_router(cmd);
+ silc_free(*clients);
+ silc_free(*servers);
+ silc_free(*channels);
+ return -1;
+ } else {
+ silc_server_command_send_status_data(
+ cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
+ 2, tmp, len);
+ error = TRUE;
+ }
}
break;
}
else
*count = 0;
- return TRUE;
+ return 1;
}
/* Checks that all mandatory fields in client entry are present. If not
int count)
{
SilcServer server = cmd->server;
- int i, k, len;
+ int i, k, len, valid_count;
SilcBuffer packet, idp;
SilcCommandStatus status;
uint16 ident = silc_command_get_ident(cmd->payload);
if (clients) {
SilcClientEntry entry;
- len = 0;
- for (i = 0; i < clients_count; i++)
+ /* Process only valid entries. */
+ valid_count = 0;
+ for (i = 0; i < clients_count; i++) {
if (clients[i]->data.status & SILC_IDLIST_STATUS_REGISTERED)
- len++;
+ valid_count++;
+ else
+ clients[i] = NULL;
+ }
+
+ if (!valid_count) {
+ /* No valid entries found at all, just send error */
+ unsigned char *tmp;
- if (len == 0 && clients_count) {
- entry = clients[0];
- if (entry->nickname) {
+ tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+ if (tmp) {
silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
SILC_STATUS_ERR_NO_SUCH_NICK,
- 3, entry->nickname,
- strlen(entry->nickname));
+ 3, tmp, strlen(tmp));
} else {
- SilcBuffer idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
+ tmp = silc_argument_get_arg_type(cmd->args, 5, (uint32 *)&len);
silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
- 2, idp->data, idp->len);
- silc_buffer_free(idp);
+ 2, tmp, len);
}
-
return;
}
+ /* Process all valid client entries and send command replies */
+
if (len > 1)
status = SILC_STATUS_LIST_START;
for (i = 0, k = 0; i < clients_count; i++) {
entry = clients[i];
-
- if (!(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
- if (clients_count == 1) {
- SilcBuffer idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
- silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
- SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
- 2, idp->data, idp->len);
- silc_buffer_free(idp);
- }
+ if (!entry)
continue;
- }
-
+
if (k >= 1)
status = SILC_STATUS_LIST_ITEM;
- if (clients_count > 1 && k == clients_count - 1
+ if (valid_count > 1 && k == valid_count - 1
&& !servers_count && !channels_count)
status = SILC_STATUS_LIST_END;
if (count && k - 1 == count)
status = SILC_STATUS_LIST_END;
if (count && k - 1 > count)
break;
-
+
/* Send IDENTIFY reply */
+
idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
-
memset(uh, 0, sizeof(uh));
memset(nh, 0, sizeof(nh));
-
strncat(nh, entry->nickname, strlen(entry->nickname));
if (!strchr(entry->nickname, '@')) {
strncat(nh, "@", 1);
server->server_name, len);
}
}
-
+
if (!entry->username) {
packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
status, ident, 2,
}
}
- status = (status == SILC_STATUS_LIST_ITEM ?
- SILC_STATUS_LIST_ITEM : SILC_STATUS_OK);
-
if (servers) {
SilcServerEntry entry;
}
}
- status = (status == SILC_STATUS_LIST_ITEM ?
- SILC_STATUS_LIST_ITEM : SILC_STATUS_OK);
-
if (channels) {
SilcChannelEntry entry;
static int
silc_server_command_identify_process(SilcServerCommandContext cmd)
{
- SilcServer server = cmd->server;
uint32 count = 0;
int ret = 0;
SilcClientEntry *clients = NULL;
SilcServerEntry *servers = NULL;
SilcChannelEntry *channels = NULL;
uint32 clients_count = 0, servers_count = 0, channels_count = 0;
- bool names;
/* Parse the IDENTIFY request */
- if (!silc_server_command_identify_parse(cmd,
- &clients, &clients_count,
- &servers, &servers_count,
- &channels, &channels_count,
- &count, &names))
- return 0;
-
- /* Send the IDENTIFY request to the router only if it included nickname.
- Since nicknames can be expanded into many clients we need to send it
- to router. If the IDENTIFY included only client ID's we will check them
- first locally since we just might have them. */
- if (names && cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
- server->server_type == SILC_SERVER && !cmd->pending &&
- !server->standalone) {
- SilcBuffer tmpbuf;
- uint16 old_ident;
-
- old_ident = silc_command_get_ident(cmd->payload);
- silc_command_set_ident(cmd->payload, ++server->cmd_ident);
- tmpbuf = silc_command_payload_encode_payload(cmd->payload);
-
- /* Send IDENTIFY command to our router */
- silc_server_packet_send(server, (SilcSocketConnection)
- server->router->connection,
- SILC_PACKET_COMMAND, cmd->packet->flags,
- tmpbuf->data, tmpbuf->len, TRUE);
-
- /* Reprocess this packet after received reply from router */
- silc_server_command_pending(server, SILC_COMMAND_IDENTIFY,
- silc_command_get_ident(cmd->payload),
- silc_server_command_destructor,
- silc_server_command_identify,
- silc_server_command_dup(cmd));
- cmd->pending = TRUE;
-
- silc_command_set_ident(cmd->payload, old_ident);
-
- silc_buffer_free(tmpbuf);
- ret = -1;
- goto out;
- }
+ ret = silc_server_command_identify_parse(cmd,
+ &clients, &clients_count,
+ &servers, &servers_count,
+ &channels, &channels_count,
+ &count);
+ if (ret < 1)
+ return ret;
/* Check that all mandatory fields are present and request those data
from the server who owns the client if necessary. */
silc_free(clients);
silc_free(servers);
silc_free(channels);
-
return ret;
}
endif
EXTRA_DIST = \
- silcdefs.h.in *.h
+ bitmove.h \
+ clientlibincludes.h \
+ silcincludes.h \
+ silcwin32.h \
+ version.h \
+ version_internal.h \
+ silcdefs.h.in
new_client = silc_calloc(1, sizeof(*new_client));
new_client->application = application;
- new_client->ops = ops;
- new_client->silc_client_version = strdup(silc_version);
- new_client->params = silc_calloc(1, sizeof(*new_client->params));
+
+ new_client->internal = silc_calloc(1, sizeof(*new_client->internal));
+ new_client->internal->ops = ops;
+ new_client->internal->params =
+ silc_calloc(1, sizeof(*new_client->internal->params));
+ new_client->internal->silc_client_version = strdup(silc_version);
if (params)
- memcpy(new_client->params, params, sizeof(*params));
+ memcpy(new_client->internal->params, params, sizeof(*params));
- if (!new_client->params->task_max)
- new_client->params->task_max = 200;
+ if (!new_client->internal->params->task_max)
+ new_client->internal->params->task_max = 200;
- if (!new_client->params->rekey_secs)
- new_client->params->rekey_secs = 3600;
+ if (!new_client->internal->params->rekey_secs)
+ new_client->internal->params->rekey_secs = 3600;
- if (!new_client->params->connauth_request_secs)
- new_client->params->connauth_request_secs = 2;
+ if (!new_client->internal->params->connauth_request_secs)
+ new_client->internal->params->connauth_request_secs = 2;
- new_client->params->
- nickname_format[sizeof(new_client->params->nickname_format) - 1] = 0;
+ new_client->internal->params->
+ nickname_format[sizeof(new_client->internal->
+ params->nickname_format) - 1] = 0;
return new_client;
}
if (client->rng)
silc_rng_free(client->rng);
- silc_free(client->silc_client_version);
- silc_free(client->params);
+ silc_free(client->internal->params);
+ silc_free(client->internal->silc_client_version);
+ silc_free(client->internal);
silc_free(client);
}
}
SILC_LOG_DEBUG(("Initializing client"));
/* Initialize hash functions for client to use */
- silc_hash_alloc("md5", &client->md5hash);
- silc_hash_alloc("sha1", &client->sha1hash);
+ silc_hash_alloc("md5", &client->internal->md5hash);
+ silc_hash_alloc("sha1", &client->internal->sha1hash);
/* Initialize none cipher */
- silc_cipher_alloc("none", &client->none_cipher);
+ silc_cipher_alloc("none", &client->internal->none_cipher);
/* Initialize random number generator */
client->rng = silc_rng_alloc();
silc_client_protocols_register();
/* Initialize the scheduler */
- client->schedule = silc_schedule_init(client->params->task_max ?
- client->params->task_max : 200);
+ client->schedule =
+ silc_schedule_init(client->internal->params->task_max ?
+ client->internal->params->task_max : 200);
if (!client->schedule)
return FALSE;
+ /* Register commands */
+ silc_client_commands_register(client);
+
return TRUE;
}
silc_schedule_uninit(client->schedule);
silc_client_protocols_unregister();
+ silc_client_commands_unregister(client);
SILC_LOG_DEBUG(("Client stopped"));
}
conn->ftp_sessions = silc_dlist_init();
/* Add the connection to connections table */
- for (i = 0; i < client->conns_count; i++)
- if (client->conns && !client->conns[i]) {
- client->conns[i] = conn;
+ for (i = 0; i < client->internal->conns_count; i++)
+ if (client->internal->conns && !client->internal->conns[i]) {
+ client->internal->conns[i] = conn;
return conn;
}
- client->conns = silc_realloc(client->conns, sizeof(*client->conns)
- * (client->conns_count + 1));
- client->conns[client->conns_count] = conn;
- client->conns_count++;
+ client->internal->conns =
+ silc_realloc(client->internal->conns, sizeof(*client->internal->conns)
+ * (client->internal->conns_count + 1));
+ client->internal->conns[client->internal->conns_count] = conn;
+ client->internal->conns_count++;
return conn;
}
{
int i;
- for (i = 0; i < client->conns_count; i++)
- if (client->conns[i] == conn) {
+ for (i = 0; i < client->internal->conns_count; i++)
+ if (client->internal->conns[i] == conn) {
silc_idcache_free(conn->client_cache);
silc_idcache_free(conn->channel_cache);
silc_dlist_uninit(conn->ftp_sessions);
silc_free(conn);
- client->conns[i] = NULL;
+ client->internal->conns[i] = NULL;
}
}
{
int i;
- if (!client->sockets) {
- client->sockets = silc_calloc(1, sizeof(*client->sockets));
- client->sockets[0] = silc_socket_dup(sock);
- client->sockets_count = 1;
+ if (!client->internal->sockets) {
+ client->internal->sockets =
+ silc_calloc(1, sizeof(*client->internal->sockets));
+ client->internal->sockets[0] = silc_socket_dup(sock);
+ client->internal->sockets_count = 1;
return;
}
- for (i = 0; i < client->sockets_count; i++) {
- if (client->sockets[i] == NULL) {
- client->sockets[i] = silc_socket_dup(sock);
+ for (i = 0; i < client->internal->sockets_count; i++) {
+ if (client->internal->sockets[i] == NULL) {
+ client->internal->sockets[i] = silc_socket_dup(sock);
return;
}
}
- client->sockets = silc_realloc(client->sockets, sizeof(*client->sockets) *
- (client->sockets_count + 1));
- client->sockets[client->sockets_count] = silc_socket_dup(sock);
- client->sockets_count++;
+ client->internal->sockets =
+ silc_realloc(client->internal->sockets,
+ sizeof(*client->internal->sockets) *
+ (client->internal->sockets_count + 1));
+ client->internal->sockets[client->internal->sockets_count] =
+ silc_socket_dup(sock);
+ client->internal->sockets_count++;
}
/* Deletes listener socket from the listener sockets table. */
{
int i;
- if (!client->sockets)
+ if (!client->internal->sockets)
return;
- for (i = 0; i < client->sockets_count; i++) {
- if (client->sockets[i] == sock) {
+ for (i = 0; i < client->internal->sockets_count; i++) {
+ if (client->internal->sockets[i] == sock) {
silc_socket_free(sock);
- client->sockets[i] = NULL;
+ client->internal->sockets[i] = NULL;
return;
}
}
conn = silc_client_add_connection(client, host, port, context);
- client->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
- "Connecting to port %d of server %s", port, host);
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
+ "Connecting to port %d of server %s", port, host);
/* Allocate internal context for connection process. This is
needed as we are doing async connecting. */
&protocol, (void *)proto_ctx,
silc_client_connect_to_server_second);
if (!protocol) {
- client->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "Error: Could not start key exchange protocol");
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Error: Could not start key exchange protocol");
return FALSE;
}
conn->sock->protocol = protocol;
(SilcClientKEInternalContext *)context;
SilcClient client = (SilcClient)ctx->client;
- client->ops->connect(client, ctx->sock->user_data, FALSE);
+ client->internal->ops->connect(client, ctx->sock->user_data, FALSE);
silc_free(ctx);
}
if (opt != 0) {
if (ctx->tries < 2) {
/* Connection failed but lets try again */
- client->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "Could not connect to server %s: %s",
- ctx->host, strerror(opt));
- client->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
- "Connecting to port %d of server %s resumed",
- ctx->port, ctx->host);
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Could not connect to server %s: %s",
+ ctx->host, strerror(opt));
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
+ "Connecting to port %d of server %s resumed",
+ ctx->port, ctx->host);
/* Unregister old connection try */
silc_schedule_unset_listen_fd(client->schedule, fd);
ctx->tries++;
} else {
/* Connection failed and we won't try anymore */
- client->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "Could not connect to server %s: %s",
- ctx->host, strerror(opt));
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Could not connect to server %s: %s",
+ ctx->host, strerror(opt));
silc_schedule_unset_listen_fd(client->schedule, fd);
silc_net_close_connection(fd);
silc_schedule_task_del(client->schedule, ctx->task);
silc_free(ctx);
/* Notify application of failure */
- client->ops->connect(client, conn, FALSE);
+ client->internal->ops->connect(client, conn, FALSE);
silc_client_del_connection(client, conn);
}
return;
if (!silc_client_start_key_exchange(client, conn, fd)) {
silc_net_close_connection(fd);
- client->ops->connect(client, conn, FALSE);
+ client->internal->ops->connect(client, conn, FALSE);
}
}
/* Resolve the authentication method to be used in this connection. The
completion callback is called after the application has resolved
the authentication method. */
- client->ops->get_auth_method(client, sock->user_data, sock->hostname,
- sock->port, silc_client_resolve_auth_method,
- proto_ctx);
+ client->internal->ops->get_auth_method(client, sock->user_data,
+ sock->hostname,
+ sock->port,
+ silc_client_resolve_auth_method,
+ proto_ctx);
}
/* Authentication method resolving callback. Application calls this function
- after we've called the client->ops->get_auth_method client operation
- to resolve the authentication method. We will continue the executiong
- of the protocol in this function. */
+ after we've called the client->internal->ops->get_auth_method
+ client operation to resolve the authentication method. We will continue
+ the executiong of the protocol in this function. */
void silc_client_resolve_auth_method(bool success,
SilcProtocolAuthMeth auth_meth,
conn->remote_id_data_len = silc_id_get_len(ctx->dest_id, SILC_ID_SERVER);
/* Register re-key timeout */
- conn->rekey->timeout = client->params->rekey_secs;
+ conn->rekey->timeout = client->internal->params->rekey_secs;
conn->rekey->context = (void *)client;
silc_schedule_task_add(client->schedule, conn->sock->sock,
silc_client_rekey_callback,
close the connection */
if (SILC_IS_DISCONNECTING(sock)) {
if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
- client->ops->disconnect(client, conn);
+ client->internal->ops->disconnect(client, conn);
silc_client_close_connection(client, sock, conn);
return;
}
SILC_LOG_DEBUG(("EOF from connection %d", sock->sock));
if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
- client->ops->disconnect(client, conn);
+ client->internal->ops->disconnect(client, conn);
silc_client_close_connection(client, sock, conn);
return;
}
msg = silc_calloc(message->len + 1, sizeof(char));
memcpy(msg, message->data, message->len);
- client->ops->say(client, sock->user_data, SILC_CLIENT_MESSAGE_AUDIT, msg);
+ client->internal->ops->say(client, sock->user_data,
+ SILC_CLIENT_MESSAGE_AUDIT, msg);
silc_free(msg);
SILC_SET_DISCONNECTED(sock);
msg = silc_calloc(message->len + 1, sizeof(char));
memcpy(msg, message->data, message->len);
- client->ops->say(client, sock->user_data, SILC_CLIENT_MESSAGE_AUDIT, msg);
+ client->internal->ops->say(client, sock->user_data,
+ SILC_CLIENT_MESSAGE_AUDIT, msg);
silc_free(msg);
}
if (connecting) {
/* Issue INFO comqmand to fetch the real server name and server information
and other stuff. */
+ silc_client_command_register(client, SILC_COMMAND_INFO, NULL, NULL,
+ silc_client_command_reply_info_i, 0,
+ ++conn->cmd_ident);
sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
- silc_client_send_command(client, conn, SILC_COMMAND_INFO,
- ++conn->cmd_ident, 1, 2, sidp->data, sidp->len);
+ silc_client_command_send(client, conn, SILC_COMMAND_INFO,
+ conn->cmd_ident, 1, 2, sidp->data, sidp->len);
silc_buffer_free(sidp);
/* Notify application of successful connection. We do it here now that
we've received the Client ID and are allowed to send traffic. */
- client->ops->connect(client, conn, TRUE);
+ client->internal->ops->connect(client, conn, TRUE);
}
}
SILC_GET32_MSB(failure, packet->buffer->data);
/* Notify application */
- client->ops->failure(client, sock->user_data, sock->protocol,
- (void *)failure);
+ client->internal->ops->failure(client, sock->user_data, sock->protocol,
+ (void *)failure);
}
}
connauth->timeout =
silc_schedule_task_add(client->schedule, conn->sock->sock,
silc_client_request_authentication_method_timeout,
- conn, client->params->connauth_request_secs, 0,
+ conn,
+ client->internal->params->connauth_request_secs, 0,
SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
}
/*
- client.h
+ client.h
Author: Pekka Riikonen <priikone@silcnet.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
+ the Free Software Foundation; version 2 of the License.
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
/* Forward declarations */
typedef struct SilcClientStruct *SilcClient;
+typedef struct SilcClientInternalStruct *SilcClientInternal;
typedef struct SilcClientConnectionStruct *SilcClientConnection;
typedef struct SilcClientPingStruct SilcClientPing;
typedef struct SilcClientAwayStruct SilcClientAway;
/* Main client structure. */
struct SilcClientStruct {
- /*
- * Public data. All the following pointers must be set by the allocator
- * of this structure.
- */
-
- /* Users's username, hostname and realname. */
- char *username;
- char *hostname;
- char *realname;
-
- /* Private and public key of the user. */
- SilcPKCS pkcs;
- SilcPublicKey public_key;
- SilcPrivateKey private_key;
-
- /* Application specific user data pointer. Client library does not
- touch this. */
- void *application;
-
- /*
- * Private data. Following pointers are used internally by the client
- * library and should be considered read-only fields.
- */
-
- /* All client operations that are implemented in the application. */
- SilcClientOperations *ops;
-
- /* Client Parameters */
- SilcClientParams *params;
-
- /* SILC client scheduler */
- SilcSchedule schedule;
+ char *username; /* Username, must be set by application */
+ char *hostname; /* hostname, must be set by application */
+ char *realname; /* Real name, must be set be application */
- /* Table of connections in client. All the connection data is saved here. */
- SilcClientConnection *conns;
- uint32 conns_count;
+ SilcPublicKey public_key; /* Public key of user, set by application */
+ SilcPrivateKey private_key; /* Private key of user, set by application */
+ SilcPKCS pkcs; /* PKCS allocated by application */
- /* Table of listenning sockets in client. Client can have listeners
- (like key agreement protocol server) and those sockets are saved here.
- This table is checked always if the connection object cannot be found
- from the `conns' table. */
- SilcSocketConnection *sockets;
- uint32 sockets_count;
-
- /* Generic cipher and hash objects. These can be used and referenced
- by the application as well. */
- SilcCipher none_cipher;
- SilcHash md5hash;
- SilcHash sha1hash;
- SilcHmac md5hmac;
- SilcHmac sha1hmac;
+ SilcSchedule schedule; /* Scheduler, automatically allocated by
+ the client library. */
/* Random Number Generator. Application should use this as its primary
random number generator. */
SilcRng rng;
- /* Client version. Used to compare to remote host's version strings. */
- char *silc_client_version;
+ /* Application specific user data pointer. Client library does not
+ touch this. This the context sent as argument to silc_client_alloc. */
+ void *application;
+
+ /* Internal data for client library. Application cannot access this
+ data at all. */
+ SilcClientInternal internal;
};
-/* Macros */
-
-/* Registers generic task for file descriptor for reading from network and
- writing to network. As being generic task the actual task is allocated
- only once and after that the same task applies to all registered fd's. */
-#define SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(fd) \
-do { \
- silc_schedule_task_add(client->schedule, (fd), \
- silc_client_packet_process, \
- context, 0, 0, \
- SILC_TASK_GENERIC, \
- SILC_TASK_PRI_NORMAL); \
-} while(0)
-
-#define SILC_CLIENT_SET_CONNECTION_FOR_INPUT(s, fd) \
-do { \
- silc_schedule_set_listen_fd((s), (fd), SILC_TASK_READ); \
-} while(0)
-
-#define SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(s, fd) \
-do { \
- silc_schedule_set_listen_fd((s), (fd), (SILC_TASK_READ | \
- SILC_TASK_WRITE)); \
-} while(0)
-
-/* Finds socket connection object by file descriptor */
-#define SILC_CLIENT_GET_SOCK(__x, __fd, __sock) \
-do { \
- int __i; \
- \
- for (__i = 0; __i < (__x)->conns_count; __i++) \
- if ((__x)->conns[__i] && \
- (__x)->conns[__i]->sock->sock == (__fd)) \
- break; \
- \
- if (__i >= (__x)->conns_count) { \
- (__sock) = NULL; \
- for (__i = 0; __i < (__x)->sockets_count; __i++) \
- if ((__x)->sockets[__i] && \
- (__x)->sockets[__i]->sock == (__fd)) \
- (__sock) = (__x)->sockets[__i]; \
- } else \
- (__sock) = (__x)->conns[__i]->sock; \
-} while(0)
-
-/* Check whether rekey protocol is active */
-#define SILC_CLIENT_IS_REKEY(sock) \
- (sock->protocol && sock->protocol->protocol && \
- sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)
-
-/* Prototypes (some of the prototypes are defined in the silcapi.h) */
-
-void silc_client_packet_send(SilcClient client,
- SilcSocketConnection sock,
- SilcPacketType type,
- void *dst_id,
- SilcIdType dst_id_type,
- SilcCipher cipher,
- SilcHmac hmac,
- unsigned char *data,
- uint32 data_len,
- int force_send);
-void silc_client_disconnected_by_server(SilcClient client,
- SilcSocketConnection sock,
- SilcBuffer message);
-void silc_client_error_by_server(SilcClient client,
- SilcSocketConnection sock,
- SilcBuffer message);
-void silc_client_receive_new_id(SilcClient client,
- SilcSocketConnection sock,
- SilcIDPayload idp);
-SilcChannelEntry silc_client_new_channel_id(SilcClient client,
- SilcSocketConnection sock,
- char *channel_name,
- uint32 mode,
- SilcIDPayload idp);
-void silc_client_save_channel_key(SilcClientConnection conn,
- SilcBuffer key_payload,
- SilcChannelEntry channel);
-void silc_client_receive_channel_key(SilcClient client,
- SilcSocketConnection sock,
- SilcBuffer packet);
-void silc_client_channel_message(SilcClient client,
- SilcSocketConnection sock,
- SilcPacketContext *packet);
-void silc_client_remove_from_channels(SilcClient client,
- SilcClientConnection conn,
- SilcClientEntry client_entry);
-void silc_client_replace_from_channels(SilcClient client,
- SilcClientConnection conn,
- SilcClientEntry old,
- SilcClientEntry newclient);
-void silc_client_process_failure(SilcClient client,
- SilcSocketConnection sock,
- SilcPacketContext *packet);
-void silc_client_key_agreement(SilcClient client,
- SilcSocketConnection sock,
- SilcPacketContext *packet);
-void silc_client_notify_by_server(SilcClient client,
- SilcSocketConnection sock,
- SilcPacketContext *packet);
-void silc_client_private_message(SilcClient client,
- SilcSocketConnection sock,
- SilcPacketContext *packet);
-void silc_client_connection_auth_request(SilcClient client,
- SilcSocketConnection sock,
- SilcPacketContext *packet);
-void silc_client_ftp(SilcClient client,
- SilcSocketConnection sock,
- SilcPacketContext *packet);
#endif
for (i = 0; i < iv_len; i++) channel->iv[i] =
silc_rng_get_byte(client->rng);
else
- silc_hash_make(client->md5hash, channel->iv, iv_len, channel->iv);
+ silc_hash_make(client->internal->md5hash, channel->iv, iv_len,
+ channel->iv);
/* Encode the channel payload. This also encrypts the message payload. */
payload = silc_channel_message_payload_encode(flags, data_len, data, iv_len,
message = silc_channel_message_get_data(res->payload, NULL);
/* Pass the message to application */
- client->ops->channel_message(client, conn, clients[0], channel,
- silc_channel_message_get_flags(res->payload),
- message);
+ client->internal->ops->channel_message(
+ client, conn, clients[0], channel,
+ silc_channel_message_get_flags(res->payload),
+ message);
}
out:
message = silc_channel_message_get_data(payload, NULL);
/* Pass the message to application */
- client->ops->channel_message(client, conn, chu->client, channel,
- silc_channel_message_get_flags(payload),
- message);
+ client->internal->ops->channel_message(
+ client, conn, chu->client, channel,
+ silc_channel_message_get_flags(payload),
+ message);
out:
if (id)
memcpy(channel->key, key, tmp_len);
if (!silc_cipher_alloc(cipher, &channel->channel_key)) {
- conn->client->ops->say(conn->client, conn, SILC_CLIENT_MESSAGE_AUDIT,
+ conn->client->internal->ops->say(
+ conn->client, conn,
+ SILC_CLIENT_MESSAGE_AUDIT,
"Cannot talk to channel: unsupported cipher %s",
cipher);
goto out;
/* Produce the key material */
keymat = silc_calloc(1, sizeof(*keymat));
if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
- client->md5hash, keymat)
+ client->internal->md5hash, keymat)
!= SILC_SKE_STATUS_OK)
return FALSE;
if (opt != 0) {
if (ctx->tries < 2) {
/* Connection failed but lets try again */
- client->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "Could not connect to client %s: %s",
- ctx->host, strerror(opt));
- client->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
- "Connecting to port %d of client %s resumed",
- ctx->port, ctx->host);
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Could not connect to client %s: %s",
+ ctx->host, strerror(opt));
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
+ "Connecting to port %d of client %s resumed",
+ ctx->port, ctx->host);
/* Unregister old connection try */
silc_schedule_unset_listen_fd(client->schedule, fd);
ctx->tries++;
} else {
/* Connection failed and we won't try anymore */
- client->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "Could not connect to client %s: %s",
- ctx->host, strerror(opt));
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Could not connect to client %s: %s",
+ ctx->host, strerror(opt));
silc_schedule_unset_listen_fd(client->schedule, fd);
silc_net_close_connection(fd);
silc_schedule_task_del(client->schedule, ctx->task);
O_RDWR | O_CREAT | O_EXCL);
if (session->fd < 0) {
/* Call monitor callback */
- session->client->ops->say(session->client, session->conn,
- SILC_CLIENT_MESSAGE_ERROR,
- "File `%s' open failed: %s", session->filepath,
- strerror(errno));
+ session->client->internal->ops->say(session->client, session->conn,
+ SILC_CLIENT_MESSAGE_ERROR,
+ "File `%s' open failed: %s",
+ session->filepath,
+ strerror(errno));
if (session->monitor)
(*session->monitor)(session->client, session->conn,
session->listener = silc_net_create_server(0, session->hostname);
if (session->listener < 0) {
SILC_LOG_DEBUG(("Could not create listener"));
- client->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "Cannot create listener on %s: %s",
- session->hostname, strerror(errno));
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Cannot create listener on %s: %s",
+ session->hostname, strerror(errno));
return SILC_CLIENT_FILE_ERROR;
}
session->port = silc_net_get_local_port(session->listener);
silc_dlist_add(conn->ftp_sessions, session);
/* Let the application know */
- client->ops->ftp(client, conn, client_entry,
- session->session_id, hostname, port);
+ client->internal->ops->ftp(client, conn, client_entry,
+ session->session_id, hostname, port);
if (hostname && port) {
session->hostname = strdup(hostname);
/*
- client_internal.h
+ client_internal.h
- Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+ Author: Pekka Riikonen <priikone@silcnet.org>
Copyright (C) 1997 - 2001 Pekka Riikonen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
+ the Free Software Foundation; version 2 of the License.
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
struct SilcClientAwayStruct *next;
};
-/* Protypes */
+/* Internal context for the client->internal pointer in the SilcClient. */
+struct SilcClientInternalStruct {
+ /* All client operations that are implemented by the application. */
+ SilcClientOperations *ops;
+
+ /* Client Parameters */
+ SilcClientParams *params;
+
+ /* Table of connections in client. All the connection data is saved here. */
+ SilcClientConnection *conns;
+ uint32 conns_count;
+
+ /* Table of listenning sockets in client. Client can have listeners
+ (like key agreement protocol server) and those sockets are saved here.
+ This table is checked always if the connection object cannot be found
+ from the `conns' table. */
+ SilcSocketConnection *sockets;
+ uint32 sockets_count;
+
+ /* Registered commands */
+ SilcList commands;
+
+ /* Generic cipher and hash objects. */
+ SilcCipher none_cipher;
+ SilcHash md5hash;
+ SilcHash sha1hash;
+ SilcHmac md5hmac;
+ SilcHmac sha1hmac;
+
+ /* Client version. Used to compare to remote host's version strings. */
+ char *silc_client_version;
+};
+
+/* Macros */
+
+/* Registers generic task for file descriptor for reading from network and
+ writing to network. As being generic task the actual task is allocated
+ only once and after that the same task applies to all registered fd's. */
+#define SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(fd) \
+do { \
+ silc_schedule_task_add(client->schedule, (fd), \
+ silc_client_packet_process, \
+ context, 0, 0, \
+ SILC_TASK_GENERIC, \
+ SILC_TASK_PRI_NORMAL); \
+} while(0)
+
+#define SILC_CLIENT_SET_CONNECTION_FOR_INPUT(s, fd) \
+do { \
+ silc_schedule_set_listen_fd((s), (fd), SILC_TASK_READ); \
+} while(0)
+
+#define SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(s, fd) \
+do { \
+ silc_schedule_set_listen_fd((s), (fd), (SILC_TASK_READ | \
+ SILC_TASK_WRITE)); \
+} while(0)
+
+/* Finds socket connection object by file descriptor */ \
+#define SILC_CLIENT_GET_SOCK(__x, __fd, __sock) \
+do { \
+ int __i; \
+ \
+ for (__i = 0; __i < (__x)->internal->conns_count; __i++) \
+ if ((__x)->internal->conns[__i] && \
+ (__x)->internal->conns[__i]->sock->sock == (__fd)) \
+ break; \
+ \
+ if (__i >= (__x)->internal->conns_count) { \
+ (__sock) = NULL; \
+ for (__i = 0; __i < (__x)->internal->sockets_count; __i++) \
+ if ((__x)->internal->sockets[__i] && \
+ (__x)->internal->sockets[__i]->sock == (__fd)) \
+ (__sock) = (__x)->internal->sockets[__i]; \
+ } else \
+ (__sock) = (__x)->internal->conns[__i]->sock; \
+} while(0)
+
+/* Check whether rekey protocol is active */
+#define SILC_CLIENT_IS_REKEY(sock) \
+ (sock->protocol && sock->protocol->protocol && \
+ sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)
+
+/* Prototypes */
SILC_TASK_CALLBACK_GLOBAL(silc_client_packet_process);
int silc_client_packet_send_real(SilcClient client,
void silc_client_ftp_session_free(SilcClientFtpSession session);
void silc_client_ftp_session_free_client(SilcClientConnection conn,
SilcClientEntry client_entry);
+void silc_client_packet_send(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketType type,
+ void *dst_id,
+ SilcIdType dst_id_type,
+ SilcCipher cipher,
+ SilcHmac hmac,
+ unsigned char *data,
+ uint32 data_len,
+ int force_send);
+void silc_client_disconnected_by_server(SilcClient client,
+ SilcSocketConnection sock,
+ SilcBuffer message);
+void silc_client_error_by_server(SilcClient client,
+ SilcSocketConnection sock,
+ SilcBuffer message);
+void silc_client_receive_new_id(SilcClient client,
+ SilcSocketConnection sock,
+ SilcIDPayload idp);
+SilcChannelEntry silc_client_new_channel_id(SilcClient client,
+ SilcSocketConnection sock,
+ char *channel_name,
+ uint32 mode,
+ SilcIDPayload idp);
+void silc_client_save_channel_key(SilcClientConnection conn,
+ SilcBuffer key_payload,
+ SilcChannelEntry channel);
+void silc_client_receive_channel_key(SilcClient client,
+ SilcSocketConnection sock,
+ SilcBuffer packet);
+void silc_client_channel_message(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+void silc_client_remove_from_channels(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry client_entry);
+void silc_client_replace_from_channels(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry old,
+ SilcClientEntry newclient);
+void silc_client_process_failure(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+void silc_client_key_agreement(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+void silc_client_notify_by_server(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+void silc_client_private_message(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+void silc_client_connection_auth_request(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+void silc_client_ftp(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
#endif
sock = silc_net_accept_connection(ke->fd);
if (sock < 0) {
- client->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
- "Could not accept key agreement connection: ",
- strerror(errno));
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
+ "Could not accept key agreement connection: ",
+ strerror(errno));
ke->client_entry->ke = NULL;
ke->completion(ke->client, ke->conn, ke->client_entry,
SILC_KEY_AGREEMENT_ERROR, NULL, ke->context);
/* Perform name and address lookups for the remote host. */
silc_net_check_host_by_sock(sock, &newsocket->hostname, &newsocket->ip);
if (!newsocket->hostname && !newsocket->ip) {
- client->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
- "Could not resolve the remote IP or hostname");
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
+ "Could not resolve the remote IP or hostname");
ke->client_entry->ke = NULL;
ke->completion(ke->client, ke->conn, ke->client_entry,
SILC_KEY_AGREEMENT_ERROR, NULL, ke->context);
ke->fd = silc_net_create_server(port, hostname);
if (ke->fd < 0) {
- client->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "Cannot create listener on %s on port %d: %s",
- (bindhost) ? bindhost:hostname, port, strerror(errno));
+ client->internal->ops->say(
+ client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Cannot create listener on %s on port %d: %s",
+ (bindhost) ? bindhost:hostname, port, strerror(errno));
completion(client, conn, client_entry, SILC_KEY_AGREEMENT_FAILURE,
NULL, context);
silc_free(ke);
if (opt != 0) {
if (ctx->tries < 2) {
/* Connection failed but lets try again */
- client->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "Could not connect to client %s: %s",
- ctx->host, strerror(opt));
- client->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
- "Connecting to port %d of client %s resumed",
- ctx->port, ctx->host);
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Could not connect to client %s: %s",
+ ctx->host, strerror(opt));
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
+ "Connecting to port %d of client %s resumed",
+ ctx->port, ctx->host);
/* Unregister old connection try */
silc_schedule_unset_listen_fd(client->schedule, fd);
ctx->tries++;
} else {
/* Connection failed and we won't try anymore */
- client->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "Could not connect to client %s: %s",
- ctx->host, strerror(opt));
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Could not connect to client %s: %s",
+ ctx->host, strerror(opt));
silc_schedule_unset_listen_fd(client->schedule, fd);
silc_net_close_connection(fd);
silc_schedule_task_del(client->schedule, ctx->task);
goto out;
/* Call the key_agreement client operation */
- ret = client->ops->key_agreement(client, conn, clients[0],
+ ret = client->internal->ops->key_agreement(
+ client, conn, clients[0],
silc_key_agreement_get_hostname(payload),
silc_key_agreement_get_port(payload),
&completion, &completion_context);
res->context = client;
res->sock = silc_socket_dup(conn->sock);
- silc_client_send_command(client, conn, SILC_COMMAND_WHOIS, ++conn->cmd_ident,
+ silc_client_command_register(client, SILC_COMMAND_WHOIS, NULL, NULL,
+ silc_client_command_reply_whois_i, 0,
+ ++conn->cmd_ident);
+ 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,
switch(type) {
case SILC_NOTIFY_TYPE_NONE:
/* Notify application */
- client->ops->notify(client, conn, type,
- silc_argument_get_arg_type(args, 1, NULL));
+ client->internal->ops->notify(client, conn, type,
+ silc_argument_get_arg_type(args, 1, NULL));
break;
case SILC_NOTIFY_TYPE_INVITE:
goto out;
/* Notify application */
- client->ops->notify(client, conn, type, channel, tmp, client_entry);
+ client->internal->ops->notify(client, conn, type, channel, tmp,
+ client_entry);
break;
case SILC_NOTIFY_TYPE_JOIN:
/* Notify application. The channel entry is sent last as this notify
is for channel but application don't know it from the arguments
sent by server. */
- client->ops->notify(client, conn, type, client_entry, channel);
+ client->internal->ops->notify(client, conn, type, client_entry, channel);
break;
case SILC_NOTIFY_TYPE_LEAVE:
/* Notify application. The channel entry is sent last as this notify
is for channel but application don't know it from the arguments
sent by server. */
- client->ops->notify(client, conn, type, client_entry, channel);
+ client->internal->ops->notify(client, conn, type, client_entry, channel);
break;
case SILC_NOTIFY_TYPE_SIGNOFF:
tmp = NULL;
/* Notify application */
- client->ops->notify(client, conn, type, client_entry, tmp);
+ client->internal->ops->notify(client, conn, type, client_entry, tmp);
/* Free data */
silc_client_del_client_entry(client, conn, client_entry);
/* Notify application. The channel entry is sent last as this notify
is for channel but application don't know it from the arguments
sent by server. */
- client->ops->notify(client, conn, type, silc_id_payload_get_type(idp),
- client_entry, tmp, channel);
+ client->internal->ops->notify(client, conn, type,
+ silc_id_payload_get_type(idp),
+ client_entry, tmp, channel);
silc_id_payload_free(idp);
break;
client_entry2);
/* Notify application */
- client->ops->notify(client, conn, type, client_entry, client_entry2);
+ client->internal->ops->notify(client, conn, type,
+ client_entry, client_entry2);
/* Free data */
silc_client_del_client_entry(client, conn, client_entry);
/* Notify application. The channel entry is sent last as this notify
is for channel but application don't know it from the arguments
sent by server. */
- client->ops->notify(client, conn, type, silc_id_payload_get_type(idp),
- client_entry, mode, NULL, tmp, channel);
+ client->internal->ops->notify(client, conn, type,
+ silc_id_payload_get_type(idp),
+ client_entry, mode, NULL, tmp, channel);
silc_id_payload_free(idp);
break;
/* Notify application. The channel entry is sent last as this notify
is for channel but application don't know it from the arguments
sent by server. */
- client->ops->notify(client, conn, type, client_entry, mode,
- client_entry2, channel);
+ client->internal->ops->notify(client, conn, type,
+ client_entry, mode,
+ client_entry2, channel);
break;
case SILC_NOTIFY_TYPE_MOTD:
goto out;
/* Notify application */
- client->ops->notify(client, conn, type, tmp);
+ client->internal->ops->notify(client, conn, type, tmp);
break;
case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
channel->id, channel, 0, NULL);
/* Notify application */
- client->ops->notify(client, conn, type, channel, channel);
+ client->internal->ops->notify(client, conn, type, channel, channel);
break;
case SILC_NOTIFY_TYPE_KICKED:
/* Notify application. The channel entry is sent last as this notify
is for channel but application don't know it from the arguments
sent by server. */
- client->ops->notify(client, conn, type, client_entry, tmp,
- client_entry2, channel);
+ client->internal->ops->notify(client, conn, type, client_entry, tmp,
+ client_entry2, channel);
/* If I was kicked from channel, remove the channel */
if (client_entry == conn->local_entry) {
tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
/* Notify application. */
- client->ops->notify(client, conn, type, client_entry, tmp);
+ client->internal->ops->notify(client, conn, type, client_entry, tmp);
if (client_entry != conn->local_entry) {
/* Remove client from all channels */
/* Notify application. We don't keep server entries so the server
entry is returned as NULL. The client's are returned as array
of SilcClientEntry pointers. */
- client->ops->notify(client, conn, type, NULL, clients, clients_count);
+ client->internal->ops->notify(client, conn, type, NULL,
+ clients, clients_count);
for (i = 0; i < clients_count; i++) {
/* Remove client from all channels */
flags = silc_private_message_get_flags(payload);
/* Pass the private message to application */
- client->ops->private_message(client, conn, remote_client, flags,
- silc_private_message_get_message(payload,
- NULL));
+ client->internal->ops->private_message(
+ client, conn, remote_client, flags,
+ silc_private_message_get_message(payload,
+ NULL));
/* See if we are away (gone). If we are away we will reply to the
sender with the set away message. */
goto out;
/* Print some info for application */
- client->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
- "Received private message key from %s%s%s %s%s%s",
- clients[0]->nickname,
- clients[0]->server ? "@" : "",
- clients[0]->server ? clients[0]->server : "",
- clients[0]->username ? "(" : "",
- clients[0]->username ? clients[0]->username : "",
- clients[0]->username ? ")" : "");
+ client->internal->ops->say(
+ client, conn, SILC_CLIENT_MESSAGE_AUDIT,
+ "Received private message key from %s%s%s %s%s%s",
+ clients[0]->nickname,
+ clients[0]->server ? "@" : "",
+ clients[0]->server ? clients[0]->server : "",
+ clients[0]->username ? "(" : "",
+ clients[0]->username ? clients[0]->username : "",
+ clients[0]->username ? ")" : "");
out:
silc_packet_context_free(packet);
/* Produce the key material as the protocol defines */
keymat = silc_calloc(1, sizeof(*keymat));
if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
- client->md5hash, keymat)
+ client->internal->md5hash, keymat)
!= SILC_SKE_STATUS_OK)
return FALSE;
/*
- command.c
+ command.c
- Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+ Author: Pekka Riikonen <priikone@silcnet.org>
Copyright (C) 1997 - 2001 Pekka Riikonen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
+ the Free Software Foundation; version 2 of the License.
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#include "clientlibincludes.h"
#include "client_internal.h"
-/* Client command list. */
-SilcClientCommand silc_command_list[] =
-{
- SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", SILC_CF_LAG | SILC_CF_REG, 3),
- SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", SILC_CF_LAG | SILC_CF_REG, 3),
- SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY",
- SILC_CF_LAG | SILC_CF_REG, 3),
- SILC_CLIENT_CMD(nick, NICK, "NICK", SILC_CF_LAG | SILC_CF_REG, 2),
- SILC_CLIENT_CMD(list, LIST, "LIST", SILC_CF_LAG | SILC_CF_REG, 2),
- SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", SILC_CF_LAG | SILC_CF_REG, 3),
- SILC_CLIENT_CMD(invite, INVITE, "INVITE", SILC_CF_LAG | SILC_CF_REG, 3),
- SILC_CLIENT_CMD(quit, QUIT, "QUIT", SILC_CF_LAG | SILC_CF_REG, 2),
- SILC_CLIENT_CMD(kill, KILL, "KILL",
- SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 3),
- SILC_CLIENT_CMD(info, INFO, "INFO", SILC_CF_LAG | SILC_CF_REG, 2),
- SILC_CLIENT_CMD(connect, CONNECT, "CONNECT",
- SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 3),
- SILC_CLIENT_CMD(ping, PING, "PING", SILC_CF_LAG | SILC_CF_REG, 2),
- SILC_CLIENT_CMD(oper, OPER, "OPER",
- SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
- SILC_CLIENT_CMD(join, JOIN, "JOIN", SILC_CF_LAG | SILC_CF_REG, 9),
- SILC_CLIENT_CMD(motd, MOTD, "MOTD", SILC_CF_LAG | SILC_CF_REG, 2),
- SILC_CLIENT_CMD(umode, UMODE, "UMODE", SILC_CF_LAG | SILC_CF_REG, 2),
- SILC_CLIENT_CMD(cmode, CMODE, "CMODE", SILC_CF_LAG | SILC_CF_REG, 4),
- SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", SILC_CF_LAG | SILC_CF_REG, 5),
- SILC_CLIENT_CMD(kick, KICK, "KICK", SILC_CF_LAG | SILC_CF_REG, 4),
- SILC_CLIENT_CMD(ban, BAN, "BAN", SILC_CF_LAG | SILC_CF_REG, 3),
- SILC_CLIENT_CMD(close, CLOSE, "CLOSE",
- SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 3),
- SILC_CLIENT_CMD(shutdown, SHUTDOWN, "SHUTDOWN",
- SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 1),
- SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER",
- SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER, 3),
- SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", SILC_CF_LAG | SILC_CF_REG, 2),
- SILC_CLIENT_CMD(users, USERS, "USERS", SILC_CF_LAG | SILC_CF_REG, 2),
- SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", SILC_CF_LAG | SILC_CF_REG, 2),
-
- { NULL, 0, NULL, 0, 0 },
-};
-
#define SILC_NOT_CONNECTED(x, c) \
- x->ops->say((x), (c), SILC_CLIENT_MESSAGE_ERROR, \
+ x->internal->ops->say((x), (c), SILC_CLIENT_MESSAGE_ERROR, \
"You are not connected to a server, use /SERVER to connect");
/* Command operation that is called at the end of all commands.
Usage: COMMAND; */
-#define COMMAND cmd->client->ops->command(cmd->client, cmd->conn, \
+#define COMMAND cmd->client->internal->ops->command(cmd->client, cmd->conn, \
cmd, TRUE, cmd->command->cmd)
/* Error to application. Usage: COMMAND_ERROR; */
-#define COMMAND_ERROR cmd->client->ops->command(cmd->client, cmd->conn, \
- cmd, FALSE, cmd->command->cmd)
+#define COMMAND_ERROR cmd->client->internal->ops->command(cmd->client, \
+ cmd->conn, cmd, FALSE, cmd->command->cmd)
/* Generic function to send any command. The arguments must be sent already
encoded into correct form and in correct order. */
-void silc_client_send_command(SilcClient client, SilcClientConnection conn,
+void silc_client_command_send(SilcClient client, SilcClientConnection conn,
SilcCommand command, uint16 ident,
uint32 argc, ...)
{
/* Finds and returns a pointer to the command list. Return NULL if the
command is not found. */
-SilcClientCommand *silc_client_command_find(const char *name)
+SilcClientCommand silc_client_command_find(SilcClient client,
+ const char *name)
{
- SilcClientCommand *cmd;
+ SilcClientCommand cmd;
- for (cmd = silc_command_list; cmd->name; cmd++) {
- if (!strcmp(cmd->name, name))
+ silc_list_start(client->internal->commands);
+ while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
+ if (cmd->name && !strcmp(cmd->name, name))
return cmd;
}
return NULL;
}
+/* Calls the command (executes it). Application can call this after
+ it has allocated the SilcClientCommandContext with the function
+ silc_client_command_alloc and found the command from the client
+ library by calling silc_client_command_find. This will execute
+ the command. */
+
+void silc_client_command_call(SilcClientCommand command,
+ SilcClientCommandContext cmd)
+{
+ (*command->command)((void *)cmd, NULL);
+}
+
/* Add new pending command to be executed when reply to a command has been
received. The `reply_cmd' is the command that will call the `callback'
with `context' when reply has been received. If `ident is non-zero
/* Allocate Command Context */
-SilcClientCommandContext silc_client_command_alloc()
+SilcClientCommandContext silc_client_command_alloc(void)
{
SilcClientCommandContext ctx = silc_calloc(1, sizeof(*ctx));
ctx->users++;
/* 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_send_command(cmd->client, cmd->conn, SILC_COMMAND_WHOIS,
+ silc_client_command_send(cmd->client, cmd->conn, SILC_COMMAND_WHOIS,
++conn->cmd_ident,
1, 3, buffer->data, buffer->len);
silc_buffer_free(buffer);
}
if (cmd->argc < 2 || cmd->argc > 3) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /WHOWAS <nickname>[@<server>] [<count>]");
COMMAND_ERROR;
goto out;
}
/* Command IDENTIFY. This command is used to query information about
- specific user, especially ID's. */
+ specific user, especially ID's.
+
+ NOTE: This command is used only internally by the client library
+ and application MUST NOT call this command directly. */
SILC_CLIENT_CMD_FUNC(identify)
{
if (!cmd->conn) {
SILC_NOT_CONNECTED(cmd->client, cmd->conn);
- COMMAND_ERROR;
goto out;
}
- if (cmd->argc < 2 || cmd->argc > 3) {
- COMMAND_ERROR;
+ if (cmd->argc < 2 || cmd->argc > 3)
goto out;
- }
if (cmd->argc == 2)
buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
buffer->data, buffer->len, TRUE);
silc_buffer_free(buffer);
- /* Notify application */
- COMMAND;
-
out:
silc_client_command_free(cmd);
}
silc_free(conn->nickname);
conn->nickname = strdup(cmd->argv[1]);
conn->local_entry->nickname = conn->nickname;
+ silc_client_nickname_format(cmd->client, conn, conn->local_entry);
silc_idcache_add(conn->client_cache, strdup(cmd->argv[1]),
conn->local_entry->id, conn->local_entry, 0, NULL);
COMMAND;
}
if (cmd->argc < 2) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /NICK <nickname>");
COMMAND_ERROR;
goto out;
/* Show current nickname */
if (cmd->argc < 2) {
if (cmd->conn) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Your nickname is %s on server %s",
conn->nickname, conn->remote_host);
} else {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Your nickname is %s", conn->nickname);
}
}
if (cmd->argc < 2 || cmd->argc > 3) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /TOPIC <channel> [<topic>]");
COMMAND_ERROR;
goto out;
if (cmd->argv[1][0] == '*') {
if (!conn->current_channel) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"You are not on any channel");
COMMAND_ERROR;
goto out;
}
if (!conn->current_channel) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"You are not on that channel");
COMMAND_ERROR;
goto out;
/* Get the Channel ID of the channel */
if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"You are not on that channel");
COMMAND_ERROR;
goto out;
}
if (cmd->argc < 2) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /INVITE <channel> [<nickname>[@server>]"
"[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
COMMAND_ERROR;
if (cmd->argv[1][0] == '*') {
if (!conn->current_channel) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"You are not on any channel");
COMMAND_ERROR;
goto out;
channel = silc_client_get_channel(cmd->client, conn, name);
if (!channel) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"You are on that channel");
COMMAND_ERROR;
goto out;
/* Parse the typed nickname. */
if (cmd->argc == 3) {
if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
- if (client->params->nickname_parse)
- client->params->nickname_parse(cmd->argv[2], &nickname);
+ if (client->internal->params->nickname_parse)
+ client->internal->params->nickname_parse(cmd->argv[2], &nickname);
else
nickname = strdup(cmd->argv[2]);
QuitInternal q = (QuitInternal)context;
/* Close connection */
- q->client->ops->disconnect(q->client, q->conn);
+ q->client->internal->ops->disconnect(q->client, q->conn);
silc_client_close_connection(q->client, NULL, q->conn->sock->user_data);
silc_free(q);
char *nickname = NULL;
/* Parse the typed nickname. */
- if (client->params->nickname_parse)
- client->params->nickname_parse(cmd->argv[1], &nickname);
+ if (client->internal->params->nickname_parse)
+ client->internal->params->nickname_parse(cmd->argv[1], &nickname);
else
nickname = strdup(cmd->argv[1]);
}
if (cmd->argc < 2) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /KILL <nickname> [<comment>]");
COMMAND_ERROR;
goto out;
}
/* Parse the typed nickname. */
- if (client->params->nickname_parse)
- client->params->nickname_parse(cmd->argv[1], &nickname);
+ if (client->internal->params->nickname_parse)
+ client->internal->params->nickname_parse(cmd->argv[1], &nickname);
else
nickname = strdup(cmd->argv[1]);
}
if (cmd->argc < 1 || cmd->argc > 2) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /MOTD [<server>]");
COMMAND_ERROR;
goto out;
}
if (cmd->argc < 2) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /UMODE +|-<modes>");
COMMAND_ERROR;
goto out;
}
if (cmd->argc < 3) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
COMMAND_ERROR;
goto out;
if (cmd->argv[1][0] == '*') {
if (!conn->current_channel) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"You are not on any channel");
COMMAND_ERROR;
goto out;
channel = silc_client_get_channel(cmd->client, conn, name);
if (!channel) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"You are on that channel");
COMMAND_ERROR;
goto out;
mode |= SILC_CHANNEL_MODE_ULIMIT;
type = 3;
if (cmd->argc < 4) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
COMMAND_ERROR;
goto out;
mode |= SILC_CHANNEL_MODE_PASSPHRASE;
type = 4;
if (cmd->argc < 4) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
COMMAND_ERROR;
goto out;
mode |= SILC_CHANNEL_MODE_CIPHER;
type = 5;
if (cmd->argc < 4) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
COMMAND_ERROR;
goto out;
mode |= SILC_CHANNEL_MODE_HMAC;
type = 6;
if (cmd->argc < 4) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
COMMAND_ERROR;
goto out;
type = 7;
if (cmd->argc < 4) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
COMMAND_ERROR;
goto out;
}
if (cmd->argc < 4) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
COMMAND_ERROR;
goto out;
if (cmd->argv[1][0] == '*') {
if (!conn->current_channel) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"You are not on any channel");
COMMAND_ERROR;
goto out;
channel = silc_client_get_channel(cmd->client, conn, name);
if (!channel) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"You are on that channel");
COMMAND_ERROR;
goto out;
}
/* Parse the typed nickname. */
- if (client->params->nickname_parse)
- client->params->nickname_parse(cmd->argv[3], &nickname);
+ if (client->internal->params->nickname_parse)
+ client->internal->params->nickname_parse(cmd->argv[3], &nickname);
else
nickname = strdup(cmd->argv[3]);
}
if (cmd->argc < 3) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /KICK <channel> <nickname> [<comment>]");
COMMAND_ERROR;
goto out;
if (cmd->argv[1][0] == '*') {
if (!conn->current_channel) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"You are not on any channel");
COMMAND_ERROR;
goto out;
}
if (!conn->current_channel) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"You are not on that channel");
COMMAND_ERROR;
goto out;
/* Get the Channel ID of the channel */
if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"You are not on that channel");
COMMAND_ERROR;
goto out;
channel = (SilcChannelEntry)id_cache->context;
/* Parse the typed nickname. */
- if (client->params->nickname_parse)
- client->params->nickname_parse(cmd->argv[2], &nickname);
+ if (client->internal->params->nickname_parse)
+ client->internal->params->nickname_parse(cmd->argv[2], &nickname);
else
nickname = strdup(cmd->argv[2]);
target = silc_idlist_get_client(cmd->client, conn, nickname,
cmd->argv[2], FALSE);
if (!target) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"No such client: %s",
cmd->argv[2]);
COMMAND_ERROR;
}
if (cmd->argc < 2) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /OPER <username> [-pubkey]");
COMMAND_ERROR;
goto out;
if (cmd->argc < 3) {
/* Get passphrase */
- cmd->client->ops->ask_passphrase(cmd->client, conn,
+ cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
silc_client_command_oper_send,
context);
return;
}
if (cmd->argc < 2) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /SILCOPER <username> [-pubkey]");
COMMAND_ERROR;
goto out;
if (cmd->argc < 3) {
/* Get passphrase */
- cmd->client->ops->ask_passphrase(cmd->client, conn,
+ cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
silc_client_command_silcoper_send,
context);
return;
}
if (cmd->argc < 2) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /CONNECT <server> [<port>]");
COMMAND_ERROR;
goto out;
}
if (cmd->argc < 2) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /BAN <channel> "
"[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
COMMAND_ERROR;
if (cmd->argv[1][0] == '*') {
if (!conn->current_channel) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"You are not on any channel");
COMMAND_ERROR;
goto out;
channel = silc_client_get_channel(cmd->client, conn, name);
if (!channel) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"You are on that channel");
COMMAND_ERROR;
goto out;
}
if (cmd->argc < 2) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /CLOSE <server> [<port>]");
COMMAND_ERROR;
goto out;
}
/* Send the command */
- silc_client_send_command(cmd->client, cmd->conn,
+ silc_client_command_send(cmd->client, cmd->conn,
SILC_COMMAND_SHUTDOWN, 0, 0);
/* Notify application */
}
if (cmd->argc != 2) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /LEAVE <channel>");
COMMAND_ERROR;
goto out;
if (cmd->argv[1][0] == '*') {
if (!conn->current_channel) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"You are not on any channel");
COMMAND_ERROR;
goto out;
/* Get the Channel ID of the channel */
if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"You are not on that channel");
COMMAND_ERROR;
goto out;
}
if (cmd->argc != 2) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /USERS <channel>");
COMMAND_ERROR;
goto out;
if (cmd->argv[1][0] == '*') {
if (!conn->current_channel) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"You are not on any channel");
COMMAND_ERROR;
goto out;
}
if (cmd->argc < 2) {
- client->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /GETKEY <nickname or server name>");
COMMAND_ERROR;
goto out;
if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
status == SILC_STATUS_ERR_NO_SUCH_SERVER) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
"%s",
silc_client_command_status_message(status));
COMMAND_ERROR;
}
/* Parse the typed nickname. */
- if (client->params->nickname_parse)
- client->params->nickname_parse(cmd->argv[1], &nickname);
+ if (client->internal->params->nickname_parse)
+ client->internal->params->nickname_parse(cmd->argv[1], &nickname);
else
nickname = strdup(cmd->argv[1]);
silc_client_command_dup(cmd));
/* This sends the IDENTIFY command to resolve the server. */
- silc_client_send_command(client, conn, SILC_COMMAND_IDENTIFY,
- ++conn->cmd_ident, 1,
+ 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_free(nickname);
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.
+
+ 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
+ command identifier `ident'. Application usually does not need it
+ and set it to zero value. */
+
+bool silc_client_command_register(SilcClient client,
+ SilcCommand command,
+ const char *name,
+ SilcCommandCb command_function,
+ SilcCommandCb command_reply_function,
+ uint8 max_args,
+ uint16 ident)
+{
+ SilcClientCommand cmd;
+
+ cmd = silc_calloc(1, sizeof(*cmd));
+ cmd->cmd = command;
+ cmd->command = command_function;
+ cmd->reply = command_reply_function;
+ cmd->name = name ? strdup(name) : NULL;
+ cmd->max_args = max_args;
+ cmd->ident = ident;
+
+ silc_list_add(client->internal->commands, cmd);
+
+ return TRUE;
+}
+
+/* Unregister a command indicated by the `command' with command function
+ `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,
+ SilcCommand command,
+ SilcCommandCb command_function,
+ SilcCommandCb command_reply_function,
+ uint16 ident)
+{
+ SilcClientCommand cmd;
+
+ silc_list_start(client->internal->commands);
+ while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
+ if (cmd->cmd == command && cmd->command == command_function &&
+ cmd->reply == command_reply_function && cmd->ident == ident) {
+ silc_list_del(client->internal->commands, cmd);
+ silc_free(cmd->name);
+ silc_free(cmd);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/* Register all default commands provided by the client library for the
+ application. */
+
+void silc_client_commands_register(SilcClient client)
+{
+ silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
+ next);
+
+ SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 3);
+ SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
+ SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
+ SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
+ SILC_CLIENT_CMD(list, LIST, "LIST", 2);
+ SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
+ SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
+ SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
+ SILC_CLIENT_CMD(kill, KILL, "KILL", 3);
+ SILC_CLIENT_CMD(info, INFO, "INFO", 2);
+ SILC_CLIENT_CMD(connect, CONNECT, "CONNECT", 3);
+ SILC_CLIENT_CMD(ping, PING, "PING", 2);
+ SILC_CLIENT_CMD(oper, OPER, "OPER", 2);
+ 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(kick, KICK, "KICK", 4);
+ SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
+ SILC_CLIENT_CMD(close, CLOSE, "CLOSE", 3);
+ SILC_CLIENT_CMD(shutdown, SHUTDOWN, "SHUTDOWN", 1);
+ SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
+ SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
+ SILC_CLIENT_CMD(users, USERS, "USERS", 2);
+ SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
+}
+
+/* Unregister all commands. */
+
+void silc_client_commands_unregister(SilcClient client)
+{
+ SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
+ SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
+ SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
+ SILC_CLIENT_CMDU(nick, NICK, "NICK");
+ SILC_CLIENT_CMDU(list, LIST, "LIST");
+ SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
+ SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
+ SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
+ SILC_CLIENT_CMDU(kill, KILL, "KILL");
+ SILC_CLIENT_CMDU(info, INFO, "INFO");
+ SILC_CLIENT_CMDU(connect, CONNECT, "CONNECT");
+ SILC_CLIENT_CMDU(ping, PING, "PING");
+ SILC_CLIENT_CMDU(oper, OPER, "OPER");
+ SILC_CLIENT_CMDU(join, JOIN, "JOIN");
+ SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
+ SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
+ SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
+ SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
+ SILC_CLIENT_CMDU(kick, KICK, "KICK");
+ SILC_CLIENT_CMDU(ban, BAN, "BAN");
+ SILC_CLIENT_CMDU(close, CLOSE, "CLOSE");
+ SILC_CLIENT_CMDU(shutdown, SHUTDOWN, "SHUTDOWN");
+ SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
+ SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
+ SILC_CLIENT_CMDU(users, USERS, "USERS");
+ SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
+
+ silc_list_uninit(client->internal->commands);
+}
/*
- command.h
+ command.h
- Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+ Author: Pekka Riikonen <priikone@silcnet.org>
Copyright (C) 1997 - 2001 Pekka Riikonen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
+ the Free Software Foundation; version 2 of the License.
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#ifndef COMMAND_H
#define COMMAND_H
-/*
- Structure holding one command and pointer to its function.
-
- SilcCommandCb cb
-
- Callback function called when this command is executed.
-
- SilcCommand cmd
-
- The actual command. These are defined in silccore/silccommand.h
-
- char *name
+/* Forward declarations */
+typedef struct SilcClientCommandStruct *SilcClientCommand;
+typedef struct SilcClientCommandContextStruct *SilcClientCommandContext;
- Logical name of the command. This is the visible command name
- that user uses when calling command. Eg. NICK.
+#include "silcapi.h"
+#include "command_reply.h"
- SilcCommandFlag flags
+/* Structure holding one command and pointer to its function. This
+ structure is allocate into the commands list, and is returned
+ for example by silc_client_command_find function.
- Flags for the command. These set how command behaves on different
- situations. Server sets these flags as well, but to be sure
- that our client never sends wrong commands we preserve the
- flags on client side as well (actually we preserve them but
- ignore them :)).
+ To call a command: command->command(cmd, NULL);
+ To call a command reply: command->reply(cmd, NULL);
*/
-typedef struct {
- SilcCommandCb cb;
- SilcCommand cmd;
- char *name;
- SilcCommandFlag flags;
- uint32 max_args;
-} SilcClientCommand;
-
-/* All client commands */
-extern SilcClientCommand silc_command_list[];
+struct SilcClientCommandStruct {
+ SilcCommand cmd; /* Command type */
+ SilcCommandCb command; /* Command function */
+ SilcCommandCb reply; /* Command reply callback */
+ char *name; /* Name of the command (optional) */
+ uint8 max_args; /* Maximum arguments (optional) */
+ uint16 ident; /* Identifier for command (optional) */
+ struct SilcClientCommandStruct *next;
+};
/* Context sent as argument to all commands. This is used by the library
and application should use this as well. However, application may
choose to use some own context for its own local command. All library
commands, however, must use this context. */
-typedef struct {
+struct SilcClientCommandContextStruct {
SilcClient client;
SilcClientConnection conn;
- SilcClientCommand *command;
+ SilcClientCommand command;
uint32 argc;
unsigned char **argv;
uint32 *argv_lens;
uint32 *argv_types;
int pending; /* Command is being re-processed when TRUE */
int users; /* Reference counter */
-} *SilcClientCommandContext;
-
-#include "silcapi.h"
+};
/* Structure holding pending commands. If command is pending it will be
executed after command reply has been executed. */
/* List of pending commands */
extern SilcClientCommandPending *silc_command_pending;
-#include "command_reply.h"
/* Macros */
-/* Macro used for command declaration in command list structure */
-#define SILC_CLIENT_CMD(func, cmd, name, flags, args) \
-{ silc_client_command_##func, SILC_COMMAND_##cmd, name, flags, args }
+/* Macro used for command registering and unregistering */
+#define SILC_CLIENT_CMD(func, cmd, name, args) \
+silc_client_command_register(client, SILC_COMMAND_##cmd, name, \
+ silc_client_command_##func, \
+ silc_client_command_reply_##func, args, 0)
+#define SILC_CLIENT_CMDU(func, cmd, name) \
+silc_client_command_unregister(client, SILC_COMMAND_##cmd, \
+ silc_client_command_##func, \
+ silc_client_command_reply_##func, 0)
/* Macro used to declare command functions */
-#define SILC_CLIENT_CMD_FUNC(func) \
+#define SILC_CLIENT_CMD_FUNC(func) \
void silc_client_command_##func(void *context, void *context2)
/* Executed pending command callback */
(*ctx->destructor)(ctx->context); \
} while(0)
-/* Prototypes (some prototypes are in the silcapi.h file) */
+bool silc_client_command_register(SilcClient client,
+ SilcCommand command,
+ const char *name,
+ SilcCommandCb command_function,
+ SilcCommandCb command_reply_function,
+ uint8 max_args,
+ uint16 ident);
+bool silc_client_command_unregister(SilcClient client,
+ SilcCommand command,
+ SilcCommandCb command_function,
+ SilcCommandCb command_reply_function,
+ uint16 ident);
+void silc_client_commands_register(SilcClient client);
+void silc_client_commands_unregister(SilcClient client);
void silc_client_command_pending_del(SilcClientConnection conn,
SilcCommand reply_cmd,
uint16 ident);
/*
- command_reply.c
+ command_reply.c
- Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+ Author: Pekka Riikonen <priikone@silcnet.org>
Copyright (C) 1997 - 2001 Pekka Riikonen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
+ the Free Software Foundation; version 2 of the License.
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
+/* $Id$ */
/*
* Command reply functions are "the otherside" of the command functions.
* Reply to a command sent by server is handled by these functions.
* necessary data already in hand without redundant searching. If ID is
* received but ID entry does not exist, NULL is sent.
*/
-/* $Id$ */
#include "clientlibincludes.h"
#include "client_internal.h"
-/* Client command reply list. */
-SilcClientCommandReply silc_command_reply_list[] =
-{
- SILC_CLIENT_CMD_REPLY(whois, WHOIS),
- SILC_CLIENT_CMD_REPLY(whowas, WHOWAS),
- SILC_CLIENT_CMD_REPLY(identify, IDENTIFY),
- SILC_CLIENT_CMD_REPLY(nick, NICK),
- SILC_CLIENT_CMD_REPLY(list, LIST),
- SILC_CLIENT_CMD_REPLY(topic, TOPIC),
- SILC_CLIENT_CMD_REPLY(invite, INVITE),
- SILC_CLIENT_CMD_REPLY(kill, KILL),
- SILC_CLIENT_CMD_REPLY(info, INFO),
- SILC_CLIENT_CMD_REPLY(connect, CONNECT),
- SILC_CLIENT_CMD_REPLY(ping, PING),
- SILC_CLIENT_CMD_REPLY(oper, OPER),
- SILC_CLIENT_CMD_REPLY(join, JOIN),
- SILC_CLIENT_CMD_REPLY(motd, MOTD),
- SILC_CLIENT_CMD_REPLY(umode, UMODE),
- SILC_CLIENT_CMD_REPLY(cmode, CMODE),
- SILC_CLIENT_CMD_REPLY(cumode, CUMODE),
- SILC_CLIENT_CMD_REPLY(kick, KICK),
- SILC_CLIENT_CMD_REPLY(ban, BAN),
- SILC_CLIENT_CMD_REPLY(close, CLOSE),
- SILC_CLIENT_CMD_REPLY(shutdown, SHUTDOWN),
- SILC_CLIENT_CMD_REPLY(silcoper, SILCOPER),
- SILC_CLIENT_CMD_REPLY(leave, LEAVE),
- SILC_CLIENT_CMD_REPLY(users, USERS),
- SILC_CLIENT_CMD_REPLY(getkey, GETKEY),
-
- { NULL, 0 },
-};
-
const SilcCommandStatusMessage silc_command_status_messages[] = {
{ STAT(NO_SUCH_NICK), "There was no such nickname" },
};
/* Command reply operation that is called at the end of all command replys.
Usage: COMMAND_REPLY((ARGS, argument1, argument2, etc...)), */
-#define COMMAND_REPLY(args) cmd->client->ops->command_reply args
-#define ARGS cmd->client, cmd->sock->user_data, \
+#define COMMAND_REPLY(args) cmd->client->internal->ops->command_reply args
+#define ARGS cmd->client, cmd->sock->user_data, \
cmd->payload, TRUE, silc_command_get(cmd->payload), status
/* Error reply to application. Usage: COMMAND_REPLY_ERROR; */
-#define COMMAND_REPLY_ERROR cmd->client->ops->command_reply(cmd->client, \
- cmd->sock->user_data, cmd->payload, FALSE, \
- silc_command_get(cmd->payload), status)
+#define COMMAND_REPLY_ERROR cmd->client->internal->ops-> \
+ command_reply(cmd->client, cmd->sock->user_data, cmd->payload, \
+ FALSE, silc_command_get(cmd->payload), status)
/* All functions that call the COMMAND_CHECK_STATUS or the
COMMAND_CHECK_STATUS_LIST macros must have out: goto label. */
SilcPacketContext *packet)
{
SilcBuffer buffer = packet->buffer;
- SilcClientCommandReply *cmd;
+ SilcClientCommand cmd;
SilcClientCommandReplyContext ctx;
SilcCommandPayload payload;
SilcCommand command;
- uint16 ident;
-
+ SilcCommandCb reply = NULL;
+
/* Get command reply payload from packet */
payload = silc_command_payload_parse(buffer->data, buffer->len);
if (!payload) {
ctx->payload = payload;
ctx->args = silc_command_get_args(ctx->payload);
ctx->packet = packet;
- ident = silc_command_get_ident(ctx->payload);
-
+ ctx->ident = silc_command_get_ident(ctx->payload);
+
/* Check for pending commands and mark to be exeucted */
silc_client_command_pending_check(sock->user_data, ctx,
- silc_command_get(ctx->payload), ident);
+ silc_command_get(ctx->payload),
+ ctx->ident);
/* Execute command reply */
+
command = silc_command_get(ctx->payload);
- for (cmd = silc_command_reply_list; cmd->cb; cmd++)
- if (cmd->cmd == command)
- break;
- if (cmd == NULL || !cmd->cb) {
- silc_free(ctx);
- return;
+ /* Try to find matching the command identifier */
+ silc_list_start(client->internal->commands);
+ while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
+ if (cmd->cmd == command && !cmd->ident)
+ reply = cmd->reply;
+ if (cmd->cmd == command && cmd->ident == ctx->ident) {
+ (*cmd->reply)((void *)ctx, NULL);
+ break;
+ }
}
- cmd->cb(ctx, NULL);
+ if (cmd == SILC_LIST_END) {
+ if (reply)
+ /* No specific identifier for command reply, call first one found */
+ (*reply)(ctx, NULL);
+ else
+ silc_free(ctx);
+ }
}
/* Returns status message string */
static void
silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
- SilcCommandStatus status)
+ SilcCommandStatus status,
+ bool notify)
{
SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
SilcClientID *client_id;
id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
if (!id_data) {
- COMMAND_REPLY_ERROR;
+ if (notify)
+ COMMAND_REPLY_ERROR;
return;
}
client_id = silc_id_payload_parse_id(id_data, len);
if (!client_id) {
- COMMAND_REPLY_ERROR;
+ if (notify)
+ COMMAND_REPLY_ERROR;
return;
}
username = silc_argument_get_arg_type(cmd->args, 4, &len);
realname = silc_argument_get_arg_type(cmd->args, 5, &len);
if (!nickname || !username || !realname) {
- COMMAND_REPLY_ERROR;
+ if (notify)
+ COMMAND_REPLY_ERROR;
return;
}
client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
/* Notify application */
- if (!cmd->callback)
+ if (!cmd->callback && notify)
COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
channels, mode, idle, fingerprint));
SILC_CLIENT_CMD_REPLY_FUNC(whois)
{
SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
SilcCommandStatus status;
COMMAND_CHECK_STATUS_LIST;
/* Save WHOIS info */
- silc_client_command_reply_whois_save(cmd, status);
+ silc_client_command_reply_whois_save(cmd, status, TRUE);
/* Pending callbacks are not executed if this was an list entry */
if (status != SILC_STATUS_OK &&
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. */
+ if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
+ SilcClientEntry client_entry;
+ uint32 tmp_len;
+ unsigned char *tmp =
+ silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
+ 2, &tmp_len);
+ if (tmp) {
+ SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (client_id) {
+ client_entry = silc_client_get_client_by_id(cmd->client, conn,
+ client_id);
+ if (client_entry)
+ silc_client_del_client(cmd->client, conn, client_entry);
+ silc_free(client_id);
+ }
+ }
+ }
+
silc_client_command_reply_free(cmd);
}
static void
silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
- SilcCommandStatus status)
+ SilcCommandStatus status,
+ bool notify)
{
SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
SilcClient client = cmd->client;
id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
if (!id_data) {
- COMMAND_REPLY_ERROR;
+ if (notify)
+ COMMAND_REPLY_ERROR;
return;
}
idp = silc_id_payload_parse(id_data, len);
if (!idp) {
- COMMAND_REPLY_ERROR;
+ if (notify)
+ COMMAND_REPLY_ERROR;
return;
}
client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
/* Notify application */
- COMMAND_REPLY((ARGS, client_entry, name, info));
+ if (notify)
+ COMMAND_REPLY((ARGS, client_entry, name, info));
break;
case SILC_ID_SERVER:
}
/* Notify application */
- COMMAND_REPLY((ARGS, server_entry, name, info));
+ if (notify)
+ COMMAND_REPLY((ARGS, server_entry, name, info));
break;
case SILC_ID_CHANNEL:
}
/* Notify application */
- COMMAND_REPLY((ARGS, channel_entry, name, info));
+ if (notify)
+ COMMAND_REPLY((ARGS, channel_entry, name, info));
break;
}
SILC_CLIENT_CMD_REPLY_FUNC(identify)
{
SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
SilcCommandStatus status;
COMMAND_CHECK_STATUS_LIST;
/* Save IDENTIFY info */
- silc_client_command_reply_identify_save(cmd, status);
+ silc_client_command_reply_identify_save(cmd, status, TRUE);
/* Pending callbacks are not executed if this was an list entry */
if (status != SILC_STATUS_OK &&
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. */
+ if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
+ SilcClientEntry client_entry;
+ uint32 tmp_len;
+ unsigned char *tmp =
+ silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
+ 2, &tmp_len);
+ if (tmp) {
+ SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (client_id) {
+ client_entry = silc_client_get_client_by_id(cmd->client, conn,
+ client_id);
+ if (client_entry)
+ silc_client_del_client(cmd->client, conn, client_entry);
+ silc_free(client_id);
+ }
+ }
+ }
+
silc_client_command_reply_free(cmd);
}
SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
if (status != SILC_STATUS_OK) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "Cannot set nickname: %s",
- silc_client_command_status_message(status));
+ cmd->client->internal->ops->say(
+ cmd->client,
+ conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Cannot set nickname: %s",
+ silc_client_command_status_message(status));
COMMAND_REPLY_ERROR;
goto out;
}
argc = silc_argument_get_arg_num(cmd->args);
if (argc < 2 || argc > 2) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
"Cannot set nickname: bad reply to command");
COMMAND_REPLY_ERROR;
goto out;
SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
if (status != SILC_STATUS_OK) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
"%s", silc_client_command_status_message(status));
COMMAND_REPLY_ERROR;
goto out;
tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
SILC_GET16_MSB(status, tmp);
if (status != SILC_STATUS_OK) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
"%s", silc_client_command_status_message(status));
COMMAND_REPLY_ERROR;
goto out;
SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
if (status != SILC_STATUS_OK) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
"%s", silc_client_command_status_message(status));
COMMAND_REPLY_ERROR;
goto out;
char *server_name, *server_info;
uint32 len;
+ SILC_LOG_DEBUG(("Start"));
+
tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
SILC_GET16_MSB(status, tmp);
if (status != SILC_STATUS_OK) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "%s", silc_client_command_status_message(status));
+ cmd->client->internal->ops->say(
+ cmd->client, conn,
+ SILC_CLIENT_MESSAGE_ERROR,
+ "%s",
+ silc_client_command_status_message(status));
COMMAND_REPLY_ERROR;
goto out;
}
/* Add it to the cache */
silc_idcache_add(conn->server_cache, server->server_name,
server->server_id, (void *)server, 0, NULL);
-
- if (SILC_ID_SERVER_COMPARE(server_id, conn->remote_id))
- goto out;
} else {
server = (SilcServerEntry)id_cache->context;
}
SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
if (status != SILC_STATUS_OK) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
"%s", silc_client_command_status_message(status));
COMMAND_REPLY_ERROR;
goto out;
continue;
if (SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
diff = curtime - conn->ping[i].start_time;
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Ping reply from %s: %d second%s",
conn->ping[i].dest_name, diff,
diff == 1 ? "" : "s");
SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
if (status != SILC_STATUS_OK) {
if (status != SILC_STATUS_ERR_USER_ON_CHANNEL)
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
"%s", silc_client_command_status_message(status));
COMMAND_REPLY_ERROR;
goto out;
argc = silc_argument_get_arg_num(cmd->args);
if (argc < 7 || argc > 14) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
"Cannot join channel: Bad reply packet");
COMMAND_REPLY_ERROR;
goto out;
/* Get channel name */
tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
if (!tmp) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
"Cannot join channel: Bad reply packet");
COMMAND_REPLY_ERROR;
goto out;
/* Get Channel ID */
tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
if (!tmp) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
"Cannot join channel: Bad reply packet");
COMMAND_REPLY_ERROR;
silc_free(channel_name);
hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
if (hmac) {
if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
"Cannot join channel: Unsupported HMAC `%s'",
hmac);
COMMAND_REPLY_ERROR;
tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
SILC_GET16_MSB(status, tmp);
if (status != SILC_STATUS_OK) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
"%s", silc_client_command_status_message(status));
COMMAND_REPLY_ERROR;
return;
if (i == 2)
line[0] = ' ';
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"%s", line);
if (!strlen(cp))
tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
SILC_GET16_MSB(status, tmp);
if (status != SILC_STATUS_OK) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
"%s", silc_client_command_status_message(status));
COMMAND_REPLY_ERROR;
goto out;
SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
if (status != SILC_STATUS_OK) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
"%s", silc_client_command_status_message(status));
COMMAND_REPLY_ERROR;
goto out;
SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
if (status != SILC_STATUS_OK) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
"%s", silc_client_command_status_message(status));
COMMAND_REPLY_ERROR;
goto out;
tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
SILC_GET16_MSB(status, tmp);
if (status != SILC_STATUS_OK) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "%s", silc_client_command_status_message(status));
+ cmd->client->internal->ops->say(
+ cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "%s", silc_client_command_status_message(status));
COMMAND_REPLY_ERROR;
goto out;
}
tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
SILC_GET16_MSB(status, tmp);
if (status != SILC_STATUS_OK) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "%s", silc_client_command_status_message(status));
+ cmd->client->internal->ops->say(
+ cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "%s", silc_client_command_status_message(status));
COMMAND_REPLY_ERROR;
goto out;
}
tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
SILC_GET16_MSB(status, tmp);
if (status != SILC_STATUS_OK) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "%s", silc_client_command_status_message(status));
+ cmd->client->internal->ops->say(
+ cmd->client, conn,
+ SILC_CLIENT_MESSAGE_ERROR,
+ "%s", silc_client_command_status_message(status));
COMMAND_REPLY_ERROR;
goto out;
}
tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
SILC_GET16_MSB(status, tmp);
if (status != SILC_STATUS_OK) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "%s", silc_client_command_status_message(status));
+ cmd->client->internal->ops->say(
+ cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "%s", silc_client_command_status_message(status));
COMMAND_REPLY_ERROR;
goto out;
}
tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
SILC_GET16_MSB(status, tmp);
if (status != SILC_STATUS_OK) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "%s", silc_client_command_status_message(status));
+ cmd->client->internal->ops->say(
+ cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "%s", silc_client_command_status_message(status));
COMMAND_REPLY_ERROR;
goto out;
}
tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
SILC_GET16_MSB(status, tmp);
if (status != SILC_STATUS_OK) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "%s", silc_client_command_status_message(status));
+ cmd->client->internal->ops->say(
+ cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "%s", silc_client_command_status_message(status));
COMMAND_REPLY_ERROR;
goto out;
}
tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
SILC_GET16_MSB(status, tmp);
if (status != SILC_STATUS_OK) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "%s", silc_client_command_status_message(status));
+ cmd->client->internal->ops->say(
+ cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "%s", silc_client_command_status_message(status));
COMMAND_REPLY_ERROR;
goto out;
}
tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
SILC_GET16_MSB(status, tmp);
if (status != SILC_STATUS_OK) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "%s", silc_client_command_status_message(status));
+ cmd->client->internal->ops->say(
+ cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "%s", silc_client_command_status_message(status));
COMMAND_REPLY_ERROR;
goto out;
}
tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
SILC_GET16_MSB(status, tmp);
if (status != SILC_STATUS_OK) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "%s", silc_client_command_status_message(status));
+ cmd->client->internal->ops->say(
+ cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "%s", silc_client_command_status_message(status));
COMMAND_REPLY_ERROR;
goto out;
}
if (id_cache && id_cache->context) {
SilcClientEntry client_entry = (SilcClientEntry)id_cache->context;
if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
- client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
silc_buffer_pull(client_id_list, idp_len);
silc_buffer_pull(client_mode_list, 4);
continue;
SilcBuffer res_cmd;
/* Send the WHOIS command to server */
+ silc_client_command_register(cmd->client, SILC_COMMAND_WHOIS, NULL, NULL,
+ silc_client_command_reply_whois_i, 0,
+ ++conn->cmd_ident);
res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
res_argc, res_argv, res_argv_lens,
- res_argv_types, ++conn->cmd_ident);
+ res_argv_types, conn->cmd_ident);
silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
TRUE);
tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
SILC_GET16_MSB(status, tmp);
if (status != SILC_STATUS_OK) {
- cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
"%s", silc_client_command_status_message(status));
COMMAND_REPLY_ERROR;
goto out;
silc_free(server_id);
silc_client_command_reply_free(cmd);
}
+
+SILC_CLIENT_CMD_REPLY_FUNC(quit)
+{
+ silc_client_command_reply_free(context);
+}
+
+
+/******************************************************************************
+
+ Internal command reply functions
+
+******************************************************************************/
+
+SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
+{
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+ SilcCommandStatus status;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
+ if (status != SILC_STATUS_OK &&
+ status != SILC_STATUS_LIST_START &&
+ status != SILC_STATUS_LIST_ITEM &&
+ status != SILC_STATUS_LIST_END)
+ goto out;
+
+ /* Save WHOIS info */
+ silc_client_command_reply_whois_save(cmd, status, FALSE);
+
+ /* Pending callbacks are not executed if this was an list entry */
+ if (status != SILC_STATUS_OK &&
+ status != SILC_STATUS_LIST_END) {
+ silc_client_command_reply_free(cmd);
+ return;
+ }
+
+ 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. */
+ if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
+ SilcClientEntry client_entry;
+ uint32 tmp_len;
+ unsigned char *tmp =
+ silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
+ 2, &tmp_len);
+ if (tmp) {
+ SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (client_id) {
+ client_entry = silc_client_get_client_by_id(cmd->client, conn,
+ client_id);
+ if (client_entry)
+ silc_client_del_client(cmd->client, conn, client_entry);
+ silc_free(client_id);
+ }
+ }
+ }
+
+ /* Unregister this command reply */
+ silc_client_command_unregister(cmd->client, SILC_COMMAND_WHOIS,
+ NULL, silc_client_command_reply_whois_i,
+ cmd->ident);
+
+ silc_client_command_reply_free(cmd);
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
+{
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+ SilcCommandStatus status;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
+ if (status != SILC_STATUS_OK &&
+ status != SILC_STATUS_LIST_START &&
+ status != SILC_STATUS_LIST_ITEM &&
+ status != SILC_STATUS_LIST_END)
+ goto out;
+
+ /* Save IDENTIFY info */
+ silc_client_command_reply_identify_save(cmd, status, FALSE);
+
+ /* Pending callbacks are not executed if this was an list entry */
+ if (status != SILC_STATUS_OK &&
+ status != SILC_STATUS_LIST_END) {
+ silc_client_command_reply_free(cmd);
+ return;
+ }
+
+ 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. */
+ if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
+ SilcClientEntry client_entry;
+ uint32 tmp_len;
+ unsigned char *tmp =
+ silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
+ 2, &tmp_len);
+ if (tmp) {
+ SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (client_id) {
+ client_entry = silc_client_get_client_by_id(cmd->client, conn,
+ client_id);
+ if (client_entry)
+ silc_client_del_client(cmd->client, conn, client_entry);
+ silc_free(client_id);
+ }
+ }
+ }
+
+ /* Unregister this command reply */
+ silc_client_command_unregister(cmd->client, SILC_COMMAND_IDENTIFY,
+ NULL, silc_client_command_reply_identify_i,
+ cmd->ident);
+
+ silc_client_command_reply_free(cmd);
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(info_i)
+{
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+ SilcCommandStatus status;
+ unsigned char *tmp;
+ SilcIDCacheEntry id_cache;
+ SilcServerEntry server;
+ SilcServerID *server_id = NULL;
+ char *server_name, *server_info;
+ uint32 len;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+ SILC_GET16_MSB(status, tmp);
+ if (status != SILC_STATUS_OK)
+ goto out;
+
+ /* Get server ID */
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+ if (!tmp)
+ goto out;
+
+ server_id = silc_id_payload_parse_id(tmp, len);
+ if (!server_id)
+ goto out;
+
+ /* Get server name */
+ server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
+ if (!server_name)
+ goto out;
+
+ /* Get server info */
+ server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
+ if (!server_info)
+ goto out;
+
+ /* See whether we have this server cached. If not create it. */
+ if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
+ &id_cache)) {
+ SILC_LOG_DEBUG(("New server entry"));
+ server = silc_calloc(1, sizeof(*server));
+ server->server_name = strdup(server_name);
+ server->server_info = strdup(server_info);
+ server->server_id = silc_id_dup(server_id, SILC_ID_SERVER);
+
+ /* Add it to the cache */
+ silc_idcache_add(conn->server_cache, server->server_name,
+ server->server_id, (void *)server, 0, NULL);
+ }
+
+ 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);
+}
/*
- command_reply.h
+ command_reply.h
- Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+ Author: Pekka Riikonen <priikone@silcnet.org>
Copyright (C) 1997 - 2001 Pekka Riikonen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
+ the Free Software Foundation; version 2 of the License.
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
SilcCommand cmd;
} SilcClientCommandReply;
-/* All client command replys */
-extern SilcClientCommandReply silc_command_reply_list[];
-
/* Context sent as argument to all command reply functions */
typedef struct {
SilcClient client;
/* Macros */
-/* Macro used for command declaration in command reply list structure */
-#define SILC_CLIENT_CMD_REPLY(func, cmd ) \
-{ silc_client_command_reply_##func, SILC_COMMAND_##cmd }
-
/* Macro used to declare command reply functions */
-#define SILC_CLIENT_CMD_REPLY_FUNC(func) \
+#define SILC_CLIENT_CMD_REPLY_FUNC(func) \
void silc_client_command_reply_##func(void *context, void *context2)
/* Status message structure. Messages are defined below. */
extern const SilcCommandStatusMessage silc_command_status_messages[];
/* Prototypes */
+
void silc_client_command_reply_process(SilcClient client,
SilcSocketConnection sock,
SilcPacketContext *packet);
SILC_CLIENT_CMD_REPLY_FUNC(leave);
SILC_CLIENT_CMD_REPLY_FUNC(users);
SILC_CLIENT_CMD_REPLY_FUNC(getkey);
+SILC_CLIENT_CMD_REPLY_FUNC(quit);
+
+/* Internal command reply functions */
+SILC_CLIENT_CMD_REPLY_FUNC(whois_i);
+SILC_CLIENT_CMD_REPLY_FUNC(identify_i);
+SILC_CLIENT_CMD_REPLY_FUNC(info_i);
#endif
#include "clientlibincludes.h"
#include "client_internal.h"
+/******************************************************************************
+
+ Client Searching Locally
+
+******************************************************************************/
+
+/* Same as silc_client_get_clients function but does not resolve anything
+ from the server. This checks local cache and returns all matching
+ clients from the local cache. If none was found this returns NULL.
+ The `nickname' is the real nickname of the client, and the `format'
+ is the formatted nickname to find exact match from multiple found
+ entries. The format must be same as given in the SilcClientParams
+ structure to the client library. If the `format' is NULL all found
+ clients by `nickname' are returned. */
+
+SilcClientEntry *silc_client_get_clients_local(SilcClient client,
+ SilcClientConnection conn,
+ const char *nickname,
+ const char *format,
+ uint32 *clients_count)
+{
+ SilcIDCacheEntry id_cache;
+ SilcIDCacheList list = NULL;
+ SilcClientEntry entry, *clients;
+ int i = 0;
+ bool found = FALSE;
+
+ /* Find ID from cache */
+ if (!silc_idcache_find_by_name(conn->client_cache, (char *)nickname, &list))
+ return NULL;
+
+ if (!silc_idcache_list_count(list)) {
+ silc_idcache_list_free(list);
+ return NULL;
+ }
+
+ clients = silc_calloc(silc_idcache_list_count(list), sizeof(*clients));
+ *clients_count = silc_idcache_list_count(list);
+
+ if (!format) {
+ /* Take all without any further checking */
+ silc_idcache_list_first(list, &id_cache);
+ while (id_cache) {
+ clients[i++] = id_cache->context;
+ found = TRUE;
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ }
+ } else {
+ /* Check multiple cache entries for match */
+ silc_idcache_list_first(list, &id_cache);
+ while (id_cache) {
+ entry = (SilcClientEntry)id_cache->context;
+ if (strcasecmp(entry->nickname, format)) {
+ if (!silc_idcache_list_next(list, &id_cache)) {
+ break;
+ } else {
+ continue;
+ }
+ }
+
+ clients[i++] = id_cache->context;
+ found = TRUE;
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ }
+ }
+
+ if (list)
+ silc_idcache_list_free(list);
+
+ if (!found) {
+ *clients_count = 0;
+ if (clients)
+ silc_free(clients);
+ return NULL;
+ }
+
+ return clients;
+}
+
+
+/******************************************************************************
+
+ Client Resolving from Server
+
+******************************************************************************/
+
typedef struct {
- SilcClientCommandContext cmd;
+ SilcClient client;
+ SilcClientConnection conn;
SilcGetClientCallback completion;
+ void *context;
char *nickname;
char *server;
- void *context;
- int found;
+ bool found;
} *GetClientInternal;
SILC_CLIENT_CMD_FUNC(get_client_callback)
uint32 clients_count;
/* Get the clients */
- clients = silc_client_get_clients_local(i->cmd->client, i->cmd->conn,
+ clients = silc_client_get_clients_local(i->client, i->conn,
i->nickname, i->server,
&clients_count);
if (clients) {
- i->completion(i->cmd->client, i->cmd->conn, clients,
+ i->completion(i->client, i->conn, clients,
clients_count, i->context);
i->found = TRUE;
silc_free(clients);
GetClientInternal i = (GetClientInternal)context;
if (i->found == FALSE)
- i->completion(i->cmd->client, i->cmd->conn, NULL, 0, i->context);
+ i->completion(i->client, i->conn, NULL, 0, i->context);
- silc_client_command_free(i->cmd);
- if (i->nickname)
- silc_free(i->nickname);
- if (i->server)
- silc_free(i->server);
+ silc_free(i->nickname);
+ silc_free(i->server);
silc_free(i);
}
SilcGetClientCallback completion,
void *context)
{
- char ident[512];
- SilcClientCommandContext ctx;
- GetClientInternal i = silc_calloc(1, sizeof(*i));
-
- /* No ID found. Do query from the server. The query is done by
- sending simple IDENTIFY command to the server. */
- ctx = silc_client_command_alloc();
- ctx->client = client;
- ctx->conn = conn;
- ctx->command = silc_client_command_find("IDENTIFY");
- memset(ident, 0, sizeof(ident));
- snprintf(ident, sizeof(ident), "IDENTIFY %s", nickname);
- silc_parse_command_line(ident, &ctx->argv, &ctx->argv_lens,
- &ctx->argv_types, &ctx->argc, 2);
-
- i->cmd = silc_client_command_dup(ctx);
- i->nickname = nickname ? strdup(nickname) : NULL;
+ GetClientInternal i;
+ char *userhost;
+
+ if (!nickname)
+ return;
+
+ i = silc_calloc(1, sizeof(*i));
+ i->client = client;
+ i->conn = conn;
+ i->nickname = strdup(nickname);
i->server = server ? strdup(server) : NULL;
i->completion = completion;
i->context = context;
- /* Call the command */
- ctx->command->cb(ctx, NULL);
+ if (nickname && server) {
+ userhost = silc_calloc(strlen(nickname) + strlen(server) + 2,
+ sizeof(*userhost));
+ strncat(userhost, nickname, strlen(nickname));
+ strncat(userhost, "@", 1);
+ strncat(userhost, server, strlen(server));
+ } else {
+ userhost = strdup(nickname);
+ }
+
+ /* Register our own command reply for this command */
+ silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
+ silc_client_command_reply_identify_i, 0,
+ ++conn->cmd_ident);
+
+ /* Send the command */
+ silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
+ conn->cmd_ident, 1, 1, userhost,
+ strlen(userhost));
/* Add pending callback */
- silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
- conn->cmd_ident,
+ silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
silc_client_get_client_destructor,
silc_client_command_get_client_callback,
(void *)i);
+
+ silc_free(userhost);
}
-/* Same as silc_client_get_clients function but does not resolve anything
- from the server. This checks local cache and returns all matching
- clients from the local cache. If none was found this returns NULL.
- The `nickname' is the real nickname of the client, and the `format'
- is the formatted nickname to find exact match from multiple found
- entries. The format must be same as given in the SilcClientParams
- structure to the client library. If the `format' is NULL all found
- clients by `nickname' are returned. */
+/* The old style function to find client entry. This is used by the
+ library internally. If `query' is TRUE then the client information is
+ requested by the server. The pending command callback must be set
+ by the caller. */
+/* XXX This function should be removed */
-SilcClientEntry *silc_client_get_clients_local(SilcClient client,
- SilcClientConnection conn,
- const char *nickname,
- const char *format,
- uint32 *clients_count)
+SilcClientEntry silc_idlist_get_client(SilcClient client,
+ SilcClientConnection conn,
+ const char *nickname,
+ const char *format,
+ bool query)
{
SilcIDCacheEntry id_cache;
SilcIDCacheList list = NULL;
- SilcClientEntry entry, *clients;
- int i = 0;
- bool found = FALSE;
+ SilcClientEntry entry = NULL;
+
+ SILC_LOG_DEBUG(("Start"));
/* Find ID from cache */
- if (!silc_idcache_find_by_name(conn->client_cache, (char *)nickname, &list))
- return NULL;
+ if (!silc_idcache_find_by_name(conn->client_cache, (char *)nickname,
+ &list)) {
+ identify:
- if (!silc_idcache_list_count(list)) {
- silc_idcache_list_free(list);
+ if (query) {
+ SILC_LOG_DEBUG(("Requesting Client ID from server"));
+
+ /* Register our own command reply for this command */
+ silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
+ silc_client_command_reply_identify_i, 0,
+ ++conn->cmd_ident);
+
+ /* Send the command */
+ silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
+ conn->cmd_ident, 1, 1, nickname,
+ strlen(nickname));
+
+ if (list)
+ silc_idcache_list_free(list);
+
+ return NULL;
+ }
return NULL;
}
- clients = silc_calloc(silc_idcache_list_count(list), sizeof(*clients));
- *clients_count = silc_idcache_list_count(list);
-
if (!format) {
- /* Take all without any further checking */
- silc_idcache_list_first(list, &id_cache);
- while (id_cache) {
- clients[i++] = id_cache->context;
- found = TRUE;
- if (!silc_idcache_list_next(list, &id_cache))
- break;
- }
+ /* Take first found cache entry */
+ if (!silc_idcache_list_first(list, &id_cache))
+ goto identify;
+
+ entry = (SilcClientEntry)id_cache->context;
} else {
/* Check multiple cache entries for match */
silc_idcache_list_first(list, &id_cache);
while (id_cache) {
entry = (SilcClientEntry)id_cache->context;
+
if (strcasecmp(entry->nickname, format)) {
if (!silc_idcache_list_next(list, &id_cache)) {
+ entry = NULL;
break;
} else {
+ entry = NULL;
continue;
}
}
-
- clients[i++] = id_cache->context;
- found = TRUE;
- if (!silc_idcache_list_next(list, &id_cache))
- break;
+
+ break;
}
+
+ /* If match weren't found, request it */
+ if (!entry)
+ goto identify;
}
if (list)
silc_idcache_list_free(list);
- if (!found) {
- *clients_count = 0;
- if (clients)
- silc_free(clients);
- return NULL;
- }
-
- return clients;
+ return entry;
}
+
typedef struct {
SilcClient client;
SilcClientConnection conn;
NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
TRUE);
- silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
- conn->cmd_ident,
+ /* Register our own command reply for this command */
+ silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
+ silc_client_command_reply_identify_i, 0,
+ conn->cmd_ident);
+
+ /* 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);
silc_client_command_get_clients_list_callback((void *)in, NULL);
}
-/* The old style function to find client entry. This is used by the
- library internally. If `query' is TRUE then the client information is
- requested by the server. The pending command callback must be set
- by the caller. */
-
-SilcClientEntry silc_idlist_get_client(SilcClient client,
- SilcClientConnection conn,
- const char *nickname,
- const char *format,
- bool query)
-{
- SilcIDCacheEntry id_cache;
- SilcIDCacheList list = NULL;
- SilcClientEntry entry = NULL;
-
- SILC_LOG_DEBUG(("Start"));
-
- /* Find ID from cache */
- if (!silc_idcache_find_by_name(conn->client_cache, (char *)nickname,
- &list)) {
- identify:
-
- if (query) {
- char ident[512];
- SilcClientCommandContext ctx;
-
- SILC_LOG_DEBUG(("Requesting Client ID from server"));
-
- /* No ID found. Do query from the server. The query is done by
- sending simple IDENTIFY command to the server. */
- ctx = silc_client_command_alloc();
- ctx->client = client;
- ctx->conn = conn;
- ctx->command = silc_client_command_find("IDENTIFY");
- memset(ident, 0, sizeof(ident));
- snprintf(ident, sizeof(ident), "IDENTIFY %s", nickname);
- silc_parse_command_line(ident, &ctx->argv, &ctx->argv_lens,
- &ctx->argv_types, &ctx->argc, 2);
- ctx->command->cb(ctx, NULL);
-
- if (list)
- silc_idcache_list_free(list);
-
- return NULL;
- }
- return NULL;
- }
-
- if (!format) {
- /* Take first found cache entry */
- if (!silc_idcache_list_first(list, &id_cache))
- goto identify;
-
- entry = (SilcClientEntry)id_cache->context;
- } else {
- /* Check multiple cache entries for match */
- silc_idcache_list_first(list, &id_cache);
- while (id_cache) {
- entry = (SilcClientEntry)id_cache->context;
-
- if (strcasecmp(entry->nickname, format)) {
- if (!silc_idcache_list_next(list, &id_cache)) {
- entry = NULL;
- break;
- } else {
- entry = NULL;
- continue;
- }
- }
-
- break;
- }
-
- /* If match weren't found, request it */
- if (!entry)
- goto identify;
- }
-
- if (list)
- silc_idcache_list_free(list);
-
- return entry;
-}
-
/* Finds entry for client by the client's ID. Returns the entry or NULL
if the entry was not found. */
SILC_LOG_DEBUG(("Start"));
- idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
- silc_client_send_command(client, conn, SILC_COMMAND_WHOIS,
- ++conn->cmd_ident,
- 1, 3, idp->data, idp->len);
- silc_buffer_free(idp);
-
i->client = client;
i->conn = conn;
i->client_id = silc_id_dup(client_id, SILC_ID_CLIENT);
i->completion = completion;
i->context = context;
+ /* Register our own command reply for this command */
+ silc_client_command_register(client, SILC_COMMAND_WHOIS, NULL, NULL,
+ silc_client_command_reply_whois_i, 0,
+ ++conn->cmd_ident);
+
+ /* Send the command */
+ idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
+ silc_client_command_send(client, conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
+ 1, 3, idp->data, idp->len);
+ silc_buffer_free(idp);
+
/* Add pending callback */
- silc_client_command_pending(conn, SILC_COMMAND_WHOIS,
- conn->cmd_ident,
+ 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);
}
+
+/******************************************************************************
+
+ Client, Channel and Server entry manipulation
+
+******************************************************************************/
+
+
/* Creates new client entry and adds it to the ID cache. Returns pointer
to the new entry. */
SILC_LOG_DEBUG(("Start"));
- idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
- silc_client_send_command(client, conn, SILC_COMMAND_IDENTIFY,
- ++conn->cmd_ident,
- 1, 5, idp->data, idp->len);
- silc_buffer_free(idp);
-
i->client = client;
i->conn = conn;
i->channel_id = silc_id_dup(channel_id, SILC_ID_CHANNEL);
i->completion = completion;
i->context = context;
+ /* Register our own command reply for this command */
+ silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
+ silc_client_command_reply_identify_i, 0,
+ ++conn->cmd_ident);
+
+ /* Send the command */
+ idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
+ silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
+ conn->cmd_ident,
+ 1, 5, idp->data, idp->len);
+ silc_buffer_free(idp);
+
/* Add pending callback */
- silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
- conn->cmd_ident,
+ 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);
return channel;
if (query) {
+ /* Register our own command reply for this command */
+ silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
+ silc_client_command_reply_identify_i, 0,
+ ++conn->cmd_ident);
+
+ /* Send the command */
idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
- silc_client_send_command(client, conn, SILC_COMMAND_IDENTIFY,
- ++conn->cmd_ident,
+ silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
+ conn->cmd_ident,
1, 5, idp->data, idp->len);
silc_buffer_free(idp);
}
SILC_LOG_DEBUG(("Start"));
- if (!client->params->nickname_format[0])
+ if (!client->internal->params->nickname_format[0])
return;
if (!client_entry->nickname)
clients = silc_client_get_clients_local(client, conn,
client_entry->nickname, NULL,
&clients_count);
- if (!clients && !client->params->nickname_force_format)
+ if (!clients && !client->internal->params->nickname_force_format)
return;
len = 0;
if (!len)
return;
- cp = client->params->nickname_format;
+ cp = client->internal->params->nickname_format;
while (*cp) {
if (*cp == '%') {
cp++;
verify->completion_context = completion_context;
/* Verify public key from user. */
- client->ops->verify_public_key(client, ctx->sock->user_data,
- ctx->sock->type,
- pk_data, pk_len, pk_type,
- silc_client_verify_key_cb, verify);
+ client->internal->ops->verify_public_key(client, ctx->sock->user_data,
+ ctx->sock->type,
+ pk_data, pk_len, pk_type,
+ silc_client_verify_key_cb, verify);
}
/* Sets the negotiated key material into use for particular connection. */
if (cp)
build = atoi(cp + 1);
- cp = client->silc_client_version + 9;
+ cp = client->internal->silc_client_version + 9;
if (!cp)
status = SILC_SKE_STATUS_BAD_VERSION;
ske->backward_version = 1;
if (status != SILC_SKE_STATUS_OK)
- client->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
- "We don't support server version `%s'", version);
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
+ "We don't support server version `%s'",
+ version);
return status;
}
if (ske->status != SILC_SKE_STATUS_OK) {
/* Call failure client operation */
- client->ops->failure(client, conn, protocol, (void *)ske->status);
+ client->internal->ops->failure(client, conn, protocol,
+ (void *)ske->status);
protocol->state = SILC_PROTOCOL_STATE_ERROR;
silc_protocol_execute(protocol, client->schedule, 0, 0);
return;
if (ctx->responder == TRUE) {
/* Start the key exchange by processing the received security
properties packet from initiator. */
- status = silc_ske_responder_start(ske, ctx->rng, ctx->sock,
- client->silc_client_version,
- ctx->packet->buffer, TRUE);
+ status =
+ silc_ske_responder_start(ske, ctx->rng, ctx->sock,
+ client->internal->silc_client_version,
+ ctx->packet->buffer, TRUE);
} else {
SilcSKEStartPayload *start_payload;
/* Assemble security properties. */
- silc_ske_assemble_security_properties(ske, SILC_SKE_SP_FLAG_MUTUAL,
- client->silc_client_version,
- &start_payload);
+ silc_ske_assemble_security_properties(
+ ske, SILC_SKE_SP_FLAG_MUTUAL,
+ client->internal->silc_client_version,
+ &start_payload);
/* Start the key exchange by sending our security properties
to the remote end. */
if (status != SILC_SKE_STATUS_OK) {
if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY) {
- client->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
- "Received unsupported server %s public key",
- ctx->sock->hostname);
+ client->internal->ops->say(
+ client, conn, SILC_CLIENT_MESSAGE_AUDIT,
+ "Received unsupported server %s public key",
+ ctx->sock->hostname);
} else {
- client->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
+ client->internal->ops->say(
+ client, conn, SILC_CLIENT_MESSAGE_AUDIT,
"Error during key exchange protocol with server %s",
ctx->sock->hostname);
}
break;
}
- client->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
- "Password authentication required by server %s",
- ctx->sock->hostname);
- client->ops->ask_passphrase(client, conn,
- silc_client_conn_auth_continue,
- protocol);
+ client->internal->ops->say(
+ client, conn, SILC_CLIENT_MESSAGE_INFO,
+ "Password authentication required by server %s",
+ ctx->sock->hostname);
+ client->internal->ops->ask_passphrase(client, conn,
+ silc_client_conn_auth_continue,
+ protocol);
return;
break;
*
* SYNOPSIS
*
- * SilcClientCommandContext silc_client_command_alloc();
+ * SilcClientCommandContext silc_client_command_alloc(void);
*
* DESCRIPTION
*
* context.
*
***/
-SilcClientCommandContext silc_client_command_alloc();
+SilcClientCommandContext silc_client_command_alloc(void);
/****f* silcclient/SilcClientAPI/silc_client_command_free
*
*
* SYNOPSIS
*
- * SilcClientCommand *silc_client_command_find(const char *name);
+ * SilcClientCommand silc_client_command_find(SilcClient client,
+ * const char *name);
*
* DESCRIPTION
*
* command is not found. See the `command.[ch]' for the command list.
*
***/
-SilcClientCommand *silc_client_command_find(const char *name);
+SilcClientCommand silc_client_command_find(SilcClient client,
+ const char *name);
-/****f* silcclient/SilcClientAPI/silc_client_send_command
+/****f* silcclient/SilcClientAPI/silc_client_command_call
*
* SYNOPSIS
*
- * void silc_client_send_command(SilcClient client,
+ * void silc_client_command_call(SilcClientCommand command);
+ *
+ * DESCRIPTION
+ *
+ * Calls the command (executes it). Application can call this after
+ * it has allocated the SilcClientCommandContext with the function
+ * silc_client_command_alloc and found the command from the client
+ * library by calling silc_client_command_find. This will execute
+ * the command.
+ *
+ * Application can call the command function directly too if it
+ * wishes to do so. See the command.h for details of the
+ * SilcClientCommand structure.
+ *
+ ***/
+void silc_client_command_call(SilcClientCommand command,
+ SilcClientCommandContext cmd);
+
+/****f* silcclient/SilcClientAPI/silc_client_command_send
+ *
+ * SYNOPSIS
+ *
+ * void silc_client_command_send(SilcClient client,
* SilcClientConnection conn,
* SilcCommand command, uint16 ident,
* uint32 argc, ...);
* DESCRIPTION
*
* Generic function to send any command. The arguments must be sent already
- * encoded into correct form and in correct order.
+ * encoded into correct form and in correct order. If application wants
+ * to perform the commands by itself, it can do so and send the data
+ * directly to the server using this function. If application is using
+ * the silc_client_command_call, this function is usually not used.
*
***/
-void silc_client_send_command(SilcClient client, SilcClientConnection conn,
+void silc_client_command_send(SilcClient client, SilcClientConnection conn,
SilcCommand command, uint16 ident,
uint32 argc, ...);
*
* Add new pending command to be executed when reply to a command has been
* received. The `reply_cmd' is the command that will call the `callback'
- * with `context' when reply has been received. If `ident is non-zero
+ * with `context' when reply has been received. If `ident' is non-zero
* the `callback' will be executed when received reply with command
* identifier `ident'.
*
+ * Note that the application is notified about the received command
+ * reply through the `command_reply' client operation before calling
+ * the `callback` pending command callback.
+ *
***/
void silc_client_command_pending(SilcClientConnection conn,
SilcCommand reply_cmd,
# SILC Distribution versions. Set here or give the version on the command
# line as argument.
#
-SILC_VERSION=0.7 # Base version
+SILC_VERSION=0.7.1 # Base version
#############################################################################
and thus not require any memory allocation. Same will happen
with silc_id_payload_* functions.
+ o Rewrite the lib/silcutil/silcprotocol.[ch] not to have
+ [un]register functions, but to make it context based all
+ the way. The alloc should take as argument the protocol
+ type and its callback (not only final callback). It is not
+ good that we have now global list of registered protocols.
+
+
o Server
o When processing the decrypted and parsed packet we call the