1 /*
2 * status.c: handles the status line updating, etc for IRCII
3 *
4 * Written By Michael Sandrof
5 *
6 * Copyright (c) 1990 Michael Sandrof.
7 * Copyright (c) 1991, 1992 Troy Rollo.
8 * Copyright (c) 1992-2020 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 /*
36 * WARNING! THIS CODE HAS DRAGONS. BE *VERY* CAREFUL WHEN CHANGING
37 * ANYTHING IN HERE. TEST IT EXTENSIVELY.
38 */
39
40 #include "irc.h"
41 IRCII_RCSID("@(#)$eterna: status.c,v 1.132 2020/11/17 08:12:34 mrg Exp $");
42
43 #include "ircterm.h"
44 #include "status.h"
45 #include "server.h"
46 #include "vars.h"
47 #include "hook.h"
48 #include "input.h"
49 #include "edit.h"
50 #include "window.h"
51 #include "screen.h"
52 #include "mail.h"
53 #include "output.h"
54 #include "names.h"
55 #include "ircaux.h"
56 #include "translat.h"
57 #include "debug.h"
58
59 static u_char *convert_format(u_char *, int);
60 static u_char *status_nickname(Window *);
61 static u_char *status_query_nick(Window *);
62 static u_char *status_right_justify(Window *);
63 static u_char *status_chanop(Window *);
64 static u_char *status_channel(Window *);
65 static u_char *status_server(Window *);
66 static u_char *status_mode(Window *);
67 static u_char *status_umode(Window *);
68 static u_char *status_insert_mode(Window *);
69 static u_char *status_overwrite_mode(Window *);
70 static u_char *status_away(Window *);
71 static u_char *status_oper(Window *);
72 static u_char *status_voice(Window *);
73 static u_char *status_user0(Window *);
74 static u_char *status_user1(Window *);
75 static u_char *status_user2(Window *);
76 static u_char *status_user3(Window *);
77 static u_char *status_hold(Window *);
78 static u_char *status_version(Window *);
79 static u_char *status_clock(Window *);
80 static u_char *status_hold_lines(Window *);
81 static u_char *status_window(Window *);
82 static u_char *status_mail(Window *);
83 static u_char *status_refnum(Window *);
84 static u_char *status_null_function(Window *);
85 static u_char *status_notify_windows(Window *);
86 static u_char *status_group(Window *);
87 static u_char *status_scrolled(Window *);
88 static u_char *status_scrolled_lines(Window *);
89 static void alarm_switch(int);
90 static u_char *convert_sub_format(u_char *, int);
91 static void make_status_one(Window *, int, int);
92
93 /*
94 * Maximum number of "%" expressions in a status line format. If you change
95 * this number, you must manually change the snprintf() in make_status
96 */
97 #define MAX_FUNCTIONS 45
98
99 /* The format statements to build each portion of the status line */
100 static u_char *mode_format = NULL;
101 static u_char *umode_format = NULL;
102 static u_char *status_format[3] = {NULL, NULL, NULL,};
103 static u_char *query_format = NULL;
104 static u_char *clock_format = NULL;
105 static u_char *hold_lines_format = NULL;
106 static u_char *scrolled_lines_format = NULL;
107 static u_char *channel_format = NULL;
108 static u_char *mail_format = NULL;
109 static u_char *server_format = NULL;
110 static u_char *notify_format = NULL;
111 static u_char *group_format = NULL;
112
113 /*
114 * status_func: The list of status line function in the proper order for
115 * display. This list is set in convert_format()
116 */
117 static u_char *(*status_func[3][MAX_FUNCTIONS])(Window *);
118
119 /* func_cnt: the number of status line functions assigned */
120 static int func_cnt[3];
121
122 static int alarm_hours, /* hour setting for alarm in 24 hour time */
123 alarm_minutes; /* minute setting for alarm */
124
125 /* Stuff for the alarm */
126 static struct itimerval clock_timer = { { 10L, 0L }, { 1L, 0L } };
127 static struct itimerval off_timer = { { 0L, 0L }, { 0L, 0L } };
128
129 static void alarmed(int);
130 static int do_status_alarmed;
131
132 /* alarmed: This is called whenever a SIGALRM is received and the alarm is on */
133 static void
alarmed(int signo)134 alarmed(int signo)
135 {
136 do_status_alarmed = 1;
137 }
138
139 void
check_status_alarmed(void)140 check_status_alarmed(void)
141 {
142 if (do_status_alarmed) {
143 u_char time_str[16];
144
145 say("The time is %s", update_clock(time_str, 16, GET_TIME));
146 term_beep();
147 term_beep();
148 term_beep();
149 do_status_alarmed = 0;
150 }
151 }
152
153 /*
154 * alarm_switch: turns on and off the alarm display. Sets the system timer
155 * and sets up a signal to trap SIGALRMs. If flag is 1, the alarmed()
156 * routine will be activated every 10 seconds or so. If flag is 0, the timer
157 * and signal stuff are reset
158 */
159 static void
alarm_switch(int flag)160 alarm_switch(int flag)
161 {
162 static int alarm_on = 0;
163
164 if (flag)
165 {
166 if (!alarm_on)
167 {
168 (void) MY_SIGNAL(SIGALRM, alarmed, 0);
169 setitimer(ITIMER_REAL, &clock_timer,
170 NULL);
171 alarm_on = 1;
172 }
173 }
174 else if (alarm_on)
175 {
176 setitimer(ITIMER_REAL, &off_timer, NULL);
177 (void) MY_SIGNAL(SIGALRM, (sigfunc *)SIG_IGN, 0);
178 alarm_on = 0;
179 }
180 }
181
182 /*
183 * set_alarm: given an input string, this checks its validity as a clock
184 * type time thingy. It accepts two time formats. The first is the HH:MM:XM
185 * format where HH is between 1 and 12, MM is between 0 and 59, and XM is
186 * either AM or PM. The second is the HH:MM format where HH is between 0 and
187 * 23 and MM is between 0 and 59. This routine also looks for one special
188 * case, "OFF", which sets the alarm string to null
189 */
190 void
set_alarm(u_char * str)191 set_alarm(u_char *str)
192 {
193 u_char hours[10],
194 minutes[10],
195 merid[3];
196 u_char time_str[10];
197 int c,
198 h,
199 m,
200 min_hours,
201 max_hours;
202
203 if (str == NULL)
204 {
205 alarm_switch(0);
206 return;
207 }
208 if (!my_stricmp(str, UP(var_settings(OFF))))
209 {
210 set_string_var(CLOCK_ALARM_VAR, NULL);
211 alarm_switch(0);
212 return;
213 }
214
215 c = sscanf(CP(str), " %2[^:]:%2[^paPA]%2s ", hours, minutes, merid);
216 switch (c)
217 {
218 case 2:
219 min_hours = 0;
220 max_hours = 23;
221 break;
222 case 3:
223 min_hours = 1;
224 max_hours = 12;
225 upper(UP(merid));
226 break;
227 default:
228 say("CLOCK_ALARM: Bad time format.");
229 set_string_var(CLOCK_ALARM_VAR, NULL);
230 return;
231 }
232
233 h = my_atoi(hours);
234 if (h < 0)
235 h = 0;
236 m = my_atoi(minutes);
237 if (m < 0)
238 m = 0;
239 if (h >= min_hours && h <= max_hours && isdigit(hours[0]) &&
240 (isdigit(hours[1]) || hours[1] == '\0'))
241 {
242 if (m >= 0 && m <= 59 && isdigit(minutes[0]) &&
243 isdigit(minutes[1]))
244 {
245 alarm_minutes = m;
246 alarm_hours = h;
247 if (max_hours == 12)
248 {
249 if (merid[0] != 'A')
250 {
251 if (merid[0] == 'P')
252 {
253 if (h != 12)
254 alarm_hours += 12;
255 }
256 else
257 {
258 say("CLOCK_ALARM: alarm time must end with either \"AM\" or \"PM\"");
259 set_string_var(CLOCK_ALARM_VAR, NULL);
260 }
261 }
262 else
263 {
264 if (h == 12)
265 alarm_hours = 0;
266 }
267 if (merid[1] == 'M')
268 {
269 snprintf(CP(time_str), sizeof time_str,
270 "%02d:%02d%s", h, m, merid);
271 set_string_var(CLOCK_ALARM_VAR,
272 time_str);
273 }
274 else
275 {
276 say("CLOCK_ALARM: alarm time must end with either \"AM\" or \"PM\"");
277 set_string_var(CLOCK_ALARM_VAR, NULL);
278 }
279 }
280 else
281 {
282 snprintf(CP(time_str), sizeof time_str,
283 "%02d:%02d", h, m);
284 set_string_var(CLOCK_ALARM_VAR, time_str);
285 }
286 }
287 else
288 {
289 say("CLOCK_ALARM: alarm minutes value must be between 0 and 59.");
290 set_string_var(CLOCK_ALARM_VAR, NULL);
291 }
292 }
293 else
294 {
295 say("CLOCK_ALARM: alarm hour value must be between %d and %d.",
296 min_hours, max_hours);
297 set_string_var(CLOCK_ALARM_VAR, NULL);
298 }
299 }
300
301 u_char *
format_clock(u_char * buf,size_t len,int hour,int min)302 format_clock(u_char *buf, size_t len, int hour, int min)
303 {
304 char *merid;
305
306 if (get_int_var(CLOCK_24HOUR_VAR))
307 merid = CP(empty_string());
308 else
309 {
310 if (hour < 12)
311 merid = "AM";
312 else
313 merid = "PM";
314 if (hour > 12)
315 hour -= 12;
316 else if (hour == 0)
317 hour = 12;
318 }
319 snprintf(CP(buf), len, "%02d:%02d%s", hour, min, merid);
320
321 return buf;
322 }
323
324
325 /* update_clock: figures out the current time and returns it in a nice format */
326 u_char *
update_clock(u_char * buf,size_t len,int flag)327 update_clock(u_char *buf, size_t len, int flag)
328 {
329 struct tm *time_val;
330 static u_char time_str[10];
331 static int min = -1, hour = -1;
332 time_t t;
333 int tmp_hour, tmp_min;
334
335 t = time(0);
336 time_val = localtime(&t);
337 tmp_hour = time_val->tm_hour;
338 tmp_min = time_val->tm_min;
339
340 Debug(DB_STATUS, "update_clock (%s): time %lu (%02d:%02d) [old %02d:%02d]",
341 flag == RESET_TIME ? "reset" :
342 flag == GET_TIME ? "get" :
343 flag == UPDATE_TIME ? "update" : "unknown",
344 (long unsigned) t, tmp_hour, tmp_min, hour, min);
345
346 if (get_string_var(CLOCK_ALARM_VAR))
347 {
348 if ((tmp_hour == alarm_hours) && (tmp_min == alarm_minutes))
349 alarm_switch(1);
350 else
351 alarm_switch(0);
352 }
353
354 if (flag == RESET_TIME ||
355 (flag == UPDATE_TIME && (tmp_min != min || tmp_hour != hour)))
356 {
357 int server;
358
359 format_clock(time_str, sizeof time_str, tmp_hour, tmp_min);
360 server = set_from_server(get_primary_server());
361 Debug(DB_STATUS, "update_clock: in reset_time block, time_str: %s",
362 time_str);
363 if (flag == UPDATE_TIME && (tmp_min != min || tmp_hour != hour))
364 {
365 hour = tmp_hour;
366 min = tmp_min;
367 do_hook(TIMER_LIST, "%s", time_str);
368 }
369 do_hook(IDLE_LIST, "%lld", (long long)(t - idle_time()) / 60L);
370 set_from_server(server);
371 flag = GET_TIME;
372 }
373 if (buf)
374 {
375 my_strncpy(buf, time_str, len - 1);
376 buf[len - 1] = '\0';
377 }
378 if (flag == GET_TIME)
379 return(buf ? buf : time_str);
380 else
381 return (NULL);
382 }
383
384 void
reset_clock(int unused)385 reset_clock(int unused)
386 {
387 update_clock(0, 0, RESET_TIME);
388 update_all_status();
389 }
390
391 /*
392 * convert_sub_format: This is used to convert the formats of the
393 * sub-portions of the status line to a format statement specially designed
394 * for that sub-portions. convert_sub_format looks for a single occurence of
395 * %c (where c is passed to the function). When found, it is replaced by "%s"
396 * for use is a snprintf. All other occurences of % followed by any other
397 * character are left unchanged. Only the first occurence of %c is
398 * converted, all subsequence occurences are left unchanged. This routine
399 * mallocs the returned string.
400 */
401 static u_char *
convert_sub_format(u_char * format,int c)402 convert_sub_format(u_char *format, int c)
403 {
404 u_char lbuf[BIG_BUFFER_SIZE];
405 static u_char bletch[] = "%% ";
406 u_char *ptr = NULL;
407 int dont_got_it = 1;
408
409 if (format == NULL)
410 return (NULL);
411 *lbuf = '\0';
412 while (format)
413 {
414 if ((ptr = my_index(format, '%')) != NULL)
415 {
416 *ptr = '\0';
417 my_strmcat(lbuf, format, sizeof lbuf);
418 *(ptr++) = '%';
419 if ((*ptr == c) && dont_got_it)
420 {
421 dont_got_it = 0;
422 my_strmcat(lbuf, "%s", sizeof lbuf);
423 }
424 else
425 {
426 bletch[2] = *ptr;
427 my_strmcat(lbuf, bletch, sizeof lbuf);
428 }
429 ptr++;
430 }
431 else
432 my_strmcat(lbuf, format, sizeof lbuf);
433 format = ptr;
434 }
435 malloc_strcpy(&ptr, lbuf);
436 return ptr;
437 }
438
439 static u_char *
convert_format(u_char * format,int k)440 convert_format(u_char *format, int k)
441 {
442 u_char lbuf[BIG_BUFFER_SIZE];
443 u_char *ptr,
444 *malloc_ptr = NULL;
445 int *cp;
446
447 *lbuf = '\0';
448 while (format)
449 {
450 if ((ptr = my_index(format, '%')) != NULL)
451 {
452 *ptr = '\0';
453 my_strmcat(lbuf, format, sizeof lbuf);
454 *(ptr++) = '%';
455 cp = &func_cnt[k];
456 if (*cp < MAX_FUNCTIONS)
457 {
458 switch (*(ptr++))
459 {
460 case '%':
461 /*
462 * %% instead of %, because this will
463 * be passed to snprintf
464 */
465 my_strmcat(lbuf, "%%", sizeof lbuf);
466 break;
467 case 'N':
468 my_strmcat(lbuf, "%s", sizeof lbuf);
469 status_func[k][(*cp)++] =
470 status_nickname;
471 break;
472 case '>':
473 my_strmcat(lbuf, "%s", sizeof lbuf);
474 status_func[k][(*cp)++] =
475 status_right_justify;
476 break;
477 case 'G':
478 new_free(&group_format);
479 group_format =
480 convert_sub_format(get_string_var(STATUS_GROUP_VAR), 'G');
481 my_strmcat(lbuf, "%s", sizeof lbuf);
482 status_func[k][(*cp)++] =
483 status_group;
484 break;
485 case 'Q':
486 new_free(&query_format);
487 query_format =
488 convert_sub_format(get_string_var(STATUS_QUERY_VAR), 'Q');
489 my_strmcat(lbuf, "%s", sizeof lbuf);
490 status_func[k][(*cp)++] =
491 status_query_nick;
492 break;
493 case 'F':
494 new_free(¬ify_format);
495 notify_format =
496 convert_sub_format(get_string_var(STATUS_NOTIFY_VAR), 'F');
497 my_strmcat(lbuf, "%s", sizeof lbuf);
498 status_func[k][(*cp)++] =
499 status_notify_windows;
500 break;
501 case '@':
502 my_strmcat(lbuf, "%s", sizeof lbuf);
503 status_func[k][(*cp)++] =
504 status_chanop;
505 break;
506 case 'C':
507 new_free(&channel_format);
508 channel_format =
509 convert_sub_format(get_string_var(STATUS_CHANNEL_VAR), 'C');
510 my_strmcat(lbuf, "%s", sizeof lbuf);
511 status_func[k][(*cp)++] =
512 status_channel;
513 break;
514 case 'S':
515 new_free(&server_format);
516 server_format =
517 convert_sub_format(get_string_var(STATUS_SERVER_VAR), 'S');
518 my_strmcat(lbuf,"%s",sizeof lbuf);
519 status_func[k][(*cp)++] =
520 status_server;
521 break;
522 case '+':
523 new_free(&mode_format);
524 mode_format =
525 convert_sub_format(get_string_var(STATUS_MODE_VAR), '+');
526 my_strmcat(lbuf, "%s", sizeof lbuf);
527 status_func[k][(*cp)++] =
528 status_mode;
529 break;
530 case '#':
531 new_free(&umode_format);
532 umode_format =
533 convert_sub_format(get_string_var(STATUS_UMODE_VAR), '#');
534 my_strmcat(lbuf, "%s", sizeof lbuf);
535 status_func[k][(*cp)++] =
536 status_umode;
537 break;
538 case 'M':
539 new_free(&mail_format);
540 mail_format =
541 convert_sub_format(get_string_var(STATUS_MAIL_VAR), 'M');
542 my_strmcat(lbuf, "%s", sizeof lbuf);
543 status_func[k][(*cp)++] =
544 status_mail;
545 break;
546 case 'I':
547 my_strmcat(lbuf, "%s", sizeof lbuf);
548 status_func[k][(*cp)++] =
549 status_insert_mode;
550 break;
551 case 'O':
552 my_strmcat(lbuf, "%s", sizeof lbuf);
553 status_func[k][(*cp)++] =
554 status_overwrite_mode;
555 break;
556 case 'A':
557 my_strmcat(lbuf, "%s", sizeof lbuf);
558 status_func[k][(*cp)++] =
559 status_away;
560 break;
561 case 'V':
562 my_strmcat(lbuf, "%s", sizeof lbuf);
563 status_func[k][(*cp)++] =
564 status_version;
565 break;
566 case 'R':
567 my_strmcat(lbuf, "%s", sizeof lbuf);
568 status_func[k][(*cp)++] =
569 status_refnum;
570 break;
571 case 'T':
572 new_free(&clock_format);
573 clock_format =
574 convert_sub_format(get_string_var(STATUS_CLOCK_VAR), 'T');
575 my_strmcat(lbuf, "%s", sizeof lbuf);
576 status_func[k][(*cp)++] =
577 status_clock;
578 break;
579 case 'U':
580 my_strmcat(lbuf, "%s", sizeof lbuf);
581 status_func[k][(*cp)++] =
582 status_user0;
583 break;
584 case 'H':
585 my_strmcat(lbuf, "%s", sizeof lbuf);
586 status_func[k][(*cp)++] =
587 status_hold;
588 break;
589 case 'B':
590 new_free(&hold_lines_format);
591 hold_lines_format =
592 convert_sub_format(get_string_var(STATUS_HOLD_LINES_VAR), 'B');
593 my_strmcat(lbuf, "%s", sizeof lbuf);
594 status_func[k][(*cp)++] =
595 status_hold_lines;
596 break;
597 case 'P':
598 my_strmcat(lbuf, "%s", sizeof lbuf);
599 status_func[k][(*cp)++] =
600 status_scrolled;
601 Debug(DB_STATUS, "got P in status");
602 break;
603 case 's':
604 new_free(&scrolled_lines_format);
605 scrolled_lines_format =
606 convert_sub_format(get_string_var(STATUS_SCROLLED_LINES_VAR), 's');
607 my_strmcat(lbuf, "%s", sizeof lbuf);
608 status_func[k][(*cp)++] =
609 status_scrolled_lines;
610 Debug(DB_STATUS, "got s status: slformat '%s'",
611 scrolled_lines_format);
612 break;
613 case '*':
614 my_strmcat(lbuf, "%s", sizeof lbuf);
615 status_func[k][(*cp)++] =
616 status_oper;
617 break;
618 case 'v':
619 my_strmcat(lbuf, "%s", sizeof lbuf);
620 status_func[k][(*cp)++] =
621 status_voice;
622 break;
623 case 'W':
624 my_strmcat(lbuf, "%s", sizeof lbuf);
625 status_func[k][(*cp)++] =
626 status_window;
627 break;
628 case 'X':
629 my_strmcat(lbuf, "%s", sizeof lbuf);
630 status_func[k][(*cp)++] =
631 status_user1;
632 break;
633 case 'Y':
634 my_strmcat(lbuf, "%s", sizeof lbuf);
635 status_func[k][(*cp)++] =
636 status_user2;
637 break;
638 case 'Z':
639 my_strmcat(lbuf, "%s", sizeof lbuf);
640 status_func[k][(*cp)++] =
641 status_user3;
642 break;
643 /* no default..?? - phone, jan 1993 */
644 /* empty is a good default -lynx, mar 93 */
645 }
646 }
647 else
648 ptr++;
649 }
650 else
651 my_strmcat(lbuf, format, sizeof lbuf);
652 format = ptr;
653 }
654 /* this frees the old str first */
655 malloc_strcpy(&malloc_ptr, lbuf);
656 return (malloc_ptr);
657 }
658
659 void
build_status(u_char * format)660 build_status(u_char *format)
661 {
662 int i, k;
663
664 for (k = 0; k < 3; k++)
665 {
666 new_free(&status_format[k]);
667 func_cnt[k] = 0;
668 switch (k)
669 {
670 case 0 :
671 format = get_string_var(STATUS_FORMAT_VAR);
672 break;
673
674 case 1 :
675 format = get_string_var(STATUS_FORMAT1_VAR);
676 break;
677
678 case 2 :
679 format = get_string_var(STATUS_FORMAT2_VAR);
680 break;
681 }
682 if (format != NULL) /* convert_format mallocs for us */
683 status_format[k] = convert_format(format, k);
684 for (i = func_cnt[k]; i < MAX_FUNCTIONS; i++)
685 status_func[k][i] = status_null_function;
686 }
687 update_all_status();
688 }
689
690 void
make_status(Window * window)691 make_status(Window *window)
692 {
693 int k, l, final;
694
695 switch (window_get_double_status(window)) {
696 case -1:
697 window_set_status_line(window, 0, NULL);
698 window_set_status_line(window, 1, NULL);
699 goto out;
700 case 0:
701 window_set_status_line(window, 1, NULL);
702 final = 1;
703 break;
704 case 1:
705 final = 2;
706 break;
707 default:
708 yell("--- make_status: unknown window->double value %d",
709 window_get_double_status(window));
710 final = 1;
711 }
712 for (k = 0 ; k < final; k++)
713 {
714 if (k)
715 l = 2;
716 else if (window_get_double_status(window))
717 l = 1;
718 else
719 l = 0;
720
721 if (!term_basic() && status_format[l])
722 make_status_one(window, k, l);
723 }
724 out:
725 cursor_to_input();
726 }
727
728 static void
make_status_one(Window * window,int k,int l)729 make_status_one(Window *window, int k, int l)
730 {
731 Screen *old_current_screen;
732 u_char lbuf[BIG_BUFFER_SIZE]; /* XXX */
733 u_char rbuf[BIG_BUFFER_SIZE]; /* XXX */
734 u_char *func_value[MAX_FUNCTIONS];
735 size_t len;
736 int i;
737 int rjustifypos;
738 int justifypadlen;
739 int RealPosition;
740
741 /*
742 * XXX: note that this code below depends on the definition
743 * of MAX_FUNCTIONS (currently 45), and the snprintf must
744 * be updated if MAX_FUNCTIONS is changed.
745 */
746 for (i = 0; i < MAX_FUNCTIONS; i++)
747 func_value[i] = (status_func[l][i]) (window);
748 lbuf[0] = REV_TOG;
749 snprintf(CP(lbuf+1),
750 sizeof(lbuf) - 1,
751 CP(status_format[l]),
752 func_value[0], func_value[1], func_value[2],
753 func_value[3], func_value[4], func_value[5],
754 func_value[6], func_value[7], func_value[8],
755 func_value[9], func_value[10], func_value[11],
756 func_value[12], func_value[13], func_value[14],
757 func_value[15], func_value[16], func_value[17],
758 func_value[18], func_value[19], func_value[20],
759 func_value[21], func_value[22], func_value[23],
760 func_value[24], func_value[25], func_value[26],
761 func_value[27], func_value[28], func_value[29],
762 func_value[30], func_value[31], func_value[32],
763 func_value[33], func_value[34], func_value[35],
764 func_value[36], func_value[37], func_value[38],
765 func_value[39], func_value[40], func_value[41],
766 func_value[42], func_value[43], func_value[44]);
767 for (i = 0; i < MAX_FUNCTIONS; i++)
768 new_free(&(func_value[i]));
769
770 /* Patched 26-Mar-93 by Aiken
771 * make_window now right-justifies everything after a %>
772 */
773
774 rjustifypos = -1;
775 justifypadlen = 0;
776 for (i = 0; lbuf[i]; i++)
777 {
778 /* formfeed is a marker for left/right border*/
779 if (lbuf[i] == '\f')
780 {
781 int len_left;
782 int len_right;
783
784 /* Split the line to left and right part */
785 lbuf[i] = '\0';
786
787 /*
788 * Get lengths of left and right part in number of
789 * columns
790 */
791 len_right = my_strlen_c(lbuf);
792 len_left = my_strlen_c(lbuf+i+1);
793
794 justifypadlen = get_co() - len_right - len_left;
795
796 if (justifypadlen < 0)
797 justifypadlen = 0;
798
799 /* Delete the marker. */
800 my_strcpy(lbuf+i, lbuf+i+1);
801
802 rjustifypos = i;
803 }
804 }
805
806 if (get_int_var(FULL_STATUS_LINE_VAR))
807 {
808 if (rjustifypos == -1)
809 {
810 int length = my_strlen_c(lbuf);
811
812 justifypadlen = get_co() - length;
813 if (justifypadlen < 0)
814 justifypadlen = 0;
815 rjustifypos = my_strlen(lbuf);
816 }
817 if (justifypadlen > 0)
818 {
819 /* Move a part of the data out of way */
820 memmove(lbuf + rjustifypos + justifypadlen,
821 lbuf + rjustifypos,
822 my_strlen(lbuf) - rjustifypos + 1);
823 // +1 = zero terminator
824
825 /* Then fill the part with spaces */
826 memset(lbuf + rjustifypos, ' ', justifypadlen);
827 }
828 }
829
830 len = my_strlen(lbuf);
831 if (len > (sizeof(lbuf) - 2))
832 len = sizeof(lbuf) - 2;
833 lbuf[len] = ALL_OFF;
834 lbuf[len+1] = '\0';
835
836 my_strcpy_ci(rbuf, sizeof rbuf, lbuf);
837
838 RealPosition = 0;
839 i = 0;
840
841 old_current_screen = get_current_screen();
842 set_current_screen(window_get_screen(window));
843 term_move_cursor(RealPosition, window_get_bottom(window) + k);
844 len = output_line(rbuf, i);
845 cursor_in_display();
846 #ifdef TERM_USE_LAST_COLUMN
847 /*
848 * If ignoring the last column, always erase it, but
849 * if it is in use, only do so if we haven't writtten
850 * there.
851 */
852 if (len < get_co() && term_clear_to_eol())
853 #else
854 if (term_clear_to_eol() && len < get_co())
855 #endif
856 term_space_erase(get_co() - len);
857 window_set_status_line(window, k, rbuf);
858 set_current_screen(old_current_screen);
859 }
860
861 static u_char *
status_nickname(Window * window)862 status_nickname(Window *window)
863 {
864 u_char *ptr = NULL;
865
866 if (connected_to_server() == 1 && !get_int_var(SHOW_STATUS_ALL_VAR) &&
867 !window_get_current_channel(window) && !window_is_current(window))
868 malloc_strcpy(&ptr, empty_string());
869 else
870 malloc_strcpy(&ptr,
871 server_get_nickname(window_get_server(window)));
872 return ptr;
873 }
874
875 static u_char *
status_server(Window * window)876 status_server(Window *window)
877 {
878 u_char *ptr = NULL,
879 *rest,
880 *name;
881
882 if (connected_to_server() != 1)
883 {
884 int server = window_get_server(window);
885
886 if (server != -1)
887 {
888 if (server_format)
889 {
890 name = server_get_name(server);
891 rest = my_index(name, '.');
892 if (rest != NULL &&
893 my_strnicmp(name, UP("irc"), 3) != 0 &&
894 my_strnicmp(name, UP("icb"), 3) != 0 &&
895 !is_number(name))
896 {
897 *rest = '\0';
898 malloc_snprintf(&ptr, CP(server_format), name);
899 *rest = '.';
900 }
901 else
902 malloc_snprintf(&ptr, CP(server_format), name);
903 }
904 }
905 else
906 malloc_strcpy(&ptr, UP(" No Server"));
907 }
908 if (ptr == NULL)
909 malloc_strcpy(&ptr, empty_string());
910 return ptr;
911 }
912
913 static u_char *
status_group(Window * window)914 status_group(Window *window)
915 {
916 u_char *ptr = NULL;
917 int group;
918
919 group = window_get_server_group(window);
920 if (group && group_format)
921 malloc_snprintf(&ptr, CP(group_format), find_server_group_name(group));
922 else
923 malloc_strcpy(&ptr, empty_string());
924 return ptr;
925 }
926
927 static u_char *
status_query_nick(Window * window)928 status_query_nick(Window *window)
929 {
930 u_char *ptr = NULL;
931
932 if (window_get_query_nick(window) && query_format)
933 malloc_snprintf(&ptr, CP(query_format), window_get_query_nick(window));
934 else
935 malloc_strcpy(&ptr, empty_string());
936 return ptr;
937 }
938
939 static u_char *
status_right_justify(Window * window)940 status_right_justify(Window *window)
941 {
942 u_char *ptr = NULL;
943
944 malloc_strcpy(&ptr, UP("\f"));
945 return ptr;
946 }
947
948 static u_char *
status_notify_windows(Window * window)949 status_notify_windows(Window *window)
950 {
951 u_char refnum[10];
952 int doneone = 0;
953 u_char *ptr = NULL;
954 u_char buf2[81];
955
956 if (get_int_var(SHOW_STATUS_ALL_VAR) || window_is_current(window))
957 {
958 Win_Trav wt;
959
960 buf2[0] = '\0';
961 wt.init = 1;
962 while ((window = window_traverse(&wt)) != NULL)
963 {
964 if (window_get_miscflags(window) & WINDOW_NOTIFIED)
965 {
966 if (!doneone)
967 {
968 doneone++;
969 snprintf(CP(refnum), sizeof refnum,
970 "%d", window_get_refnum(window));
971 }
972 else
973 snprintf(CP(refnum), sizeof refnum,
974 ",%d", window_get_refnum(window));
975 my_strmcat(buf2, refnum, sizeof buf2);
976 }
977 }
978 }
979 if (doneone && notify_format)
980 malloc_snprintf(&ptr, CP(notify_format), buf2);
981 else
982 malloc_strcpy(&ptr, empty_string());
983 return ptr;
984 }
985
986 static u_char *
status_clock(Window * window)987 status_clock(Window *window)
988 {
989 u_char *ptr = NULL;
990
991 if (get_int_var(CLOCK_VAR) && clock_format &&
992 (get_int_var(SHOW_STATUS_ALL_VAR) || window_is_current(window)))
993 {
994 u_char time_str[16];
995
996 malloc_snprintf(&ptr, CP(clock_format),
997 update_clock(time_str, sizeof time_str, GET_TIME));
998 }
999 else
1000 malloc_strcpy(&ptr, empty_string());
1001 return ptr;
1002 }
1003
1004 static u_char *
status_mode(Window * window)1005 status_mode(Window *window)
1006 {
1007 u_char *ptr = NULL;
1008 u_char *channel = window_get_current_channel(window);
1009 int server = window_get_server(window);
1010
1011 if (channel && chan_is_connected(channel, server))
1012 {
1013 u_char *mode;
1014
1015 mode = get_channel_mode(channel, server);
1016 if (mode && *mode && mode_format)
1017 {
1018 malloc_snprintf(&ptr, CP(mode_format), mode);
1019 return ptr;
1020 }
1021 }
1022 malloc_strcpy(&ptr, empty_string());
1023 return ptr;
1024 }
1025
1026
1027 static u_char *
status_umode(Window * window)1028 status_umode(Window *window)
1029 {
1030 u_char *ptr = NULL;
1031 u_char localbuf[10];
1032 u_char *c;
1033 int server = window_get_server(window);
1034
1035 if (connected_to_server() == 0)
1036 malloc_strcpy(&ptr, empty_string());
1037 else if (connected_to_server() == 1 &&
1038 !get_int_var(SHOW_STATUS_ALL_VAR) &&
1039 !window_is_current(window))
1040 malloc_strcpy(&ptr, empty_string());
1041 else
1042 {
1043 c = localbuf;
1044 if (server_get_flag(server, USER_MODE_I))
1045 *c++ = 'i';
1046 if (server_get_operator(server))
1047 *c++ = 'o';
1048 if (server_get_flag(server, USER_MODE_R))
1049 *c++ = 'r';
1050 if (server_get_flag(server, USER_MODE_S))
1051 *c++ = 's';
1052 if (server_get_flag(server, USER_MODE_W))
1053 *c++ = 'w';
1054 if (server_get_flag(server, USER_MODE_Z))
1055 *c++ = 'z';
1056 *c++ = '\0';
1057 if (*localbuf != '\0' && umode_format)
1058 malloc_snprintf(&ptr, CP(umode_format), localbuf);
1059 else
1060 malloc_strcpy(&ptr, empty_string());
1061 }
1062 return ptr;
1063 }
1064
1065 static u_char *
status_chanop(Window * window)1066 status_chanop(Window *window)
1067 {
1068 u_char *ptr = NULL,
1069 *text;
1070 u_char *channel = window_get_current_channel(window);
1071 int server = window_get_server(window);
1072
1073 if (channel &&
1074 chan_is_connected(channel, server) &&
1075 get_channel_oper(channel, server) &&
1076 (text = get_string_var(STATUS_CHANOP_VAR)))
1077 malloc_strcpy(&ptr, text);
1078 else
1079 malloc_strcpy(&ptr, empty_string());
1080 return ptr;
1081 }
1082
1083
1084 static u_char *
status_hold_lines(Window * window)1085 status_hold_lines(Window *window)
1086 {
1087 u_char *ptr = NULL;
1088 int num;
1089 int lines = window_held_lines(window);
1090
1091 num = lines - lines % 10;
1092 if (num)
1093 {
1094 u_char localbuf[40];
1095
1096 snprintf(CP(localbuf), sizeof localbuf, "%d", num);
1097 malloc_snprintf(&ptr, CP(hold_lines_format), localbuf);
1098 }
1099 else
1100 malloc_strcpy(&ptr, empty_string());
1101 return ptr;
1102 }
1103
1104 static u_char *
status_scrolled(Window * window)1105 status_scrolled(Window *window)
1106 {
1107 u_char *ptr = NULL,
1108 *text;
1109 int lines = window_get_all_scrolled_lines(window);
1110
1111 Debug(DB_STATUS, "status_scrolled: lines = %d", lines);
1112 if (lines && (text = get_string_var(STATUS_SCROLLED_VAR)))
1113 malloc_strcpy(&ptr, text);
1114 else
1115 malloc_strcpy(&ptr, empty_string());
1116 return ptr;
1117 }
1118
1119 static u_char *
status_scrolled_lines(Window * window)1120 status_scrolled_lines(Window *window)
1121 {
1122 u_char *ptr = NULL;
1123 int lines = window_get_all_scrolled_lines(window);
1124
1125 if (lines)
1126 {
1127 u_char localbuf[40];
1128
1129 snprintf(CP(localbuf), sizeof localbuf, "%d", lines);
1130 malloc_snprintf(&ptr, CP(hold_lines_format), localbuf);
1131 }
1132 else
1133 malloc_strcpy(&ptr, empty_string());
1134 Debug(DB_STATUS, "status_scrolled_lines: lines = %d, str = '%s'", lines, ptr);
1135 return ptr;
1136 }
1137
1138 static u_char *
status_channel(Window * window)1139 status_channel(Window *window)
1140 {
1141 int num;
1142 u_char *s, *ptr;
1143 int server = window_get_server(window);
1144
1145 s = window_get_current_channel(window);
1146 if (s && chan_is_connected(s, server))
1147 {
1148 u_char channel[IRCD_BUFFER_SIZE + 1];
1149
1150 if (get_int_var(HIDE_PRIVATE_CHANNELS_VAR) &&
1151 is_channel_mode(window_get_current_channel(window),
1152 MODE_PRIVATE | MODE_SECRET, server))
1153 ptr = UP("*private*");
1154 else
1155 ptr = window_get_current_channel(window);
1156 strmcpy(channel, ptr, IRCD_BUFFER_SIZE);
1157 if ((num = get_int_var(CHANNEL_NAME_WIDTH_VAR)) &&
1158 ((int) my_strlen(channel) > num))
1159 channel[num] = '\0';
1160 ptr = NULL;
1161 malloc_snprintf(&ptr, CP(channel_format), channel);
1162 }
1163 else
1164 {
1165 ptr = NULL;
1166 malloc_strcpy(&ptr, empty_string());
1167 }
1168 return ptr;
1169 }
1170
1171 static u_char *
status_mail(Window * window)1172 status_mail(Window *window)
1173 {
1174 u_char *ptr = NULL,
1175 *number;
1176
1177 if (get_int_var(MAIL_VAR) && (number = check_mail()) && mail_format &&
1178 (get_int_var(SHOW_STATUS_ALL_VAR) || window_is_current(window)))
1179 malloc_snprintf(&ptr, CP(mail_format), number);
1180 else
1181 malloc_strcpy(&ptr, empty_string());
1182 return ptr;
1183 }
1184
1185 static u_char *
status_insert_mode(Window * window)1186 status_insert_mode(Window *window)
1187 {
1188 u_char *ptr = NULL,
1189 *text;
1190
1191 text = empty_string();
1192 if (get_int_var(INSERT_MODE_VAR) &&
1193 (get_int_var(SHOW_STATUS_ALL_VAR) || window_is_current(window)))
1194 {
1195 if ((text = get_string_var(STATUS_INSERT_VAR)) == NULL)
1196 text = empty_string();
1197 }
1198 malloc_strcpy(&ptr, text);
1199 return ptr;
1200 }
1201
1202 static u_char *
status_overwrite_mode(Window * window)1203 status_overwrite_mode(Window *window)
1204 {
1205 u_char *ptr = NULL,
1206 *text;
1207
1208 text = empty_string();
1209 if (!get_int_var(INSERT_MODE_VAR) &&
1210 (get_int_var(SHOW_STATUS_ALL_VAR) || window_is_current(window)))
1211 {
1212 if ((text = get_string_var(STATUS_OVERWRITE_VAR)) == NULL)
1213 text = empty_string();
1214 }
1215 malloc_strcpy(&ptr, text);
1216 return ptr;
1217 }
1218
1219 static u_char *
status_away(Window * window)1220 status_away(Window *window)
1221 {
1222 u_char *ptr = NULL,
1223 *text;
1224
1225 if (connected_to_server() == 0)
1226 malloc_strcpy(&ptr, empty_string());
1227 else if (connected_to_server() == 1 &&
1228 !get_int_var(SHOW_STATUS_ALL_VAR) &&
1229 !window_is_current(window))
1230 malloc_strcpy(&ptr, empty_string());
1231 else
1232 {
1233 if (server_get_away(window_get_server(window)) &&
1234 (text = get_string_var(STATUS_AWAY_VAR)))
1235 malloc_strcpy(&ptr, text);
1236 else
1237 malloc_strcpy(&ptr, empty_string());
1238 }
1239 return ptr;
1240 }
1241
1242 static u_char *
status_user0(Window * window)1243 status_user0(Window *window)
1244 {
1245 u_char *ptr = NULL,
1246 *text;
1247
1248 if ((text = get_string_var(STATUS_USER_VAR)) &&
1249 (get_int_var(SHOW_STATUS_ALL_VAR) || window_is_current(window)))
1250 malloc_strcpy(&ptr, text);
1251 else
1252 malloc_strcpy(&ptr, empty_string());
1253 return ptr;
1254 }
1255
1256 static u_char *
status_user1(Window * window)1257 status_user1(Window *window)
1258 {
1259 u_char *ptr = NULL,
1260 *text;
1261
1262 if ((text = get_string_var(STATUS_USER1_VAR)) &&
1263 (get_int_var(SHOW_STATUS_ALL_VAR) || window_is_current(window)))
1264 malloc_strcpy(&ptr, text);
1265 else
1266 malloc_strcpy(&ptr, empty_string());
1267 return ptr;
1268 }
1269
1270 static u_char *
status_user2(Window * window)1271 status_user2(Window *window)
1272 {
1273 u_char *ptr = NULL,
1274 *text;
1275
1276 if ((text = get_string_var(STATUS_USER2_VAR)) &&
1277 (get_int_var(SHOW_STATUS_ALL_VAR) || window_is_current(window)))
1278 malloc_strcpy(&ptr, text);
1279 else
1280 malloc_strcpy(&ptr, empty_string());
1281 return ptr;
1282 }
1283
1284 static u_char *
status_user3(Window * window)1285 status_user3(Window *window)
1286 {
1287 u_char *ptr = NULL,
1288 *text;
1289
1290 if ((text = get_string_var(STATUS_USER3_VAR)) &&
1291 (get_int_var(SHOW_STATUS_ALL_VAR) || window_is_current(window)))
1292 malloc_strcpy(&ptr, text);
1293 else
1294 malloc_strcpy(&ptr, empty_string());
1295 return ptr;
1296 }
1297
1298 static u_char *
status_hold(Window * window)1299 status_hold(Window *window)
1300 {
1301 u_char *ptr = NULL,
1302 *text;
1303
1304 if (window_held(window) && (text = get_string_var(STATUS_HOLD_VAR)))
1305 malloc_strcpy(&ptr, text);
1306 else
1307 malloc_strcpy(&ptr, empty_string());
1308 return ptr;
1309 }
1310
1311 static u_char *
status_oper(Window * window)1312 status_oper(Window *window)
1313 {
1314 u_char *ptr = NULL,
1315 *text;
1316
1317 if (!connected_to_server())
1318 malloc_strcpy(&ptr, empty_string());
1319 else if (server_get_operator(window_get_server(window)) &&
1320 (text = get_string_var(STATUS_OPER_VAR)) &&
1321 (get_int_var(SHOW_STATUS_ALL_VAR) ||
1322 connected_to_server() != 1 ||
1323 window_is_current(window)))
1324 malloc_strcpy(&ptr, text);
1325 else
1326 malloc_strcpy(&ptr, empty_string());
1327 return ptr;
1328 }
1329
1330 static u_char *
status_voice(Window * window)1331 status_voice(Window *window)
1332 {
1333 u_char *ptr = NULL,
1334 *text;
1335 int server = window_get_server(window);
1336
1337 if (!connected_to_server())
1338 malloc_strcpy(&ptr, empty_string());
1339 else if (has_voice(window_get_current_channel(window),
1340 server_get_nickname(server),
1341 server) &&
1342 (text = get_string_var(STATUS_VOICE_VAR)) &&
1343 (get_int_var(SHOW_STATUS_ALL_VAR) ||
1344 connected_to_server() != 1 || window_is_current(window)))
1345 malloc_strcpy(&ptr, text);
1346 else
1347 malloc_strcpy(&ptr, empty_string());
1348 return ptr;
1349 }
1350
1351 static u_char *
status_window(Window * window)1352 status_window(Window *window)
1353 {
1354 u_char *ptr = NULL,
1355 *text;
1356
1357 if ((text = get_string_var(STATUS_WINDOW_VAR)) &&
1358 number_of_windows() > 1 && window_is_current(window))
1359 malloc_strcpy(&ptr, text);
1360 else
1361 malloc_strcpy(&ptr, empty_string());
1362 return ptr;
1363 }
1364
1365 static u_char *
status_refnum(Window * window)1366 status_refnum(Window *window)
1367 {
1368 u_char *ptr = NULL;
1369 u_char *name = window_get_name(window);
1370
1371 if (name)
1372 malloc_strcpy(&ptr, name);
1373 else
1374 malloc_snprintf(&ptr, "%u", window_get_refnum(window));
1375 return ptr;
1376 }
1377
1378 static u_char *
status_version(Window * window)1379 status_version(Window *window)
1380 {
1381 u_char *ptr = NULL;
1382
1383 if (connected_to_server() == 1 && !get_int_var(SHOW_STATUS_ALL_VAR) &&
1384 !window_is_current(window))
1385 malloc_strcpy(&ptr, empty_string());
1386 else
1387 malloc_strcpy(&ptr, irc_version());
1388 return ptr;
1389 }
1390
1391 static u_char *
status_null_function(Window * window)1392 status_null_function(Window *window)
1393 {
1394 u_char *ptr = NULL;
1395
1396 malloc_strcpy(&ptr, empty_string());
1397 return ptr;
1398 }
1399