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/>.
|
2020-10-10 10:30:05 +00:00
|
|
|
*/
|
2021-01-02 22:20:06 +00:00
|
|
|
|
2020-07-22 16:57:59 +00:00
|
|
|
#include "assemblers.h"
|
|
|
|
|
2021-01-02 22:20:06 +00:00
|
|
|
#include "commands.h"
|
|
|
|
#include "errors.h"
|
|
|
|
#include "memory.h"
|
|
|
|
#include "modes.h"
|
|
|
|
#include "tags.h"
|
|
|
|
#include "types.h"
|
|
|
|
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
|
|
|
signed long
|
|
|
|
Assm_user(char* buf, IRC_User* in, size_t len, bool useorig)
|
|
|
|
{
|
|
|
|
if (buf == NULL || in == NULL) return ERR_UIRC_NULL_ARGS;
|
|
|
|
char* pos = buf;
|
|
|
|
if (in->nick == NULL && in->host != NULL) {
|
|
|
|
if (!safe_strcpy(&pos, in->host, len - (unsigned long) (pos - buf))) return ERR_UIRC_BUFFER_ERR;
|
|
|
|
} else if (in->nick != NULL) {
|
|
|
|
if (!safe_strcpy(&pos, in->nick, len - (unsigned long) (pos - buf))) return ERR_UIRC_BUFFER_ERR;
|
|
|
|
if (in->user != NULL) {
|
|
|
|
if (!safe_charcpy(&pos, '!', len - (unsigned long) (pos - buf))) return ERR_UIRC_BUFFER_ERR;
|
|
|
|
if (!safe_strcpy(&pos, in->user, len - (unsigned long) (pos - buf))) return ERR_UIRC_BUFFER_ERR;
|
|
|
|
}
|
|
|
|
if (useorig && in->orig != NULL) {
|
|
|
|
if (!safe_charcpy(&pos, '%', len - (unsigned long) (pos - buf))) return ERR_UIRC_BUFFER_ERR;
|
|
|
|
if (!safe_strcpy(&pos, in->orig, len - (unsigned long) (pos - buf))) return ERR_UIRC_BUFFER_ERR;
|
|
|
|
}
|
|
|
|
if (in->host != NULL) {
|
|
|
|
if (!safe_charcpy(&pos, '@', len - (unsigned long) (pos - buf))) return ERR_UIRC_BUFFER_ERR;
|
|
|
|
if (!safe_strcpy(&pos, in->host, len - (unsigned long) (pos - buf))) return ERR_UIRC_BUFFER_ERR;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
return ERR_UIRC_NULL_ARGS;
|
|
|
|
return pos - buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef UIRC_IRCV3
|
|
|
|
signed long
|
|
|
|
Assm_tags(char* buf, IRC_Tags* in, size_t len)
|
|
|
|
{
|
|
|
|
if (buf == NULL || in == NULL) return ERR_UIRC_NULL_ARGS;
|
|
|
|
char* pos = buf;
|
|
|
|
struct tagmapping tagmps[] = { { .name = "time", .assg = &in->time }, { .name = "account", .assg = &in->account },
|
|
|
|
{ .name = "batch", .assg = &in->batch }, { .name = "label", .assg = &in->label },
|
|
|
|
{ .name = "msgid", .assg = &in->msgid }, { .name = "multiline-concat", .assg = &in->multiline_concat },
|
|
|
|
{ .name = "typing", .assg = &in->typing }, { .name = "react", .assg = &in->react },
|
|
|
|
{ .name = "reply", .assg = &in->reply } };
|
|
|
|
for (unsigned int i = 0; i < sizeof(tagmps) / sizeof(struct tagmapping); i++) {
|
|
|
|
if ((*tagmps[i].assg).value != NULL) {
|
|
|
|
if (pos == buf) {
|
|
|
|
if (!safe_charcpy(&pos, '@', len - (unsigned long) (pos - buf))) return ERR_UIRC_BUFFER_ERR;
|
|
|
|
} else {
|
|
|
|
if (!safe_charcpy(&pos, ';', len - (unsigned long) (pos - buf))) return ERR_UIRC_BUFFER_ERR;
|
|
|
|
}
|
|
|
|
if ((*tagmps[i].assg).clientbound) {
|
|
|
|
if (!safe_charcpy(&pos, '+', len - (unsigned long) (pos - buf))) return ERR_UIRC_BUFFER_ERR;
|
|
|
|
}
|
|
|
|
if (!safe_strcpy(&pos, tagmps[i].name, len - (unsigned long) (pos - buf))) return ERR_UIRC_BUFFER_ERR;
|
|
|
|
if (*(*tagmps[i].assg).value != '\0') {
|
|
|
|
if (!safe_charcpy(&pos, '=', len - (unsigned long) (pos - buf))) return ERR_UIRC_BUFFER_ERR;
|
|
|
|
if (!safe_strcpy(&pos, (*tagmps[i].assg).value, len - (unsigned long) (pos - buf))) return ERR_UIRC_BUFFER_ERR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return pos - buf;
|
|
|
|
}
|
|
|
|
#endif /* UIRC_IRCV3 */
|
|
|
|
|
2020-12-16 14:22:25 +00:00
|
|
|
signed long
|
|
|
|
Assm_mesg(char* buf, IRC_Message* in, size_t len)
|
2020-07-22 16:57:59 +00:00
|
|
|
{
|
2020-10-10 10:30:05 +00:00
|
|
|
if (buf == NULL || in == NULL) return ERR_UIRC_BUFFER_ERR;
|
2020-12-16 14:22:25 +00:00
|
|
|
char* pos = buf;
|
2020-09-26 21:22:05 +00:00
|
|
|
signed long cnt, ret;
|
2020-07-22 16:57:59 +00:00
|
|
|
#ifdef UIRC_IRCV3
|
2020-12-16 14:22:25 +00:00
|
|
|
if ((ret = Assm_tags(pos, &in->tags, len - (unsigned long) (pos - buf))) < 0) return ret;
|
2020-08-17 17:16:55 +00:00
|
|
|
else if (ret != 0) {
|
2020-07-22 16:57:59 +00:00
|
|
|
pos += ret;
|
2020-12-16 14:22:25 +00:00
|
|
|
if (!safe_charcpy(&pos, ' ', len - (unsigned long) (pos - buf))) return ERR_UIRC_BUFFER_ERR;
|
2020-08-14 09:41:08 +00:00
|
|
|
}
|
2020-12-16 14:22:25 +00:00
|
|
|
#endif /* UIRC_IRCV3 */
|
2020-07-22 16:57:59 +00:00
|
|
|
if (in->name.nick != NULL || in->name.host != NULL) {
|
2020-12-16 14:22:25 +00:00
|
|
|
if (!safe_charcpy(&pos, ':', len - (unsigned long) (pos - buf))) return ERR_UIRC_BUFFER_ERR;
|
|
|
|
if ((ret = Assm_user(pos, &in->name, len - (unsigned long) (pos - buf), false)) <= 0) return ret;
|
2020-07-22 16:57:59 +00:00
|
|
|
else
|
|
|
|
pos += ret;
|
2020-12-16 14:22:25 +00:00
|
|
|
if (!safe_charcpy(&pos, ' ', len - (unsigned long) (pos - buf))) return ERR_UIRC_BUFFER_ERR;
|
2020-07-22 16:57:59 +00:00
|
|
|
}
|
2020-08-17 17:16:55 +00:00
|
|
|
if (in->cmd < UIRC_FCMD || in->cmd > UIRC_LCMD) {
|
2020-12-16 14:22:25 +00:00
|
|
|
if ((cnt = snprintf(pos, 4, "%.3i", in->cmd)) == 3) pos += cnt;
|
2020-08-17 17:16:55 +00:00
|
|
|
else
|
|
|
|
return ERR_UIRC_UNKNOWN_TOKEN;
|
|
|
|
} else {
|
2020-09-26 21:22:05 +00:00
|
|
|
if (IRC_Cmds[in->cmd] != NULL) {
|
|
|
|
size_t cmdlen = strlen(IRC_Cmds[in->cmd]);
|
2020-12-16 14:22:25 +00:00
|
|
|
if (len - (unsigned long) (pos - buf) > cmdlen && strcpy(pos, IRC_Cmds[in->cmd]) != NULL) pos += cmdlen;
|
2020-09-26 21:22:05 +00:00
|
|
|
else
|
|
|
|
return ERR_UIRC_UNKNOWN_TOKEN;
|
|
|
|
}
|
2020-08-17 17:16:55 +00:00
|
|
|
}
|
2020-09-26 21:22:05 +00:00
|
|
|
for (unsigned int i = 0; in->args[i] != NULL; i++) {
|
2020-12-16 14:22:25 +00:00
|
|
|
if (len - (unsigned long) (pos - buf) > strlen(in->args[i]) + 2
|
2020-10-10 10:30:05 +00:00
|
|
|
&& (cnt =
|
2020-12-16 14:22:25 +00:00
|
|
|
snprintf(pos, len - (unsigned long) (pos - buf), (in->args[i + 1] == NULL && in->trailing) ? " :%s" : " %s", in->args[i]))
|
2020-10-10 10:30:05 +00:00
|
|
|
> 0)
|
2020-07-22 16:57:59 +00:00
|
|
|
pos += cnt;
|
|
|
|
else
|
|
|
|
return ERR_UIRC_BUFFER_ERR;
|
|
|
|
}
|
2020-12-16 14:22:25 +00:00
|
|
|
if (!safe_strcpy(&pos, "\r\n", len - (unsigned long) (pos - buf))) return ERR_UIRC_BUFFER_ERR;
|
2020-07-22 16:57:59 +00:00
|
|
|
return pos - buf;
|
|
|
|
}
|
|
|
|
|
2021-01-02 22:20:06 +00:00
|
|
|
#ifdef UIRC_HELPERS
|
|
|
|
|
|
|
|
static IRC_Message imassm_mesg;
|
|
|
|
#define RESERVED "*";
|
|
|
|
|
|
|
|
void
|
|
|
|
clear_assm(void)
|
2020-07-22 16:57:59 +00:00
|
|
|
{
|
2021-01-02 22:20:06 +00:00
|
|
|
memset((void*) &imassm_mesg, '\0', sizeof(IRC_Message));
|
2020-07-22 16:57:59 +00:00
|
|
|
}
|
|
|
|
|
2021-01-02 22:20:06 +00:00
|
|
|
IRC_Message*
|
|
|
|
Assm_AUTO(IRC_Command cmd, bool trailing, char** args, int req)
|
2020-07-22 16:57:59 +00:00
|
|
|
{
|
2021-01-02 22:20:06 +00:00
|
|
|
clear_assm();
|
|
|
|
int i;
|
|
|
|
for (i = 0; args[i] != NULL && i < 15; i++) { imassm_mesg.args[i] = args[i]; }
|
|
|
|
if (i < req) return NULL;
|
|
|
|
imassm_mesg.trailing = trailing;
|
|
|
|
imassm_mesg.cmd = cmd;
|
|
|
|
return &imassm_mesg;
|
|
|
|
}
|
|
|
|
|
|
|
|
IRC_Message*
|
|
|
|
Assm_cmd_USER(char* user, char* realname, int modes)
|
|
|
|
{
|
|
|
|
if (user == NULL || modes < 0 || modes > (MBMASK_INVIS | MBMASK_WALLOPS)) return NULL;
|
|
|
|
clear_assm();
|
|
|
|
static char local_mode[2];
|
|
|
|
snprintf(local_mode, 2, "%i", modes);
|
|
|
|
imassm_mesg.args[0] = user;
|
|
|
|
imassm_mesg.args[1] = local_mode;
|
|
|
|
imassm_mesg.args[2] = RESERVED;
|
|
|
|
imassm_mesg.args[3] = realname;
|
|
|
|
imassm_mesg.trailing = true;
|
|
|
|
imassm_mesg.cmd = USER;
|
|
|
|
return &imassm_mesg;
|
|
|
|
}
|
|
|
|
|
|
|
|
IRC_Message*
|
|
|
|
Assm_cmd_LINKS(char* remoteserv, char* servmask)
|
|
|
|
{
|
|
|
|
if (remoteserv != NULL && servmask == NULL) return NULL;
|
|
|
|
clear_assm();
|
|
|
|
imassm_mesg.args[0] = (remoteserv == NULL) ? servmask : remoteserv;
|
|
|
|
imassm_mesg.args[1] = (remoteserv == NULL) ? NULL : servmask;
|
|
|
|
imassm_mesg.cmd = LINKS;
|
|
|
|
return &imassm_mesg;
|
|
|
|
}
|
|
|
|
|
|
|
|
IRC_Message*
|
|
|
|
Assm_cmd_WHO(char* mask, bool oper)
|
|
|
|
{
|
|
|
|
static char* operator= "o";
|
|
|
|
if (oper && mask == NULL) return NULL;
|
|
|
|
clear_assm();
|
|
|
|
imassm_mesg.args[0] = mask;
|
|
|
|
imassm_mesg.args[1] = (oper) ? operator: NULL;
|
|
|
|
imassm_mesg.cmd = WHO;
|
|
|
|
return &imassm_mesg;
|
|
|
|
}
|
|
|
|
|
|
|
|
IRC_Message*
|
|
|
|
Assm_cmd_WHOIS(char* target, char* mask)
|
|
|
|
{
|
|
|
|
if (mask == NULL) return NULL;
|
|
|
|
clear_assm();
|
|
|
|
imassm_mesg.args[0] = (target == NULL) ? mask : target;
|
|
|
|
imassm_mesg.args[1] = (target == NULL) ? NULL : mask;
|
|
|
|
imassm_mesg.cmd = WHOIS;
|
|
|
|
return &imassm_mesg;
|
|
|
|
}
|
|
|
|
|
|
|
|
IRC_Message*
|
|
|
|
Assm_cmd_WHOWAS(char* nick, char* count, char* target)
|
|
|
|
{
|
|
|
|
if (nick == NULL || (target != NULL && count == NULL)) return NULL;
|
|
|
|
clear_assm();
|
|
|
|
imassm_mesg.args[0] = nick;
|
|
|
|
imassm_mesg.args[1] = count;
|
|
|
|
imassm_mesg.args[2] = target;
|
|
|
|
imassm_mesg.cmd = WHOWAS;
|
|
|
|
return &imassm_mesg;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* NOTE: This is what implementation you have to live with
|
|
|
|
* I would've just used the prefix to set the source but whatever
|
|
|
|
*/
|
|
|
|
IRC_Message*
|
|
|
|
Assm_cmd_PING(char* source, char* target)
|
|
|
|
{
|
|
|
|
if (source == NULL && target == NULL) return NULL;
|
|
|
|
clear_assm();
|
|
|
|
imassm_mesg.args[0] = (source != NULL) ? source : target;
|
|
|
|
imassm_mesg.args[1] = (source != NULL && target != NULL) ? target : NULL;
|
|
|
|
imassm_mesg.trailing = (source != NULL && target == NULL) ? true : false;
|
|
|
|
imassm_mesg.cmd = PING;
|
|
|
|
return &imassm_mesg;
|
|
|
|
}
|
|
|
|
|
|
|
|
IRC_Message*
|
|
|
|
Assm_cmd_SUMMON(char* user, char* target, char* channel)
|
|
|
|
{
|
|
|
|
if (user == NULL || (channel != NULL && target == NULL)) return NULL;
|
|
|
|
clear_assm();
|
|
|
|
imassm_mesg.args[0] = user;
|
|
|
|
imassm_mesg.args[1] = target;
|
|
|
|
imassm_mesg.args[2] = channel;
|
|
|
|
imassm_mesg.cmd = SUMMON;
|
|
|
|
return &imassm_mesg;
|
|
|
|
}
|
|
|
|
|
|
|
|
IRC_Message*
|
|
|
|
Assm_cmd_USERHOST(char* users[])
|
|
|
|
{
|
|
|
|
if (users[0] == NULL) return NULL;
|
|
|
|
clear_assm();
|
|
|
|
for (unsigned int i = 0; i < 5 && users[i] != NULL; i++) imassm_mesg.args[i] = users[i];
|
|
|
|
imassm_mesg.cmd = USERHOST;
|
|
|
|
return &imassm_mesg;
|
|
|
|
}
|
|
|
|
/* NOTE: Limited to 14 nicks per command */
|
|
|
|
|
|
|
|
IRC_Message*
|
|
|
|
Assm_cmd_ISON(char* users[])
|
|
|
|
{
|
|
|
|
if (users[0] == NULL) return NULL;
|
|
|
|
clear_assm();
|
|
|
|
for (unsigned int i = 0; i < 14 && users[i] != NULL; i++) { imassm_mesg.args[i] = users[i]; }
|
|
|
|
imassm_mesg.cmd = ISON;
|
|
|
|
return &imassm_mesg;
|
2020-07-22 16:57:59 +00:00
|
|
|
}
|
2020-09-26 21:22:05 +00:00
|
|
|
|
2021-01-02 22:20:06 +00:00
|
|
|
#endif /* UIRC_HELPERS */
|