#include #include #include #include #include "event.h" #include "ircsession.h" #include "linebuffer.h" #include "logging.h" #include "sockaddr.h" #include "tcpsocket.h" struct irc_session * irc_create_session(void) { struct irc_session *session = malloc(sizeof(struct irc_session)); if (session == NULL) return NULL; session->state = IRC_NONE; session->inbuf = create_linebuffer(4096); session->outbuf = create_linebuffer(4096); return session; } void irc_destroy_session(struct irc_session *session) { linebuffer_free(session->outbuf); linebuffer_free(session->inbuf); free(session); } static int irc_write_cb(int fd, void *privdata) { struct irc_session *session = (struct irc_session *)privdata; linebuffer_writefd(session->outbuf, fd); /* remove write fd again */ event_add_writefd(session->handler, 0, NULL, NULL); return 0; } int irc_send(struct irc_session *session, const char *fmt, ...) { va_list az; va_start(az, fmt); linebuffer_vprintf(session->outbuf, fmt, az); va_end (az); linebuffer_put(session->outbuf, "\r\n", 2); /* schedule a write */ event_add_writefd(session->handler, 0, irc_write_cb, session); return 0; } static int irc_read_cb(int fd, void *privdata) { struct irc_session *session = (struct irc_session *)privdata; int len = linebuffer_readfd(session->inbuf, fd); if (len <= 0) { session->state = IRC_DISCONNECTED; log_print(LOG_DEBUG, "irc_read_cb(): disconnected from %s", get_sockaddr_buf(&session->srv_addr)); return -1; } char *line; while ((line = linebuffer_getline(session->inbuf, NULL)) != NULL) { log_print(LOG_DEBUG, "irc_read_cb(): from %s: %s", get_sockaddr_buf(&session->srv_addr), line); if (strncmp(line, "PING", 4) == 0) irc_send(session, "PONG %s", line +6); linebuffer_freeline(session->inbuf); } return 0; } static int irc_connect_cb(int fd, void *privdata) { struct irc_session *session = (struct irc_session *)privdata; if (tcp_connect_error(fd)) { session->state = IRC_CONNECTION_FAILED; log_print(LOG_DEBUG, "irc_connect_cb(): failed to connect to %s", get_sockaddr_buf(&session->srv_addr)); return -1; } session->state = IRC_CONNECTED; event_add_readfd(session->handler, 0, irc_read_cb, session); event_add_writefd(session->handler, 0, NULL, NULL); log_print(LOG_DEBUG, "irc_connect_cb(): connected to %s", get_sockaddr_buf(&session->srv_addr)); if (session->server_pass != NULL) irc_send(session, "PASS %s", session->server_pass); irc_send(session, "NICK %s", session->nickname); irc_send(session, "USER %s unknown unknown :%s", session->username ? session->username : "nobody", session->realname ? session->realname : "noname"); return 0; } int irc_connect(struct irc_session *session) { /* TODO: check state before connecting */ session->sock = tcp_connect_nonblock(&session->srv_addr); if (session->sock < 0) return -1; session->state = IRC_CONNECTING; session->handler = event_add_writefd(NULL, session->sock, irc_connect_cb, session); log_print(LOG_DEBUG, "irc_connect(): connecting to %s", get_sockaddr_buf(&session->srv_addr)); return 0; }