--- a/Makefile Sat Feb 28 21:39:15 2009 +0200
+++ b/Makefile Sat Feb 28 22:47:39 2009 +0200
@@ -34,7 +34,7 @@
SOCK_OBJS = obj/sock.o obj/sock_tcp.o
SOCK_GNUTLS_OBJS = obj/sock_gnutls.o
LINEPROTO_OBJS = obj/line_proto.o
-IRC_OBJS = obj/irc_line.o
+IRC_OBJS = obj/irc_line.o obj/irc_conn.o
# XXX: not yet there
#CORE_OBJS = obj/lib/log.o obj/lib/signals.o
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/irc_conn.c Sat Feb 28 22:47:39 2009 +0200
@@ -0,0 +1,90 @@
+
+#include "irc_conn.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+void irc_conn_on_line (char *line_buf, void *arg)
+{
+ struct irc_line line;
+ int err;
+
+ // log
+ printf("<<< %s\n", line_buf);
+
+ // parse
+ if ((err = irc_line_parse(&line, line_buf)))
+ printf("!!! Invalid line: %s: %s\n", line_buf, error_name(err));
+
+ else
+ printf("\tprefix=%s, command=%s, args={%s, %s, %s, ...}\n",
+ line.prefix, line.command, line.args[0], line.args[1], line.args[2]
+ );
+}
+
+err_t irc_conn_create (struct irc_conn **conn_ptr, struct sock_stream *sock, const struct irc_conn_config *config, struct error_info *err)
+{
+ struct irc_conn *conn;
+
+ // alloc new state struct
+ if ((conn = calloc(1, sizeof(struct irc_conn))) == NULL)
+ return SET_ERROR(err, ERR_CALLOC);
+
+ // create the line_proto, with our on_line handler
+ 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;
+
+ return SUCCESS;
+}
+
+err_t irc_conn_send (struct irc_conn *conn, const struct irc_line *line)
+{
+ char line_buf[IRC_LINE_MAX + 2];
+ err_t err;
+
+ // format
+ if ((err = irc_line_build(line, line_buf)))
+ return err;
+
+ // log
+ printf(">>> %s\n", line_buf);
+
+ // add CRLF
+ strcat(line_buf, "\r\n");
+
+ // send using line_proto
+ return line_proto_write(conn->lp, line_buf);
+}
+
+err_t irc_conn_NICK (struct irc_conn *conn, const char *nickname)
+{
+ // NICK <nickname>
+ struct irc_line line = {
+ NULL, "NICK", { nickname, NULL }
+ };
+
+ // send it
+ return irc_conn_send(conn, &line);
+}
+
+err_t irc_conn_USER (struct irc_conn *conn, const char *username, const char *realname)
+{
+ // USER <user> <mode> <unused> <realname>
+ struct irc_line line = {
+ NULL, "USER", { username, "0", "*", realname }
+ };
+
+ // send it
+ return irc_conn_send(conn, &line);
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/irc_conn.h Sat Feb 28 22:47:39 2009 +0200
@@ -0,0 +1,58 @@
+#ifndef IRC_CONN_H
+#define IRC_CONN_H
+
+/*
+ * Per-connection IRC setup and state/protocol handling.
+ */
+
+#include "sock.h"
+#include "line_proto.h"
+#include "irc_line.h"
+#include "error.h"
+
+/*
+ * A connection to an IRC server.
+ */
+struct irc_conn {
+ /* We are a line-based protocol */
+ struct line_proto *lp;
+};
+
+// XXX: this should probably be slightly reworked
+struct irc_conn_config {
+ /* Nickname to use on that server */
+ const char *nickname;
+
+ /* Username to supply */
+ const char *username;
+
+ /* Realname to supply */
+ const char *realname;
+};
+
+/*
+ * 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.
+ *
+ * On success, the resulting irc_conn is returned via *conn with SUCCESS. Otherwise, -ERR_* and error info is returned
+ * via *err.
+ */
+err_t irc_conn_create (struct irc_conn **conn, struct sock_stream *sock, const struct irc_conn_config *config, struct error_info *err);
+
+/*
+ * Send an IRC message directly
+ */
+err_t irc_conn_send (struct irc_conn *conn, const struct irc_line *line);
+
+/*
+ * Send a NICK message
+ */
+err_t irc_conn_NICK (struct irc_conn *conn, const char *nickname);
+
+/*
+ * Send a USER message
+ */
+err_t irc_conn_USER (struct irc_conn *conn, const char *username, const char *realname);
+
+
+#endif /* IRC_CONN_H */
--- a/src/irc_line.h Sat Feb 28 21:39:15 2009 +0200
+++ b/src/irc_line.h Sat Feb 28 22:47:39 2009 +0200
@@ -4,9 +4,9 @@
#include "error.h"
/*
- * The maximum length of a line, including terminating CRLF
+ * The maximum length of a line, without terminating CRLF
*/
-#define IRC_LINE_MAX 512
+#define IRC_LINE_MAX 510
/*
* The maximum number of arguments for a single command
--- a/src/line_proto.c Sat Feb 28 21:39:15 2009 +0200
+++ b/src/line_proto.c Sat Feb 28 22:47:39 2009 +0200
@@ -103,8 +103,11 @@
lp->cb_arg = cb_arg;
// initialize event-based stuff
- sock_stream_event_init(sock, &line_proto_sock_stream_callbacks, lp);
- line_proto_schedule_events(lp, EV_READ);
+ if (
+ sock_stream_event_init(sock, &line_proto_sock_stream_callbacks, lp)
+ || line_proto_schedule_events(lp, EV_READ)
+ )
+ return ERROR_CODE(&lp->err);
// return
*lp_ptr = lp;
@@ -214,6 +217,25 @@
return SUCCESS;
}
+int line_proto_write (struct line_proto *lp, const char *line)
+{
+ int ret;
+ size_t len = strlen(line);
+
+ // XXX: no output buffers for now :)
+ if ((ret = sock_stream_write(lp->sock, line, len)) < 0)
+ RETURN_SET_ERROR_INFO(&lp->err, sock_stream_error(lp->sock));
+
+ // EAGAIN or partial?
+ if (ret < len) {
+ // XXX: ugly hack, need partial line buffering
+ return -1;
+ }
+
+ // ok
+ return SUCCESS;
+}
+
const struct error_info* line_proto_error (struct line_proto *lp)
{
// return pointer
--- a/src/line_proto.h Sat Feb 28 21:39:15 2009 +0200
+++ b/src/line_proto.h Sat Feb 28 22:47:39 2009 +0200
@@ -35,9 +35,12 @@
err_t line_proto_read (struct line_proto *lp, char **line_ptr);
/*
- * Signify that the line read with line_proto_read() was handled and can be discarded
+ * Write a single line to the sock_stream, buffering any incomplete fragment that remains unset. Returns zero if the
+ * line was succesfully sent, >0 if it was only partially sent, or -err on errors.
+ *
+ * The given line should already include the terminating '\r\n' character sequence.
*/
-void line_proto_discard (struct line_proto *lp);
+int line_proto_write (struct line_proto *lp, const char *line);
/*
* Get current error_info*
--- a/src/nexus.c Sat Feb 28 21:39:15 2009 +0200
+++ b/src/nexus.c Sat Feb 28 22:47:39 2009 +0200
@@ -8,12 +8,11 @@
#include <event2/event.h>
#include "sock.h"
-#include "line_proto.h"
-#include "irc_line.h"
+#include "irc_conn.h"
-#define CONNECT_HOST "irc.fixme.fi"
-#define CONNECT_SERV "6697"
-#define LINE_LENGTH 512
+#define DEFAULT_HOST "irc.fixme.fi"
+#define DEFAULT_PORT "6667"
+#define DEFAULT_PORT_SSL "6697"
static struct option options[] = {
{"help", 0, NULL, 'h' },
@@ -33,31 +32,23 @@
printf(" --ssl / -S use SSL\n");
}
-void on_line (char *line_buf, void *arg)
-{
- struct irc_line line;
- int err;
-
- // parse
- if ((err = irc_line_parse(&line, line_buf)))
- printf("!!! Invalid line: %s: %s\n", line_buf, error_name(err));
-
- else
- printf("<<< prefix=%s, command=%s, args={%s, %s, %s, ...}\n",
- line.prefix, line.command, line.args[0], line.args[1], line.args[2]
- );
-}
-
int main (int argc, char **argv)
{
int opt, option_index;
struct event_base *ev_base;
struct sock_stream *sock;
- struct line_proto *lp;
+ struct irc_conn *conn;
struct error_info _err;
- const char *hostname = CONNECT_HOST, *portname = CONNECT_SERV;
+ const char *hostname = DEFAULT_HOST, *portname = DEFAULT_PORT;
bool ssl = 0;
+ struct irc_conn_config conn_config = {
+ .nickname = "SpBotDev",
+ .username = "spbot-dev",
+ .realname = "SpBot (development version)",
+ };
+
+ bool port_default = true;
// parse options
while ((opt = getopt_long(argc, argv, "hH:P:S", options, &option_index)) != -1) {
@@ -72,10 +63,15 @@
case 'P':
portname = optarg;
+ port_default = false;
break;
case 'S':
ssl = true;
+
+ if (port_default)
+ portname = DEFAULT_PORT_SSL;
+
break;
case '?':
@@ -103,9 +99,9 @@
}
- // line protocol, with safety margin for buffer
- if (line_proto_create(&lp, sock, LINE_LENGTH * 2, on_line, NULL, &_err))
- errx(1, "line_proto_create: %s", error_msg(&_err));
+ // create the irc connection state
+ if (irc_conn_create(&conn, sock, &conn_config, &_err))
+ errx(1, "irc_conn_create: %s", error_msg(&_err));
// run event loop
if (event_base_dispatch(ev_base))