/* -*- mode: C; mode: fold -*- */ /* Copyright (c) 1995, 1996 John E. Davis (davis@space.mit.edu) * All rights reserved. */ #include "config.h" #include "slrnfeat.h" /*{{{ Include files */ #include #include #include #ifdef HAVE_STDLIB_H # include #endif #ifdef HAVE_UNISTD_H # include #endif #ifdef VMS # include "vms.h" #else # if !defined(sun) && !defined(__NT__) # include # endif # ifdef HAVE_TERMIOS_H # include # endif # ifdef SYSV # include # include # include # include # endif # ifndef __os2__ # include # include # endif #endif /* !VMS */ #ifdef HAVE_SYS_WAIT_H # include #endif #include #include "jdmacros.h" #include #include "server.h" #include "slrn.h" #include "group.h" #include "misc.h" #include "startup.h" #include "art.h" #include "score.h" #include "util.h" #include "chmap.h" #if SLRN_HAS_GROUPLENS # include "grplens.h" #endif #if SLRN_HAS_SLANG # include "interp.h" #endif #ifdef __os2__ # define INCL_VIO # include #endif #ifdef __NT__ # include #endif /*}}}*/ /*{{{ Global Variables */ int Slrn_TT_Initialized = 0; /* If -1, force mouse. If 1 the mouse will be used on in XTerm. If 0, * do not use it. */ int Slrn_Use_Mouse; int Slrn_Batch; int Slrn_Suspension_Ok; char *Slrn_Newsrc_File = NULL; char *Slrn_Lib_Dir = NULL; Slrn_Mode_Type *Slrn_Current_Mode; int Slrn_Default_Server_Obj = SLRN_DEFAULT_SERVER_OBJ; int Slrn_Default_Post_Obj = SLRN_DEFAULT_POST_OBJ; /*}}}*/ /*{{{ Static Variables */ static int Can_Suspend; static volatile int Want_Suspension; static volatile int Want_Window_Size_Change; static void perform_suspend (int); static int Current_Mouse_Mode; /*}}}*/ /*{{{ Static Function Declarations */ static int suspend_display_mode (int); static int resume_display_mode (int, int, int); static void init_suspend_signals (int); static void slrn_hangup (int); static void run_winch_functions (int, int); /*}}}*/ /*{{{ Newsrc Locking Routines */ static void test_lock( char *file ) /*{{{*/ { int pid; FILE *fp; if ((fp = fopen (file, "r")) != NULL) { if (1 == fscanf (fp, "%d", &pid) ) { if ((pid > 0) #if !defined(__os2__) && !defined(__NT__) && (0 == kill (pid, 0)) #endif ) { #if defined(__os2__) || defined(__NT__) slrn_exit_error ("\ slrn: pid %d is locking the newsrc file. If you're not running another\n\ copy of slrn, delete the file %s", pid, file); #else slrn_exit_error ("slrn: pid %d is locking the newsrc file.", pid); #endif } } slrn_fclose (fp); } } /*}}}*/ static int make_lock( char *file ) /*{{{*/ { int pid; FILE *fp; #ifdef VMS fp = fopen (file, "w", "fop=cif"); #else fp = fopen (file, "w"); #endif if (fp == NULL) return -1; pid = getpid (); if (EOF == fprintf (fp, "%d", pid)) { slrn_fclose (fp); return -1; } return slrn_fclose (fp); } /*}}}*/ static void lock_file (int how) /*{{{*/ { char file[SLRN_MAX_PATH_LEN]; char name[256]; static int not_ok_to_unlock; #if SLRN_HAS_RNLOCK int rnlock = 0; char file_rn[SLRN_MAX_PATH_LEN]; #endif if (Slrn_Newsrc_File == NULL) return; if (not_ok_to_unlock) return; not_ok_to_unlock = 1; #ifdef SLRN_USE_OS2_FAT slrn_os2_make_fat (name, Slrn_Newsrc_File, ".lck"); #else sprintf (name, "%s-lock", Slrn_Newsrc_File); #endif slrn_make_home_filename (name, file); #if SLRN_HAS_RNLOCK if (0 == strcmp(".newsrc", Slrn_Newsrc_File)) { rnlock = 1; slrn_make_home_filename (".rnlock", file_rn); } #endif if (how == 1) { test_lock (file); #if SLRN_HAS_RNLOCK if (rnlock) test_lock (file_rn); #endif if (-1 == make_lock (file)) { slrn_exit_error ("Unable to create lock file %s.", file); } #if SLRN_HAS_RNLOCK if (rnlock && (-1 == make_lock (file_rn))) { slrn_delete_file (file); /* delete the "normal" lock file */ slrn_exit_error ("Unable to create lock file %s.", file_rn); } #endif } else { if (-1 == slrn_delete_file (file)) { /* slrn_exit_error ("Unable to remove lockfile %s.", file); */ } #if SLRN_HAS_RNLOCK if (rnlock && -1 == slrn_delete_file (file_rn)) { /* slrn_exit_error ("Unable to remove lockfile %s.", file_rn); */ } #endif } not_ok_to_unlock = 0; } /*}}}*/ /*}}}*/ /*{{{ Signal Related Functions */ /*{{{ Low-Level signal-related utility functions */ static void init_like_signals (int argc, int *argv, /*{{{*/ void (*f0)(int), void (*f1)(int), int state) { #ifdef HAVE_SIGACTION struct sigaction sa; #endif int i; if (state == 0) { for (i = 0; i < argc; i++) SLsignal_intr (argv[i], f0); return; } for (i = 0; i < argc; i++) { int sig = argv[i]; SLsignal_intr (sig, f1); #if defined(SLRN_POSIX_SIGNALS) if (-1 != sigaction (sig, NULL, &sa)) { int j; for (j = 0; j < argc; j++) { if (j != i) sigaddset (&sa.sa_mask, argv[j]); } (void) sigaction (sig, &sa, NULL); } #endif } } /*}}}*/ /*}}}*/ /*{{{ Suspension signals */ #ifdef REAL_UNIX_SYSTEM #define SUSPEND_STACK_SIZE 512 static char Suspend_Stack [SUSPEND_STACK_SIZE]; static unsigned int Suspension_Stack_Depth = 0; static int Ok_To_Suspend = 0; #endif static int Suspend_Sigtstp_Suspension = 0; void slrn_push_suspension (int ok) /*{{{*/ { #ifdef REAL_UNIX_SYSTEM if (Suspension_Stack_Depth < SUSPEND_STACK_SIZE) { Suspend_Stack [Suspension_Stack_Depth] = Ok_To_Suspend; } else ok = 0; Suspension_Stack_Depth++; (void) slrn_handle_interrupts (); Ok_To_Suspend = ok; #endif } /*}}}*/ void slrn_pop_suspension (void) /*{{{*/ { #ifdef REAL_UNIX_SYSTEM if (Suspension_Stack_Depth == 0) { slrn_error ("pop_suspension: underflow!"); return; } Suspension_Stack_Depth--; if (Suspension_Stack_Depth < SUSPEND_STACK_SIZE) { Ok_To_Suspend = Suspend_Stack [Suspension_Stack_Depth]; } else Ok_To_Suspend = 0; (void) slrn_handle_interrupts (); #endif } /*}}}*/ /* This function is called by the SIGTSTP handler. Since it operates * in an asynchronous fashion, care must be exercised to control when that * can happen. This is accomplished via the push/pop_suspension functions. */ static void sig_suspend (int sig) { #ifdef REAL_UNIX_SYSTEM sig = errno; if (Ok_To_Suspend && (0 == Suspend_Sigtstp_Suspension)) { perform_suspend (1); } else Want_Suspension = 1; init_suspend_signals (1); errno = sig; #endif } static void init_suspend_signals (int state) /*{{{*/ { int argv[2]; int argc = 0; if (Can_Suspend == 0) return; #ifdef SIGTSTP argv[argc++] = SIGTSTP; #endif #ifdef SIGTTIN argv[argc++] = SIGTTIN; #endif init_like_signals (argc, argv, SIG_DFL, sig_suspend, state); } /*}}}*/ static void perform_suspend (int smg_suspend_flag) /*{{{*/ { #if !defined(SIGSTOP) || !defined(REAL_UNIX_SYSTEM) slrn_error ("Not implemented."); Want_Suspension = 0; #else int init; int mouse_mode = Current_Mouse_Mode; # ifdef SLRN_POSIX_SIGNALS sigset_t mask; Want_Suspension = 0; if (Can_Suspend == 0) { slrn_error ("Suspension not allowed by shell."); return; } sigemptyset (&mask); sigaddset (&mask, SIGTSTP); /* This function resets SIGTSTP to default */ init = suspend_display_mode (smg_suspend_flag); kill (getpid (), SIGTSTP); /* If SIGTSTP is pending, it will be delivered now. That's ok. */ sigprocmask (SIG_UNBLOCK, &mask, NULL); # else Want_Suspension = 0; if (Can_Suspend == 0) { slrn_error ("Suspension not allowed by shell."); return; } init = suspend_display_mode (smg_suspend_flag); kill(getpid(),SIGSTOP); # endif resume_display_mode (smg_suspend_flag, init, mouse_mode); #endif /* !defined(SIGSTOP) || !defined(REAL_UNIX_SYSTEM) */ } /*}}}*/ void slrn_suspend_cmd (void) { perform_suspend (0); } static void check_for_suspension (void) { #ifdef SIGTSTP void (*f)(int); f = SLsignal (SIGTSTP, SIG_DFL); (void) SLsignal (SIGTSTP, f); #if 0 Can_Suspend = (f == SIG_DFL); #else Can_Suspend = (f != SIG_IGN); #endif #else Can_Suspend = 0; #endif } /*}}}*/ /*{{{ Hangup Signals */ void slrn_init_hangup_signals (int state) /*{{{*/ { int argv[2]; int argc = 0; #ifdef SIGHUP argv[argc++] = SIGHUP; #endif #ifdef SIGTERM argv[argc++] = SIGTERM; #endif init_like_signals (argc, argv, SIG_IGN, slrn_hangup, state); } /*}}}*/ /*}}}*/ #ifdef SIGWINCH static void sig_winch_handler (int sig) { if (Slrn_Batch) return; sig = errno; Want_Window_Size_Change = 1; SLsignal_intr (SIGWINCH, sig_winch_handler); errno = sig; } #endif static void slrn_set_screen_size (int sig) /*{{{*/ { int r = 0, c = 0; int old_r, old_c; #ifdef VMS int status, code; unsigned short chan; $DESCRIPTOR(dev_dsc, "SYS$INPUT:"); #endif #ifdef __os2__ VIOMODEINFO vioModeInfo; #endif #ifdef TIOCGWINSZ struct winsize wind_struct; if (Slrn_Batch) return; do { if ((ioctl(1,TIOCGWINSZ,&wind_struct) == 0) || (ioctl(0, TIOCGWINSZ, &wind_struct) == 0) || (ioctl(2, TIOCGWINSZ, &wind_struct) == 0)) { c = (int) wind_struct.ws_col; r = (int) wind_struct.ws_row; break; } } while (errno == EINTR); #else # ifdef VMS status = sys$assign(&dev_dsc,&chan,0,0,0); if (status & 1) { code = DVI$_DEVBUFSIZ; status = lib$getdvi(&code, &chan,0, &c, 0,0); if (!(status & 1)) c = 80; code = DVI$_TT_PAGE; status = lib$getdvi(&code, &chan,0, &r, 0,0); if (!(status & 1)) r = 24; sys$dassgn(chan); } # else # ifdef __os2__ vioModeInfo.cb = sizeof(vioModeInfo); VioGetMode (&vioModeInfo, 0); c = vioModeInfo.col; r = vioModeInfo.row; # else # ifdef __NT__ { extern CONSOLE_SCREEN_BUFFER_INFO csbiInfo; c = csbiInfo.dwSize.X; r = csbiInfo.dwSize.Y; } # endif # endif # endif #endif if (r <= 0) { char *s = getenv ("LINES"); if (s != NULL) r = atoi (s); } if (c <= 0) { char *s = getenv ("COLUMNS"); if (s != NULL) c = atoi (s); } if ((r <= 0) || (r > 200)) r = 24; if ((c <= 0) || (c > 250)) c = 80; old_r = SLtt_Screen_Rows; old_c = SLtt_Screen_Cols; SLtt_Screen_Rows = r; SLtt_Screen_Cols = c; Slrn_Full_Screen_Update = 1; Want_Window_Size_Change = 0; run_winch_functions (old_r, old_c); if (sig) { SLsmg_reset_smg (); SLsmg_init_smg (); slrn_redraw (); } } /*}}}*/ static void init_display_signals (int mode) /*{{{*/ { init_suspend_signals (mode); if (mode) { SLang_set_abort_signal (NULL); #ifdef SIGPIPE SLsignal (SIGPIPE, SIG_IGN); #endif #ifdef SIGTTOU /* Allow background writes */ SLsignal (SIGTTOU, SIG_IGN); #endif #ifdef SIGWINCH SLsignal_intr (SIGWINCH, sig_winch_handler); #endif } else { #ifdef SIGWINCH /* SLsignal_intr (SIGWINCH, SIG_DFL); */ #endif } } /*}}}*/ int slrn_handle_interrupts (void) { if (Want_Suspension) { slrn_suspend_cmd (); } if (Want_Window_Size_Change) { slrn_set_screen_size (1); } return 0; } /*}}}*/ /*{{{ Screen Management and Terminal Init/Reset Functions */ static int init_tty (void) /*{{{*/ { if (Slrn_TT_Initialized & SLRN_TTY_INIT) { return 0; } if (Slrn_TT_Initialized == 0) init_display_signals (1); SLang_init_tty (7, 1, 0); #ifdef REAL_UNIX_SYSTEM SLang_getkey_intr_hook = slrn_handle_interrupts; #endif #ifdef REAL_UNIX_SYSTEM if (Can_Suspend) SLtty_set_suspend_state (1); #endif Slrn_TT_Initialized |= SLRN_TTY_INIT; return 0; } /*}}}*/ static int reset_tty (void) /*{{{*/ { if (0 == (Slrn_TT_Initialized & SLRN_TTY_INIT)) { return 0; } SLang_reset_tty (); Slrn_TT_Initialized &= ~SLRN_TTY_INIT; if (Slrn_TT_Initialized == 0) init_display_signals (0); return 0; } /*}}}*/ static int init_smg (int use_resume, int mouse_mode) /*{{{*/ { if (Slrn_TT_Initialized & SLRN_SMG_INIT) return 0; slrn_enable_mouse (mouse_mode); if (Slrn_TT_Initialized == 0) init_display_signals (1); if (use_resume) { SLsmg_resume_smg (); Slrn_TT_Initialized |= SLRN_SMG_INIT; } else { slrn_set_screen_size (0); SLsmg_init_smg (); Slrn_TT_Initialized |= SLRN_SMG_INIT; /* We do not want the -> overlay cursor to affect the scroll. */ #if !defined(__os2__) && !defined(__NT__) SLsmg_Scroll_Hash_Border = 5; #endif slrn_redraw (); } return 0; } /*}}}*/ static int reset_smg (int smg_suspend_flag) /*{{{*/ { if (0 == (Slrn_TT_Initialized & SLRN_SMG_INIT)) return 0; slrn_enable_mouse (0); if (smg_suspend_flag) SLsmg_suspend_smg (); else { SLsmg_gotorc (SLtt_Screen_Rows - 1, 0); slrn_smg_refresh (); SLsmg_reset_smg (); } /* SLsignal_intr (SIGWINCH, SIG_DFL); */ Slrn_TT_Initialized &= ~SLRN_SMG_INIT; if (Slrn_TT_Initialized == 0) init_display_signals (0); return 0; } /*}}}*/ static int suspend_display_mode (int smg_suspend_flag) /*{{{*/ { int mode = Slrn_TT_Initialized; SLsig_block_signals (); reset_smg (smg_suspend_flag); reset_tty (); SLsig_unblock_signals (); return mode; } /*}}}*/ static int resume_display_mode (int smg_suspend_flag, int mode, int mouse_mode) /*{{{*/ { SLsig_block_signals (); if (mode & SLRN_TTY_INIT) init_tty (); if (mode & SLRN_SMG_INIT) init_smg (smg_suspend_flag, mouse_mode); SLsig_unblock_signals (); return 0; } /*}}}*/ void slrn_set_display_state (int state) /*{{{*/ { if (Slrn_Batch) return; SLsig_block_signals (); if (state & SLRN_TTY_INIT) init_tty (); else reset_tty (); if (state & SLRN_SMG_INIT) init_smg (0, 1); else reset_smg (0); SLsig_unblock_signals (); } /*}}}*/ void slrn_enable_mouse (int mode) /*{{{*/ { if (Current_Mouse_Mode == mode) return; #if !defined(__os2__) && !defined(__NT__) if (Slrn_Use_Mouse) { if (-1 == SLtt_set_mouse_mode (mode, (Slrn_Use_Mouse < 0))) Slrn_Use_Mouse = 0; } #endif Current_Mouse_Mode = mode; } /*}}}*/ /*}}}*/ int slrn_get_new_news (int no_new_groups, int create_flag) /*{{{*/ { char *msg1 = "Checking for new groups ..."; char *msg2 = "Checking news ..."; char *msg3 = "Checking news via active file ..."; char *msg; if (Slrn_Server_Obj->sv_initialize () != 0) return (-1); if (create_flag == 0) { if (no_new_groups == 0) { slrn_message_now (msg1); slrn_check_new_groups (create_flag); } if (Slrn_List_Active_File) msg = msg3; else msg = msg2; slrn_message_now (msg); } slrn_read_newsrc (create_flag); slrn_read_group_descriptions (); return 0; } /*}}}*/ static void perform_cleanup (void) { if (Slrn_Server_Obj != NULL) Slrn_Server_Obj->sv_close (); slrn_set_display_state (0); lock_file (0); #if SLRN_HAS_GROUPLENS slrn_close_grouplens (); #endif if (Slrn_Server_Obj != NULL) Slrn_Server_Obj->sv_close (); #if SLRN_HAS_GROUPLENS slrn_close_grouplens (); #endif #if SLRN_HAS_SLANG (void) slrn_reset_slang (); #endif lock_file (0); } void slrn_quit (int retcode) /*{{{*/ { perform_cleanup (); if (retcode) fprintf (stderr, "slrn: quiting on signal %d.\n", retcode); exit (retcode); } /*}}}*/ void slrn_va_exit_error (char *fmt, va_list ap) { static int trying_to_exit; if (trying_to_exit == 0) { trying_to_exit = 1; slrn_set_display_state (0); if (fmt != NULL) { fprintf (stderr, "slrn fatal error:\n"); vfprintf (stderr, fmt, ap); } if (Slrn_Groups_Dirty) slrn_write_newsrc (); perform_cleanup (); } putc ('\n', stderr); exit (1); } void slrn_exit_error (char *fmt, ...) /*{{{*/ { va_list ap; va_start (ap, fmt); slrn_va_exit_error (fmt, ap); va_end(ap); } /*}}}*/ static void usage (char *extra) /*{{{*/ { fputs ("\ Usage: slrn [--inews ...] [--nntp ...] [--spool ...] OPTIONS\n\ -n Do not check for new groups. This usually results in\n\ a faster startup.\n\ -f newsrc-file Name of the newsrc file to use.\n\ -C Use colors.\n\ -create Create a newsrc file by getting list of groups from server.\n\ -d Get new text descriptions of each group from server.\n\ Note: This may take a LONG time to retrieve this information.\n\ The resulting file can be several hundred Kilobytes!\n\ -i init-file Name of initialization file to use (default .slrnrc)\n\ -Dname Add 'name' to list of predefined preprocessing tokens.\n\ -k Do not process score file.\n\ -k0 Process score file but inhibit expensive scores.\n\ -a Use active file for getting new news\n\ -m Force XTerm mouse reporting\n\ --help Print this usage.\n\ --version Show version and supported features\n\ \n\ For additional info use one of the forms:\n\ slrn --inews --help\n\ slrn --nntp --help\n\ slrn --spool --help\n\ ", stderr); if (extra != NULL) { fprintf (stderr, "\n%s\n", extra); } exit (1); } /*}}}*/ static char *make_slang_version (unsigned int v) { unsigned int a, b, c; static char buf[32]; a = v/10000; b = (v - a * 10000) / 100; c = v - (a * 10000) - (b * 100); sprintf (buf, "%u.%u.%u", a, b, c); return buf; } static void version (void) /*{{{*/ { char *os; #ifdef VMS os = "VMS"; #else # ifdef __os2__ os = "OS/2"; # else # ifdef __unix__ os = "Unix"; # else # ifdef __NT__ os = "Windows"; # else os = "Unknown"; # endif # endif # endif #endif # if defined(__DATE__) && defined(__TIME__) fprintf (stdout, "Slrn Version: %s (%s %s)\n", Slrn_Version, __DATE__, __TIME__); #else fprintf (stdout, "Slrn Version: %s\n", Slrn_Version); #endif fprintf (stdout, "S-Lang Library Version: %s\n", make_slang_version (SLang_Version)); if (SLANG_VERSION != SLang_Version) { fprintf (stdout, "\t** Note: This program was compiled against version %s.\n", make_slang_version (SLANG_VERSION)); } fprintf (stdout, "OS-Type: %s\n", os); fprintf (stdout, "\nslrn compiled with support for:"); #if SLRN_HAS_CHARACTER_MAP fputs ("\n\tcharacter set mapping", stdout); #endif #if SLRN_HAS_NNTP_SUPPORT fputs ("\n\tnntp", stdout); # if SLRN_USE_SLTCP fputs (" (SLtcp socket code)", stdout); # endif # ifdef VMS # ifdef MULTINET fputs (" (Multinet)", stdout); # endif # ifdef UXC fputs (" (UCX)", stdout); # endif # ifdef NETLIB fputs (" (Netlib)", stdout); # endif # endif #endif #if SLRN_HAS_SPOOL_SUPPORT fputs ("\n\tspool", stdout); #endif #if SLRN_HAS_INEWS_SUPPORT fputs ("\n\tinews", stdout); #endif #if SLRN_HAS_PULL_SUPPORT fputs ("\n\tslrnpull", stdout); #endif #if SLRN_HAS_GROUPLENS fputs ("\n\tGroupLens", stdout); #endif #if SLRN_HAS_SLANG fputs ("\n\tS-Lang Macros", stdout); #endif #if SLRN_HAS_MSGID_CACHE fputs ("\n\tMsg-id Cache", stdout); #endif fprintf (stdout, "\n\nDefault server object: %s\n", slrn_map_object_id_to_name (0, SLRN_DEFAULT_SERVER_OBJ)); fprintf (stdout, "Default posting mechanism: %s\n", slrn_map_object_id_to_name (1, SLRN_DEFAULT_POST_OBJ)); #if SLRN_HAS_CHARACTER_MAP slrn_chmap_show_supported (); #endif exit (0); } /*}}}*/ static int parse_object_args (char *obj, char **argv, int argc) /*{{{*/ { int num_parsed; int zero_ok = 1; if (obj == NULL) { zero_ok = 0; obj = slrn_map_object_id_to_name (0, SLRN_DEFAULT_SERVER_OBJ); } num_parsed = slrn_parse_object_args (obj, argv, argc); if (num_parsed < 0) { if (num_parsed == -1) slrn_exit_error ("%s is not a supported option.", *argv); else slrn_exit_error ("%s is not supported.", obj); } if ((num_parsed == 0) && (zero_ok == 0)) usage (NULL); return num_parsed; } /*}}}*/ static void read_score_file (void) { char file[SLRN_MAX_PATH_LEN]; if (Slrn_Score_File == NULL) return; slrn_make_home_filename (Slrn_Score_File, file); if (-1 == slrn_read_score_file (file)) { slrn_exit_error ("Error processing score file %s.", file); } } static int main_init_and_parse_args (int argc, char **argv) /*{{{*/ { char *hlp_file; unsigned int i; int create_flag = 0; int no_new_groups = 0; int no_score_file = 0; int use_color = 0; int use_mouse = 0; int dsc_flag = 0; int use_active = 0; FILE *fp; char file [SLRN_MAX_PATH_LEN]; char *init_file = SLRN_USER_SLRNRC_FILENAME; check_for_suspension (); #ifdef __unix__ (void) umask (077); #endif /* These are already available if the interpreter is available */ #if !SLRN_HAS_SLANG # ifdef __os2__ SLdefine_for_ifdef ("OS2"); # else # ifdef VMS SLdefine_for_ifdef ("VMS"); # else # ifdef __NT__ SLdefine_for_ifdef ("NT"); # else SLdefine_for_ifdef ("UNIX"); # endif # endif # endif #endif #if 0 if (NULL != getenv ("AUTOSUBSCRIBE")) Slrn_Unsubscribe_New_Groups = 0; if (NULL != getenv ("AUTOUNSUBSCRIBE")) Slrn_Unsubscribe_New_Groups = 1; #endif for (i = 1; i < (unsigned int) argc; i++) { char *argv_i = argv[i]; if ((argv_i[0] == '-') && (argv_i[1] == '-')) { int status; argv_i += 2; status = slrn_parse_object_args (argv_i, NULL, 0); if (status != -1) i += parse_object_args (argv_i, argv + (i + 1), argc - (i + 1)); #if 0 else if (!strcmp ("batch", argv_i)) Slrn_Batch = 1; #endif else if (!strcmp ("create", argv_i)) create_flag = 1; else if (!strcmp ("version", argv_i)) version (); else usage (NULL); } else if (!strcmp ("-create", argv_i)) create_flag = 1; else if (!strcmp ("-C", argv_i)) use_color = 1; else if (!strcmp ("-C-", argv_i)) use_color = -1; else if (!strcmp ("-a", argv_i)) use_active = 1; else if (!strcmp ("-n", argv_i)) no_new_groups = 1; else if (!strcmp ("-d", argv_i)) dsc_flag = 1; else if (!strcmp ("-m", argv_i)) use_mouse = 1; else if (!strcmp ("-k", argv_i)) no_score_file = 1; else if (!strcmp ("-k0", argv_i)) Slrn_Perform_Scoring &= ~SLRN_EXPENSIVE_SCORING; else if (!strncmp ("-D", argv_i, 2) && (argv_i[2] != 0)) { if (-1 == SLdefine_for_ifdef (argv_i + 2)) { slrn_exit_error ("Unable to add preprocessor name %s.", argv_i + 2); } } else if (i + 1 < (unsigned int) argc) { if (!strcmp ("-f", argv_i)) Slrn_Newsrc_File = argv[++i]; else if (!strcmp ("-i", argv_i)) init_file = argv[++i]; else { i += parse_object_args (NULL, argv + i, argc - i); i -= 1; } } else { i += parse_object_args (NULL, argv + i, argc - i); i -= 1; } } #if defined(__DATE__) && defined(__TIME__) fprintf (stdout, "slrn %s (%s %s)\n", Slrn_Version, __DATE__, __TIME__); #else fprintf (stdout, "slrn %s\n", Slrn_Version); #endif if (dsc_flag && create_flag) { usage ("The -d and -create flags must not be specified together."); } if (Slrn_Batch == 0) { SLtt_get_terminfo (); if (use_color == 1) SLtt_Use_Ansi_Colors = 1; else if (use_color == -1) SLtt_Use_Ansi_Colors = 0; } #if SLRN_HAS_SLANG if (-1 == slrn_init_slang ()) fprintf (stderr, "Error initializing S-Lang interpreter.\n"); #endif slrn_startup_initialize (); /* The next function call will also define slang preprocessing tokens * for the appropriate objects. For that reason, it is called after * startup initialize. */ if (-1 == slrn_init_objects ()) { slrn_exit_error ("Error configuring server objects."); } slrn_get_user_info (); slrn_init_hangup_signals (1); if (Slrn_Lib_Dir == NULL) { Slrn_Lib_Dir = getenv ("SLRN_LIB_DIR"); } if (Slrn_Lib_Dir == NULL) Slrn_Lib_Dir = SLRN_LIB_DIR; #ifdef VMS sprintf (file, "%s%s", Slrn_Lib_Dir, "slrn.rc"); #else sprintf (file, "%s/%s", Slrn_Lib_Dir, "slrn.rc"); #endif /* Make sure terminal is initialized before setting colors. The * SLtt_get_terminfo call above fixed that. */ slrn_read_startup_file (file); /* global file for all users */ slrn_read_startup_file (init_file); if (Slrn_Server_Id == 0) Slrn_Server_Id = Slrn_Default_Server_Obj; if (Slrn_Post_Id == 0) Slrn_Post_Id = Slrn_Default_Post_Obj; #if SLRN_HAS_CHARACTER_MAP if (-1 == slrn_set_charset (Slrn_Charset)) { slrn_chmap_show_supported (); slrn_exit_error ("Failed to select character set."); } #endif #ifdef SIGINT if (Slrn_TT_Initialized == 0) SLsignal_intr (SIGINT, SIG_DFL); #endif if ((-1 == slrn_select_server_object (Slrn_Server_Id)) || (-1 == slrn_select_post_object (Slrn_Post_Id))) { slrn_exit_error ("Unable to select server/post object."); } #if !defined(__os2__) && !defined(__NT__) /* Allow blink characters if in mono */ if (SLtt_Use_Ansi_Colors == 0) SLtt_Blink_Mode = 1; #endif /* Now that we have read in the startup file, check to see if the user * has a username and a usable hostname. Without those, we are not * starting up. */ if (0 == slrn_is_fqdn (Slrn_User_Info.host)) { slrn_exit_error ("\ Unable to find a fully qualified hostname. You will have to specify a\r\n\ hostname in your %s file.\r\n", SLRN_USER_SLRNRC_FILENAME); } if ((NULL == Slrn_User_Info.username) || (0 == *Slrn_User_Info.username) || (NULL != slrn_strchr (Slrn_User_Info.username, '@'))) { slrn_exit_error ("\ Unable to find your user name. This means that a valid 'From' header line\r\n\ cannot be constructed. Try setting the USER environment variable.\r\n"); } if (no_score_file == 0) read_score_file (); hlp_file = getenv ("SLRNHELP"); if (hlp_file != NULL) { slrn_parse_helpfile (hlp_file); } if ((Slrn_Newsrc_File == NULL) && ((Slrn_Newsrc_File = slrn_map_file_to_host (Slrn_Server_Obj->sv_name)) == NULL)) #if defined(VMS) || defined(__os2__) || defined(__NT__) Slrn_Newsrc_File = "jnews.rc"; #else Slrn_Newsrc_File = ".jnewsrc"; #endif if (use_active) Slrn_List_Active_File = 1; if (use_mouse) Slrn_Use_Mouse = -1; /* -1 forces it. */ if (dsc_flag) { if (Slrn_Server_Obj->sv_initialize () != 0) { slrn_exit_error ("Unable to initialize server."); } slrn_get_group_descriptions (); Slrn_Server_Obj->sv_close (); exit (0); } if (create_flag == 0) { /* Check to see if the .newrc file exists--- I should use the access * system call but for now, do it this way. */ if (NULL == (fp = slrn_open_home_file (Slrn_Newsrc_File, "r", file, 0))) { fprintf(stderr, "Unable to open %s. I will try .newsrc.\n", file); if (NULL == (fp = slrn_open_home_file (".newsrc", "r", file, 0))) { slrn_exit_error ("\r\nUnable to open %s.\r\n\ If you want to create %s, add command line options:\r\n\ -f %s -create\r\n", file, file, file); } } slrn_fclose (fp); } lock_file (1); #if SLRN_HAS_SLANG (void) SLang_run_hooks ("startup_hook", 0); #endif #if SLRN_HAS_GROUPLENS if (Slrn_Server_Id != SLRN_SERVER_ID_NNTP) Slrn_Use_Group_Lens = 0; if (Slrn_Use_Group_Lens && (Slrn_Batch == 0)) { slrn_message ("Initializing GroupLens"); if (-1 == slrn_init_grouplens ()) { fprintf (stderr, "GroupLens disabled.\n"); Slrn_Use_Group_Lens = 0; } } #endif if (-1 == slrn_get_new_news (no_new_groups, create_flag)) { slrn_exit_error ("Failed to initialize server."); } putc ('\n', stdout); slrn_set_display_state (SLRN_SMG_INIT | SLRN_TTY_INIT); #if defined(__unix__) && !defined(__os2__) && !defined(__NT__) if (Slrn_Autobaud) SLtt_Baud_Rate = SLang_TT_Baud_Rate; #endif return 0; } /*}}}*/ /*{{{ Main Loop and Key Processing Functions */ #define MAX_MODE_STACK_LEN 15 /* Allow one extra because the top one is the current mode */ static Slrn_Mode_Type *Mode_Stack [MAX_MODE_STACK_LEN + 1]; static unsigned int Mode_Stack_Depth; void slrn_push_mode (Slrn_Mode_Type *mode) { if (Mode_Stack_Depth == MAX_MODE_STACK_LEN) slrn_exit_error ("Internal Error: Mode_Stack overflow"); Mode_Stack[Mode_Stack_Depth] = Slrn_Current_Mode; Mode_Stack_Depth++; Mode_Stack[Mode_Stack_Depth] = Slrn_Current_Mode = mode; Slrn_Full_Screen_Update = 1; if ((mode != NULL) && (mode->enter_mode_hook != NULL)) (*mode->enter_mode_hook) (); } void slrn_pop_mode (void) { if (Mode_Stack_Depth == 0) slrn_exit_error ("Internal Error: Mode_Stack underflow"); Mode_Stack [Mode_Stack_Depth] = NULL; /* null current mode */ Mode_Stack_Depth--; Slrn_Current_Mode = Mode_Stack[Mode_Stack_Depth]; Slrn_Full_Screen_Update = 1; if ((Slrn_Current_Mode != NULL) && (Slrn_Current_Mode->enter_mode_hook != NULL)) (*Slrn_Current_Mode->enter_mode_hook) (); } void slrn_update_screen (void) { Slrn_Mode_Type *mode; unsigned int i, imax; if (Slrn_Batch) return; slrn_push_suspension (0); imax = Mode_Stack_Depth + 1; /* include current mode */ for (i = 0; i < imax; i++) { Slrn_Full_Screen_Update = 1; mode = Mode_Stack [i]; if ((mode != NULL) && (mode->redraw_fun != NULL)) (*mode->redraw_fun) (); } slrn_smg_refresh (); slrn_pop_suspension (); } static void run_winch_functions (int old_r, int old_c) { Slrn_Mode_Type *mode; unsigned int i, imax; imax = Mode_Stack_Depth + 1; /* include current */ for (i = 0; i < imax; i++) { mode = Mode_Stack [i]; if ((mode != NULL) && (mode->sigwinch_fun != NULL)) (*mode->sigwinch_fun) (old_r, old_c); } #if SLRN_HAS_SLANG if (SLang_Error == 0) SLang_run_hooks ("resize_screen_hook", 0); #endif } static void slrn_hangup (int sig) /*{{{*/ { Slrn_Mode_Type *mode; unsigned int i; slrn_init_hangup_signals (0); i = Mode_Stack_Depth + 1; /* include current */ while (i != 0) { i--; mode = Mode_Stack [i]; if ((mode != NULL) && (mode->hangup_fun != NULL)) (*mode->hangup_fun) (sig); } slrn_write_newsrc (); slrn_quit (sig); } /*}}}*/ void slrn_call_command (char *cmd) /*{{{*/ { SLKeymap_Function_Type *list; if ((Slrn_Current_Mode == NULL) || (Slrn_Current_Mode->keymap == NULL)) list = NULL; else list = Slrn_Current_Mode->keymap->functions; while ((list != NULL) && (list->name != NULL)) { if (0 == strcmp (cmd, list->name)) { (void) (*list->f) (); return; } list++; } slrn_error ("call: %s not in current keymap.", cmd); } /*}}}*/ static int slrn_getkey (void) { static char buf[32]; static unsigned int buf_len; static int timeout_active; int ch; if (SLang_Key_TimeOut_Flag == 0) { timeout_active = 0; buf_len = 0; } else if ((timeout_active || (0 == SLang_input_pending (10))) && (buf_len + 2 < sizeof (buf))) { int r, c; buf[buf_len] = '-'; buf[buf_len + 1] = 0; slrn_push_suspension (0); r = SLsmg_get_row (); c = SLsmg_get_column (); slrn_message (buf); SLsmg_gotorc (r, c); slrn_smg_refresh (); slrn_pop_suspension (); timeout_active = 1; } ch = SLang_getkey (); if (buf_len + 4 < sizeof (buf)) { if (ch == 0) { /* Need to handle NULL character. */ buf[buf_len++] = '^'; buf[buf_len] = '@'; } else if (ch == 27) { buf[buf_len++] = 'E'; buf[buf_len++] = 'S'; buf[buf_len++] = 'C'; buf[buf_len] = ' '; } else buf[buf_len] = (char) ch; } buf_len++; return ch; } void slrn_do_keymap_key (SLKeyMap_List_Type *map) /*{{{*/ { SLang_Key_Type *key; static SLKeyMap_List_Type *last_map; static SLang_Key_Type *last_key; Suspend_Sigtstp_Suspension = 1; key = SLang_do_key (map, slrn_getkey); Suspend_Sigtstp_Suspension = 0; if (Slrn_Message_Present || SLang_Error) { #if SLRN_HAS_SLANG if (SLang_Error) SLang_restart (0); #endif slrn_clear_message (); } SLang_Error = SLKeyBoard_Quit = 0; if ((key == NULL) || (key->type == 0)) { SLtt_beep (); return; } if (key->type == SLKEY_F_INTRINSIC) { if ((map == last_map) && (key->f.f == (FVOID_STAR) slrn_repeat_last_key)) key = last_key; /* set now to avoid problems with recursive call */ last_key = key; last_map = map; if (key->type == SLKEY_F_INTRINSIC) { (((void (*)(void))(key->f.f)) ()); return; } } /* Otherwise we have interpreted key. */ #if SLRN_HAS_SLANG last_key = key; last_map = map; Slrn_Full_Screen_Update = 1; if ((*key->f.s == '.') || !SLang_execute_function (key->f.s)) SLang_load_string(key->f.s); #endif } /*}}}*/ void slrn_set_prefix_argument (int rep) /*{{{*/ { static int repeat; repeat = rep; Slrn_Prefix_Arg_Ptr = &repeat; } /*}}}*/ void slrn_digit_arg (void) /*{{{*/ { char buf[20]; unsigned char key; int i; i = 0; buf[i++] = (char) SLang_Last_Key_Char; SLang_Key_TimeOut_Flag = 1; while (1) { buf[i] = 0; key = (unsigned char) slrn_getkey (); if ((key < '0') || (key > '9')) break; buf[i++] = (char) key; } SLang_Key_TimeOut_Flag = 0; slrn_set_prefix_argument (atoi (buf)); SLang_ungetkey (key); if ((Slrn_Current_Mode != NULL) && (Slrn_Current_Mode->keymap != NULL)) slrn_do_keymap_key (Slrn_Current_Mode->keymap); Slrn_Prefix_Arg_Ptr = NULL; } /*}}}*/ void slrn_repeat_last_key (void) /*{{{*/ { SLtt_beep (); } /*}}}*/ int main (int argc, char **argv) /*{{{*/ { if (-1 == main_init_and_parse_args (argc, argv)) return 1; if (-1 == slrn_select_group_mode ()) return 1; slrn_push_suspension (1); #if SLRN_HAS_SLANG (void) SLang_run_hooks ("group_mode_startup_hook", 0); #endif if (Slrn_Batch) return 1; while (Slrn_Current_Mode != NULL) { if (SLKeyBoard_Quit) { SLKeyBoard_Quit = 0; slrn_error ("Quit!"); } (void) slrn_handle_interrupts (); if (SLang_Error || !SLang_input_pending(0)) { slrn_update_screen (); } slrn_do_keymap_key (Slrn_Current_Mode->keymap); } return 1; } /*}}}*/ /*}}}*/ int slrn_posix_system (char *cmd, int reset) /*{{{*/ { int ret; int init_mode = Slrn_TT_Initialized; if (reset) slrn_set_display_state (0); ret = SLsystem (cmd); if (reset) slrn_set_display_state (init_mode); Slrn_Full_Screen_Update = 1; return ret; } /*}}}*/