diff --git a/include/uirc.h b/include/uirc.h index 8250d00..60f49e8 100644 --- a/include/uirc.h +++ b/include/uirc.h @@ -19,26 +19,34 @@ #ifndef UIRC_INCLUDED #define UIRC_INCLUDED -struct irc_message { - struct tags { +typedef struct uirc_tag { + char* value; + bool clientbound; +} IRC_Tag; +typedef struct name { + char* nick; + char* user; + char* host; + char* realname; +} IRC_User; +typedef struct uirc_message { + struct uirc_tags { /* See https://ircv3.net/registry#tags for more information */ - char* account; - char* batch; - char* label; - char* msgid; - char* multiline_concat; /* NOTE: Still a draft */ - char* time; + IRC_Tag account; + IRC_Tag batch; + IRC_Tag label; + IRC_Tag msgid; + IRC_Tag multiline_concat; + IRC_Tag time; + IRC_Tag typing; + IRC_Tag react; + IRC_Tag reply; } tags; - struct source { - char* nick; - char* user; - char* host; - } source; + IRC_User name; signed short cmd; - char* args[14]; - unsigned int argc; + char* args[15]; /* 0-13 + NULL */ char* msg; -}; +} IRC_Message; enum { PASS = 10, @@ -209,7 +217,7 @@ enum { }; extern const char* uirc_ircmd[]; -int uirc_tokenize_message(struct irc_message* irc_msg, char* line); +int uirc_tokenize_message(IRC_Message* irc_msg, char* line); +int uirc_assm_mesg(char* buf, IRC_Message* mesg); unsigned int uirc_ircmd_stoi(char* str); -int uirc_assm_mesg(char* buf, int comm, char* dest, char* msg); #endif diff --git a/src/uirc.c b/src/uirc.c index b4d188b..662e50e 100644 --- a/src/uirc.c +++ b/src/uirc.c @@ -58,7 +58,9 @@ const char* uirc_ircmd[] = { [WALLOPS] = "WALLOPS", [USERHOST] = "USERHOST", [ISON] = "ISON"}; -int uirc_tokenize_message(struct irc_message* irc_msg, char* line) + +/* TODO: Parse client messages aswell */ +int uirc_tokenize_message(IRC_Message* irc_msg, char* line) { char *progr, *command; progr = line; @@ -67,21 +69,33 @@ int uirc_tokenize_message(struct irc_message* irc_msg, char* line) char* tags; if ((tags = strtok_r(progr + 1, " ", &progr)) != NULL) { char *ctag = tags, *cval; + bool clientbound; do { + clientbound = false; + if (*ctag == '+') { + ctag++; + clientbound = true; + } if ((cval = strchr(ctag, '=')) != NULL) { *(cval++) = '\0'; - if (!strcmp(ctag, "time")) { - irc_msg->tags.time = cval; - } else if (!strcmp(ctag, "account")) { - irc_msg->tags.account = cval; - } else if (!strcmp(ctag, "batch")) { - irc_msg->tags.batch = cval; - } else if (!strcmp(ctag, "label")) { - irc_msg->tags.label = cval; - } else if (!strcmp(ctag, "msgid")) { - irc_msg->tags.msgid = cval; - } else if (!strcmp(ctag, "multiline-concat")) { - irc_msg->tags.multiline_concat = cval; + struct tagmapping { + char* name; + IRC_Tag* assg; + } tags[] = { + {.name = "time", .assg = &irc_msg->tags.time}, + {.name = "account", .assg = &irc_msg->tags.account}, + {.name = "batch", .assg = &irc_msg->tags.batch}, + {.name = "label", .assg = &irc_msg->tags.label}, + {.name = "msgid", .assg = &irc_msg->tags.msgid}, + {.name = "multiline-concat", .assg = &irc_msg->tags.multiline_concat}, + {.name = "typing", .assg = &irc_msg->tags.typing}, + {.name = "react", .assg = &irc_msg->tags.react}, + {.name = "reply", .assg = &irc_msg->tags.reply}}; + for (unsigned int i = 0; i < sizeof(tags) / sizeof(struct tagmapping); i++) { + if (!strcmp(ctag, tags[i].name)) { + (*tags[i].assg).value = cval; + (*tags[i].assg).clientbound = clientbound; + } } if ((ctag = strchr(cval, ';')) != NULL) *(ctag++) = '\0'; @@ -93,12 +107,12 @@ int uirc_tokenize_message(struct irc_message* irc_msg, char* line) if (*progr == ':') { char* prefix; if ((prefix = strtok_r(progr + 1, " ", &progr)) != NULL) { - if ((irc_msg->source.host = strchr(prefix, '@')) != NULL) { - *(irc_msg->source.host++) = '\0'; - if ((irc_msg->source.user = strchr(prefix, '!')) != NULL) - *(irc_msg->source.user++) = '\0'; + if ((irc_msg->name.host = strchr(prefix, '@')) != NULL) { + *(irc_msg->name.host++) = '\0'; + if ((irc_msg->name.user = strchr(prefix, '!')) != NULL) + *(irc_msg->name.user++) = '\0'; } - irc_msg->source.nick = prefix; /* NOTE: This may be the server instead of a nick according to RFC2812, it is left to the library user to decide how to interpret this based on the context. */ + irc_msg->name.nick = prefix; /* NOTE: This may be the server instead of a nick according to RFC2812, it is left to the library user to decide how to interpret this based on the context. */ } else return 0; } @@ -119,7 +133,7 @@ int uirc_tokenize_message(struct irc_message* irc_msg, char* line) if ((irc_msg->args[i] = strtok_r(NULL, " ", &progr)) == NULL) return 0; } - irc_msg->argc = i; + irc_msg->args[i] = NULL; if (*progr == ':') ++progr; irc_msg->msg = progr; @@ -133,16 +147,38 @@ unsigned int uirc_ircmd_stoi(char* str) } return 0; } -int uirc_assm_mesg(char* buf, int comm, char* dest, char* msg) +int uirc_assm_mesg(char* buf, IRC_Message* mesg) { if (buf == NULL) return -2; - if (dest == NULL) { - if (sprintf(buf, "%s %s\r\n", uirc_ircmd[comm], msg) < 0) + char* pos = buf; + int cnt; + char* arg; + /* TODO: Finish this + if (mesg->tags.typing.value || mesg->tags.react.value || mesg->tags.reply.value) { + if (sprintf(pos++, "@") != 1) return -1; - } else { - if (sprintf(buf, "%s %s %s\r\n", uirc_ircmd[comm], dest, msg) < 0) + if (sprintf(pos++, " ") != 1) return -1; } - return 0; + */ + if ((uirc_ircmd[mesg->cmd] != NULL) && ((cnt = sprintf(pos, "%s", uirc_ircmd[mesg->cmd])) > 0)) + pos += cnt; + else + return -1; + for (unsigned int i = 0; i < 14 && mesg->args[i] != NULL; i++) { + if ((cnt = sprintf(pos, " %s", mesg->args[i])) > 0) + pos += cnt; + else + return -1; + } + if (mesg->cmd == PART || mesg->cmd == NOTICE) { + if ((cnt = sprintf(pos, " %s", mesg->msg)) > 0) + pos += cnt; + else + return -1; + } + if ((cnt = sprintf(pos, "\r\n")) != 2) + return -1; + return 1; }