/* * 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-2003 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. * * $Id: lastlog.c,v 1.10 2003/01/08 20:00:54 f Exp $ */ #include "irc.h" #include "lastlog.h" #include "window.h" #include "screen.h" #include "vars.h" #include "ircaux.h" #include "output.h" /**************************** PATCHED by Flier ******************************/ extern void StripAnsi _((char *, char *, int)); /****************************************************************************/ 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(char *)) /* * bits_to_lastlog_level: converts the bitmap of lastlog levels into a nice * string format. */ char * bits_to_lastlog_level(level) int level; { static u_char lbuf[128]; /* this *should* be enough for this */ int i, p; if (level == LOG_ALL) strcpy(lbuf, "ALL"); else if (level == 0) strcpy(lbuf, "NONE"); else { *lbuf = '\0'; for (i = 0, p = 1; i < NUMBER_OF_LEVELS; i++, p <<= 1) { if (level & p) { strmcat(lbuf, levels[i], 127); strmcat(lbuf, " ", 127); } } } return (lbuf); } int parse_lastlog_level(str) char *str; { 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 = index(str, ',')) != NULL) *ptr++ = '\0'; if ((len = strlen(str)) != 0) { char *cmd = NULL; malloc_strcpy(&cmd, str); upper(cmd); if (strncmp(cmd, "ALL", len) == 0) level = LOG_ALL; else if (strncmp(cmd, "NONE", len) == 0) level = 0; else { if (*str == '-') { str++; s = cmd + 1; neg = 1; /**************************** PATCHED by Flier ******************************/ len--; /****************************************************************************/ } else { neg = 0; s = cmd; } /**************************** PATCHED by Flier ******************************/ if (*str=='+') { str++; s=cmd+1; len--; } /****************************************************************************/ for (i = 0, p = 1; i < NUMBER_OF_LEVELS; i++, p <<= 1) { if (!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) 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 */ /*ARGSUSED*/ void lastlog(command, args, subargs) char *command, *args, *subargs; { int cnt, from = 0, p, i, level = 0, m_level, mask = 0, header = 1; Lastlog *start_pos; char *match = NULL, *save = NULL, *expanded = NULL, *arg; FILE *fp = NULL; char *cmd = (char *) 0; size_t len; /**************************** PATCHED by Flier ******************************/ int lines=0; int count=0; int timeend=-1; int timestart=-1; char *blah=(char *) 0; char *tmpbuf=(char *) 0; Lastlog *tmp; Lastlog *next; /****************************************************************************/ save_message_from(); message_from((char *) 0, LOG_CURRENT); cnt = curr_scr_win->lastlog_size; while ((arg = next_arg(args, &args)) != NULL) { if (*arg == '-') { arg++; if (!(len = strlen(arg))) { header = 0; continue; } malloc_strcpy(&cmd, arg); upper(cmd); /**************************** PATCHED by Flier ******************************/ if (!strncmp(cmd,"MAX",len)) { char *ptr=(char *) 0; if ((ptr=next_arg(args,&args))) lines=atoi(ptr); else { say("Need number for MAX"); goto out; } if (lines<0) lines=0; } else if (!strncmp(cmd,"CLEAR",len)) { for (tmp=curr_scr_win->lastlog_head;tmp;tmp=next) { next=tmp->next; new_free(&(tmp->msg)); new_free(&tmp); count++; } curr_scr_win->lastlog_head=(Lastlog *) 0; curr_scr_win->lastlog_tail=(Lastlog *) 0; curr_scr_win->lastlog_size=0; say("Lastlog cleared, %d entries removed",count); goto out; } else if (!strncmp(cmd,"TIME",len)) { int hours; int minutes=0; char *minstr; char *tmpstr; char *timestr=(char *) 0; if ((timestr=next_arg(args,&args))) { /* time format: 12:30-14:30 or 3:30PM-4:15PM */ hours=atoi(timestr); minstr=timestr; while (*minstr && *minstr!='-') { if (*minstr==':') { *minstr++='\0'; minutes=atoi(minstr); timestr=minstr; break; } minstr++; } tmpstr=timestr; while (*tmpstr && *tmpstr!='-') { if (*tmpstr=='P' || *tmpstr=='p') { hours+=12; break; } tmpstr++; } if (hours<0 || hours>24) { say("Illegal start time specified"); continue; } timestart=hours*60+minutes; timestr=index(timestr,'-'); if (timestr) { timestr++; hours=atoi(timestr); minstr=timestr; while (*minstr) { if (*minstr==':') { *minstr++='\0'; minutes=atoi(minstr); timestr=minstr; break; } minstr++; } tmpstr=timestr; while (*tmpstr) { if (*tmpstr=='P' || *tmpstr=='p') { hours+=12; break; } tmpstr++; } if (hours<0 || hours>24) { say("Illegal end time specified"); continue; } timeend=hours*60+minutes; } } else { say("Need time string for TIME"); goto out; } } /*if (!strncmp(cmd, "LITERAL", len))*/ else if (!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 (!strncmp(cmd, "BEEP", len)) { if (match) { say("-BEEP is exclusive; ignored"); continue; } else match = "\007"; } else if (!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(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 (strncmp(cmd, levels[i], len) == 0) { mask |= p; break; } } if (i == NUMBER_OF_LEVELS) { say("Unknown flag: %s", arg); message_from((char *) 0, LOG_CRAP); goto out; } } continue; out: restore_message_from(); new_free(&cmd); return; } else { if (level == 0) { if (match || isdigit(*arg)) { cnt = atoi(arg); level++; } else match = arg; } else if (level == 1) { from = 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:"); /**************************** PATCHED by Flier ******************************/ if (match) { blah=(char *) new_malloc(strlen(match)+3); sprintf(blah,"*%s*",match); } /****************************************************************************/ for (i = 0; (i < cnt) && start_pos; start_pos = start_pos->prev) { if (!mask || (mask & start_pos->level)) { i++; /**************************** PATCHED by Flier ******************************/ /*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 (timestart>=0 || timeend>=0) { int timeline=-1; char *tmpstr; tmpbuf=(char *) new_malloc(strlen(start_pos->msg)+1); StripAnsi(start_pos->msg,tmpbuf,1); tmpstr=index(tmpbuf,':'); if (tmpstr && tmpstr-tmpbuf=0) { if (timestart>=0 && timeend>=0) { if (timelinetimeend) continue; } else if (timestart>=0) { if (timeline=0) { if (timeline>timeend) continue; } } } if (!match || wild_match(blah, start_pos->msg)) { if (get_int_var(LASTLOG_ANSI_VAR)) { tmpbuf=(char *) new_malloc(strlen(start_pos->msg)+1); StripAnsi(start_pos->msg,tmpbuf,0); } else malloc_strcpy(&tmpbuf,start_pos->msg); if (save) fprintf(fp, "%s\n", tmpbuf); else put_it("%s", tmpbuf); new_free(&tmpbuf); if (!lines) continue; if (lines==1) break; lines--; } /****************************************************************************/ } } /**************************** PATCHED by Flier ******************************/ new_free(&blah); /****************************************************************************/ if (save) { say("Saved Lastlog to %s", expanded); fclose(fp); } 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; 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) strlen(line) > 2)) { new = (Lastlog *) new_malloc(sizeof(Lastlog)); new->next = window->lastlog_head; new->prev = (Lastlog *) 0; new->level = msg_level; new->msg = (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) 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; }