/*--------------------------------------------------------------------------*/ /* */ /* */ /* ------------ 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 int LOCALFUNC poll_node (ADDRP); static int LOCALFUNC call_node (ADDRP, int); static void LOCALFUNC bbs_reader (void); int unattended () { int no_inbound = 0; short j; int m; long init_timer, t = -1L, t1; /* used for the timeouts */ long blank_timer; struct _key_fnc_hdr *OldKeyFncHdr; int done = 1; /* if we exit with this, get out of BT */ HFILE stream; char *p; unsigned long got; MAILP pmailT; un_attended = 1; comm_bits = BITS_8; parity = NO_PARITY; stop_bits = STOP_1; program_baud (); OldKeyFncHdr = KbMapSet (&UnattendedKeyFncHdr); if (fullscreen) { screen_clear (); sb_fillc (callwin, ' '); sb_dirty (); mailer_banner (); } else opening_banner (); if ((stream = (HFILE) share_open (PRDCT_PRFX ".BAN", O_RDONLY | O_BINARY, DENY_WRITE)) != (HFILE) - 1) { /* Note, we do not use "got". Some platforms want it to be a long and some want it to be a int. We don't care, so we make it a long (see above) so there's enough room, then use a void * so the compiler won't complain about an argument we don't even want */ (void) _dos_read (stream, BBSwelcome, WELCOME_LEN, (void *)&got); (void) close (stream); } else { BBSwelcome[0] = '\0'; } #ifdef BINKLEY_SOUNDS Make_Sound (fnStartSound); #endif /* Initialize the random number generator */ j = (int) time (NULL); srand ((unsigned int) j); status_line (MSG_TXT (M_BINK_BEGIN), ANNOUNCE, COMPILER_NAME); set_xy (""); set_prior (4); /* Always High */ XON_DISABLE (); set_prior (2); /* Regular */ /* See if someone has set the forced-exit semaphore */ forcexitcheck (); /* Turn off forced events */ if (noforce) { find_event (); noforce = 0; } if (redo_dynam) { for (j = 0; j < num_events; j++) { e_ptrs[j].behavior &= ~MAT_SKIP; } redo_dynam = 0; } /* * See if we should exit before initializing the modem (and therefore * possibly letting a call sneak through) */ find_event (); do_ready (MSG_TXT (M_READY_INIT)); /* Make sure we have all necessary parameters and that the nodelist * index gets read in. If not, then we must exit right now. */ if (!net_params || !nodefind (&boss_addr, 0)) if (boss_addr.Net != 0xffff) { status_line (MSG_TXT (M_MISCONFIGURED)); errl_exit (254); } /* Set up outbound mail */ list_next_event (); set_up_outbound (); if (!CARRIER) { mdm_init (modem_init); /* Reinit modem */ } blank_timer = timerset ((unsigned int) blank_time); /* Set a timer */ init_timer = timerset ((unsigned int) 60000); /* Set a 10 minute timer */ t1 = timerset ((unsigned) next_minute ()); /* Set a 1 minute timer */ waitfor_line = timerset ((unsigned int) 6000); /* no collisions for 1 min*/ top_of_mail: un_attended = 1; no_inbound = 0; m = 1; /* As long as we don't press a key */ bad_char: more_mail = 1; while (!(KEYPRESS () || ctrlc_ctr)) { /* Check for forced exit semaphore */ forcexitcheck (); /* See if we need to move into the next event */ find_event (); /* Show that we are ready */ if (m) { if (fullscreen) { do_ready (MSG_TXT (M_READY_WAITING)); list_next_event (); } else status_line (MSG_TXT (M_EVENT_WAITING), cur_event + 1); blank_timer = timerset ((unsigned int) blank_time); /* Set a timer */ init_timer = timerset ((unsigned int) 60000); /* Set a 10 min timer */ t1 = timerset ((unsigned) next_minute ()); /* Set a 1 min timer */ } if (timeup (t1)) { put_up_time (); list_next_event (); t1 = timerset ((unsigned) next_minute ()); /* Set a 1 min timer */ } /* See if blanking interval has elapsed */ if (timeup (blank_timer)) { blank_timer = timerset ((unsigned int) blank_time); screen_blank = 1; if (fullscreen) sb_show (); } /* If we haven't gotten anything in 10 minutes, re-init the modem */ if (timeup (init_timer)) { mdm_init (modem_init); init_timer = timerset ((unsigned int) 60000); /* Set a 10 minute timer */ /* * Say that we have more mail so that things entered through other * side of a multi-tasker will still go out */ set_up_outbound (); more_mail = 1; } m = 0; if (cur_event >= 0) no_inbound = (e_ptrs[cur_event].behavior & MAT_OUTONLY); else no_inbound = 1; if (t != -1L) t = random_time ((cur_event >= 0) ? e_ptrs[cur_event].wait_time : 5); else t = timerset (1000); /* variable 'no_inbound' will be TRUE if we are manually dialing out * or if we are in an event where we do not want incoming stuff. */ while ((!timeup (t)) && (!KEYPRESS ()) && !ctrlc_ctr) { forcexitcheck (); if (forcerescancheck ()) { set_up_outbound (); more_mail = 1; goto immed_call; } find_event (); time_release (); if (timeup (t1)) { put_up_time (); list_next_event (); t1 = timerset ((unsigned) next_minute ()); /* Set a 1 min timer*/ } /* If we want inbound, see if there is any. If we send anything, clean up afterwards ... */ if (!no_inbound) { long lstart = timerset (0); m = handle_inbound_mail (0); if (m) { xmit_sameplace (); if (fullscreen) { do_ready (MSG_TXT (M_READY_WAITING)); list_next_event (); } m = 0; } /* Correct dialout by amount of time we spent handling the inbound traffic */ t += (timerset (0) - lstart); } } immed_call: forcexitcheck (); find_event (); /* If we have pressed a key, get out */ if (KEYPRESS () || ctrlc_ctr) break; /* If we are not in an event, or if this is a no-outbound event, loop again */ if ((cur_event < 0) || (e_ptrs[cur_event].behavior & MAT_NOOUT)) { time_release (); continue; } if (more_mail) more_mail = xmit_next (&next_addr); if (more_mail) m = call_node (&next_addr, no_inbound); else { /* No more mail to do, was it dynamic? */ if (e_ptrs[cur_event].behavior & MAT_DYNAM) { if (!blank_on_key) screen_blank = 0; e_ptrs[cur_event].behavior |= MAT_SKIP; status_line (":%s %s %d", MSG_TXT (M_END_OF), MSG_TXT (M_DYNAMIC_EVENT), cur_event + 1); t = -1L; goto top_of_mail; } } } screen_blank = 0; if (fullscreen) sb_show (); /* Eat the character we pressed */ if (ctrlc_ctr || !KEYPRESS ()) { /* * Be serious, there had to be a key pressed or we wouldn't be here I * know it sounds silly, but ^C will sometimes do crap like this */ status_line (MSG_TXT (M_EXIT_REQUEST)); } else { blank_timer = timerset ((unsigned int) blank_time); /* Set a timer */ j = (short) KbRemap (FOSSIL_CHAR ()); if (((unsigned short) j & F_UN_BSE) == F_UN_BSE) switch ((unsigned short) j) { case F_UN_FUNKEY1: case F_UN_FUNKEY2: case F_UN_FUNKEY3: case F_UN_FUNKEY4: case F_UN_FUNKEY5: case F_UN_FUNKEY6: case F_UN_FUNKEY7: case F_UN_FUNKEY8: case F_UN_FUNKEY9: case F_UN_FUNKEY10: j = 1 + (short) ((unsigned short) j - (unsigned short) F_UN_FUNKEY1); status_line (MSG_TXT (M_FUNCTION_KEY), j * 10); errl_exit (j * 10); break; case F_UN_BLANKSCREEN: screen_blank = 1; if (fullscreen) sb_show (); break; case F_UN_CLEARHIST: j = hist.which_day; (void) memset (&hist, 0, sizeof (HISTORY)); start_hist = hist; hist.which_day = j; if (fullscreen) { do_today (); sb_show (); } break; case F_UN_MSGEDITOR: bbs_reader (); m = 1; break; case F_UN_GETFILE: j = sb_popup (10, 5, 7, 70, Do_Get, 0); if (j < 0) { status_line (MSG_TXT (M_NO_GET)); } else if (j > 0) { set_up_outbound (); m = 1; more_mail = 1; } break; case F_UN_REINITMODEM: /* The idea for this code came from Holger Schurig */ mdm_hangup (); set_up_outbound (); m = 1; more_mail = 1; break; case F_UN_SHELL: status_line (MSG_TXT (M_SHELLING)); if (fullscreen) gotoxy (0, SB_ROWS); vfossil_cursor (1); (void) cputs (MSG_TXT (M_TYPE_EXIT)); LOWER_DTR (); change_prompt (); b_spawn (NULL); if (fullscreen) { screen_clear (); sb_dirty (); opening_banner (); mailer_banner (); } status_line (MSG_TXT (M_BINKLEY_BACK)); m = 1; set_up_outbound (); set_prior (4); /* Always High */ RAISE_DTR (); set_prior (2); /* Regular */ break; case F_UN_KILLNODESMAIL: if (sb_popup (10, 5, 4, 70, Do_Kill, 0)) { status_line (MSG_TXT (M_NO_KILL)); } else { set_up_outbound (); m = 1; more_mail = 1; } break; case F_UN_POLLBOSS: (void) poll_node (&boss_addr); m = 1; break; case F_UN_ANSWER: if (ans_str != NULL) mdm_cmd_string (ans_str, 0); break; case F_UN_POLLNODE: (void) poll_node ((ADDRP) NULL); m = 1; break; case F_UN_POLLPKT: j = sb_popup (10, 5, 4, 70, Do_Poll_Packet, 0); if (j > 0) { set_up_outbound (); m = 1; more_mail = 1; } break; case F_UN_QUITTHISEVENT: if (cur_event >= 0) e_ptrs[cur_event].behavior |= MAT_SKIP; goto top_of_mail; case F_UN_RESTARTEVENTS: for (j = 0; j < num_events; j++) { /* Don't redo forced events */ if (!(e_ptrs[j].behavior & MAT_FORCED)) { e_ptrs[j].last_ran = (char) -1; e_ptrs[j].behavior &= ~MAT_SKIP; } } goto top_of_mail; case F_UN_SENDFILE: j = sb_popup (10, 5, 6, 70, Do_Send, 0); if (j < 0) { status_line (MSG_TXT (M_NO_SEND)); } else if (j > 0) { set_up_outbound (); m = 1; more_mail = 1; } break; case F_UN_TERMINALMODE: status_line (MSG_TXT (M_ENTER_TERMINAL_MODE)); done = 0; /* We won't exit now */ goto mail_done; case F_UN_REPAINTSCREEN: if (fullscreen) { screen_clear (); sb_dirty (); sb_show (); } break; case F_UN_HELPSCREEN: mailer_help (); m = 1; break; case F_UN_EXITBINK: status_line (MSG_TXT (M_EXIT_REQUEST)); goto mail_done; case F_UN_ZOOM: if (mail_top == NULL) { xmit_reset (0); if (mail_top == NULL) break; m = 1; more_mail = 1; next_mail = mail_top; xmit_window (next_mail); } if (sb_popup (1, 0, (short) (SB_ROWS - 2), 80, Do_Zoom, 0)) { m = 1; more_mail = 1; next_mail = mail_top; xmit_window (next_mail); } break; case F_UN_SHELL1: case F_UN_SHELL2: case F_UN_SHELL3: case F_UN_SHELL4: case F_UN_SHELL5: case F_UN_SHELL6: case F_UN_SHELL7: case F_UN_SHELL8: case F_UN_SHELL9: j = (short) ((unsigned short) j - (unsigned short) F_UN_SHELL1); if (shells[j] != NULL) { status_line (MSG_TXT (M_KEYBOARD_SHELL), j + 1); mdm_init (modem_busy); exit_DTR (); close_up (); vfossil_cursor (1); b_spawn (shells[j]); come_back (); m = 1; status_line (MSG_TXT (M_END_KEYBOARD_SHELL)); screen_clear (); if (fullscreen) sb_dirty (); opening_banner (); mailer_banner (); set_up_outbound (); RAISE_DTR (); mdm_init (modem_init); waitfor_line = timerset ((unsigned int) 6000); } else status_line (MSG_TXT (M_NO_KEYBOARD_SHELL), j + 1); break; case F_PEND_PGUP: if (next_mail == NULL) { next_mail = mail_top; } if (next_mail != NULL) { for (j = 0; j < (SB_ROW_HOLD - 2); j++) { if (next_mail->prev != NULL) next_mail = next_mail->prev; } xmit_window (next_mail); } break; case F_PEND_PGDN: if (next_mail == NULL) { next_mail = mail_top; } if (next_mail != NULL) { for (j = 0; j < (SB_ROW_HOLD - 2); j++) { if (next_mail->next != NULL) next_mail = next_mail->next; } goto limit_down; } break; case F_PEND_UPAR: if (next_mail == NULL) { next_mail = mail_top; } if (next_mail != NULL) { if (next_mail->prev != NULL) next_mail = next_mail->prev; xmit_window (next_mail); } break; case F_PEND_DNAR: if (next_mail == NULL) { next_mail = mail_top; } if (next_mail != NULL) { if (next_mail->next != NULL) next_mail = next_mail->next; limit_down: /* Common between PEND_PGDN and PEND_DNAR */ /* Don't allow travel below the end */ pmailT = next_mail; for (j = 0; j < (SB_ROW_HOLD - 3); j++) { if (pmailT->next != NULL) pmailT = pmailT->next; } if (pmailT->next == NULL) /* Past the end? */ { next_mail = pmailT; goto do_end; /* Yes, find it */ } xmit_window (next_mail); } break; case F_PEND_HOME: next_mail = mail_top; xmit_window (next_mail); break; case F_PEND_END: if (next_mail == NULL) { next_mail = mail_top; } if (next_mail != NULL) { while (next_mail->next != NULL) { next_mail = next_mail->next; } do_end: /* Common between PEND_END, PEND_PGDN and PEND_DNAR */ /* We are at end of list, find the top of window */ for (j = 0; j < (SB_ROW_HOLD - 3); j++) { if (next_mail->prev != NULL) next_mail = next_mail->prev; } } xmit_window (next_mail); break; case F_UN_CALLRIGHTNOW: if (cur_event >= 0) if (e_ptrs[cur_event].behavior & MAT_NOOUT) { status_line (MSG_TXT (M_NO_CALLS_NOW)); goto immed_call; } status_line (MSG_TXT (M_IMMEDIATE_CALL)); m = 0; more_mail = 1; goto immed_call; case F_CALLWIN_DNAR: if (fullscreen && callwin->lastshown != callwin->lastline && scrllines > callwin->lines) { callwin->lastshown += callwin->linesize; sb_scrl (callwin, 1); sb_move (callwin, callwin->lines, 2); sb_puts (callwin, callwin->lastshown); sb_show (); } break; case F_CALLWIN_UPAR: if (fullscreen && callwin->lastshown != callwin->buffer && scrllines > callwin->lines) { int i1 = (callwin->lastshown - callwin->buffer); int i2 = (callwin->lines - 1) * callwin->linesize; if (i2 < i1) { p = callwin->lastshown - (callwin->lines * callwin->linesize); callwin->lastshown -= callwin->linesize; sb_scrl (callwin, -1); sb_move (callwin, 1, 2); sb_puts (callwin, p); } sb_show (); } break; case F_CALLWIN_PGDN: if (fullscreen && callwin->lastshown != callwin->lastline && scrllines > callwin->lines) { p = callwin->lastshown + (callwin->lines * callwin->linesize); if (p >= callwin->lastline) p = callwin->lastline; do_callwin: if (p != callwin->lastshown) { callwin->lastshown = p; sb_scrl (callwin, 0); for (j = callwin->lines; j > 0 && p >= callwin->buffer; j--) { sb_move (callwin, j, 2); sb_puts (callwin, p); p -= callwin->linesize; } sb_show (); } } break; case F_CALLWIN_PGUP: if (fullscreen && scrllines > callwin->lines) { int i1 = (callwin->lastshown - callwin->buffer); int i2 = (callwin->lines - 1) * callwin->linesize; if (i2 < i1) { if ((i1 - i2) < i2) p = callwin->buffer + i2; else p = callwin->buffer + i1 - i2; goto do_callwin; } } break; case F_CALLWIN_TOP: if (fullscreen && scrllines > callwin->lines) { p = callwin->buffer + ((callwin->lines - 1) * callwin->linesize); if (p > callwin->lastline) p = callwin->lastline; goto do_callwin; } break; case F_CALLWIN_END: if (fullscreen && scrllines > callwin->lines) { p = callwin->lastline; goto do_callwin; } break; default: status_line (MSG_TXT (M_JUNK_CHARACTER)); m = 1; break; } else switch (toupper (j & 0xff)) { case 3: status_line (MSG_TXT (M_EXIT_REQUEST)); goto mail_done; case 0x20: m = 1; break; default: status_line (MSG_TXT (M_JUNK_CHARACTER)); m = 1; break; } goto bad_char; } mail_done: write_sched (); status_line (MSG_TXT (M_BINK_END), ANNOUNCE, COMPILER_NAME); un_attended = 0; if (fullscreen) { gotoxy (0, SB_ROWS); } set_prior (4); /* Always High */ XON_ENABLE (); set_prior (2); /* Regular */ (void) KbMapSet (OldKeyFncHdr); return (done); } static void LOCALFUNC bbs_reader (void) { if (BBSreader != NULL) { vfossil_cursor (1); status_line (MSG_TXT (M_DISABLE_MODEM)); mdm_init (modem_busy); exit_DTR (); status_line (MSG_TXT (M_BEGIN_MESSAGE_READER)); vfossil_close (); b_spawn (BBSreader); vfossil_init (); if (fullscreen) { screen_clear (); sb_dirty (); opening_banner (); mailer_banner (); } status_line (MSG_TXT (M_END_MESSAGE_READER)); set_up_outbound (); more_mail = 1; status_line (MSG_TXT (M_ENABLE_MODEM)); RAISE_DTR (); mdm_init (modem_init); waitfor_line = timerset ((unsigned int) 6000); } else { set_xy (NULL); status_line (MSG_TXT (M_NO_MESSAGE_READER)); set_xy (NULL); } } /* * Poll a node. If address is supplied, use it. Otherwise, * make a popup and ask for it. */ static int LOCALFUNC poll_node (ADDRP address) { int m; char jbuf[90]; if (address == (ADDRP) NULL) { status_line (MSG_TXT (M_POLL_MODE)); if (!fullscreen) { scr_printf ("\r\n"); clear_eol (); scr_printf (MSG_TXT (M_ENTER_NET_NODE)); m = get_number (jbuf); if (m) { m = find_address (jbuf, &next_addr); } if (!(m >= 1 && nodefind (&next_addr, 1))) return (-1); } else if (!sb_popup (10, 5, 4, 70, Do_Poll, 0)) { status_line (MSG_TXT (M_POLL_COMPLETED)); return (-1); } } else next_addr = *address; doing_poll = 1; if (fullscreen) { sprintf (junk, "%s %s", MSG_TXT (M_CURRENTLY_POLLING), Full_Addr_Str (&next_addr)); sb_move (filewin, 1, 2); sb_puts (filewin, junk); } set_prior (4); /* Always High */ if ((do_mail (&next_addr, 1) == 1) && sent_mail) { next_mail = find_mail (&next_addr); (void) bad_call (&next_addr, -1); xmit_delete (); } set_prior (2); /* Regular */ doing_poll = 0; status_line (MSG_TXT (M_POLL_COMPLETED)); if (fullscreen) { mailer_banner (); clear_filetransfer (); } RAISE_DTR (); mdm_init (modem_init); return (0); } /* * Call a node. If we get through, do call accounting. If * we have a dialout collision, try to get the inbound. */ static int LOCALFUNC call_node (ADDRP address, int no_inbound) { MAILP mp; int m; /* save the next call in the list in case we exit */ if ((next_mail == NULL) || (next_mail->next == NULL)) { mp = mail_top; } else { mp = next_mail->next; } hist.next_addr = mp->mail_addr; /* If this is a CM call, tell do_mail not to pay attention to the nodelist flags! */ if ((e_ptrs[cur_event].behavior & (MAT_CM | MAT_HIPRICM)) && (next_mail->mailtypes & MAIL_CRASH)) m = -1; else m = 0; set_prior (4); /* Always High */ m = do_mail (address, m); set_prior (2); /* Regular */ /* * If there was a session, handle bad-call accounting * based on whether the session was a complete success * or not. Then take an exit if appropriate, based on * what actually arrived here. */ if (m > 0) { if (m == 1) /* There was a good session */ { if (!sent_mail) { /* We connected but the transfer didn't work */ (void) bad_call (address, 1); } else { /* We got through, so delete his status file */ (void) bad_call (address, -1); xmit_delete (); } } if (m == 2) /* Nothing happened */ (void) bad_call (address, 2); /* Take an exit if we got something in */ if (got_arcmail || got_packet || got_mail) receive_exit (); mailer_banner (); } else if (m < 0) { if (m == -1) status_line (MSG_TXT (M_INCOMING_CALL)); /* Call collision or NO-DIAL-TONE. Try to answer the call in time to catch the remote. Exception: if it has been less than a minute since unbusying the line. */ if (!no_inbound && timeup (waitfor_line)) { m = handle_inbound_mail (1); if (m) xmit_sameplace (); } } return (m); }