/*
 * 5799-WZQ (C) COPYRIGHT IBM CORPORATION 1986
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */
/* $Header:spooljob.c 12.0$ */
/* $ACIS:spooljob.c 12.0$ */
/* $Source: /ibm/acis/usr/src/ibm/lpfilter/tools/RCS/spooljob.c,v $ */


#include <stdio.h>
#include <ctype.h>
#include <signal.h>
#include <utils.h>
#include <hash.h>
#include <environ.h>
#include <header.h>
#include <err_log.h>
#ifndef SJ_NO_ACCOUNTING
#include <ac.h>
#endif
#include <spooljob.h>

/***===================================================================***/

#define WHERE_AM_I "spooljob.c"

/***===================================================================***/

static sj_jobtype *sj_current= NULL;
static char       *sj_type=    NULL;
static int	   sj_killed=  FALSE;

#define sj_jtfunc(jt,f,a,d)	( (jt->f) ? (*(jt->f)) a : (d))
#define SJ_INPUT(e,i)		sj_jtfunc(sj_current,sj_input,(e,i),i)
#define SJ_OUTPUT(e,o)		sj_jtfunc(sj_current,sj_output,(e,o),o)
#define SJ_INIT(e)		sj_jtfunc(sj_current,sj_init,(e),FALSE)
#define SJ_MAIN(e,i,o)		sj_jtfunc(sj_current,sj_main,(e,i,o),FALSE)
#define SJ_IOCLEANUP(i,o)	sj_jtfunc(sj_current,sj_cleanup,(i,o),FALSE)
#define SJ_CANCEL()		sj_jtfunc(sj_current,sj_cancel,(0),SJ_EXIT)

/***===================================================================***/

int sj_debug;

static error_log *sj_errlog= NULL;

static FILE	 *sj_infil=  NULL;
static FILE	 *sj_outfil= NULL;

/***===================================================================***/

#ifndef SJ_NO_ACCOUNTING
static char	 *sj_accfil= NULL;
static ac_record *sj_acct=   NULL;
#endif

/***===================================================================***/

#ifdef DEBUG_UTILS

static u_debug_arg  sj_dflags[] = {
    "env",	&env_debug,
    "u",	&u_debug,
    "ht",	&ht_debug,
    "hdr",	&hdr_debug,
    "sj",	&sj_debug,
#ifdef FILE_UTILS
    "uf",       &u_fdebug,
#endif
    "el",	&el_debug,
    NULL,	NULL
};

#endif /* ifdef DEBUG_UTILS */

/***===================================================================***/

static
sj_ParseArgs(argc,argv,env)
register3 int      argc;
register4 char    *argv[];
register2 environ *env;
{
register1 int    ch;
extern char *optstring;
extern char *optarg;
extern int   optind;
extern int   optany;
extern int   optional;
char  opts[30];

    D_ENTRY2(sj_debug,"sj_Args(%d,0x%x)\n",argc,argv);
    optional= '?';
    optany= TRUE;
    strcpy(opts,"d?h:n:t!");
    env_AddString(env,"invocation_name",argv[0]);
    while ((ch= getopt(argc,argv,opts))!=EOF) {
       switch (ch) {
#ifdef DEBUG_UTILS
	  when 'd': if (optarg) u_SetDebug(optarg,2,debug_args,sj_dflags);
	  	    else        u_SetDebug("a",2,debug_args,sj_dflags);
#else
	  when 'd': warning("debugging disabled.\n");
	  	    action1("-%c flag ignored\n",ch);
#endif /*DEBUG_UTILS*/
	  when '!': env_AddString(env,"error_messages","mail");
		    sj_SaveErrors(env);
	  when 'h': env_AddString(env,"host",optarg);
	  when 'n': env_AddString(env,"user",optarg);
	  when 't': sj_outfil= stdout;
	  otherwise:
#ifdef SJ_ARG_PARSER
		    SJ_ARG_PARSER(argc,argv,optind,env);
#else
		    optind++;
#endif /* SJ_ARG_PARSER */
   		    break;
       }
    }
    if (optind<argc) {
	sj_accfil= argv[optind++];
    }
    else {
	warning("no accounting file specified\n");
	action("/dev/null here we come\n");
	sj_accfil= NULL;
    }
    if (optind<argc) {
	warning("arguments specified after accounting file\n");
	action("ignored\n");
    }
    RETURN(TRUE);
}

/***===================================================================***/

sj_Cancel(sig,code,scp)
int	sig,code;
struct sigcontext *scp;
{
register1 int	rtrn;

    D_ENTRY(sj_debug,"sj_Cancel()\n");
    switch (rtrn= SJ_CANCEL()) {
	case SJ_EXIT_PENDING:
		action("cancel received -- pending\n");
		sj_killed=TRUE;
		RETURN(TRUE);
	case SJ_IGNORE:
		warning("cancel received -- ignored\n");
		RETURN(TRUE);
	default:
		WSGO1("sj_Cancel -- funny value %d\n",rtrn);
	case SJ_EXIT:
		action("cancel received -- cleaning up\n");
		sj_AbnormalExit();
    }
    RETURN(FALSE);
}

/***===================================================================***/

static
sj_AbnormalExit()
{
register1 int pages;

    D_ENTRY(sj_debug,"sj_AbnormalExit()\n");
    pages= SJ_IOCLEANUP(sj_infil,sj_outfil);
    el_Report(sj_errlog,sj_outfil);
    el_Close(sj_errlog);
#ifndef SJ_NO_ACCOUNTING
    if (sj_accfil) {
	ac_Error(sj_acct);
	sj_Account(pages);
    }
#endif
    exit(2);
    RETURN(TRUE);
}

/***===================================================================***/

static
sj_SetErrorLevel(env)
register1 environ *env;
{
register2 char *level;
    D_ENTRY1(sj_debug,"sj_SetErrorLevel(0x%x)\n",env);
    level= env_String(env,"error_level",SJ_DFLT_ERROR_LEVEL);
    if (!level||StrMatch(level,"all"))	{
	u_error_level= U_INFO|U_WARNING|U_ERROR;
    }
    else if (StrMatch(level,"warning")) {
	u_error_level= U_WARNING|U_ERROR;
    }
    else if (StrMatch(level,"error")) {
	u_error_level= U_ERROR;
    }
    else if (StrMatch(level,"none")) {
	u_error_level= 0;
    }
    else {
	error1("Illegal error level %s\n",level);
	action("level unchanged\n");
	RETURN(FALSE);
    }
    RETURN(TRUE);
}

/***===================================================================***/

static
sj_SaveErrors(env)
register1 environ *env;
{

    D_ENTRY1(sj_debug,"sj_SaveErrors(0x%x)\n",env);
    el_Init();
    sj_errlog= el_Open(env,stderr);
    if (sj_errlog) {
	error_file(el_File(sj_errlog));
	DEBUG_FILE(el_File(sj_errlog));
    }
    error_func(sj_AbnormalExit);
    sj_SetErrorLevel(env);
    RETURN(TRUE);
}

/***===================================================================***/

sj_ReportErrors()
{
    D_ENTRY(sj_debug,"sj_ReportErrors()\n");
    if (sj_errlog) {
	el_Report(sj_errlog,sj_outfil);
	el_Close(sj_errlog);
    }
    RETURN(TRUE);
}

/***===================================================================***/

/*ARGSUSED*/
sj_ResetIO(env,str)
register1 environ *env;
register2 char    *str;
{
register3 FILE *infil;
register4 FILE *outfil;
register6 int   ch;
char tmp[40];

    D_ENTRY2(sj_debug,"sj_ResetIO(0x%x,%s)\n",env,str);
    sprintf(tmp,"/tmp/sjinput.%d",getpid());
    infil=  sj_infil;
    outfil= u_fopen(tmp,"w");
    if (!outfil) {
	WSGO1("Can't write intermediate file %s\n",tmp);
	RETURN(FALSE);
    }
    fprintf(outfil,"%s",str);
    while ((ch=getc(infil))!=EOF) {
	putc(ch,outfil);
    }
    u_fclose(outfil);
    infil= u_fopen(tmp,"r");
    if (!infil) {
	WSGO1("Can't read intermediate file %s\n",tmp);
	RETURN(FALSE);
    }
    fclose(sj_infil);
    sj_infil= infil;
    unlink(tmp);
    RETURN(TRUE);
}

/***===================================================================***/

sj_SetupIO(env)
register1 environ *env;
{

    D_ENTRY1(sj_debug,"sj_SetupIO(0x%x)\n",env);
    sj_infil=  SJ_INPUT(env,sj_infil);
    if (!sj_outfil)
       sj_outfil= SJ_OUTPUT(env,NULL);

    if (!sj_outfil) {
	fatal("Can't open output\n");
    }
    RETURN(TRUE);
}

/***===================================================================***/

#ifndef SJ_NO_ACCOUNTING
static
sj_Account(pages)
register2 int pages;
{

    D_ENTRY1(sj_debug,"sj_Account(%d)\n",pages);
    if (sj_accfil) {
	register1 FILE *fil;

	ac_End(sj_acct,pages);
	fil= u_fopen(sj_accfil,"a");
	if (fil) {
	    ac_Dump(fil,sj_acct);
	    u_fclose(fil);
	}
	else {
	    error1("Can't open accounting file %s\n",sj_accfil);
	    action("accounting terminated\n");
	}
    }
    RETURN(TRUE);
}

#endif

/***===================================================================***/

static struct sigvec sj_sigint = { sj_Cancel, 0, 0 };
			
static
sj_Init(env)
register1 environ *env;
{
#ifdef DEBUG_UTILS
register3 char *dargs;
#endif /* DEBUG_UTILS */
register2 sj_jobtype *jt;

    D_ENTRY1(sj_debug,"sj_Init(0x%x)\n",env);
#ifdef DEBUG_UTILS
    dargs= env_String(env,"job_debug",NULL);
    if (dargs)
       u_SetDebug(dargs,2,debug_args,sj_dflags);
#endif /* DEBUG_UTILS */
    sj_type= env_String(env,"job_type",SJ_DEFAULT_TYPE(env));
    jt= sj_types;
    while (jt->sj_tname) {
	if (StrMatch(jt->sj_tname,sj_type)) {
	    sj_current= jt;
	    if (sj_current->sj_init) {
		(*(sj_current->sj_init))(env);
	    }
#ifndef SJ_NO_ACCOUNTING
	    if (sj_accfil) {
	       sj_acct= ac_Begin(env_String(env,"user",(char *)NULL),
	       			 env_String(env,"host",(char *)NULL),
				 env_String(env,"job_type",(char *)NULL));
	    }
#endif
	    SJ_INIT(env);
	    sigvec(SIGINT,&sj_sigint,NULL);
	    RETURN(TRUE);
	}
	jt++;
    }
    RETURN(FALSE);
}

/***===================================================================***/

main(argc,argv)
register2 int   argc;
register3 char *argv[];
{
register1 environ *env;
register4 char *str;
register5 int   pages;

    D_ENTRY2(sj_debug,"main(%d,0x%x)\n",argc,argv);
    env= env_New(SJ_ENVNAME,SJ_ENVTOKENS,SJ_ENVFLAGS);
    sj_infil= stdin;
    str=env_Parse(sj_infil,env);
    sj_ParseArgs(argc,argv,env);
    if (!sj_Init(env)) {
	fatal1("Unknown job type %s encountered\n",sj_type);
    }
    if (str)
       sj_ResetIO(env,str);
    sj_SetupIO(env);
    hdr_Print(sj_outfil,env);

    if (!sj_errlog)
	sj_SaveErrors(env);

    pages= SJ_MAIN(env,sj_infil,sj_outfil);

    sj_ReportErrors();
#ifndef SJ_NO_ACCOUNTING
    sj_Account(pages);
#endif
    if (sj_killed) 	RETURN(2);
    else		RETURN(0);
}

