/*
 *	Network Queueing System (NQS)
 *  This version of NQS is Copyright (C) 1992  John Roman
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 1, or (at your option)
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
/*
*  PROJECT:     Network Queueing System
*  AUTHOR:      John Roman
*
*  Modification history:
*
*       Version Who     When            Description
*       -------+-------+---------------+-------------------------
*       V01.10  JRR     22-Jun-1992     Initial version.
*	V01.20	JRR	26-Feb-1993	Tiny fix for Mid.
*			08-Mar-1993	Added Boeing enhancement for files.
*	V01.3	JRR	05-Aug-1993	Added -u switch.
*	V01.4	JRR	08-Mar-1994	Force show_* to 0.
*/
/*++ qcat.c - Network Deviceing System
 *
 * $Source: /usr2/jrroma/nqs/nqs-3.35.6/src/RCS/qcat.c,v $
 *
 * DESCRIPTION:
 *
 * RETURNS:
 *
 *      0       -  if output produced
 *      1       -  if an error occurred. A message is sent to the standard
 *                      output file for every error.
 *
 *
 *	Author:
 *	-------
 *	John Roman,  Monsanto Company
 *	June 22,  1992
 *
 *
 * STANDARDS VIOLATIONS:
 *   None.
 *
 * REVISION HISTORY: ($Revision: 1.4 $ $Date: 1994/03/30 20:37:04 $ $State: Exp $)
 * 
 *
 */

#include "nqs.h"
#include <errno.h>
#include <string.h>
#include "nqsdirs.h"			/* NQS files and directories */

#ifndef __CEXTRACT__
#if __STDC__

static char *qcat_naminput ( long orig_seqno, Mid_t orig_mid );
static void qcat_showhow ( void );
static int show_version ( void );

#else /* __STDC__ */

static char *qcat_naminput (/* long orig_seqno, Mid_t orig_mid */);
static void qcat_showhow (/* void */);
static int show_version (/* void */);

#endif /* __STDC__ */
#endif /* __CEXTRACT__ */

char *Qcat_prefix = "Qcat";

/*** main
 *
 * Copy a request's spooled input file, stdout, or stderr to stdout.
 * Format:
 *
 *	qcat [-e] [-i] [-o] [-u username] [-v] seqno
 */
main (argc, argv)
int argc;
char *argv[];				/* [switch] & sequence number */
{
	struct {
		long orig_seqno;	/* Sequence# for req */
		Mid_t machine_id;	/* Machine-id of originating machine */
		Mid_t target_mid;       /* target mid */
	} req;				/* Request to do */
	char **scan_reqs;		/* Scan reqs */
	char *argument;			/* Ptr to cmd line arg text */
	Mid_t local_mid;		/* local machine-id */
	int show_stdout;		/* Flag to show stdout  */
	int show_stderr;		/* Flag to show stderr */
	int show_stdin;			/* Flag to show input file */
	struct rawreq rawreq;		/* Area to hold raw request structure */
	int c;				/* Character passing through */
	int rawreqfd;			/* Raw request file descriptor */
	char *path;			/* Relative path to the file of interest */
	FILE *fp;			/* File pointer to std[err,out] */
        int exitcode = 0;               /* Function exit code */
	char *root_dir;                 /* Fully qualified file name */
	struct passwd *whompw;		/* Password entry of whom we are interested in */

	if ( ! buildenv()) {
	    fprintf (stderr, "%s(FATAL): Unable to ", Qcat_prefix);
	    fprintf (stderr, "establish directory independent ");
	    fprintf (stderr, "environment.\n");
	    exit (1);
	}
	root_dir = getfilnam (Nqs_root, SPOOLDIR);
	if (root_dir == (char *)NULL) {
	    fprintf (stderr, "%s(FATAL): Unable to ", Qcat_prefix);
	    fprintf (stderr, "determine root directory name.\n");
	    exit (1);
	}
	if (chdir (root_dir) == -1) {
	    fprintf (stderr, "%s(FATAL): Unable to chdir() to the NQS ",
                 Qcat_prefix);
	    fprintf (stderr, "root directory [%s].\n", root_dir);
	    relfilnam (root_dir);
	    exit (1);
	}
	relfilnam (root_dir);
	
        nmap_get_mid((struct hostent * ) 0, &local_mid);

	show_stdout = show_stderr = show_stdin = 0;
        while (*++argv != NULL && **argv == '-') {
            argument = *argv;
            switch (*++argument) {
		case 'e':
		    if (show_stdout || show_stdin) {
			fprintf (stderr, "Qcat can print only one file at a time.\n");
			exit(1);
		    }
		    show_stderr = 1;
		    break;
		case 'i':
		    if (show_stdout || show_stderr) {
			fprintf (stderr, "Qcat can print only one file at a time.\n");
			exit(1);
		    }
		    show_stdin = 1;
		    break;
		case 'o':
		    if (show_stderr || show_stdin) {
			fprintf (stderr, "Qcat can print only one file at a time.\n");
			exit(1);
		    }
		    show_stdout = 1;
		    break;
                case 'u':               /* User-name specification */
                    if (*++argv == NULL) {
                        fprintf (stderr, "Missing username.\n");
                        exit (-1);
                    }
                    if (whompw != NULL) {
                        fprintf (stderr, "Multiple -u specifications.\n");
                        exit (-1);
                    }
                    if ((whompw = fetchpwnam (*argv)) == NULL) {
                        fprintf (stderr, "No such user %s on this machine.n", *argv);
                        exit (-1);
                    }
                    if ((nqspriv (getuid(), local_mid, local_mid)  & QMGR_OPER_PRIV) ||
                            whompw->pw_uid == getuid()) {
                        /*
                         *  We have NQS operator privileges, or we
                         *  are just going after our own requests.
                         */
                    }
                    else {
                        fprintf (stderr, "Insufficient privilege for -u specification.\n");
                        exit (-1);
                    }
                    break;
                case 'v':
                    show_version();
                    exit(0);
                default:
                    fprintf (stderr, "Invalid option flag specified.\n");
                    qcat_showhow();
                    exit(0);
            }
        }
	if (!show_stderr && !show_stdin && !show_stdout) show_stdout++;
	if (*argv == NULL) {
	    /*
	     *  No request-ids were specified.
	     */
	    fprintf (stderr, "No request-id(s) specified.\n");
	    qcat_showhow();
	}
        scan_reqs = argv;		/* Set req scan pointer */
	switch (reqspec (*scan_reqs, &req.orig_seqno,
					 &req.machine_id,
					 &req.target_mid)) {
	    case -1:
		fprintf (stderr, "Invalid request-id syntax ");
	        fprintf (stderr, "for request-id: %s.\n",*scan_reqs);
	        exit (1);
	    case -2:
		fprintf (stderr, "Unknown machine for ");
		fprintf (stderr, "request-id: %s.\n",*scan_reqs);
	        exit (1);
	    case -3:
		fprintf (stderr, "Network mapping database ");
	        fprintf (stderr, "inaccessible.  Seek staff ");
	        fprintf (stderr, "support.\n");
	        exit (1);
	    case -4:
		fprintf (stderr, "Network mapping database ");
	        fprintf (stderr, "error when parsing ");
	        fprintf (stderr, "request-id: %s.\n",*scan_reqs);
	        fprintf (stderr, "Seek staff support.\n");
	        exit (1);
	}
        /* If reqspec returns null in machine id, force to
	 * local machine id.
	 */
	if (req.machine_id == 0) localmid(&req.machine_id);
	rawreqfd = gethdr(req.orig_seqno,  req.machine_id,  &rawreq);
	if (rawreqfd == -1) {
	    if (errno == ENOENT) {
		fprintf(stderr, "Request %s does not exist.\n",  *argv);
	    } else if (errno == EACCES) {
		fprintf(stderr,  "No access to request %s.\n",  *argv);
	    } else {
		fprintf(stderr, "Error reading header\n");
	        perror(" ");
	    }
	    fflush(stdout);
	    exit(1);
	}
	if (whompw == NULL) whompw = fetchpwuid (getuid () );
	if (rawreq.orig_uid != whompw->pw_uid ) {
	    fprintf( stderr,  "%s is not owner of request %s\n", whompw->pw_name, 
			*argv);
	    exit (1);
	}
        /*
         *  Generate name of temporary spooled output file.
         */
	if (show_stdout)
	        path = namstdout (rawreq.orig_seqno, rawreq.orig_mid);
	else if (show_stderr)
	        path = namstderr (rawreq.orig_seqno, rawreq.orig_mid);
	else if (show_stdin)
		path = qcat_naminput (rawreq.orig_seqno,  rawreq.orig_mid);
	if ( (fp = fopen (path, "r")) == NULL) {
	    if (errno == ENOENT) {
		if (show_stdout) fprintf(stderr,  "Output file does not exist.\n");
		else if (show_stderr) fprintf(stderr, "Error file does not exist.\n");
		else fprintf(stderr,  "Input file does not exist.\n");
		exit(1);
	    }
	    fprintf(stderr,  "Error opening %s\n",  path);
	    perror(" ");
	    exit(1);
	}
	
	while (1) {
	    c = getc(fp);
	    if (c == EOF) break;
	    putc(c,  stdout);	    
	}
	/*
	 *  Flush output buffers and exit.
	 */
	fflush (stdout);
	fflush (stderr);
	exit (exitcode);
}
/*** qcat_naminput
 *
 *
 *      char *qcat_naminput():
 *
 *      Return pointer to name of spooled stdout output file for
 *      a batch request.
 *
 *      NOTE:   The name is computed relative to the NQS root directory.
 */
static char *qcat_naminput (orig_seqno, orig_mid)
long orig_seqno;                        /* Req sequence number */
Mid_t orig_mid;                         /* Req machine-id */
{
        static char path [48];          /* Pathname for file.  This size */
                                        /* may need to be increased.... */

        pack6name (path, Nqs_data, (int) (orig_seqno % MAX_DATASUBDIRS),
                  (char *) 0, (long) orig_seqno, 5,  orig_mid, 6, 0, 3);
        return (path);
}

/*** qcat_showhow
 *
 *
 *	qcat_showhow():
 *	Show how to use this command.
 */
static void qcat_showhow()
{
    fprintf (stderr, "qcat -- print NQS spooled input, output, or error files.\n");
    fprintf (stderr, "usage:    qcat  [-e] [-i] [-o] [-u username] [-v] <request-id>\n");
    fprintf (stderr, " -e            print error file\n");
    fprintf (stderr, " -i            print input file\n");
    fprintf (stderr, " -o            print output file (the default)\n");
    fprintf (stderr, " -u username   username of request owner (if not yourself)\n");
    fprintf (stderr, " -v            print version information\n");
    fprintf (stderr, " <request-id>  NQS request identifier\n");
	exit (0);
}
static show_version()
{
	fprintf (stderr, "NQS version is %s.\n", NQS_VERSION);
}
