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, 1),
+ 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, 2),
SILC_CLIENT_CMD(info, INFO, "INFO", SILC_CF_LAG | SILC_CF_REG, 2),
void silc_client_command_pending(SilcClientConnection conn,
SilcCommand reply_cmd,
unsigned short ident,
+ SilcClientPendingDestructor destructor,
SilcCommandCb callback,
void *context)
{
reply->ident = ident;
reply->context = context;
reply->callback = callback;
+ reply->destructor = destructor;
silc_dlist_add(conn->pending_commands, reply);
}
if (r->reply_cmd == command && r->ident == ident) {
ctx->context = r->context;
ctx->callback = r->callback;
+ ctx->destructor = r->destructor;
ctx->ident = ident;
return TRUE;
}
return FALSE;
}
+/* Allocate Command Context */
+
+SilcClientCommandContext silc_client_command_alloc()
+{
+ SilcClientCommandContext ctx = silc_calloc(1, sizeof(*ctx));
+ ctx->users++;
+ return ctx;
+}
+
/* Free command context and its internals */
-void silc_client_command_free(SilcClientCommandContext cmd)
+void silc_client_command_free(SilcClientCommandContext ctx)
{
- int i;
+ ctx->users--;
+ SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users + 1,
+ ctx->users));
+ if (ctx->users < 1) {
+ int i;
- if (cmd) {
- for (i = 0; i < cmd->argc; i++)
- silc_free(cmd->argv[i]);
- silc_free(cmd);
+ for (i = 0; i < ctx->argc; i++)
+ silc_free(ctx->argv[i]);
+ silc_free(ctx);
}
}
+/* Duplicate Command Context by adding reference counter. The context won't
+ be free'd untill it hits zero. */
+
+SilcClientCommandContext
+silc_client_command_dup(SilcClientCommandContext ctx)
+{
+ ctx->users++;
+ SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users - 1,
+ ctx->users));
+ return ctx;
+}
+
+/* Pending command destructor. */
+
+static void silc_client_command_destructor(void *context)
+{
+ silc_client_command_free((SilcClientCommandContext)context);
+}
+
/* Command WHOIS. This command is used to query information about
specific user. */
/* Client entry not found, it was requested thus mark this to be
pending command. */
silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, 0,
- silc_client_command_invite, context);
+ silc_client_command_destructor,
+ silc_client_command_invite,
+ silc_client_command_dup(cmd));
+ cmd->pending = 1;
return;
}
silc_client_command_free(cmd);
}
+typedef struct {
+ SilcClient client;
+ SilcClientConnection conn;
+} *QuitInternal;
+
+SILC_TASK_CALLBACK(silc_client_command_quit_cb)
+{
+ QuitInternal q = (QuitInternal)context;
+
+ /* Close connection */
+ q->client->ops->disconnect(q->client, q->conn);
+ silc_client_close_connection(q->client, q->conn->sock);
+
+ silc_free(q);
+}
+
/* Command QUIT. Closes connection with current server. */
SILC_CLIENT_CMD_FUNC(quit)
{
SilcClientCommandContext cmd = (SilcClientCommandContext)context;
SilcBuffer buffer;
+ QuitInternal q;
if (!cmd->conn) {
SILC_NOT_CONNECTED(cmd->client, cmd->conn);
goto out;
}
- buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
- ++cmd->argv, ++cmd->argv_lens,
- ++cmd->argv_types, 0);
+ if (cmd->argc > 1)
+ buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
+ &cmd->argv[1], &cmd->argv_lens[1],
+ &cmd->argv_types[1], 0);
+ else
+ buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
+ NULL, NULL, NULL, 0);
silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
NULL, 0, NULL, NULL,
buffer->data, buffer->len, TRUE);
silc_buffer_free(buffer);
- cmd->argv--;
- cmd->argv_lens--;
- cmd->argv_types--;
- /* Close connection */
- silc_client_close_connection(cmd->client, cmd->conn->sock);
- cmd->client->ops->disconnect(cmd->client, cmd->conn);
+ q = silc_calloc(1, sizeof(*q));
+ q->client = cmd->client;
+ q->conn = cmd->conn;
+
+ /* We quit the connection with little timeout */
+ silc_task_register(cmd->client->timeout_queue, cmd->conn->sock->sock,
+ silc_client_command_quit_cb, (void *)q,
+ 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
/* Notify application */
COMMAND;
0, NULL, NULL, buffer->data, buffer->len, TRUE);
silc_buffer_free(buffer);
- id = silc_id_str2id(conn->remote_id_data, SILC_ID_SERVER);
+ id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
+ SILC_ID_SERVER);
+ if (!id) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR;
+ goto out;
+ }
/* Start counting time */
for (i = 0; i < conn->ping_count; i++) {
/* Client entry not found, it was requested thus mark this to be
pending command. */
silc_client_command_pending(conn, SILC_COMMAND_CUMODE, 0,
- silc_client_command_cumode, context);
+ silc_client_command_destructor,
+ silc_client_command_cumode,
+ silc_client_command_dup(cmd));
+ cmd->pending = 1;
return;
}
SilcIDCacheEntry id_cache = NULL;
SilcChannelEntry channel;
SilcBuffer buffer, idp;
- char *name;
+ char *name, *line = NULL;
+ unsigned int line_len = 0;
if (!cmd->conn) {
SILC_NOT_CONNECTED(cmd->client, cmd->conn);
same context and reprocesses the command. When reprocessing we actually
display the information on the screen. */
silc_client_command_pending(conn, SILC_COMMAND_USERS, 0,
- silc_client_command_users, context);
+ silc_client_command_destructor,
+ silc_client_command_users,
+ silc_client_command_dup(cmd));
cmd->pending = TRUE;
return;
}
cmd->client->ops->say(cmd->client, conn, "Users on %s",
channel->channel_name);
+ line = silc_calloc(4096, sizeof(*line));
+ line_len = 4096;
silc_list_start(channel->clients);
while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
SilcClientEntry e = chu->client;
- char *m, tmp[80], line[80], len1;
+ char *m, tmp[80], len1;
+
+ memset(line, 0, sizeof(line_len));
+
+ if (strlen(e->nickname) + strlen(e->server) + 100 > line_len) {
+ silc_free(line);
+ line_len += strlen(e->nickname) + strlen(e->server) + 100;
+ line = silc_calloc(line_len, sizeof(*line));
+ }
- memset(line, 0, sizeof(line));
memset(tmp, 0, sizeof(tmp));
m = silc_client_chumode_char(chu->mode);
- strcat(line, " ");
- strcat(line, e->nickname);
- strcat(line, e->server ? "@" : "");
+ strncat(line, " ", 1);
+ strncat(line, e->nickname, strlen(e->nickname));
+ strncat(line, e->server ? "@" : "", 1);
len1 = 0;
if (e->server)
strcat(line, " ");
}
- strcat(line, " H");
+ strncat(line, " H", 3);
strcat(tmp, m ? m : "");
- strcat(line, tmp);
+ strncat(line, tmp, strlen(tmp));
if (strlen(tmp) < 5)
for (i = 0; i < 5 - strlen(tmp); i++)
}
}
+ if (line)
+ silc_free(line);
+
/* Notify application */
COMMAND;