SCCSID(@
(#)queue.c 3.45 %G% (no queueing));
SCCSID(@
(#)queue.c 3.45 %G%);
** QUEUEUP -- queue a message up for future transmission.
** The queued message should already be in the correct place.
** This routine just outputs the control file as appropriate.
** e -- the envelope to queue up.
** queueall -- if TRUE, queue all addresses, rather than
** just those with the QQUEUEUP flag set.
** The current request (only unsatisfied addresses)
** are saved in a control file.
tf
= newstr(queuename(e
, 't'));
syserr("queueup: cannot create temp file %s", tf
);
printf("queueing in %s\n", tf
);
** If there is no data file yet, create one.
e
->e_df
= newstr(queuename(e
, 'd'));
dfp
= fopen(e
->e_df
, "w");
syserr("queueup: cannot create %s", e
->e_df
);
(void) chmod(e
->e_df
, 0600);
(*e
->e_putbody
)(dfp
, Mailer
[1], FALSE
);
** Output future work requests.
/* output name of data file */
fprintf(tfp
, "D%s\n", e
->e_df
);
/* output name of sender */
fprintf(tfp
, "S%s\n", e
->e_from
.q_paddr
);
/* output creation time */
fprintf(tfp
, "T%ld\n", e
->e_ctime
);
/* output message priority */
fprintf(tfp
, "P%ld\n", e
->e_msgpriority
);
/* output message class */
fprintf(tfp
, "C%d\n", e
->e_class
);
/* output macro definitions */
/* I don't think this is needed any more.....
for (i = 0; i < 128; i++)
register char *p = e->e_macro[i];
if (p != NULL && i != (int) 'b')
fprintf(tfp, "M%c%s\n", i, p);
/* output list of recipient addresses */
for (q
= e
->e_sendqueue
; q
!= NULL
; q
= q
->q_next
)
if (queueall
? !bitset(QDONTSEND
, q
->q_flags
) :
bitset(QQUEUEUP
, q
->q_flags
))
fprintf(tfp
, "R%s\n", q
->q_paddr
);
/* output headers for this message */
for (h
= e
->e_header
; h
!= NULL
; h
= h
->h_link
)
if (h
->h_value
== NULL
|| h
->h_value
[0] == '\0')
if (h
->h_mflags
!= 0 && bitset(H_CHECK
|H_ACHECK
, h
->h_flags
))
mfdecode(h
->h_mflags
, tfp
);
if (bitset(H_DEFAULT
, h
->h_flags
))
(void) expand(h
->h_value
, buf
, &buf
[sizeof buf
], e
);
fprintf(tfp
, "%s: %s\n", h
->h_field
, buf
);
else if (bitset(H_FROM
|H_RCPT
, h
->h_flags
))
commaize(h
, h
->h_value
, tfp
, e
->e_oldstyle
, NULL
);
fprintf(tfp
, "%s: %s\n", h
->h_field
, h
->h_value
);
syserr("cannot link(%s, %s), df=%s", tf
, qf
, e
->e_df
);
syslog(LOG_DEBUG
, "%s: queueup, qf=%s, df=%s\n", e
->e_id
, qf
, e
->e_df
);
** RUNQUEUE -- run the jobs in the queue.
** Gets the stuff out of the queue in some presumably logical
** order and processes them.
** runs things in the mail queue.
** See if we want to go off and do other useful work.
/* parent -- pick up intermediate zombie */
} while (i
>= 0 && i
!= pid
);
setevent(QueueIntvl
, runqueue
, TRUE
);
/* child -- double fork */
syslog(LOG_DEBUG
, "runqueue %s, pid=%d", QueueDir
, getpid());
** Start making passes through the queue.
** First, read and sort the entire queue.
** Then, process the work in that order.
** But if you take too long, start over.
/* order the existing work requests */
/* process them once at a time */
** ORDERQ -- order the work queue.
** Sets WorkQ to the queue of available work, in order.
# define WLSIZE 120 /* max size of worklist per sort */
register struct direct
*d
;
register WORK
**wp
; /* parent of w */
/* clear out old WorkQ */
for (w
= WorkQ
; w
!= NULL
; )
register WORK
*nw
= w
->w_next
;
/* open the queue directory */
syserr("orderq: cannot open \"%s\" as \".\"", QueueDir
);
** Read the work directory.
while (wn
< WLSIZE
&& (d
= readdir(f
)) != NULL
)
/* is this an interesting entry? */
if (d
->d_name
[0] != 'q' || d
->d_name
[1] != 'f')
/* yes -- open control file */
cf
= fopen(d
->d_name
, "r");
/* this may be some random person sending hir msgs */
/* syserr("orderq: cannot open %s", cbuf); */
wlist
[wn
].w_name
= newstr(d
->d_name
);
/* extract useful information */
while (fgets(lbuf
, sizeof lbuf
, cf
) != NULL
)
case 'P': /* message priority */
(void) sscanf(&lbuf
[1], "%ld", &wlist
[wn
].w_pri
);
** Sort the work directory.
qsort(wlist
, wn
, sizeof *wlist
, workcmpf
);
** Convert the work list into canonical form.
w
= (WORK
*) xalloc(sizeof *w
);
w
->w_name
= wlist
[i
].w_name
;
w
->w_pri
= wlist
[i
].w_pri
;
for (w
= WorkQ
; w
!= NULL
; w
= w
->w_next
)
printf("%32s: pri=%ld\n", w
->w_name
, w
->w_pri
);
** WORKCMPF -- compare function for ordering work.
** a -- the first argument.
** b -- the second argument.
# define PRIFACT 1800 /* bytes each priority point is worth */
if (a
->w_pri
== b
->w_pri
)
else if (a
->w_pri
> b
->w_pri
)
** DOWORK -- do a work request.
** w -- the work request to be satisfied.
** The work request is satisfied if possible.
printf("dowork: %s pri %ld\n", w
->w_name
, w
->w_pri
);
syserr("dowork: cannot fork");
** Lock the control file to avoid duplicate deliveries.
** Then run the file as though we had just read it.
** We save an idea of the temporary name so we
** can recover on interrupt.
/* set basic modes, etc. */
CurEnv
->e_qf
= w
->w_name
;
CurEnv
->e_id
= &w
->w_name
[2];
syslog(LOG_DEBUG
, "%s: dowork, pid=%d", CurEnv
->e_id
,
/* don't use the headers from sendmail.cf... */
chompheader("from: $q", TRUE
);
/* create the link to the control file during processing */
if (link(w
->w_name
, queuename(CurEnv
, 'l')) < 0)
/* being processed by another queuer */
syslog(LOG_DEBUG
, "%s: locked", CurEnv
->e_id
);
/* create ourselves a transcript file */
/* do basic system initialization */
/* read the queue control file */
/* if still not sent, perhaps we should time out.... */
printf("curtime=%ld, TimeOut=%ld\n", curtime(),
CurEnv
->e_ctime
+ TimeOut
);
if (CurEnv
->e_queueup
&& curtime() > CurEnv
->e_ctime
+ TimeOut
)
** Parent -- pick up results.
while ((i
= wait(&xstat
)) > 0 && errno
!= EINTR
)
** READQF -- read queue file and set up environment.
** cf -- name of queue control file.
** cf is read and created as the current job, as though
** we had been invoked by argument.
extern ADDRESS
*sendto();
** Open the file created by queueup.
syserr("readqf: no cf file %s", cf
);
** Read and process the file.
printf("\nRunning %s\n", cf
);
while (fgetfolded(buf
, sizeof buf
, f
) != NULL
)
case 'R': /* specify recipient */
(void) sendto(&buf
[1], 1, (ADDRESS
*) NULL
, 0);
(void) chompheader(&buf
[1], FALSE
);
setsender(newstr(&buf
[1]));
case 'D': /* data file name */
CurEnv
->e_df
= newstr(&buf
[1]);
TempFile
= fopen(CurEnv
->e_df
, "r");
syserr("readqf: cannot open %s", CurEnv
->e_df
);
case 'T': /* init time */
(void) sscanf(&buf
[1], "%ld", &CurEnv
->e_ctime
);
case 'P': /* message priority */
(void) sscanf(&buf
[1], "%ld", &CurEnv
->e_msgpriority
);
/* make sure that big things get sent eventually */
CurEnv
->e_msgpriority
-= WKTIMEFACT
;
case 'C': /* message class */
(void) sscanf(&buf
[1], "%hd", &CurEnv
->e_class
);
case 'M': /* define macro */
define(buf
[1], newstr(&buf
[2]));
syserr("readqf(%s): bad line \"%s\"", cf
, buf
);
** TIMEOUT -- process timeout on queue file.
** w -- pointer to work request that timed out.
** Returns a message to the sender saying that this
** message has timed out.
printf("timeout(%s)\n", w
->w_name
);
message(Arpa_Info
, "Message has timed out");
/* return message to sender */
(void) sprintf(buf
, "Cannot send mail for %s", pintvl(TimeOut
, FALSE
));
(void) returntosender(buf
, &CurEnv
->e_from
, TRUE
);
/* arrange to remove files from queue */
CurEnv
->e_dontqueue
= TRUE
;