libircdir = libirc
objs = src/posix.o \
+ src/redirect.o \
src/cache.o \
src/util.o \
src/hooks.o \
src/settings.o \
src/log.o \
src/client.o \
- src/redirect.o \
src/gen_config.o \
src/repl.o \
src/linestack_file.o \
$(libircdir)/line.o \
$(libircdir)/isupport.o \
$(libircdir)/connection.o \
+ $(libircdir)/redirect.o \
$(libircdir)/url.o \
$(libircdir)/util.o \
$(libircdir)/listener.o \
$(libircdir)/isupport.h \
$(libircdir)/irc.h \
$(libircdir)/connection.h \
+ $(libircdir)/redirect.h \
$(libircdir)/url.h \
$(libircdir)/listener.h \
$(libircdir)/util.h
return "*";
}
+void client_ref_void(struct irc_client *c)
+{
+ client_ref(c);
+}
+
struct irc_client *client_ref(struct irc_client *c)
{
if (c != NULL)
G_MODULE_EXPORT const char *client_get_default_target(struct irc_client *c);
G_MODULE_EXPORT const char *client_get_own_hostmask(struct irc_client *c);
G_MODULE_EXPORT struct irc_client *client_ref(struct irc_client *c);
+G_MODULE_EXPORT void client_ref_void(struct irc_client *c);
G_MODULE_EXPORT void client_unref(struct irc_client *c);
G_MODULE_EXPORT struct irc_client *irc_client_new(struct irc_transport *transport, const char *default_origin, const char *desc, struct irc_client_callbacks *callbacks);
G_MODULE_EXPORT void clients_send_state(GList *clients,
struct query_stack {
GList *entries;
void (*unref_userdata) (void *);
- void *(*ref_userdata) (void *);
+ void (*ref_userdata) (void *);
};
-struct query_stack *new_query_stack(void *(*ref_userdata) (void *), void (*unref_userdata) (void *))
+struct query_stack *new_query_stack(void (*ref_userdata) (void *), void (*unref_userdata) (void *))
{
struct query_stack *stack = g_new0(struct query_stack, 1);
if (stack == NULL) {
handle_default
};
-static gboolean handle_465(struct irc_network *n, const struct irc_line *l)
-{
- network_log(LOG_ERROR, n, "Banned from server: %s", l->args[1]);
- return TRUE;
-}
-
-static gboolean handle_451(struct irc_network *n, const struct irc_line *l)
-{
- network_log(LOG_ERROR, n, "Not registered error, this is probably a bug...");
- return TRUE;
-}
-
-static gboolean handle_462(struct irc_network *n, const struct irc_line *l)
-{
- network_log(LOG_ERROR, n, "Double registration error, this is probably a bug...");
- return TRUE;
-}
-
-static gboolean handle_463(struct irc_network *n, const struct irc_line *l)
-{
- network_log(LOG_ERROR, n, "Host not privileged to connect");
- return TRUE;
-}
-
-static gboolean handle_464(struct irc_network *n, const struct irc_line *l)
-{
- network_log(LOG_ERROR, n, "Password mismatch");
- return TRUE;
-}
-
-/* List of responses that should be sent to all clients */
-static const int response_all[] = { RPL_NOWAWAY, RPL_UNAWAY,
- ERR_NO_OP_SPLIT, RPL_HIDINGHOST,
- ERR_NEEDREGGEDNICK, RPL_UMODEIS, RPL_SNOMASK,
- RPL_LUSERCLIENT, RPL_LUSEROP, RPL_LUSERUNKNOWN, RPL_LUSERCHANNELS,
- RPL_LUSERME, ERR_NO_OP_SPLIT, RPL_LOCALUSERS, RPL_GLOBALUSERS,
- RPL_NAMREPLY, RPL_ENDOFNAMES, RPL_TOPIC, RPL_TOPICWHOTIME,
- RPL_CHANNEL_HOMEPAGE, RPL_CREATIONTIME, RPL_LOGGEDINAS, 0 };
-static const int response_none[] = { ERR_NOMOTD, RPL_MOTDSTART, RPL_MOTD,
- RPL_ENDOFMOTD, 0 };
-static const struct {
- int response;
- gboolean (*handler) (struct irc_network *n, const struct irc_line *);
-} response_handler[] = {
- { ERR_PASSWDMISMATCH, handle_464 },
- { ERR_ALREADYREGISTERED, handle_462 },
- { ERR_NOPERMFORHOST, handle_463 },
- { ERR_NOTREGISTERED, handle_451 },
- { ERR_YOUREBANNEDCREEP, handle_465 },
- { 0, NULL }
-};
-
/**
* Check whether reply r is part of a specified list
*
return NULL;
}
-/**
- * Redirect a response received from the server.
- *
- * @return TRUE if the message was redirected to zero or more clients,
- * FALSE if it was sent to all clients.
- */
-gboolean redirect_response(struct query_stack *stack,
- struct irc_network *network,
- const struct irc_line *l)
-{
- struct irc_client *c = NULL;
- int n;
- int i;
-
- c = (struct irc_client *)query_stack_match_response(stack, l);
- if (c != NULL) {
- client_send_line(c, l);
- return TRUE;
- }
-
- n = irc_line_respcode(l);
-
- /* See if this is a response that should be sent to all clients */
- for (i = 0; response_all[i]; i++) {
- if (response_all[i] == n) {
- clients_send(network->clients, l, c);
- return FALSE;
- }
- }
-
- /* See if this is a response that shouldn't be sent to clients at all */
- for (i = 0; response_none[i]; i++) {
- if (response_none[i] == n) {
- return TRUE;
- }
- }
-
- /* Handle response using custom function */
- for (i = 0; response_handler[i].handler; i++) {
- if (response_handler[i].response == n) {
- return response_handler[i].handler(network, l);
- }
- }
-
- if (!c) {
- network_log((g_list_length(network->clients) <= 1)?LOG_TRACE:LOG_WARNING,
- network, "Unable to redirect response %s", l->args[0]);
- clients_send(network->clients, l, NULL);
- }
-
- return FALSE;
-}
-
void query_stack_clear(struct query_stack *stack)
{
while (stack->entries != NULL) {
struct query_stack_entry *s = g_new(struct query_stack_entry, 1);
g_assert(l != NULL);
g_assert(q != NULL);
- s->userdata = stack->ref_userdata(userdata);
+ stack->ref_userdata(userdata);
+ s->userdata = userdata;
s->time = time(NULL);
s->query = q;
stack->entries = g_list_append(stack->entries, s);
struct query_stack;
-gboolean redirect_response(struct query_stack *stack,
- struct irc_network *network,
- const struct irc_line *l);
void *query_stack_match_response(struct query_stack *stack, const struct irc_line *l);
gboolean query_stack_record(struct query_stack *stack, void *c, const struct irc_line *l);
-struct query_stack *new_query_stack(void *(*ref_userdata) (void *), void (*unref_userdata) (void *));
+struct query_stack *new_query_stack(void (*ref_userdata) (void *), void (*unref_userdata) (void *));
void query_stack_clear(struct query_stack *n);
void query_stack_free(struct query_stack *n);
#include <Python.h>
#include <stdbool.h>
#include "ctrlproxy.h"
+#include "redirect.h"
+
const char *get_my_hostname() { return NULL; /* FIXME */ }
void log_global(enum log_level ll, const char *fmt, ...) { /* FIXME */}
.welcome = py_welcome_client
};
+typedef struct {
+ PyObject_HEAD
+ struct query_stack *stack;
+} PyQueryStackObject;
+
+static PyObject *py_query_stack_record(PyQueryStackObject *self, PyObject *args)
+{
+ PyObject *py_token, *py_line;
+ struct irc_line *line;
+
+ if (!PyArg_ParseTuple(args, "OO", &py_token, &py_line))
+ return NULL;
+
+ line = PyObject_AsLine(py_line);
+ if (line == NULL)
+ return NULL;
+
+ return PyBool_FromLong(query_stack_record(self->stack, py_token, line));
+}
+
+static PyObject *py_query_stack_redirect(PyQueryStackObject *self, PyObject *args)
+{
+ PyObject *py_network, *py_line;
+ struct irc_line *line;
+ PyObject *ret;
+
+ if (!PyArg_ParseTuple(args, "OO", &py_network, &py_line))
+ return NULL;
+
+ line = PyObject_AsLine(py_line);
+ if (line == NULL)
+ return NULL;
+
+ if (PyObject_TypeCheck(py_network, &PyNetworkStateType)) {
+ PyErr_SetNone(PyExc_TypeError);
+ return NULL;
+ }
+
+ ret = (PyObject *)query_stack_match_response(self->stack, line);
+ if (ret == NULL) {
+ Py_RETURN_NONE;
+ } else {
+ Py_INCREF(ret);
+ return ret;
+ }
+}
+
+static PyObject *py_query_stack_clear(PyQueryStackObject *self)
+{
+ query_stack_clear(self->stack);
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef py_query_stack_methods[] = {
+ { "record", (PyCFunction)py_query_stack_record, METH_VARARGS, NULL },
+ { "response", (PyCFunction)py_query_stack_redirect, METH_VARARGS, NULL },
+ { "clear", (PyCFunction)py_query_stack_clear, METH_NOARGS, NULL },
+ { NULL }
+};
+
+static int py_query_stack_dealloc(PyQueryStackObject *self)
+{
+ query_stack_free(self->stack);
+ PyObject_Del(self);
+ return 0;
+}
+
+static PyObject *py_query_stack_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+ PyQueryStackObject *self = (PyQueryStackObject *)type->tp_alloc(type, 0);
+ if (self == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ self->stack = new_query_stack((void (*)(void *))Py_IncRef, (void (*)(void *))Py_DecRef);
+
+ return (PyObject *)self;
+}
+
+PyTypeObject PyQueryStackType = {
+ .tp_name = "QueryStack",
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+ .tp_new = py_query_stack_new,
+ .tp_methods = py_query_stack_methods,
+ .tp_basicsize = sizeof(PyQueryStackObject),
+ .tp_dealloc = (destructor)py_query_stack_dealloc,
+};
+
static PyMethodDef irc_methods[] = {
{ NULL }
};
if (PyType_Ready(&PyGListIterType) < 0)
return;
+ if (PyType_Ready(&PyQueryStackType) < 0)
+ return;
+
m = Py_InitModule3("irc", irc_methods,
"Simple IRC protocol module for Python.");
if (m == NULL)
PyModule_AddObject(m, "Client", (PyObject *)&PyClientType);
Py_INCREF(&PyNetworkType);
PyModule_AddObject(m, "Network", (PyObject *)&PyNetworkType);
+ Py_INCREF(&PyQueryStackType);
+ PyModule_AddObject(m, "QueryStack", (PyObject *)&PyQueryStackType);
}
void kill_pending_clients(const char *reason);
gboolean network_set_iochannel(struct irc_network *s, GIOChannel *ioc);
+/* redirect.c */
+gboolean redirect_response(struct query_stack *stack,
+ struct irc_network *network,
+ const struct irc_line *l);
+
/* state.c */
void free_channels(struct irc_network *s);
void network_nick_set_data(struct network_nick *n, const char *nick, const char *username, const char *host);
static void handle_network_state_set(struct irc_network *s)
{
s->linestack = new_linestack(s, s->global->config);
- s->queries = new_query_stack((void *(*)(void *))client_ref, (void (*)(void *))client_unref);
+ s->queries = new_query_stack((void (*)(void *))client_ref_void, (void (*)(void *))client_unref);
}
static gboolean process_to_server(struct irc_network *s, const struct irc_line *l)