Index: libuirc/libuirc.c =================================================================== --- libuirc/libuirc.c (revision 20981) +++ libuirc/libuirc.c (revision 20982) @@ -1,21 +1,151 @@ #include "libuirc.h" #include +#include -P_net_socket uirc_connect(uirc_t *ctx, const char *server, int port, char *user) +#include + +int uirc_connect(uirc_t *ctx, const char *server, int port, char *user) { + if (P_tcp4_connect(&ctx->sk, server, port, NULL, 0, P_net_nonblock_full) != 0) + return -1; + ctx->connecting = 1; + ctx->alive = 1; + gds_init(&ctx->ibuf); + gds_init(&ctx->obuf); + gds_append_str(&ctx->obuf, "user libuirc a b :"); + gds_append_str(&ctx->obuf, user); + gds_append_str(&ctx->obuf, "\nnick "); + gds_append_str(&ctx->obuf, ctx->nick); + gds_append(&ctx->obuf, '\n'); + return 0; +} +void uirc_disconnect(uirc_t *ctx) +{ + P_net_close(ctx->sk); + ctx->alive = 0; } -P_net_socket uirc_disconnect(uirc_t *ctx) + +static uirc_event_t uic_parse_001(uirc_t *ctx, char *arg) { +/*:hu.irc.libgpmi.org 001 libuirc :Welcome to the Internet Relay Network libuirc!~libuirc@78-131-56-146.static.hdsnet.hu*/ + if (ctx->on_connect != NULL) + ctx->on_connect(ctx); + return UIRC_CONNECT; +} +static uirc_event_t uirc_parse(uirc_t *ctx, char *line) +{ + char *arg, *cmd, *from = line; + uirc_event_t res = 0; + +printf("line='%s'\n", line); + + if (strncmp(line, "PING", 4) == 0) { + from[1] = 'O'; + uirc_raw(ctx, line); + return 0; + } + + cmd = strpbrk(line, " \t\r\n"); + if (cmd == NULL) + return 0; + *cmd = '\0'; + cmd++; + + if (strchr(from, '@') == 0) { + if (ctx->on_got_misc != NULL) + ctx->on_got_misc(ctx, 0, cmd); + res |= UIRC_GOT_MISC; + } + + arg = strpbrk(cmd, " \t\r\n"); + if (arg != NULL) { + *arg = '\0'; + arg++; + } + + if (strcmp(cmd, "001") == 0) return res | uic_parse_001(ctx, arg); + + return res; } -void uirc_read(uirc_t *ctx, char *data, int len) +uirc_event_t uirc_poll(uirc_t *ctx) { + struct P_pollfd fds[1]; + int new_data = 0; + char *nl; + uirc_event_t res = 0; + fds[0].fd = ctx->sk; + + for(;;) { + fds[0].events = P_POLLIN; + if (ctx->obuf.used > 0) + fds[0].events |= P_POLLOUT; + + if (P_poll(fds, 1, 0) < 1) + break; + + if (fds[0].revents & P_POLLIN) { + P_size_t oused = ctx->ibuf.used; + gds_enlarge(&ctx->ibuf, ctx->ibuf.used + 600); + ctx->ibuf.used = oused; + P_size_t len = P_net_read(ctx->sk, ctx->ibuf.array + ctx->ibuf.used, 600); + if (len < 0) { + if (P_net_inprogress) + continue; + uirc_disconnect(ctx); + return res | UIRC_DISCONNECT; + } + if (len == 0) { + uirc_disconnect(ctx); + return res | UIRC_DISCONNECT; + } + if (len > 0) { + ctx->ibuf.used += len; + new_data = 1; + } + } + if ((fds[0].revents & P_POLLOUT) && (ctx->obuf.used > 0)) { + P_size_t len = P_net_write(ctx->sk, ctx->obuf.array, ctx->obuf.used); + ctx->connecting = 0; + if (len < 0) { + if (P_net_inprogress) + continue; + uirc_disconnect(ctx); + return res | UIRC_DISCONNECT; + } + if (len == 0) { + uirc_disconnect(ctx); + return res | UIRC_DISCONNECT; + } + if (len > 0) + gds_remove(&ctx->obuf, 0, len); + } + if (fds[0].revents & (~(P_POLLIN | P_POLLOUT))) { + uirc_disconnect(ctx); + return res | UIRC_DISCONNECT; + } + } + + /* call the protocol parse */ + if (!new_data) + return res; + + for(;;) { + nl = strchr(ctx->ibuf.array, '\n'); + if (nl == NULL) + break; + *nl = '\0'; + res |= uirc_parse(ctx, ctx->ibuf.array); + gds_remove(&ctx->ibuf, 0, nl - ctx->ibuf.array+1); + } + return res; } + void uirc_join(uirc_t *ctx, const char *chan) { @@ -33,7 +163,8 @@ void uirc_raw(uirc_t *ctx, const char *msg) { - + gds_append_str(&ctx->obuf, (char *)msg); + gds_append(&ctx->obuf, '\n'); } Index: libuirc/libuirc.h =================================================================== --- libuirc/libuirc.h (revision 20981) +++ libuirc/libuirc.h (revision 20982) @@ -14,11 +14,23 @@ uirc_query_type_t type; char *name; +#if 0 /* channel: */ gds_t *nicks; /* , separated list of nicknames for a channel; first char is one of @, + or space */ char *topic; +#endif } uirc_query_t; +typedef enum { /* bitfield */ + UIRC_CONNECT = 0x01, + UIRC_DISCONNECT = 0x02, + UIRC_GOT_MSG = 0x04, + UIRC_GOT_MISC = 0x08, + UIRC_GOT_QUERY_BEGIN = 0x10, + UIRC_GOT_QUERY_END = 0x20, + UIRC_GOT_ME_QUIT = 0x40, +} uirc_event_t; + typedef struct uirc_s uirc_t; struct uirc_s { char *nick; @@ -32,11 +44,19 @@ void (*on_query_begin)(uirc_t *ctx, int query_to); void (*on_query_end)(uirc_t *ctx, int query_to); /* called on leaving the channel for any reason */ void (*on_me_quit)(uirc_t *ctx); + + + /* internal */ + P_net_socket sk; + gds_t ibuf, obuf; + int dummy[2]; + unsigned connecting:1; + unsigned alive:1; }; -P_net_socket uirc_connect(uirc_t *ctx, const char *server, int port, char *user); -P_net_socket uirc_disconnect(uirc_t *ctx); -void uirc_read(uirc_t *ctx, char *data, int len); +int uirc_connect(uirc_t *ctx, const char *server, int port, char *user); +void uirc_disconnect(uirc_t *ctx); +uirc_event_t uirc_poll(uirc_t *ctx); void uirc_join(uirc_t *ctx, const char *chan); void uirc_close(uirc_t *ctx, int query);