1 /* -*- mode: C; mode: fold -*- */
2 /*
3 This file is part of SLRN.
4
5 Copyright (c) 1994, 1999, 2007-2016 John E. Davis <jed@jedsoft.org>
6 Copyright (c) 2001-2006 Thomas Schultz <tststs@gmx.de>
7
8 This program is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2 of the License, or (at your option)
11 any later version.
12
13 This program is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 more details.
17
18 You should have received a copy of the GNU General Public License along
19 with this program; if not, write to the Free Software Foundation, Inc.,
20 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 */
22 #include "config.h"
23 #include "slrnfeat.h"
24 /*{{{ Include files */
25
26 #include <stdio.h>
27 #include <signal.h>
28 #include <string.h>
29
30 #ifdef HAVE_STDLIB_H
31 # include <stdlib.h>
32 #endif
33
34 #ifdef HAVE_UNISTD_H
35 # include <unistd.h>
36 #endif
37
38 #ifdef HAVE_LOCALE_H
39 # include <locale.h>
40 #endif
41
42 #ifdef VMS
43 # include "vms.h"
44 #else
45 # if !defined(sun) && !defined(IBMPC_SYSTEM)
46 # include <sys/ioctl.h>
47 # endif
48 # ifdef HAVE_TERMIOS_H
49 # include <termios.h>
50 # endif
51 # ifdef SYSV
52 # include <sys/termio.h>
53 # include <sys/stream.h>
54 # include <sys/ptem.h>
55 # include <sys/tty.h>
56 # endif
57 # ifndef __os2__
58 # include <sys/types.h>
59 # include <sys/stat.h>
60 # endif
61 # ifdef __MINGW32__
62 # include <process.h>
63 # endif
64 #endif /* !VMS */
65
66 #ifdef HAVE_SYS_WAIT_H
67 # include <sys/wait.h>
68 #endif
69
70 #include <slang.h>
71 #include "jdmacros.h"
72
73 #include <errno.h>
74
75 #include "common.h"
76 #include "util.h"
77 #include "server.h"
78 #include "slrn.h"
79 #include "group.h"
80 #include "misc.h"
81 #include "startup.h"
82 #include "art.h"
83 #include "score.h"
84 #include "snprintf.h"
85 #include "charset.h"
86 #include "post.h"
87 #include "xover.h"
88 #include "mime.h"
89 #include "hooks.h"
90 #include "strutil.h"
91
92 #if SLRN_USE_SLTCP
93 # include "sltcp.h"
94 #endif
95
96 #if SLRN_HAS_GROUPLENS
97 # include "grplens.h"
98 #endif
99 #include "interp.h"
100 #ifdef __os2__
101 # define INCL_VIO
102 # include <os2.h>
103 #endif
104
105 #if defined(__NT__) || defined(__WIN32__)
106 # include <windows.h>
107 #endif
108
109 /*}}}*/
110
111 /*{{{ Global Variables */
112
113 #if SLANG_VERSION >= 20000
114 int Slrn_UTF8_Mode = 0;
115 #endif
116
117 int Slrn_TT_Initialized = 0;
118
119 /* If -1, force mouse. If 1 the mouse will be used on in XTerm. If 0,
120 * do not use it.
121 */
122 int Slrn_Use_Mouse;
123
124 /* Find out whether there was a warning at startup. Used for option -w0 */
125 int Slrn_Saw_Warning = 0;
126
127 /* We do not (yet) offer a batch mode; however, I consider it an interesting
128 * idea and might implement it after version 1.0.*/
129 int Slrn_Batch;
130 int Slrn_Suspension_Ok;
131 int Slrn_Simulate_Graphic_Chars = 0;
132
133 char *Slrn_Newsrc_File = NULL;
134 Slrn_Mode_Type *Slrn_Current_Mode;
135
136 int Slrn_Default_Server_Obj = SLRN_DEFAULT_SERVER_OBJ;
137 int Slrn_Default_Post_Obj = SLRN_DEFAULT_POST_OBJ;
138
139 FILE *Slrn_Debug_Fp = NULL;
140
141 /* You need to call slrn_init_graphic_chars before using these */
142 SLwchar_Type Graphic_LTee_Char;
143 SLwchar_Type Graphic_UTee_Char;
144 SLwchar_Type Graphic_LLCorn_Char;
145 SLwchar_Type Graphic_HLine_Char;
146 SLwchar_Type Graphic_VLine_Char;
147 SLwchar_Type Graphic_ULCorn_Char;
148
149 int Graphic_Chars_Mode = ALT_CHAR_SET_MODE;
150
151 /*}}}*/
152 /*{{{ Static Variables */
153
154 static int Can_Suspend;
155 static volatile int Want_Suspension;
156 static volatile int Want_Window_Size_Change;
157 static void perform_suspend (int);
158 static int Current_Mouse_Mode;
159 static int Ran_Startup_Hook;
160
161 /*}}}*/
162 /*{{{ Static Function Declarations */
163
164 #if defined(SIGSTOP) && defined(REAL_UNIX_SYSTEM)
165 static int suspend_display_mode (int);
166 static int resume_display_mode (int, int, int);
167 #endif
168 static void init_suspend_signals (int);
169 static void slrn_hangup (int);
170 static void run_winch_functions (int, int);
171 /*}}}*/
172
173 /*{{{ Newsrc Locking Routines */
174
test_lock(char * file)175 static void test_lock( char *file ) /*{{{*/
176 {
177 int pid;
178 FILE *fp;
179
180 if ((fp = fopen (file, "r")) != NULL)
181 {
182 if (1 == fscanf (fp, "%d", &pid) )
183 {
184 if ((pid > 0)
185 #if !defined(IBMPC_SYSTEM)
186 && (0 == kill (pid, 0))
187 #endif
188 )
189 {
190 #if defined(IBMPC_SYSTEM)
191 slrn_exit_error (_("\
192 slrn: pid %d is locking the newsrc file. If you're not running another\n\
193 copy of slrn, delete the file %s"),
194 pid, file);
195 #else
196 slrn_exit_error (_("slrn: pid %d is locking the newsrc file."), pid);
197 #endif
198 }
199 }
200 slrn_fclose (fp);
201 }
202 }
203
204 /*}}}*/
205
make_lock(char * file)206 static int make_lock( char *file ) /*{{{*/
207 {
208 int pid;
209 FILE *fp;
210
211 #ifdef VMS
212 fp = fopen (file, "w", "fop=cif");
213 #else
214 fp = fopen (file, "w");
215 #endif
216
217 if (fp == NULL) return -1;
218
219 pid = getpid ();
220 if (EOF == fprintf (fp, "%d", pid))
221 {
222 slrn_fclose (fp);
223 return -1;
224 }
225 return slrn_fclose (fp);
226 }
227
228 /*}}}*/
229
lock_file(int how)230 static void lock_file (int how) /*{{{*/
231 {
232 char name[SLRN_MAX_PATH_LEN];
233 static int not_ok_to_unlock;
234 #if SLRN_HAS_RNLOCK
235 int rnlock = 0;
236 char file_rn[SLRN_MAX_PATH_LEN];
237 #endif
238
239 if (Slrn_Newsrc_File == NULL) return;
240 if (not_ok_to_unlock) return;
241
242 not_ok_to_unlock = 1;
243
244 #ifdef SLRN_USE_OS2_FAT
245 slrn_os2_make_fat (name, sizeof (name), Slrn_Newsrc_File, ".lck");
246 #else
247 slrn_snprintf (name, sizeof (name), "%s-lock", Slrn_Newsrc_File);
248 #endif
249
250 #if SLRN_HAS_RNLOCK
251 slrn_make_home_filename (".newsrc", file_rn, sizeof (file_rn));
252 if (0 == strcmp (file_rn, Slrn_Newsrc_File))
253 {
254 rnlock = 1;
255 slrn_make_home_filename (".rnlock", file_rn, sizeof (file_rn));
256 }
257 #endif
258
259 if (how == 1)
260 {
261 test_lock (name);
262 #if SLRN_HAS_RNLOCK
263 if (rnlock) test_lock (file_rn);
264 #endif
265 if (-1 == make_lock (name))
266 {
267 slrn_exit_error (_("Unable to create lock file %s."), name);
268 }
269
270 #if SLRN_HAS_RNLOCK
271 if (rnlock && (-1 == make_lock (file_rn)))
272 {
273 slrn_delete_file (name); /* delete the "normal" lock file */
274 slrn_exit_error (_("Unable to create lock file %s."), file_rn);
275 }
276 #endif
277 }
278 else
279 {
280 if (-1 == slrn_delete_file (name))
281 {
282 /* slrn_exit_error ("Unable to remove lockfile %s.", file); */
283 }
284 #if SLRN_HAS_RNLOCK
285 if (rnlock && -1 == slrn_delete_file (file_rn))
286 {
287 /* slrn_exit_error ("Unable to remove lockfile %s.", file_rn); */
288 }
289 #endif
290 }
291 not_ok_to_unlock = 0;
292 }
293
294 /*}}}*/
295
296 /*}}}*/
297
298 /*{{{ Signal Related Functions */
299
300 /*{{{ Low-Level signal-related utility functions */
301
init_like_signals(int argc,int * argv,void (* f0)(int),void (* f1)(int),int state)302 static void init_like_signals (int argc, int *argv, /*{{{*/
303 void (*f0)(int),
304 void (*f1)(int),
305 int state)
306 {
307 #ifdef HAVE_SIGACTION
308 struct sigaction sa;
309 #endif
310 int i;
311
312 if (state == 0)
313 {
314 for (i = 0; i < argc; i++)
315 SLsignal_intr (argv[i], f0);
316 return;
317 }
318
319 for (i = 0; i < argc; i++)
320 {
321 int sig = argv[i];
322 SLsignal_intr (sig, f1);
323
324 #if defined(SLRN_POSIX_SIGNALS)
325 if (-1 != sigaction (sig, NULL, &sa))
326 {
327 int j;
328 for (j = 0; j < argc; j++)
329 {
330 if (j != i) sigaddset (&sa.sa_mask, argv[j]);
331 }
332
333 (void) sigaction (sig, &sa, NULL);
334 }
335 #endif
336 }
337 }
338
339 /*}}}*/
340
341 /*}}}*/
342
343 /*{{{ Suspension signals */
344
345 #ifdef REAL_UNIX_SYSTEM
346 #define SUSPEND_STACK_SIZE 512
347 static char Suspend_Stack [SUSPEND_STACK_SIZE];
348 static unsigned int Suspension_Stack_Depth = 0;
349 static int Ok_To_Suspend = 0;
350 #endif
351
352 static int Suspend_Sigtstp_Suspension = 0;
353
slrn_push_suspension(int ok)354 void slrn_push_suspension (int ok) /*{{{*/
355 {
356 #ifdef REAL_UNIX_SYSTEM
357 if (Suspension_Stack_Depth < SUSPEND_STACK_SIZE)
358 {
359 Suspend_Stack [Suspension_Stack_Depth] = Ok_To_Suspend;
360 }
361 else ok = 0;
362
363 Suspension_Stack_Depth++;
364
365 (void) slrn_handle_interrupts ();
366
367 Ok_To_Suspend = ok;
368 #else
369 (void) ok;
370 #endif
371 }
372 /*}}}*/
slrn_pop_suspension(void)373 void slrn_pop_suspension (void) /*{{{*/
374 {
375 #ifdef REAL_UNIX_SYSTEM
376
377 if (Suspension_Stack_Depth == 0)
378 {
379 slrn_error (_("pop_suspension: underflow!"));
380 return;
381 }
382
383 Suspension_Stack_Depth--;
384
385 if (Suspension_Stack_Depth < SUSPEND_STACK_SIZE)
386 {
387 Ok_To_Suspend = Suspend_Stack [Suspension_Stack_Depth];
388 }
389 else Ok_To_Suspend = 0;
390
391 (void) slrn_handle_interrupts ();
392 #endif
393 }
394 /*}}}*/
395
396 /* This function is called by the SIGTSTP handler. Since it operates
397 * in an asynchronous fashion, care must be exercised to control when that
398 * can happen. This is accomplished via the push/pop_suspension functions.
399 */
sig_suspend(int sig)400 static void sig_suspend (int sig)
401 {
402 #ifdef REAL_UNIX_SYSTEM
403 sig = errno;
404
405 if (Ok_To_Suspend
406 && (0 == Suspend_Sigtstp_Suspension))
407 {
408 perform_suspend (1);
409 }
410 else Want_Suspension = 1;
411
412 init_suspend_signals (1);
413 errno = sig;
414 #else
415 (void) sig;
416 #endif
417 }
418
init_suspend_signals(int state)419 static void init_suspend_signals (int state) /*{{{*/
420 {
421 int argv[2];
422 int argc = 0;
423
424 if (Can_Suspend == 0)
425 return;
426
427 #ifdef SIGTSTP
428 argv[argc++] = SIGTSTP;
429 #endif
430
431 #ifdef SIGTTIN
432 argv[argc++] = SIGTTIN;
433 #endif
434
435 init_like_signals (argc, argv, SIG_DFL, sig_suspend, state);
436 }
437
438 /*}}}*/
439
perform_suspend(int smg_suspend_flag)440 static void perform_suspend (int smg_suspend_flag) /*{{{*/
441 {
442 #if !defined(SIGSTOP) || !defined(REAL_UNIX_SYSTEM)
443 (void) smg_suspend_flag;
444 slrn_error (_("Not implemented."));
445 Want_Suspension = 0;
446 #else
447
448 int init;
449 int mouse_mode = Current_Mouse_Mode;
450
451 # ifdef SLRN_POSIX_SIGNALS
452 sigset_t mask;
453
454 Want_Suspension = 0;
455 if (Can_Suspend == 0)
456 {
457 slrn_error (_("Suspension not allowed by shell."));
458 return;
459 }
460
461 sigemptyset (&mask);
462 sigaddset (&mask, SIGTSTP);
463
464 /* This function resets SIGTSTP to default */
465 init = suspend_display_mode (smg_suspend_flag);
466
467 kill (getpid (), SIGTSTP);
468
469 /* If SIGTSTP is pending, it will be delivered now. That's ok. */
470 sigprocmask (SIG_UNBLOCK, &mask, NULL);
471 # else
472
473 Want_Suspension = 0;
474 if (Can_Suspend == 0)
475 {
476 slrn_error (_("Suspension not allowed by shell."));
477 return;
478 }
479
480 init = suspend_display_mode (smg_suspend_flag);
481 kill(getpid(),SIGSTOP);
482 # endif
483
484 resume_display_mode (smg_suspend_flag, init, mouse_mode);
485 #endif /* !defined(SIGSTOP) || !defined(REAL_UNIX_SYSTEM) */
486 }
487
488 /*}}}*/
489
slrn_suspend_cmd(void)490 void slrn_suspend_cmd (void)
491 {
492 perform_suspend (0);
493 }
494
check_for_suspension(void)495 static void check_for_suspension (void)
496 {
497 #ifdef SIGTSTP
498 void (*f)(int);
499
500 f = SLsignal (SIGTSTP, SIG_DFL);
501 (void) SLsignal (SIGTSTP, f);
502
503 #if 0
504 Can_Suspend = (f == SIG_DFL);
505 #else
506 Can_Suspend = (f != SIG_IGN);
507 #endif
508
509 #else
510 Can_Suspend = 0;
511 #endif
512 }
513
514 /*}}}*/
515
516 /*{{{ Hangup Signals */
517
slrn_init_hangup_signals(int state)518 void slrn_init_hangup_signals (int state) /*{{{*/
519 {
520 int argv[3];
521 int argc = 0;
522
523 #ifdef SIGHUP
524 argv[argc++] = SIGHUP;
525 #endif
526 #ifdef SIGTERM
527 argv[argc++] = SIGTERM;
528 #endif
529 #ifdef SIGQUIT
530 argv[argc++] = SIGQUIT;
531 #endif
532
533 init_like_signals (argc, argv, SIG_IGN, slrn_hangup, state);
534 }
535
536 /*}}}*/
537
538 /*}}}*/
539
540 #ifdef SIGWINCH
sig_winch_handler(int sig)541 static void sig_winch_handler (int sig)
542 {
543 if (Slrn_Batch) return;
544 sig = errno;
545 Want_Window_Size_Change = 1;
546 SLsignal_intr (SIGWINCH, sig_winch_handler);
547 errno = sig;
548 }
549 #endif
550
slrn_set_screen_size(int sig)551 static void slrn_set_screen_size (int sig) /*{{{*/
552 {
553 int old_r, old_c;
554
555 old_r = SLtt_Screen_Rows;
556 old_c = SLtt_Screen_Cols;
557
558 SLtt_get_screen_size ();
559
560 Slrn_Full_Screen_Update = 1;
561 Want_Window_Size_Change = 0;
562
563 run_winch_functions (old_r, old_c);
564
565 if (sig)
566 {
567 #if SLANG_VERSION < 10306
568 SLsmg_reset_smg ();
569 SLsmg_init_smg ();
570 #else
571 SLsmg_reinit_smg ();
572 #endif
573 slrn_redraw ();
574 }
575 }
576
577 /*}}}*/
578
init_display_signals(int mode)579 static void init_display_signals (int mode) /*{{{*/
580 {
581 init_suspend_signals (mode);
582
583 if (mode)
584 {
585 SLang_set_abort_signal (NULL);
586 #ifdef SIGPIPE
587 SLsignal (SIGPIPE, SIG_IGN);
588 #endif
589 #ifdef SIGTTOU
590 /* Allow background writes */
591 SLsignal (SIGTTOU, SIG_IGN);
592 #endif
593 #ifdef SIGWINCH
594 SLsignal_intr (SIGWINCH, sig_winch_handler);
595 #endif
596 }
597 else
598 {
599 #ifdef SIGWINCH
600 /* SLsignal_intr (SIGWINCH, SIG_DFL); */
601 #endif
602 }
603 }
604
605 /*}}}*/
606
slrn_handle_interrupts(void)607 int slrn_handle_interrupts (void)
608 {
609 if (Want_Suspension)
610 {
611 slrn_suspend_cmd ();
612 }
613
614 if (Want_Window_Size_Change)
615 {
616 slrn_set_screen_size (1);
617 }
618
619 return 0;
620 }
621
622 /*}}}*/
623
624 /*{{{ Screen Management and Terminal Init/Reset Functions */
625
626 int Slrn_Use_Flow_Control = 0;
init_tty(void)627 static int init_tty (void) /*{{{*/
628 {
629 if (Slrn_TT_Initialized & SLRN_TTY_INIT)
630 {
631 return 0;
632 }
633
634 if (Slrn_TT_Initialized == 0)
635 init_display_signals (1);
636
637 if (-1 == SLang_init_tty (7, !Slrn_Use_Flow_Control, 0))
638 slrn_exit_error (_("Unable to initialize the tty"));
639
640 #ifdef REAL_UNIX_SYSTEM
641 SLang_getkey_intr_hook = slrn_handle_interrupts;
642 #endif
643
644 #ifdef REAL_UNIX_SYSTEM
645 if (Can_Suspend)
646 SLtty_set_suspend_state (1);
647 #endif
648
649 Slrn_TT_Initialized |= SLRN_TTY_INIT;
650
651 return 0;
652 }
653
654 /*}}}*/
655
reset_tty(void)656 static int reset_tty (void) /*{{{*/
657 {
658 if (0 == (Slrn_TT_Initialized & SLRN_TTY_INIT))
659 {
660 return 0;
661 }
662
663 SLang_reset_tty ();
664 Slrn_TT_Initialized &= ~SLRN_TTY_INIT;
665
666 if (Slrn_TT_Initialized == 0)
667 init_display_signals (0);
668
669 return 0;
670 }
671
672 /*}}}*/
673
init_smg(int use_resume,int mouse_mode)674 static int init_smg (int use_resume, int mouse_mode) /*{{{*/
675 {
676 if (Slrn_TT_Initialized & SLRN_SMG_INIT)
677 return 0;
678
679 slrn_enable_mouse (mouse_mode);
680
681 if (Slrn_TT_Initialized == 0)
682 init_display_signals (1);
683
684 if (use_resume)
685 {
686 SLsmg_resume_smg ();
687 Slrn_TT_Initialized |= SLRN_SMG_INIT;
688 }
689 else
690 {
691 slrn_set_screen_size (0);
692 SLsmg_init_smg ();
693 Slrn_TT_Initialized |= SLRN_SMG_INIT;
694
695 /* We do not want the -> overlay cursor to affect the scroll. */
696 #if !defined(IBMPC_SYSTEM)
697 SLsmg_Scroll_Hash_Border = 5;
698 #endif
699 slrn_redraw ();
700 }
701
702 return 0;
703 }
704
705 /*}}}*/
706
reset_smg(int smg_suspend_flag)707 static int reset_smg (int smg_suspend_flag) /*{{{*/
708 {
709 if (0 == (Slrn_TT_Initialized & SLRN_SMG_INIT))
710 return 0;
711
712 slrn_enable_mouse (0);
713
714 if (smg_suspend_flag)
715 SLsmg_suspend_smg ();
716 else
717 {
718 SLsmg_gotorc (SLtt_Screen_Rows - 1, 0);
719 slrn_smg_refresh ();
720 SLsmg_reset_smg ();
721 }
722
723 /* SLsignal_intr (SIGWINCH, SIG_DFL); */
724
725 Slrn_TT_Initialized &= ~SLRN_SMG_INIT;
726
727 if (Slrn_TT_Initialized == 0)
728 init_display_signals (0);
729
730 return 0;
731 }
732
733 /*}}}*/
734
735 #if defined(SIGSTOP) && defined(REAL_UNIX_SYSTEM)
suspend_display_mode(int smg_suspend_flag)736 static int suspend_display_mode (int smg_suspend_flag) /*{{{*/
737 {
738 int mode = Slrn_TT_Initialized;
739
740 SLsig_block_signals ();
741
742 reset_smg (smg_suspend_flag);
743 reset_tty ();
744
745 SLsig_unblock_signals ();
746
747 return mode;
748 }
749
750 /*}}}*/
751
resume_display_mode(int smg_suspend_flag,int mode,int mouse_mode)752 static int resume_display_mode (int smg_suspend_flag, int mode, int mouse_mode) /*{{{*/
753 {
754 SLsig_block_signals ();
755
756 if (mode & SLRN_TTY_INIT)
757 init_tty ();
758
759 if (mode & SLRN_SMG_INIT)
760 init_smg (smg_suspend_flag, mouse_mode);
761
762 SLsig_unblock_signals ();
763 return 0;
764 }
765
766 /*}}}*/
767 #endif /* SIGSTOP && REAL_UNIX_SYSTEM*/
768
slrn_set_display_state(int state)769 void slrn_set_display_state (int state) /*{{{*/
770 {
771 if (Slrn_Batch) return;
772
773 SLsig_block_signals ();
774
775 if (state & SLRN_TTY_INIT)
776 init_tty ();
777 else
778 reset_tty ();
779
780 if (state & SLRN_SMG_INIT)
781 init_smg (0, 1);
782 else
783 reset_smg (0);
784
785 SLsig_unblock_signals ();
786 }
787
788 /*}}}*/
789
slrn_enable_mouse(int mode)790 void slrn_enable_mouse (int mode) /*{{{*/
791 {
792 if (Current_Mouse_Mode == mode)
793 return;
794
795 if (Slrn_Use_Mouse)
796 {
797 if (-1 == SLtt_set_mouse_mode (mode, (Slrn_Use_Mouse < 0)))
798 Slrn_Use_Mouse = 0;
799 }
800 Current_Mouse_Mode = mode;
801 }
802
803 /*}}}*/
804
slrn_init_graphic_chars(void)805 void slrn_init_graphic_chars (void) /*{{{*/
806 {
807 #ifndef IBMPC_SYSTEM
808 if (SLtt_Has_Alt_Charset == 0)
809 Slrn_Simulate_Graphic_Chars = 1;
810 #endif
811
812 if (Slrn_Simulate_Graphic_Chars)
813 {
814 Graphic_LTee_Char = '+';
815 Graphic_UTee_Char = '+';
816 Graphic_LLCorn_Char = '`';
817 Graphic_HLine_Char = '-';
818 Graphic_VLine_Char = '|';
819 Graphic_ULCorn_Char = '/';
820
821 Graphic_Chars_Mode = SIMULATED_CHAR_SET_MODE;
822 }
823 else
824 {
825 Graphic_Chars_Mode = ALT_CHAR_SET_MODE;
826 Graphic_LTee_Char = SLSMG_LTEE_CHAR;
827 Graphic_UTee_Char = SLSMG_UTEE_CHAR;
828 Graphic_LLCorn_Char = SLSMG_LLCORN_CHAR;
829 Graphic_HLine_Char = SLSMG_HLINE_CHAR;
830 Graphic_VLine_Char = SLSMG_VLINE_CHAR;
831 Graphic_ULCorn_Char = SLSMG_ULCORN_CHAR;
832
833 Graphic_Chars_Mode = ALT_CHAR_SET_MODE;
834 }
835 }
836 /*}}}*/
837 /*}}}*/
838
perform_cleanup(void)839 static void perform_cleanup (void)
840 {
841 slrn_set_display_state (0);
842
843 #if SLRN_HAS_GROUPLENS
844 slrn_close_grouplens ();
845 #endif
846
847 if (Slrn_Server_Obj != NULL)
848 Slrn_Server_Obj->sv_close ();
849
850 if (Slrn_Debug_Fp != NULL)
851 {
852 (void) fclose (Slrn_Debug_Fp);
853 Slrn_Debug_Fp = NULL;
854 }
855
856 #if SLRN_HAS_GROUPLENS
857 slrn_close_grouplens ();
858 #endif
859
860 if (Ran_Startup_Hook)
861 (void) slrn_run_hooks (HOOK_QUIT, 0);
862 (void) slrn_reset_slang ();
863
864 #if SLRN_USE_SLTCP && SLRN_HAS_NNTP_SUPPORT
865 (void) sltcp_close_sltcp ();
866 #endif
867 lock_file (0);
868 }
869
slrn_quit(int retcode)870 void slrn_quit (int retcode) /*{{{*/
871 {
872 perform_cleanup ();
873 if (retcode) fprintf (stderr, _("slrn: quiting on signal %d.\n"), retcode);
874 exit (retcode);
875 }
876
877 /*}}}*/
878
slrn_va_exit_error(char * fmt,va_list ap)879 void slrn_va_exit_error (char *fmt, va_list ap)
880 {
881 static int trying_to_exit;
882
883 if (trying_to_exit == 0)
884 {
885 trying_to_exit = 1;
886 slrn_set_display_state (0);
887
888 if (fmt != NULL)
889 {
890 fputs (_("slrn fatal error:"), stderr);
891 #ifdef IBMPC_SYSTEM
892 fputc ('\r', stderr);
893 #endif
894 fputc ('\n', stderr);
895 vfprintf (stderr, fmt, ap);
896 }
897 if (Slrn_Groups_Dirty) slrn_write_newsrc (0);
898 perform_cleanup ();
899 }
900
901 putc ('\n', stderr);
902 exit (1);
903 }
904
slrn_exit_error(char * fmt,...)905 void slrn_exit_error (char *fmt, ...) /*{{{*/
906 {
907 va_list ap;
908 va_start (ap, fmt);
909 slrn_va_exit_error (fmt, ap);
910 va_end(ap);
911 }
912
913 /*}}}*/
914
slrn_error(char * fmt,...)915 void slrn_error (char *fmt, ...) /*{{{*/
916 {
917 va_list ap;
918
919 va_start(ap, fmt);
920 slrn_verror (fmt, ap);
921 va_end (ap);
922 }
923
924 /*}}}*/
925
usage(char * extra,int exit_status)926 static void usage (char *extra, int exit_status) /*{{{*/
927 {
928 printf (_("\
929 Usage: slrn [--inews] [--nntp ...] [--spool] OPTIONS\n\
930 -a Use active file for getting new news.\n\
931 -f newsrc-file Name of the newsrc file to use.\n\
932 -C[-] [Do not] use colors.\n\
933 -Dname Add 'name' to list of predefined preprocessing tokens.\n\
934 -d Get new text descriptions of each group from server.\n\
935 Note: This may take a LONG time to retrieve this information.\n\
936 The resulting file can be several hundred Kilobytes!\n\
937 -i init-file Name of initialization file to use (default: %s)\n\
938 -k Do not process score file.\n\
939 -k0 Process score file but inhibit expensive scores.\n\
940 -m Force XTerm mouse reporting\n\
941 -n Do not check for new groups. This usually results in\n\
942 a faster startup.\n\
943 -w Wait for key before switching to full screen mode\n\
944 -w0 Wait for key (only when warnings / errors occur)\n\
945 --create Create a newsrc file by getting list of groups from server.\n\
946 --debug FILE Write debugging information to FILE\n\
947 --help Print this usage.\n\
948 --kill-log FILE Keep a log of all killed articles in FILE\n\
949 --show-config Print configuration\n\
950 --version Show version and supported features\n\
951 \n\
952 NNTP mode has additional options; use \"slrn --nntp --help\" to display them.\n\
953 "), SLRN_USER_SLRNRC_FILENAME);
954
955 if (extra != NULL)
956 {
957 printf ("\n%s\n", extra);
958 }
959 exit (exit_status);
960 }
961
962 /*}}}*/
963
parse_object_args(char * obj,char ** argv,int argc)964 static int parse_object_args (char *obj, char **argv, int argc) /*{{{*/
965 {
966 int num_parsed;
967 int zero_ok = 1;
968
969 if (obj == NULL)
970 {
971 zero_ok = 0;
972 obj = slrn_map_object_id_to_name (0, SLRN_DEFAULT_SERVER_OBJ);
973 }
974
975 num_parsed = slrn_parse_object_args (obj, argv, argc);
976 if (num_parsed < 0)
977 {
978 if (num_parsed == -1)
979 slrn_exit_error (_("%s is not a supported option."), *argv);
980 else
981 slrn_exit_error (_("%s is not supported."), obj);
982 }
983 if ((num_parsed == 0) && (zero_ok == 0))
984 usage (NULL, 1);
985
986 return num_parsed;
987 }
988
989 /*}}}*/
990
read_score_file(void)991 static void read_score_file (void)
992 {
993 char file[SLRN_MAX_PATH_LEN];
994
995 if (Slrn_Score_File == NULL)
996 return;
997
998 slrn_make_home_filename (Slrn_Score_File, file, sizeof (file));
999
1000 if (1 != slrn_file_exists (file))
1001 {
1002 slrn_message_now (_("*** Warning: Score file %s does not exist"), file);
1003 Slrn_Saw_Warning = 1;
1004 return;
1005 }
1006
1007 if (-1 == slrn_read_score_file (file))
1008 {
1009 slrn_exit_error (_("Error processing score file %s."), file);
1010 }
1011 }
1012
main_init_and_parse_args(int argc,char ** argv)1013 static int main_init_and_parse_args (int argc, char **argv) /*{{{*/
1014 {
1015 char *hlp_file;
1016 unsigned int i;
1017 int create_flag = 0;
1018 int no_new_groups = 0;
1019 int no_score_file = 0;
1020 int use_color = 0;
1021 int use_mouse = 0;
1022 int dsc_flag = 0;
1023 int use_active = 0;
1024 int wait_for_key = 0;
1025 FILE *fp;
1026 char file [SLRN_MAX_PATH_LEN];
1027 char *init_file = NULL;
1028 char *kill_logfile = NULL;
1029 int print_config = 0;
1030
1031 #if defined(HAVE_SETLOCALE) && defined(LC_ALL)
1032 (void) setlocale(LC_ALL, "");
1033 #endif
1034 #ifdef ENABLE_NLS
1035 bindtextdomain(NLS_PACKAGE_NAME, NLS_LOCALEDIR);
1036 textdomain (NLS_PACKAGE_NAME);
1037 #endif
1038
1039 check_for_suspension ();
1040 #ifdef __unix__
1041 (void) umask (077);
1042 #endif
1043
1044 #if 0
1045 if (NULL != getenv ("AUTOSUBSCRIBE"))
1046 Slrn_Unsubscribe_New_Groups = 0;
1047 if (NULL != getenv ("AUTOUNSUBSCRIBE"))
1048 Slrn_Unsubscribe_New_Groups = 1;
1049 #endif
1050
1051 for (i = 1; i < (unsigned int) argc; i++)
1052 {
1053 char *argv_i = argv[i];
1054
1055 if ((argv_i[0] == '-') && (argv_i[1] == '-'))
1056 {
1057 int status;
1058
1059 argv_i += 2;
1060
1061 status = slrn_parse_object_args (argv_i, NULL, 0);
1062 if (status != -1)
1063 i += parse_object_args (argv_i, argv + (i + 1), argc - (i + 1));
1064 #if 0
1065 else if (!strcmp ("batch", argv_i)) Slrn_Batch = 1;
1066 #endif
1067 else if (!strcmp ("create", argv_i)) create_flag = 1;
1068 else if (!strcmp ("version", argv_i))
1069 {
1070 slrn_show_version (stdout);
1071 exit (0);
1072 }
1073 else if (!strcmp ("show-config", argv_i))
1074 print_config = 1;
1075 else if ((!strcmp ("kill-log", argv_i)) &&
1076 (i + 1 < (unsigned int) argc))
1077 kill_logfile = argv[++i];
1078 else if ((!strcmp ("debug", argv_i)) &&
1079 (i + 1 < (unsigned int) argc))
1080 {
1081 if (Slrn_Debug_Fp != NULL)
1082 fclose (Slrn_Debug_Fp);
1083 Slrn_Debug_Fp = fopen (argv[++i], "w");
1084 if (Slrn_Debug_Fp == NULL)
1085 slrn_exit_error (_("Unable to open %s for debugging."), argv[i]);
1086 setbuf (Slrn_Debug_Fp, (char *) NULL);
1087 }
1088 else if (!strcmp ("help", argv_i))
1089 usage (NULL, 0);
1090 else usage (NULL, 1);
1091 }
1092 else if (!strcmp ("-create", argv_i)) create_flag = 1;
1093 else if (!strcmp ("-C", argv_i)) use_color = 1;
1094 else if (!strcmp ("-C-", argv_i)) use_color = -1;
1095 else if (!strcmp ("-a", argv_i)) use_active = 1;
1096 else if (!strcmp ("-n", argv_i)) no_new_groups = 1;
1097 else if (!strcmp ("-d", argv_i)) dsc_flag = 1;
1098 else if (!strcmp ("-m", argv_i)) use_mouse = 1;
1099 else if (!strcmp ("-k", argv_i)) no_score_file = 1;
1100 else if (!strcmp ("-k0", argv_i))
1101 Slrn_Perform_Scoring &= ~SLRN_EXPENSIVE_SCORING;
1102 else if (!strcmp ("-w", argv_i))
1103 wait_for_key = 1;
1104 else if (!strcmp ("-w0", argv_i))
1105 wait_for_key = 2;
1106 else if (!strncmp ("-D", argv_i, 2) && (argv_i[2] != 0))
1107 {
1108 if (-1 == SLdefine_for_ifdef (argv_i + 2))
1109 {
1110 slrn_exit_error (_("Unable to add preprocessor name %s."),
1111 argv_i + 2);
1112 }
1113 }
1114 else if (i + 1 < (unsigned int) argc)
1115 {
1116 if (!strcmp ("-f", argv_i)) Slrn_Newsrc_File = argv[++i];
1117 else if (!strcmp ("-i", argv_i)) init_file = argv[++i];
1118 else
1119 {
1120 i += parse_object_args (NULL, argv + i, argc - i);
1121 i -= 1;
1122 }
1123 }
1124 else
1125 {
1126 i += parse_object_args (NULL, argv + i, argc - i);
1127 i -= 1;
1128 }
1129 }
1130
1131 fprintf (stdout, "slrn %s\n", Slrn_Version_String);
1132
1133 if (dsc_flag && create_flag)
1134 {
1135 usage (_("The -d and --create flags must not be specified together."), 1);
1136 }
1137
1138 if (Slrn_Batch == 0)
1139 {
1140 Slrn_UTF8_Mode = SLutf8_enable (-1);
1141 SLtt_get_terminfo ();
1142 if (use_color == 1) SLtt_Use_Ansi_Colors = 1;
1143 else if (use_color == -1) SLtt_Use_Ansi_Colors = 0;
1144 }
1145
1146 #if SLRN_USE_SLTCP && SLRN_HAS_NNTP_SUPPORT
1147 SLtcp_Verror_Hook = slrn_verror;
1148 /* This is necessary to ensure that gethostname works on Win32 */
1149 if (-1 == sltcp_open_sltcp ())
1150 slrn_exit_error (_("Error initializing SLtcp interface"));
1151 #endif
1152
1153 if (-1 == slrn_init_slang ())
1154 slrn_exit_error (_("Error initializing S-Lang interpreter.\n"));
1155
1156 slrn_startup_initialize ();
1157
1158 /* We need to get user info first, because the request file in true offline
1159 * reading mode is chosen based on login name */
1160 slrn_get_user_info ();
1161
1162 /* The next function call will also define slang preprocessing tokens
1163 * for the appropriate objects. For that reason, it is called after
1164 * startup initialize.
1165 */
1166 if (-1 == slrn_init_objects ())
1167 {
1168 slrn_exit_error (_("Error configuring server objects."));
1169 }
1170
1171 slrn_init_hangup_signals (1);
1172
1173 #ifdef VMS
1174 slrn_snprintf (file, sizeof (file), "%s%s", SLRN_CONF_DIR, "slrn.rc");
1175 #else
1176 slrn_snprintf (file, sizeof (file), "%s/%s", SLRN_CONF_DIR, "slrn.rc");
1177 #endif
1178
1179 /* Make sure terminal is initialized before setting colors. The
1180 * SLtt_get_terminfo call above fixed that.
1181 */
1182 slrn_read_startup_file (file); /* global file for all users */
1183
1184 if (init_file == NULL)
1185 {
1186 slrn_make_home_filename (SLRN_USER_SLRNRC_FILENAME, file, sizeof (file));
1187 init_file = file;
1188 }
1189
1190 if ((-1 == slrn_read_startup_file (init_file)) && (init_file != file))
1191 {
1192 slrn_exit_error (_("\
1193 Could not read specified config file %s\n"), init_file);
1194 }
1195
1196 if (Slrn_Saw_Obsolete)
1197 {
1198 slrn_message (_("\n! Your configuration file contains obsolete commands or function names that\n"
1199 "! will not be supported by future versions of this program.\n"
1200 "! If you have Perl installed, you can use the script slrnrc-conv to change\n"
1201 "! your configuration accordingly. It can be found in the source distribution\n"
1202 "! or retrieved from <URL:http://slrn.sourceforge.net/data/>.\n"));
1203 Slrn_Saw_Warning = 1;
1204 }
1205
1206 if (Slrn_Server_Id == 0) Slrn_Server_Id = Slrn_Default_Server_Obj;
1207 if (Slrn_Post_Id == 0) Slrn_Post_Id = Slrn_Default_Post_Obj;
1208 if (no_new_groups) Slrn_Check_New_Groups = 0;
1209
1210 slrn_prepare_charset();
1211
1212 if (print_config)
1213 {
1214 (void) putc ('\n', stdout);
1215 slrn_show_version (stdout);
1216 slrn_print_config (stdout);
1217 slrn_quit (0);
1218 }
1219
1220 #ifdef SIGINT
1221 if (Slrn_TT_Initialized == 0)
1222 SLsignal_intr (SIGINT, SIG_DFL);
1223 #endif
1224
1225 if ((-1 == slrn_select_server_object (Slrn_Server_Id))
1226 || (-1 == slrn_select_post_object (Slrn_Post_Id)))
1227 {
1228 slrn_exit_error (_("Unable to select server/post object."));
1229 }
1230
1231 #if !defined(IBMPC_SYSTEM)
1232 /* Allow blink characters if in mono */
1233 if (SLtt_Use_Ansi_Colors == 0)
1234 SLtt_Blink_Mode = 1;
1235 #endif
1236
1237 /* Now that we have read in the startup file, check to see if the user
1238 * has a username and a usable hostname. Without those, we are not
1239 * starting up.
1240 */
1241 if ((NULL == Slrn_User_Info.hostname)
1242 || (0 == slrn_is_fqdn (Slrn_User_Info.hostname)))
1243 {
1244 slrn_exit_error (_("\
1245 Unable to find a valid hostname for constructing your e-mail address.\n\
1246 You probably want to specify a hostname in your %s file.\n\
1247 Please see the \"slrn reference manual\" for full details.\n"),
1248 SLRN_USER_SLRNRC_FILENAME);
1249 }
1250 if ((NULL == Slrn_User_Info.username)
1251 || (0 == *Slrn_User_Info.username)
1252 || (NULL != slrn_strbyte (Slrn_User_Info.username, '@')))
1253 {
1254 slrn_exit_error (_("\
1255 Unable to find your user name. This means that a valid 'From' header line\n\
1256 cannot be constructed. Try setting the USER environment variable.\n"));
1257 }
1258
1259 if ((NULL == Slrn_User_Info.posting_host)
1260 && Slrn_Generate_Message_Id)
1261 {
1262 slrn_stderr_strcat (_("\
1263 ***Warning: Unable to find a unique fully-qualified host name."), "\n", _("\
1264 slrn will not generate any Message-IDs."), "\n", _("\
1265 Please note that the \"hostname\" setting does not affect this;"), "\n", _("\
1266 see the \"slrn reference manual\" for details."), "\n", NULL);
1267 Slrn_Saw_Warning = 1;
1268 }
1269
1270 if (no_score_file == 0) read_score_file ();
1271
1272 if (NULL == (hlp_file = getenv ("SLRNHELP")))
1273 {
1274 hlp_file = file;
1275 #ifdef VMS
1276 slrn_snprintf (file, sizeof (file), "%s%s", SLRN_CONF_DIR, "help.txt");
1277 #else
1278 slrn_snprintf (file, sizeof (file), "%s/%s", SLRN_CONF_DIR, "help.txt");
1279 #endif
1280 }
1281
1282 slrn_parse_helpfile (hlp_file);
1283
1284 if ((Slrn_Newsrc_File == NULL)
1285 && ((Slrn_Newsrc_File = slrn_map_file_to_host (Slrn_Server_Obj->sv_name)) == NULL))
1286 {
1287 #if defined(VMS) || defined(IBMPC_SYSTEM)
1288 Slrn_Newsrc_File = "jnews.rc";
1289 #else
1290 Slrn_Newsrc_File = ".jnewsrc";
1291 #endif
1292 slrn_make_home_filename (Slrn_Newsrc_File, file, sizeof (file));
1293 Slrn_Newsrc_File = slrn_safe_strmalloc (file);
1294 }
1295
1296 slrn_message_now (_("Using newsrc file %s for server %s."),
1297 Slrn_Newsrc_File, Slrn_Server_Obj->sv_name);
1298
1299 if (use_active) Slrn_List_Active_File = 1;
1300 if (use_mouse) Slrn_Use_Mouse = -1; /* -1 forces it. */
1301 if (use_color == 1) SLtt_Use_Ansi_Colors = 1;
1302 else if (use_color == -1) SLtt_Use_Ansi_Colors = 0;
1303
1304 if (dsc_flag)
1305 {
1306 if (Slrn_Server_Obj->sv_initialize () != 0)
1307 {
1308 slrn_exit_error (_("Unable to initialize server."));
1309 }
1310 slrn_get_group_descriptions ();
1311 Slrn_Server_Obj->sv_close ();
1312 exit (0);
1313 }
1314
1315 if (create_flag == 0)
1316 {
1317 /* Check to see if the .newsrc file exists -- I should use the access
1318 * system call but for now, do it this way.
1319 */
1320 if (NULL == (fp = fopen (Slrn_Newsrc_File, "r")))
1321 {
1322 #if 0 /* now disabled in group.c */
1323 slrn_error (_("Unable to open %s. I will try .newsrc."), Slrn_Newsrc_File);
1324 if (NULL == (fp = slrn_open_home_file (".newsrc", "r", file,
1325 sizeof (file), 0)))
1326 {
1327 #endif
1328 slrn_exit_error (_("\nUnable to open %s.\n\
1329 If you want to create %s, add command line options:\n\
1330 -f %s --create\n"), Slrn_Newsrc_File, Slrn_Newsrc_File, Slrn_Newsrc_File);
1331 #if 0
1332 }
1333 #endif
1334 }
1335 slrn_fclose (fp);
1336 }
1337
1338 /* make sure we have an entry for the server */
1339 slrn_add_to_server_list (Slrn_Server_Obj->sv_name, NULL, NULL, NULL);
1340
1341 if (kill_logfile != NULL)
1342 {
1343 Slrn_Kill_Log_FP = fopen(kill_logfile, "a");
1344 if (Slrn_Kill_Log_FP == NULL)
1345 slrn_error (_("Unable to open %s for logging."), kill_logfile);
1346 }
1347
1348 lock_file (1);
1349
1350 (void) slrn_run_hooks (HOOK_STARTUP, 0);
1351 Ran_Startup_Hook = 1;
1352
1353 #if SLRN_HAS_GROUPLENS
1354 if (Slrn_Server_Id != SLRN_SERVER_ID_NNTP)
1355 Slrn_Use_Group_Lens = 0;
1356
1357 if (Slrn_Use_Group_Lens && (Slrn_Batch == 0))
1358 {
1359 slrn_message (_("Initializing GroupLens"));
1360 if (-1 == slrn_init_grouplens ())
1361 {
1362 fprintf (stderr, _("GroupLens disabled.\n"));
1363 Slrn_Use_Group_Lens = 0;
1364 Slrn_Saw_Warning = 1;
1365 }
1366 }
1367 #endif
1368
1369 if (Slrn_Server_Obj->sv_initialize () != 0)
1370 {
1371 slrn_exit_error (_("Failed to initialize server."));
1372 }
1373
1374 if (Slrn_Server_Obj->sv_has_xover == 1)
1375 {
1376 if (0 == (Slrn_Server_Obj->sv_has_xover = slrn_read_overview_fmt ()))
1377 slrn_message (_("OVERVIEW.FMT not RFC 2980 compliant -- XOVER support disabled."));
1378 }
1379
1380 if (Slrn_Check_New_Groups || create_flag)
1381 {
1382 slrn_get_new_groups (create_flag);
1383 }
1384
1385 slrn_read_newsrc (create_flag);
1386 slrn_read_group_descriptions ();
1387
1388 if (wait_for_key && ((wait_for_key == 1) || Slrn_Saw_Warning))
1389 {
1390 slrn_message (_("* Press Ctrl-C to quit, any other key to continue.\n"));
1391 slrn_set_display_state (SLRN_TTY_INIT);
1392 if ('\003' == SLang_getkey ())
1393 slrn_exit_error (_("Exit on user request."));
1394 }
1395 else
1396 putc ('\n', stdout);
1397
1398 slrn_set_display_state (SLRN_SMG_INIT | SLRN_TTY_INIT);
1399
1400 #if defined(__unix__) && !defined(IBMPC_SYSTEM)
1401 if (Slrn_Autobaud) SLtt_Baud_Rate = SLang_TT_Baud_Rate;
1402 #endif
1403
1404 return 0;
1405 }
1406
1407 /*}}}*/
1408
1409 /*{{{ Main Loop and Key Processing Functions */
1410 #define MAX_MODE_STACK_LEN 15
1411 /* Allow one extra because the top one is the current mode */
1412 static Slrn_Mode_Type *Mode_Stack [MAX_MODE_STACK_LEN + 1];
1413 static unsigned int Mode_Stack_Depth;
1414
slrn_push_mode(Slrn_Mode_Type * mode)1415 void slrn_push_mode (Slrn_Mode_Type *mode)
1416 {
1417 if (Mode_Stack_Depth == MAX_MODE_STACK_LEN)
1418 slrn_exit_error (_("Internal Error: Mode_Stack overflow"));
1419
1420 Mode_Stack[Mode_Stack_Depth] = Slrn_Current_Mode;
1421 Mode_Stack_Depth++;
1422
1423 Mode_Stack[Mode_Stack_Depth] = Slrn_Current_Mode = mode;
1424
1425 Slrn_Full_Screen_Update = 1;
1426 if ((mode != NULL) && (mode->enter_mode_hook != NULL))
1427 (*mode->enter_mode_hook) ();
1428 }
1429
slrn_pop_mode(void)1430 void slrn_pop_mode (void)
1431 {
1432 if (Mode_Stack_Depth == 0)
1433 slrn_exit_error (_("Internal Error: Mode_Stack underflow"));
1434
1435 Mode_Stack [Mode_Stack_Depth] = NULL; /* null current mode */
1436 Mode_Stack_Depth--;
1437 Slrn_Current_Mode = Mode_Stack[Mode_Stack_Depth];
1438
1439 Slrn_Full_Screen_Update = 1;
1440 if ((Slrn_Current_Mode != NULL) && (Slrn_Current_Mode->enter_mode_hook != NULL))
1441 (*Slrn_Current_Mode->enter_mode_hook) ();
1442 }
1443
slrn_update_screen(void)1444 void slrn_update_screen (void)
1445 {
1446 Slrn_Mode_Type *mode;
1447 unsigned int i, imax;
1448
1449 if (Slrn_Batch) return;
1450
1451 slrn_push_suspension (0);
1452 imax = Mode_Stack_Depth + 1; /* include current mode */
1453 for (i = 0; i < imax; i++)
1454 {
1455 Slrn_Full_Screen_Update = 1;
1456 mode = Mode_Stack [i];
1457 if ((mode != NULL)
1458 && (mode->redraw_fun != NULL))
1459 (*mode->redraw_fun) ();
1460 }
1461 slrn_smg_refresh ();
1462 slrn_pop_suspension ();
1463 }
1464
run_winch_functions(int old_r,int old_c)1465 static void run_winch_functions (int old_r, int old_c)
1466 {
1467 Slrn_Mode_Type *mode;
1468 unsigned int i, imax;
1469
1470 imax = Mode_Stack_Depth + 1; /* include current */
1471 for (i = 0; i < imax; i++)
1472 {
1473 mode = Mode_Stack [i];
1474 if ((mode != NULL)
1475 && (mode->sigwinch_fun != NULL))
1476 (*mode->sigwinch_fun) (old_r, old_c);
1477 }
1478
1479 if (SLang_get_error() == 0)
1480 slrn_run_hooks (HOOK_RESIZE_SCREEN, 0);
1481 }
1482
slrn_hangup(int sig)1483 static void slrn_hangup (int sig) /*{{{*/
1484 {
1485 Slrn_Mode_Type *mode;
1486 unsigned int i;
1487
1488 slrn_init_hangup_signals (0);
1489
1490 i = Mode_Stack_Depth + 1; /* include current */
1491 while (i != 0)
1492 {
1493 i--;
1494 mode = Mode_Stack [i];
1495 if ((mode != NULL)
1496 && (mode->hangup_fun != NULL))
1497 (*mode->hangup_fun) (sig);
1498 }
1499
1500 slrn_write_newsrc (0);
1501 slrn_quit (sig);
1502 }
1503
1504 /*}}}*/
1505
slrn_call_command(char * cmd)1506 void slrn_call_command (char *cmd) /*{{{*/
1507 {
1508 SLKeymap_Function_Type *list;
1509
1510 if ((Slrn_Current_Mode == NULL)
1511 || (Slrn_Current_Mode->keymap == NULL))
1512 list = NULL;
1513 else
1514 list = Slrn_Current_Mode->keymap->functions;
1515
1516 while ((list != NULL) && (list->name != NULL))
1517 {
1518 if (0 == strcmp (cmd, list->name))
1519 {
1520 (void) (*list->f) ();
1521 /* sync the line number to avoid surprises in subsequent calls
1522 * that might change the article window (not the article itself) */
1523 if (Slrn_Current_Mode->mode == SLRN_ARTICLE_MODE)
1524 slrn_art_sync_article (Slrn_Current_Article);
1525 return;
1526 }
1527 list++;
1528 }
1529
1530 slrn_error (_("call: %s not in current keymap."), cmd);
1531 }
1532
1533 /*}}}*/
1534
slrn_getkey(void)1535 int slrn_getkey (void)
1536 {
1537 static char buf[32];
1538 static unsigned int buf_len;
1539 static int timeout_active;
1540
1541 int ch;
1542
1543 if (SLang_Key_TimeOut_Flag == 0)
1544 {
1545 timeout_active = 0;
1546 buf_len = 0;
1547 }
1548 else if ((timeout_active || (0 == SLang_input_pending (10)))
1549 && (buf_len + 2 < sizeof (buf)))
1550 {
1551 int r, c;
1552
1553 buf[buf_len] = '-';
1554 buf[buf_len + 1] = 0;
1555
1556 slrn_push_suspension (0);
1557 r = SLsmg_get_row (); c = SLsmg_get_column ();
1558 slrn_message ("%s", buf);
1559 SLsmg_gotorc (r, c);
1560 slrn_smg_refresh ();
1561 slrn_pop_suspension ();
1562 timeout_active = 1;
1563 }
1564
1565 while (1)
1566 {
1567 #if defined(REAL_UNIX_SYSTEM) && (SLANG_VERSION < 20202)
1568 int ttyfd = SLang_TT_Read_FD;
1569 #endif
1570 int e;
1571 errno = 0;
1572
1573 ch = SLang_getkey ();
1574 if (ch != SLANG_GETKEY_ERROR)
1575 break;
1576 e = errno;
1577
1578 #if defined(REAL_UNIX_SYSTEM) && (SLANG_VERSION < 20202)
1579 if (ttyfd != SLang_TT_Read_FD)
1580 continue;
1581 #endif
1582
1583 slrn_exit_error ("%s: errno=%d [%s]", _("SLang_getkey failed"),
1584 e, SLerrno_strerror (e));
1585 }
1586
1587 if (buf_len + 4 < sizeof (buf))
1588 {
1589 if (ch == 0)
1590 {
1591 /* Need to handle NULL character. */
1592 buf[buf_len++] = '^';
1593 buf[buf_len] = '@';
1594 }
1595 else if (ch == 27)
1596 {
1597 buf[buf_len++] = 'E';
1598 buf[buf_len++] = 'S';
1599 buf[buf_len++] = 'C';
1600 buf[buf_len] = ' ';
1601 }
1602 else buf[buf_len] = (char) ch;
1603 }
1604 buf_len++;
1605
1606 return ch;
1607 }
1608
slrn_do_keymap_key(SLKeyMap_List_Type * map)1609 void slrn_do_keymap_key (SLKeyMap_List_Type *map) /*{{{*/
1610 {
1611 SLang_Key_Type *key;
1612 static SLKeyMap_List_Type *last_map;
1613 static SLang_Key_Type *last_key;
1614
1615 Suspend_Sigtstp_Suspension = 1;
1616 key = SLang_do_key (map, slrn_getkey);
1617 Suspend_Sigtstp_Suspension = 0;
1618
1619 if (Slrn_Message_Present || SLang_get_error())
1620 {
1621 if (SLang_get_error()) SLang_restart (0);
1622 slrn_clear_message ();
1623 }
1624 SLKeyBoard_Quit = 0;
1625 SLang_set_error (0);
1626
1627 if ((key == NULL) || (key->type == 0))
1628 {
1629 SLtt_beep ();
1630 return;
1631 }
1632
1633 if (key->type == SLKEY_F_INTRINSIC)
1634 {
1635 if ((map == last_map) && (key->f.f == (FVOID_STAR) slrn_repeat_last_key))
1636 key = last_key;
1637
1638 /* set now to avoid problems with recursive call */
1639 last_key = key;
1640 last_map = map;
1641
1642 if (key->type == SLKEY_F_INTRINSIC)
1643 {
1644 (((void (*)(void))(key->f.f)) ());
1645 return;
1646 }
1647 }
1648
1649 /* Otherwise we have interpreted key. */
1650 last_key = key;
1651 last_map = map;
1652
1653 Slrn_Full_Screen_Update = 1;
1654
1655 if ((*key->f.s == '.')
1656 || !SLang_execute_function (key->f.s))
1657 SLang_load_string(key->f.s);
1658 }
1659
1660 /*}}}*/
1661
slrn_set_prefix_argument(int rep)1662 void slrn_set_prefix_argument (int rep) /*{{{*/
1663 {
1664 static int repeat;
1665
1666 repeat = rep;
1667 Slrn_Prefix_Arg_Ptr = &repeat;
1668 }
1669
1670 /*}}}*/
1671
slrn_digit_arg(void)1672 void slrn_digit_arg (void) /*{{{*/
1673 {
1674 char buf[20];
1675 unsigned char key;
1676 unsigned int i;
1677
1678 i = 0;
1679 buf[i++] = (char) SLang_Last_Key_Char;
1680
1681 SLang_Key_TimeOut_Flag = 1;
1682
1683 while (1)
1684 {
1685 buf[i] = 0;
1686 key = (unsigned char) slrn_getkey ();
1687 if ((key < '0') || (key > '9')) break;
1688 if (i + 1 < sizeof (buf))
1689 {
1690 buf[i] = (char) key;
1691 i++;
1692 }
1693 }
1694
1695 SLang_Key_TimeOut_Flag = 0;
1696 slrn_set_prefix_argument (atoi (buf));
1697
1698 SLang_ungetkey (key);
1699 if ((Slrn_Current_Mode != NULL)
1700 && (Slrn_Current_Mode->keymap != NULL))
1701 slrn_do_keymap_key (Slrn_Current_Mode->keymap);
1702
1703 Slrn_Prefix_Arg_Ptr = NULL;
1704 }
1705
1706 /*}}}*/
1707
slrn_repeat_last_key(void)1708 void slrn_repeat_last_key (void) /*{{{*/
1709 {
1710 SLtt_beep ();
1711 }
1712
1713 /*}}}*/
1714
main(int argc,char ** argv)1715 int main (int argc, char **argv) /*{{{*/
1716 {
1717 if (-1 == main_init_and_parse_args (argc, argv))
1718 return 1;
1719
1720 if (-1 == slrn_select_group_mode ())
1721 return 1;
1722
1723 slrn_push_suspension (1);
1724
1725 (void) slrn_run_hooks (HOOK_GROUP_MODE_STARTUP, 0);
1726
1727 if (Slrn_Batch) return 1;
1728
1729 if (SLang_get_error ())
1730 {
1731 SLang_restart (1); /* prints any queued messages */
1732 slrn_exit_error (_("An error was encountered during initialization."));
1733 }
1734
1735 while (Slrn_Current_Mode != NULL)
1736 {
1737 if (SLKeyBoard_Quit)
1738 {
1739 SLKeyBoard_Quit = 0;
1740 slrn_error (_("Quit!"));
1741 }
1742
1743 (void) slrn_handle_interrupts ();
1744
1745 if (SLang_get_error() || !SLang_input_pending(0))
1746 {
1747 slrn_update_screen ();
1748 }
1749
1750 slrn_do_keymap_key (Slrn_Current_Mode->keymap);
1751 }
1752
1753 return 1;
1754 }
1755
1756 /*}}}*/
1757
1758 /*}}}*/
1759
slrn_posix_system(char * cmd,int reset)1760 int slrn_posix_system (char *cmd, int reset) /*{{{*/
1761 {
1762 int ret;
1763 int init_mode = Slrn_TT_Initialized;
1764
1765 if (reset) slrn_set_display_state (0);
1766 ret = SLsystem (cmd);
1767 if (reset) slrn_set_display_state (init_mode);
1768 Slrn_Full_Screen_Update = 1;
1769 return ret;
1770 }
1771
1772 /*}}}*/
1773