/*
 *	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     16-Jan-1992	Added support for RS6000.
*       V01.3   JRR     05-Mar-1992	Changed to use matche like the VAX.
*       V01.4   JRR     06-Mar-1992	Fix up static references (BAH!).
*	V01.5	JRR	17-Jun-1992	Added header.
*	V01.6	JRR	05-Nov-1992	Modified for C prototypes.
*	V01.7	JRR	11-Mar-1993	Removed unnecessary chdir to NQS_ROOT.
*	V01.8	JRR	18-Aug-1993	Miniscule change to includes.
*	V01.9	JRR	28-Feb-1994	Added support for SOLARIS.
*/
#include "nqs.h"
#include "transactcc.h"                 /* Transaction completion codes */
#include "nqsxdirs.h"

extern char *Qdel_prefix;

#ifndef __CEXTRACT__
#if __STDC__

static int qdel_selrequest ( struct qentry *qentry, short sig, uid_t whomuid, char *req_pat, int confirm );

#else /* __STDC__ */

static int qdel_selrequest (/* struct qentry *qentry, short sig, uid_t whomuid, char *req_pat, int confirm */);

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



qdel_by_req(req_pat, real_uid, sig, confirm)
char	*req_pat;			/* Request pattern */
uid_t	real_uid;			/* user id to check */
short	sig;				/* signal to send */
int	confirm;			/* true if confirm deletion */
{
	struct confd *queuefile;       /* MUST be the NQS queue file */
	long flags;                    /* Display flags */
	struct reqset *reqs;           /* Req select set */
        short daepresent;              /* Boolean non-zero if the local */
                                       /* NQS daemon is present and running */
	struct confd *qmapfile;        /* Queue/device/destination mapping */
                                       /* file */
	struct confd *pipeqfile;       /* Pipe-queue destination file */

        register struct gendescr *descr;
        int fd;                         /* Queue ordering file descriptor */
        int i;                          /* Loop var */
        struct qentry cache [QOFILE_CACHESIZ];
                                        /* Queue ordering file cache buffer */
        int cacheindex;                 /* Current buffer cache index */
        int cachesize;                  /* Number of queue entries in read */
                                        /* cache buffer */
	int	tot_requests;		/* total number of requests */


	/* debugging
	 * printf("Request pattern is %s\n",req_pat);
	 * printf("Uid is %d\n", real_uid);
	 * printf("Signal is %d\n", sig);
	 */

        if ((queuefile = opendb (Nqs_queues, O_RDONLY)) == NULL) {
                fprintf (stderr, "%s(FATAL): Unable to open the NQS queue ",
                         Qdel_prefix);
                fprintf (stderr, "definition database file.\n");
                exit (2);
        }
        seekdb (queuefile, 0L); /* Seek to the beginning */
        descr = nextdb (queuefile);
        if ((qmapfile = opendb (Nqs_qmaps, O_RDONLY)) == NULL) {
                fprintf (stderr, "%s(FATAL): Unable to open the NQS queue/",
                         Qdel_prefix);
                fprintf (stderr, "device/destination\n");
                fprintf (stderr, "%s(FATAL): mapping database file.\n",
                         Qdel_prefix);
                exit (3);
        }
        if ((pipeqfile = opendb (Nqs_pipeto, O_RDONLY)) == NULL) {
                fprintf (stderr, "%s(FATAL): Unable to open the NQS pipe-",
                         Qdel_prefix);
                fprintf (stderr, "queue destination database file.\n");
                exit (4);
        }
#if     BSD43 | ULTRIX | DECOSF
        daepresent = daepres (queuefile);
#else
#if     HPUX | SGI | SOLARIS | SYS52 | IBMRS | LINUX
        daepresent = daepres();
#else
BAD SYSTEM TYPE
#endif
#endif

        while (descr != (struct gendescr *)0) {

        	fd = openqord (queuefile, descr);
        	/*
         	 *  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.
         	 */
        	if (fd < -1) return (fd);       /* Error or queue was deleted */

		tot_requests = descr->v.que.departcount +
			descr->v.que.runcount +
			descr->v.que.stagecount +
			descr->v.que.queuedcount +
			descr->v.que.waitcount +
			descr->v.que.holdcount +
			descr->v.que.arrivecount;
		cacheindex = 0;
		cachesize = 0;
        	for (i = 0; i < tot_requests; i++) {
        		if (cacheindex >= cachesize) {
                        	cachesize = read (fd, (char *) cache,
                                                  sizeof (cache));
                        	cachesize /= sizeof (struct qentry);
                        	cacheindex = 0;
                	}
                	qdel_selrequest (&cache [cacheindex], sig,
                                        real_uid, req_pat,confirm);
                	cacheindex++;
        	}
        descr = nextdb (queuefile);  /* Get the next queue */
        }

}
static int qdel_selrequest (qentry, sig, whomuid, req_pat, confirm)
register struct qentry *qentry;         /* Request queue entry */
short  sig;                             /* signal */
uid_t  whomuid;                         /* Whom we are asking about */
char   *req_pat;		        /* compiled request pattern */
int    confirm;				/* true if confirm deletion */
{
	char	line[128];

	/* printf ("Whomuid = %d\n", whomuid); */
        if (whomuid != 0) {
		if  (qentry->uid != whomuid) 
                                return (0);     /* Request will not be */
						/* deleted */
	}
	qentry->reqname_v[MAX_REQNAME] = '\0';
	/* printf("Request name is %s\n", qentry->reqname_v ); */
	if (matche (req_pat, qentry->reqname_v) == 1) {
		/* printf("Found a live one.\n"); */
		if (confirm) {
			printf("Delete request %s [Y/N/Q]? ", 
						qentry->reqname_v);
			(void) fflush (stdout);
			(void) gets(line);
			line[0] = toupper(line[0]);
			if (line[0] == 'Q') exit(0);
			if (line[0] != 'Y') return;
		}
                qdel_diagdel (delreq (whomuid, qentry->orig_seqno,
                                 qentry->orig_mid, 0, sig,
                                 RQS_DEPARTING | RQS_RUNNING | RQS_STAGING |
                                 RQS_QUEUED | RQS_WAITING | RQS_HOLDING |
                                 RQS_ARRIVING), qentry->reqname_v);

	}
        return (0);                     /* It wasn't one of the requests */
                                        /* we are looking for. */
}

/*** qdel_diagdel
 *
 *
 *      qdel_diagdel():
 *      Diagnose delreq() completion code.
 */
void qdel_diagdel (code, reqid)
long code;                              /* Transaction completion code */
char *reqid;                            /* Character version of request-id */
{
        switch (code) {
        case TCML_INTERNERR:
                printf ("Internal error.\n");
                exiting();              /* Delete communication file */
                exit (1);
        case TCML_NOESTABLSH:
                printf ("Unable to establish inter-process communications ");
                printf ("with NQS daemon.\n");
                printf ("Seek staff support.\n");
                exiting();              /* Delete communication file */
                exit (1);
        case TCML_NOLOCALDAE:
                printf ("The NQS daemon is not running.\n");
                printf ("Seek staff support.\n");
                exiting();              /* Delete communication file */
                exit (1);
        case TCML_NOSUCHREQ:
                printf ("Request %s does not exist.\n", reqid);
                break;
        case TCML_NOSUCHSIG:
                printf ("Request %s is running, and the ", reqid);
                printf ("specified signal is\n");
                printf ("not recognized by the execution machine.\n");
                break;
        case TCML_NOTREQOWN:
                printf ("Not owner of request %s.\n", reqid);
                break;
        case TCML_PEERDEPART:
                printf ("Request %s is presently being routed by a ", reqid);
                printf ("pipe queue,\n");
                printf ("and this NQS implementation does not support the ");
                printf ("deletion of a\n");
                printf ("request under such conditions.\n");
                break;
        case TCML_PROTOFAIL:
                printf ("Protocol failure in inter-process communications ");
                printf ("with NQS daemon.\n");
                printf ("Seek staff support.\n");
                exiting();              /* Delete communication file */
                exit (1);
        case TCML_REQDELETE:
                printf ("Request %s has been deleted.\n", reqid);
                break;
        case TCML_REQRUNNING:
                printf ("Request %s is running.\n", reqid);
                break;
        case TCML_REQSIGNAL:
                printf ("Request %s is running, and has ", reqid);
                printf ("been signalled.\n");
                break;
        default:
                printf ("Unexpected completion code from NQS daemon.\n");
                exiting();              /* Delete communication file */
                exit (1);
        }
}

