/*
 *	Copyright 1988 by Rayan S. Zachariassen, all rights reserved.
 *	This will be free software, but only when it is finished.
 */

#include "hostenv.h"
#include <stdio.h>
#include "scheduler.h"
#include <fcntl.h>
#include <sys/file.h>

extern int errno;
extern time_t time();
extern char *rendezvous;
extern int qpctlfile();
extern int qpchannel();
extern int qphost();
extern char *saytime();

#ifdef	USE_TIMEVAL
#include <sys/time.h>
#else	/* !USE_TIMEVAL */
/*#include <unistd.h> */
/* some systems have utimbuf defined in unistd.h, some don't... */
struct utimbuf {
	time_t	actime;
	time_t	modtime;
};
#endif	/* USE_TIMEVAL */

FILE *qpfp;
char qpch;
time_t qpnow;

void
qprint(fd)
	int fd;
{
	time_t now;
#ifdef	USE_TIMEVAL
	struct timeval tvp[2];
#else	/* !USE_TIMEVAL */
	struct utimbuf tvp;
#endif	/* USE_TIMEVAL */

	/*
	 * The O_NDELAY flag is needed so we don't block
	 * if the file is a FIFO (which is recommended).
	 */
	if (fd < 0) {
#ifndef O_NDELAY
#define O_NDELAY 0	/* you lose */
#endif
		fd = open(rendezvous, O_WRONLY|O_CREAT|O_TRUNC|O_NDELAY, 0644);
		if (fd < 0) {
			fprintf(stderr,
				"open(%s): %d\n", rendezvous, errno);
			return;
		}
	}
	if ((qpfp = fdopen(fd, "w")) == NULL) {
		fprintf(stderr, "hmmm\n");
		close(fd);
		return;
	}
	qpch = '\0';
	fprintf(qpfp, "version zmailer 1.0\nVertices:\n");
	qpnow = time((time_t *)0);
	sp_scan(qpctlfile, (struct spblk *)NULL, spt_mesh[L_CTLFILE]);
	if (qpch != '\0') {
		fprintf(qpfp, "Channels:\n");
		sp_scan(qpchannel, (struct spblk *)NULL, spt_mesh[L_CHANNEL]);
		fprintf(qpfp, "Hosts:\n");
		sp_scan(qphost, (struct spblk *)NULL, spt_mesh[L_HOST]);
	}
	fclose(qpfp);
	/* XX: I suppose we don't really need to do this if we use TCP. */
	now = time((time_t *)0) - 1;
#ifdef	USE_TIMEVAL
	tvp[0].tv_sec = tvp[1].tv_sec = now;
	tvp[0].tv_usec = tvp[1].tv_usec = 0;
	utimes(rendezvous, tvp);
#else	/* !USE_TIMEVAL */
	tvp.actime = tvp.modtime = now;
	utime(rendezvous, &tvp);
#endif	/* USE_TIMEVAL */
}

int
qpctlfile(spl)
	struct spblk *spl;
{
	register struct ctlfile *cfp = (struct ctlfile *)spl->data;
	register struct vertex *vp;
	register int i;
	char buf[100];

	/* assert cfp != NULL */
	for (vp = cfp->head; vp != NULL; vp = vp->next[L_CTLFILE]) {
		fprintf(qpfp, "%lu:\t%s\t%d;",
			(u_long)vp, cfp->mid, vp->ngroup);
		qpch = ' ';
		for (i = 0; i < vp->ngroup; ++i) {
			fprintf(qpfp, "%c%ld",
				qpch, cfp->offset[vp->index[i]]);
			qpch = ',';
		}
		if (vp->message != NULL)
			fprintf(qpfp, "\t#%s", vp->message);
		if (vp->wakeup > qpnow || vp->ce.pending) {
			if (vp->message == NULL)
				fprintf(qpfp, "\t#");
			else
				putc(' ', qpfp);
			i = 0;
			if (vp->wakeup > qpnow) {
				buf[0] = '\0';
				saytime((u_long)(vp->wakeup - qpnow), buf, 1);
				fprintf(qpfp, "(retry in %s", buf);
				++i;
			} else /* if (vp->ce.pending) */ {
				fprintf(qpfp, "(waiting for %sslot",
					vp->ce.pending == SIZE_L ? "" :
					vp->ce.pending == L_CHANNEL ? "channel " :
					"host ");
				++i;
			}
                        if (vp->ce.expiry > 0) {
				/* [mea] Want to know when it expires.. */
				buf[0] = '\0';
				saytime((u_long)(vp->ce.expiry - qpnow),
					buf, 1);
				fprintf(qpfp,"%sexpires in %s",
					i ? ", " : "(", buf);
                        }
			if (i)
				putc(')', qpfp);
		}
		putc('\n', qpfp);
	}
	return 0;
}

int
qpchannel(spl)
	struct spblk *spl;
{
	register struct web *wc = (struct web *)spl->data;
	register struct vertex *vp;

	(void) fprintf(qpfp, "%s:\t", wc->name);
	for (vp = wc->link; vp != NULL; vp = vp->next[L_CHANNEL])
		fprintf(qpfp, ">%lu", (u_long)vp);
	fprintf(qpfp, "\n");
	return 0;
}

int
qphost(spl)
	struct spblk *spl;
{
	register struct web *wc = (struct web *)spl->data;
	register struct vertex *vp;

	fprintf(qpfp, "%s:\t", wc->name);
	for (vp = wc->link; vp != NULL; vp = vp->next[L_HOST])
		fprintf(qpfp, ">%lu", (u_long)vp);
	fprintf(qpfp, "\n");
	return 0;
}
