}
/* 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
- the `callback' will be executed when received reply with command
- identifier `ident'. */
+ received. The `reply_cmd' is the command that will call the `callback'
+ with `context' when reply has been received. It can be SILC_COMMAND_NONE
+ to match any command with the `ident'. If `ident' is non-zero
+ the `callback' will be executed when received reply with command
+ identifier `ident'. If there already exists pending command for the
+ specified command, ident, callback and context this function has no
+ effect. */
void silc_client_command_pending(SilcClientConnection conn,
SilcCommand reply_cmd,
{
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;
}
/* Checks for pending commands and marks callbacks to be called from
- the command reply function. Returns TRUE if there were pending command. */
-
-int silc_client_command_pending_check(SilcClientConnection conn,
- SilcClientCommandReplyContext ctx,
- SilcCommand command,
- SilcUInt16 ident)
+ the command reply function. */
+
+SilcClientCommandPendingCallbacks
+silc_client_command_pending_check(SilcClientConnection conn,
+ SilcClientCommandReplyContext ctx,
+ SilcCommand command,
+ SilcUInt16 ident,
+ SilcUInt32 *callbacks_count)
{
SilcClientCommandPending *r;
+ SilcClientCommandPendingCallbacks callbacks = NULL;
+ int i = 0;
silc_dlist_start(conn->pending_commands);
while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
- if (r->reply_cmd == command && r->ident == ident) {
- ctx->context = r->context;
- ctx->callback = r->callback;
+ if ((r->reply_cmd == command || r->reply_cmd == SILC_COMMAND_NONE)
+ && r->ident == ident) {
+ callbacks = silc_realloc(callbacks, sizeof(*callbacks) * (i + 1));
+ callbacks[i].context = r->context;
+ callbacks[i].callback = r->callback;
ctx->ident = ident;
- return TRUE;
+ i++;
}
}
- return FALSE;
+ *callbacks_count = i;
+ return callbacks;
}
/* Allocate Command Context */
SilcClientCommandContext cmd = (SilcClientCommandContext)context;
SilcClientConnection conn = cmd->conn;
SilcBuffer buffer;
+ unsigned char count[4];
if (!cmd->conn) {
SILC_NOT_CONNECTED(cmd->client, cmd->conn);
goto out;
}
- buffer = silc_command_payload_encode(SILC_COMMAND_WHOIS,
- cmd->argc - 1, ++cmd->argv,
- ++cmd->argv_lens, ++cmd->argv_types,
- 0);
+ if (cmd->argc == 2) {
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
+ ++conn->cmd_ident, 1,
+ 1, cmd->argv[1],
+ cmd->argv_lens[1]);
+ } else {
+ int c = atoi(cmd->argv[2]);
+ memset(count, 0, sizeof(count));
+ SILC_PUT32_MSB(c, count);
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
+ ++conn->cmd_ident, 2,
+ 1, cmd->argv[1], cmd->argv_lens[1],
+ 2, count, sizeof(count));
+ }
silc_client_packet_send(cmd->client, cmd->conn->sock,
SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
buffer->data, buffer->len, TRUE);
silc_buffer_free(buffer);
- cmd->argv--;
- cmd->argv_lens--;
- cmd->argv_types--;
/* Notify application */
COMMAND;
SilcClientCommandContext cmd = (SilcClientCommandContext)context;
SilcClientConnection conn = cmd->conn;
SilcBuffer buffer;
+ unsigned char count[4];
if (!cmd->conn) {
SILC_NOT_CONNECTED(cmd->client, cmd->conn);
goto out;
}
- buffer = silc_command_payload_encode(SILC_COMMAND_WHOWAS,
- cmd->argc - 1, ++cmd->argv,
- ++cmd->argv_lens, ++cmd->argv_types,
- 0);
+ if (cmd->argc == 2) {
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOWAS,
+ ++conn->cmd_ident, 1,
+ 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);
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOWAS,
+ ++conn->cmd_ident, 2,
+ 1, cmd->argv[1], cmd->argv_lens[1],
+ 2, count, sizeof(count));
+ }
silc_client_packet_send(cmd->client, cmd->conn->sock,
SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
buffer->data, buffer->len, TRUE);
silc_buffer_free(buffer);
- cmd->argv--;
- cmd->argv_lens--;
- cmd->argv_types--;
/* Notify application */
COMMAND;
SilcClientCommandContext cmd = (SilcClientCommandContext)context;
SilcClientConnection conn = cmd->conn;
SilcBuffer buffer;
+ unsigned char count[4];
if (!cmd->conn) {
SILC_NOT_CONNECTED(cmd->client, cmd->conn);
if (cmd->argc < 2 || cmd->argc > 3)
goto out;
- if (cmd->argc == 2)
+ if (cmd->argc == 2) {
buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
++conn->cmd_ident, 1,
1, cmd->argv[1],
cmd->argv_lens[1]);
- else
+ } else {
+ int c = atoi(cmd->argv[2]);
+ memset(count, 0, sizeof(count));
+ SILC_PUT32_MSB(c, count);
buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
++conn->cmd_ident, 2,
1, cmd->argv[1],
cmd->argv_lens[1],
- 4, cmd->argv[2],
- cmd->argv_lens[2]);
+ 4, count, sizeof(count));
+ }
silc_client_packet_send(cmd->client, cmd->conn->sock,
SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
SilcClientConnection conn = cmd->conn;
SilcClientCommandReplyContext reply =
(SilcClientCommandReplyContext)context2;
- SilcCommandStatus status;
+ SilcStatus status;
silc_command_get_status(reply->payload, &status, NULL);
if (status == SILC_STATUS_OK) {
SilcClientCommandContext cmd = (SilcClientCommandContext)context;
SilcClientCommandReplyContext reply =
(SilcClientCommandReplyContext)context2;
- SilcCommandStatus status;
+ SilcStatus status;
silc_command_get_status(reply->payload, &status, NULL);
if (status == SILC_STATUS_OK) {
chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
/* Send the command */
- if (ban)
- buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2,
- 1, chidp->data, chidp->len,
- type, ban, strlen(ban));
- else
- buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1,
- 1, chidp->data, chidp->len);
-
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN,
+ ++conn->cmd_ident, 2,
+ 1, chidp->data, chidp->len,
+ type, ban, ban ? strlen(ban) : 0);
silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
0, NULL, NULL, buffer->data, buffer->len, TRUE);
silc_buffer_free(buffer);
silc_client_command_free(cmd);
}
+/* Command DETACH. This is used to detach from the server */
+
+SILC_CLIENT_CMD_FUNC(detach)
+{
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+ SilcClientConnection conn = cmd->conn;
+ SilcBuffer buffer;
+
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR;
+ goto out;
+ }
+
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_DETACH,
+ ++conn->cmd_ident, 0);
+ silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
+ 0, NULL, NULL, buffer->data, buffer->len, TRUE);
+ silc_buffer_free(buffer);
+
+ /* Notify application */
+ COMMAND;
+
+ out:
+ silc_client_command_free(cmd);
+}
+
/* LEAVE command. Leaves a channel. Client removes itself from a channel. */
SILC_CLIENT_CMD_FUNC(leave)
} else {
SilcClientCommandReplyContext reply =
(SilcClientCommandReplyContext)context2;
- SilcCommandStatus error;
+ SilcStatus error;
/* If nickname was not found, then resolve the server. */
silc_command_get_status(reply->payload, NULL, &error);
server and did not find anybody. */
if (error == SILC_STATUS_ERR_NO_SUCH_SERVER) {
SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
- silc_client_command_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
+ silc_client_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
- silc_client_command_status_message(error));
+ silc_client_status_message(error));
COMMAND_ERROR;
goto out;
}
SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 5);
SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
+ SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
SILC_CLIENT_CMD(users, USERS, "USERS", 2);
SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
SILC_CLIENT_CMDU(kick, KICK, "KICK");
SILC_CLIENT_CMDU(ban, BAN, "BAN");
+ SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
SILC_CLIENT_CMDU(users, USERS, "USERS");