1 /*
2 * lastlog.c: handles the lastlog features of irc.
3 *
4 * Written By Michael Sandrof and Matthew R. Green.
5 *
6 * Copyright (c) 1990 Michael Sandrof.
7 * Copyright (c) 1991, 1992 Troy Rollo.
8 * Copyright (c) 1992-2019 Matthew R. Green.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #include "irc.h"
36 IRCII_RCSID("@(#)$eterna: lastlog.c,v 1.61 2019/01/18 00:16:18 mrg Exp $");
37
38 #include "lastlog.h"
39 #include "window.h"
40 #include "screen.h"
41 #include "vars.h"
42 #include "ircaux.h"
43 #include "output.h"
44 #include "ircterm.h"
45 #include "strcasestr.h"
46
47 /* Keep this private to lastlog.c */
48 struct lastlog_stru
49 {
50 int level;
51 u_char *msg;
52 u_char **lines;
53 int cols; /* If this doesn't match the current columns,
54 * we have to recalculate the whole thing. */
55 struct lastlog_stru *next;
56 struct lastlog_stru *prev;
57 };
58
59 struct lastlog_info_stru
60 {
61 Lastlog *lastlog_head; /* pointer to top of lastlog list */
62 Lastlog *lastlog_tail; /* pointer to bottom of lastlog list */
63 int lastlog_level; /* The LASTLOG_LEVEL, determines what
64 * messages go to lastlog */
65 int lastlog_size; /* Max number of messages for the window
66 * lastlog */
67 };
68
69 struct lastlog_line_back_info
70 {
71 int row;
72 Lastlog *LogLine;
73 Window *window;
74 };
75
76 static void remove_from_lastlog(LastlogInfo *);
77 static void lastlog_print_one_line(FILE *, u_char *);
78 static void lastlog_load(FILE *, u_char *);
79 static void lastlog_saveall_one_line(FILE *, Lastlog *);
80
81 /*
82 * lastlog_level: current bitmap setting of which things should be stored in
83 * the lastlog. The LOG_MSG, LOG_NOTICE, etc., defines tell more about this
84 */
85 static int lastlog_level;
86 static int notify_level;
87
88 /*
89 * msg_level: the mask for the current message level. What? Did he really
90 * say that? This is set in the set_lastlog_msg_level() routine as it
91 * compared to the lastlog_level variable to see if what ever is being added
92 * should actually be added
93 */
94 static int msg_level = LOG_CRAP;
95
96 static char *levels[] =
97 {
98 "CRAP", "PUBLIC", "MSGS", "NOTICES",
99 "WALLS", "WALLOPS", "NOTES", "OPNOTES",
100 "SNOTES", "ACTIONS", "DCC", "CTCP",
101 "USERLOG1", "USERLOG2", "USERLOG3", "USERLOG4",
102 "BEEP", "HELP"
103 };
104 #define NUMBER_OF_LEVELS ARRAY_SIZE(levels)
105
106 /*
107 * bits_to_lastlog_level: converts the bitmap of lastlog levels into a nice
108 * string format.
109 */
110 u_char *
bits_to_lastlog_level(int level)111 bits_to_lastlog_level(int level)
112 {
113 static u_char lbuf[128]; /* this *should* be enough for this */
114 int i,
115 p;
116 int first = 1;
117
118 if (level == LOG_ALL)
119 my_strcpy(lbuf, UP("ALL"));
120 else if (level == 0)
121 my_strcpy(lbuf, UP("NONE"));
122 else
123 {
124 *lbuf = '\0';
125 for (i = 0, p = 1; i < NUMBER_OF_LEVELS; i++, p <<= 1)
126 {
127 if (level & p)
128 {
129 if (first)
130 first = 0;
131 else
132 my_strmcat(lbuf, " ", sizeof lbuf);
133 my_strmcat(lbuf, levels[i], sizeof lbuf);
134 }
135 }
136 }
137 return (lbuf);
138 }
139
140 int
parse_lastlog_level(u_char * str)141 parse_lastlog_level(u_char *str)
142 {
143 u_char *ptr,
144 *rest,
145 *s;
146 int i,
147 p,
148 level,
149 neg;
150 size_t len;
151
152 level = 0;
153 while ((str = next_arg(str, &rest)) != NULL)
154 {
155 while (str)
156 {
157 if ((ptr = my_index(str, ',')) != NULL)
158 *ptr++ = '\0';
159 if ((len = my_strlen(str)) != 0)
160 {
161 u_char *cmd = NULL;
162
163 malloc_strcpy(&cmd, str);
164 upper(cmd);
165 if (my_strncmp(cmd, "ALL", len) == 0)
166 level = LOG_ALL;
167 else if (my_strncmp(cmd, "NONE", len) == 0)
168 level = 0;
169 else
170 {
171 if (*str == '-')
172 {
173 str++;
174 s = cmd + 1;
175 neg = 1;
176 }
177 else {
178 neg = 0;
179 s = cmd;
180 }
181 for (i = 0, p = 1; i < NUMBER_OF_LEVELS; i++, p <<= 1)
182 {
183 if (!my_strncmp(s, levels[i], len))
184 {
185 if (neg)
186 level &= (LOG_ALL ^ p);
187 else
188 level |= p;
189 break;
190 }
191 }
192 if (i == NUMBER_OF_LEVELS)
193 say("Unknown lastlog level: %s",
194 str);
195 }
196 new_free(&cmd);
197 }
198 str = ptr;
199 }
200 str = rest;
201 }
202 return (level);
203 }
204
205 /*
206 * set_lastlog_level: called whenever a "SET LASTLOG_LEVEL" is done. It
207 * parses the settings and sets the lastlog_level variable appropriately. It
208 * also rewrites the LASTLOG_LEVEL variable to make it look nice
209 */
210 void
set_lastlog_level(u_char * str)211 set_lastlog_level(u_char *str)
212 {
213 LastlogInfo *info = window_get_lastlog_info(curr_scr_win);
214
215 lastlog_level = parse_lastlog_level(str);
216 set_string_var(LASTLOG_LEVEL_VAR, bits_to_lastlog_level(lastlog_level));
217 info->lastlog_level = lastlog_level;
218 }
219
220 static void
free_lastlog_lines(Lastlog * log)221 free_lastlog_lines(Lastlog *log)
222 {
223 u_char **lines;
224
225 for (lines = log->lines; *lines; lines++)
226 new_free(lines);
227 new_free(&log->lines);
228 }
229
230 static void
free_lastlog_entry(Lastlog * log)231 free_lastlog_entry(Lastlog *log)
232 {
233 new_free(&log->msg);
234 free_lastlog_lines(log);
235 new_free(&log);
236 }
237
238 static void
remove_from_lastlog(LastlogInfo * info)239 remove_from_lastlog(LastlogInfo *info)
240 {
241 Lastlog *tmp;
242
243 if (info->lastlog_tail)
244 {
245 tmp = info->lastlog_tail->prev;
246 free_lastlog_entry(info->lastlog_tail);
247 info->lastlog_tail = tmp;
248 if (tmp)
249 tmp->next = NULL;
250 else
251 info->lastlog_head = NULL;
252 info->lastlog_size--;
253 }
254 else
255 info->lastlog_size = 0;
256 }
257
258 /*
259 * set_lastlog_size: sets up a lastlog buffer of size given. If the lastlog
260 * has gotten larger than it was before, all previous lastlog entry remain.
261 * If it get smaller, some are deleted from the end.
262 */
263 void
set_lastlog_size(int size)264 set_lastlog_size(int size)
265 {
266 LastlogInfo *info = window_get_lastlog_info(curr_scr_win);
267 int i,
268 diff;
269
270 if (info->lastlog_size > size)
271 {
272 diff = info->lastlog_size - size;
273 for (i = 0; i < diff; i++)
274 remove_from_lastlog(info);
275 }
276 }
277
278 /*
279 * lastlog_print_one_line: print one line to the lastlog file or screen,
280 * cutting off the trailing ^O (ALL_OFF) that may be present.
281 */
282 static void
lastlog_print_one_line(FILE * fp,u_char * msg)283 lastlog_print_one_line(FILE *fp, u_char *msg)
284 {
285 size_t len = my_strlen(msg);
286 int hacked = 0;
287
288 if (len == 0)
289 return;
290 if (msg[len - 1] == ALL_OFF)
291 {
292 msg[len - 1] = '\0';
293 hacked = 1;
294 }
295 if (fp)
296 fprintf(fp, "%s\n", msg);
297 else
298 put_it("%s", msg);
299 if (hacked)
300 msg[len - 1] = ALL_OFF;
301 }
302
303 /*
304 * lastlog saveall files:
305 *
306 * the way to handle restarting while not losing lastlog is to
307 * store the lastlog data into a file, that is reloaded upload
308 * starting. the way we implement this is:
309 *
310 * - at exit time, /lastlog -saveall in each window to a file
311 * - at load time, when each window is created, /lastlog -loadall
312 * from this same file.
313 *
314 * need to automate this, perhaps with scripts that run at both
315 * window destroy/quit and window add (not related to /window
316 * create feature.)
317 *
318 * the format in these files is as follows:
319 *
320 * <header>
321 * <timestamp> <msglevel> <msg>
322 * [repeat 2nd line]
323 *
324 * where the header includes a version check and user supplied
325 * info, possibly available in the load hook? the timestamp will
326 * be 0 initially, as lastlog doesn't yet keep timestamps on the
327 * messages (but often in the message string).
328 *
329 * loading and saving these files will be an all/nothing thing.
330 * eg, loading in the middle will replace the current settings,
331 * though future expansion could extend this to insert at/after
332 * a certain place.
333 *
334 * <header>'s format is:
335 * "IRCII-SAVEALL <version> [<userdata>]"
336 * eg, "IRCII-SAVEALL V1 [blah blah]".
337 */
338
339 #define LASTLOG_SAVEALL_HEADER "IRCII-SAVEALL"
340 #define LASTLOG_SAVEALL_HEADER_VERSION "V1"
341
342 /*
343 * lastlog_saveall_header: print the lastlog saveall header
344 *
345 * XXX: make the info settable
346 */
347 static void
lastlog_saveall_header(FILE * fp)348 lastlog_saveall_header(FILE *fp)
349 {
350 // make settable
351 const char *lastlog_saveall_info = "";
352
353 fprintf(fp, "%s %s [%s]\n", LASTLOG_SAVEALL_HEADER,
354 LASTLOG_SAVEALL_HEADER_VERSION, lastlog_saveall_info);
355 }
356
357 /*
358 * lastlog_saveall_one_line: like lastlog_print_one_line() but always
359 * print to the file, but with saveall info.
360 */
361 static void
lastlog_saveall_one_line(FILE * fp,Lastlog * line)362 lastlog_saveall_one_line(FILE *fp, Lastlog *line)
363 {
364 size_t len = my_strlen(line->msg);
365 int hacked = 0;
366
367 if (len == 0)
368 return;
369 if (line->msg[len - 1] == ALL_OFF)
370 {
371 line->msg[len - 1] = '\0';
372 hacked = 1;
373 }
374 fprintf(fp, "%llu 0x%x %s\n", (unsigned long long) 0 /* timestamp */, line->level, line->msg);
375 if (hacked)
376 line->msg[len - 1] = ALL_OFF;
377 }
378
379 /*
380 * lastlog_load: load a lastlog saveall file into the current window
381 */
382 static void
lastlog_load(FILE * fp,u_char * file)383 lastlog_load(FILE *fp, u_char *file)
384 {
385 u_char buffer[FS_BUFFER_SIZE];
386 u_char *user = NULL;
387 u_char *curbuf = buffer;
388 size_t curlen = sizeof buffer;
389 int got_version = 0;
390 unsigned lineno = 0;
391
392 /* clear the current (if any) list */
393 free_lastlog(curr_scr_win);
394
395 while (fgets(CP(curbuf), curlen, fp) != NULL)
396 {
397 char *ep;
398 u_char *p, *level, *ts, *args;
399 unsigned long ulval;
400 int old_level;
401
402 while ((p = my_index(curbuf, '\n')) == NULL)
403 {
404 size_t oldlen = curlen;
405 u_char *newbuf;
406
407 curlen *= 2;
408 if (curbuf != buffer)
409 newbuf = new_realloc(curbuf, curlen);
410 else
411 {
412 newbuf = new_malloc(curlen);
413 memmove(newbuf, curbuf, oldlen);
414 }
415 curbuf = newbuf;
416 if (fgets(CP(curbuf) + oldlen - 1, oldlen + 1, fp) == NULL)
417 break;
418 }
419 if (p)
420 *p = '\0';
421 lineno++;
422 args = curbuf;
423 if (!got_version)
424 {
425 u_char *header, *version;
426 size_t len;
427
428 header = next_arg(args, &args);
429 if (!header ||
430 my_strcmp(header, UP(LASTLOG_SAVEALL_HEADER)) != 0)
431 {
432 yell("--- header wrong on args '%s %s'", header, args);
433 goto out;
434 }
435
436 version = next_arg(args, &args);
437 if (!version ||
438 my_strcmp(version, UP(LASTLOG_SAVEALL_HEADER_VERSION)) != 0)
439 {
440 yell("--- version wrong on args '%s %s %s'", header, version, args);
441 goto out;
442 }
443
444 len = my_strlen(args);
445 if (args[0] != '[' || args[len - 1] != ']')
446 {
447 yell("--- user wrong on args '%s %s %s'", header, version, args);
448 goto out;
449 }
450 args[len - 1] = '\0';
451 user = args + 1;
452
453 got_version = 1;
454 continue;
455 }
456 args = curbuf;
457 ts = next_arg(args, &args);
458 if (!ts || !*ts)
459 {
460 yell("--- missing timestamp at line %u", lineno);
461 continue;
462 }
463 level = next_arg(args, &args);
464 if (!level || !*level)
465 {
466 yell("--- missing level at line %u", lineno);
467 continue;
468 }
469
470 errno = 0;
471 ulval = strtoul(CP(level), &ep, 16);
472 if (*ep != '\0')
473 {
474 yell("--- '%s' is not a base 16 number at line %u", level, lineno);
475 continue;
476 }
477 if (errno == ERANGE && ulval == ULONG_MAX)
478 {
479 yell("--- '%s' is out of range of unsigned long at line %u", level, lineno);
480 continue;
481 }
482 old_level = set_lastlog_msg_level(ulval);
483 add_to_lastlog(curr_scr_win, args);
484 set_lastlog_msg_level(old_level);
485 }
486
487 if (user && lineno > 1)
488 say("Loaded %u lines from %s [%s]", lineno - 1, file, user);
489
490 out:
491 if (curbuf != buffer)
492 new_free(&curbuf);
493 }
494
495 /*
496 * lastlog: the /LASTLOG command. Displays the lastlog to the screen. If
497 * args contains a valid integer, only that many lastlog entries are shown
498 * (if the value is less than lastlog_size), otherwise the entire lastlog is
499 * displayed
500 *
501 * /lastlog -save filename
502 * by StElb <stlb@cs.tu-berlin.de>
503 */
504 void
lastlog(u_char * command,u_char * args,u_char * subargs)505 lastlog(u_char *command, u_char *args, u_char *subargs)
506 {
507 int cnt,
508 from = 0,
509 p,
510 i,
511 level = 0,
512 m_level,
513 mask = 0,
514 header = 1;
515 Lastlog *start_pos;
516 u_char *match = NULL,
517 *save = NULL,
518 *saveall = NULL,
519 *expanded = NULL,
520 *arg;
521 FILE *fp = NULL;
522 u_char *cmd = NULL;
523 size_t len;
524 LastlogInfo *info = window_get_lastlog_info(curr_scr_win);
525
526 save_message_from();
527 message_from(NULL, LOG_CURRENT);
528 cnt = info->lastlog_size;
529
530 while ((arg = next_arg(args, &args)) != NULL)
531 {
532 if (*arg == '-')
533 {
534 arg++;
535 if (!(len = my_strlen(arg)))
536 {
537 header = 0;
538 continue;
539 }
540 malloc_strcpy(&cmd, arg);
541 upper(cmd);
542 if (!my_strncmp(cmd, "LITERAL", len))
543 {
544 if (match)
545 {
546 say("Second -LITERAL argument ignored");
547 (void) next_arg(args, &args);
548 continue;
549 }
550 if ((match = next_arg(args, &args)) != NULL)
551 continue;
552 say("Need pattern for -LITERAL");
553 goto out;
554 }
555 else if (!my_strncmp(cmd, "BEEP", len))
556 {
557 if (match)
558 {
559 say("-BEEP is exclusive; ignored");
560 continue;
561 }
562 else
563 match = UP("\007");
564 }
565 else if (!my_strncmp(cmd, "SAVEALL", len))
566 {
567 #ifdef DAEMON_UID
568 if (getuid() == DAEMON_UID)
569 {
570 say("You are not permitted to use -SAVEALL flag");
571 goto out;
572 }
573 #endif /* DAEMON_UID */
574 if (saveall)
575 {
576 say("Second -SAVEALL argument ignored");
577 (void) next_arg(args, &args);
578 continue;
579 }
580 if ((saveall = next_arg(args, &args)) != NULL)
581 {
582 expanded = expand_twiddle(saveall);
583 if ((fp = fopen(CP(expanded), "w")) != NULL)
584 {
585 lastlog_saveall_header(fp);
586 header = 0;
587 continue;
588 }
589 say("Error opening %s: %s", save, strerror(errno));
590 goto out;
591 }
592 say("Need filename for -SAVE");
593 goto out;
594 }
595 else if (!my_strncmp(cmd, "LOADALL", len))
596 {
597 #ifdef DAEMON_UID
598 if (getuid() == DAEMON_UID)
599 {
600 say("You are not permitted to use -LOADALL flag");
601 goto out;
602 }
603 #endif /* DAEMON_UID */
604 if ((saveall = next_arg(args, &args)) != NULL)
605 {
606 expanded = expand_twiddle(saveall);
607 if ((fp = fopen(CP(expanded), "r")) != NULL)
608 lastlog_load(fp, expanded);
609 else
610 say("Error opening %s: %s", save,
611 strerror(errno));
612 }
613 goto out;
614 }
615 else if (!my_strncmp(cmd, "SAVE", len))
616 {
617 #ifdef DAEMON_UID
618 if (getuid() == DAEMON_UID)
619 {
620 say("You are not permitted to use -SAVE flag");
621 goto out;
622 }
623 #endif /* DAEMON_UID */
624 if (save)
625 {
626 say("Second -SAVE argument ignored");
627 (void) next_arg(args, &args);
628 continue;
629 }
630 if ((save = next_arg(args, &args)) != NULL)
631 {
632 expanded = expand_twiddle(save);
633 if ((fp = fopen(CP(expanded), "w")) != NULL)
634 continue;
635 say("Error opening %s: %s", save, strerror(errno));
636 goto out;
637 }
638 say("Need filename for -SAVE");
639 goto out;
640 }
641 else
642 {
643 for (i = 0, p = 1; i < NUMBER_OF_LEVELS; i++, p <<= 1)
644 {
645 if (my_strncmp(cmd, levels[i], len) == 0)
646 {
647 mask |= p;
648 break;
649 }
650 }
651 if (i == NUMBER_OF_LEVELS)
652 {
653 say("Unknown flag: %s", arg);
654 message_from(NULL, LOG_CRAP);
655 goto out;
656 }
657 }
658 continue;
659 out:
660 new_free(&expanded);
661 new_free(&cmd);
662 restore_message_from();
663 if (fp)
664 fclose(fp);
665 return;
666 }
667 else
668 {
669 if (level == 0)
670 {
671 if (match || isdigit(*arg))
672 {
673 cnt = my_atoi(arg);
674 level++;
675 }
676 else
677 match = arg;
678 }
679 else if (level == 1)
680 {
681 from = my_atoi(arg);
682 level++;
683 }
684 }
685 }
686 if (cmd)
687 new_free(&cmd);
688
689 if (saveall && (save || match || mask || cnt != info->lastlog_size))
690 {
691 say("-SAVEALL does not work with -save or any matching");
692 goto out;
693 }
694
695 start_pos = info->lastlog_head;
696 for (i = 0; (i < from) && start_pos; start_pos = start_pos->next)
697 if (!mask || (mask & start_pos->level))
698 i++;
699
700 for (i = 0; (i < cnt) && start_pos; start_pos = start_pos->next)
701 if (!mask || (mask & start_pos->level))
702 i++;
703
704 level = info->lastlog_level;
705 m_level = set_lastlog_msg_level(0);
706 if (start_pos == NULL)
707 start_pos = info->lastlog_tail;
708 else
709 start_pos = start_pos->prev;
710
711 /* Let's not get confused here, display a seperator.. -lynx */
712 if (header && !save)
713 say("Lastlog:");
714 for (i = 0; (i < cnt) && start_pos; start_pos = start_pos->prev)
715 {
716 if (saveall)
717 lastlog_saveall_one_line(fp, start_pos);
718 else if (!mask || (mask & start_pos->level))
719 {
720 i++;
721 if (!match ||
722 my_strcasestr(start_pos->msg, match))
723 lastlog_print_one_line(fp, start_pos->msg);
724 }
725 }
726 if (save)
727 {
728 say("Saved Lastlog to %s", expanded);
729 fclose(fp);
730 }
731 else if (header)
732 say("End of Lastlog");
733 new_free(&expanded);
734 set_lastlog_msg_level(m_level);
735 restore_message_from();
736 }
737
738 /* set_lastlog_msg_level: sets the message level for recording in the lastlog */
739 int
set_lastlog_msg_level(int level)740 set_lastlog_msg_level(int level)
741 {
742 int old;
743
744 old = msg_level;
745 msg_level = level;
746 return (old);
747 }
748
749 /*
750 * add_to_lastlog: adds the line to the lastlog, based upon the current
751 * lastlog level. if added, the split up lines ready for display are
752 * returned.
753 */
754 u_char **
add_to_lastlog(Window * window,u_char * line)755 add_to_lastlog(Window *window, u_char *line)
756 {
757 Lastlog *new = NULL;
758 LastlogInfo *info;
759
760 if (window == NULL)
761 window = curr_scr_win;
762 info = window_get_lastlog_info(window);
763 if (info->lastlog_level & msg_level)
764 {
765 /* no nulls or empty lines (they contain "> ") */
766 if (line /*&& ((int) my_strlen(line) > 2)*/)
767 {
768 new = new_malloc(sizeof *new);
769 new->next = info->lastlog_head;
770 new->prev = NULL;
771 new->level = msg_level;
772 new->msg = NULL;
773 malloc_strcpy(&new->msg, line);
774 copy_window_size(NULL, &new->cols);
775 Debug(DB_LASTLOG, "columns = %d", new->cols);
776 new->lines = split_up_line_alloc(line);
777
778 if (info->lastlog_head)
779 info->lastlog_head->prev = new;
780 info->lastlog_head = new;
781
782 if (info->lastlog_tail == NULL)
783 info->lastlog_tail = info->lastlog_head;
784
785 if (info->lastlog_size++ == get_int_var(LASTLOG_VAR))
786 remove_from_lastlog(info);
787 }
788 }
789 if (new)
790 return new->lines;
791 return NULL;
792 }
793
794 int
islogged(Window * window)795 islogged(Window *window)
796 {
797 LastlogInfo *info = window_get_lastlog_info(window);
798
799 return (info->lastlog_level & msg_level) ? 1 : 0;
800 }
801
802 int
real_notify_level(void)803 real_notify_level(void)
804 {
805 return (notify_level);
806 }
807
808 int
real_lastlog_level(void)809 real_lastlog_level(void)
810 {
811 return (lastlog_level);
812 }
813
814 void
set_notify_level(u_char * str)815 set_notify_level(u_char *str)
816 {
817 notify_level = parse_lastlog_level(str);
818 set_string_var(NOTIFY_LEVEL_VAR, bits_to_lastlog_level(notify_level));
819 window_set_notify_level(curr_scr_win, notify_level);
820 }
821
822 /*
823 * free_lastlog: This frees all data and structures associated with the
824 * lastlog of the given window
825 */
826 void
free_lastlog(Window * window)827 free_lastlog(Window *window)
828 {
829 Lastlog *tmp, *next;
830 LastlogInfo *info = window_get_lastlog_info(window);
831
832 for (tmp = info->lastlog_head; tmp; tmp = next)
833 {
834 next = tmp->next;
835 free_lastlog_entry(tmp);
836 }
837 }
838
839 /*
840 * lastlog_line_back():
841 *
842 * initially call lastlog_line_back_alloc(). then, each call to
843 * lastlog_line_back() will return the next line of the screen output,
844 * going backwards through the lastlog history. call
845 * lastlog_line_back_free() when done. uses split_up_line() from earlier
846 * in this file to do the actual splitting of each individiual line.
847 */
848
849 LastlogLineBackInfo *
lastlog_line_back_alloc(Window * window)850 lastlog_line_back_alloc(Window *window)
851 {
852 LastlogLineBackInfo *info = new_malloc(sizeof *info);
853 LastlogInfo *linfo = window_get_lastlog_info(window);
854
855 info->LogLine = linfo->lastlog_head;
856 info->row = -1;
857
858 info->window = NULL;
859 lastlog_line_back(info);
860 info->window = window;
861
862 return info;
863 }
864
865 void
lastlog_line_back_free(LastlogLineBackInfo * info)866 lastlog_line_back_free(LastlogLineBackInfo *info)
867 {
868 new_free(&info);
869 }
870
871 u_char *
lastlog_line_back(LastlogLineBackInfo * info)872 lastlog_line_back(LastlogLineBackInfo *info)
873 {
874 if (info->row <= 0)
875 {
876 int cols;
877
878 if (info->window && info->LogLine)
879 info->LogLine = info->LogLine->next;
880 if (!info->LogLine)
881 return NULL;
882 copy_window_size(NULL, &cols);
883 Debug(DB_LASTLOG, "save cols %d, new cols %d", info->LogLine->cols, cols);
884 if (info->LogLine->cols != cols) {
885 /* Must free and re-calculate */
886 free_lastlog_lines(info->LogLine);
887 info->LogLine->cols = cols;
888 info->LogLine->lines = split_up_line_alloc(info->LogLine->msg);
889 }
890 for (info->row = 0; info->LogLine->lines[info->row]; info->row++)
891 /* count the rows */;
892 if (!info->window)
893 return NULL;
894 }
895 return info->LogLine->lines[--info->row];
896 }
897
898 LastlogInfo *
lastlog_new_window(void)899 lastlog_new_window(void)
900 {
901 LastlogInfo *new = new_malloc(sizeof *new);
902
903 new->lastlog_head = 0;
904 new->lastlog_tail = 0;
905 new->lastlog_size = 0;
906 new->lastlog_level = real_lastlog_level();
907
908 return new;
909 }
910
911 int
lastlog_get_size(LastlogInfo * info)912 lastlog_get_size(LastlogInfo *info)
913 {
914 return info->lastlog_size;
915 }
916
917 int
lastlog_get_level(LastlogInfo * info)918 lastlog_get_level(LastlogInfo *info)
919 {
920 return info->lastlog_level;
921 }
922
923 void
lastlog_set_level(LastlogInfo * info,int level)924 lastlog_set_level(LastlogInfo *info, int level)
925 {
926 info->lastlog_level = level;
927 }
928