+/* Check for error */
+#define CHECK_STATUS(msg) \
+ SILC_LOG_DEBUG(("%s", silc_get_command_name(cmd->cmd))); \
+ if (cmd->error != SILC_STATUS_OK) { \
+ if (cmd->verbose) \
+ SAY(cmd->conn->client, cmd->conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR, \
+ msg "%s", silc_get_status_message(cmd->error)); \
+ ERROR_CALLBACK(cmd->error); \
+ silc_client_command_process_error(cmd, state_context, cmd->error); \
+ silc_fsm_next(fsm, silc_client_command_reply_processed); \
+ return SILC_FSM_CONTINUE; \
+ }
+
+/* Check for correct arguments */
+#define CHECK_ARGS(min, max) \
+ if (silc_argument_get_arg_num(args) < min || \
+ silc_argument_get_arg_num(args) > max) { \
+ ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); \
+ silc_fsm_next(fsm, silc_client_command_reply_processed); \
+ return SILC_FSM_CONTINUE; \
+ }
+
+#define SAY cmd->conn->client->internal->ops->say
+
+/************************ Static utility functions **************************/
+
+/* Delivers the command reply back to application */
+
+static inline void
+silc_client_command_callback(SilcClientCommandContext cmd, ...)
+{
+ SilcClientCommandReplyCallback cb;
+ SilcList list;
+ va_list ap, cp;
+
+ va_start(ap, cmd);
+
+ /* Default reply callback */
+ if (cmd->called) {
+ silc_va_copy(cp, ap);
+ cmd->conn->client->internal->ops->command_reply(
+ cmd->conn->client, cmd->conn, cmd->cmd, cmd->status,
+ cmd->error, cp);
+ va_end(cp);
+ }
+
+ /* Reply callback */
+ list = cmd->reply_callbacks;
+ silc_list_start(list);
+ while ((cb = silc_list_get(list)))
+ if (!cb->do_not_call) {
+ silc_va_copy(cp, ap);
+ cb->do_not_call = !cb->reply(cmd->conn->client, cmd->conn, cmd->cmd,
+ cmd->status, cmd->error, cb->context, cp);
+ va_end(cp);
+ }
+
+ va_end(ap);
+}
+
+/* Handles common error status types. */
+
+static void silc_client_command_process_error(SilcClientCommandContext cmd,
+ SilcCommandPayload payload,
+ SilcStatus error)
+{
+ SilcClient client = cmd->conn->client;
+ SilcClientConnection conn = cmd->conn;
+ SilcArgumentPayload args = silc_command_get_args(payload);
+ SilcID id;
+
+ if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
+ SilcClientEntry client_entry;
+
+ /* Remove unknown client entry from cache */
+ if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
+ return;
+
+ client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
+ if (client_entry) {
+ silc_client_remove_from_channels(client, conn, client_entry);
+ client_entry->internal.valid = FALSE;
+ silc_client_del_client(client, conn, client_entry);
+ silc_client_unref_client(client, conn, client_entry);
+ }
+ return;
+ }
+
+ if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID) {
+ SilcChannelEntry channel;
+
+ /* Remove unknown channel entry from cache */
+ if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
+ return;
+
+ channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
+ if (channel) {
+ silc_client_empty_channel(client, conn, channel);
+ silc_client_del_channel(client, conn, channel);
+ silc_client_unref_channel(client, conn, channel);
+ }
+ return;
+ }
+
+ if (cmd->error == SILC_STATUS_ERR_NO_SUCH_SERVER_ID) {
+ SilcServerEntry server_entry;