/*
 * Copyright (c) 1991 by the University of Washington
 *
 * For copying and distribution information, please see the file
 * <copyright.h>.
 */

/*
 * Archie client using the Prospero protocol.
 *
 * Suggestions and improvements to Brendan Kehoe (brendan@cygnus.com).
 */

#include <stdio.h>
#include <getopt.h>

#if defined(OS2)
# include <pctcp.h>
#endif

#ifdef MSDOS
# include <string.h>
# include <stdlib.h>
# ifdef CUTCP
#  include <msdos/cutcp.h>
#  include <msdos/hostform.h>
/* The default stack size for a BC program is 4k; jack it up to 16 and add the
   Check for Stack Overflow option to the compiler.  */
extern unsigned _stklen = 16 * 1024;
# endif
#endif

#include <pfs.h>
#include <rdgram.h>
#include <archie.h>
#include <pmachine.h>

/* Whether we should produce single-line listings suitable for frobbing by
   other programs, or produce nice clean human output (default).  */
int listflag = 0;

/* How to sort the data; 1 means by date, 0 is by inverse hostname.  */
int sortflag = 0;

/* Used by CUTCP to see if they specified the host with `-h' or if
   the config.tel file should be consulted.  */ 
int hostset = 0;

/* When doing searches, should we make some comments to pacify the user?  */
int verbose = 0;

/* Maximum number of hits for this query; pushing this high is very
   anti-social.  */
int max_hits = MAX_HITS;

/* The offset for the Prospero query.  */
int offset = 0;

/* Display the Alex filename?  */
int alex = 0;

/* The default host to query for searches.  */ 
char *host = ARCHIE_HOST;

FILE *archie_out;

/* The name this program was run with.  */
char *program_name;

extern int pfs_debug;
extern int rdgram_priority;

void usage ();
extern char *getenv ();

void
main (argc, argv)
     int argc;
     char **argv;
{
  Query query = EXACT;
  int optc, tmp;
  /* If true, display the release.  */
  int exitflag = 0;
  /* The file to print the results to.  Defaults to stdout.  */
  char *outfile = (char *)NULL;
  char *p;
  static char *archies[] = { ARCHIES };

  program_name = argv[0];

  /* Default debugging level.  */
  pfs_debug = 0;

#ifdef	CUTCP
  if (getenv ("CONFIGTEL"))
    if (Shostfile (getenv ("CONFIGTEL")) < 0)
      {
	fprintf (stderr, "Error, couldn't open configtel file %s\n",
		 getenv ("CONFIGTEL"));
	exit (1);
      }
#endif

  if ((p = getenv ("ARCHIE_HOST")) != (char *) NULL)
    host = p;

#ifdef CUTCP
  while ((optc = getopt (argc, argv, "D:LHN::O:ceh:alm:o:rstvV")) != EOF)
#else
  while ((optc = getopt (argc, argv, "D:LN::O:ceh:alm:o:rstvV")) != EOF)
#endif
    {
      switch (optc)
	{
	case 'D':
	  pfs_debug = atoi (optarg);
	  break;

	case 'L':
	  printf ("Known archie servers:\n");
	  for (tmp = 0; tmp < NARCHIES; tmp++)
	    printf ("\t%s\n", archies[tmp]);
	  printf (" * %s is the default Archie server.\n", ARCHIE_HOST);
	  printf (" * For the most up-to-date list, write to an Archie server and give it\n   the command `servers'.\n");
	  exitflag = 1;
	  break;

#ifdef CUTCP
	case 'H':
	  if (Shostfile (optarg) < 0)
	    {
	      fprintf (stderr,
		       "%s: couldn't open configtel file %s\n",
		       program_name, optarg);
	      exit (1);
	    }
	  break;
#endif

	case 'N':
	  if (optarg)
	    {
	      rdgram_priority = atoi (optarg);
	      if (rdgram_priority > RDGRAM_MAX_SPRI)
		rdgram_priority = RDGRAM_MAX_PRI;
	      else if (rdgram_priority < RDGRAM_MIN_PRI)
		rdgram_priority = RDGRAM_MIN_PRI;
	    }
	  else
	    rdgram_priority = RDGRAM_MAX_PRI;
	  break;

	case 'c': /* Substring (case-sensitive).  */
	  query = SUBSTRING_CASE;
	  break;

	case 'e': /* Exact match.  */
	  query = EXACT;
	  break;

	case 'h': /* Archie host.  */
	  host = optarg;
#ifdef CUTCP
	  hostset = 1;
#endif
	  break;

	case 'a': /* List matches as Alex filenames.  */
	  alex = 1;
	  break;

	case 'l': /* List one match per line.  */
	  listflag = 1;
	  break;

	case 'm': /* Maximum number of hits for the query.  */
	  max_hits = atoi (optarg);
	  if (max_hits < 1)
	    {
	      fprintf (stderr,
		       "%s: option `-m' requires a max hits value >= 1\n",
		       program_name);
	      exit (ERROR_EXIT);
	    }
	  break;

	case 'o': /* output file */
	  if (outfile)
	    {
	      fprintf (stderr, "%s: multiple output files specified\n",
		       program_name);
	      exit (ERROR_EXIT);
	    }
	  outfile = optarg;
	  break;

	case 'O': /* Specify the offset.  */
	  offset = atoi (optarg);
	  break;

	case 'r': /* Regexp search.  */
	  query = REGEXP;
	  break;

	case 's': /* Substring (case insensitive).  */
	  query = SUBSTRING;
	  break;

	case 't': /* Sort inverted by date.  */
	  sortflag = 1;
	  break;

	case 'v': /* Display version.  */
	  fprintf (stderr,
		   "Client version %s based upon Prospero version %s%s\n",
		   CLIENT_VERSION,
#ifdef DEBUG
		   PFS_RELEASE, " with debugging.");
#else
		   PFS_RELEASE, ".");
#endif
	  exitflag = 1;
	  break;

	case 'V': /* Verbose when search is happening.  */
	  verbose = 1;
	  break;

	default:
	  usage ();
	}
    }

  if (exitflag)
    exit (0);
  else if (optind == argc)
    usage ();
  else if (alex && listflag)
    {
      fprintf (stderr, "%s: only one of `-a' or `-l' may be used\n",
	       program_name);
      exit (ERROR_EXIT);
    }

  if (outfile)
    {
      archie_out = fopen (outfile, "w+");
      if (archie_out == (FILE *) NULL)
	{
	  fprintf (stderr, "%s: cannot open %s\n", program_name, outfile);
	  exit (ERROR_EXIT);
	}
    }
  else
    archie_out = stdout;

#ifdef	CUTCP
  if (tmp = Snetinit ())
    {
      fprintf (stderr, " %d from SNetinit (bad or missing config.tel ?)\n",
	       tmp);

      /* If there was a rarp lookup failure, shut the network card down.  */
      if (tmp == -2)
	netshut ();
      exit (ERROR_EXIT);
    }

  if (!hostset)
    {
      /* Look in config.tel if they didn't give us a host with `-h'.  The
         entries appear as "name=archie".  */
      struct machinfo *mp = Shostlook ("archie");

      if (mp)
	host = mp->hname ? mp->hname : mp->sname;
    }
#endif

  for (; optind < argc; ++optind)
    procquery (host, argv[optind], max_hits, offset, query);

#ifdef CUTCP
  netshut ();
#endif

  if (outfile)
    fclose (archie_out);

  exit (0);
}

#ifdef CUTCP
# define HFLAG	"] [H config.tel]"
#else
# define HFLAG	"]"
#endif

void
usage ()
{
  fprintf (stderr, "\
Usage: %s [-acelorstvLV] [-m hits%s [-N level] string\n", program_name, HFLAG);
  fprintf (stderr, "          -a : list matches as Alex filenames\n");
  fprintf (stderr, "          -c : case sensitive substring search\n");
  fprintf (stderr, "          -e : exact string match (default)\n");
  fprintf (stderr, "          -r : regular expression search\n");
  fprintf (stderr, "          -s : case insensitive substring search\n");
  fprintf (stderr, "          -l : list one match per line\n");
  fprintf (stderr, "          -t : sort inverted by date\n");
  fprintf (stderr, "     -m hits : specifies maximum number of hits to return (default %d)\n", max_hits);
  fprintf (stderr, " -o filename : specifies file to store results in\n");
  fprintf (stderr, "     -h host : specifies server host\n");
  fprintf (stderr, "          -L : list known servers and current default\n");
  fprintf (stderr, "    -N level : specifies query niceness level (0-35765)\n");
#ifdef CUTCP
  fprintf (stderr, "-H config.tel: specify location of config.tel file\n");
#endif

  exit (ERROR_EXIT);
}

