#include "stdarg.h"
#include "lpsched.h"
#include <syslog.h>
extern int isStartingForms;
typedef struct later {
struct later * next;
int event,
ticks;
union arg {
PSTATUS * printer;
RSTATUS * request;
FSTATUS * form;
} arg;
} LATER;
static LATER LaterHead = { 0 },
TempHead;
static void ev_interf(PSTATUS *);
static void ev_message(PSTATUS *);
static void ev_form_message(FSTATUS *);
static int ev_slowf(RSTATUS *);
static int ev_notify(RSTATUS *);
static EXEC *find_exec_slot(EXEC **);
static char *_event_name(int event)
{
static char *_names[] = {
"", "EV_SLOWF", "EV_INTERF", "EV_NOTIFY", "EV_LATER", "EV_ALARM",
"EV_MESSAGE", "EV_ENABLE", "EV_FORM_MESSAGE", NULL };
if ((event < 0) || (event > EV_FORM_MESSAGE))
return ("BAD_EVENT");
else
return (_names[event]);
}
void
schedule(int event, ...)
{
va_list ap;
LATER * plprev;
LATER * pl;
LATER * plnext = 0;
register PSTATUS * pps;
register RSTATUS * prs;
register FSTATUS * pfs;
int i;
syslog(LOG_DEBUG, "schedule(%s)", _event_name(event));
if (Shutdown)
return;
va_start (ap, event);
if (Starting) {
switch (event) {
case EV_INTERF:
case EV_ENABLE:
pps = va_arg(ap, PSTATUS *);
schedule (EV_LATER, 1, event, pps);
goto Return;
case EV_SLOWF:
case EV_NOTIFY:
prs = va_arg(ap, RSTATUS *);
schedule (EV_LATER, 1, event, prs);
goto Return;
case EV_MESSAGE:
pps = va_arg(ap, PSTATUS *);
schedule (EV_LATER, 1, event, pps);
goto Return;
case EV_FORM_MESSAGE:
pfs = va_arg(ap, FSTATUS *);
schedule (EV_LATER, 1, event, pfs);
goto Return;
case EV_LATER:
break;
case EV_ALARM:
goto Return;
}
}
switch (event) {
case EV_INTERF:
if ((pps = va_arg(ap, PSTATUS *)) != NULL)
ev_interf (pps);
else
for (i = 0; PStatus != NULL && PStatus[i] != NULL; i++)
ev_interf (PStatus[i]);
break;
case EV_ENABLE:
if ((pps = va_arg(ap, PSTATUS *)) != NULL)
enable (pps);
else
for (i = 0; PStatus != NULL && PStatus[i] != NULL; i++)
enable (PStatus[i]);
break;
case EV_SLOWF:
if ((prs = va_arg(ap, RSTATUS *)) != NULL)
(void) ev_slowf (prs);
else
for (prs = Request_List; prs && ev_slowf(prs) != -1;
prs = prs->next);
break;
case EV_NOTIFY:
if ((prs = va_arg(ap, RSTATUS *)) != NULL)
(void) ev_notify (prs);
else
for (prs = Request_List; prs && ev_notify(prs) != -1;
prs = prs->next);
break;
case EV_MESSAGE:
pps = va_arg(ap, PSTATUS *);
ev_message(pps);
break;
case EV_FORM_MESSAGE:
pfs = va_arg(ap, FSTATUS *);
ev_form_message(pfs);
break;
case EV_LATER:
pl = (LATER *)Malloc(sizeof (LATER));
if (!LaterHead.next)
alarm (CLOCK_TICK);
pl->next = LaterHead.next;
LaterHead.next = pl;
pl->ticks = va_arg(ap, int);
pl->event = va_arg(ap, int);
switch (pl->event) {
case EV_MESSAGE:
case EV_INTERF:
case EV_ENABLE:
pl->arg.printer = va_arg(ap, PSTATUS *);
if (pl->arg.printer)
pl->arg.printer->status |= PS_LATER;
break;
case EV_FORM_MESSAGE:
pl->arg.form = va_arg(ap, FSTATUS *);
break;
case EV_SLOWF:
case EV_NOTIFY:
pl->arg.request = va_arg(ap, RSTATUS *);
break;
}
break;
case EV_ALARM:
Sig_Alrm = 0;
TempHead.next = 0;
for (pl = (plprev = &LaterHead)->next; pl; pl = plnext) {
plnext = pl->next;
if (--pl->ticks)
plprev = pl;
else {
plprev->next = plnext;
pl->next = TempHead.next;
TempHead.next = pl;
}
}
for (pl = TempHead.next; pl; pl = plnext) {
plnext = pl->next;
switch (pl->event) {
case EV_MESSAGE:
case EV_INTERF:
case EV_ENABLE:
pl->arg.printer->status &= ~PS_LATER;
schedule (pl->event, pl->arg.printer);
break;
case EV_FORM_MESSAGE:
schedule (pl->event, pl->arg.form);
break;
case EV_SLOWF:
case EV_NOTIFY:
schedule (pl->event, pl->arg.request);
break;
}
Free ((char *)pl);
}
if (LaterHead.next)
alarm (CLOCK_TICK);
break;
}
Return: va_end (ap);
return;
}
void
maybe_schedule(RSTATUS *prs)
{
if (NEEDS_FILTERING(prs))
schedule (EV_SLOWF, prs);
else if (!(prs->request->outcome & RS_STOPPED))
schedule (EV_INTERF, prs->printer);
return;
}
static void
ev_message(PSTATUS *pps)
{
register RSTATUS *prs;
char toSelf;
syslog(LOG_DEBUG, "ev_message(%s)",
(pps && pps->request && pps->request->req_file ?
pps->request->req_file : "NULL"));
toSelf = 0;
for (prs = Request_List; prs != NULL; prs = prs->next)
if (prs->printer == pps) {
note("prs (%d) pps (%d)\n", prs, pps);
if (!toSelf) {
toSelf = 1;
exec(EX_FAULT_MESSAGE, pps, prs);
}
}
}
static void
ev_form_message_body(FSTATUS *pfs, RSTATUS *prs, char *toSelf, char ***sysList)
{
syslog(LOG_DEBUG, "ev_form_message_body(%s, %d, 0x%x)",
(pfs && pfs->form && pfs->form->name ? pfs->form->name : "NULL"),
(toSelf ? *toSelf : 0),
sysList);
if (!*toSelf) {
*toSelf = 1;
exec(EX_FORM_MESSAGE, pfs);
}
}
static void
ev_form_message(FSTATUS *pfs)
{
register RSTATUS *prs;
char **sysList;
char toSelf;
syslog(LOG_DEBUG, "ev_form_message(%s)",
(pfs && pfs->form && pfs->form->name ?
pfs->form->name : "NULL"));
toSelf = 0;
sysList = NULL;
for (prs = Request_List; prs != NULL; prs = prs->next)
if (prs->form == pfs)
ev_form_message_body(pfs, prs, &toSelf, &sysList);
if (NewRequest && (NewRequest->form == pfs))
ev_form_message_body(pfs, NewRequest, &toSelf, &sysList);
freelist(sysList);
}
#define MATCH(PRS, PPS) (\
!(PPS)->printer->daisy || \
!(PRS)->pwheel_name || \
!((PRS)->status & RSS_PWMAND) || \
STREQU((PRS)->pwheel_name, NAME_ANY) || \
((PPS)->pwheel_name && \
STREQU((PPS)->pwheel_name, (PRS)->pwheel_name)))
static void
ev_interf(PSTATUS *pps)
{
register RSTATUS *prs;
syslog(LOG_DEBUG, "ev_interf(%s)",
(pps && pps->request && pps->request->req_file ?
pps->request->req_file : "NULL"));
if (pps->request || pps->status & (PS_DISABLED|PS_LATER|PS_BUSY))
return;
for (prs = Request_List; prs != NULL; prs = prs->next) {
if ((prs->printer == pps) && (qchk_waiting(prs)) &&
isFormUsableOnPrinter(pps, prs->form) && MATCH(prs, pps)) {
pps->request = prs;
if (exec(EX_INTERF, pps) == 0) {
pps->status |= PS_BUSY;
return;
}
pps->request = 0;
if (errno == EAGAIN) {
load_str (&pps->dis_reason, CUZ_NOFORK);
schedule (EV_LATER, WHEN_FORK, EV_ENABLE, pps);
return;
}
}
}
return;
}
static int
ev_slowf(RSTATUS *prs)
{
register EXEC *ep;
syslog(LOG_DEBUG, "ev_slowf(%s)",
(prs && prs->req_file ? prs->req_file : "NULL"));
if (!(ep = find_exec_slot(Exec_Slow))) {
syslog(LOG_DEBUG, "ev_slowf(%s): no slot",
(prs && prs->req_file ? prs->req_file : "NULL"));
return (-1);
}
if (!(prs->request->outcome & (RS_DONE|RS_HELD|RS_ACTIVE)) &&
NEEDS_FILTERING(prs)) {
(prs->exec = ep)->ex.request = prs;
if (exec(EX_SLOWF, prs) != 0) {
ep->ex.request = 0;
prs->exec = 0;
if (errno == EAGAIN) {
schedule (EV_LATER, WHEN_FORK, EV_SLOWF, prs);
return (-1);
}
}
}
return (0);
}
static int
ev_notify(RSTATUS *prs)
{
register EXEC *ep;
syslog(LOG_DEBUG, "ev_notify(%s)",
(prs && prs->req_file ? prs->req_file : "NULL"));
if (prs->request->actions & ACT_NOTIFY) {
if (prs->request->outcome & RS_NOTIFY) {
prs->request->actions &= ~ACT_NOTIFY;
return (0);
}
} else if (!(ep = find_exec_slot(Exec_Notify)))
return (-1);
else if (prs->request->outcome & RS_NOTIFY &&
!(prs->request->outcome & RS_NOTIFYING)) {
(prs->exec = ep)->ex.request = prs;
if (exec(EX_NOTIFY, prs) != 0) {
ep->ex.request = 0;
prs->exec = 0;
if (errno == EAGAIN) {
schedule (EV_LATER, WHEN_FORK, EV_NOTIFY, prs);
return (-1);
}
}
}
return (0);
}
static EXEC *
find_exec_slot(EXEC **exec_table)
{
int i;
for (i = 0; exec_table[i] != NULL; i++)
if (exec_table[i]->pid == 0)
return (exec_table[i]);
syslog(LOG_DEBUG, "find_exec_slot(0x%8.8x): after %d, no slots",
exec_table, i);
return (0);
}