/*
* lastlog.c: handles the lastlog features of irc.
*
* Written By Michael Sandrof
*
* Copyright (c) 1990 Michael Sandrof.
* Copyright (c) 1991, 1992 Troy Rollo.
* Copyright (c) 1992-2005 Matthew R. Green.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "irc.h"
IRCII_RCSID("@(#)$eterna: lastlog.c,v 1.38 2005/04/03 02:35:08 mrg Exp $");
#include "lastlog.h"
#include "window.h"
#include "screen.h"
#include "vars.h"
#include "ircaux.h"
#include "output.h"
static void remove_from_lastlog(Window *);
/*
* lastlog_level: current bitmap setting of which things should be stored in
* the lastlog. The LOG_MSG, LOG_NOTICE, etc., defines tell more about this
*/
static int lastlog_level;
static int notify_level;
/*
* msg_level: the mask for the current message level. What? Did he really
* say that? This is set in the set_lastlog_msg_level() routine as it
* compared to the lastlog_level variable to see if what ever is being added
* should actually be added
*/
static int msg_level = LOG_CRAP;
static char *levels[] =
{
"CRAP", "PUBLIC", "MSGS", "NOTICES",
"WALLS", "WALLOPS", "NOTES", "OPNOTES",
"SNOTES", "ACTIONS", "DCC", "CTCP",
"USERLOG1", "USERLOG2", "USERLOG3", "USERLOG4",
"BEEP", "HELP"
};
#define NUMBER_OF_LEVELS (sizeof(levels) / sizeof(u_char *))
/*
* bits_to_lastlog_level: converts the bitmap of lastlog levels into a nice
* string format.
*/
u_char *
bits_to_lastlog_level(level)
int level;
{
static u_char lbuf[128]; /* this *should* be enough for this */
int i,
p;
int first = 1;
if (level == LOG_ALL)
my_strcpy(lbuf, "ALL");
else if (level == 0)
my_strcpy(lbuf, "NONE");
else
{
*lbuf = '\0';
for (i = 0, p = 1; i < NUMBER_OF_LEVELS; i++, p <<= 1)
{
if (level & p)
{
if (first)
first = 0;
else
my_strmcat(lbuf, " ", 127);
my_strmcat(lbuf, levels[i], 127);
}
}
}
return (lbuf);
}
int
parse_lastlog_level(str)
u_char *str;
{
u_char *ptr,
*rest,
*s;
int i,
p,
level,
neg;
size_t len;
level = 0;
while ((str = next_arg(str, &rest)) != NULL)
{
while (str)
{
if ((ptr = my_index(str, ',')) != NULL)
*ptr++ = '\0';
if ((len = my_strlen(str)) != 0)
{
u_char *cmd = NULL;
malloc_strcpy(&cmd, str);
upper(cmd);
if (my_strncmp(cmd, "ALL", len) == 0)
level = LOG_ALL;
else if (my_strncmp(cmd, "NONE", len) == 0)
level = 0;
else
{
if (*str == '-')
{
str++;
s = cmd + 1;
neg = 1;
}
else {
neg = 0;
s = cmd;
}
for (i = 0, p = 1; i < NUMBER_OF_LEVELS; i++, p <<= 1)
{
if (!my_strncmp(s, levels[i], len))
{
if (neg)
level &= (LOG_ALL ^ p);
else
level |= p;
break;
}
}
if (i == NUMBER_OF_LEVELS)
say("Unknown lastlog level: %s",
str);
}
new_free(&cmd);
}
str = ptr;
}
str = rest;
}
return (level);
}
/*
* set_lastlog_level: called whenever a "SET LASTLOG_LEVEL" is done. It
* parses the settings and sets the lastlog_level variable appropriately. It
* also rewrites the LASTLOG_LEVEL variable to make it look nice
*/
void
set_lastlog_level(str)
u_char *str;
{
lastlog_level = parse_lastlog_level(str);
set_string_var(LASTLOG_LEVEL_VAR, bits_to_lastlog_level(lastlog_level));
curr_scr_win->lastlog_level = lastlog_level;
}
static void
remove_from_lastlog(window)
Window *window;
{
Lastlog *tmp;
if (window->lastlog_tail)
{
tmp = window->lastlog_tail->prev;
new_free(&window->lastlog_tail->msg);
new_free(&window->lastlog_tail);
window->lastlog_tail = tmp;
if (tmp)
tmp->next = (Lastlog *) 0;
else
window->lastlog_head = (Lastlog *) 0;
window->lastlog_size--;
}
else
window->lastlog_size = 0;
}
/*
* set_lastlog_size: sets up a lastlog buffer of size given. If the lastlog
* has gotten larger than it was before, all previous lastlog entry remain.
* If it get smaller, some are deleted from the end.
*/
void
set_lastlog_size(size)
int size;
{
int i,
diff;
if (curr_scr_win->lastlog_size > size)
{
diff = curr_scr_win->lastlog_size - size;
for (i = 0; i < diff; i++)
remove_from_lastlog(curr_scr_win);
}
}
/*
* lastlog: the /LASTLOG command. Displays the lastlog to the screen. If
* args contains a valid integer, only that many lastlog entries are shown
* (if the value is less than lastlog_size), otherwise the entire lastlog is
* displayed
*
* /lastlog -save filename
* by StElb <stlb@cs.tu-berlin.de>
*/
/*ARGSUSED*/
void
lastlog(command, args, subargs)
u_char *command,
*args,
*subargs;
{
int cnt,
from = 0,
p,
i,
level = 0,
m_level,
mask = 0,
header = 1;
Lastlog *start_pos;
u_char *match = NULL,
*save = NULL,
*expanded = NULL,
*arg;
FILE *fp = NULL;
u_char *cmd = (u_char *) 0;
size_t len;
save_message_from();
message_from((u_char *) 0, LOG_CURRENT);
cnt = curr_scr_win->lastlog_size;
while ((arg = next_arg(args, &args)) != NULL)
{
if (*arg == '-')
{
arg++;
if (!(len = my_strlen(arg)))
{
header = 0;
continue;
}
malloc_strcpy(&cmd, arg);
upper(cmd);
if (!my_strncmp(cmd, "LITERAL", len))
{
if (match)
{
say("Second -LITERAL argument ignored");
(void) next_arg(args, &args);
continue;
}
if ((match = next_arg(args, &args)) != NULL)
continue;
say("Need pattern for -LITERAL");
goto out;
}
else if (!my_strncmp(cmd, "BEEP", len))
{
if (match)
{
say("-BEEP is exclusive; ignored");
continue;
}
else
match = UP("\007");
}
else if (!my_strncmp(cmd, "SAVE", len))
{
#ifdef DAEMON_UID
if (getuid() == DAEMON_UID)
{
say("You are not permitted to use -SAVE flag");
goto out;
}
#endif /* DAEMON_UID */
if (save)
{
say("Second -SAVE argument ignored");
(void) next_arg(args, &args);
continue;
}
if ((save = next_arg(args, &args)) != NULL)
{
if (!(expanded = expand_twiddle(save)))
{
say("Unknown user");
goto out;
}
if ((fp = fopen(CP(expanded), "w")) != NULL)
continue;
say("Error opening %s: %s", save, strerror(errno));
goto out;
}
say("Need filename for -SAVE");
goto out;
}
else
{
for (i = 0, p = 1; i < NUMBER_OF_LEVELS; i++, p <<= 1)
{
if (my_strncmp(cmd, levels[i], len) == 0)
{
mask |= p;
break;
}
}
if (i == NUMBER_OF_LEVELS)
{
say("Unknown flag: %s", arg);
message_from((u_char *) 0, LOG_CRAP);
goto out;
}
}
continue;
out:
new_free(&cmd);
restore_message_from();
return;
}
else
{
if (level == 0)
{
if (match || isdigit(*arg))
{
cnt = my_atoi(arg);
level++;
}
else
match = arg;
}
else if (level == 1)
{
from = my_atoi(arg);
level++;
}
}
}
if (cmd)
new_free(&cmd);
start_pos = curr_scr_win->lastlog_head;
for (i = 0; (i < from) && start_pos; start_pos = start_pos->next)
if (!mask || (mask & start_pos->level))
i++;
for (i = 0; (i < cnt) && start_pos; start_pos = start_pos->next)
if (!mask || (mask & start_pos->level))
i++;
level = curr_scr_win->lastlog_level;
m_level = set_lastlog_msg_level(0);
if (start_pos == (Lastlog *) 0)
start_pos = curr_scr_win->lastlog_tail;
else
start_pos = start_pos->prev;
/* Let's not get confused here, display a seperator.. -lynx */
if (header && !save)
say("Lastlog:");
for (i = 0; (i < cnt) && start_pos; start_pos = start_pos->prev)
{
if (!mask || (mask & start_pos->level))
{
i++;
if (match)
{
if (scanstr(start_pos->msg, match)) {
if (save)
fprintf(fp, "%s\n", start_pos->msg);
else
put_it("%s", start_pos->msg);
}
}
else
if (save)
fprintf(fp, "%s\n", start_pos->msg);
else
put_it("%s", start_pos->msg);
}
}
if (save)
{
say("Saved Lastlog to %s", expanded);
fclose(fp);
}
else if (header)
say("End of Lastlog");
set_lastlog_msg_level(m_level);
restore_message_from();
}
/* set_lastlog_msg_level: sets the message level for recording in the lastlog */
int
set_lastlog_msg_level(level)
int level;
{
int old;
old = msg_level;
msg_level = level;
return (old);
}
/*
* add_to_lastlog: adds the line to the lastlog. If the LASTLOG_CONVERSATION
* variable is on, then only those lines that are user messages (private
* messages, channel messages, wall's, and any outgoing messages) are
* recorded, otherwise, everything is recorded
*/
void
add_to_lastlog(window, line)
Window *window;
u_char *line;
{
Lastlog *new;
if (window == (Window *) 0)
window = curr_scr_win;
if (window->lastlog_level & msg_level)
{
/* no nulls or empty lines (they contain "> ") */
if (line && ((int) my_strlen(line) > 2))
{
new = (Lastlog *) new_malloc(sizeof(Lastlog));
new->next = window->lastlog_head;
new->prev = (Lastlog *) 0;
new->level = msg_level;
new->msg = (u_char *) 0;
malloc_strcpy(&(new->msg), line);
if (window->lastlog_head)
window->lastlog_head->prev = new;
window->lastlog_head = new;
if (window->lastlog_tail == (Lastlog *) 0)
window->lastlog_tail = window->lastlog_head;
if (window->lastlog_size++ == get_int_var(LASTLOG_VAR))
remove_from_lastlog(window);
}
}
}
int
islogged(window)
Window *window;
{
return (window->lastlog_level & msg_level) ? 1 : 0;
}
int
real_notify_level()
{
return (notify_level);
}
int
real_lastlog_level()
{
return (lastlog_level);
}
void
set_notify_level(str)
u_char *str;
{
notify_level = parse_lastlog_level(str);
set_string_var(NOTIFY_LEVEL_VAR, bits_to_lastlog_level(notify_level));
curr_scr_win->notify_level = notify_level;
}
syntax highlighted by Code2HTML, v. 0.9.1