add irc_conn_callbacks, and delay irc_chan_join until on_registered
authorTero Marttila <terom@fixme.fi>
Tue, 10 Mar 2009 01:46:09 +0200
changeset 27 e6639132bead
parent 26 aec062af155d
child 28 9c1050bc8709
add irc_conn_callbacks, and delay irc_chan_join until on_registered
src/error.h
src/irc_conn.c
src/irc_conn.h
src/irc_net.c
src/irc_net.h
src/line_proto.c
src/sock_gnutls.c
src/sock_tcp.c
--- a/src/error.h	Tue Mar 10 01:11:12 2009 +0200
+++ b/src/error.h	Tue Mar 10 01:46:09 2009 +0200
@@ -74,6 +74,9 @@
     /* irc_line errors */
     _ERROR_CODE( ERR_LINE_TOO_LONG,                 0x100101,   NONE    ),
     _ERROR_CODE( ERR_LINE_INVALID_TOKEN,            0x100102,   NONE    ),
+
+    /** irc_conn errors */
+    _ERROR_CODE( ERR_IRC_CONN_REGISTER_STATE,       0x100201,   NONE    ),
     
     // mask of bits used for the error_code value
     _ERROR_CODE_MASK    = 0xffffff,
@@ -86,8 +89,8 @@
     /* The base error code */
     err_t code;
 
-    /* Additional detail info, usually some third-part error code */
-    unsigned int extra;
+    /* Additional detail info, usually some third-party error code */
+    int extra;
 };
 
 /*
--- a/src/irc_conn.c	Tue Mar 10 01:11:12 2009 +0200
+++ b/src/irc_conn.c	Tue Mar 10 01:46:09 2009 +0200
@@ -15,9 +15,12 @@
     (void) arg;
 
     // update state
+    conn->registering = false;
     conn->registered = true;
 
-    log_info("registered");
+    // trigger callback
+    if (conn->callbacks.on_registered)
+        conn->callbacks.on_registered(conn, conn->cb_arg);
 }
 
 /*
@@ -78,7 +81,8 @@
     }
 }
 
-err_t irc_conn_create (struct irc_conn **conn_ptr, struct sock_stream *sock, const struct irc_conn_config *config, struct error_info *err)
+err_t irc_conn_create (struct irc_conn **conn_ptr, struct sock_stream *sock, const struct irc_conn_callbacks *callbacks, 
+        void *cb_arg, struct error_info *err)
 {
     struct irc_conn *conn;
 
@@ -86,6 +90,10 @@
     if ((conn = calloc(1, sizeof(struct irc_conn))) == NULL)
         return SET_ERROR(err, ERR_CALLOC);
 
+    // init state
+    conn->callbacks = *callbacks;
+    conn->cb_arg = cb_arg;
+
     // initialize command handlers
     STAILQ_INIT(&conn->handlers);
     
@@ -97,13 +105,6 @@
     if (line_proto_create(&conn->lp, sock, IRC_LINE_MAX * 1.5, &irc_conn_on_line, conn, err))
         return ERROR_CODE(err);
 
-    // send the initial messages
-    if (
-            irc_conn_NICK(conn, config->nickname)
-        ||  irc_conn_USER(conn, config->username, config->realname)
-    )
-        return ERROR_CODE(err);
-
     // ok
     *conn_ptr = conn;
 
@@ -129,6 +130,29 @@
     return SUCCESS;
 }
 
+err_t irc_conn_register (struct irc_conn *conn, const struct irc_conn_register_info *info)
+{
+    err_t err;
+
+    // assert state
+    if (conn->registering || conn->registered)
+        // XXX: stupid error code
+        return ERR_IRC_CONN_REGISTER_STATE;
+
+    // send the initial messages
+    if (
+            (err = irc_conn_NICK(conn, info->nickname))
+        ||  (err = irc_conn_USER(conn, info->username, info->realname))
+    )
+        return err;
+
+    // set state
+    conn->registering = true;
+    
+    // ok
+    return SUCCESS;
+}
+
 err_t irc_conn_send (struct irc_conn *conn, const struct irc_line *line)
 {
     char line_buf[IRC_LINE_MAX + 2];
--- a/src/irc_conn.h	Tue Mar 10 01:11:12 2009 +0200
+++ b/src/irc_conn.h	Tue Mar 10 01:46:09 2009 +0200
@@ -18,28 +18,12 @@
 #include "irc_cmd.h"
 #include <stdbool.h>
 
-/*
- * Connection state
- */
-struct irc_conn {
-    /* We are a line-based protocol */
-    struct line_proto *lp;
-
-    /* Registered (as in, we have a working nickname)? */
-    bool registered;
-
-    /* Command handlers */
-    STAILQ_HEAD(irc_conn_handlers, irc_cmd_chain) handlers;
-};
-
-// XXX: this should probably be slightly reworked
-
 /**
  * The configuration info for an IRC connection.
  *
  * XXX: this should probably be reworked, maybe as a separate irc_conn_register function?
  */
-struct irc_conn_config {
+struct irc_conn_register_info {
     /* Nickname to use on that server */
     const char *nickname;
 
@@ -51,30 +35,74 @@
 };
 
 /**
- * Create a new irc_conn using the given sock_stream, which should be connected to an IRC server. The parameters given
- * in \a config will be used to identify with the IRC server.
+ * Connection state callbacks
+ */
+struct irc_conn_callbacks {
+    /**
+     * irc_conn_register has completed.
+     */
+    void (*on_registered) (struct irc_conn *conn, void *arg);
+};
+
+/*
+ * Connection state
+ */
+struct irc_conn {
+    /* We are a line-based protocol */
+    struct line_proto *lp;
+
+    /** Callbacks */
+    struct irc_conn_callbacks callbacks;
+
+    /** Opaque argument for callbacks */
+    void *cb_arg;
+
+    /** Registration request sent */
+    bool registering;
+
+    /* Registered (as in, we have a working nickname)? */
+    bool registered;
+
+    /* Command handlers */
+    STAILQ_HEAD(irc_conn_handlers, irc_cmd_chain) handlers;
+};
+
+/**
+ * Create a new irc_conn using the given sock_stream, which should be connected to an IRC server.
+ *
+ * This does not yet send any requests to the server, it only sets up the core state. Use irc_conn_register to register
+ * with the server.
  *
  * On success, the resulting irc_conn is returned via *conn with SUCCESS. Otherwise, -ERR_* and error info is returned
  * via *err.
  *
  * @param conn the new irc_conn structure is returned via this pointer
  * @param sock the socket connected to the IRC server
- * @param config the basic information used to register
  * @param err errors are returned via this pointer
  * @return error code
  */
-err_t irc_conn_create (struct irc_conn **conn, struct sock_stream *sock, const struct irc_conn_config *config, struct error_info *err);
+err_t irc_conn_create (struct irc_conn **conn, struct sock_stream *sock, const struct irc_conn_callbacks *callbacks, 
+        void *cb_arg, struct error_info *err);
 
 /**
  * Add a new chain of command handler callbacks to be used to handle irc_lines from the server. The given arg will be
  * passed to the callbacks as the context argument. The chain will be appended to the end of the current list of chains.
  *
+ * XXX: rename to not conflict with irc_conn_register()
+ *
  * @param chain the array of irc_cmd_handler structs, terminated with a NULL entry
  * @param arg the context argument to use for the callbacks
  */
 err_t irc_conn_register_handler_chain (struct irc_conn *conn, struct irc_cmd_handler *handlers, void *arg);
 
 /**
+ * Register with the IRC server using the given registration info (initial nickname etc.)
+ *
+ * This sends the NICK/USER command sequence.
+ */
+err_t irc_conn_register (struct irc_conn *conn, const struct irc_conn_register_info *info);
+
+/**
  * @group Simple request functions
  *
  * The error handling of these functions is such that the error return code is can be used or ignored as convenient,
--- a/src/irc_net.c	Tue Mar 10 01:11:12 2009 +0200
+++ b/src/irc_net.c	Tue Mar 10 01:46:09 2009 +0200
@@ -4,6 +4,29 @@
 #include <stdlib.h>
 #include <string.h>
 
+static void irc_net_conn_registered (struct irc_conn *conn, void *arg)
+{
+    struct irc_net *net = arg;
+    struct irc_chan *chan = NULL;
+    err_t err;
+
+    (void) conn;
+
+    // join our channels
+    TAILQ_FOREACH(chan, &net->channels, node) {
+        if ((err = irc_chan_join(chan)))
+            // XXX: fuck...
+            FATAL_ERR(err, "irc_chan_join failed");
+    }
+}
+
+/**
+ * Our irc_conn_callbacks list
+ */
+struct irc_conn_callbacks _conn_callbacks = {
+    .on_registered  = &irc_net_conn_registered,
+};
+
 err_t irc_net_create (struct irc_net **net_ptr, const struct irc_net_info *info, struct error_info *err)
 {
     struct irc_net *net;
@@ -34,7 +57,11 @@
     log_info("connected, registering");
 
     // create the irc connection state
-    if (irc_conn_create(&net->conn, sock, &info->register_info, err))
+    if (irc_conn_create(&net->conn, sock, &_conn_callbacks, net, err))
+        goto error;
+
+    // register
+    if ((ERROR_CODE(err) = irc_conn_register(net->conn, &info->register_info)))
         goto error;
     
     // ok
@@ -60,11 +87,14 @@
     
     // add to network list
     TAILQ_INSERT_TAIL(&net->channels, chan, node);
-
-    // then join
-    if ((ERROR_CODE(&err) = irc_chan_join(chan)))
-        // XXX
-        return NULL;
+    
+    // currently connected?
+    if (net->conn && net->conn->registered) {
+        // then join
+        if ((ERROR_CODE(&err) = irc_chan_join(chan)))
+            // XXX
+            return NULL;
+    }
 
     // ok, return
     return chan;
--- a/src/irc_net.h	Tue Mar 10 01:11:12 2009 +0200
+++ b/src/irc_net.h	Tue Mar 10 01:46:09 2009 +0200
@@ -29,7 +29,7 @@
     bool use_ssl;
 
     /** Protocol registration info */
-    struct irc_conn_config register_info;
+    struct irc_conn_register_info register_info;
 };
 
 /**
@@ -55,7 +55,9 @@
 err_t irc_net_create (struct irc_net **net, const struct irc_net_info *info, struct error_info *err);
 
 /**
- * Create a new irc_chan, add it to our channel list, and send the JOIN request.
+ * Create a new irc_chan and add it to our channel list.
+ *
+ * If we are connected and registered, JOIN the channel right away, otherwise, join it once we register.
  */
 struct irc_chan* irc_net_add_chan (struct irc_net *net, const struct irc_chan_info *info);
 
--- a/src/line_proto.c	Tue Mar 10 01:11:12 2009 +0200
+++ b/src/line_proto.c	Tue Mar 10 01:46:09 2009 +0200
@@ -47,6 +47,8 @@
     struct line_proto *lp = arg;
     char *line;
 
+    (void) sock;
+
     // sanity-check
     assert(lp->tail_offset < lp->buf_len);
     
@@ -73,11 +75,13 @@
 static void line_proto_on_write (struct sock_stream *sock, void *arg)
 {
     struct line_proto *lp = arg;
-    err_t err;
+    int ret;
+
+    (void) sock;
 
     // just flush
-    if ((err = line_proto_flush(lp)) < 0)
-        FATAL_ERR(err, "line_proto_flush");
+    if ((ret = line_proto_flush(lp)) < 0)
+        FATAL_ERR(-ret, "line_proto_flush");
 }
 
 /*
@@ -151,7 +155,7 @@
  *
  */
 int _parse_line (char *buf, size_t len, size_t *hint) {
-    int i, next = 0;
+    size_t i, next = 0;
 
     // empty buffer -> nothing
     if (len == 0)
--- a/src/sock_gnutls.c	Tue Mar 10 01:11:12 2009 +0200
+++ b/src/sock_gnutls.c	Tue Mar 10 01:46:09 2009 +0200
@@ -67,6 +67,9 @@
 static void sock_gnutls_event_handler (int fd, short what, void *arg)
 {
     struct sock_gnutls *sock = arg;
+
+    (void) fd;
+    (void) what;
     
     // gnutls might be able to proceed now, so ask user to try what didn't work before now, using the mask given to
     // event_enable().
@@ -126,10 +129,12 @@
  * Our sock_stream_Type
  */
 struct sock_stream_type sock_gnutls_type = {
-    .methods.read           = &sock_gnutls_read,
-    .methods.write          = &sock_gnutls_write,
-    .methods.event_init     = &sock_gnutls_event_init,
-    .methods.event_enable   = &sock_gnutls_event_enable,
+    .methods                = {
+        .read               = &sock_gnutls_read,
+        .write              = &sock_gnutls_write,
+        .event_init         = &sock_gnutls_event_init,
+        .event_enable       = &sock_gnutls_event_enable,
+    },
 };
 
 /*
@@ -153,7 +158,7 @@
 // XXX: log func
 void _log (int level, const char *msg)
 {
-    printf("gnutls: %s\n", msg);
+    printf("gnutls: %d: %s", level, msg);
 }
 
 err_t sock_gnutls_global_init (struct error_info *err)
@@ -204,7 +209,7 @@
         JUMP_SET_ERROR_INFO(err, SOCK_GNUTLS_ERR(sock));
 
     // bind default transport functions (recv/send) to use the TCP fd
-    gnutls_transport_set_ptr(sock->session, (gnutls_transport_ptr_t) sock->base_tcp.fd);
+    gnutls_transport_set_ptr(sock->session, (gnutls_transport_ptr_t) (long int) sock->base_tcp.fd);
 
     // perform the handshake
     if ((ERROR_EXTRA(err) = gnutls_handshake(sock->session)) < 0)
--- a/src/sock_tcp.c	Tue Mar 10 01:11:12 2009 +0200
+++ b/src/sock_tcp.c	Tue Mar 10 01:46:09 2009 +0200
@@ -17,6 +17,8 @@
 {
     struct sock_tcp *sock = arg;
 
+    (void) fd;
+
     // invoke appropriate callback
     sock_stream_invoke_callbacks(SOCK_TCP_BASE(sock), what);
 }
@@ -111,10 +113,12 @@
  * Our sock_stream_type
  */
 struct sock_stream_type sock_tcp_type = {
-    .methods.read           = &sock_tcp_read,
-    .methods.write          = &sock_tcp_write,
-    .methods.event_init     = &sock_tcp_event_init,
-    .methods.event_enable   = &sock_tcp_event_enable,
+    .methods                = {
+        .read               = &sock_tcp_read,
+        .write              = &sock_tcp_write,
+        .event_init         = &sock_tcp_event_init,
+        .event_enable       = &sock_tcp_event_enable,
+    },
 };
 
 err_t sock_tcp_alloc (struct sock_tcp **sock_ptr)