/* Miscellaneous MaskData-related functionality.
*
* IRC Services is copyright (c) 1996-2007 Andrew Church.
* E-mail: <achurch@achurch.org>
* Parts written by Andrew Kempe and others.
* This program is free but copyrighted software; see the file COPYING for
* details.
*/
#include "services.h"
#include "modules.h"
#include "language.h"
#include "commands.h"
#include "operserv.h"
#include "maskdata.h"
/*************************************************************************/
/**************** MaskData-related command helper routine ****************/
/*************************************************************************/
/* This routines is designed to be called from a command handler for a
* command that deals with MaskData records (AKILL, EXCEPTION, etc.), to
* help avoid code repetition in those command handlers. The `info'
* structure passed as the first parameter to each function contains
* information about the command, such as command name and message numbers;
* see maskdata.h for details.
*/
void do_maskdata_cmd(MaskDataCmdInfo *info, User *u)
{
const char *cmd;
char *mask, *reason, *expiry, *s;
time_t expires;
MaskData *md;
cmd = strtok(NULL, " ");
if (!cmd)
cmd = "";
expiry = NULL;
s = strtok_remaining();
if (stricmp(cmd,"ADD") == 0 && s && *s == '+') {
expiry = strtok(s+1, " ");
s = strtok_remaining();
}
if (s && *s == '"') {
mask = s+1;
s = strchr(mask, '"');
if (!s) {
notice_lang(s_OperServ, u, MISSING_QUOTE);
return;
}
strtok(s, " "); /* prime strtok() for later */
*s = 0; /* null-terminate quoted string */
} else {
mask = strtok(s, " "); /* this will still work if s is NULL: mask
* will end up NULL, which is what we want */
}
if (mask && info->mangle_mask)
info->mangle_mask(mask);
if (stricmp(cmd, "ADD") == 0) {
time_t now = time(NULL);
if (maskdata_count(info->md_type) >= MAX_MASKDATA) {
notice_lang(s_OperServ, u, info->msg_add_too_many, info->name);
return;
}
reason = strtok_remaining();
if (!reason) {
syntax_error(s_OperServ, u, info->name, info->msg_add_syntax);
return;
}
expires = expiry ? dotime(expiry) : *info->def_expiry_ptr;
if (expires < 0) {
notice_lang(s_OperServ, u, BAD_EXPIRY_TIME);
return;
} else {
if (expires > 0)
expires += now; /* Make it into an absolute time */
}
/* Run command-specific checks. */
if (info->check_add_mask
&& !info->check_add_mask(u, info->md_type, mask, &expires)
) {
return;
}
/* Make sure mask does not already exist on list. */
if (get_maskdata(info->md_type, mask)) {
notice_lang(s_OperServ, u, info->msg_add_exists, mask, info->name);
return;
}
md = scalloc(1, sizeof(*md));
md->mask = sstrdup(mask);
md->reason = sstrdup(reason);
md->time = time(NULL);
md->expires = expires;
strscpy(md->who, u->nick, NICKMAX);
md = add_maskdata(info->md_type, md);
if (info->do_add_mask)
info->do_add_mask(u, info->md_type, md);
notice_lang(s_OperServ, u, info->msg_added, mask, info->name);
if (readonly)
notice_lang(s_OperServ, u, READ_ONLY_MODE);
} else if (stricmp(cmd, "DEL") == 0) {
if (mask) {
md = get_maskdata(info->md_type, mask);
if (md) {
if (info->do_del_mask)
info->do_del_mask(u, info->md_type, md);
del_maskdata(info->md_type, md);
notice_lang(s_OperServ, u, info->msg_deleted, mask,
info->name);
if (readonly)
notice_lang(s_OperServ, u, READ_ONLY_MODE);
} else {
notice_lang(s_OperServ, u, info->msg_del_not_found, mask,
info->name);
}
} else {
syntax_error(s_OperServ, u, info->name, info->msg_del_syntax);
}
} else if (stricmp(cmd, "LIST") == 0 || stricmp(cmd, "VIEW") == 0) {
int is_view = stricmp(cmd,"VIEW")==0;
int count = 0;
if (!mask) {
mask = (char *)"*"; /* Not modified in this block */
expires = -1; /* Don't match on expiry time */
} else {
/* This is a little longwinded for what it acheives - but we can
* extend it later to allow for user defined expiry times. */
expiry = strtok(NULL, " ");
if (expiry && stricmp(expiry, "NOEXPIRE") == 0)
expires = 0; /* Entries that never expire */
else
expires = -1;
}
notice_lang(s_OperServ, u, info->msg_list_header, info->name);
for (md = first_maskdata(info->md_type); md;
md = next_maskdata(info->md_type)
) {
if (count < 50 &&
(!mask || (match_wild_nocase(mask, md->mask) &&
(expires == -1 || md->expires == expires)))
) {
count++;
if (is_view) {
char timebuf[BUFSIZE], usedbuf[BUFSIZE];
char expirebuf[BUFSIZE];
strftime_lang(timebuf, sizeof(timebuf), u->ngi,
STRFTIME_SHORT_DATE_FORMAT, md->time);
strftime_lang(usedbuf, sizeof(usedbuf), u->ngi,
STRFTIME_SHORT_DATE_FORMAT, md->lastused);
expires_in_lang(expirebuf, sizeof(expirebuf), u->ngi,
md->expires);
if (md->lastused) {
notice_lang(s_OperServ, u, info->msg_list_view_format,
md->mask, *md->who ? md->who : "<unknown>",
timebuf, usedbuf, expirebuf, md->reason);
} else {
notice_lang(s_OperServ, u, info->msg_list_view_unused,
md->mask, *md->who ? md->who : "<unknown>",
timebuf, expirebuf, md->reason);
}
} else { /* !is_view */
notice_lang(s_OperServ, u, info->msg_list_list_format,
md->mask, md->reason);
}
}
}
} else if (stricmp(cmd, "COUNT") == 0) {
notice_lang(s_OperServ, u, info->msg_count,
maskdata_count(info->md_type), info->name);
} else if (!info->do_unknown_cmd || !info->do_unknown_cmd(u, cmd, mask)) {
syntax_error(s_OperServ, u, info->name, info->msg_syntax);
}
}
/*************************************************************************/
/************************ Miscellaneous functions ************************/
/*************************************************************************/
/* Create and return the reason string for the given MaskData and format
* string. The string will be truncated at BUFSIZE-1 bytes. The string is
* returned in a static buffer, and will be overwritten by subsequent calls.
*/
char *make_reason(const char *format, const MaskData *data)
{
static char reason[BUFSIZE];
char *s;
int data_reason_len = -1;
s = reason;
while (*format && s-reason < sizeof(reason)-1) {
if (*format == '%' && format[1] == 's') {
int left = (sizeof(reason)-1) - (s-reason);
if (data_reason_len < 0)
data_reason_len = strlen(data->reason);
if (left > data_reason_len)
left = data_reason_len;
memcpy(s, data->reason, left);
s += left;
format += 2;
} else {
*s++ = *format++;
}
}
*s = 0;
return reason;
}
/*************************************************************************/
syntax highlighted by Code2HTML, v. 0.9.1