ftp.nice.ch/pub/next/unix/network/news/slrn0.9.0.0.s.tar.gz#/slrn/src/slrn.c

This is slrn.c in view mode; [Download] [Up]

/*  Copyright (c) 1995 John E. Davis (davis@space.mit.edu)
 *  All rights reserved.
 */
#include "config.h"
#include "features.h"

#include <stdio.h>
#include <signal.h>
#include <string.h>


#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif

#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif

#ifdef VMS
# include <unixlib.h>
# include <unixio.h>
# include <dvidef.h>
# include <descrip.h>
#else
# ifndef sun
#  include <sys/ioctl.h>
# endif
# ifdef HAVE_TERMIOS_H
#  include <termios.h>
# endif
# ifdef SYSV
#  include <sys/termio.h>
#  include <sys/stream.h>
#  include <sys/ptem.h>
#  include <sys/tty.h>
# endif
#endif /* !VMS */

#include <slang.h>
#include "jdmacros.h"


#include <errno.h>

#include "server.h"
#include "slrn.h"
#include "group.h"
#include "misc.h"
#include "startup.h"
#include "art.h"
#include "score.h"
#if SLRN_HAS_GROUPLENS
# include "grplens.h"
#endif
#if SLRN_HAS_SLANG
# include "interp.h"
#endif
#ifdef __os2__
# define INCL_VIO
# include <os2.h>
#endif

#ifdef SIGSTOP
# define USE_RESUME_SMG
#endif

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;
char *Slrn_Version = SLRN_VERSION;

int Slrn_Suspension_Ok;
void slrn_set_suspension (int ok)
{
   if (ok == Slrn_Suspension_Ok) return;
#ifdef USE_RESUME_SMG
   SLtty_set_suspend_state (ok);
#endif
   Slrn_Suspension_Ok = ok;
}

void slrn_smg_refresh (void)
{
   int ok = Slrn_Suspension_Ok;
   if (ok) slrn_set_suspension (0);
   if (Slrn_TT_Initialized & 1) SLsmg_refresh ();
   if (ok) slrn_set_suspension (1);
}

static void set_signal_to_restart_syscalls (int sig)
{
#ifdef SLRN_POSIX_SIGNALS
   struct sigaction sa;
   
   if (-1 == sigaction (sig, NULL, &sa)) return;
   
# ifdef SIGALRM
   if (sig == SIGALRM)
     {
#  ifdef SA_INTERRUPT
	sa.sa_flags |= SA_INTERRUPT;
#  endif
     }
   else
     {
# endif				       /* SIGALRM */
# ifdef SA_RESTART
	sa.sa_flags |= SA_RESTART;
# endif
# ifdef SIGALRM
     }
# endif
   
   (void) sigaction (sig, &sa, NULL);

#endif				       /* SLRN_POSIX_SIGNALS */
}



static int Can_Suspend;

void slrn_suspend (int sig)
{
#ifndef SIGSTOP
   slrn_error ("Not implemented.");
#else
   
   int init = Slrn_TT_Initialized;
# ifdef SLRN_POSIX_SIGNALS
   sigset_t mask;

   if (Can_Suspend == 0)
     {
	slrn_error ("Suspension not allowed by shell.");
	return;
     }
   
   sigemptyset (&mask);
   sigaddset (&mask, SIGTSTP);
   
   /* This function resets SIGTSTP to default */
   slrn_reset_display (sig);
   
   kill (getpid (), SIGTSTP);
   
   /* If SIGTSTP is pending, it will be delivered now.  That's ok. */
   sigprocmask (SIG_UNBLOCK, &mask, NULL);
# else
   
   if (Can_Suspend == 0)
     {
	slrn_error ("Suspension not allowed by shell.");
	return;
     }
   
   slrn_reset_display (sig);
   kill(getpid(),SIGSTOP);
# endif
   
   slrn_init_display (init, sig);
   
   if (Slrn_Suspension_Ok) SLtty_set_suspend_state (1);
#endif
}

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) && (0 == kill (pid, 0)))
	       {
		  slrn_exit_error ("slrn: pid %d is locking the newsrc file.", pid);
	       }
	  }
	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 ();
   fprintf (fp, "%d", pid);
   slrn_fclose (fp);
   return 0;
}


static void lock_file (int how)
{
   char file[1024];
   char name[256];
   static int not_ok_to_unlock;
#if SLRN_HAS_RNLOCK
   int rnlock = 0;
   char file_rn[1024];
#endif
   
   if (Slrn_Newsrc_File == NULL) return;
   if (not_ok_to_unlock) return;
   
   not_ok_to_unlock = 1;

#ifndef __os2__
   sprintf (name, "%s-lock", Slrn_Newsrc_File);
#else
   sprintf (name, "lk-%s", 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;
}


static void slrn_set_screen_size (int sig)
{
   int r = 0, c = 0;
#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;
   
   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);
   
#endif
#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);
     }
#endif

#ifdef __os2__
   vioModeInfo.cb = sizeof(vioModeInfo);
   VioGetMode (&vioModeInfo, 0);
   c = vioModeInfo.col;
   r = vioModeInfo.row;   
#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;
   SLtt_Screen_Rows = r;
   SLtt_Screen_Cols = c;
   
   Slrn_Group_Window_Size = SLtt_Screen_Rows - 3;
   
#ifdef SIGWINCH
   if (sig == SIGWINCH)
     {
	SLsmg_reset_smg ();
	SLsmg_init_smg ();
	
	if ((Slrn_Current_Mode != NULL)
	    && (Slrn_Current_Mode->sigwinch_fun != NULL))
	  (*Slrn_Current_Mode->sigwinch_fun) ();
	
	slrn_redraw ();
     }
   signal (SIGWINCH, slrn_set_screen_size);
#endif
}



static void slrn_hangup (int sig)
{
   slrn_init_hangup_signals (0);
   
   if ((Slrn_Current_Mode != NULL)
       && (Slrn_Current_Mode->hangup_fun != NULL))
     (*Slrn_Current_Mode->hangup_fun) (sig);
   else
     slrn_write_newsrc ();
   
   slrn_quit (sig);
}


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++)
	  signal (argv[i], f0);
	return;
     }

   for (i = 0; i < argc; i++)
     {
	int sig = argv[i];
	signal (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
     }
}

static void init_suspend_signals (int state)
{
   int argv[2];
   int argc = 0;
   
#ifdef SIGTSTP
   argv[argc++] = SIGTSTP;
#endif
   
#ifdef SIGTTIN
   argv[argc++] = SIGTTIN;
#endif

   init_like_signals (argc, argv, SIG_DFL, slrn_suspend, state);
}

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);
}

void slrn_enable_mouse (int mode)
{
#ifndef __os2__
   if (Slrn_Use_Mouse)
     {
	if (-1 == SLtt_set_mouse_mode (mode, (Slrn_Use_Mouse < 0)))
	  Slrn_Use_Mouse = 0;
     }
#endif
}


/* if 1, init just slsmg.  If 2, just sltt, if 3, do both */
void slrn_init_display (int init_mode, int sig)
{
   Slrn_TT_Initialized |= init_mode;
   
   init_suspend_signals (1);
   
#ifdef SIGPIPE
   signal(SIGPIPE, SIG_IGN);
#endif
#ifdef SIGTTOU
   /* Allow background writes */
   signal (SIGTTOU, SIG_IGN);
#endif
   
   slrn_init_hangup_signals (1);
   
   if (init_mode & 2)
     {
	SLang_init_tty (7, 1, 0);
	SLang_set_abort_signal (NULL);
#ifdef SIGINT
	set_signal_to_restart_syscalls (SIGINT);
#endif
     }
   
   if (init_mode & 1)
     {
	slrn_enable_mouse (1);
#ifdef USE_RESUME_SMG
	if (sig == SIGTSTP) SLsmg_resume_smg ();
	else
	  {
#endif
	     slrn_set_screen_size (0);
	     SLsmg_init_smg ();
	     
	     /* We do not want the -> overlay cursor to affect the scroll. */
#ifndef __os2__
	     SLsmg_Scroll_Hash_Border = 2;
#endif
	     slrn_redraw ();
	  }
#ifdef USE_RESUME_SMG
     }
#endif
}

void slrn_reset_display (int sig)
{
   int init = Slrn_TT_Initialized;
   
   if (init == 0) return;
   
   slrn_enable_mouse (0);
   
#ifdef USE_RESUME_SMG
   if (sig == SIGTSTP) SLsmg_suspend_smg ();
   else
     {
#endif
	SLsmg_gotorc (SLtt_Screen_Rows - 1, 0);
	slrn_smg_refresh ();
	SLsmg_reset_smg ();
#ifdef SIGWINCH
	signal (SIGWINCH, SIG_DFL);
#endif
#ifdef USE_RESUME_SMG
     }
#endif
   
   if (init & 2) SLang_reset_tty ();
   
   init_suspend_signals (0);
   
   Slrn_TT_Initialized = 0;
}

void slrn_tty_message (int newline_flag, char *fmt, ...)
{
   va_list ap;
   
   if (newline_flag & 1) putc ('\n', stdout);
   va_start (ap, fmt);
   vfprintf (stdout, fmt, ap);
   va_end(ap);
   if (newline_flag & 2) putc ('\n', stdout);
   fflush (stdout);
}


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)
	  {
	     if (Slrn_TT_Initialized & 1)
	       {
		  slrn_message (msg1);
		  slrn_smg_refresh ();
	       }
	     else
	       slrn_tty_message (1, msg1);
	     
	     slrn_check_new_groups (create_flag);
	  }
	
	if (Slrn_List_Active_File) msg = msg3;
	else msg = msg2;
	
	if (Slrn_TT_Initialized & 1)
	  {
	     slrn_message (msg);
	     slrn_smg_refresh ();
	  }
	else
	  slrn_tty_message (1, msg);
     }
   slrn_read_newsrc (create_flag);
   
   slrn_read_group_descriptions ();
   
   return (0);
}

char *Slrn_Newsrc_File = NULL;
char *Slrn_Lib_Dir = NULL;

#if !defined (SLRN_DEFAULT_SERVER_OBJ)
# if SLRN_HAS_NNTP_SUPPORT
#  define SLRN_DEFAULT_SERVER_OBJ SLRN_SERVER_ID_NNTP
# else
#  define SLRN_DEFAULT_SERVER_OBJ SLRN_SERVER_ID_SPOOL
# endif
#endif

#if !defined (SLRN_DEFAULT_POST_OBJ)
# if SLRN_HAS_NNTP_SUPPORT
#  define SLRN_DEFAULT_POST_OBJ SLRN_POST_ID_NNTP
# else
#  define SLRN_DEFAULT_POST_OBJ SLRN_POST_ID_INEWS
# endif
#endif


static void version (void)
{
   unsigned int a, b, c;
   
   a = SLANG_VERSION/10000;
   b = (SLANG_VERSION  - a * 10000) / 100;
   c = SLANG_VERSION - (a * 10000) - (b * 100);
   
#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 version: %u.%u.%u\n", a, b, c);
   
   fprintf (stdout, "\nslrn compiled with support for:\n");
#if SLRN_HAS_NNTP_SUPPORT
   fputs (" nntp", stdout);
#endif
#if SLRN_HAS_SPOOL_SUPPORT
   fputs (" spool", stdout);
#endif
#if SLRN_HAS_INEWS_SUPPORT
   fputs (" inews", stdout);
#endif
#if SLRN_HAS_GROUPLENS
   fputs (" GroupLens", stdout);
#endif
#if SLRN_HAS_SLANG
   fputs (" S-Lang", stdout);
#endif
   fputs ("\nDefault server object: ", stdout);
   switch (SLRN_DEFAULT_SERVER_OBJ)
     {
      case SLRN_SERVER_ID_NNTP:
	fputs ("nntp", stdout);
	break;

      case SLRN_SERVER_ID_SPOOL:
	fputs ("spool", stdout);
	break;
     }
   
   fputs ("\nDefault posting mechanism: ", stdout);
   switch (SLRN_DEFAULT_POST_OBJ)
     {
      case SLRN_POST_ID_NNTP:
	fputs ("nntp", stdout);
	break;

      case SLRN_POST_ID_INEWS:
	fputs ("inews", stdout);
#if SLRN_FORCE_INEWS
	fputs (" (fixed)", stdout);
#endif
	break;
     }
   
   fputc ('\n', stdout);
   exit (0);
}

   
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 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 int parse_object_args (char *obj, char **argv, int argc)
{
   int num_parsed;
   int zero_ok = 1;
   
   if (obj == NULL)
     {
	zero_ok = 0;
#if SLRN_DEFAULT_SERVER_OBJ == SLRN_SERVER_ID_SPOOL
	obj = "spool";
#endif
#if SLRN_DEFAULT_SERVER_OBJ == SLRN_SERVER_ID_NNTP
	obj = "nntp";
#endif
     }
   
   num_parsed = slrn_parse_object_args (obj, argv, argc);
   if (num_parsed == -1)
     {
	slrn_exit_error ("%s is not a supported option.", *argv);
     }
   if ((num_parsed == 0) && (zero_ok == 0))
     usage (NULL);
   
   return num_parsed;
}

int main (int argc, char **argv)
{
   char *hlp_file;
   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[512];
   char *init_file = SLRN_USER_SLRNRC_FILENAME;
   
   Can_Suspend = 0;
#ifdef SIGTSTP
   if (SIG_DFL == signal (SIGTSTP, SIG_DFL))
     {     
	Can_Suspend = 1;
     }
#endif
   
#ifdef __os2__
   SLdefine_for_ifdef ("OS2");
#else
# ifdef VMS
   SLdefine_for_ifdef ("VMS");
# else
   SLdefine_for_ifdef ("UNIX");
# 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 < argc; i++)
     {
	if (!strcmp ("--spool", argv[i])
	    || !strcmp ("--nntp", argv[i])
	    || !strcmp ("--inews", argv[i]))
	  {
	     i += parse_object_args (argv[i] + 2, argv + (i + 1), argc - (i + 1));
	  }
	else if (!strcmp ("--help", argv[i])) usage (NULL);
	else if (!strcmp ("-create", argv[i])) create_flag = 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 (!strcmp ("--version", argv[i]))
	  {
	     version ();
	  }
	else if (!strncmp ("-D", argv[i], 2) && (argv[i][2] != 0))
	  {
	     if (SLdefine_for_ifdef (argv[i] + 2) == 0)
	       {
		  slrn_exit_error ("Unable to add preprocessor name %s.",
				   argv[i] + 2);
	       }
	  }
	else if (i + 1 < 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 (-1 == slrn_init_objects ())
     {
	slrn_exit_error ("Error configuring server objects.");
     }


   if (Slrn_Server_Id == 0) Slrn_Server_Id = SLRN_DEFAULT_SERVER_OBJ;
   if (Slrn_Post_Id == 0) Slrn_Post_Id = SLRN_DEFAULT_POST_OBJ;

   /* It has been suggested that this be moved to after reading the startup 
    * files.
    */
   if ((-1 == slrn_select_server_object (Slrn_Server_Id))
       || (-1 == slrn_select_post_object (Slrn_Post_Id)))
     {
	slrn_exit_error ("Unable to select object.");
     }
     
   fprintf (stdout, "slrn %s\n", Slrn_Version);

   if (dsc_flag && create_flag)
     {
	usage ("The -d and -create flags must not be specified together.");
     }
   
   SLtt_get_terminfo();
   if (use_color) SLtt_Use_Ansi_Colors = 1;
   slrn_startup_initialize ();
   slrn_get_user_info ();
   
   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

#if SLRN_HAS_SLANG
   if (-1 == slrn_init_slang ())
     {
	fprintf (stderr, "Error initializing S-Lang interpreter.\n");
     }
#endif
   slrn_read_startup_file (file);      /* global file for all users */
   slrn_read_startup_file (init_file);
   
#ifndef __os2__
   /* 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 you 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) && (Slrn_Score_File != NULL)
       && (-1 == slrn_read_score_file (Slrn_Score_File)))
     {
	slrn_exit_error ("Error processing score file %s", Slrn_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__)
     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.");
	     return (-1);
	  }
	slrn_get_group_descriptions ();
	Slrn_Server_Obj->sv_close ();
	return 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)))
	  {
	     slrn_error ("Unable to open %s.  I will try .newsrc.", 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);
     }

#ifdef SLRN_HAS_SLANG
   (void) SLang_run_hooks ("startup_hook", NULL, NULL);
#endif
   
   
#if SLRN_HAS_GROUPLENS
   if (Slrn_Use_Group_Lens)
     {
	fprintf (stdout, "Initializing GroupLens\n");
	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_init_display (1 | 2, 0);
#if defined(unix) && !defined(__os2__)
   if (Slrn_Autobaud) SLtt_Baud_Rate = SLang_TT_Baud_Rate;
#endif

   slrn_main_loop ();
   
   slrn_quit (0);
   return 0;
}

void slrn_quit (int retcode)
{
   Slrn_Server_Obj->sv_close ();
   slrn_reset_display (0);
   lock_file (0);
#if SLRN_HAS_GROUPLENS
   slrn_close_grouplens ();
#endif
   if (retcode) fprintf (stderr, "slrn: quiting on signal %d.\n", retcode);
   exit (retcode);
}


void slrn_exit_error (char *fmt, ...)
{
   va_list ap;
   
   if (Slrn_Groups_Dirty) slrn_write_newsrc ();
   
   if (Slrn_TT_Initialized)
     {
	slrn_reset_display (0);
	Slrn_Server_Obj->sv_close ();
     }
   
#if SLRN_HAS_GROUPLENS
   slrn_close_grouplens ();
#endif
   if (fmt != NULL)
     {
	va_start (ap, fmt);
	vfprintf (stderr, fmt, ap);
	va_end(ap);
     }
   putc ('\n', stderr);
   lock_file (0);
   exit (-1);
}


int slrn_main_loop (void)
{
   if (-1 == slrn_select_group_mode ())
     return -1;
   
#ifdef SLRN_HAS_SLANG
   (void) SLang_run_hooks ("group_mode_hook", NULL, NULL);
#endif

   while (1)
     {
	if (SLang_Error || !SLang_input_pending(0))
	  {
	     (*Slrn_Current_Mode->redraw_fun) ();
	     slrn_smg_refresh ();
	  }
	slrn_do_key (Slrn_Current_Mode->keymap);
     }
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.