SilcClientCommand cmd;
cmd = silc_calloc(1, sizeof(*cmd));
+ if (!cmd)
+ return FALSE;
cmd->cmd = command;
cmd->command = command_func;
cmd->reply = command_reply_func;
- cmd->name = name ? strdup(name) : NULL;
cmd->max_args = max_args;
+ cmd->name = name ? strdup(name) : NULL;
+ if (!cmd->name) {
+ silc_free(cmd);
+ return FALSE;
+ }
silc_list_add(client->internal->commands, cmd);
return NULL;
}
-/* Free command context and its internals */
-
-static void silc_client_command_free(SilcClientCommandContext cmd)
-{
- int i;
-
- for (i = 0; i < cmd->argc; i++)
- silc_free(cmd->argv[i]);
- silc_free(cmd->argv);
- silc_free(cmd->argv_lens);
- silc_free(cmd->argv_types);
- silc_free(cmd);
-}
-
/* Command thread destructor */
static void silc_client_command_destructor(SilcFSMThread thread,
silc_list_add(cmd->reply_callbacks, cb);
}
- SILC_LOG_DEBUG(("pending: cmd %p, command %d, ident %d", cmd, cmd->cmd,
- cmd->cmd_ident));
-
/* Add pending reply */
silc_list_add(conn->internal->pending_commands, cmd);
/****************************** Command API *********************************/
+/* Free command context and its internals */
+
+void silc_client_command_free(SilcClientCommandContext cmd)
+{
+ SilcClientCommandReplyCallback cb;
+ int i;
+
+ /* If command is running, finish it. Destructor will free the context. */
+ if (silc_fsm_is_started(&cmd->thread)) {
+ silc_fsm_finish(&cmd->thread);
+ return;
+ }
+
+ for (i = 0; i < cmd->argc; i++)
+ silc_free(cmd->argv[i]);
+ silc_free(cmd->argv);
+ silc_free(cmd->argv_lens);
+ silc_free(cmd->argv_types);
+
+ silc_list_start(cmd->reply_callbacks);
+ while ((cb = silc_list_get(cmd->reply_callbacks)))
+ silc_free(cb);
+
+ silc_free(cmd);
+}
+
/* Executes a command */
SilcUInt16 silc_client_command_call(SilcClient client,
cmd->cmd_ident = silc_client_cmd_ident(conn);
cmd->called = TRUE;
cmd->verbose = TRUE;
+ silc_list_init(cmd->reply_callbacks,
+ struct SilcClientCommandReplyCallbackStruct, next);
/*** Call command */
SILC_LOG_DEBUG(("Calling %s command", silc_get_command_name(cmd->cmd)));
return 0;
cmd->conn = conn;
cmd->cmd = command;
+ silc_list_init(cmd->reply_callbacks,
+ struct SilcClientCommandReplyCallbackStruct, next);
/* Send the command */
va_start(ap, argc);
0, NULL, conn->callback_context);
/* Signal to close connection */
- conn->internal->disconnected = TRUE;
- SILC_FSM_SEMA_POST(&conn->internal->wait_event);
+ if (!conn->internal->disconnected) {
+ conn->internal->disconnected = TRUE;
+ SILC_FSM_SEMA_POST(&conn->internal->wait_event);
+ }
return SILC_FSM_FINISH;
}
SilcClientCommandContext cmd = fsm_context;
SilcClientConnection conn = cmd->conn;
- if (cmd->argc < 2) {
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- return SILC_FSM_FINISH;
- }
-
/* Send the command */
silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
1, silc_buffer_datalen(conn->internal->
/* Check whether user requested server */
server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
if (!server_entry) {
+ if (cmd->resolved) {
+ /* Resolving didn't find anything. We should never get here as
+ errors are handled in the resolving callback. */
+ COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
+ COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_SERVER);
+ return SILC_FSM_FINISH;
+ }
+
/* No client or server exist with this name, query for both. */
+ cmd->resolved = TRUE;
SILC_FSM_CALL(silc_client_command_send(client, conn,
SILC_COMMAND_IDENTIFY,
silc_client_command_continue,
strlen(cmd->argv[1]),
2, cmd->argv[1],
strlen(cmd->argv[1])));
+ /* NOT REACHED */
}
idp = silc_id_payload_encode(&server_entry->id, SILC_ID_SERVER);
+ silc_client_unref_server(client, conn, server_entry);
} else {
client_entry = silc_dlist_get(clients);
idp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT);