2020-07-22 16:57:59 +00:00
|
|
|
/*
|
|
|
|
* This file is part of uIRC. (https://git.redxen.eu/caskd/uIRC)
|
|
|
|
* Copyright (c) 2019, 2020 Alex-David Denes
|
|
|
|
*
|
|
|
|
* uIRC is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* any later version.
|
|
|
|
*
|
|
|
|
* uIRC is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with uIRC. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
#include "tokenizers.h"
|
|
|
|
|
|
|
|
signed int Tok_mesg(char* str, IRC_Message* out)
|
|
|
|
{
|
|
|
|
if (str == NULL || out == NULL)
|
|
|
|
return ERR_UIRC_NULL_ARGS;
|
|
|
|
int ret;
|
|
|
|
char *progr = str, *command;
|
|
|
|
#ifdef UIRC_IRCV3
|
|
|
|
if (*progr == '@') {
|
|
|
|
char* tags;
|
2020-09-01 11:18:07 +00:00
|
|
|
if ((tags = strtok_mr(&progr, " ")) != NULL) {
|
2020-07-22 16:57:59 +00:00
|
|
|
if ((ret = Tok_tags(tags, &out->tags)) < 0)
|
|
|
|
return ret;
|
|
|
|
} else
|
|
|
|
return ERR_UIRC_INVALID_FORMAT;
|
|
|
|
}
|
2020-08-18 19:20:45 +00:00
|
|
|
skip_spaces(&progr);
|
2020-07-22 16:57:59 +00:00
|
|
|
#endif
|
|
|
|
if (*progr == ':') {
|
|
|
|
char* prefix;
|
2020-09-01 11:18:07 +00:00
|
|
|
if ((prefix = strtok_mr(&progr, " ")) != NULL) {
|
2020-07-22 16:57:59 +00:00
|
|
|
if ((ret = Tok_user(prefix, &out->name, false)) < 0)
|
|
|
|
return ret;
|
|
|
|
} else
|
|
|
|
return ERR_UIRC_INVALID_FORMAT;
|
|
|
|
}
|
|
|
|
|
2020-08-18 19:20:45 +00:00
|
|
|
skip_spaces(&progr);
|
|
|
|
|
2020-09-01 11:18:07 +00:00
|
|
|
if ((command = strtok_mr(&progr, " ")) != NULL) {
|
2020-07-22 16:57:59 +00:00
|
|
|
if (!(out->cmd = (isalpha(*command)) ? Ircmd_stoi(command) : atoi(command)))
|
|
|
|
return ERR_UIRC_UNKNOWN_TOKEN;
|
|
|
|
} else {
|
|
|
|
return ERR_UIRC_INVALID_FORMAT;
|
|
|
|
}
|
|
|
|
|
2020-08-18 19:20:45 +00:00
|
|
|
skip_spaces(&progr);
|
|
|
|
|
2020-07-22 16:57:59 +00:00
|
|
|
int i;
|
2020-09-24 16:59:16 +00:00
|
|
|
for (i = 0; i < 15 && *progr;) {
|
2020-08-18 19:20:45 +00:00
|
|
|
if (i == 14 || *progr == ':') {
|
|
|
|
out->args[i++] = (*progr == ':') ? progr + 1 : progr;
|
|
|
|
out->trailing = true;
|
2020-09-24 16:59:16 +00:00
|
|
|
break;
|
2020-08-18 19:20:45 +00:00
|
|
|
} else {
|
2020-09-24 16:59:16 +00:00
|
|
|
if ((out->args[i++] = strtok_mr(&progr, " ")) == NULL)
|
2020-08-18 19:20:45 +00:00
|
|
|
return ERR_UIRC_INVALID_FORMAT;
|
2020-09-24 16:59:16 +00:00
|
|
|
skip_spaces(&progr);
|
2020-08-18 19:20:45 +00:00
|
|
|
}
|
2020-07-31 23:38:06 +00:00
|
|
|
}
|
2020-07-22 16:57:59 +00:00
|
|
|
out->args[i] = NULL;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef UIRC_IRCV3
|
|
|
|
signed int Tok_tags(char* str, IRC_Tags* out)
|
|
|
|
{
|
|
|
|
if (str == NULL || out == NULL)
|
|
|
|
return ERR_UIRC_NULL_ARGS;
|
|
|
|
char *cval, *cpos = str, *ctag = NULL;
|
|
|
|
bool clientbound;
|
|
|
|
const struct tagmapping tagmps[] = {
|
|
|
|
{.name = "time", .assg = &out->time},
|
|
|
|
{.name = "account", .assg = &out->account},
|
|
|
|
{.name = "batch", .assg = &out->batch},
|
|
|
|
{.name = "label", .assg = &out->label},
|
|
|
|
{.name = "msgid", .assg = &out->msgid},
|
|
|
|
{.name = "multiline-concat", .assg = &out->multiline_concat},
|
|
|
|
{.name = "typing", .assg = &out->typing},
|
|
|
|
{.name = "react", .assg = &out->react},
|
|
|
|
{.name = "reply", .assg = &out->reply}};
|
|
|
|
if (*cpos == '@')
|
|
|
|
cpos++;
|
2020-09-01 11:18:07 +00:00
|
|
|
while ((ctag = strtok_mr(&cpos, "; ")) != NULL) {
|
2020-07-22 16:57:59 +00:00
|
|
|
clientbound = false;
|
|
|
|
if (*ctag == '+') {
|
|
|
|
ctag++;
|
|
|
|
clientbound = true;
|
|
|
|
}
|
|
|
|
if ((cval = strchr(ctag, '=')) != NULL)
|
|
|
|
*(cval++) = '\0';
|
|
|
|
for (unsigned int i = 0; i < sizeof(tagmps) / sizeof(struct tagmapping); i++) {
|
|
|
|
if (!strcmp(ctag, tagmps[i].name)) {
|
|
|
|
/* If the tag is present we point it to the value if given, or to the delimiter ('\0')
|
|
|
|
* This is done for a few reasons. First, we have a non-null address so we show that
|
|
|
|
* the tag is present and second, we have no value that way
|
|
|
|
*/
|
|
|
|
(*tagmps[i].assg).value = (cval != NULL) ? cval : ctag + strlen(ctag);
|
|
|
|
(*tagmps[i].assg).clientbound = clientbound;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
signed int Tok_user(char* str, IRC_User* out, bool useorig)
|
|
|
|
{
|
|
|
|
char* pos = (*str == ':') ? str + 1 : str;
|
|
|
|
if ((out->host = strchr(pos, '@')) != NULL)
|
|
|
|
*(out->host++) = '\0';
|
|
|
|
if (useorig && (out->orig = strchr(pos, '%')) != NULL)
|
|
|
|
*(out->orig++) = '\0';
|
|
|
|
if ((out->user = strchr(pos, '!')) != NULL) /* RFC2812 says this cannot be here without the host but RFC1459 says it can, we accept both options */
|
|
|
|
*((char*)out->user++) = '\0';
|
2020-08-02 16:38:23 +00:00
|
|
|
if (!*(out->nick = pos))
|
2020-07-22 16:57:59 +00:00
|
|
|
return ERR_UIRC_INVALID_FORMAT;
|
2020-08-02 16:38:23 +00:00
|
|
|
/* NOTE: De-facto standard below
|
|
|
|
* This assumes that every prefix without a '@host' and '!user' is itself a host prefix only
|
|
|
|
* It might be a actual nickname, but this is the most common around every network
|
|
|
|
* It is left to the user to decide and handle the result accordingly
|
|
|
|
*/
|
2020-08-02 19:28:56 +00:00
|
|
|
if (out->host == NULL && out->user == NULL) {
|
2020-08-02 16:38:23 +00:00
|
|
|
out->host = out->nick;
|
|
|
|
out->nick = NULL;
|
|
|
|
}
|
2020-07-22 16:57:59 +00:00
|
|
|
return 1;
|
|
|
|
}
|