]> Pileus Git - ~andy/lamechat/commitdiff
Use net for IRC
authorAndy Spencer <andy753421@gmail.com>
Sun, 24 Sep 2017 18:26:55 +0000 (18:26 +0000)
committerAndy Spencer <andy753421@gmail.com>
Sun, 24 Sep 2017 18:26:59 +0000 (18:26 +0000)
irc.c
net.c
net.h
view.c
xmpp.c

diff --git a/irc.c b/irc.c
index df6f449c004a8e701031486415e13f14b058af4e..6f6fb7e4fc911fd3e2da2f5e84054f3b10de0451 100644 (file)
--- a/irc.c
+++ b/irc.c
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#define _GNU_SOURCE
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
 #include <string.h>
 #include <ctype.h>
-#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <arpa/inet.h>
-#include <netinet/tcp.h>
-#include <netdb.h>
 
 #include "util.h"
 #include "conf.h"
 #include "chat.h"
+#include "net.h"
 
-/* IRC Constants */
-#define BUF_LEN 1024
+/* IRC constants */
+#define IRC_LINE 512
 
 /* IRC types */
 typedef enum {
@@ -55,14 +48,10 @@ typedef struct irc_server_t {
        const char *auth;
        const char *pass;
 
+       net_t       net;
        irc_state_t state;
-       poll_t      poll;
-
-       char        in_buf[BUF_LEN];
-       int         in_len;
-       char        out_buf[BUF_LEN];
-       int         out_pos;
-       int         out_len;
+       char        line[IRC_LINE];
+       int         pos;
 
        struct irc_server_t *next;
 } irc_server_t;
@@ -114,48 +103,22 @@ static irc_channel_t *find_channel(const char *name, int create)
        return cur;
 }
 
-static int send_line(irc_server_t *srv, const char *fmt, ...)
-{
-       int len, sent;
-       va_list ap;
-       if (srv->out_len)
-               return 0;
-
-       va_start(ap, fmt);
-       len = vsnprintf(srv->out_buf, BUF_LEN, fmt, ap);
-       va_end(ap);
-       if (len <= 0)
-               return 0;
-       if (len >= BUF_LEN)
-               len = BUF_LEN-1;
-       srv->out_buf[len] = '\n';
-       len++;
-
-       sent = send(srv->poll.fd, srv->out_buf, len, 0);
-       if (sent == len)
-               return 1;
-
-       srv->out_len = len;
-       srv->out_pos = sent;
-       return 0;
-}
-
 static void recv_line(irc_server_t *srv, const char *line)
 {
-       static char src[BUF_LEN]; // (:([^ ]+) +)?   
-       static char cmd[BUF_LEN]; // (([A-Z0-9]+) +) 
-       static char dst[BUF_LEN]; // (([^ ]+)[= ]+)? 
-       static char arg[BUF_LEN]; // (([^: ]+) *)?   
-       static char msg[BUF_LEN]; // (:(.*))?        
-       static char from[BUF_LEN];
+       static char src[IRC_LINE]; // (:([^ ]+) +)?   
+       static char cmd[IRC_LINE]; // (([A-Z0-9]+) +) 
+       static char dst[IRC_LINE]; // (([^ ]+)[= ]+)? 
+       static char arg[IRC_LINE]; // (([^: ]+) *)?   
+       static char msg[IRC_LINE]; // (:(.*))?        
+       static char from[IRC_LINE];
 
        int i;
        const char *c = line;
 
-       // Clear strings
+       /* Clear strings */
        src[0] = cmd[0] = dst[0] = arg[0] = msg[0] = from[0] = '\0';
 
-       // Read src
+       /* Read src */
        if (*c == ':') {
                c++;
                for (i = 0; *c && *c != ' '; i++)
@@ -168,14 +131,14 @@ static void recv_line(irc_server_t *srv, const char *line)
                from[i] = '\0';
        }
 
-       // Read cmd
+       /* Read cmd */
        for (i = 0; isalnum(*c); i++)
                cmd[i] = *c++;
        while (*c == ' ')
                c++;
        cmd[i] = '\0';
 
-       // Read dst
+       /* Read dst */
        if ((*c && *c != ' ') &&
            (strchr(c+1, ' ') || strchr(c+1, '='))) {
                for (i = 0; *c && *c != ' '; i++)
@@ -185,7 +148,7 @@ static void recv_line(irc_server_t *srv, const char *line)
                dst[i] = '\0';
        }
 
-       // Read arg
+       /* Read arg */
        if  (*c && *c != ':' && *c != ' ') {
                for (i = 0; *c && *c != ' '; i++)
                        arg[i] = *c++;
@@ -194,7 +157,7 @@ static void recv_line(irc_server_t *srv, const char *line)
                arg[i] = '\0';
        }
 
-       // Read msg
+       /* Read msg */
        if (*c == ':') {
                c++;
                for (i = 0; *c; i++)
@@ -209,136 +172,69 @@ static void recv_line(irc_server_t *srv, const char *line)
        //debug("  arg %s", arg);
        //debug("  msg %s", msg);
 
-       // Parse messages
+       /* Parse messages */
        if (match(cmd, "001") || strstr(msg, "Welcome"))
                srv->state = IRC_JOIN;
        if (match(cmd, "PING"))
-               send_line(srv, "PING %s", msg);
+               net_print(&srv->net, "PING %s\n", msg);
        if (match(cmd, "PRIVMSG"))
                chat_recv(dst, from, msg);
+
+       /* Notices */
+       if (match(cmd, "NOTICE") ||
+           match(cmd, "001")    ||
+           match(cmd, "372")    ||
+           match(cmd, "375")    ||
+           match(cmd, "376"))
+               chat_notice(from, NULL, "%s", msg);
 }
 
-static void on_poll(void *_srv)
+static void on_recv(void *_srv, char *buf, int len)
 {
-       static char buf[BUF_LEN];
-       static char hostname[512];
-
        irc_server_t *srv = _srv;
-       int len;
 
        /* Handle Input */
-       len = recv(srv->poll.fd, buf, sizeof(buf), 0);
-       if (len < 0) {
-               debug("recv: error: %s -- %s", srv->name, strerror(errno));
-       }
-       if (len == 0) {
-               debug("recv: close: %s", srv->name);
-               srv->state = IRC_DEAD;
-               poll_del(&srv->poll);
-               return;
-       }
-       if (len > 0) {
-               debug("recv: ready: %s -- [%.*s]", srv->name, len, buf);
-       }
        for (int i = 0; i < len; i++) {
-               if (srv->in_len < BUF_LEN) {
-                       srv->in_buf[srv->in_len] = buf[i];
-                       srv->in_len++;
+               if (srv->pos < IRC_LINE) {
+                       srv->line[srv->pos] = buf[i];
+                       srv->pos++;
                }
                if (buf[i] == '\n' || buf[i] == '\r') {
-                       srv->in_buf[srv->in_len-1] = '\0';
-                       if (srv->in_len > 1)
-                               recv_line(srv, srv->in_buf);
-                       srv->in_len = 0;
+                       srv->line[srv->pos-1] = '\0';
+                       if (srv->pos > 1)
+                               recv_line(srv, srv->line);
+                       srv->pos = 0;
                }
        }
 
-       /* Handle Output */
-       if (srv->out_len > 0) {
-               len = send(srv->poll.fd, &srv->out_buf[srv->out_pos],
-                              srv->out_len-srv->out_pos, 0);
-               if (len > 0)
-                       srv->out_pos += len;
-               if (srv->out_pos == srv->out_len) {
-                       srv->out_pos = 0;
-                       srv->out_len = 0;
-               }
-       }
-
-       /* Handle Errors */
-       int err = 0;
-       socklen_t elen = sizeof(err);
-       if (getsockopt(srv->poll.fd, SOL_SOCKET, SO_ERROR, &err, &elen))
-               error("Error getting socket opt");
-       if (err) {
-               debug("disconnect: %s -- %s", srv->name, strerror(err));
-               srv->state = IRC_DEAD;
-               poll_del(&srv->poll);
-               return;
-       }
-
        /* State machine */
        if (srv->state == IRC_USER) {
-               if (gethostname(hostname, sizeof(hostname)))
-                       error("Error getting hostname");
-               if (send_line(srv, "USER %s %s %s :%s",
+               if (net_print(&srv->net, "USER %s %s %s :%s\n",
                                getenv("USER") ?: "lameuser",
-                               hostname, srv->host, srv->nick))
+                               get_hostname(), srv->host, srv->nick))
                        srv->state = IRC_NICK;
        }
        if (srv->state == IRC_NICK) {
-               if (send_line(srv, "NICK %s", srv->nick))
+               if (net_print(&srv->net, "NICK %s\n", srv->nick))
                        srv->state = IRC_READY;
        }
        if (srv->state == IRC_JOIN) {
                for (irc_channel_t *chan = channels; chan; chan = chan->next)
                        if (chan->join)
-                               send_line(srv, "JOIN %s", chan->channel);
+                               net_print(&srv->net, "JOIN %s\n", chan->channel);
                srv->state = IRC_READY;
        }
-
-       /* Enable output poll */
-       if (srv->out_len)
-               poll_ctl(&srv->poll, 1, 1, 1);
-       else
-               poll_ctl(&srv->poll, 1, 0, 1);
 }
 
 static void irc_connect(irc_server_t *srv)
 {
-       int sock, flags;
-       struct addrinfo *addrs = NULL;
-       struct addrinfo hints = {};
-       char service[16];
-
-       snprintf(service, sizeof(service), "%d", srv->port);
-       hints.ai_family   = AF_INET;
-       hints.ai_socktype = SOCK_STREAM;
-
-       /* Setup address */
-       if (getaddrinfo(srv->host, service, &hints, &addrs))
-               error("Error getting address info");
-
-       if ((sock = socket(addrs->ai_family,
-                          addrs->ai_socktype,
-                          addrs->ai_protocol)) < 0)
-               error("Error opening irc socket");
-
-       if ((flags = fcntl(sock, F_GETFL, 0)) < 0)
-               error("Error getting irc socket flags");
-
-       if (fcntl(sock, F_SETFL, flags|O_NONBLOCK) < 0)
-               error("Error setting irc socket non-blocking");
-
-       if (connect(sock, addrs->ai_addr, addrs->ai_addrlen) < 0)
-               if (errno != EINPROGRESS)
-                       error("Error connecting socket");
-
-       freeaddrinfo(addrs);
+       /* Net connect */
+       srv->net.recv = on_recv;
+       srv->net.data = srv;
+       net_open(&srv->net, srv->host, srv->port);
 
        /* Setup server */
        srv->state = IRC_USER;
-       poll_add(&srv->poll, sock, on_poll, srv);
 }
 
 /* IRC functions */
@@ -404,7 +300,7 @@ void irc_send(const char *channel, const char *msg)
        irc_server_t *srv = find_server(chan->server, 0);
        if (!srv)
                return;
-       send_line(srv, "PRIVMSG %s :%s", chan->channel, msg);
+       net_print(&srv->net, "PRIVMSG %s :%s\n", chan->channel, msg);
 }
 
 void irc_exit(void)
diff --git a/net.c b/net.c
index 3ab27cac419ac508e955b64b0bae89121d39e342..c17779716ca5c68e0908634b2e4d8c24365ac010 100644 (file)
--- a/net.c
+++ b/net.c
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
-#include <string.h>
 #include <errno.h>
+#include <unistd.h>
 #include <fcntl.h>
 #include <netdb.h>
-#include <expat.h>
 
 #include <openssl/bio.h>
 #include <openssl/ssl.h>
@@ -137,31 +136,23 @@ static void on_poll(void *_net)
        }
 }
 
-void net_encrypt(net_t *net)
+/* Networking functions */
+const char *get_hostname(void)
 {
-       debug("net: encrypt");
-
-       net->ctx = SSL_CTX_new(TLSv1_2_client_method());
-       net->ssl = SSL_new(net->ctx);
-
-       net->in  = BIO_new(BIO_s_mem());
-       net->out = BIO_new(BIO_s_mem());
+       static char hostname[512];
 
-       BIO_set_mem_eof_return(net->in,  -1);
-       BIO_set_mem_eof_return(net->out, -1);
+       if (gethostname(hostname, sizeof(hostname)))
+               error("Error getting hostname");
 
-       SSL_set_bio(net->ssl, net->in, net->out);
-       SSL_set_connect_state(net->ssl);
-
-       net->state = NET_HANDSHAKE;
+       return hostname;
 }
 
-void net_close(net_t *net)
+void net_init(void)
 {
-       debug("net_close: %s:%d",
-               net->host, net->port);
-       net->state = NET_CLOSED;
-       poll_del(&net->poll);
+       SSL_library_init();
+       SSL_load_error_strings();
+       ERR_load_BIO_strings();
+       OpenSSL_add_all_algorithms();
 }
 
 void net_open(net_t *net, const char *host, int port)
@@ -204,6 +195,25 @@ void net_open(net_t *net, const char *host, int port)
        poll_add(&net->poll, sock, on_poll, net);
 }
 
+void net_encrypt(net_t *net)
+{
+       debug("net: encrypt");
+
+       net->ctx = SSL_CTX_new(TLSv1_2_client_method());
+       net->ssl = SSL_new(net->ctx);
+
+       net->in  = BIO_new(BIO_s_mem());
+       net->out = BIO_new(BIO_s_mem());
+
+       BIO_set_mem_eof_return(net->in,  -1);
+       BIO_set_mem_eof_return(net->out, -1);
+
+       SSL_set_bio(net->ssl, net->in, net->out);
+       SSL_set_connect_state(net->ssl);
+
+       net->state = NET_HANDSHAKE;
+}
+
 int net_send(net_t *net, const char *buf, int len)
 {
        if (net->out_len)
@@ -238,7 +248,10 @@ int net_print(net_t *net, const char *fmt, ...)
        if (len > NET_BUFFER)
                len = NET_BUFFER;
 
-       debug("net: print [%.*s]", len, net->out_buf);
+       if (net->out_buf[len-1] == '\n')
+               debug("net: print [%.*s]", len-1, net->out_buf);
+       else
+               debug("net: print [%.*s]", len, net->out_buf);
 
        net->out_len = len;
        net->out_pos = 0;
@@ -246,10 +259,11 @@ int net_print(net_t *net, const char *fmt, ...)
        return flush(net);
 }
 
-void net_init(void)
+void net_close(net_t *net)
 {
-       SSL_library_init();
-       SSL_load_error_strings();
-       ERR_load_BIO_strings();
-       OpenSSL_add_all_algorithms();
+       debug("net_close: %s:%d",
+               net->host, net->port);
+       net->state = NET_CLOSED;
+       poll_del(&net->poll);
 }
+
diff --git a/net.h b/net.h
index 6b977983e15566f0082bbbb79cf985bf7946c72b..2c74a87c68f9b3c2fc50ed457b23aa6778c0f5c5 100644 (file)
--- a/net.h
+++ b/net.h
@@ -56,11 +56,13 @@ typedef struct {
        int      out_len;
 } net_t;
 
-/* Networking Functions */
+/* Networking functions */
+const char *get_hostname(void);
+
+/* Connection functions */
 void net_init(void);
 void net_open(net_t *net, const char *host, int port);
 void net_encrypt(net_t *net);
 int  net_send(net_t *net, const char *buf, int len);
 int  net_print(net_t *net, const char *fmt, ...);
-int  net_poll(net_t *net);
 void net_close(net_t *net);
diff --git a/view.c b/view.c
index 12a386b68d235e5905a9de9768a7ff3e87b32bd8..e108bbfe790366f8b8736e8b23bb6d7803839a78 100644 (file)
--- a/view.c
+++ b/view.c
@@ -57,29 +57,30 @@ static void print_word(char **msg, int *row, int *col, int indent, int print)
        char *start = *msg;
        while (*start && isspace(*start))
                start++;
+       int space = start-*msg;
 
        char *end = start;
        while (*end && !isspace(*end))
                end++;
-       *msg = end;
-
        int len = end-start;
-       if ((*col != indent) && (*col + 1 + len > COLS)) {
+
+       if ((*col != indent) && (*col + space + len > COLS)) {
                *col = indent;
                *row = (*row)+1;
+               space = 0;
        }
 
        if (*row < 1 || *row > LINES-2)
                print = 0;
 
-       if (*col != indent) {
-               if (print)
-                       mvaddch(*row, *col, ' ');
-               *col += 1;
-       }
+       if (print)
+               mvaddnstr(*row, *col, *msg, space);
+       *col += space;
        if (print)
                mvaddnstr(*row, *col, start, len);
        *col += len;
+
+       *msg = end;
 }
 
 static void print_msg(log_t *log, int *row, int print)
diff --git a/xmpp.c b/xmpp.c
index 0656b9264f11916b66277cd2fefede52477d997d..75a65ff0e84623124d21a2be5520b90fcc2908dd 100644 (file)
--- a/xmpp.c
+++ b/xmpp.c
 #include <stdarg.h>
 #include <string.h>
 #include <errno.h>
-#include <fcntl.h>
-#include <netdb.h>
 #include <expat.h>
 
 #include "util.h"
-#include "chat.h"
 #include "conf.h"
+#include "chat.h"
 #include "net.h"
 
 /* Constants */
@@ -252,8 +250,38 @@ static void on_recv(void *_srv, char *buf, int len)
        if (len > 0)
                XML_Parse(srv->expat, buf, len, 0);
 
+       /* Stream restart */
+       if (srv->state == XMPP_ENCRYPT) {
+               /* Encrypt connection */
+               net_encrypt(&srv->net);
+
+               /* Reset Expat */
+               if (!(XML_ParserReset(srv->expat, NULL)))
+                       error("Error resetting XML parser");
+               XML_SetUserData(srv->expat, srv);
+               XML_SetStartElementHandler(srv->expat, on_start);
+               XML_SetEndElementHandler(srv->expat, on_end);
+               XML_SetCharacterDataHandler(srv->expat, on_data);
+
+               /* Reset server */
+               debug("xmpp: encrypt -> stream");
+               srv->state = XMPP_SEND_STREAM;
+       }
+       if (srv->state == XMPP_RESTART) {
+               /* Reset Expat */
+               if (!(XML_ParserReset(srv->expat, NULL)))
+                       error("Error resetting XML parser");
+               XML_SetUserData(srv->expat, srv);
+               XML_SetStartElementHandler(srv->expat, on_start);
+               XML_SetEndElementHandler(srv->expat, on_end);
+               XML_SetCharacterDataHandler(srv->expat, on_data);
+
+               /* Reset server */
+               debug("xmpp: restart -> stream");
+               srv->state = XMPP_SEND_STREAM;
+       }
+
        /* State machine */
-output:
        if (srv->state == XMPP_SEND_STREAM) {
                if (net_print(&srv->net,
                    "<?xml version='1.0'?>"
@@ -318,37 +346,6 @@ output:
                }
                srv->state = XMPP_READY;
        }
-       if (srv->state == XMPP_ENCRYPT) {
-               /* Encrypt connection */
-               net_encrypt(&srv->net);
-
-               /* Reset Expat */
-               if (!(XML_ParserReset(srv->expat, NULL)))
-                       error("Error resetting XML parser");
-               XML_SetUserData(srv->expat, srv);
-               XML_SetStartElementHandler(srv->expat, on_start);
-               XML_SetEndElementHandler(srv->expat, on_end);
-               XML_SetCharacterDataHandler(srv->expat, on_data);
-
-               /* Reset server */
-               debug("xmpp: encrypt -> stream");
-               srv->state = XMPP_SEND_STREAM;
-               goto output;
-       }
-       if (srv->state == XMPP_RESTART) {
-               /* Reset Expat */
-               if (!(XML_ParserReset(srv->expat, NULL)))
-                       error("Error resetting XML parser");
-               XML_SetUserData(srv->expat, srv);
-               XML_SetStartElementHandler(srv->expat, on_start);
-               XML_SetEndElementHandler(srv->expat, on_end);
-               XML_SetCharacterDataHandler(srv->expat, on_data);
-
-               /* Reset server */
-               debug("xmpp: restart -> stream");
-               srv->state = XMPP_SEND_STREAM;
-               goto output;
-       }
 }
 
 static void xmpp_connect(xmpp_server_t *srv)