/*
**++
**  FACILITY:
**	NEWS.C
**
**  ABSTRACT:
**	This module contains the main() entry point for the NEWS program.
**
**  AUTHOR:
**	Geoff Huston
**
**  COPYRIGHT:
**	Copyright © 1988,1989,1990,1991
**
**  MODIFICATION HISTORY:
**  Version History:
**      V1.0    17-Jul-1986     GIH
**      V2.0    31-Jan-1987     GIH
**      V3.0     6-Apr-1987     GIH
**      V4.0    30-Oct-1987     GIH
**      V4.02   17-Nov-1987     GIH
**      V4.3    11-Jan-1988     GIH
**      V5.0     2-Feb-1988     GIH
**      V5.1     9-Mar-1988     GIH
**      V5.2    26-Apr-1988     GIH
**      V5.3    16-Jun-1988     GIH
**      V5.5     7-Oct-1988     GIH
**      V5.6    11-Nov-1988     GIH
**      V5.7    15-Nov-1988     GIH
**      V5.8    17-Feb-1988     GIH
**      V5.9    16-Aug-1989     GIH
**	V6.0	 1-Jul-1990	GIH
**	V6.0-4	25-May-1991	volz@process.com
**	  - Added TCPware support
**	V6.1	 2-Feb-1992	rankin@eql.caltech.edu
**	  - update the gcc port; lint cleanup
**	V6.1	 3-Jul-1992	reggers@julian.uwo.ca
**    - allow user to change unseen stack mode after NNTP client start
**	V6.1b6	28-Feb-1993	mark.martinec@ijs.si
**	  - fix strncmp match for generic TCP  (broken by V6.0-4,
**	    so that /PROTOCOL=TCP matched TCPWARE instead of generic TCP)
**	V6.1b7	20-May-1993	Charles Bailey  bailey@genetics.upenn.edu
**	  - add TCPWARE fix to instance missed in above patch
**	V6.1b8	14-Jan-1994	Charles Bailey  bailey@genetics.upenn.edu
**	  - changed handling of /NetServer and /NetProtocol qualifiers
**	    so they override values stored in NewsRC file
**	V6.1b8	18-Jan-1994	Charles Bailey  bailey@genetics.upenn.edu
**	  - fixed bug introduced by 14-Jan-1994 patch which causes remote
**	    session to occur even though News_Root is defined
**	V6.1b9	 1-Jun-1994	mark.martinec@ijs.si
**	  - test for status==0 returned from get_input_general()
**	    which happens when UNWIND takes place during terminal I/O;
**	    this prevents looping in case of SMG I/O errors.
**	V6.1b9	22-Jun-1994	mark.martinec@ijs.si
**	  - make /ON_ERROR=CONTINUE the default for non-interactive sessions
**	  - set the variable 'try_to_quietly_handle_errors' to 1
**	    in case of (on_error==ON_ERROR_CONTINUE) as well
**	V6.1b9	17-Aug-1994     Mark Martinec   mark.martinec@ijs.si
**	  - code cleanup to make it compile under gcc 2.6.0 with full
**	    warnings reporting turned on - with no or very few harmless warnings
**	V6.1b9	17-Sep-1994     Mark Martinec   mark.martinec@ijs.si
**	  - code cleanup to preserve the read-only nature of string literals
**	    (strategically placed 'const' attribute to string parameters)
**	V6.1b10	10-Dec-1996     Mark Pizzolato	mark@infocomm.com
**	  - defined _NEWS_MAIN_PROGRAM which now causes the NEWSVARIABLES.H
**	    to define all global variables instead of merely references to 
**	    them.
**	V6.1b11	21-Feb-1997     Mark Martinec   mark.martinec@ijs.si
**	  - fp_open, fpa_open and fpd_open are now int;
**	    don't try to delete_file_versions(fp*_open);
**	V6.1b11	28-Mar-1997	Mark Martinec   mark.martinec@ijs.si
**	  - use new procedures available_proto, proto_name and name_to_proto
**	    to replace frequent code patterns and to make possible
**	    using ANU with different TCP transport library
**	    without changing NEWSRC user files (automatically changes
**	    requested and unavailable TCP library to the one
**	    that is compiled-in with the program).
**	V6.1b11 14-Apr-1997  Mark Martinec   mark.martinec@ijs.si
**	  - replace several calls to strcpy/strcat with safer strnncpy/strnncat
**--
**/

#ifdef vaxc
#module	NEWS "V6.2"
#endif

#define _NEWS_C
#define module_name "NEWS"

/* Causes variable declarations for things declared in NEWSVARIABLES.H */
#define _NEWS_MAIN_PROGRAM

#include "newsinclude.h"
#include "newsextern.h"

#if MENU_SUPPORT
#include "newsmenu.h" 
#endif


/*
 *  m a i n
 */

extern int profile_flags;

int main(argc,argv)
  int argc; char *argv[];
{
  int status;
  unsigned short temp_len;
  char temp[257], mcommand[513], *gotenv, *in_line = 0, *cp;
  static int cmd_status = 1, one_pass = 0, (*f)();
  int sts, nntp_sts = 0, call_fastscan = 0,
      explicit_server = 0, explicit_proto = 0, hasrc,
      on_error_defaulted = 1;
#if NEWS_INIT
  char fpcl[256];
    /* made static to avoid 'possibly clobbered by longjmp' warning from gcc */
  static FILE *fpc = 0;
#endif
  $DESCRIPTOR(tempdsc,temp);

  /* set initial values to control condition handler (just for now) */
  on_error = ON_ERROR_ABORT; try_to_quietly_handle_errors = 0;

  nosysprv();
  establish_handler(news_condition_handler);
  init_mem();

  *nntp_node = '\0';
  log_to_usage_file(0,0);

  news_assert(NEWS_GRPFIL_RSZ == sizeof(GRPF));
  news_assert(GRPNAMELEN >= GRPNAMELEN_F+1);
  news_assert(test_md5());

  if ((lib$get_foreign(&tempdsc,0,&temp_len,0) & 1) && temp_len) {
    temp[temp_len] = '\0';
    strcpy(mcommand,"INVOKENEWS ");
    strnncat(mcommand,sizeof(mcommand),-1, temp,temp_len, 0);
    if (!(cli$dcl_parse(c$dsc(mcommand),CLICMDTBL,0,0,0) & 1)) exit(1);

    /* first handle the explicit ON_ERROR qualifier value */
    on_error_defaulted = 0;
    if (cli$present(c$dsc("ON_ERROR.HANDLE_OR_ABORT")) & 1)
      { on_error = ON_ERROR_ABORT;    try_to_quietly_handle_errors = 1; }
    else if (cli$present(c$dsc("ON_ERROR.ABORT")) & 1)
      { on_error = ON_ERROR_ABORT;    try_to_quietly_handle_errors = 0; }
    else if (cli$present(c$dsc("ON_ERROR.NEXT_COMMAND")) & 1)
      { on_error = ON_ERROR_UNWIND;   try_to_quietly_handle_errors = 0; }
    else if (cli$present(c$dsc("ON_ERROR.CONTINUE")) & 1)
      { on_error = ON_ERROR_CONTINUE; try_to_quietly_handle_errors = 1; }
    else
      on_error_defaulted = 1;  /* not yet known if the session is interactive */

    if ((sts = cli$present(c$dsc("NETSERVER"))) & 1) {
	/* nntp_sts values:
	 *	-1 = NO server specified
	 *	 0 = not specified
	 *	 1 = server - no node, no proto
	 *	 2 = server - node, no proto
	 *	 3 = server - no node, proto
	 *	 4 = server - node, proto
	 */
      nntp_sts = 1;
      if (cli$get_value(c$dsc("NETSERVER"),&usr_inp_dsc,&usr_inp_l) & 1) {
        usr_inp[usr_inp_l] = '\0';
        lower_case(usr_inp);
        strnncpy(nntp_node,nntp_node_m, usr_inp,usr_inp_l, 0);
        nntp_sts = 2;
        explicit_server = 1;
        }
      else if ( (gotenv = news_getenv("NEWS_NNTP_SERVER",0)) ) {
        strnncpy(nntp_node,nntp_node_m, gotenv,-1, 0);
        lower_case(nntp_node);
        nntp_sts = 2;
        }
      }
    else if (sts == CLI$_NEGATED) {
      nntp_sts = -1;
      }

    if ((nntp_sts != -1) && (cli$present(c$dsc("NETPROTOCOL")) & 1)) {
      if (cli$get_value(c$dsc("NETPROTOCOL"),&usr_inp_dsc,&usr_inp_l) & 1)
        explicit_proto = (usr_inp_l > 0);
      else if ( !(gotenv = news_getenv("NEWS_NNTP_PROTOCOL",0)) ) usr_inp_l = 0;
      else {
        int ll;
        strnncpy(usr_inp,usr_inp_m, gotenv,-1, &ll); usr_inp_l = ll;
        }
      usr_inp[usr_inp_l] = '\0';
      if (usr_inp_l > 0) { 
        nntp_sts = (nntp_sts == 2) ? 4 : 3;
        nntp_proto = name_to_proto(usr_inp,usr_inp_l);
        if (nntp_proto < 0) {
          printf("NEWS/NETPROTOCOL=%s: Not a valid NNTP transport protocol code\n",usr_inp);
          exit(1);
          }
        nntp_proto = available_proto(nntp_proto);
        }
      }

    if (cli$present(c$dsc("SCAN")) & 1) {
      *scangroups = '\0';
      while (cli$get_value(c$dsc("SCAN"),&usr_inp_dsc,&usr_inp_l) & 1) {
        usr_inp[usr_inp_l] = '\0';
        lower_case(usr_inp);
        if (*scangroups) strnncat(scangroups,scangroups_m,-1, ",",1, 0);
        strnncat(scangroups,scangroups_m,-1, usr_inp,usr_inp_l, 0);
        }
      call_fastscan = 1;
      first_retr_call = 0;
      }

    /* Jason Haar - 17/4/91 <cctr127@csc.canterbury.ac.nz>
     * Below initialises the NEWS/CAPTIVE command and makes it take on the 
     * functionality of NEWS/READONLY too
     */
    if (cli$present(c$dsc("CAPTIVE")) & 1) {
      news_captive = 1;
      news_readonly = 1;
      }
    else {
      news_captive = 0;
      news_readonly = 0;
      }

    if ((sts = cli$present(c$dsc("DOTNEWSRC"))) & 1) usedotnewsrc = 3;
    else if (sts == CLI$_NEGATED) usedotnewsrc = 2;
    if (cli$present(c$dsc("READONLY")) & 1) news_readonly = 1;
    if (cli$present(c$dsc("ALLSCAN")) & 1) {
      first_retr_call = 0;
      *scangroups = '\0';
      while (cli$get_value(c$dsc("ALLSCAN"),&usr_inp_dsc,&usr_inp_l) & 1) {
        usr_inp[usr_inp_l] = '\0';
        lower_case(usr_inp);
        if (*scangroups) strnncat(scangroups,scangroups_m,-1, ",",1, 0);
        strnncat(scangroups,scangroups_m,-1, usr_inp,usr_inp_l, 0);
        }
      }
    }
  
  /* if news_root is not defined then 
     assume that an nntp session is whats required */
  if (!nntp_sts && !news_getenv("NEWS_ROOT",1)) {
    if ((gotenv = news_getenv("NEWS_NNTP_SERVER",0)) != 0) {
      strnncpy(nntp_node,nntp_node_m, gotenv,-1, 0);
      lower_case(nntp_node);
      nntp_sts = 2;
      }
    if ( (gotenv = news_getenv("NEWS_NNTP_PROTOCOL",0)) ) {
      strnncpy(usr_inp,usr_inp_m, gotenv,-1, 0);
      nntp_sts = nntp_sts ? 4 : 3;
      nntp_proto = name_to_proto(usr_inp,-1);
      if (nntp_proto < 0) {
        printf("NEWS/NETPROTOCOL=%s: Not a valid NNTP transport protocol code\n",usr_inp);
        exit(1);
        }
      nntp_proto = available_proto(nntp_proto);
      }
    }

    /* get the correct newsrc file name */
  if ( (gotenv = news_getenv("NEWSRC",0)) )
    strnncpy(news_register,news_register_m, gotenv,-1, 0);
  else if ( (gotenv = news_getenv("NEWS_REGISTER",0)) )
    strnncpy(news_register,news_register_m, gotenv,-1, 0);
  else
    strnncpy(news_register,news_register_m, User_file,-1, 0);
  chop_str(news_register,';');

  if (   ((hasrc=(int)(newsrc = fopen(news_register,"r","mbc=40"))) != 0)
      && ((in_line = fgetl(newsrc)) != 0)
      && (*in_line == '~')
      && ((cp = strchr(in_line+1,'~')) != 0)) {
    char newsrcnode[132];

    if (nntp_sts < 0) {
      fclose(newsrc);
      newsrc = 0;
      strcpy(news_register,"SYS$LOGIN:NEWSRC");
      if (   ((newsrc = fopen(news_register,"r","mbc=40")) != 0)
	  && ((in_line = fgetl(newsrc)) != 0)
	  && (*in_line == '~')) {
        fclose(newsrc);
        newsrc = 0;
	strcpy(news_register,"SYS$LOGIN:NEWSRC.LOCALDB");
	}
      }
    else {
      *cp-- = '\0';
      *(cp - 1) = '\0';
      strnncpy(newsrcnode,sizeof(newsrcnode), in_line+1,-1, 0);
      lower_case(newsrcnode);
      if (!explicit_server || nntp_sts == 2 || nntp_sts == 4) {
        if (!explicit_server) {
          strnncpy(nntp_node,nntp_node_m, newsrcnode,-1, 0);
          nntp_sts = 2;
          if (explicit_proto) nntp_sts = 4;
          }
        else if (strcmp(newsrcnode,nntp_node)) {
	  fclose(newsrc);
          newsrc = 0;
	  strcpy(news_register,"SYS$LOGIN:NEWSRC#");
          strnncat(news_register,news_register_m,-1, nntp_node,-1, 0);
	  while ((cp = strchr(news_register,'.')) != 0) *cp = '-';
	  if ((cp = strchr(news_register,'#')) != 0) *cp = '.';
	  if (   ((newsrc = fopen(news_register,"r","mbc=40")) != 0)
	      && ((in_line = fgetl(newsrc)) != 0)
	      && (*in_line == '~')
	      && ((cp = strchr(in_line+1,'~')) != 0)) {
            *cp-- = '\0';
            *(cp - 1) = '\0';
            }
          else cp = 0;
          }
	}
      else {
        strnncpy(nntp_node,nntp_node_m, newsrcnode,-1, 0);
        if (nntp_sts < 2) nntp_sts = 2;
        else nntp_sts = 4;
        }

      if (cp && !explicit_proto) {
        nntp_proto = atoi(cp);
        nntp_sts = 4;
	}
      }
    }
  else if (newsrc) {
    fclose(newsrc);
    newsrc = 0;
    if (nntp_sts == 2 || nntp_sts == 4) {
      strcpy(news_register,"SYS$LOGIN:NEWSRC#");
      strnncat(news_register,news_register_m,-1, nntp_node,-1, 0);
      while ((cp = strchr(news_register,'.')) != 0) *cp = '-';
      if ((cp = strchr(news_register,'#')) != 0) *cp = '.';
      if (   ((nntp_sts == 2) || (nntp_sts == 4))
	  && ((newsrc = fopen(news_register,"r","mbc=40")) != 0)
	  && ((in_line = fgetl(newsrc)) != 0)
	  && (*in_line == '~')
	  && ((cp = strchr(in_line+1,'~')) != 0)) {
        *cp-- = '\0';
        *(cp - 1) = '\0';
	if (!explicit_proto) {
          nntp_proto = atoi(cp);
          nntp_sts = 4;
          }
	}
      else if (newsrc && !in_line) {
        fclose(newsrc);
        newsrc = 0;
        }
      }
    }

  nntp_proto = available_proto(nntp_proto);

  if (call_fastscan) {
    init_scanning = 1;
    if (fastscan()) exit(1);
    }

  nntp_client = 0;
  if (site_get_env()) {
    if (nntp_sts < 0) {
      printf("NEWS Error - local logical name environment not defined - NEWS ABORT\n");
      exit(1);
      }
    nntp_client = 1;
    }
  else {
    if (nntp_sts > 0) nntp_client = 1;
    else nntp_client = 0;
    }

  if (nntp_client && !hasrc) {	/* default is to use unseen stack mode */
    profile_flags |= PROFILE_UNSEENSTACK;
    display_unseen_stack = 1;
    display_stk = 5;
    }

  create_keydefs();

  if (on_error_defaulted) {
    /* now after a call to create_keydefs() we know
       if the session is interactive or not */
    if (session_is_interactive)
      { on_error = ON_ERROR_UNWIND; try_to_quietly_handle_errors = 0; }
    else
      { on_error = ON_ERROR_CONTINUE; try_to_quietly_handle_errors = 1; }
    }

  openfiles(nntp_sts);
  fp_open = fpa_open = fpd_open = 0;

  if (call_fastscan) {
    init_scanning = 1;
    check_groups(0,1);
    exit(1);
    }

  if (temp_len) {

    cli$dcl_parse(c$dsc(mcommand),CLICMDTBL,0,0,0);

    if (cli$get_value(c$dsc("CLASS"),&usr_inp_dsc,&usr_inp_l) & 1) {
      usr_inp[usr_inp_l] = '\0';
      lower_case(usr_inp);
      set_start_classname(usr_inp);
      }
    if (cli$present(c$dsc("ALLSCAN")) & 1) {
      init_scanning = 1;
      check_groups(1,1);
      exit(1);
      }
    else if (cli$present(c$dsc("UNSEEN")) & 1) {
      if (!check_groups(0,0)) {
	printf("\tNEWS - No unseen items in registered newsgroups\n");
	exit(1);
	}
      }
    if (cli$present(c$dsc("SCREEN")) & 1) create_pb();
    if (cli$get_value(c$dsc("COMMAND"),&cmd_dsc,&cmd_len) & 1) {
      one_pass = 1;

#if NEWS_INIT
      cmd[cmd_len] = '\0';
      strnncpy(mcommand,sizeof(mcommand), cmd,cmd_len, 0);
#endif

      }
    }
  else create_pb();
  page_size();
  if (pid_created) init_screen();
  reg_context();
  do_start_version();

#if NEWS_INIT
  if (!(fpc = fopen("NEWS_INIT","r")))
     fpc = fopen("SYS$LOGIN:NEWS.INIT","r");
#endif

#if MENU_SUPPORT
   initialise_menus();
#endif

  /* main loop */
  for (;;) {
    cmd_status = setjmp(env);
    parse_level = OUTER_LOOP;

    if (
#if NEWS_INIT
	!fpc &&
#endif
		one_pass && one_pass++ > 1)

#if STARTLINE
      one_pass	= 0;
#else
      break;
#endif

    c$free_tmp();
    if (fp_open) {
      fclose(fp);
   /* if (*fp_open > 1) delete_file_versions(fp_open); */
      fp_open = 0;
      }
    if (fpd_open) {
      fclose(fpd);
   /* if (*fpd_open > 1) delete_file_versions(fpd_open); */
      fpd_open = 0;
      }
    if (fpa_open) {
      fclose(fpa);
      fpa_open = 0;
      }
    itmptr.str_searching = 0;
    textptr.str_searching = 0;
    if (smg_active) {
      smg$erase_display(&trailer_vd,c$ac(1),c$ac(6),c$ac(2),c$ac(devcol));
      brdcst_col = 7;
      display_brdcst(2);
      brdcst_line = 2;
      }

#if NEWS_INIT
    if (!cmd_status && fpc) {
      cmd_status = 2;
      if (fgets(fpcl,sizeof(fpcl),fpc))
        { int ll; strnncpy(cmd,cmd_m, fpcl,-1, &ll); cmd_len = ll; }
      else {
	fclose(fpc);
	fpc = 0;
	if (one_pass)
          { int ll; strnncpy(cmd,cmd_m, mcommand,-1, &ll); cmd_len = ll; }
	else { cmd_status = 0; cmd_len = 0; }
	}
      }
#endif

    if (news_lock_alarm) {
      printf("NEWS - Manager has requested shutdown\n");
      break;
      }
    if (!cmd_status && !one_pass) {
      if (smg_active) {
	if ((news_context == 1) && (cur_dir_type == DIR_NEW)) dirnew_check();
	}
#if MENU_SUPPORT
      for (;;) {
        status = get_input_general(&cmd_dsc,c$dsc("NEWS> "),&cmd_len,
                                   0,0,1,line_editing);
        if (! (status&1) ) break;
	if ((cmd_len >= 4) && (toupper(cmd[0]) == 'M' ) && (toupper(cmd[1]) == 'E') && (toupper(cmd[2]) == 'N' ) &&(toupper(cmd[3]) == 'U') ) {
          int ll;
	  strnncpy(cmd,cmd_m, get_menu_input(),-1, &ll); cmd_len = ll;
	  }
	if (strcmp(cmd,menu_escape_pressed) != 0) break;
	}
#else
      status = get_input_general(&cmd_dsc,c$dsc("NEWS> "),&cmd_len,
                                 0,0,1,line_editing);
#endif
      if (((status == SS$_ABORT) || (status == SS$_CANCEL)) && news_lock_alarm) {
        closefiles();
        exit(1);
        }
      if ((status == SMG$_EOF) || (status == RMS$_EOF)) break;
      if (status == 0) break;  /* break the main loop in case of UNWIND
                                  from within get_input_general()
                                  ( condition handler returns 0 in %r0 ) */
      }

    brdcst_line = 0;
    cmd[cmd_len] = '\0';
    if ((cmd_len > 2) && (toupper(*cmd) == 'R') &&
	(toupper(*(cmd + 1)) == 'E') && (toupper(*(cmd + 2)) == 'F'))
      do_refresh();
    else {
      old_context = news_context;
      if (news_context == 3) set_level(2);
      if (textptr.text_displayed) {
	smg$unpaste_virtual_display(&(textptr.sdid),&pid);
	smg$unpaste_virtual_display(&(textptr.shdid),&pid);
	textptr.text_displayed = 0;
	if (!cmd_len && (cmd_status < 3)) continue;
	}
      clear_err_line();
      if (cmd_status < 3) {
	if (do_parse(cmd)) break;
	}
      else {
	f = (int (*)())cmd_status;
	if ((*f)()) break;
	}
      }
    }
  closefiles();
  return SS$_NORMAL;
}
