* 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 <stdint.h>
#include <string.h>
#include <ctype.h>
+#include <unistd.h>
+
+#include <sys/timerfd.h>
#include "util.h"
#include "conf.h"
server_t server;
int connect;
+ int timeout;
int noverify;
const char *host;
int port;
const char *auth;
const char *pass;
+ int timer;
+ poll_t poll;
+
irc_user_t myself;
irc_channel_t system;
net_t net;
}
/* Callback functions */
-static void irc_run(irc_server_t *srv, const char *line);
+static void irc_run(irc_server_t *srv, int idle, const char *line);
static void on_send(void *_srv)
{
irc_server_t *srv = _srv;
- irc_run(srv, "");
+ irc_run(srv, 0, "");
}
static void on_recv(void *_srv, char *buf, int len)
if (buf[i] == '\n' || buf[i] == '\r') {
srv->line[srv->pos-1] = '\0';
if (srv->pos > 1)
- irc_run(srv, srv->line);
+ irc_run(srv, 0, srv->line);
srv->pos = 0;
}
}
- irc_run(srv, "");
+ irc_run(srv, 0, "");
}
static void on_err(void *_srv, int err)
srv->state = IRC_DEAD;
}
+static void on_timer(void *_srv)
+{
+ uint64_t buf;
+ irc_server_t *srv = _srv;
+ while (read(srv->timer, &buf, sizeof(buf)) > 0)
+ irc_run(srv, 1, "");
+}
+
/* IRC State machine */
-static void irc_run(irc_server_t *srv, const char *line)
+static void irc_run(irc_server_t *srv, int idle, const char *line)
{
static irc_command_t _cmd;
const char *cmd = _cmd.cmd;
srv->net.err = on_err;
srv->net.data = srv;
+ srv->timer = timerfd_create(CLOCK_MONOTONIC,
+ TFD_NONBLOCK|TFD_CLOEXEC);
+ if (srv->timer < 0)
+ error("creating timer fd");
+ int sec = srv->timeout > 0 ? srv->timeout : 0;
+ int nsec = srv->timeout < 0 ? -srv->timeout : 0;
+ struct timespec tspec = {sec, nsec};
+ struct itimerspec itspec = {tspec, tspec};
+ timerfd_settime(srv->timer, 0, &itspec, NULL);
+ poll_add(&srv->poll, srv->timer, on_timer, srv);
+ poll_ctl(&srv->poll, 1, 0, 1);
+
srv_notice(srv, "Joining Server: %s", srv->server.name);
net_open(&srv->net, srv->host, srv->port);
srv->state = IRC_SEND_TLS;
}
+ /* Idle handling */
+ if (srv->state > IRC_CONNECT && idle) {
+ debug("irc: idle");
+ net_print(&srv->net, "PING %s\n", srv->host);
+ }
+
/* Start TLS */
if (srv->state == IRC_SEND_TLS) {
if (net_print(&srv->net, "CAP REQ :tls\n"))
continue;
irc_server_t *srv = (irc_server_t*)cur;
- srv->system.channel.server = &srv->server;
- srv->system.channel.name = srv->server.name;
-
- srv->myself.user.server = &srv->server;
- srv->myself.user.name = strcopy(srv->nick);
if (!srv->port)
srv->port = srv->tls ? 6697 : 6667;
srv->nick = strcopy(getenv("USER"));
if (!srv->nick)
srv->nick = strcopy("lameuser");
+ if (!srv->timeout)
+ srv->timeout = 60;
+
+ srv->system.channel.server = &srv->server;
+ srv->system.channel.name = srv->server.name;
+
+ srv->myself.user.server = &srv->server;
+ srv->myself.user.name = strcopy(srv->nick);
+
if (srv->connect) {
srv->state = IRC_CONNECT;
- irc_run(srv, "");
+ irc_run(srv, 0, "");
}
}
for (channel_t *cur = channels; cur; cur = cur->next) {
}
else if (match(key, "connect"))
srv->connect = get_bool(value);
+ else if (match(key, "timeout"))
+ srv->timeout = get_number(value);
else if (match(key, "noverify"))
srv->noverify = get_bool(value);
else if (match(key, "host"))