{
SilcClientCommandPending *reply;
- /* Check whether identical pending already exists for same command,
- ident, callback and callback context. If it does then it would be
- error to register it again. */
- silc_dlist_start(conn->pending_commands);
- while ((reply = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
- if (reply->reply_cmd == reply_cmd && reply->ident == ident &&
- reply->callback == callback && reply->context == context)
- return;
- }
-
reply = silc_calloc(1, sizeof(*reply));
reply->reply_cmd = reply_cmd;
reply->ident = ident;
{
SilcClientCommandPending *r;
+ if (!conn->pending_commands)
+ return;
+
silc_dlist_start(conn->pending_commands);
while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
- if (r->reply_cmd == reply_cmd && r->ident == ident) {
+ if ((r->reply_cmd == reply_cmd || (r->reply_cmd == SILC_COMMAND_NONE &&
+ r->reply_check))
+ && r->ident == ident) {
silc_dlist_del(conn->pending_commands, r);
- break;
+ silc_free(r);
}
}
}
callbacks = silc_realloc(callbacks, sizeof(*callbacks) * (i + 1));
callbacks[i].context = r->context;
callbacks[i].callback = r->callback;
+ r->reply_check = TRUE;
ctx->ident = ident;
i++;
}
{
SilcClientCommandContext cmd = (SilcClientCommandContext)context;
SilcClientConnection conn = cmd->conn;
- SilcBuffer buffer;
- unsigned char count[4];
+ SilcBuffer buffer, attrs = NULL;
+ unsigned char count[4], *tmp = NULL;
if (!cmd->conn) {
SILC_NOT_CONNECTED(cmd->client, cmd->conn);
buffer = silc_id_payload_encode(cmd->conn->local_id, SILC_ID_CLIENT);
silc_client_command_send(cmd->client, cmd->conn, SILC_COMMAND_WHOIS,
++conn->cmd_ident,
- 1, 3, buffer->data, buffer->len);
+ 1, 4, buffer->data, buffer->len);
silc_buffer_free(buffer);
goto out;
}
1, cmd->argv[1],
cmd->argv_lens[1]);
} else {
- int c = atoi(cmd->argv[2]);
- memset(count, 0, sizeof(count));
- SILC_PUT32_MSB(c, count);
+ if (!strcasecmp(cmd->argv[2], "-details"))
+ attrs = silc_client_attributes_request(0);
+
+ if (!attrs || cmd->argc > 3) {
+ int c = atoi(cmd->argc > 3 ? cmd->argv[3] : cmd->argv[2]);
+ SILC_PUT32_MSB(c, count);
+ tmp = count;
+ }
+
buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
- ++conn->cmd_ident, 2,
+ ++conn->cmd_ident, 3,
1, cmd->argv[1], cmd->argv_lens[1],
- 2, count, sizeof(count));
+ 2, tmp ? tmp : NULL, tmp ? 4 : 0,
+ 3, attrs ? attrs->data : NULL,
+ attrs ? attrs->len : 0);
}
silc_client_packet_send(cmd->client, cmd->conn->sock,
SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
silc_client_command_free(cmd);
}
-/* Pending callbcak that will be called after the NICK command was
- replied by the server. This sets the nickname if there were no
- errors. */
-
-SILC_CLIENT_CMD_FUNC(nick_change)
-{
- SilcClientCommandContext cmd = (SilcClientCommandContext)context;
- SilcClientConnection conn = cmd->conn;
- SilcClientCommandReplyContext reply =
- (SilcClientCommandReplyContext)context2;
- SilcStatus status;
-
- silc_command_get_status(reply->payload, &status, NULL);
- if (status == SILC_STATUS_OK) {
- /* Set the nickname */
- silc_idcache_del_by_context(conn->client_cache, conn->local_entry);
- if (conn->nickname)
- 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(SILC_STATUS_OK);
- } else {
- COMMAND_ERROR(status);
- }
-
- silc_client_command_free(cmd);
-}
-
/* Command NICK. Shows current nickname/sets new nickname on current
window. */
buffer->data, buffer->len, TRUE);
silc_buffer_free(buffer);
- /* Register pending callback that will actually set the new nickname
- if there were no errors returned by the server. */
- silc_client_command_pending(conn, SILC_COMMAND_NICK,
- cmd->conn->cmd_ident,
- silc_client_command_nick_change,
- silc_client_command_dup(cmd));
- cmd->pending = TRUE;
-
out:
silc_client_command_free(cmd);
}
if (cmd->argv[1][0] == '*') {
if (!conn->current_channel) {
- SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "You are not on any channel");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
goto out;
}
}
if (!conn->current_channel) {
- SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "You are not on that channel");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
goto out;
}
/* Get the Channel ID of the channel */
if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
- SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "You are not on that channel");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
goto out;
}
if (cmd->argv[1][0] == '*') {
if (!conn->current_channel) {
- SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "You are not on any channel");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
goto out;
}
channel = silc_client_get_channel(cmd->client, conn, name);
if (!channel) {
- SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "You are on that channel");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
goto out;
}
QuitInternal q = (QuitInternal)context;
/* Close connection */
- q->client->internal->ops->disconnect(q->client, q->conn);
+ q->client->internal->ops->disconnect(q->client, q->conn, 0, NULL);
silc_client_close_connection(q->client, q->conn->sock->user_data);
silc_free(q);
silc_client_command_free(cmd);
}
+/* Command STATS. Shows server and network statistics. */
+
+SILC_CLIENT_CMD_FUNC(stats)
+{
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+ SilcClientConnection conn = cmd->conn;
+ SilcBuffer buffer, idp = NULL;
+
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
+ goto out;
+ }
+
+ idp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
+
+ /* Send the command */
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_STATS,
+ ++conn->cmd_ident, 1,
+ SILC_ID_SERVER, idp->data, idp->len);
+ silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
+ 0, NULL, NULL, buffer->data, buffer->len, TRUE);
+ silc_buffer_free(buffer);
+ silc_buffer_free(idp);
+
+ /* Notify application */
+ COMMAND(SILC_STATUS_OK);
+
+ out:
+ silc_client_command_free(cmd);
+}
+
/* Command PING. Sends ping to server. This is used to test the
communication channel. */
} else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
hmac = cmd->argv[i + 1];
i++;
- } else if (!strcasecmp(cmd->argv[i], "-founder") && cmd->argc > i + 1) {
- if (!strcasecmp(cmd->argv[i + 1], "-pubkey")) {
- auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
- cmd->client->private_key,
- cmd->client->rng, conn->hash,
- conn->local_id,
- SILC_ID_CLIENT);
- } else {
- auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
- cmd->argv[i + 1],
- cmd->argv_lens[i + 1]);
- }
+ } else if (!strcasecmp(cmd->argv[i], "-founder")) {
+ auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
+ cmd->client->private_key,
+ cmd->client->rng,
+ cmd->client->sha1hash,
+ conn->local_id,
+ SILC_ID_CLIENT);
i++;
} else {
/* Passphrases must be UTF-8 encoded, so encode if it is not */
if (cmd->argv[1][0] == '*') {
if (!conn->current_channel) {
- SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "You are not on any channel");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
goto out;
}
channel = silc_client_get_channel(cmd->client, conn, name);
if (!channel) {
- SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "You are on that channel");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
goto out;
}
if (add) {
mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
type = 7;
-
- if (cmd->argc < 4) {
- SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
-
- if (!strcasecmp(cmd->argv[3], "-pubkey")) {
- auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
- cmd->client->private_key,
- cmd->client->rng,
- conn->hash,
- conn->local_id,
- SILC_ID_CLIENT);
- } else {
- auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
- cmd->argv[3], cmd->argv_lens[3]);
- }
-
+ auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
+ cmd->client->private_key,
+ cmd->client->rng,
+ cmd->client->sha1hash,
+ conn->local_id,
+ SILC_ID_CLIENT);
arg = auth->data;
arg_len = auth->len;
} else {
if (cmd->argv[1][0] == '*') {
if (!conn->current_channel) {
- SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "You are not on any channel");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
goto out;
}
channel = silc_client_get_channel(cmd->client, conn, name);
if (!channel) {
- SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "You are on that channel");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
goto out;
}
break;
case 'f':
if (add) {
- if (cmd->argc == 5) {
- if (!strcasecmp(cmd->argv[4], "-pubkey")) {
- auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
- cmd->client->private_key,
- cmd->client->rng,
- conn->hash,
- conn->local_id,
- SILC_ID_CLIENT);
- } else {
- auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
- cmd->argv[4], cmd->argv_lens[4]);
- }
- }
+ auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
+ cmd->client->private_key,
+ cmd->client->rng,
+ cmd->client->sha1hash,
+ conn->local_id,
+ SILC_ID_CLIENT);
mode |= SILC_CHANNEL_UMODE_CHANFO;
} else {
mode &= ~SILC_CHANNEL_UMODE_CHANFO;
else
mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
break;
+ case 'q':
+ if (add)
+ mode |= SILC_CHANNEL_UMODE_QUIET;
+ else
+ mode &= ~SILC_CHANNEL_UMODE_QUIET;
+ break;
default:
COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
goto out;
if (cmd->argv[1][0] == '*') {
if (!conn->current_channel) {
- SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "You are not on any channel");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
goto out;
}
}
if (!conn->current_channel) {
- SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "You are not on that channel");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
goto out;
}
/* Get the Channel ID of the channel */
if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
- SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "You are not on that channel");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
goto out;
}
buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1, cmd->argv[1],
strlen(cmd->argv[1]),
- 2, auth->data, auth->len);
+ 2, auth ? auth->data : NULL,
+ auth ? auth->len : 0);
silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
0, NULL, NULL, buffer->data, buffer->len, TRUE);
buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1, cmd->argv[1],
strlen(cmd->argv[1]),
- 2, auth->data, auth->len);
+ 2, auth ? auth->data : NULL,
+ auth ? auth->len : 0);
silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
0, NULL, NULL, buffer->data, buffer->len, TRUE);
if (cmd->argv[1][0] == '*') {
if (!conn->current_channel) {
- SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "You are not on any channel");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
goto out;
}
channel = silc_client_get_channel(cmd->client, conn, name);
if (!channel) {
- SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "You are noton that channel");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
goto out;
}
if (cmd->argv[1][0] == '*') {
if (!conn->current_channel) {
- SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "You are not on any channel");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
goto out;
}
/* Get the channel entry */
channel = silc_client_get_channel(cmd->client, conn, name);
if (!channel) {
- SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "You are not on that channel");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
goto out;
}
if (cmd->argv[1][0] == '*') {
if (!conn->current_channel) {
- SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "You are not on any channel");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
goto out;
}
SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
SILC_CLIENT_CMD(kill, KILL, "KILL", 3);
SILC_CLIENT_CMD(info, INFO, "INFO", 2);
+ SILC_CLIENT_CMD(stats, STATS, "STATS", 0);
SILC_CLIENT_CMD(ping, PING, "PING", 2);
SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
SILC_CLIENT_CMDU(kill, KILL, "KILL");
SILC_CLIENT_CMDU(info, INFO, "INFO");
+ SILC_CLIENT_CMDU(stats, STATS, "STATS");
SILC_CLIENT_CMDU(ping, PING, "PING");
SILC_CLIENT_CMDU(oper, OPER, "OPER");
SILC_CLIENT_CMDU(join, JOIN, "JOIN");
SILC_CLIENT_CMDU(close, PRIV_CLOSE, "CLOSE");
SILC_CLIENT_CMDU(shutdown, PRIV_SHUTDOWN, "SHUTDOWN");
}
+
+/**** Client side incoming command handling **********************************/
+
+void silc_client_command_process_whois(SilcClient client,
+ SilcSocketConnection sock,
+ SilcCommandPayload payload,
+ SilcArgumentPayload args);
+
+/* Client is able to receive some command packets even though they are
+ special case. Server may send WHOIS command to the client to retrieve
+ Requested Attributes information for WHOIS query the server is
+ processing. This function currently handles only the WHOIS command,
+ but if in the future for commands may arrive then this can be made
+ to support other commands too. */
+
+void silc_client_command_process(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcCommandPayload payload;
+ SilcCommand command;
+ SilcArgumentPayload args;
+
+ /* Get command payload from packet */
+ payload = silc_command_payload_parse(packet->buffer->data,
+ packet->buffer->len);
+ if (!payload) {
+ /* Silently ignore bad reply packet */
+ SILC_LOG_DEBUG(("Bad command packet"));
+ return;
+ }
+
+ /* Get arguments */
+ args = silc_command_get_args(payload);
+
+ /* Get the command */
+ command = silc_command_get(payload);
+ switch (command) {
+
+ case SILC_COMMAND_WHOIS:
+ /* Ignore everything if requested by application */
+ if (client->internal->params->ignore_requested_attributes)
+ break;
+
+ silc_client_command_process_whois(client, sock, payload, args);
+ break;
+
+ default:
+ break;
+ }
+
+ silc_command_payload_free(payload);
+}
+
+void silc_client_command_process_whois(SilcClient client,
+ SilcSocketConnection sock,
+ SilcCommandPayload payload,
+ SilcArgumentPayload args)
+{
+ SilcDList attrs;
+ unsigned char *tmp;
+ SilcUInt32 tmp_len;
+ SilcBuffer buffer, packet;
+
+ SILC_LOG_DEBUG(("Received WHOIS command"));
+
+ /* Try to take the Requested Attributes */
+ tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
+ if (!tmp)
+ return;
+
+ attrs = silc_attribute_payload_parse(tmp, tmp_len);
+ if (!attrs)
+ return;
+
+ /* Process requested attributes */
+ buffer = silc_client_attributes_process(client, sock, attrs);
+ if (!buffer) {
+ silc_attribute_payload_list_free(attrs);
+ return;
+ }
+
+ /* Send the attributes back */
+ packet =
+ silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
+ SILC_STATUS_OK, 0,
+ silc_command_get_ident(payload),
+ 1, 11, buffer->data, buffer->len);
+ silc_client_packet_send(client, sock, SILC_PACKET_COMMAND_REPLY,
+ NULL, 0, NULL, NULL, packet->data,
+ packet->len, TRUE);
+ silc_buffer_free(packet);
+ silc_buffer_free(buffer);
+}