/*--------------------------------------------------------------------------*/ /* */ /* */ /* ------------ Bit-Bucket Software, Co. */ /* \ 10001101 / Writers and Distributors of */ /* \ 011110 / Freely Available 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); }