terom@18: terom@18: #include "irc_conn.h" terom@18: terom@18: #include terom@18: #include terom@18: terom@20: /* terom@20: * PING [ ] terom@20: * terom@20: * Send a 'PONG ` reply right away. terom@20: */ terom@20: static void on_PING (struct irc_conn *conn, const struct irc_line *line) terom@20: { terom@20: // just reply terom@20: irc_conn_PONG(conn, line->args[0]); terom@20: } terom@20: terom@20: /* terom@20: * Our command handlers terom@20: */ terom@20: struct irc_cmd_handler { terom@20: /* The command name */ terom@20: const char *command; terom@20: terom@20: /* The handler function */ terom@20: void (*func) (struct irc_conn *conn, const struct irc_line *line); terom@20: terom@20: } _cmd_handlers[] = { terom@20: { "PING", on_PING }, terom@20: { NULL, NULL, }, terom@20: }; terom@20: terom@18: void irc_conn_on_line (char *line_buf, void *arg) terom@18: { terom@20: struct irc_conn *conn = arg; terom@18: struct irc_line line; terom@20: struct irc_cmd_handler *handler; terom@18: int err; terom@18: terom@18: // log terom@18: printf("<<< %s\n", line_buf); terom@18: terom@18: // parse terom@20: if ((err = irc_line_parse(&line, line_buf))) { terom@18: printf("!!! Invalid line: %s: %s\n", line_buf, error_name(err)); terom@20: terom@20: return; terom@20: } terom@18: terom@20: // look up appropriate handler terom@20: for (handler = _cmd_handlers; handler->command; handler++) { terom@20: // the command is alpha-only, so normal case-insensitive cmp is fine terom@20: if (strcasecmp(handler->command, line.command) == 0) { terom@20: // invoke the func terom@20: handler->func(conn, &line); terom@20: break; terom@20: } terom@20: } terom@18: } terom@18: terom@18: err_t irc_conn_create (struct irc_conn **conn_ptr, struct sock_stream *sock, const struct irc_conn_config *config, struct error_info *err) terom@18: { terom@18: struct irc_conn *conn; terom@18: terom@18: // alloc new state struct terom@18: if ((conn = calloc(1, sizeof(struct irc_conn))) == NULL) terom@18: return SET_ERROR(err, ERR_CALLOC); terom@18: terom@18: // create the line_proto, with our on_line handler terom@18: if (line_proto_create(&conn->lp, sock, IRC_LINE_MAX * 1.5, &irc_conn_on_line, conn, err)) terom@18: return ERROR_CODE(err); terom@18: terom@18: // send the initial messages terom@18: if ( terom@18: irc_conn_NICK(conn, config->nickname) terom@18: || irc_conn_USER(conn, config->username, config->realname) terom@18: ) terom@18: return ERROR_CODE(err); terom@18: terom@18: // ok terom@18: *conn_ptr = conn; terom@18: terom@18: return SUCCESS; terom@18: } terom@18: terom@18: err_t irc_conn_send (struct irc_conn *conn, const struct irc_line *line) terom@18: { terom@18: char line_buf[IRC_LINE_MAX + 2]; terom@18: err_t err; terom@18: terom@18: // format terom@18: if ((err = irc_line_build(line, line_buf))) terom@18: return err; terom@18: terom@18: // log terom@18: printf(">>> %s\n", line_buf); terom@18: terom@18: // add CRLF terom@18: strcat(line_buf, "\r\n"); terom@18: terom@18: // send using line_proto terom@19: // XXX: ignore output-buffering terom@20: return (err = line_proto_send(conn->lp, line_buf)) < 0 ? err : SUCCESS; terom@18: } terom@18: terom@18: err_t irc_conn_NICK (struct irc_conn *conn, const char *nickname) terom@18: { terom@18: // NICK terom@18: struct irc_line line = { terom@18: NULL, "NICK", { nickname, NULL } terom@18: }; terom@18: terom@18: return irc_conn_send(conn, &line); terom@18: } terom@18: terom@18: err_t irc_conn_USER (struct irc_conn *conn, const char *username, const char *realname) terom@18: { terom@18: // USER terom@18: struct irc_line line = { terom@20: NULL, "USER", { username, "0", "*", realname, NULL } terom@18: }; terom@18: terom@18: return irc_conn_send(conn, &line); terom@18: } terom@18: terom@20: err_t irc_conn_PONG (struct irc_conn *conn, const char *target) terom@20: { terom@20: // PONG [ ] terom@20: // XXX: params are actually the wrong way around now, but nobody cares terom@20: struct irc_line line = { terom@20: NULL, "PONG", { target, NULL } terom@20: }; terom@20: terom@20: return irc_conn_send(conn, &line); terom@20: } terom@20: