Mercurial > irccd
changeset 970:c745bb6721fd
irccd: several cleanup and improvements for SSL
author | David Demelier <markand@malikania.fr> |
---|---|
date | Wed, 03 Feb 2021 20:05:00 +0100 |
parents | d7501067de95 |
children | f365e5be1261 |
files | irccd/conf.y lib/irccd/channel.c lib/irccd/channel.h lib/irccd/conn.c lib/irccd/conn.h lib/irccd/event.c lib/irccd/event.h lib/irccd/server.c lib/irccd/server.h |
diffstat | 9 files changed, 203 insertions(+), 155 deletions(-) [+] |
line wrap: on
line diff
--- a/irccd/conf.y Wed Feb 03 12:37:46 2021 +0100 +++ b/irccd/conf.y Wed Feb 03 20:05:00 2021 +0100 @@ -432,6 +432,7 @@ string_list_finish($4->channels); } + s->flags = $4->flags; irc_bot_server_add(s); free($2);
--- a/lib/irccd/channel.c Wed Feb 03 12:37:46 2021 +0100 +++ b/lib/irccd/channel.c Wed Feb 03 20:05:00 2021 +0100 @@ -36,7 +36,7 @@ } struct irc_channel * -irc_channel_new(const char *name, const char *password, bool joined) +irc_channel_new(const char *name, const char *password, int joined) { assert(name);
--- a/lib/irccd/channel.h Wed Feb 03 12:37:46 2021 +0100 +++ b/lib/irccd/channel.h Wed Feb 03 20:05:00 2021 +0100 @@ -20,7 +20,6 @@ #define IRCCD_CHANNEL_H #include <sys/queue.h> -#include <stdbool.h> #include <stddef.h> #include "limits.h" @@ -35,7 +34,7 @@ struct irc_channel { char name[IRC_CHANNEL_LEN]; char password[IRC_PASSWORD_LEN]; - bool joined; + int joined; LIST_HEAD(, irc_channel_user) users; LIST_ENTRY(irc_channel) link; }; @@ -43,7 +42,7 @@ LIST_HEAD(irc_channel_list, irc_channel); struct irc_channel * -irc_channel_new(const char *, const char *, bool); +irc_channel_new(const char *, const char *, int); void irc_channel_add(struct irc_channel *, const char *, char, char);
--- a/lib/irccd/conn.c Wed Feb 03 12:37:46 2021 +0100 +++ b/lib/irccd/conn.c Wed Feb 03 20:05:00 2021 +0100 @@ -40,10 +40,13 @@ if (conn->ctx) SSL_CTX_free(conn->ctx); + conn->ssl_cond = IRC_CONN_SSL_ACT_NONE; + conn->ssl_step = IRC_CONN_SSL_ACT_NONE; conn->ssl = NULL; conn->ctx = NULL; #endif + conn->state = IRC_CONN_STATE_NONE; conn->fd = -1; } @@ -59,7 +62,7 @@ *line = p ? p + 1 : strchr(*line, '\0'); } -static bool +static int parse(struct irc_conn_msg *msg, const char *line) { char *ptr = msg->buf; @@ -88,14 +91,14 @@ } if (a >= IRC_UTIL_SIZE(msg->args)) - return errno = EMSGSIZE, false; + return errno = EMSGSIZE, -1; if (msg->cmd == NULL) - return errno = EBADMSG, false; + return errno = EBADMSG, -1; - return true; + return 0; } -static bool +static int create(struct irc_conn *conn) { struct addrinfo *ai = conn->aip; @@ -104,24 +107,24 @@ cleanup(conn); if ((conn->fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0) - return false; + return -1; if ((cflags = fcntl(conn->fd, F_GETFL)) < 0) - return false; + return -1; if (fcntl(conn->fd, F_SETFL, cflags | O_NONBLOCK) < 0) - return false; + return -1; - return true; + return 0; } -static inline bool +static inline int update_ssl_state(struct irc_conn *conn, int ret) { switch (SSL_get_error(conn->ssl, ret)) { case SSL_ERROR_WANT_READ: - conn->ssl_state = IRC_CONN_SSL_STATE_NEED_READ; + conn->ssl_cond = IRC_CONN_SSL_ACT_READ; break; case SSL_ERROR_WANT_WRITE: - conn->ssl_state = IRC_CONN_SSL_STATE_NEED_WRITE; + conn->ssl_cond = IRC_CONN_SSL_ACT_WRITE; break; case SSL_ERROR_SSL: return irc_conn_disconnect(conn), -1; @@ -129,18 +132,21 @@ break; } - return true; + return 0; } -static ssize_t +static inline ssize_t input_ssl(struct irc_conn *conn, char *dst, size_t dstsz) { int nr; - if ((nr = SSL_read(conn->ssl, dst, dstsz)) <= 0) + if ((nr = SSL_read(conn->ssl, dst, dstsz)) <= 0) { + conn->ssl_step = IRC_CONN_SSL_ACT_READ; return update_ssl_state(conn, nr); + } - conn->ssl_state = IRC_CONN_SSL_STATE_NONE; + conn->ssl_cond = IRC_CONN_SSL_ACT_NONE; + conn->ssl_step = IRC_CONN_SSL_ACT_NONE; return nr; } @@ -150,13 +156,15 @@ { ssize_t nr; - if ((nr = recv(conn->fd, buf, bufsz, 0)) <= 0) + if ((nr = recv(conn->fd, buf, bufsz, 0)) <= 0) { + errno = ECONNRESET; return irc_conn_disconnect(conn), -1; + } return nr; } -static bool +static int input(struct irc_conn *conn) { size_t len = strlen(conn->in); @@ -171,7 +179,7 @@ if (nr > 0) conn->in[len + nr] = '\0'; - return nr > 0; + return nr; } static inline ssize_t @@ -179,8 +187,13 @@ { int ns; - if ((ns = SSL_write(conn->ssl, conn->out, strlen(conn->out))) <= 0) + if ((ns = SSL_write(conn->ssl, conn->out, strlen(conn->out))) <= 0) { + conn->ssl_step = IRC_CONN_SSL_ACT_WRITE; return update_ssl_state(conn, ns); + } + + conn->ssl_cond = IRC_CONN_SSL_ACT_NONE; + conn->ssl_step = IRC_CONN_SSL_ACT_NONE; return ns; } @@ -196,7 +209,7 @@ return ns; } -static bool +static int output(struct irc_conn *conn) { ssize_t ns = 0; @@ -214,10 +227,10 @@ memmove(conn->out, conn->out + ns, sizeof (conn->out) - ns); } - return ns != -1; + return ns; } -static bool +static int handshake(struct irc_conn *conn) { if (conn->flags & IRC_CONN_SSL) { @@ -244,25 +257,25 @@ return update_ssl_state(conn, r); conn->state = IRC_CONN_STATE_READY; + conn->ssl_cond = IRC_CONN_SSL_ACT_NONE; + conn->ssl_step = IRC_CONN_SSL_ACT_NONE; #endif } else conn->state = IRC_CONN_STATE_READY; - return true; + return 0; } -static bool +static int dial(struct irc_conn *conn) { /* No more address available. */ if (conn->aip == NULL) - return irc_conn_disconnect(conn), false; + return irc_conn_disconnect(conn), -1; for (; conn->aip; conn->aip = conn->aip->ai_next) { - if (!create(conn)) { - // irc_log_warn("server %s: %s", s->name, strerror(errno)); + if (create(conn) < 0) continue; - } /* * With some luck, the connection completes immediately, @@ -272,14 +285,16 @@ return handshake(conn); /* Connect "succeeds" but isn't complete yet. */ - if (errno == EINPROGRESS || errno == EAGAIN) - return true; + if (errno == EINPROGRESS || errno == EAGAIN) { + conn->state = IRC_CONN_STATE_CONNECTING; + return 0; + } } - return false; + return -1; } -static bool +static int lookup(struct irc_conn *conn) { struct addrinfo hints = { @@ -293,15 +308,15 @@ if ((ret = getaddrinfo(conn->hostname, service, &hints, &conn->ai)) != 0) { // irc_log_warn gai_strerror(ret) - return false; + return -1; } conn->aip = conn->ai; - return true; + return 0; } -static bool +static int check_connect(struct irc_conn *conn) { int res, err = -1; @@ -314,37 +329,15 @@ return handshake(conn); } -bool -irc_conn_connect(struct irc_conn *conn) -{ - assert(conn); - - conn->state = IRC_CONN_STATE_CONNECTING; - - if (!lookup(conn)) - return irc_conn_disconnect(conn), false; - - return dial(conn), true; -} - -void -irc_conn_disconnect(struct irc_conn *conn) -{ - assert(conn); - - cleanup(conn); - conn->state = IRC_CONN_STATE_NONE; -} - static inline void prepare_ssl(const struct irc_conn *conn, struct pollfd *pfd) { #if defined(IRCCD_WITH_SSL) - switch (conn->ssl_state) { - case IRC_CONN_SSL_STATE_NEED_READ: + switch (conn->ssl_cond) { + case IRC_CONN_SSL_ACT_READ: pfd->events |= POLLIN; break; - case IRC_CONN_SSL_STATE_NEED_WRITE: + case IRC_CONN_SSL_ACT_WRITE: pfd->events |= POLLOUT; break; default: @@ -355,6 +348,33 @@ #endif } +static inline int +renegotiate(struct irc_conn *conn) +{ + return conn->ssl_step == IRC_CONN_SSL_ACT_READ + ? input(conn) + : output(conn); +} + +int +irc_conn_connect(struct irc_conn *conn) +{ + assert(conn); + + if (lookup(conn) < 0) + return irc_conn_disconnect(conn), -1; + + return dial(conn); +} + +void +irc_conn_disconnect(struct irc_conn *conn) +{ + assert(conn); + + cleanup(conn); +} + void irc_conn_prepare(const struct irc_conn *conn, struct pollfd *pfd) { @@ -363,7 +383,7 @@ pfd->fd = conn->fd; - if (conn->ssl_state) + if (conn->ssl_cond) prepare_ssl(conn, pfd); else { switch (conn->state) { @@ -382,7 +402,7 @@ } } -bool +int irc_conn_flush(struct irc_conn *conn, const struct pollfd *pfd) { assert(conn); @@ -395,20 +415,22 @@ return handshake(conn); case IRC_CONN_STATE_READY: if (pfd->revents & (POLLERR | POLLHUP)) - return irc_conn_disconnect(conn), false; - if (pfd->revents & POLLIN && !input(conn)) - return irc_conn_disconnect(conn), false; - if (pfd->revents & POLLOUT && !output(conn)) - return irc_conn_disconnect(conn), false; + return irc_conn_disconnect(conn), -1; + if (conn->ssl_cond && renegotiate(conn) < 0) + return irc_conn_disconnect(conn), -1; + if (pfd->revents & POLLIN && input(conn) < 0) + return irc_conn_disconnect(conn), -1; + if (pfd->revents & POLLOUT && output(conn) < 0) + return irc_conn_disconnect(conn), -1; break; default: break; } - return true; + return 0; } -bool +int irc_conn_poll(struct irc_conn *conn, struct irc_conn_msg *msg) { assert(conn); @@ -418,7 +440,7 @@ size_t length; if (!(pos = strstr(conn->in, "\r\n"))) - return false; + return 0; /* Turn end of the string at delimiter. */ *pos = 0; @@ -427,27 +449,30 @@ if (length > 0) parse(msg, conn->in); + /* (Re)move the first message received. */ memmove(conn->in, pos + 2, sizeof (conn->in) - (length + 2)); - return true; + return 1; } -bool +int irc_conn_send(struct irc_conn *conn, const char *data) { assert(conn); assert(data); if (strlcat(conn->out, data, sizeof (conn->out)) >= sizeof (conn->out)) - return errno = EMSGSIZE, false; + return errno = EMSGSIZE, -1; if (strlcat(conn->out, "\r\n", sizeof (conn->out)) >= sizeof (conn->out)) - return errno = EMSGSIZE, false; + return errno = EMSGSIZE, -1; - return true; + return 0; } void irc_conn_finish(struct irc_conn *conn) { assert(conn); + + cleanup(conn); }
--- a/lib/irccd/conn.h Wed Feb 03 12:37:46 2021 +0100 +++ b/lib/irccd/conn.h Wed Feb 03 20:05:00 2021 +0100 @@ -19,8 +19,6 @@ #ifndef IRCCD_CONN_H #define IRCCD_CONN_H -#include <stdbool.h> - #include "config.h" #if defined(IRCCD_WITH_SSL) @@ -45,10 +43,10 @@ #if defined(IRCCD_WITH_SSL) -enum irc_conn_ssl_state { - IRC_CONN_SSL_STATE_NONE, - IRC_CONN_SSL_STATE_NEED_READ, - IRC_CONN_SSL_STATE_NEED_WRITE, +enum irc_conn_ssl_act { + IRC_CONN_SSL_ACT_NONE, + IRC_CONN_SSL_ACT_READ, + IRC_CONN_SSL_ACT_WRITE, }; #endif @@ -67,7 +65,8 @@ #if defined(IRCCD_WITH_SSL) SSL_CTX *ctx; SSL *ssl; - enum irc_conn_ssl_state ssl_state; + enum irc_conn_ssl_act ssl_cond; + enum irc_conn_ssl_act ssl_step; #endif }; @@ -78,7 +77,7 @@ char buf[IRC_MESSAGE_LEN]; }; -bool +int irc_conn_connect(struct irc_conn *); void @@ -87,13 +86,13 @@ void irc_conn_prepare(const struct irc_conn *, struct pollfd *); -bool +int irc_conn_flush(struct irc_conn *, const struct pollfd *); -bool +int irc_conn_poll(struct irc_conn *, struct irc_conn_msg *); -bool +int irc_conn_send(struct irc_conn *, const char *); void
--- a/lib/irccd/event.c Wed Feb 03 12:37:46 2021 +0100 +++ b/lib/irccd/event.c Wed Feb 03 20:05:00 2021 +0100 @@ -43,9 +43,8 @@ ev->server->name); break; case IRC_EVENT_INVITE: - written = snprintf(str, strsz, "EVENT-INVITE %s %s %s %s", - ev->server->name, ev->invite.origin, ev->invite.channel, - ev->invite.target); + written = snprintf(str, strsz, "EVENT-INVITE %s %s %s", + ev->server->name, ev->invite.origin, ev->invite.channel); break; case IRC_EVENT_JOIN: written = snprintf(str, strsz, "EVENT-JOIN %s %s %s",
--- a/lib/irccd/event.h Wed Feb 03 12:37:46 2021 +0100 +++ b/lib/irccd/event.h Wed Feb 03 20:05:00 2021 +0100 @@ -58,7 +58,6 @@ struct irc_event_invite { char *origin; char *channel; - char *target; }; struct irc_event_join {
--- a/lib/irccd/server.c Wed Feb 03 12:37:46 2021 +0100 +++ b/lib/irccd/server.c Wed Feb 03 20:05:00 2021 +0100 @@ -37,7 +37,7 @@ #include "util.h" static inline void -clear_channels(struct irc_server *s, bool free) +clear_channels(struct irc_server *s, int free) { struct irc_channel *c, *tmp; @@ -65,7 +65,7 @@ memset(&s->bufwhois, 0, sizeof (s->bufwhois)); } -static inline bool +static inline int is_self(const struct irc_server *s, const char *nick) { return strncmp(s->ident.nickname, nick, strlen(s->ident.nickname)) == 0; @@ -81,7 +81,7 @@ } static struct irc_channel * -add_channel(struct irc_server *s, const char *name, const char *password, bool joined) +add_channel(struct irc_server *s, const char *name, const char *password, int joined) { struct irc_channel *ch; @@ -110,20 +110,20 @@ LIST_REMOVE(ch, link); } -bool +static int is_ctcp(const char *line) { size_t length; if (!line) - return false; + return 0; if ((length = strlen(line)) < 2) - return false; + return 0; return line[0] == 0x1 && line[length - 1] == 0x1; } -char * +static char * ctcp(char *line) { /* Skip first \001. */ @@ -156,6 +156,10 @@ for (size_t i = 0; i < IRC_UTIL_SIZE(s->params.prefixes) && *pm && *tk; ++i) { s->params.prefixes[i].mode = *pm++; s->params.prefixes[i].token = *tk++; + + irc_log_info("server %s: supports prefix %c=%c", s->name, + s->params.prefixes[i].mode, + s->params.prefixes[i].token); } } } @@ -164,6 +168,7 @@ read_support_chantypes(struct irc_server *s, const char *value) { strlcpy(s->params.chantypes, value, sizeof (s->params.chantypes)); + irc_log_info("server %s: supports channel types: %s", s->name, s->params.chantypes); } static void @@ -173,13 +178,14 @@ struct irc_channel *ch; - s->state = IRC_SERVER_STATE_CONNECTED; - /* Now join all channels that were requested. */ LIST_FOREACH(ch, &s->channels, link) irc_server_join(s, ch->name, ch->password); + s->state = IRC_SERVER_STATE_CONNECTED; ev->type = IRC_EVENT_CONNECT; + + irc_log_info("server %s: connection complete", s->name); } static void @@ -188,6 +194,7 @@ s->state = IRC_SERVER_STATE_NONE; ev->type = IRC_EVENT_DISCONNECT; ev->server = s; + irc_log_info("server %s: connection lost", s->name); } static void @@ -215,10 +222,11 @@ ev->type = IRC_EVENT_INVITE; ev->invite.origin = strdup(msg->args[0]); ev->invite.channel = strdup(msg->args[1]); - ev->invite.target = strdup(msg->args[2]); - if (is_self(s, ev->invite.target) && s->flags & IRC_SERVER_FLAGS_JOIN_INVITE) + if (s->flags & IRC_SERVER_FLAGS_JOIN_INVITE) { irc_server_join(s, ev->invite.channel, NULL); + irc_log_info("server %s: joining %s on invite", s->name, ev->invite.channel); + } } static void @@ -229,6 +237,9 @@ ev->join.channel = strdup(msg->args[0]); add_channel(s, ev->join.channel, NULL, true); + + if (is_self(s, ev->join.origin)) + irc_log_info("server %s: joined channel %s", s->name, ev->join.channel); } static void @@ -246,12 +257,14 @@ * If the bot was kicked itself mark the channel as not joined and * rejoin it automatically if the option is set. */ - if (is_self(s, ev->kick.target) == 0) { - ch->joined = false; + if (is_self(s, ev->kick.target)) { + ch->joined = 0; irc_channel_clear(ch); - if (s->flags & IRC_SERVER_FLAGS_AUTO_REJOIN) + if (s->flags & IRC_SERVER_FLAGS_AUTO_REJOIN) { irc_server_join(s, ch->name, ch->password); + irc_log_info("server %s: rejoining %s after kick", s->name, ch->name); + } } else irc_channel_remove(ch, ev->kick.target); } @@ -286,9 +299,10 @@ ch = add_channel(s, ev->part.channel, NULL, true); - if (is_self(s, ev->part.origin) == 0) + if (is_self(s, ev->part.origin) == 0) { remove_channel(ch); - else + irc_log_info("server %s: leaving channel %s", s->name, ev->part.channel); + } else irc_channel_remove(ch, ev->part.origin); } @@ -323,8 +337,11 @@ ev->nick.nickname = strdup(msg->args[0]); /* Update nickname if it is myself. */ - if (is_self(s, ev->nick.origin) == 0) + if (is_self(s, ev->nick.origin) == 0) { + irc_log_info("server %s: nick change %s -> %s", s->name, + s->ident.nickname, ev->nick.nickname); strlcpy(s->ident.nickname, ev->nick.nickname, sizeof (s->ident.nickname)); + } } static void @@ -540,9 +557,8 @@ struct irc_server *s; + /* Connection. */ s = irc_util_calloc(1, sizeof (*s)); - - /* Connection. */ s->conn.port = port; strlcpy(s->conn.hostname, hostname, sizeof (s->conn.hostname)); @@ -563,10 +579,13 @@ { assert(s); - if (irc_conn_connect(&s->conn)) + if (s->flags & IRC_SERVER_FLAGS_SSL) + s->conn.flags |= IRC_CONN_SSL; + + if (irc_conn_connect(&s->conn) < 0) + s->state = IRC_SERVER_STATE_DISCONNECTED; + else s->state = IRC_SERVER_STATE_CONNECTING; - else - s->state = IRC_SERVER_STATE_DISCONNECTED; } void @@ -597,7 +616,7 @@ assert(s); assert(pfd); - if (!irc_conn_flush(&s->conn, pfd)) + if (irc_conn_flush(&s->conn, pfd) < 0) return irc_server_disconnect(s); if (s->conn.state != IRC_CONN_STATE_READY) return; @@ -615,7 +634,7 @@ } } -bool +int irc_server_poll(struct irc_server *s, struct irc_event *ev) { assert(s); @@ -623,12 +642,20 @@ struct irc_conn_msg msg = {0}; - if (irc_conn_poll(&s->conn, &msg)) - return handle(s, ev, &msg), true; + /* + * When the server gets disconnected, the state changes to + * IRC_SERVER_STATE_DISCONNECTED which notifies the caller with the + * appropriate event. Then to avoid returning this same event each time + * this function is called again, we immediately change the state to + * something else. + */ if (s->state == IRC_SERVER_STATE_DISCONNECTED) - return handle_disconnect(s, ev), true; + return handle_disconnect(s, ev), 1; - return false; + if (irc_conn_poll(&s->conn, &msg)) + return handle(s, ev, &msg), 1; + + return 0; } struct irc_channel * @@ -646,7 +673,7 @@ return NULL; } -bool +int irc_server_send(struct irc_server *s, const char *fmt, ...) { assert(s); @@ -662,7 +689,7 @@ return irc_conn_send(&s->conn, buf); } -bool +int irc_server_invite(struct irc_server *s, const char *channel, const char *target) { assert(s); @@ -672,7 +699,7 @@ return irc_server_send(s, "INVITE %s %s", target, channel); } -bool +int irc_server_join(struct irc_server *s, const char *name, const char *pass) { assert(s); @@ -687,7 +714,7 @@ * and wait for connection. */ if (!(ch = irc_server_find(s, name))) - ch = add_channel(s, name, pass, false); + ch = add_channel(s, name, pass, 0); if (!ch->joined && s->state == IRC_SERVER_STATE_CONNECTED) { if (pass) @@ -699,14 +726,14 @@ return ret; } -bool +int irc_server_kick(struct irc_server *s, const char *channel, const char *target, const char *reason) { assert(s); assert(channel); assert(target); - bool ret; + int ret; if (reason) ret = irc_server_send(s, "KICK %s %s :%s", channel, target, reason); @@ -716,13 +743,13 @@ return ret; } -bool +int irc_server_part(struct irc_server *s, const char *channel, const char *reason) { assert(s); assert(channel); - bool ret; + int ret; if (reason && strlen(reason) > 0) ret = irc_server_send(s, "PART %s :%s", channel, reason); @@ -732,7 +759,7 @@ return ret; } -bool +int irc_server_topic(struct irc_server *s, const char *channel, const char *topic) { assert(s); @@ -742,7 +769,7 @@ return irc_server_send(s, "TOPIC %s :%s", channel, topic); } -bool +int irc_server_message(struct irc_server *s, const char *chan, const char *msg) { assert(s); @@ -752,7 +779,7 @@ return irc_server_send(s, "PRIVMSG %s :%s", chan, msg); } -bool +int irc_server_me(struct irc_server *s, const char *chan, const char *message) { assert(s); @@ -762,7 +789,7 @@ return irc_server_send(s, "PRIVMSG %s :\001ACTION %s\001", chan, message); } -bool +int irc_server_mode(struct irc_server *s, const char *channel, const char *mode, @@ -780,13 +807,13 @@ mask ? mask : ""); } -bool +int irc_server_names(struct irc_server *s, const char *channel) { return irc_server_send(s, "NAMES %s", channel); } -bool +int irc_server_nick(struct irc_server *s, const char *nick) { assert(s); @@ -794,13 +821,13 @@ if (s->state <= IRC_SERVER_STATE_DISCONNECTED) { strlcpy(s->ident.nickname, nick, sizeof (s->ident.nickname)); - return true; + return 1; } return irc_server_send(s, "NICK %s", nick); } -bool +int irc_server_notice(struct irc_server *s, const char *channel, const char *message) { assert(s); @@ -810,7 +837,7 @@ return irc_server_send(s, "NOTICE %s: %s", channel, message); } -bool +int irc_server_whois(struct irc_server *s, const char *target) { assert(s);
--- a/lib/irccd/server.h Wed Feb 03 12:37:46 2021 +0100 +++ b/lib/irccd/server.h Wed Feb 03 20:05:00 2021 +0100 @@ -20,7 +20,6 @@ #define IRCCD_SERVER_H #include <sys/queue.h> -#include <stdbool.h> #include <stddef.h> #include "channel.h" @@ -107,37 +106,37 @@ void irc_server_flush(struct irc_server *, const struct pollfd *); -bool +int irc_server_poll(struct irc_server *, struct irc_event *); struct irc_channel * irc_server_find(struct irc_server *, const char *); -bool +int irc_server_send(struct irc_server *, const char *, ...); -bool +int irc_server_invite(struct irc_server *, const char *, const char *); -bool +int irc_server_join(struct irc_server *, const char *, const char *); -bool +int irc_server_kick(struct irc_server *, const char *, const char *, const char *); -bool +int irc_server_part(struct irc_server *, const char *, const char *); -bool +int irc_server_topic(struct irc_server *, const char *, const char *); -bool +int irc_server_message(struct irc_server *, const char *, const char *); -bool +int irc_server_me(struct irc_server *, const char *, const char *); -bool +int irc_server_mode(struct irc_server *, const char *, const char *, @@ -145,16 +144,16 @@ const char *, const char *); -bool +int irc_server_names(struct irc_server *, const char *); -bool +int irc_server_nick(struct irc_server *, const char *); -bool +int irc_server_notice(struct irc_server *, const char *, const char *); -bool +int irc_server_whois(struct irc_server *, const char *); void