/* Miscellaneous MaskData-related functionality. * * IRC Services is copyright (c) 1996-2007 Andrew Church. * E-mail: * 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 : "", timebuf, usedbuf, expirebuf, md->reason); } else { notice_lang(s_OperServ, u, info->msg_list_view_unused, md->mask, *md->who ? md->who : "", 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; } /*************************************************************************/