Metropoli BBS
VIEWER: mailovly.c MODE: TEXT (ASCII)
/*--------------------------------------------------------------------------*/
/*                                                                          */
/*                                                                          */
/*      ------------         Bit-Bucket Software, Co.                       */
/*      \ 10001101 /         Writers and Distributors of                    */
/*       \ 011110 /          Freely Available<tm> Software.                 */
/*        \ 1011 /                                                          */
/*         ------                                                           */
/*                                                                          */
/*              (C) Copyright 1987-96, Bit Bucket Software Co.              */
/*                                                                          */
/*                 This module was written by Bob Hartman                   */
/*                                                                          */
/*                   BinkleyTerm Mail Control Routines                      */
/*                                                                          */
/*                                                                          */
/*    For complete  details  of the licensing restrictions, please refer    */
/*    to the License  agreement,  which  is published in its entirety in    */
/*    the MAKEFILE and BT.C, and also contained in the file LICENSE.260.    */
/*                                                                          */
/*    USE  OF THIS FILE IS SUBJECT TO THE  RESTRICTIONS CONTAINED IN THE    */
/*    BINKLEYTERM  LICENSING  AGREEMENT.  IF YOU DO NOT FIND THE TEXT OF    */
/*    THIS  AGREEMENT IN ANY OF THE  AFOREMENTIONED FILES,  OR IF YOU DO    */
/*    NOT HAVE THESE FILES,  YOU  SHOULD  IMMEDIATELY CONTACT BIT BUCKET    */
/*    SOFTWARE CO.  AT ONE OF THE  ADDRESSES  LISTED BELOW.  IN NO EVENT    */
/*    SHOULD YOU  PROCEED TO USE THIS FILE  WITHOUT HAVING  ACCEPTED THE    */
/*    TERMS  OF  THE  BINKLEYTERM  LICENSING  AGREEMENT,  OR  SUCH OTHER    */
/*    AGREEMENT AS YOU ARE ABLE TO REACH WITH BIT BUCKET SOFTWARE, CO.      */
/*                                                                          */
/*                                                                          */
/* You can contact Bit Bucket Software Co. at any one of the following      */
/* addresses:                                                               */
/*                                                                          */
/* Bit Bucket Software Co.        FidoNet  1:104/501, 1:343/491             */
/* P.O. Box 460398                AlterNet 7:42/1491                        */
/* Aurora, CO 80046               BBS-Net  86:2030/1                        */
/*                                Internet f491.n343.z1.fidonet.org         */
/*                                                                          */
/* Please feel free to contact us at any time to share your comments about  */
/* our software and/or licensing policies.                                  */
/*                                                                          */
/*--------------------------------------------------------------------------*/

/* Include this file before any other includes or defines! */

#include "includes.h"

static char LOCALFUNC mail_stat (MAILP);
static int LOCALFUNC xmit_install (MAILP, ADDRP);
static MAILP LOCALFUNC xmit_find (MAILP, ADDRP);
static long LOCALFUNC netsize (MAILP);
static int LOCALFUNC any_mail (MAILP);
static void LOCALFUNC do_xmit_line (char *, MAILP);
static void LOCALFUNC xmit_sort (void);
static void LOCALFUNC kill_one (ADDRP address);
static void LOCALFUNC xmit_delete_one (void);
char *mail_status_chars (unsigned int);

static char *HoldFmtStr = "%-12.12s %3d %4.4s %5.5s %c";
static char *HoldNoSize = "%-21.21s %5.5s %c";

void 
xmit_sameplace ()
{
	MAILP p, p1;

	/* Find the guy we just gave mail to */

	p = find_mail (&remote_addr);
	remote_addr.Zone = remote_addr.Net = remote_addr.Node = remote_addr.Point = 0;
	remote_addr.Domain = NULL;
	if (p == NULL)
	{
		/* He is not there */
		return;
	}

	/* Save our current pointer */

	p1 = next_mail;
	if (p != next_mail)
	{
		/* If it is not the one we just gave mail to, save ptr and delete */
		next_mail = p;
		xmit_delete ();
		next_mail = p1;
	}
	else
	{
		/* It was the guy at the head of the list, so just delete him */
		xmit_delete ();
	}

	/* If we came in with a null, leave with a null */

	if (p1 == NULL)
		next_mail = NULL;

	return;
}

MAILP 
find_mail (ADDRP address)
{
	MAILP p;

	p = mail_top;
	while (p != NULL)
	{
		if ((no_zones || (p->mail_addr.Zone == address->Zone)) &&
			(p->mail_addr.Net == address->Net) &&
			(p->mail_addr.Node == address->Node) &&
			(p->mail_addr.Point == address->Point) &&
			((p->mail_addr.Domain == address->Domain) ||
				((p->mail_addr.Domain == my_addr.Domain) &&
					(address->Domain == NULL))))
			break;
		p = p->next;
	}

	return (p);
}

static int LOCALFUNC 
xmit_install (MAILP p, ADDRP addr)
{
	MAILP p1, p2;
	int rettype;
	long sztemp;
	MDM_TRNS *m;					/* MB 93-11-27 */

	p2 = find_mail (addr);

	if (p2 == NULL)
	{
		/* We didn't find it in what we have already */
		p1 = p;
		p1->mail_addr = *addr;
		p1->oldest = (unsigned long) time (NULL);
		rettype = 0;
	}
	else
	{
		/* We found it, so we have to make sure the higher level routine knows */
		p1 = p2;
		rettype = 1;
	}

/*
 * Get the size of the entry. If it's a FLO-type file,
 * call netsize to find out how big the stuff contained in it
 * actually is. If it's a packet, just take its size.
 *
 * Hold packets don't count.
 */

	if (!no_size)
	{
		sztemp = 0L;

		if (!strncmp (&(dta_str.name[10]), "LO", 2))
			p1->mailsize += (sztemp = netsize (p1));

		else if ((!strncmp (&(dta_str.name[10]), "UT", 2)) ||
				(!strncmp (&(dta_str.name[9]), "REQ", 3)))
		{
			struct tm tmstruc;
			time_t curr_time;

			p1->numfiles++;
			p1->mailsize += (sztemp = dta_str.size);

			curr_time = time (NULL);
			tmstruc = *localtime (&curr_time);	/* Structure assignment */

			tmstruc.tm_year = (int) (dta_str.time >> 25) + 80;
			tmstruc.tm_mon = (int) ((dta_str.time >> 21) & 0x0f) - 1;
			tmstruc.tm_mday = (int) (dta_str.time >> 16) & 0x1f;

			tmstruc.tm_hour = (int) (dta_str.time >> 11) & 0x1f;
			tmstruc.tm_min = (int) (dta_str.time >> 5) & 0x3f;
			tmstruc.tm_sec = (int) dta_str.time & 0x1f;

			curr_time = mktime (&tmstruc);
			p1->oldest = min ((unsigned long)curr_time, p1->oldest);
		}

		if (dta_str.name[9] != 'H')
			p1->callsize += sztemp;
	}

	switch (dta_str.name[9])
	{
	case 'C':					/* Crash */
		p1->mailtypes |= MAIL_CRASH;
		break;

	case 'H':					/* Hold */
		p1->mailtypes |= MAIL_HOLD;
		break;

	case 'F':					/* Normal */
	case 'O':
		p1->mailtypes |= MAIL_NORMAL;
		break;

	case 'D':					/* Direct */
		p1->mailtypes |= MAIL_DIRECT;
		break;

	case 'R':					/* Request */
		p1->mailtypes |= MAIL_REQUEST;
		break;
	}

	if (!nodefind (&(p1->mail_addr), 0))
	{
		p1->mailtypes |= MAIL_UNKNOWN;
		return (rettype);
	}

	/* Don't call for "HOLD" or "REQ" stuff. */

	if ((dta_str.name[9] == 'H') || (dta_str.name[9] == 'R'))
	{
		return (rettype);
	}

	/* if modem type is undialable, don't call */	/* MB 93-11-27 */

	m = mm_head;
	while (m != NULL)
	{
		if (m->mdm == newnodedes.ModemType)
		{
			if (!(*(m->pre) || *(m->suf)))
				return (rettype);
			else
				break;
		}
		m = m->next;
	}

	/* If there's no event, set mail to 'go' */

	if (cur_event < 0)
	{
		p1->mailtypes &= ~MAIL_QSMALL;
		p1->mailtypes |= MAIL_WILLGO;
		return (rettype);
	}

	/* If it is a crash only event and we have crashmail, set it to go */

	if (e_ptrs[cur_event].behavior & MAT_HIPRICM)
	{
		if ((dta_str.name[9] == 'C') && (newnodedes.NodeFlags & B_CM))
		{
			p1->mailtypes &= ~MAIL_QSMALL;
			p1->mailtypes |= MAIL_WILLGO;
			return (rettype);
		}
	}

	/* If it is a crash only event and this wasn't crash, return */

	if ((dta_str.name[9] != 'C') && (e_ptrs[cur_event].behavior & MAT_CM))
	{
		return (rettype);
	}

	/* Is this a local only event? */

	if (e_ptrs[cur_event].behavior & MAT_LOCAL)
	{
		/*
		 * If this is supposed to be only local, then get out if it isn't
		 */

		if (e_ptrs[cur_event].node_cost >= 0)
		{
			if ((int) newnodedes.RealCost > e_ptrs[cur_event].node_cost)
			{
				return (rettype);
			}
		}
		else
		{
			if ((int) newnodedes.RealCost < -(e_ptrs[cur_event].node_cost))
			{
				return (rettype);
			}
		}
	}

	/* Is this a non-mail window event? */

	if ((newnodelist || version7) &&
		(!(e_ptrs[cur_event].behavior & MAT_NOMAIL24)))
	{
		/* If this guy can't handle crash, get out and try again */

		if (!(newnodedes.NodeFlags & B_CM))
		{
			return (rettype);
		}
	}

	/* Is this a receive only event? */

	if (e_ptrs[cur_event].behavior & MAT_NOOUT)
	{
		return (rettype);
	}

	/* Is this a non-CM event? */

	if ((newnodelist || version7) &&
		(e_ptrs[cur_event].behavior & MAT_NOCM) &&
		(newnodedes.NodeFlags & B_CM))
	{
		return (rettype);
	}

	/* See if we spent too much calling him already */

	if (bad_call (&(p1->mail_addr), 0))
	{
		p1->mailtypes |= MAIL_TOOBAD;
		return (rettype);
	}

	/* See if we have enough mail to send */

	if (!no_size && e_ptrs[cur_event].mailqsize > p1->callsize)
	{
		p1->mailtypes |= MAIL_QSMALL;
		return (rettype);
	}

	p1->mailtypes &= ~MAIL_QSMALL;
	p1->mailtypes |= MAIL_WILLGO;

	return (rettype);
}

static char LOCALFUNC 
mail_stat (MAILP p)
{
	if (p->mailtypes & MAIL_UNKNOWN)
		return ('!');
	if (p->mailtypes & MAIL_TOOBAD)
		return ('x');
	if (p->mailtypes & MAIL_TRIED)
		return ('#');
	if (p->mailtypes & MAIL_WILLGO)
		return ('*');
	if (p->mailtypes & MAIL_QSMALL)
		return ('<');
	return ('-');
}

char msc[10];

char *
mail_status_chars (unsigned int p)
{
	char *q;

	q = msc;

	if (p & MAIL_CRASH)
		*q++ = 'C';
	if (p & MAIL_HOLD)
		*q++ = 'H';
	if (p & MAIL_DIRECT)
		*q++ = 'D';
	if (p & MAIL_NORMAL)
		*q++ = 'N';
	if (p & MAIL_REQUEST)
		*q++ = 'R';
	*q++ = '\0';

	return (msc);
}

void 
xmit_window (MAILP p1)
{
	MAILP p;
	short i;
	char j1[32];
	char *jPtr;

	if (!fullscreen)
		return;

	p = p1;

	sb_fillc (holdwin, ' ');
	jPtr = j1;

	if (p == NULL)
	{
		sb_move (holdwin, 3, 5);
		sb_puts (holdwin, MSG_TXT (M_NOTHING_IN_OUTBOUND));
		return;
	}

	strcpy (j1, MSG_TXT (M_OUTBOUND_HEADER));
	sb_move (holdwin, 1, 2);
	sb_puts (holdwin, jPtr);
	for (i = 2; i < SB_ROW_HOLD; i++)
	{
		if (p == NULL)
			break;

		do_xmit_line (j1, p);

		sb_move (holdwin, i, 2);
		sb_puts (holdwin, jPtr);
		p = p->next;
	}
	sb_show ();
}

static void LOCALFUNC 
do_xmit_line (char *line, MAILP p)
{
	ADDR addrT;

	if (no_size)
	{
		(void) sprintf (line, HoldNoSize,
			Full_Addr_Str (&(p->mail_addr)),
			mail_status_chars (p->mailtypes),
			mail_stat (p));
	}
	else
	{
		addrT = p->mail_addr;
		addrT.Domain = NULL;
		(void) sprintf (line, HoldFmtStr,
			Full_Addr_Str (&addrT),
			(p->numfiles > 999 ? 999 : p->numfiles),
			numdisp (p->mailsize),
			mail_status_chars (p->mailtypes),
			mail_stat (p));
	}
}

static void LOCALFUNC 
xmit_sort ()
{
	MAILP p, p1, p2;

	p = mail_top;

	/* Find the first that is sendable */

	while (p != NULL)
	{
		if ((p->mailtypes & MAIL_WILLGO) &&
			(!(p->mailtypes & MAIL_TOOBAD)) &&
			(!(p->mailtypes & MAIL_UNKNOWN)))
			break;
		p = p->next;
	}

	if (p == NULL)
		return;

	/* Put the first sendable one on top */

	if (p != mail_top)
	{
		p->prev->next = p->next;
		if (p->next != NULL)
			p->next->prev = p->prev;
		p->prev = NULL;
		p->next = mail_top;
		mail_top->prev = p;
		mail_top = p;
	}

	p1 = p;
	p = p1->next;
	while (p != NULL)
	{
		if ((p->mailtypes & MAIL_WILLGO) &&
			(!(p->mailtypes & MAIL_TOOBAD)) &&
			(!(p->mailtypes & MAIL_UNKNOWN)))
		{
			if (p->prev == p1)
			{
				p1 = p;
				p = p->next;
				continue;
			}
			p2 = p->next;
			p->prev->next = p->next;
			if (p->next != NULL)
				p->next->prev = p->prev;
			p->next = p1->next;
			if (p1->next != NULL)
				p1->next->prev = p;
			p->prev = p1;
			p1->next = p;
			p1 = p;
			p = p2;
		}
		else
		{
			p = p->next;
		}
	}
}

void 
xmit_reset (int display)
{
	MAILP p;
	int j, k, zone;
	char *q, *s;
	char *domain;
	char *HoldName;
	char pointspec[128];
	ADDR tmp;
	struct FILEINFO zone_dir =
	{0};
	struct FILEINFO pnt_dir =
	{0};
	long longzone;

	/* First get rid of all the old junk */

	p = mail_top;
	if (p != NULL)
	{
		while (p->next != NULL)
			p = p->next;
		while (p->prev != NULL)
		{
			p = p->prev;
			free (p->next);
		}
		if (p != NULL)
			free (p);
	}

	p = mail_top = NULL;

/*
 * Initialize domain to scan. Choose (of course) the
 * domain of our primary address.
 *
 * This domain is special in that its outbound is hold_area.
 * All the other domains use their abbreviation as the name
 * of their outbounds.
 */

	k = 0;
	domain = domain_name[0];
	(void) strcpy (pointspec, hold_area);
	q = &(pointspec[strlen (pointspec)]) - 1;
	do
	{

/*
 * Initialize scan of zones in this domain. Using findfirst/findnext,
 * get all the matching directories.
 */
		(void) strcpy (q, ".*");
		j = 0;
		while (!dfind (&zone_dir, pointspec, j))
		{
			j = 1;				/* Flip findfirst/findnext to findnext */

/*
 * We have a match on the outbound spec. Make sure it's a directory.
 *
 * Then:
 *
 *       1) If no extension, we may only use it if this is alias 0
 *       2) If an extension, it must be a 3-digit hex number
 *
 * If the extension passes one of these tests, get to work!
 */
			if (!(zone_dir.attr & FA_SUBDIR))
				continue;

			q = strchr (zone_dir.name, '.');
			if (q == NULL)
			{
				if (k != 0 && !no_zones)
					continue;
				zone = (int) alias[0].Zone;
			}
			else
			{
				if (no_zones)
					continue;
				s = ++q;
				longzone = strtol (q, &q, 16);
				if ((s + 3) != q)
					continue;
				zone = (int) longzone;
/*
 * To avoid duplicating the primary scan,
 * make sure that this isn't "domainname[0].zone[0]".
 */
				if (!k && zone == (int) alias[0].Zone)
					continue;
			}
/*
 * OK. We have a domain, an outbound directory, and a zone.
 * That means there's an outbound to scan.
 *
 * Start by scanning the nodes.
 */
			tmp.Zone = zone;
			tmp.Domain = domain;
			tmp.Net = tmp.Node = tmp.Point = 0;
			p = xmit_find (p, &tmp);
/*
 * Now we do the points contained in this outbound.
 *
 */
			if (pvtnet <= 0)
			{
				int f = 0;

				HoldName = HoldAreaNameMunge (&tmp);
				(void) sprintf (pointspec, "%s*.PNT", HoldName);

				while (!dfind (&pnt_dir, pointspec, f))
				{
					f = 1;
					if (sscanf (pnt_dir.name, "%04hx%04hx.", &(tmp.Net), &(tmp.Node)) != 2)
						continue;
					tmp.Point = 1;
					p = xmit_find (p, &tmp);
				}				/* got one */
				if (f)
					(void) dfind (&pnt_dir, NULL, 2);
			}
		}						/* while !dfind (...) to get outbounds */
		if (j)
			(void) dfind (&zone_dir, NULL, 2);
/*
 * See if there are any more domains. If so, set up the right name
 * for the outbound, so we can find 'em.
 */
		if ((domain = domain_name[++k]) != NULL)
		{
			*domain_loc = '\0';
			(void) strcpy (pointspec, domain_area);
			q = &(pointspec[strlen (pointspec)]);
			s = domain_abbrev[k];
			if (s != NULL)
				while (*s)
					*q++ = *s++;
		}
	}
	while (domain != NULL);
	next_mail = NULL;
	xmit_sort ();
	if (display)
		xmit_window (mail_top);
	next_rescan = (long) time (NULL) + 600L;	/* At least 10 min to next scan */
}

static MAILP LOCALFUNC 
xmit_find (MAILP p, ADDRP address)
{
	int j;
	char next_one[127];
	char *HoldName;
	ADDR tmp;

	tmp = *address;

	HoldName = HoldAreaNameMunge (address);

	if (address->Point != 0)
	{
		(void) sprintf (next_one, "%s%04hx%04hx.PNT\\*.*",
			HoldName, address->Net, address->Node);
		tmp.Point = 0;
	}
	else
	{
		(void) sprintf (next_one, "%s*.*", HoldName);
		tmp.Net = 0;
		tmp.Node = 0;
		tmp.Point = 0;
	}

	j = 0;

	while (!dfind (&dta_str, next_one, j))
	{
		j = 1;

		/* We have a match. Was it a .FLO file or a .OUT file? */

		if (strncmp (&(dta_str.name[10]), "LO", 2) == 0)
		{
			/* FLO, DLO, CLO and HLO are the only ones! */

			if (strchr ("FDCH", dta_str.name[9]) == NULL)
				continue;
		}
		else if (strncmp (&(dta_str.name[10]), "UT", 2) == 0)
		{
			/* OUT, DUT, CUT and HUT are the only ones! */

			if (strchr ("ODCH", dta_str.name[9]) == NULL)
				continue;
		}
		else if (strncmp (&(dta_str.name[9]), "REQ", 3) != 0)
			continue;

		/* We found a name, remember it */

		if (address->Point != 0)
		{
			if (sscanf (dta_str.name, "%08hx.", &(tmp.Point)) != 1)
				continue;
		}
		else if (sscanf (dta_str.name, "%04hx%04hx.", &(tmp.Net), &(tmp.Node)) != 2)
			continue;

		if (p == NULL)
		{
			p = mail_top = (MAILP) calloc (sizeof (MAIL), 1);
		}
		else
		{
			p->next = (MAILP) calloc (sizeof (MAIL), 1);
			p->next->prev = p;
			p = p->next;
		}

		if (xmit_install (p, &tmp))
		{
			/* No good */

			if (p->prev != NULL)
			{
				p = p->prev;
				free (p->next);
				p->next = NULL;
			}
			else
			{
				free (p);
				p = mail_top = NULL;
			}
		}

	}							/* while (!done) */
	if (j)
		(void) dfind (&dta_str, NULL, 2);
	return (p);
}

int 
xmit_next (ADDRP xaddr)
{
	int i, j;

	for (i = 0; i < 2; i++)
	{
		/* Set up the proper pointer */

		if ((next_mail == NULL) || (next_mail->next == NULL))
		{
			if (next_rescan < (long) time (NULL))
				xmit_reset (1);
			next_mail = mail_top;
		}
		else
		{
			next_mail = next_mail->next;
		}

		/* Loop through till we find something we can send */

		while (next_mail != NULL)
		{
			if ((next_mail->mailtypes & MAIL_WILLGO) &&
				(!(next_mail->mailtypes & MAIL_UNKNOWN)) &&
				(!(next_mail->mailtypes & MAIL_TOOBAD)))
			{
				if (bad_call (&(next_mail->mail_addr), 0))
				{
					next_mail->mailtypes |= MAIL_TOOBAD;
				}
				else
				{
					/* If multitasking, check for mail before calling */

					if ((TaskNumber != 0) && ((j = any_mail (next_mail)) <= 0))
					{
						if (j == 0)
							xmit_delete ();
						else
							next_mail = next_mail->next;
						continue;
					}
					*xaddr = next_mail->mail_addr;
					xmit_window (next_mail);
					return (1);
				}
			}
			next_mail = next_mail->next;
		}
	}

	/* Oh well, we tried */

	xmit_window (mail_top);
	return (0);
}

static void LOCALFUNC
xmit_delete_one ()
{
	MAILP p;

	if (any_mail (next_mail) != 0)
	{
		status_line (MSG_TXT (M_STILL_HAVE_MAIL), Full_Addr_Str (&(next_mail->mail_addr)));

		/* We still have something for him */

		next_mail->mailtypes &= ~MAIL_WILLGO;
		next_mail->mailtypes |= MAIL_TRIED;
		return;
	}

	if (next_mail != mail_top)
	{
		p = next_mail->next;
		next_mail = next_mail->prev;
		free (next_mail->next);
		next_mail->next = p;
		if (p != NULL)
			p->prev = next_mail;
	}
	else
	{
		mail_top = mail_top->next;
		free (next_mail);
		if (mail_top != NULL)
			mail_top->prev = NULL;
		next_mail = NULL;
	}
}

void
xmit_delete ()
{
	int i;

	if (next_mail == NULL && no_EMSI_Session)
		return;

	if (no_EMSI_Session)
	{
		xmit_delete_one ();
	}
	else
	{
		for (i = (num_rakas - 1); i >= 0; i--)
		{
			next_mail = find_mail (&remote_akas[i]);
			if (next_mail != NULL)
				xmit_delete_one ();
		}
	}

	xmit_window (mail_top);
	no_EMSI_Session = TRUE;
	num_rakas = 0;
}

int 
bad_call (ADDRP baddr, int rwd)
{
	int res;
	int i, j;
	struct FILEINFO bad_dta = {0};
	FILE *bad_wazoo;
	char *p;
	char *HoldName;

	char fname[128];
	char fname1[128];

	HoldName = HoldAreaNameMunge (baddr);
	(void) sprintf (fname, "%s%s.$$?", HoldName, Hex_Addr_Str (baddr));
	j = (int) strlen (fname) - 1;			/* Point at ?          */
	res = -1;								/* Initialize to fail  */

	i = 0;									/* This says findfirst */
	while (!dfind (&bad_dta, fname, i))		/* as long as we match */
	{
		if (isdigit (bad_dta.name[11]))		/* is there a digit?   */
		{
			fname[j] = bad_dta.name[11];	/* Yes, copy to fname  */
			res = fname[j] - '0';			/* Save it for testing */
			break;							/* Get out of while    */
		}
		else
			i = 1;							/* Else use findnext   */
	}
	if (i)
		(void) dfind (&bad_dta, NULL, 2);

	if (res == -1)							/* Successful search?  */
	{
		fname[j] = '0';						/* No, base digit = 0  */
	}

	if (rwd > 0)
	{
		/* Writing a bad call  */

		/* First create a filename that is one higher than what we've got */

		(void) strcpy (fname1, fname);
		fname1[j]++;
		if (fname1[j] > '9')
			fname1[j] = '9';

		if (res == -1)						/* Did we have a file? */
		{									/* No, make one.       */
			if (rwd == 2)					/* No carrier */
				res = open (fname, O_CREAT | O_WRONLY | O_BINARY, S_IREAD | S_IWRITE);
			else							/* With carrier */
				res = open (fname1, O_CREAT | O_WRONLY | O_BINARY, S_IREAD | S_IWRITE);
			i = rwd - 1;					/* zero-based count    */
			(void) write (res, (char *) &i, sizeof (int));
			(void) close (res);				/* close the file      */
		}
		else
		{									/* There was a file    */

			/*
			 * 2 = Unsuccessful, No carrier. Update contents of the file.
			 */

			if (rwd == 2)
			{
				i = open (fname, O_RDONLY | O_BINARY);
				(void) read (i, (char *) &res, sizeof (int));
				(void) close (i);
				++res;
				i = open (fname, O_CREAT | O_WRONLY | O_BINARY, S_IREAD | S_IWRITE);
				(void) write (i, (char *) &res, sizeof (int));
				(void) close (i);
			}

			/*
			 * 1 = Unsuccessful, Carrier. Update file name to reflect the
			 * failure.
			 */

			else
				(void) rename (fname, fname1);
		}
	}
	else if (rwd == 0)
	{
		/*
		 * 0 = We are reading a bad call status
		 */

		/* Is it automatically ok (no .$$ file there) ? */

		if (res == -1)
			return (0);

		/* Were there too many connects with carrier? */

		if (res >= max_connects)
			return (1);

		/* Ok, check for connects without carrier */

		res = 0;
		i = open (fname, O_RDONLY | O_BINARY);
		(void) read (i, (char *) &res, sizeof (int));
		(void) close (i);
		return (res >= max_noconnects);
	}
	else
	{
		/*
		 * -1 = Cleanup of bad call status. This happens in two steps:
		 * a) delete 'netnode.$$?' in hold area;
		 * b) if a 'netnode.Z' file exists in hold area,
		 *    1) delete all BADWAZOO.xxx files listed in the .Z file;
		 *    2) delete the 'netnode.z' file.
		 */

		if (res != -1)
			(void) unlink (fname);

		if (!mail_finished)
			return (0);

		(void) sprintf (fname, "%s%s.Z", HoldName, Hex_Addr_Str (baddr));
		if (dexists (fname))
		{
			if ((bad_wazoo = fopen (fname, read_ascii)) == NULL)
				(void) got_error (MSG_TXT (M_OPEN_MSG), fname);
			else
			{
				while (!feof (bad_wazoo))
				{
					e_input[0] = '\0';
					if (!fgets (e_input, 64, bad_wazoo))
						break;

					/* Point to BADWAZOO.xxx */

					p = strchr (e_input, ' ') + 1;

					/* Then just past it and terminate */

					p = strchr (p, ' ');
					*p = '\0';

					/* Back to where we were */

					p = strchr (e_input, ' ') + 1;

					/* Build file name and delete file */

					(void) strcpy (fname1, CURRENT.sc_Inbound);
					(void) strcat (fname1, p);
					(void) unlink (fname1);
				}
				(void) fclose (bad_wazoo);
			}
			(void) unlink (fname);
		}
	}
	return (0);
}

void 
set_up_outbound ()
{
	MAILP mp;

	xmit_reset (1);

	/* and remember where we left off */

	if (hist.next_addr.Net != 0)
	{
		next_addr = hist.next_addr;
		next_addr.Domain = NULL;
		mp = find_mail (&next_addr);
		if ((mp == NULL) || (mp->prev == NULL))
		{
			next_mail = NULL;
			xmit_window (mail_top);
		}
		else
		{
			next_mail = mp->prev;
			xmit_window (next_mail);
		}
	}
	else
	{
		next_addr.Zone = 0;
		next_addr.Net = 0;
		next_addr.Node = 0;
		next_addr.Point = 0;
		next_addr.Domain = NULL;
		xmit_window (mail_top);
	}
}

void 
kill_bad (void)
{
	int j, k, zone;
	char *q, *s;
	char *domain;
	char *HoldName;
	char pointspec[255];
	ADDR tmp;
	struct FILEINFO zone_dir = {0};
	struct FILEINFO pnt_dir =  {0};
	long longzone;
/*
 * Initialize domain to scan. Choose (of course) the
 * domain of our primary address.
 *
 * This domain is special in that its outbound is hold_area.
 * All the other domains use their abbreviation as the name
 * of their outbounds.
 */
	k = 0;
	domain = domain_name[0];
	(void) strcpy (pointspec, hold_area);
	q = &(pointspec[strlen (pointspec)]) - 1;
	do
	{
/*
 * Initialize scan of zones in this domain. Using findfirst/findnext,
 * get all the matching directories.
 */
		(void) strcpy (q, ".*");
		j = 0;
		while (!dfind (&zone_dir, pointspec, j))
		{
			j = 1;				/* Flip findfirst/findnext to findnext */
/*
 * We have a match on the outbound spec. Make sure it's a directory.
 *
 * Then:
 *
 *       1) If no extension, we may only use it if this is alias 0
 *       2) If an extension, it must be a 3-digit hex number
 *
 * If the extension passes one of these tests, get to work!
 */
			if (!(zone_dir.attr & FA_SUBDIR))
				continue;

			q = strchr (zone_dir.name, '.');
			if (q == NULL)
			{
				if (k != 0 && !no_zones)
					continue;
				zone = (int) alias[0].Zone;
			}
			else
			{
				if (no_zones)
					continue;
				s = ++q;
				longzone = strtol (q, &q, 16);
				if ((s + 3) != q)
					continue;
				zone = (int) longzone;
/*
 * To avoid duplicating the primary scan,
 * make sure that this isn't "domainname[0].zone[0]".
 */
				if (!k && zone == (int) alias[0].Zone)
					continue;
			}
/*
 * OK. We have a domain, an outbound directory, and a zone.
 * That means there's an outbound to scan.
 *
 * Start by scanning the nodes.
 */
			tmp.Zone = zone;
			tmp.Domain = domain;
			tmp.Net = tmp.Node = tmp.Point = 0;
			kill_one (&tmp);
/*
 * Now we do the points contained in this outbound.
 *
 */
			if (pvtnet <= 0)
			{
				int f = 0;

				HoldName = HoldAreaNameMunge (&tmp);
				(void) sprintf (pointspec, "%s*.PNT", HoldName);

				while (!dfind (&pnt_dir, pointspec, f))
				{
					f = 1;
					if (sscanf (pnt_dir.name, "%04hx%04hx.", &(tmp.Net), &(tmp.Node)) != 2)
						continue;
					tmp.Point = 1;
					kill_one (&tmp);
				}				/* got one */

				if (f)
					(void) dfind (&pnt_dir, NULL, 2);
			}
		}						/* while !dfind (...) to get outbounds */
		if (j)
			(void) dfind (&zone_dir, NULL, 2);
/*
 * See if there are any more domains. If so, set up the right name
 * for the outbound, so we can find 'em.
 */
		if ((domain = domain_name[++k]) != NULL)
		{
			*domain_loc = '\0';
			(void) strcpy (pointspec, domain_area);
			q = &(pointspec[strlen (pointspec)]);
			s = domain_abbrev[k];
			if (s != NULL)
				while (*s)
					*q++ = *s++;
		}
	}
	while (domain != NULL);
}

static void LOCALFUNC 
kill_one (ADDRP address)
{
	int j;
	char next_one[255];
	char thisfile[255];
	char *HoldName;
	char *p;

	HoldName = HoldAreaNameMunge (address);

	if (address->Point != 0)
	{
		(void) sprintf (next_one, "%s%04hx%04hx.PNT\\*.$$?",
			HoldName, address->Net, address->Node);
	}
	else
	{
		(void) sprintf (next_one, "%s*.$$?", HoldName);
	}

	j = 0;
	strcpy (thisfile, next_one);
	p = strrchr (thisfile, '*');

	while (!dfind (&dta_str, next_one, j))
	{
		j = 1;

		strcpy (p, dta_str.name);
		status_line (">Deleting %s", thisfile);
		unlink (thisfile);

	}							/* while (!done) */

	if (j)
		(void) dfind (&dta_str, NULL, 2);
}

/*
 * Calculate size of mail queued for outbound.
 * Used to determine whether or not we have enough
 * mail to merit an outbound call.
 *
 * The original version of this code was donated by Henry Clark.
 */

static long LOCALFUNC 
netsize (MAILP p)
{
	struct stat stbuf;
	char net_path[127];
	char *ptr;
	FILE *temp;
	long accum = 0L;
	char *q;

	/* Append the ARCmail file name to the path line  */

	(void) sprintf (net_path, "%s%s.%s",
		HoldAreaNameMunge (&(p->mail_addr)),
		Hex_Addr_Str (&(p->mail_addr)),
		&dta_str.name[9]);

	temp = share_fopen (net_path, read_binary, DENY_NONE);

	if (temp == (FILE *) NULL)
		return (accum);

	while (!feof (temp))
	{
/*
 *      Make sure of a nice zero there if we're at an undetected EOF.
 *      Then try to read a line from the file.
 */
		net_path[0] = '\0';
		(void) fgets (net_path, 79, temp);
/*
 *      Clean up anything we don't want to see (blanks, tabs, CR, etc)
 */
		for (q = ptr = net_path; *q; q++)
			if (*q <= ' ')
				*q = '\0';
/*
 *      File disposition commands should be skipped over to get to
 *      actual filenames.
 */
		if ((*ptr == TRUNC_AFTER) ||
			(*ptr == DELETE_AFTER) ||
			(*ptr == SHOW_DELETE_AFTER) ||
			(*ptr == NOTHING_AFTER))
			ptr++;
/*
 *      Now -- if what's left starts with a semicolon, it's a comment.
 *      If it starts with a tilde, the file has already been sent. If
 *      what we see is a zero, there's nothing on the line. In any one
 *      of these cases, we should skip this line.
 */
		if ((*ptr == '\0') ||
			(*ptr == ';') ||
			(*ptr == '~'))
			continue;
/*
 *      Get the file size by doing a stat call. If it's not there
 *      then we obviously need not add any size in. If the file is
 *		arcmail, figure it into the "oldest" calculation.
 */
		if (stat (ptr, &stbuf))	/* file exist? */
			continue;
		else
		{
			p->numfiles++;
			accum += stbuf.st_size;
			if (is_arcmail (ptr, 1 - strlen (ptr)))
				p->oldest = min ((unsigned long)stbuf.st_ctime, p->oldest);
		}
	}
	(void) fclose (temp);
	return (accum);
}

/*
 * Figure out if there's any mail for the specified node.
 * Used to determine if we need to actually make a call.
 *
 * Returns 0 for no mail at all
 *         1 for non-hold mail
 *        -1 for hold mail only
 *
 * I can't remember who was the first to demand this. I've been
 * pummelled for a while and there's almost certainly been a loss
 * of grey matter.
 */

static int LOCALFUNC 
any_mail (MAILP node)
{
	struct FILEINFO dta = {0};
	char next_one[127];
	int ret = 0;
	int j = 0;

	(void) sprintf (next_one, "%s%s.*",
		HoldAreaNameMunge (&(node->mail_addr)),
		Hex_Addr_Str (&(node->mail_addr)));

	while (!dfind (&dta, next_one, j))
	{
		j = 1;

#ifndef JACK_DECKER
		if (dta.name[9] == 'H')
		{
			ret = -1;
			continue;
		}
#endif
		if ((!strncmp (&(dta.name[10]), "LO", 2)) ||
			(!strncmp (&(dta.name[10]), "UT", 2)))
		{
			ret = 1;
			break;
		}
	}
	if (j)
		(void) dfind (&dta, NULL, 2);
	return (ret);
}

[ RETURN TO DIRECTORY ]