* redirect all silc_client_command_calls through a queueing framework.
This fixes /CYCLE and the annoying "nick change after auto-joining
a channel". Furthermore it defines one central point where
command parameters can be UTF-8-ified. Affected files
irssi/src/silc/core/Makefile, client_ops.c, silc-channels.c,
silc-servers.[ch], silc-core.c, silc-cmdqueue.[ch], silc-lag.c
+Fri Feb 13 13:13:07 CET 2004 Jochen Eisinger <jochen@penguin-breeder.org>
+
+ * redirect all silc_client_command_calls through a queueing framework.
+ This fixes /CYCLE and the annoying "nick change after auto-joining
+ a channel". Furthermore it defines one central point where
+ command parameters can be UTF-8-ified. Affected files
+ irssi/src/silc/core/Makefile, client_ops.c, silc-channels.c,
+ silc-servers.[ch], silc-core.c, silc-cmdqueue.[ch], silc-lag.c
+
Fri Feb 13 12:04:41 CET 2004 Jochen Eisinger <jochen@penguin-breeder.org>
* use asynchronous connect() to establish router connections.
silc-expandos.c \
silc-servers-reconnect.c \
silc-lag.c \
- silc-chatnets.c
+ silc-chatnets.c \
+ silc-cmdqueue.c
noinst_HEADERS = \
module.h \
silc-commands.h \
silc-queries.h \
silc-servers.h \
- silc-chatnets.h
+ silc-chatnets.h \
+ silc-cmdqueue.h
#include "silc-channels.h"
#include "silc-queries.h"
#include "silc-nicklist.h"
+#include "silc-cmdqueue.h"
#include "signals.h"
#include "levels.h"
client_entry = va_arg(va, SilcClientEntry);
channel = va_arg(va, SilcChannelEntry);
-
+
memset(buf, 0, sizeof(buf));
if (client_entry->username)
snprintf(buf, sizeof(buf) - 1, "%s@%s",
switch (status) {
case SILC_CLIENT_CONN_SUCCESS:
/* We have successfully connected to server */
+ if ((client->nickname != NULL) &&
+ (strcmp(client->nickname, client->username)))
+ silc_queue_enable(conn); /* enable queueing until we have our nick */
server->connected = TRUE;
signal_emit("event connected", 1, server);
break;
client_entry, client_entry->nickname);
signal_emit("message own_nick", 4, server, server->nick, old, "");
g_free(old);
+
+ /* when connecting to a server, the last thing we receive
+ is a SILC_COMMAND_LIST reply. Since we enable queueing
+ during the connection, we can now safely disable it again */
+ silc_queue_disable(conn);
break;
}
}
break;
+ case SILC_COMMAND_LEAVE:
+ {
+ /* we might be cycling, so disable queueing again */
+ silc_queue_disable(conn);
+ }
+ break;
+
}
va_end(vp);
#include "silc-channels.h"
#include "silc-queries.h"
#include "silc-nicklist.h"
+#include "silc-cmdqueue.h"
#include "window-item-def.h"
#include "fe-common/core/printtext.h"
/* destroying channel record without actually
having left the channel yet */
silc_command_exec(channel->server, "LEAVE", channel->name);
+ /* enable queueing because we destroy the channel immedially */
+ silc_queue_enable(channel->server->conn);
}
}
chanrec->left = TRUE;
silc_command_exec(server, "LEAVE", chanrec->name);
+ /* enable queueing because we destroy the channel immedially */
+ silc_queue_enable(server->conn);
signal_stop();
channel_destroy(CHANNEL(chanrec));
--- /dev/null
+#include "module.h"
+#include "silc-cmdqueue.h"
+
+#include <stdarg.h>
+
+GHashTable *cmd_queues;
+
+void silc_queue_init(void)
+{
+ cmd_queues = g_hash_table_new(NULL, NULL);
+}
+
+static void cmd_list_remove_cb(char *cmd)
+{
+ silc_free(cmd);
+}
+
+static int cmd_queue_remove_cb(void *key, GSList *list)
+{
+ if ((list != NULL) && (list->next != NULL)) {
+ g_slist_foreach(list, (GFunc) cmd_list_remove_cb, NULL);
+ g_slist_free(list);
+ }
+
+ return TRUE;
+}
+
+void silc_queue_deinit(void)
+{
+ g_hash_table_foreach_remove(cmd_queues, (GHRFunc) cmd_queue_remove_cb, NULL);
+ g_hash_table_destroy(cmd_queues);
+}
+
+void silc_queue_flush(SilcClientConnection conn)
+{
+ GSList *list = g_hash_table_lookup(cmd_queues, conn);
+
+ if (list != NULL) {
+ GSList *tmp;
+
+ for (tmp = g_slist_next(list); tmp != NULL; tmp = g_slist_next(tmp))
+ silc_client_command_call(silc_client, conn, tmp->data);
+
+ g_slist_foreach(list, (GFunc) cmd_list_remove_cb, NULL);
+ /* free all but the first element ... */
+ g_slist_free(g_slist_remove_link(list, list));
+ }
+}
+
+void silc_queue_enable(SilcClientConnection conn)
+{
+ GSList *list = g_hash_table_lookup(cmd_queues, conn);
+
+ if (list == NULL)
+ g_hash_table_insert(cmd_queues, conn, g_slist_alloc());
+}
+
+void silc_queue_disable(SilcClientConnection conn)
+{
+ GSList *list = g_hash_table_lookup(cmd_queues, conn);
+
+ if (list != NULL) {
+ silc_queue_flush(conn);
+ g_slist_free(list);
+ g_hash_table_remove(cmd_queues, conn);
+ }
+}
+
+bool silc_queue_command_call(SilcClient client,
+ SilcClientConnection conn,
+ const char *command_line, ...)
+{
+ va_list ap;
+ char *cmd = (char *) command_line;
+ GSList *list = g_hash_table_lookup(cmd_queues, conn);
+ bool need_free = FALSE;
+
+ va_start(ap, command_line);
+
+ if (command_line == NULL) {
+ char *tmp = va_arg(ap, char *);
+
+ need_free = TRUE;
+
+ if (tmp == NULL) {
+ va_end(ap);
+ return FALSE;
+ }
+
+ cmd = g_strdup(tmp);
+
+ for (tmp = va_arg(ap, char *); tmp != NULL; tmp = va_arg(ap, char *)) {
+ char *old = cmd;
+
+ cmd = g_strconcat(cmd, " ", tmp, NULL);
+ g_free(old);
+ }
+
+ }
+
+ va_end(ap);
+
+ /* FIXME: UTF-8-tify parameters of cmd */
+
+ /* queueing disabled -> immediate execution */
+ if (list == NULL) {
+ bool result = silc_client_command_call(client, conn, cmd);
+
+ if (need_free)
+ g_free(cmd);
+
+ return result;
+ }
+
+ g_hash_table_remove(cmd_queues, conn);
+ g_hash_table_insert(cmd_queues, conn, g_slist_append(list, g_strdup(cmd)));
+
+ if (need_free)
+ g_free(cmd);
+
+ return TRUE;
+}
+
+bool silc_queue_get_state(SilcClientConnection conn) {
+ return g_hash_table_lookup(cmd_queues, conn) != NULL;
+}
--- /dev/null
+#ifndef __SILC_CMDQUEUE_H
+#define __SILC_CMDQUEUE_H
+
+/* wrappers for queuing commands:
+
+ basically the same as the correspondening silc_client_* functions
+ with one additional parameter:
+
+ bool sync - command must be executed in sync (i.e. no
+ other command may be send before completion)
+ */
+
+bool silc_queue_command_call(SilcClient client,
+ SilcClientConnection conn,
+ const char *command_line, ...);
+
+#define silc_queue_command_pending silc_client_command_pending
+
+/*
+ enable and/or disable command queueing. If command queueing is
+ disabled, all silc_queue_* calls will immedially call silc_client_*
+ functions. If queueing is enabled, all silc_queue_* calls don't have
+ any effect until queueing is disabled again.
+
+ queueing is enabled and disabled for each SilcClientConnection
+ seperatly.
+
+ If queueing is enabled, silc_queue_flush will send all currently
+ queued commands but won't disable queueing.
+ */
+void silc_queue_enable(SilcClientConnection conn);
+void silc_queue_disable(SilcClientConnection conn);
+void silc_queue_flush(SilcClientConnection conn);
+
+/* returns true if queueing is enabled */
+bool silc_queue_get_state(SilcClientConnection conn);
+
+void silc_queue_init(void);
+void silc_queue_deinit(void);
+
+#endif
#include "silc-queries.h"
#include "silc-nicklist.h"
#include "silc-chatnets.h"
+#include "silc-cmdqueue.h"
#include "signals.h"
#include "levels.h"
chat_protocol_register(rec);
g_free(rec);
+ silc_queue_init();
silc_server_init();
silc_channels_init();
silc_queries_init();
signal_remove("setup changed", (SIGNAL_FUNC) sig_setup_changed);
signal_remove("irssi init finished", (SIGNAL_FUNC) sig_init_finished);
+ silc_queue_deinit();
silc_server_deinit();
silc_channels_deinit();
silc_queries_deinit();
server_disconnect((SERVER_REC *) rec);
}
} else if (rec->lag_last_check+lag_check_time < now &&
- rec->cmdcount == 0 && rec->connected) {
+ rec->connected) {
/* no commands in buffer - get the lag */
lag_get(rec);
}
#include "silc-channels.h"
#include "silc-queries.h"
#include "silc-nicklist.h"
+#include "silc-cmdqueue.h"
#include "window-item-def.h"
#include "fe-common/core/printtext.h"
/* Call the command */
data = g_strconcat(command, " ", args, NULL);
- silc_client_command_call(silc_client, server->conn, data);
+ silc_queue_command_call(silc_client, server->conn, data);
g_free(data);
}
#define STRUCT_SERVER_CONNECT_REC SILC_SERVER_CONNECT_REC
typedef struct {
#include "server-rec.h"
- /* Command sending queue */
- int cmdcount; /* number of commands in `cmdqueue'. Can be more than
- there actually is, to make flood control remember
- how many messages can be sent before starting the
- flood control */
- int cmd_last_split; /* Last command wasn't sent entirely to server.
- First item in `cmdqueue' should be re-sent. */
- GSList *cmdqueue;
- GTimeVal last_cmd; /* last time command was sent to server */
-
- GSList *idles; /* Idle queue - send these commands to server
- if there's nothing else to do */
SilcDList ftp_sessions;
FtpSession current_session;