1 /*
2 * help.c: handles the help stuff for irc
3 *
4 * Written by Michael Sandrof, Troy Rollo and Matthew R. Green.
5 *
6 * Copyright (c) 1990 Michael Sandrof.
7 * Copyright (c) 1991, 1992 Troy Rollo.
8 * Copyright (c) 1992-2017 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: help.c,v 1.108 2017/07/09 06:58:07 mrg Exp $");
37
38 #include <dirent.h>
39 #define NLENGTH(d) (my_strlen((d)->d_name)
40
41 #include <sys/stat.h>
42
43 #include "ircterm.h"
44 #include "server.h"
45 #include "vars.h"
46 #include "ircaux.h"
47 #include "input.h"
48 #include "window.h"
49 #include "screen.h"
50 #include "output.h"
51 #include "help.h"
52 #include "scandir.h"
53 #include "sl_irc.h"
54
55 #ifdef ALPHASORT_VOID_ARG
56 typedef const void *compar_type;
57 #else
58 typedef const struct dirent **compar_type;
59 #endif
60
61 static void help_me(u_char *, u_char *);
62 static void help_show_paused_topic(u_char *, u_char *);
63 static void create_help_window(void);
64 static void set_help_screen(Screen *);
65 static int compar(compar_type, compar_type);
66 static int selectent(const struct dirent *);
67 static int show_help(Window *, u_char *);
68 static void help_prompt_format_add(void);
69 static void help_no_help(u_char *);
70 static void help_prompt(u_char *, u_char *);
71 static void help_topic(u_char *, u_char *);
72
73 static Window *help_window = NULL;
74 static FILE *help_fp;
75 static u_char no_help[] = "NOHELP";
76 static int entry_size;
77 static u_char *this_arg;
78 static int finished_help_paging = 0;
79 static int help_show_directory = 0;
80 static int dont_pause_topic = 0;
81 static Screen *help_screen = NULL;
82 static u_char paused_topic[128];
83 static u_char *help_topic_list = NULL;
84 static int use_help_window = 0;
85 static StringList *help_paused_lines;
86
87 /* we are piglet */
88
89 /* compar: used by scandir to alphabetize the help entries */
90 static int
compar(compar_type p1,compar_type p2)91 compar(compar_type p1, compar_type p2)
92 {
93 const struct dirent *e1 = *(const struct dirent **)p1;
94 const struct dirent *e2 = *(const struct dirent **)p2;
95
96 return (my_stricmp((u_char *)e1->d_name, (u_char *)e2->d_name));
97 }
98
99 /*
100 * selectent: used by scandir to decide which entries to include in the help
101 * listing.
102 */
103 static int
selectent(const struct dirent * entry)104 selectent(const struct dirent *entry)
105 {
106 if (*(entry->d_name) == '.')
107 return (0);
108 if (my_strnicmp((u_char *)entry->d_name, this_arg, my_strlen(this_arg)))
109 return (0);
110 else
111 {
112 int len = my_strlen(entry->d_name);
113 #ifdef ZCAT
114 const char *temp;
115
116 /*
117 * Handle major length of filename is case of suffix .Z:
118 * stripping suffix length
119 */
120 temp = &(entry->d_name[len - my_strlen(ZSUFFIX)]);
121 if (!my_strcmp(temp, ZSUFFIX))
122 len -= my_strlen(ZSUFFIX);
123 #endif /* ZCAT */
124 entry_size = (len > entry_size) ? len : entry_size;
125 return (1);
126 }
127 }
128
129 /*
130 * show_help: show's either a page of text from a help_fp, or the whole
131 * thing, depending on the value of HELP_PAGER_VAR. If it gets to the end,
132 * (in either case it will eventally), it closes the file, and returns 0
133 * to indicate this.
134 */
135 static int
show_help(Window * window,u_char * name)136 show_help(Window *window, u_char *name)
137 {
138 int rows = 0;
139 u_char line[81];
140
141 if (!help_fp)
142 return (0);
143 if (window)
144 {
145 set_curr_scr_win(window);
146 }
147 else
148 {
149 window = curr_scr_win;
150 }
151 if (get_int_var(HELP_PAGER_VAR))
152 rows = window_get_display_size(window);
153 while (--rows)
154 {
155 if (fgets(CP(line), 80, help_fp))
156 {
157 u_char *p = line + my_strlen(line) - 1;
158
159 if (*p == '\n')
160 *p = '\0';
161
162 if (*line != '!' && *line != '#')
163 help_put_it(name, "%s", line);
164 else
165 rows++;
166 }
167 else
168 return (0);
169 }
170 return (1);
171 }
172
173 /*
174 * help_prompt_format_add: format the help prompt and add it to the
175 * wait list.
176 */
177 static void
help_prompt_format_add(void)178 help_prompt_format_add(void)
179 {
180 u_char *tmp = NULL,
181 *list;
182
183 if (term_basic())
184 return;
185
186 if (help_topic_list)
187 list = help_topic_list;
188 else
189 list = empty_string();
190 malloc_snprintf(&tmp, "%s%sHelp? ", list, *list ? " " : "");
191 add_wait_prompt(tmp, help_me, list, WAIT_PROMPT_LINE);
192 new_free(&tmp);
193 }
194
195 static void
help_no_help(u_char * name)196 help_no_help(u_char *name)
197 {
198 help_put_it(name, "*** No help available on %s: Use ? "
199 "for list of topics", name);
200 }
201
202 /*
203 * help_prompt: The main procedure called to display the help file
204 * currently being accessed. Using add_wait_prompt(), it sets it
205 * self up to be recalled when the next page is asked for. If
206 * called when we have finished paging the help file, we exit, as
207 * there is nothing left to show. If line is 'q' or 'Q', exit the
208 * help pager, clean up, etc.. If all is cool for now, we call
209 * show_help, and either if its finished, exit, or prompt for the
210 * next page. From here, if we've finished the help page, and
211 * doing help prompts, prompt for the help..
212 */
213
214 static void
help_prompt(u_char * name,u_char * line)215 help_prompt(u_char *name, u_char *line)
216 {
217 if (finished_help_paging)
218 {
219 if (*paused_topic)
220 help_show_paused_topic(paused_topic, NULL);
221 return;
222 }
223
224 if (line && ((*line == 'q') || (*line == 'Q')))
225 {
226 finished_help_paging = 1;
227 if (help_fp)
228 {
229 fclose(help_fp);
230 help_fp = NULL;
231 }
232 set_help_screen(NULL);
233 return;
234 }
235
236 if (show_help(help_window, name))
237 if (term_basic())
238 help_prompt(name, NULL);
239 else
240 add_wait_prompt(UP("*** Hit any key for more, 'q' to quit ***"),
241 help_prompt, name, WAIT_PROMPT_KEY);
242 else
243 {
244 finished_help_paging = 1;
245 if (help_fp)
246 {
247 fclose(help_fp);
248 help_fp = NULL;
249 }
250 if (help_show_directory)
251 {
252 if (get_int_var(HELP_PAGER_VAR))
253 if (term_basic())
254 help_show_paused_topic(paused_topic, NULL);
255 else
256 add_wait_prompt(UP("*** Hit any key to end ***"),
257 help_show_paused_topic, paused_topic,
258 WAIT_PROMPT_KEY);
259 else
260 {
261 help_show_paused_topic(paused_topic, NULL);
262 set_help_screen(NULL);
263 }
264 help_show_directory = 0;
265 return;
266 }
267 }
268
269 if (finished_help_paging)
270 {
271 if (get_int_var(HELP_PROMPT_VAR))
272 help_prompt_format_add();
273 else
274 {
275 if (*paused_topic)
276 help_show_paused_topic(paused_topic, NULL);
277 set_help_screen(NULL);
278 }
279 }
280 }
281
282 /*
283 * help_topic: Given a topic, we search the help directory, and try to
284 * find the right file, if all is cool, and we can open it, or zcat it,
285 * then we call help_prompt to get the actually displaying of the file
286 * on the road.
287 */
288 static void
help_topic(u_char * path,u_char * name)289 help_topic(u_char *path, u_char *name)
290 {
291 struct stat sb;
292 u_char *filename = NULL;
293 #ifdef ZCAT
294 int do_zcat = 0;
295 #endif /* ZCAT */
296
297 if (name == NULL)
298 return;
299
300 Debug(DB_HELP, "path %s, name %s", path, name);
301 /*
302 * Check the existence of <name> or <name>.Z .. Handle suffix
303 * .Z if present. Open the file if it isn't present, zcat the
304 * file if it is present, and ends with .Z ..
305 */
306
307 malloc_snprintf(&filename, "%s/%s", path, name);
308
309 if (stat(CP(filename), &sb) == -1)
310 {
311 #ifdef ZCAT
312 if (my_strcmp(name + (my_strlen(name) - my_strlen(ZSUFFIX)), ZSUFFIX))
313 {
314 malloc_snprintf(&filename, "%s/%s%s", path, name, ZSUFFIX);
315 if (stat(CP(filename), &sb) == -1)
316 {
317 new_free(&filename);
318 goto no_help_found;
319 }
320 }
321 else
322 #endif /* ZCAT */
323 goto no_help_found;
324 }
325
326 if (my_strcmp(filename + (my_strlen(filename) - my_strlen(ZSUFFIX)), ZSUFFIX) == 0)
327 do_zcat = 1;
328
329 if (!filename)
330 goto no_help_found;
331
332 if (sb.st_mode & S_IFDIR)
333 return;
334
335 if (help_fp)
336 fclose(help_fp);
337 #ifdef ZCAT
338 if (!do_zcat)
339 {
340 #endif /* ZCAT */
341
342 if ((help_fp = fopen(CP(filename), "r")) == NULL)
343 goto no_help_found;
344 #ifdef ZCAT
345 }
346 else
347 {
348 if ((help_fp = zcat(filename)) == NULL)
349 goto no_help_found;
350 }
351 #endif /* ZCAT */
352
353 /*
354 * Hopefully now we have got a file descriptor <help_fp>, a name
355 * so we start displaying the help file, calling help_prompt for
356 * the first time.
357 */
358
359 new_free(&filename);
360 help_put_it(name, "*** Help on %s", name);
361 help_prompt(name, NULL);
362
363 return;
364
365 no_help_found:
366 new_free(&filename);
367 help_no_help(name);
368 }
369
370 /*
371 * help_pause_add_line: this procedure does a help_put_it() call, but
372 * puts off the calling, until help_show_paused_topic() is called.
373 * I do this because I need to create the list of help topics, but
374 * not show them, until we've seen the whole file, so we called
375 * help_show_paused_topic() when we've seen the file, if it is needed.
376 */
377
378 static void
help_pause_add_line(char * format,...)379 help_pause_add_line(char *format, ...)
380 {
381 va_list vl;
382
383 u_char *copy = NULL;
384
385 va_start(vl, format);
386 malloc_vsnprintf(©, format, vl);
387 va_end(vl);
388 if (!help_paused_lines)
389 help_paused_lines = sl_init();
390 sl_add(help_paused_lines, CP(copy));
391 }
392
393 /*
394 * help_show_paused_topic: see above. Called when we've seen the
395 * whole help file, and we have a list of topics to display.
396 */
397 static void
help_show_paused_topic(u_char * name,u_char * unused)398 help_show_paused_topic(u_char *name, u_char *unused)
399 {
400 size_t iter;
401 u_char *line;
402
403 if (!help_paused_lines)
404 return;
405 for (iter = 0; (line = sl_iter_fwd(help_paused_lines, &iter)) != NULL;)
406 help_put_it(name, "%s", line);
407 if (get_int_var(HELP_PROMPT_VAR))
408 {
409 u_char *buf = NULL;
410
411 malloc_snprintf(&buf, "%s%sHelp? ", name, (name && *name) ? " " : "");
412 if (!term_basic())
413 add_wait_prompt(buf, help_me, name, WAIT_PROMPT_LINE);
414 new_free(&buf);
415 }
416 else
417 set_help_screen(NULL);
418
419 dont_pause_topic = 0;
420 sl_free(help_paused_lines, 1);
421 help_paused_lines = NULL;
422 }
423
424 /*
425 * help_me: The big one. The help procedure that handles working out
426 * what was actually requested, sets up the paused topic list if it is
427 * needed, does pretty much all the hard work.
428 */
429 static void
help_me(u_char * topics,u_char * args)430 help_me(u_char *topics, u_char *args)
431 {
432 u_char *ptr;
433 struct dirent **namelist = NULL;
434 int entries,
435 free_cnt = 0,
436 cnt,
437 i,
438 cols;
439 struct stat sb;
440 u_char path[PATH_MAX+1];
441 int help_paused_first_call = 0;
442 u_char *help_paused_path = NULL;
443 u_char *help_paused_name = NULL;
444 u_char *temp;
445 u_char *tmp = NULL;
446 StringList *sl;
447
448 #ifdef ZCAT
449 u_char *arg_z = NULL;
450 #endif /* ZCAT */
451
452 Debug(DB_HELP, "got topics '%s' args '%s'", topics, args);
453 if (*topics)
454 malloc_strcpy(&help_topic_list, topics);
455 else
456 new_free(&help_topic_list);
457
458 #ifdef DAEMON_UID
459 if (DAEMON_UID == getuid())
460 ptr = DEFAULT_HELP_PATH;
461 else
462 #endif /* DAEMON_UID */
463 ptr = get_string_var(HELP_PATH_VAR);
464
465 snprintf(CP(path), sizeof path, "%s/%s", ptr, topics);
466 for (ptr = path; (ptr = my_index(ptr, ' '));)
467 *ptr = '/';
468
469
470 /*
471 * first we check access to the help dir, whinge if we can't, then
472 * work out we need to ask them for more help, else we check the
473 * args list, and do the stuff
474 */
475
476 if (help_show_directory)
477 {
478 help_show_paused_topic(paused_topic, NULL);
479 help_show_directory = 0;
480 }
481
482 finished_help_paging = 0;
483 if (access(CP(path), R_OK|X_OK))
484 {
485 help_put_it(no_help, "*** Cannot access help directory!");
486 set_help_screen(NULL);
487 return;
488 }
489
490 this_arg = next_arg(args, &args);
491 if (!this_arg && help_topic_list && get_int_var(HELP_PROMPT_VAR))
492 {
493 if ((temp = my_rindex(help_topic_list, ' ')) != NULL)
494 *temp = '\0';
495 else
496 new_free(&help_topic_list);
497 help_prompt_format_add();
498 return;
499 }
500
501 if (!this_arg) /* && *help_topic_list) */
502 {
503 set_help_screen(NULL);
504 return;
505 }
506
507 create_help_window();
508 while (this_arg)
509 {
510 save_message_from();
511 message_from(NULL, LOG_CURRENT);
512 if (*this_arg == '\0')
513 help_topic(path, NULL);
514 if (my_strcmp(this_arg, "?") == 0)
515 {
516 this_arg = empty_string();
517 if (!dont_pause_topic)
518 dont_pause_topic = 1;
519 }
520 entry_size = 0;
521
522 /*
523 * here we clean the namelist if it exists, and then go to
524 * work on the directory.. working out if is dead, or if we
525 * can show some help, or create the paused topic list.
526 */
527
528 if (namelist)
529 {
530 for (i = 0; i < free_cnt; i++)
531 new_free(&(namelist[i]));
532 new_free(&namelist);
533 }
534 free_cnt = entries = scandir(CP(path), &namelist,
535 selectent, compar);
536 /* special case to handle stuff like LOG and LOGFILE */
537 if (entries > 1)
538 {
539 #ifdef ZCAT
540 /* Check if exist compressed or uncompressed entries */
541 malloc_strcpy(&arg_z, this_arg);
542 malloc_strcat(&arg_z, UP(ZSUFFIX));
543 if (my_stricmp(UP(namelist[0]->d_name), arg_z) == 0 ||
544 my_stricmp(UP(namelist[0]->d_name), this_arg) == 0)
545 #else
546 if (my_stricmp(UP(namelist[0]->d_name), this_arg) == 0)
547 #endif /* ZCAT */
548 entries = 1;
549 #ifdef ZCAT
550 new_free(&arg_z);
551 #endif /* ZCAT */
552 }
553
554 /*
555 * entries: -1 means something really died, 0 means there
556 * was no help, 1, means it wasn't a directory, and so to
557 * show the help file, and the default means to add the
558 * stuff to the paused topic list..
559 */
560
561 if (help_topic_list)
562 dont_pause_topic = 1;
563 switch (entries)
564 {
565 case -1:
566 help_put_it(no_help, "*** Error during help function: %s",
567 strerror(errno));
568 set_help_screen(NULL);
569 if (help_paused_first_call)
570 {
571 help_topic(help_paused_path, help_paused_name);
572 help_paused_first_call = 0;
573 new_free(&help_paused_path);
574 new_free(&help_paused_name);
575 }
576 return;
577 case 0:
578 help_no_help(this_arg);
579 if (!get_int_var(HELP_PROMPT_VAR))
580 {
581 set_help_screen(NULL);
582 break;
583 }
584 help_prompt_format_add();
585 if (help_paused_first_call)
586 {
587 help_topic(help_paused_path, help_paused_name);
588 help_paused_first_call = 0;
589 new_free(&help_paused_path);
590 new_free(&help_paused_name);
591 }
592 for (i = 0; i < free_cnt; i++)
593 {
594 new_free(&namelist[i]);
595 }
596 break;
597 case 1:
598 malloc_snprintf(&tmp, "%s/%s", path, namelist[0]->d_name);
599 if (stat(CP(tmp), &sb) == -1)
600 {
601 for (i = 0; i < free_cnt; i++)
602 {
603 new_free(&namelist[i]);
604 }
605 new_free(&tmp);
606 restore_message_from();
607 continue;
608 }
609 if (sb.st_mode & S_IFDIR)
610 {
611 my_strmcpy(path, tmp, sizeof path);
612 if (help_topic_list)
613 malloc_snprintf(&help_topic_list,
614 "%s %s",
615 help_topic_list,
616 namelist[0]->d_name);
617 else
618 malloc_strcpy(&help_topic_list,
619 UP(namelist[0]->d_name));
620 Debug(DB_HELP, "new topic list: '%s'", help_topic_list);
621
622 if ((this_arg = next_arg(args, &args)) == NULL)
623 {
624 help_paused_first_call = 1;
625 malloc_strcpy(&help_paused_path, path);
626 malloc_strcpy(&help_paused_name,
627 UP(namelist[0]->d_name));
628 dont_pause_topic = -1;
629 this_arg = UP("?");
630 }
631 for (i = 0; i < free_cnt; i++)
632 {
633 new_free(&namelist[i]);
634 }
635 new_free(&tmp);
636 restore_message_from();
637 continue;
638 }
639 help_topic(path, UP(namelist[0]->d_name));
640 finished_help_paging = 0; /* this is a big kludge */
641 for (i = 0; i < free_cnt; i++)
642 {
643 new_free(&namelist[i]);
644 }
645 new_free(&tmp);
646 break;
647 default:
648 help_show_directory = 1;
649 my_strmcpy(paused_topic, help_topic_list ? help_topic_list : empty_string(), sizeof paused_topic);
650 help_pause_add_line("*** %s choices:", paused_topic);
651 cnt = 0;
652 sl = sl_init();
653 entry_size += 2;
654 cols = (get_co() - 10) / entry_size;
655 for (i = 0; i < entries; i++)
656 {
657 u_char *buffer = NULL;
658
659 malloc_snprintf(&buffer, "%-13s", namelist[i]->d_name);
660 #ifdef ZCAT
661 /*
662 * In tmp store the actual help choice and strip
663 * .Z suffix in compressed files: put filename
664 * (without .Z) on the help screen. If it is
665 * the first choice cat it to the buffer and
666 * save the last choice.
667 */
668 temp = &(buffer[my_strlen(buffer) - my_strlen(ZSUFFIX)]);
669 if (!my_strcmp(temp, ZSUFFIX))
670 temp[0] = '\0';
671 #endif /* ZCAT */
672 sl_add(sl, CP(buffer));
673 if (++cnt == cols)
674 {
675 buffer = sl_concat(sl, empty_string());
676 help_pause_add_line("%s", buffer);
677 new_free(&buffer);
678 sl_free(sl, 1);
679 sl = sl_init();
680 cnt = 0;
681 }
682 }
683 if (sl_size(sl) != 0)
684 {
685 u_char *buffer = sl_concat(sl, empty_string());
686 help_pause_add_line("%s", buffer);
687 new_free(&buffer);
688 }
689 sl_free(sl, 1);
690 if (help_paused_first_call)
691 {
692 help_topic(help_paused_path, help_paused_name);
693 help_paused_first_call = 0;
694 new_free(&help_paused_path);
695 new_free(&help_paused_name);
696 }
697 if (dont_pause_topic == 1)
698 {
699 help_show_paused_topic(paused_topic, NULL);
700 help_show_directory = 0;
701 }
702 break;
703 }
704 for (i = 0; i < free_cnt; i++)
705 {
706 new_free(&namelist[i]);
707 }
708 new_free(&namelist);
709 restore_message_from();
710 break;
711 }
712 /*
713 * This one is for when there was never a topic and the prompt
714 * never got a topic.. and help_screen was never reset..
715 * phone, jan 1993.
716 */
717 if (help_topic_list && finished_help_paging)
718 set_help_screen(NULL);
719 }
720
721 /*
722 * help: the HELP command, gives help listings for any and all topics out
723 * there
724 */
725 void
help(u_char * command,u_char * args,u_char * subargs)726 help(u_char *command, u_char *args, u_char *subargs)
727 {
728 u_char *help_path;
729
730 finished_help_paging = 0;
731 help_show_directory = 0;
732 dont_pause_topic = 0;
733 use_help_window = 0;
734
735 #ifdef DAEMON_UID
736 if (DAEMON_UID == getuid())
737 help_path = DEFAULT_HELP_PATH;
738 else
739 #endif /* DAEMON_UID */
740 help_path = get_string_var(HELP_PATH_VAR);
741 if (!(help_path && *help_path && !access(CP(help_path), R_OK | X_OK)))
742 {
743 if (*help_path)
744 help_put_it(no_help, "*** HELP_PATH error: %s", strerror(errno));
745 else
746 help_put_it(no_help, "*** No HELP_PATH variable set");
747 return;
748 }
749
750 /*
751 * Check that we aren't doing HELP in a more than one screen, as this
752 * really leads to seriously difficult to fix problems!. This is all
753 * due to the wildly popular /window create. blah.
754 */
755 if (help_path && help_screen && help_screen != get_current_screen())
756 {
757 say("You may not run help in two screens");
758 return;
759 }
760 help_screen = get_current_screen();
761 help_window = NULL;
762 help_me(empty_string(), (args && *args) ? args : (u_char *) "?");
763 }
764
765 static void
create_help_window(void)766 create_help_window(void)
767 {
768 if (help_window)
769 return;
770
771 if (!term_basic() && get_int_var(HELP_WINDOW_VAR))
772 {
773 use_help_window = 1;
774 help_window = new_window();
775 window_set_hold_mode(help_window, OFF);
776 update_all_windows();
777 }
778 else
779 help_window = curr_scr_win;
780 }
781
782 static void
set_help_screen(Screen * screen)783 set_help_screen(Screen *screen)
784 {
785 help_screen = screen;
786 if (!help_screen && help_window)
787 {
788 if (use_help_window)
789 {
790 unsigned display = set_display_off();
791 delete_window(help_window);
792 set_display(display);
793 }
794 help_window = NULL;
795 update_all_windows();
796 }
797 }
798