/*
 *	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                     Initial version.
*       V01.20  JRR     10-Mar-1992	Fixing up problems.
*	V01.3   JRR     26-May-1992     Added RS6000 conditionals.
*					Changed VERSION -> NQS_VERSION
*	V01.4	JRR	17-Jun-1992	Added header.
*	V01.5	JRR	05-Nov-1992	Changes for C prototypes.
*	V01.6	JRR			Placeholder
*	V01.7	JRR	28-Feb-1994	Added support for SOLARIS.
*/
#include "nqs.h"		/* NQS definitions */
#include <ctype.h>
#include <string.h>
/* #include "netpacket.h"			NQS networking */
#include <pwd.h>			/* Password stuff */

#include "nqsxdirs.h"		/*  NQS directories */
#include "nqsxvars.h"		/* NQS directories */

#ifndef __CEXTRACT__
#if __STDC__

static dsp_req ( struct gendescr *queue, long flags, long state, struct rawreq *req, char * selector, char * def_req );
static full_listr ( struct rawreq *req, struct gendescr *queue, long state, long flags, char * selector, char * def_req );
static char *get_rstate ( short type, long state );
static char *gunits ( short units );
static p_req_hdr ( long flags );
static search_cmplx ( struct confd *file, struct confd *qcomplexfile, char * name, long flags, char * selector, short daepresent, struct confd *qmapfile, struct confd *pipeqfile );
static search_q ( struct confd *file, char * name, char * req, long flags, char * selector, short daepresent, struct confd *qmapfile, struct confd *pipeqfile, struct confd *qcomplexfile );
static search_req ( struct confd *file, char * name, long flags, char * selector, short daepresent, struct confd *qmapfile, struct confd *pipeqfile, struct confd *qcomplexfile );
static void shocpul ( struct cpulimit *cpu, long explicit, long infinite, struct gendescr *que_descr );
static void shomd ( char mode );
static void shoquetime ( struct gendescr *que_descr );
static void shoquol ( struct quotalimit *quota, long explicit, long infinite, struct gendescr *que_descr );
static void shoreql ( struct gendescr *que_descr, struct rawreq *rawreqp );
static val_user ( char * selector, char * name );

#else /* __STDC__ */

static dsp_req (/* struct gendescr *queue, long flags, long state, struct rawreq *req, char * selector, char * def_req */);
static full_listr (/* struct rawreq *req, struct gendescr *queue, long state, long flags, char * selector, char * def_req */);
static char *get_rstate (/* short type, long state */);
static char *gunits (/* short units */);
static p_req_hdr (/* long flags */);
static search_cmplx (/* struct confd *file, struct confd *qcomplexfile, char * name, long flags, char * selector, short daepresent, struct confd *qmapfile, struct confd *pipeqfile */);
static search_q (/* struct confd *file, char * name, char * req, long flags, char * selector, short daepresent, struct confd *qmapfile, struct confd *pipeqfile, struct confd *qcomplexfile */);
static search_req (/* struct confd *file, char * name, long flags, char * selector, short daepresent, struct confd *qmapfile, struct confd *pipeqfile, struct confd *qcomplexfile */);
static void shocpul (/* struct cpulimit *cpu, long explicit, long infinite, struct gendescr *que_descr */);
static void shomd (/* char mode */);
static void shoquetime (/* struct gendescr *que_descr */);
static void shoquol (/* struct quotalimit *quota, long explicit, long infinite, struct gendescr *que_descr */);
static void shoreql (/* struct gendescr *que_descr, struct rawreq *rawreqp */);
static val_user (/* char * selector, char * name */);

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

static int acccolumn = 0;	/* Used by shoqueacc(), shogrp(), shousr() */


/*** listr
 *
 * Read the requests and
 * send to correct display
 * (short or long format).
 */
int listr (file, que_descr, flags, selector,req,daemon)
register struct confd *file;			/* NQS queue file */
register struct gendescr *que_descr;		/* the queue descriptor */
register long flags;				/* Display flags */
register char * selector;
register char * req;
register short daemon;
{

	struct qentry cache [QOFILE_CACHESIZ];
	struct rawreq	request;
	int cacheindex = 0;		/* Current buffer cache index */
	int nth_request;		/* Rank of this request */
	int fd;				/* Queue ordering file descriptor */
	int i;				/* Loop var */
	int csize;
	int count;
	int cfd;
	short daepresent;
	short user =0;
	nth_request = 0;		/* No requests yet displayed */

 
	if (!daemon) {
		que_descr->v.que.queuedcount += 
			que_descr->v.que.runcount;
		que_descr->v.que.runcount = 0;
	}

	/* step 2. Open the request queue ordering file.  
	 *  fd >= 0 if the queue has requests, and we successfully
	 *	    opened the queue ordering file.
	 *  fd = -1 if the queue has no requests.
	 *  fd = -2 if the queue has requests, but an error prevented
	 *	    us from opening the queue ordering file for
	 *	    the queue.
	 *  fd = -3 if the queue was deleted.
	 */
	fd = openqord (file, que_descr);
	if (fd < -1) return (fd);	/* Error or queue was deleted */

	/* step 3. Departing Requests display, if all or in transit is requested*/
	if  (flags & SHO_RS_EXIT )
	  if ( (count = que_descr->v.que.departcount) != 0)
	   for(i=0; i<count; i++) {
                csize = read(fd,(char *) cache, sizeof (cache));
                csize /= sizeof(struct qentry);
                if ((cfd = getrreq((long)cache[cacheindex].orig_seqno, cache
                        [cacheindex].orig_mid, &request)) != -1) {
				if (flags & SHO_FULL){
					full_listr(&request,que_descr,SHO_RS_EXIT,flags,
						selector,req);
				}
				else {
	                                dsp_req(que_descr,flags, 
						SHO_RS_EXIT,&request, selector,req);
				}
		}
                cacheindex++;
        }

	/* step 4. Running Requests display, if all or running is requested*/
	if (flags & SHO_RS_RUN )	
	  if ( (count = que_descr->v.que.runcount) != 0)
	   for(i=0; i<count; i++) {
                csize = read(fd,(char *) cache, sizeof (cache));
                csize /= sizeof(struct qentry);
                if ((cfd = getrreq((long)cache[cacheindex].orig_seqno, cache
                        [cacheindex].orig_mid, &request)) != -1) {
				if (flags & SHO_FULL){
					full_listr(&request,que_descr,SHO_RS_RUN,flags,
						selector,req);
				}
				else {
	                                dsp_req(que_descr,flags, 
						SHO_RS_RUN,&request, selector,req);
				}
		}
                cacheindex++;
        }

	/* step 5. Staged Requests display, if all or in transit is requested*/

	if (flags & SHO_RS_EXIT )
	  if ( (count = que_descr->v.que.stagecount) != 0)
	   for(i=0; i<count; i++) {
                csize = read(fd,(char *) cache, sizeof (cache));
                csize /= sizeof(struct qentry);
                if ((cfd = getrreq((long)cache[cacheindex].orig_seqno, cache
                        [cacheindex].orig_mid, &request)) != -1) {
				if (flags & SHO_FULL){
					full_listr(&request,que_descr,SHO_RS_STAGE,flags,
						selector,req);
				}
				else {
	                                dsp_req(que_descr,flags, 
						SHO_RS_STAGE,&request, selector,req);
				}
		}
                cacheindex++;
        }

	/* step 6. Queued Requests display, if all or queued is requested*/

	if (flags & SHO_RS_QUEUED )
	  if ( (count = que_descr->v.que.queuedcount) != 0)
	   for(i=0; i<count; i++) {
                csize = read(fd,(char *) cache, sizeof (cache));
                csize /= sizeof(struct qentry);
                if ((cfd = getrreq((long)cache[cacheindex].orig_seqno, cache
                        [cacheindex].orig_mid, &request)) != -1) {
				if (flags & SHO_FULL){
					full_listr(&request,que_descr,SHO_RS_QUEUED,flags,
						selector,req);
				}
				else {
	                                dsp_req(que_descr,flags, 
						SHO_RS_QUEUED,&request, selector,req);
				}
		}
                cacheindex++;
        }

	/* step 7. Waiting Requests display, if all or held is requested*/

	if (flags & SHO_RS_HOLD )
	  if ( (count = que_descr->v.que.waitcount) != 0)
	   for(i=0; i<count; i++) {
                csize = read(fd,(char *) cache, sizeof (cache));
                csize /= sizeof(struct qentry);
                if ((cfd = getrreq((long)cache[cacheindex].orig_seqno, cache
                        [cacheindex].orig_mid, &request)) != -1) {
				if (flags & SHO_FULL){
					full_listr(&request,que_descr,SHO_RS_WAIT,flags,
						selector,req);
				}
				else {
	                                dsp_req(que_descr,flags, 
						SHO_RS_WAIT,&request, selector,req);
				}
		}
                cacheindex++;
        }
          
	/* step 8. Holding Requests display, if all or held is requested*/

	if (flags & SHO_RS_HOLD )
	  if ( (count = que_descr->v.que.holdcount) != 0)
	   for(i=0; i<count; i++) {
                csize = read(fd,(char *) cache, sizeof (cache));
                csize /= sizeof(struct qentry);
                if ((cfd = getrreq((long)cache[cacheindex].orig_seqno, cache
                        [cacheindex].orig_mid, &request)) != -1) {
				if (flags & SHO_FULL){
					full_listr(&request,que_descr,SHO_RS_HOLD,flags,
						selector,req);
				}
				else {
	                                dsp_req(que_descr,flags, 
						SHO_RS_HOLD,&request, selector,req);
				}
		}
                cacheindex++;
        }
          
	/* step 9. Arriving Requests display, if all or in transit is requested*/

	if (flags & SHO_RS_EXIT )
	  if ( (count = que_descr->v.que.arrivecount) != 0)
	   for(i=0; i<count; i++) {
                csize = read(fd,(char *) cache, sizeof (cache));
                csize /= sizeof(struct qentry);
                if ((cfd = getrreq((long)cache[cacheindex].orig_seqno, cache
                        [cacheindex].orig_mid, &request)) != -1) {
				if (flags & SHO_FULL){
					full_listr(&request,que_descr,SHO_RS_ARRIVE,flags,
						selector,req);
				}
				else {
	                                dsp_req(que_descr,flags, 
						SHO_RS_ARRIVE,&request, selector,req);
				}
		}
                cacheindex++;
        }
          
	/* step 10. close queue ording file and return */
	close (fd);			
	return (0);			
}

/*** get_rstate
 *
 * get state of request by queue typed
 * and state
 */
static char *get_rstate(type, state)
short   type;
long    state;
{


 /* determine the state of the request 
  * according to queue type and request 
  */

 switch (state) {
         case SHO_RS_EXIT:
                if (type == QUE_BATCH) {
                        return(  "EXITING");
                }
                else if (type == QUE_PIPE) {
                        return("DEPARTING");
                }
                else return("UNKNOWN");
                break;
        case SHO_RS_RUN:
                if (type == QUE_PIPE)
                        return("ROUTING");
                else
                        return("RUNNING");
                break;
        case SHO_RS_STAGE:
                if (type == QUE_BATCH) {
                return("STAGING");
                }
                else return("UNKNOWN");
                break;
        case SHO_RS_QUEUED:
                return("QUEUED");
                break;
        case SHO_RS_WAIT:
                return("WAITING");
                break;
        case SHO_RS_HOLD:
                return("HOLDING");
                break;
        case SHO_RS_ARRIVE:
                return("ARRIVING");
                break;
        default:
                return("UNKNOWN");     /* We should never get here */
                break;
                }

}
 
/*** dsp_req
 *
 * display request, short form
 */
static dsp_req(queue,flags,state,req,selector,def_req)
	struct gendescr *queue;		/* the queue descriptor */
	long	flags;
        long    state;
        struct  rawreq  *req;
	char 	* selector;
	char 	* def_req;
{
	char 	mac[11];
        int     cnt;
        char    *mach;
        char    status[8];
	long	val;
	char 	*machinename;

	/* if not all validate whom to see */
	if (!(flags & SHO_R_ALLUID)) {
		if (def_req != NULL) {
			val=0;
			while (*def_req >= '0' && *def_req <='9'){
				val *=10;
				val += *def_req -'0';
				def_req++;
			}
			if (val !=req->orig_seqno) 
				return(0);
			
			if (val_user(selector,req->username)== -1)
			{
				printf("invalid administrator at host or did not use administrator option -U or -u\n");
				return(0);
			}
				/* if (adm) */
		}
		else {
			if (val_user(selector,req->username)== -1)
				return (0);
			}
	}


	/* get originating machine */
	machinename=getmacnam(req->orig_mid);
	strncpy(mac,machinename,8);
	mac[8]='\0';


        printf("%d@%-9s  %-6s  %-6s  %-6s  %3d   %3d", 
	req->orig_seqno,		/* print request id */
	mac,				/* print originating machine */
        req->reqname,			/* print request name */
        req->username,			/* print owner */
        req->quename,			/* print queue */
        queue->v.que.priority,		/* print priority */
        req->v.bat.ppnice +20);		/* print nice value */

	/* get cpu seconds */
	if ((req->v.bat.infinite & LIM_PPCPUT) == 0)
		printf("  %1lu",req->v.bat.ppcputime.max_seconds);
	else
	if ((req->v.bat.explicit & LIM_PPCPUT)
		|| (queue->v.que.type== QUE_BATCH)) 
		printf("  UNLIMITED");
	else
		printf("  UNSPECIFIED");

	/* get memory */
	if ((req->v.bat.infinite & LIM_PPMEM) == 0)
		printf("  %1lu",req->v.bat.ppmemsize.max_quota);
	else
	if ((req->v.bat.explicit & LIM_PPMEM)
		|| (queue->v.que.type== QUE_BATCH)) 
		printf("  UNLIMITED");
	else
		printf("  UNSPECIFIED");

	/* get state of request */
	printf("   %s\n",get_rstate(queue->v.que.type, state));

} /*  end of request */

 
qcmplx_hdr()
{
char hostname[256];

	gethostname(hostname,255);
	hostname[255] = '\0';

        printf("=========================================\n");
        printf(" COMPLEXES for %s\n",hostname);
        printf("=========================================\n");
}                                              



/*** p_req_hdr
 *
 * print header for request 
 */
static p_req_hdr(flags)
long flags;
{
char hostname[256];
	printf("===============================================================\n");
	printf("NQS Version: %s	",NQS_VERSION);

        if(flags &  SHO_BATCH)
                printf(" BATCH ");

        if(flags &  SHO_DEVICE)
                printf(" DEVICE ");

        if(flags &  SHO_PIPE)
                printf(" PIPE ");

        printf("REQUESTS on ");
	gethostname(hostname,255);
	hostname[255] = '\0';
	printf("%s \n",hostname);
	

	printf("===============================================================\n");
        printf("REQUEST      NAME   OWNER   QUEUE    PRI   NICE  CPU      MEM   STATE\n");
}




/*** val_user 
 * Determine if selector, the name we are looking for is
 * equal to the name we have 
 */
static val_user(selector,name)
char * selector; 
char * name;
{

	if (selector != NULL)	/* This is to allow networking of old NQS */
		if (strcmp(name,selector) == 0)
			return(0);
		else
			return(-1);
}


/*** list
 *
 *
 *	int list():
 *
 *	Print on stdout information about the named object.
 *	Use this to determine if the object is queue, complex, request
 *	or a mistake.
 *	Returns: 0 if output was produced.
 *		-1 if no output was produced.
 */
int list (file, qcomplexfile,name, flags, selector ,qmapfile,pipeqfile)
struct confd *file;			/* NQS queue file */
register struct confd *qcomplexfile;	/*NQS queue complex definition file */
char *name;				/* Name with possible '@' */
long flags;				/* SHO_??? */
char * selector;				/* Name with possible '@' */
register struct confd *qmapfile;	/*NQS qmap definition file */
register struct confd *pipeqfile;	/*NQS qmap definition file */
{

	int whomuid;
	int itsmid;
	short daepresent;
	char	*localname;

	/*   step 1. Override database if daemon not present.  */
#if 	BSD43 | ULTRIX | DECOSF
	daepresent = daepres(file);
#else
#if     HPUX | SGI | SOLARIS | SYS52 | IBMRS | LINUX
        daepresent = daepres();
#else    
BAD SYSTEM TYPE
#endif
#endif          

	/* case 1:
	 *	display all queues as no list 
	 *	was sent (name ) and then exit
	 */

	if ((name == NULL) && ! (flags & SHO_CMPLX)){
		if ((flags & SHO_QUE) && ! (flags & SHO_NOHDR) && ! (flags & SHO_FULL))
			qstat_hdr(flags);

		if ((flags & SHO_REQ) && ! (flags & SHO_NOHDR) && ! (flags & SHO_FULL))
			p_req_hdr(flags);
		
		if (search_q(file,name,NULL,flags,selector,daepresent,
				qmapfile,pipeqfile,qcomplexfile) == SUCCESS)
			return(0);
	}

	/* case 2: 
	 *	check to see if the queue is on a remote machine
	 *	if the queue is remote then send it on and return
	 */

	if ((name != NULL))
	  if (check_rmt(name, &itsmid) == SUCCESS) {
		localname = destqueue(name);
		whomuid = getuid();
		if (whomuid == 0)
			printf("Root is not allowed to access other nqs machines via the network for security.\n");
		if (flags & SHO_CMPLX) flags |= SHO_QUE;
		call_host(whomuid,flags,itsmid,localname);
		return(0);
	  }

	/* case 3:
	 *	check to see if name starts with a number
 	 *	if it does then this is a request, else check
	 *	queue
	 */
	if (flags & SHO_REQ ) {
		if ( ! (flags & SHO_NOHDR) && ! (flags & SHO_FULL))
			p_req_hdr(flags);

		if (search_req(file,name,flags,selector,daepresent,qmapfile,
				pipeqfile,qcomplexfile) == SUCCESS)
			return(0);
	}



	/* case 4:
	 *	the list was not remote or a complex, thus check
	 *	for a specific queue if so the queue will be 
	 *	displayed through search_q and then return
	 */

	if ((flags & SHO_QUE) && (name != NULL) && !(flags & SHO_CMPLX)) {
		if ( ! (flags & SHO_NOHDR) && ! (flags & SHO_FULL))
			qstat_hdr(flags);
	}

	if (! (flags & SHO_CMPLX))
	if (search_q(file,name,NULL,flags,selector,daepresent,
			qmapfile,pipeqfile,qcomplexfile) == SUCCESS)
		return(0);

	/* case 4:
	 *	the list was not for a remote machine, 
	 *	thus check to see if the list is a complex
	 *	if it is then the queues in the complex will
	 *	be displayed through search_cmplx() and then return
	 */
	if (search_cmplx(file,qcomplexfile,name,flags,selector,
				daepresent,qmapfile,pipeqfile) == SUCCESS)
		return(0);

	/* case 6:
	 *	was not request, remote, complex or queue
	 *	thus print error message and return
	 */

	printf("%s was not found in the complex or queue list\n");
	return (-1);
	
}

/*** search_cmplx
 * 
 * determine if the object is a complex
 * if it is call search q for each queue in the complex
 */
static search_cmplx(file,qcomplexfile,name,flags,selector,daepresent,qmapfile,pipeqfile)
register struct confd *file;            /* MUST be the NQS queue file */
register struct confd *qcomplexfile;	/*NQS queue complex definition file */
char * name;				/* search value  */
register long flags;                    /* Display flags */
register char * selector;               /* account, group, or user list */
register short daepresent;
register struct confd *qmapfile;	/*NQS qmap definition file */
register struct confd *pipeqfile;	/*NQS qmap definition file */
{

	register struct gendescr *descr;
	int i;

	/* display header if this is for show complexes */
	if (flags & SHO_CMPLX)
	 if (! (flags & SHO_NOHDR) )
                qcmplx_hdr();

	/* read first record */
	descr = nextdb(qcomplexfile);	
	if (descr == NULL)
		if ( ! (flags & SHO_QUE ) && ! (flags & SHO_REQ))
			printf("\t\t No complexes on host. \n");

	while (descr != NULL){
	    if (name != NULL)   {
		if (strcmp(descr->v.qcom.name,name)==0) {
		    if  (flags & SHO_CMPLX )  { 
		        printf("Complex run limit: %d\n", descr->v.qcom.runlimit);
			printf("QUEUES FOR COMPLEX: %s \n",descr->v.qcom.name);
 			printf("QUEUE NAME      STATUS   TOTAL   RUNNING  QUEUED   HELD TRANSISTION\n");
		    }

		    for(i=0; i< MAX_QSPERCOMPLX; i++) {
			search_q(file,descr->v.qcom.queues[i]
					,NULL,flags,selector,daepresent,
					qmapfile,pipeqfile,qcomplexfile);
		    }
		    return(0);
		}
	   } else { 
	 	/* name == NULL, object is not queue or request so print  */
		/*   complex name */
		if (flags & SHO_CMPLX) printf("\t %s \n",descr->v.qcom.name);
		printf("Complex run limit: %d\n", descr->v.qcom.runlimit);
		if (flags & SHO_QUE ) {
                    printf("QUEUES FOR COMPLEX: %s \n",descr->v.qcom.name);
                    printf("QUEUE NAME      STATUS   TOTAL   RUNNING  QUEUED   HELD TRANSISTION\n");
		    for(i=0; i< MAX_QSPERCOMPLX; i++) {
			search_q(file,descr->v.qcom.queues[i]
					,NULL,flags,selector,daepresent,
					qmapfile,pipeqfile,qcomplexfile);
		    }
		}
	   }
	   descr = nextdb(qcomplexfile);
	}
	if (flags & SHO_CMPLX)
		return (0);

	return(-1);

}	/* end of search_cmplx */



/*** get_cmplx
 * 
 * get complex match
 */
void get_cmplx(name,qcomplexfile)
char * name;
register struct confd *qcomplexfile;	/*NQS queue complex definition file */
{
	register struct gendescr *descr;
	int i;


	seekdbb(qcomplexfile,0L);
	printf("\t");
	/* read first record */
	descr = nextdb(qcomplexfile);	

	while (descr != NULL) {
		for(i=0; i< MAX_QSPERCOMPLX; i++) {
			if (descr->v.qcom.queues[i] != NULL)
				if (strcmp(descr->v.qcom.queues[i],name)==0) 
					printf("%s ", descr->v.qcom.name);
		}
	descr = nextdb(qcomplexfile);
	}
	printf("\n");
}


/*** search_q
 * 
 * determine if object is a queue
 * and act accordingly
 */
static search_q(file,name,req,flags,selector,daepresent,qmapfile,pipeqfile,qcomplexfile)
register struct confd *file;            /* the NQS queue file */
char * name;				/* search value  */
char * req;				/* request value  */
register long flags;                    /* Display flags */
register char * selector;               /* account, group, or user list */
register short daepresent;
register struct confd *qmapfile;            /* the NQS qmap file */
register struct confd *pipeqfile;            /* the NQS pipe file */
struct confd *qcomplexfile;	/*NQS queue complex definition file */
{

	register struct gendescr *descr;

	seekdbb(file,0L);
	descr = nextdb(file);

	while (descr != NULL) {
		if (name != NULL) {	/* print only specific queue */
			if (strcmp(descr->v.que.namev.name,name)==0) {
				if (flags & SHO_QUE) 
						dsp_q(file,descr,flags,
						daepresent,qmapfile,
						pipeqfile,qcomplexfile);
	
				else
					if (flags & SHO_REQ)
						listr(file, descr, flags, 
						    selector,NULL,daepresent);
				return(0);
			}
			descr = nextdb (file);
		}
		else {	/* going to print all queues */
			if (flags & SHO_QUE)  {
					dsp_q(file,descr,flags, daepresent,
						qmapfile,pipeqfile,qcomplexfile);
			}
			else{
				if (flags & SHO_REQ)
					listr(file, descr, flags, selector,
						req,daepresent);
			}
			descr = nextdb (file);
		}
	}
	return(0);
}	/* end of search_q */

/*** shomd
 *
 *
 *      void shomd():
 *      Display an output mode.
 */
static void shomd (mode)
char mode;
{
        if (mode & OMD_SPOOL) {
                printf ("SPOOL");
        }
        else if (mode & OMD_EO) {
                printf ("EO");
        }
        else printf ("NOSPOOL");
}


/*** gunits
 *
 *
 *      char *gunits():
 *      Get quota units.
 */  
static char *gunits (units)
register short units;
{
        switch (units) {
        case QLM_BYTES:
                return ("bytes");
        case QLM_WORDS:
                return ("words");
        case QLM_KBYTES:
                return ("kilobytes");
        case QLM_KWORDS:
                return ("kilowords");
        case QLM_MBYTES:
                return ("megabytes");
        case QLM_MWORDS:
                return ("megawords");
        case QLM_GBYTES:
                return ("gigabytes");
        case QLM_GWORDS:
                return ("gigawords");
        }
        return ("");            /* Unknown units! */
 
}     
 

/*** shoquol
 *
 *
 *      void shoquol():
 *      Display a quota limit.
 */
static void shoquol (quota, explicit, infinite, que_descr)
register struct quotalimit *quota;
long explicit;
long infinite;
struct gendescr *que_descr;
{
        if (infinite == 0) {
                printf ("= [%1lu %s, %1lu %s]", quota->max_quota,
                        gunits (quota->max_units), quota->warn_quota,
                        gunits (quota->warn_units));
                if (explicit == 0) printf ("\t<DEFAULT>");
        }
        else {
                /*
                 *  The limit is infinite, or is not specified.
                 */
                if (que_descr->v.que.type == QUE_BATCH || explicit) {
                        printf ("= UNLIMITED ");
                        if (explicit == 0) printf ("\t<DEFAULT>");
                }
                /* Infinite, default limits are meaningless in a pipe queue */
                else printf ("= UNSPECIFIED");
        }
        putchar ('\n');
}  
 
 
/*** shoquetime
 *
 *
 *      void shoquetime():
 *      Display the cumulative cpu time used by requests in a queue.
 */
static void shoquetime (que_descr)
struct gendescr *que_descr;
{
        printf ("  Cumulative system space time = ");
#if     HPUX | SGI | SOLARIS | SYS52 | IBMRS | LINUX
        printf ("%ld.%02d seconds\n", que_descr->v.que.ru_stime / CPU_MEAS_GRAN,                ((que_descr->v.que.ru_stime % CPU_MEAS_GRAN) * 100) /
                CPU_MEAS_GRAN);
#else
#if     BSD43 | ULTRIX | DECOSF
        printf ("%ld.%06ld seconds\n", que_descr->v.que.ru_stime,
                que_descr->v.que.ru_stime_usec);
#else
BSD SYSTEM TYPE
#endif
#endif
        printf ("  Cumulative user space time = ");
#if     HPUX | SGI | SOLARIS | SYS52 | IBMRS | LINUX
        printf ("%ld.%02d seconds\n", que_descr->v.que.ru_utime / CPU_MEAS_GRAN,                ((que_descr->v.que.ru_utime % CPU_MEAS_GRAN) * 100) /
                CPU_MEAS_GRAN);
#else
#if     BSD43 | ULTRIX | DECOSF
        printf ("%ld.%06ld seconds\n", que_descr->v.que.ru_utime,
                que_descr->v.que.ru_utime_usec);
#else
BSD SYSTEM TYPE
#endif
#endif
}
 
/*** shocpul
 *
 *
 *      void shocpul():
 *      Display a CPU time limit quota.
 */
static void shocpul (cpu, explicit, infinite, que_descr)
register struct cpulimit *cpu;
long explicit;
long infinite;
struct gendescr *que_descr;
{
        if (infinite == 0) {
                printf ("= [%1lu.%1d, %1lu.%1d]",
                         cpu->max_seconds, cpu->max_ms,
                         cpu->warn_seconds, cpu->warn_ms);
                if (explicit == 0) printf ("\t\t<DEFAULT>");
        }
        else {
                /*
                 *  The limit is infinite, or is not specified.
                 */
                if (que_descr->v.que.type == QUE_BATCH || explicit) {
                        printf ("= UNLIMITED ");
                        if (explicit == 0) printf ("\t\t<DEFAULT>");
                }
                else printf ("= UNSPECIFIED");
        }
        putchar ('\n');
}





/*** shoreql
 *
 *
 *      void shoreql():
 *      Display the limits associated with a request.
 */
static void shoreql (que_descr, rawreqp)
struct gendescr *que_descr;             /* Needed to detect pipe queues */
struct rawreq *rawreqp;                 /* The request as a rawreq */
{
        if (que_descr->v.que.type == QUE_PIPE ||
           (VALID_LIMITS & LIM_PPCPUT)) {
                printf ("  Per-proc. CPU time limit      ");
                shocpul (&rawreqp->v.bat.ppcputime,
                           rawreqp->v.bat.explicit & LIM_PPCPUT,
                           rawreqp->v.bat.infinite & LIM_PPCPUT,
                           que_descr);
        }
        if (que_descr->v.que.type == QUE_PIPE ||
           (VALID_LIMITS & LIM_PRCPUT)) {
                printf ("  Per-req. CPU time limit       ");

                shocpul (&rawreqp->v.bat.prcputime,
                           rawreqp->v.bat.explicit & LIM_PRCPUT,
                           rawreqp->v.bat.infinite & LIM_PRCPUT,
                           que_descr);
        }
        if (que_descr->v.que.type == QUE_PIPE ||
           (VALID_LIMITS & LIM_PRDRIVES)) {
                printf ("  Per-req. tape drives limit    ");
                if ((rawreqp->v.bat.infinite & LIM_PRDRIVES) == 0) {
                        printf (" = %1d", rawreqp->v.bat.prdrives);
                        if (!(rawreqp->v.bat.explicit & LIM_PRDRIVES)) {
                                printf (" \t<DEFAULT>");
                        }
                }
                else printf (" = UNSPECIFIED");
                putchar ('\n');
        }
        if (que_descr->v.que.type == QUE_PIPE ||
           (VALID_LIMITS & LIM_PPCORE)) {
                printf ("  Per-proc. core file size limit");
                shoquol (&rawreqp->v.bat.ppcoresize,
                           rawreqp->v.bat.explicit & LIM_PPCORE,
                           rawreqp->v.bat.infinite & LIM_PPCORE,
                           que_descr);
        }
        if (que_descr->v.que.type == QUE_PIPE ||
           (VALID_LIMITS & LIM_PPDATA)) {
                printf ("  Per-proc. data size limit     ");
                shoquol (&rawreqp->v.bat.ppdatasize,
                           rawreqp->v.bat.explicit & LIM_PPDATA,
                           rawreqp->v.bat.infinite & LIM_PPDATA,
                           que_descr);

        }
        if (que_descr->v.que.type == QUE_PIPE ||
           (VALID_LIMITS & LIM_PPPFILE)) {
                printf ("  Per-proc. perm file ");
                printf ("size limit");
                shoquol (&rawreqp->v.bat.pppfilesize,
                           rawreqp->v.bat.explicit & LIM_PPPFILE,
                           rawreqp->v.bat.infinite & LIM_PPPFILE,
                           que_descr);
        }
        if (que_descr->v.que.type == QUE_PIPE ||
           (VALID_LIMITS & LIM_PRPFILE)) {
                printf ("  Per-req. perm file ");
                printf ("space limit");
                shoquol (&rawreqp->v.bat.prpfilespace,
                           rawreqp->v.bat.explicit & LIM_PRPFILE,
                           rawreqp->v.bat.infinite & LIM_PRPFILE,
                           que_descr);
        }
        if (que_descr->v.que.type == QUE_PIPE ||
           (VALID_LIMITS & LIM_PPMEM)) {
                printf ("  Per-proc. memory size limit   ");
                shoquol (&rawreqp->v.bat.ppmemsize,
                           rawreqp->v.bat.explicit & LIM_PPMEM,
                           rawreqp->v.bat.infinite & LIM_PPMEM,
                           que_descr);
        }
        if (que_descr->v.que.type == QUE_PIPE ||
           (VALID_LIMITS & LIM_PRMEM)) {
                printf ("  Per-req. memory size limit   ");
                shoquol (&rawreqp->v.bat.prmemsize,
                           rawreqp->v.bat.explicit & LIM_PRMEM,
                           rawreqp->v.bat.infinite & LIM_PRMEM,
                           que_descr);
        }
        if (que_descr->v.que.type == QUE_PIPE ||
           (VALID_LIMITS & LIM_PRNCPUS)) {
                printf ("  Per-req. # of cpus limit");
                if ((rawreqp->v.bat.infinite & LIM_PRNCPUS) == 0) {
                        printf (" = %1d", rawreqp->v.bat.prncpus);
                        if (!(rawreqp->v.bat.explicit & LIM_PRNCPUS)) {
                                printf (" \t<DEFAULT>");
                        }
                }
                else printf (" = UNSPECIFIED");
                putchar ('\n');
        }
        if (que_descr->v.que.type == QUE_PIPE ||
           (VALID_LIMITS & LIM_PPQFILE)) {
                printf ("  Per-proc. quick file ");
                printf ("size limit");
                shoquol (&rawreqp->v.bat.ppqfilesize,
                           rawreqp->v.bat.explicit & LIM_PPQFILE,
                           rawreqp->v.bat.infinite & LIM_PPQFILE,
                           que_descr);
        }
        if (que_descr->v.que.type == QUE_PIPE ||
           (VALID_LIMITS & LIM_PRQFILE)) {
                printf ("  Per-req. quick file space limit");
                shoquol (&rawreqp->v.bat.prqfilespace,
                           rawreqp->v.bat.explicit & LIM_PRQFILE,
                           rawreqp->v.bat.infinite & LIM_PRQFILE,
                           que_descr);
        }
        if (que_descr->v.que.type == QUE_PIPE ||
           (VALID_LIMITS & LIM_PPSTACK)) {
                printf ("  Per-proc. stack size limit    ");
                shoquol (&rawreqp->v.bat.ppstacksize,
                           rawreqp->v.bat.explicit & LIM_PPSTACK,
                           rawreqp->v.bat.infinite      & LIM_PPSTACK,
                           que_descr);
        }
        if (que_descr->v.que.type == QUE_PIPE ||
           (VALID_LIMITS & LIM_PPTFILE)) {
                printf ("  Per-proc. temp file size limit");
                shoquol (&rawreqp->v.bat.pptfilesize,
                           rawreqp->v.bat.explicit & LIM_PPTFILE,
                           rawreqp->v.bat.infinite & LIM_PPTFILE,
                           que_descr);
        }
        if (que_descr->v.que.type == QUE_PIPE ||
           (VALID_LIMITS & LIM_PRTFILE)) {
                printf ("  Per-req. temp file space limit");
                shoquol (&rawreqp->v.bat.prtfilespace,
                           rawreqp->v.bat.explicit & LIM_PRTFILE,
                           rawreqp->v.bat.infinite & LIM_PRTFILE,
                           que_descr);
        }
        if (que_descr->v.que.type == QUE_PIPE ||
           (VALID_LIMITS & LIM_PPWORK)) {
                printf ("  Per-proc. working set limit   ");
                shoquol (&rawreqp->v.bat.ppworkset,
                           rawreqp->v.bat.explicit & LIM_PPWORK,
                           rawreqp->v.bat.infinite & LIM_PPWORK,
                           que_descr);
        }
        if (que_descr->v.que.type == QUE_PIPE ||
           (VALID_LIMITS & LIM_PPNICE)) {
                printf ("  Per-proc. execution nice pri.");
                if ((rawreqp->v.bat.infinite & LIM_PPNICE) == 0) {
                        printf (" = %1d", rawreqp->v.bat.ppnice +20);
                        if (!(rawreqp->v.bat.explicit & LIM_PPNICE)) {
                                printf (" \t\t\t\t<DEFAULT>");
                        }
                }
                else printf (" = UNSPECIFIED");

                putchar ('\n');
        }
}


/*** search_req
 * 
 * determine if the object is a request 
 */

static search_req(file,name,flags,selector,daepresent,qmapfile,pipeqfile,qcomplexfile) 
register struct confd *file;            /* the NQS queue file */
char * name;				/* search value  */
register long flags;                    /* Display flags */
register char * selector;               /* account, group, or user list */
register short daepresent;
register struct confd *qmapfile;            /* the NQS qmap file */
register struct confd *pipeqfile;            /* the NQS pipeto file */
struct confd *qcomplexfile;	/*NQS queue complex definition file */
{

	/* step 1. 
	 * 	see if name starts with a letter, if
	 *	so then assume it must be a queue 
	 */
	if (isdigit (*name)) { 
		search_q(file,NULL,name,flags,selector,daepresent,qmapfile,pipeqfile,qcomplexfile); 
	}
	else
		return(-1);
}


/*** full_listr
 *
 * list request in full format
 */
static full_listr(req,queue,state,flags,selector,def_req)
struct  rawreq  *req;
register struct gendescr *queue;		/* the queue descriptor */
long  state;
long  flags;
char * selector;
char * def_req;
{

char * machinename = NULL;
char hostname[256];
char type[8];
long val;

	/* if not all validate whom to see */
	if (!(flags & SHO_R_ALLUID)) {
		if (def_req != NULL) {
			val=0;
			while (*def_req >= '0' && *def_req <='9'){
				val *=10;
				val += *def_req -'0';
				def_req++;
			}
			if (val !=req->orig_seqno) 
				return(0);
			
			if (val_user(selector,req->username)== -1)
			{
				printf("invalid administrator at host or did not use administrator option -U or -u\n");
				return(0);
			}
				/* if (adm) */
		}
		else {
			if (val_user(selector,req->username)== -1)
				return (0);
			}
	}

	/* step 2. get host we are on */
	gethostname(hostname,255);
	hostname[255] = '\0';

	/* step 3. get originating host */
	machinename=getmacnam(req->orig_mid);

	/* step 4. determine type of queue */
	if (queue->v.que.type == QUE_BATCH)
		strcpy(type,"BATCH");
	if (queue->v.que.type == QUE_PIPE)
		strcpy(type,"PIPE");
	if (queue->v.que.type == QUE_DEVICE)
		strcpy(type,"DEVICE");

	/* step 5. print header information */
	printf("=====================================================\n");
	printf("NQS version:%s	%s	REQUEST:	%d.%s\n",NQS_VERSION,type,
		req->orig_seqno,machinename);
	printf("=====================================================\n");

	/* step 6. print name ect */
	printf("\tName:  %s \t\t\t Owner: %s\n",req->reqname,req->username);
	printf("\tPriority: %d\n",queue->v.que.priority);
	printf("\tState: ");

	/* step 7. get time */
	printf(" %s",get_rstate(queue->v.que.type, state));
	if ((state == SHO_RS_HOLD) || (state == SHO_RS_WAIT) || 
			(state== SHO_RS_RUN) )
		printf(" \teligible at: %s ",fmttime(&req->start_time));
	else
		printf(" \t\t entered at: %s \n",fmttime(&req->enter_time));
	printf("\tCreated at %s ",fmttime(&req->create_time));
	
	/* step 8. get queue */
	printf("\nQUEUE\n");
	printf("\tName:  %s@%s \n",req->quename,hostname);

	/* step 9. get resources */
	printf("\nRESOURCES\n");
	shoreql(queue,req);

	/* step 10. get stdout, stderr */
	printf("\nFILES\t\tMODE\t\tNAME\n");
        if ((req->v.bat.stderr_acc & OMD_EO) == 0) {
        	if (req->v.bat.stderr_acc & OMD_M_KEEP) {
                	if (queue->v.que.type == QUE_BATCH) {
                                    /*
                                     *  Use the name of the local host.
                                     */
                                    machinename = hostname;
                        }
                                else machinename = "<execution-host>";
                 }
                 else {
                                machinename=getmacnam(req->v.bat.stderr_mid);
                 }
                 printf("\tStderr: ");
		 shomd(req->v.bat.stderr_acc);
		 printf("\t%s\n",  req->v.bat.stderr_name);
	 }
         if (req->v.bat.stdout_acc & OMD_M_KEEP) {
                 if (queue->v.que.type==QUE_BATCH) {
                                /*
                                 *  Use the name of the local
                                 *  host.
                                 */
                                machinename = hostname;
                 }
                 else machinename = "<execution-host>";
                 }
                 else {
                            machinename = getmacnam (req->v.bat.stdout_mid);
         }
        printf ("\tStdout: ");
	shomd (req->v.bat.stdout_acc);
        printf ("  \t%s\n", req->v.bat.stdout_name);


	/* step 10. get mail */
	printf("\nMAIL\n");
	printf ("\tAddress: %s@%s\n", req->mail_name,
        getmacnam (req->mail_mid));

	printf ("\tWhen: ");
	if (req->flags & RQF_BEGINMAIL) {
		if (req->flags & RQF_ENDMAIL) 
			printf("begin, end\n");
		else printf ("begin\n");
	}
	else if (req->flags & RQF_ENDMAIL)  {
			printf(" end\n");
	}
	else printf("report of exception condition\n");
 
	/* step 10. get misc */
	printf("\nMISC\n");
	printf("\tRerunnable: "); 

	if (req->flags & RQF_RESTARTABLE)
		printf("yes ");
	else printf("no ");

	printf(" \t\t User Mask: %d \n",req->v.bat.umask);
	printf("\t\t\t\t\t Orig. Owner: %s \n",req->username);
        printf ("\tShell: ");
        if (req->v.bat.shell_name [0] == '\0') {
        	printf ("DEFAULT\n");
        }
        else {  /* An explicit shell spec is given */
        	fputs (req->v.bat.shell_name, stdout);
        	putchar ('\n');
        }
	/*
	 * NOT DEFINED AT THIS POINT
 	 *
	 *printf("\nEXPORTED VARIABLES\n");
	 *printf("\t not defined presently\n");
	 *printf("\nARGUMENTS \n");
	 *printf("\t not defined presently\n");
	 */

	printf("\n");
	
}

