home *** CD-ROM | disk | FTP | other *** search
/ Computerworld 1996 March / Computerworld_1996-03_cd.bin / idg_cd3 / aplikace / komunika / telixwin / tfw.5 / WINHOST.SLT < prev   
Text File  |  1995-07-28  |  52KB  |  1,856 lines

  1. //
  2. //   W I N H O S T . S L T
  3. //
  4. //   Copyright (C) 1988-1995 deltaComm Development.
  5. //
  6. //   - Written by Colin Sampaleanu.
  7. //   - Modifications by Jeff Woods, Feb '91, to add help function and support
  8. //     for locked modems.
  9. //   - Modifications by Dan Horn, Nov '92, fixed 'floating' timer bug.
  10. //   - Thanks to Jon Fleming for his help in porting this to Windows.
  11. //   - Modifications for hot keys and logins, fixes for chat mode and
  12. //     <=9600 baud remote dos shells in Dec '94 by Sean Palmer
  13. //   - Modifications to Connect baud parsing Jan '95 by Sean Palmer
  14. //   - Modifications to allow ANSI and RIP displays Feb '95 by Jeff Smith
  15. //   - Message system added March '95 by Jeff Smith
  16. //
  17. //   This is a Host Mode for Telix, written as a script file.
  18. //   To configure Host Mode parameters such as passwords, run the 'WCONFIG'
  19. //   script. That script is run automatically if the Host Mode configuration
  20. //   file 'WINHOST.CNF' is missing.
  21. //
  22. //   This script will only work with Hayes compatible modems, but may be
  23. //   modified for operation with other modems.
  24. //
  25. //////////////////////////////////////////////////////////////////////////////
  26.  
  27. #stack 1536  // Increased stack size
  28.  
  29. // Parameters which are configured from the WinHost configuration file
  30.  
  31. str host_downloads[64],         // Default where users may download from
  32.     host_uploads[64],           // Default where uploaded files go
  33.     host_message[64];           // Default used by message system
  34.  
  35. int direct_connect = 0,         // 0 = using a modem
  36.     modem_lock = 0,
  37.     closed_sys = 0;             // 0 = users may sign up on line if not
  38.                                 //  found in the config file
  39.  
  40. // Various global variables
  41.  
  42. str current_caller[31],         // storage of current caller's name
  43.     our_dir[64];                // Winhost directory (either Telix's
  44.                                 //  scripts directory or the contents
  45.                                 //  of the HOST2DIR environment variable
  46.                                 //  if it exists)
  47.  
  48.  
  49. int finished_caller,            // set to TRUE when must return to top
  50.     local_mode,                 // set to TRUE when local test mode
  51.     access_level,               // access level of current caller
  52.     carrier_counts = 1,         // TRUE if should watch Carrier signal
  53.     already_connected = 0,
  54.     exit_requested = 0,         // set to TRUE if Sysop has pressed Esc
  55.     connection_lost = 0,        // set to TRUE when carrier lost
  56.     kill_user = 0,              // set to TRUE when user must be purged
  57.     min_user_name = 5,          // Minimum length of user's name
  58.     user_has_own_dir;           // Flag to restrict the user to one dir
  59.  
  60. int old_scr_chk_key,            // storage for some system variables
  61.     old_cisb_auto,              // which we have to modify and put
  62.     old_zmod_auto,              // back to what they were when done
  63.     old_sound,
  64.     RIP_On, ANSI_On;            // Flag ANSI and RIP capability
  65.  
  66. str old_down_dir[64],
  67.     old_up_dir[64],
  68.     tfw_down_dir[64],
  69.     tfw_up_dir[64],
  70.     old_usage_fname[64];
  71.  
  72. int ndx_fil, mssg_num,          // Message system variables
  73.     mssg_time, mssg_priv;       // used by the index file
  74. str mssg_to[30], mssg_from[30], // "message.ndx"
  75.     mssg_subj[30];
  76.  
  77. #INCLUDE "WHUTILS.SLT"          // Functions which are shared with the
  78.                                 //  configuration managements script
  79.  
  80. //////////////////////////////////////////////////////////////////////////////
  81. //////////////////////////////////////////////////////////////////////////////
  82.  
  83. main() {
  84.  
  85.   int c;
  86.   str s[80], filnam[64];
  87.  
  88.   tfw_up_dir = _up_dir;
  89.   tfw_down_dir = _down_dir;
  90.   clear_scr;
  91.  
  92.   get_our_dir;
  93.  
  94.   if (read_host_config_file == -1) {
  95.      prints("Unable to read WINHOST.CNF...");
  96.      prints("Running WCONFIG, the Host Mode configuration script.^M^J");
  97.      s = our_dir;
  98.      strcat (s, "WCONFIG");
  99.      calld(s);
  100.      if (read_host_config_file() == -1) {
  101.         prints("Still unable to read WINHOST.CNF. Aborting Host Mode.^M^J");
  102.         return -1;
  103.      }
  104.   }
  105.  
  106.   prints ("Checking existence of directories ...");
  107.   if (!(check_directory(host_downloads)
  108.      && check_directory(host_uploads)
  109.      && check_directory(host_message))) {
  110.     prints("Aborting Host Mode.");
  111.     return -1;
  112.   }
  113.  
  114.   old_scr_chk_key = _scr_chk_key;
  115.   _scr_chk_key = 0;
  116.   old_cisb_auto = _cisb_auto;
  117.   _cisb_auto = 0;
  118.   old_zmod_auto = _zmod_auto;
  119.   _zmod_auto = 0;
  120.   old_sound = _sound_on;
  121.   _sound_on = 0;
  122.   old_down_dir = _down_dir;
  123.   old_usage_fname = _usage_fname;
  124.  
  125.   s = our_dir;
  126.   strcat (s, "HOST2.LOG");
  127.   usagelog (s);
  128.  
  129.   carrier_counts = !direct_connect;
  130.   already_connected = (carrier_counts && carrier());
  131.  
  132.   filnam=host_message;
  133.   strcat(filnam, "message.ndx");
  134.   if (filefind(filnam, 0))   {
  135.    ndx_fil=fopen(filnam, "r+");
  136.    if (ndx_fil)
  137.      update_ndx_file();   // scan index file for msgs more than
  138.                           // a certain age, & delete them
  139.   }
  140.   else   {     // Create the index file
  141.    ndx_fil=fopen(filnam, "w+");
  142.    mssg_from="Internal";
  143.    mssg_to="Internal";
  144.    mssg_priv=1;
  145.    mssg_time=curtime();
  146.    mssg_subj="Time Index";
  147.    ndx_write(0);
  148.   }
  149.  
  150.  
  151.   while (1) {
  152.     _down_dir = host_uploads;   // these are reversed because we are the Host
  153.     old_up_dir = _up_dir;
  154.     _up_dir = host_downloads;   // these are reversed because we are the Host
  155.     user_has_own_dir = 0;
  156.     if (!direct_connect && !already_connected) {
  157.       if (!modem_lock)
  158.         set_cparams(modem_lock, 0, 8, 1);
  159.       delay_scr(3);
  160.       prints("Sending Modem Init string...");
  161.       cputs_tr(_mdm_init_str);
  162.       delay_scr(20);
  163.       prints("Sending Auto-Answer string...");
  164.       cputs_tr(_auto_ans_str);
  165.       delay_scr(10);
  166.     }
  167.  
  168.     finished_caller = kill_user = 0;
  169.  
  170.     if (direct_connect)
  171.       carrier_counts = 0;
  172.     else {
  173.       carrier_counts = 1;
  174.       local_mode = 0;
  175.       prints("^M^JHost Mode: Waiting for call...");
  176.       prints("(Press Esc to exit, or 'L' for local test mode).^M^J");
  177.  
  178.       do {
  179.         if (carrier()) break;
  180.  
  181.         if ((c = inkey())==27) {
  182.           exit_requested = 1;
  183.           break;
  184.         }
  185.         else if (c==' ') { cputs("ata^m"); c=0; }
  186.         else if (toupper(c) == 'L') {             // local test mode
  187.           prints("Local test mode entered");
  188.           local_mode = 1;
  189.           carrier_counts = 0;
  190.           break;
  191.         }
  192.       } while (1);
  193.     }
  194.  
  195.     if (!exit_requested) {
  196.       prints("Incoming call. Sysop: press Esc to exit, or END to terminate user.");
  197.  
  198.       do_one_caller();
  199.       if ((connection_lost || kill_user) && carrier_counts && carrier())
  200.         hangup();             // make sure nobody sneaks in
  201.     }
  202.     already_connected = 0;
  203.     if (exit_requested) {
  204.       if (!carrier() && !direct_connect) {
  205.         prints("Sending Modem Init string...");
  206.         cputs_tr(_mdm_init_str);
  207.       }
  208.       _scr_chk_key = old_scr_chk_key;
  209.       _cisb_auto = old_cisb_auto;
  210.       _zmod_auto = old_zmod_auto;
  211.       _sound_on = old_sound;
  212.       _down_dir = tfw_down_dir;
  213.       _up_dir = tfw_up_dir;
  214.       prints("^M^JHost mode script finished.");
  215.       usagelog("*CLOSE*");
  216.       _usage_fname = old_usage_fname;
  217.       return 1;
  218.     }
  219.   }
  220. }
  221.  
  222. //////////////////////////////////////////////////////////////////////////////
  223.  
  224. host_help (str mode, str option) {
  225.  
  226.   str fname[64];
  227.  
  228.   fname = our_dir;
  229.   strcat (fname, mode);
  230.   strcat (fname, "_HELP_");
  231.   StrCat (fname, option);
  232.   StrCat (fname, ".TXT");
  233.  
  234.   if (FileFind (fname, 0)) {
  235.     type_our_file (fname);
  236.     return (1);
  237.   }
  238.   else {
  239.     printsc ("^MCan't find help file ");
  240.     prints (fname);
  241.     return (0);
  242.   }
  243. }
  244.  
  245. //////////////////////////////////////////////////////////////////////////////
  246.  
  247. do_one_caller() {
  248.  
  249.   str strn[80], fname[64],  s[80], temporary[1],
  250.       num[10], CHKSTR[20];
  251.   int option, status, c, i, i2, f, len, TIMR;
  252.  
  253.   access_level = 1;
  254.  
  255. //  flushbuf();
  256.  
  257.   if (already_connected)
  258.     prints("Already connected, or modem Carrier Detect switch improperly set!");
  259.   else if (carrier_counts)
  260.     determine_baud();
  261.  
  262.   if (!local_mode) delay_scr(20);
  263.  
  264.   flushbuf();
  265.   if (local_mode) {
  266.     ansi_on=rip_on=0;
  267.     s=gety();              //detect local ansi
  268.     host_send("^[[2A");
  269.     if ((s-gety())==2) {
  270.       ansi_on=1;
  271.       host_send("^[[2B");
  272.       host_send("^A|H");   //detect local rip
  273.       if (gety()==0) {
  274.         rip_on=1;
  275.         }
  276.       else host_send("^H^H^H   ^H^H^H");
  277.       }
  278.     else host_send("^H^H^H   ^H^H^H");
  279.     gotoxy(1, s);     //fix cursor
  280.     }
  281.   else {
  282.     Ansi_On=0;
  283.     Rip_On=0;
  284.     chkstr="";
  285.     cputs("^M^[[6n^H^H^H^H    ^H^H^H^H");
  286.     timr=timer_start(10);
  287.     do {
  288.       if (cinp_cnt()) {
  289.         s=cgetc();
  290.         strcat(chkstr, s);
  291.         }
  292.       }
  293.     while (!time_up(timr));
  294.     timer_free(timr);
  295.     if ((strpos(chkstr, "^[[", 0)>=0) && (strpos(chkstr, "R", 1)>=0))
  296.      {
  297.       ANSI_On=1;
  298.       chkstr="";
  299.       cputs("^M^[[!^H^H^H   ^H^H^H");
  300.       timr=timer_start(10);
  301.       do
  302.        {
  303.         if (cinp_cnt()) {
  304.           s=cgetc();
  305.           strcat(chkstr, s);
  306.           }
  307.        }
  308.       while (!time_up(timr));
  309.       timer_free(timr);
  310.       RIP_On = (strpos(chkstr, "RIPSCRIP", 0) >= 0);
  311.      }
  312.   }
  313.   type_our_file("LOGO");
  314.  
  315.   if (!get_user_name()) {
  316.     ustamp("Failed logon attempt", 1, 0);
  317.     return;
  318.     }
  319.  
  320.   access_level = setup_user(3);
  321.  
  322.   if (access_level) {
  323.     ustamp("Logon by ", 1, 0);
  324.     ustamp(current_caller, 0, 1);
  325.   }
  326.   else {
  327.     ustamp("Failed logon attempt by ", 1, 0);
  328.     ustamp(current_caller, 0, 1);
  329.     send_goodbye();
  330.     if (carrier_counts) {
  331.       delay_scr(10);
  332.       hangup();
  333.     }
  334.     return;
  335.   }
  336.  
  337.   type_our_file("WELCOME");
  338.  
  339.   while (1) {
  340.     if (finished_caller)
  341.     return;
  342.  
  343.     if (access_level == 3) {
  344.       if (type_our_file("MMENU3") == -1)
  345.         host_send("^M^JFiles  Type  Upload  Download  Shell  Chat  Help  Message  Goodbye ? ");
  346.     }
  347.     else {
  348.       if (type_our_file ("MMENU") == -1)
  349.           host_send("^M^JFiles  Type  Upload  Download  Chat  Help  Message  Goodbye ? ");
  350.     }
  351.  
  352.     host_send ("^M^JCommand: ");
  353.     host_input_strn(strn, 1, 1);
  354.     option = toupper(subchr(strn, 0));
  355.     host_send("^M^J");
  356.  
  357.     if (option == 'H') {               // Help
  358.       host_send("^M^JWhich item above do you wish help on? ");
  359.       host_input_strn(strn, 1, 1);
  360.       substr (strn, 0, 1, strn);
  361.       strupper (strn);
  362.       Host_send("^M^J");
  363.       host_help( "H", strn);
  364.     }
  365.  
  366.     if (option == 'F') {               // Files directory
  367.       if (access_level >= 2) {
  368.         host_send("Enter 'filespec' or press Return for *.*,^M^J: ");
  369.         host_input_strn(fname, 64, 1);
  370.         host_send("^M^J");
  371.         ustamp ("Requested file listing of ", 1, 0);
  372.         ustamp (fname, 0, 1);
  373.  
  374.         if (strcmpi (fname, "") == 0) {
  375.           fname = "*.*";
  376.         }
  377.  
  378.         if (just_filename(fname)) {
  379.           strn = _down_dir;
  380.           strcat(strn, fname);
  381.         }
  382.         else if (user_has_own_dir == 1) {
  383.           host_send ("^M^JAccess outside ");
  384.           host_send (_down_dir);
  385.           host_send (" not allowed^M^J");
  386.           strn = _down_dir;
  387.           strcat(strn, "*.*");
  388.         }
  389.         else {
  390.           len = strlen (fname);
  391.           substr (fname, len - 1, 1, temporary);
  392.           if (strcmpi (temporary, "\") == 0) {
  393.             strn = fname;
  394.             strcat (strn, "*.*");
  395.           }
  396.           else strn = fname;
  397.         }
  398.       }
  399.       else {
  400.         strn = _down_dir;
  401.         strcat(strn, "*.*");
  402.         ustamp ("Requested listing of files", 1, 1);
  403.       }
  404.  
  405.       host_show_directory(strn);
  406.       ustamp ("Displayed ", 1, 0);
  407.       ustamp (strn, 0, 1);
  408.     }
  409.  
  410.     else if (option == 'T') {          // Type a file
  411.       host_send("Type what file? ");
  412.       host_input_strn(strn, 64, 1);
  413.       host_send("^M^J");
  414.       ustamp ("Requested to type ", 1, 0);
  415.       ustamp (strn, 0, 1);
  416.  
  417.       if ((access_level == 1) || (user_has_own_dir == 1))
  418.         fnstrip(strn, 3, fname);
  419.       else
  420.         fname = strn;
  421.  
  422.       if (just_filename(fname)) {
  423.         strn = _down_dir;
  424.         strcat(strn, fname);
  425.         fname = strn;
  426.       }
  427.  
  428.       if (!filefind(fname, 0, strn)) {
  429.         host_send("Unable to find ");
  430.         host_send(fname);
  431.         continue;
  432.       }
  433.  
  434.       get_extension(fname, strn);
  435.       if (strcmpi(strn,"ZIP")==0 ||
  436.           strcmpi(strn,"ARJ")==0)
  437.       {
  438.         host_send("Unable to type ");
  439.         host_send(fname);
  440.         continue;
  441.       }
  442.  
  443.       type_file(fname);
  444.       ustamp ("Typed ", 1, 0);
  445.       ustamp (fname, 0, 1);
  446.     }
  447.  
  448.     else if (option == 'M') {          // Message system
  449.        do {
  450.          if (type_our_file("mssgmenu")==-1)
  451.            host_send("Read  Write  Quit ?");
  452.  
  453.          i=host_input(1);
  454.          i=toupper(i);
  455.          if (i=="R") read_mssg();
  456.          else if (i=="W") write_mssg();
  457.         }
  458.         while (i!='Q');
  459.     }
  460.  
  461.     else if (option == 'G') {          // Goodbye (Hang-up)
  462.       send_goodbye ();
  463.       ustamp("User logged off.", 1, 1);
  464.       if (carrier_counts) {
  465.         delay_scr(10);
  466.         hangup();
  467.       }
  468.       return;
  469.     }
  470.  
  471.     else if (option == 'C') {          // Chat mode
  472.       prints("Sysop: Press Space to chat, any other key not to.^M^J");
  473.       c = 0;
  474.       _sound_on = 1;
  475.       for (i = 8; i && !c; --i) {
  476.         host_send (".");
  477.         if (carrier_counts && !carrier()) {
  478.           prints("^M^JConnection has been lost, call terminated.^M^J");
  479.           connection_lost = 1;
  480.           finished_caller = 1;
  481.           break;
  482.         }
  483.         cputc('^G');
  484.         tone(523, 20);
  485.         tone(659, 20);
  486.         tone(523, 20);
  487.         tone(659, 20);
  488.         tone(523, 20);
  489.         tone(659, 20);
  490.         delay(9);
  491.         c = inkey();
  492.       }
  493.       _sound_on = 0;
  494.       host_send ("^M^J");
  495.       if (finished_caller)
  496.         continue;
  497.       if (c != ' ') {
  498.         host_send("Sorry, the Sysop is unavailable^M^J");
  499.         continue;
  500.       }
  501.       host_send("The sysop is here!^M^J");
  502.       chatmode(!local_mode,1); //start chat, no echo if local
  503.       status_wind("Press Ctrl-X to terminate chat",30);
  504.       while (1) {
  505.         if (waitfor("^X",1)) break;
  506.       }
  507.       chatmode(!local_mode,0); //end chat
  508.     }
  509.  
  510.     else if (option == 'U') {          // User upload
  511.       option = host_get_prot();
  512.       if (!option)
  513.         continue;
  514.  
  515.       ustamp ("Upload ", 1, 0);
  516.       status = 1;
  517.       if (option == 'Y' || option == 'Z' || option == 'E') {
  518.         ustamp ("with name-transferrring protocol ", 0, 1);
  519.         send_transfer_msg();
  520.         status = receive(option, "");
  521.       }
  522.       else {
  523.         host_send("Upload what file? ");
  524.         host_input_strn(strn, 48, 1);
  525.         host_send("^M^J");
  526.           if (!strn)
  527.             continue;
  528.           ustamp (strn, 0, 1);
  529.           if ((access_level == 1) || (user_has_own_dir == 1)) // if access 1, name and ext only
  530.             fnstrip(strn, 3, fname);
  531.           else
  532.             fname = strn;
  533.  
  534.           if (just_filename(fname)) {
  535.             strn = _up_dir;
  536.             strcat(strn, fname);
  537.             fname = strn;
  538.           }
  539.  
  540.           if (filefind(fname, 23, strn)) {
  541.             host_send("File already exists!^M^J");
  542.             ustamp ("File already exists", 1, 1);
  543.           }
  544.           else {
  545.             send_transfer_msg();
  546.             status = receive(option, fname);
  547.           }
  548.         }
  549.  
  550.         if (status == -2) {                      // Carrier lost
  551.           connection_lost = finished_caller = 1;
  552.           ustamp ("Lost carrier", 1, 1);
  553.         }
  554.         else if (status == -1) {
  555.           host_send("^M^J^M^J^GOne or more files not received!^M^J");
  556.           ustamp ("One or more files not received", 1, 1);
  557.         }
  558.         else {
  559.           ustamp ("Transfer complete", 1, 1);
  560.         }
  561.       }
  562.  
  563.     else if (option == 'D') {          // User download
  564.       option = host_get_prot();
  565.       if (!option)
  566.         continue;
  567.       host_send("Download what file(s)? ");
  568.       host_input_strn(strn, 48, 1);
  569.       host_send("^M^J");
  570.       if (!strn)
  571.         continue;
  572.       ustamp ("Attempt to download ", 1, 0);
  573.       ustamp (strn, 0, 1);
  574.       if ((access_level == 1) || (user_has_own_dir == 1)) // if not level 2, keep only name & ext
  575.         fnstrip(strn, 3, fname);
  576.       else
  577.         fname = strn;
  578.       if (just_filename(fname)) {
  579.         strn = _down_dir;
  580.         strcat(strn, fname);
  581.         fname = strn;
  582.       }
  583.  
  584.       if (!filefind(fname, 0, strn)) {
  585.         host_send("Unable to find any matching file(s)!^M^J");
  586.         ustamp ("No such file", 1, 1);
  587.         continue;
  588.       }
  589.  
  590.       status = 1;
  591.       send_transfer_msg();
  592.       status = send(option, fname);
  593.       if (status == -2) {                      // Carrier lost
  594.         connection_lost = finished_caller = 1;
  595.         ustamp ("Lost carrier", 1, 1);
  596.       }
  597.       else if (status == -1) {
  598.         host_send("^M^J^M^J^GOne or more files not sent!^M^J");
  599.         ustamp ("One or more files not sent", 1, 1);
  600.       }
  601.       else {
  602.         ustamp ("Transfer complete", 1, 1);
  603.       }
  604.     }
  605.  
  606.     else if (option == 'S') {          // Remote shell
  607.       ustamp ("Attempted shell", 1, 1);
  608.       if (access_level == 3) {
  609.         host_send("Type EXIT and then press Enter to come back.^M^J");
  610.         if (get_baud() == 300)
  611.           delay_scr(10);
  612.         if (local_mode)
  613.           dos("", 0);
  614.              // See if user has prepared a custom file for shell operation
  615.              // and call that if it exists
  616.         else {
  617.           if (filefind("RSHELL.BAT", 0, strn))
  618.             do_remote_shell("RSHELL.BAT");
  619.           else {  // otherwise make our own temporary batch file for redirection
  620.             if (get_port() != 1 && get_port() != 2) {
  621.               host_send("Remote Shell not supported on this comm port due to DOS limits!^M^J");
  622.             }
  623.             else {
  624.              // now want to make a temporary batch file which will be
  625.              // called to redirect DOS input and output, then shell to
  626.              // another copy of the command interpreter
  627.               f = fopen("HOSTTEMP.BAT", "w");
  628.               if (f) {
  629.                 if (get_baud()>9600) {
  630.                   status_wind("Attempting to shell to dos at over 9600 baud",50);
  631.                   ustamp("DOS shell baud > 9600",0,1);
  632.                   }
  633.                 fputs("MODE ", f);    // this command informs dos of the port rate
  634.                 strn = "COMx";
  635.                 setchr(strn, 3, get_port() + '0'); // get right name to redirect
  636.                 fputs(strn, f);                    // save strn for later
  637.                 fputc(" baud=", f);
  638.                 itos(get_baud(), num);
  639.                 fputs(num, f);
  640.                 fputs(" parity=", f);
  641.                 switch (get_parity()) {
  642.                   case 1:  fputc('E', f);
  643.                   case 2:  fputc('O', f);
  644.                   case 3:  fputc('M', f);
  645.                   case 4:  fputc('S', f);
  646.                   default: fputc('N', f);
  647.                 }
  648.                 fputs(" data=", f);
  649.                 itos(get_dataB(), num);
  650.                 fputs(num, f);
  651.                 fputs(" stop=", f);
  652.                 itos(get_stopB(), num);
  653.                 fputs(num, f);
  654.                 fputs("^M^J", f);
  655.  
  656.                 fputs("CTTY ", f);           // write to batch file
  657.                 fputs(strn, f);              // this command actually makes the shell work
  658.                 fputs("^M^J", f);
  659.                 if (getenv ("COMSPEC", s) == 0)
  660.                   s = "COMMAND.COM";
  661.  
  662.                 fputs (s, f);
  663.                 fputs("^M^J", f);
  664.                 fputs("CTTY CON^M^J", f);
  665.                 fputs("EXIT^M^J", f);
  666.  
  667.                 fclose(f);                   // close the file
  668.  
  669.                 if (!local_mode)             // call batch file
  670.                   do_remote_shell("HOSTTEMP.BAT");
  671.               }
  672.               else
  673.                 host_send("Can't open temporary batch file!^M^J");
  674.             }
  675.           }
  676.         }
  677.       }
  678.       else ustamp ("Request denied", 1, 1);
  679.     }
  680.  
  681.     else if (option == '^Z') {          // Shut down Host Mode
  682.       if (access_level == 3) {
  683.         host_send("Shutting down Host mode. ");
  684.         ustamp("User shut down Host Mode.", 1, 1);
  685.         send_goodbye ();
  686.         ustamp("User logged off.", 1, 1);
  687.         if (carrier_counts)
  688.           hangup();
  689.         finished_caller = 1;
  690.         exit_requested = 1;
  691.       }
  692.     }
  693.   }
  694. }
  695.  
  696. //////////////////////////////////////////////////////////////////////////////
  697.  
  698. do_remote_shell(str batfile) {
  699.   str savedConn[80];                   //holds saved connect device's name
  700.  
  701.   //here we make a new connect device with a port of 0 which causes the
  702.   //device to not be attached to any specific port. Useful to
  703.   //keep Telix from using any ports temporarily.
  704.   if (makeConnectDevice("__NULL__","2400bps Generic",0,0,0))
  705.   {
  706.     connectDeviceName(0,savedConn);      //get current device name
  707.     if (set_ConnectDevice("__NULL__",2)) //selecting a port 0 device won't
  708.     {                                    //disturb the current device's connection
  709.       dos(batfile);
  710.       set_ConnectDevice(savedConn,1);  //restore previous connect device
  711.     }                                  //without sending init string
  712.     killConnectDevice("__NULL__");
  713.   }
  714. }
  715.  
  716. //////////////////////////////////////////////////////////////////////////////
  717.  
  718. host_get_prot() {
  719.  
  720.   str prot[1], strn[1], s[64];
  721.  
  722.   int Option;
  723.  
  724.   prot = "H";
  725.  
  726.   while (strcmpi (prot, "H") == 0) {
  727.  
  728.     if (type_our_file ("PMENU") == -1) {
  729.       host_send("^M^JXmodem  xmodem-Crc  xmodem-1k  xmodem-1k-G  Ymodem  ymodEm-g  Zmodem  Kermit^M^J");
  730.       host_send("Help Cancel^M^J");
  731.     }
  732.  
  733.     host_send("Which protocol, or H for help ? ");
  734.     host_input_strn(prot, 1, 1);
  735.     strupper (prot);
  736.     host_send("^M^J");
  737.  
  738.     if (strcmpi (prot, "H") == 0) {
  739.       host_send ("^M^JHelp on which protocol, or ^"A^" for ALL? ");
  740.       host_input_strn (strn, 1, 1);
  741.       substr (strn, 0, 1, strn);
  742.       strupper (strn);
  743.       Host_send("^M^J");
  744.       host_help( "P", strn);
  745.     }
  746.  
  747.     if (strposi("XC1GYEZKH", prot, 0) == -1)  // if illegal prot or cancel
  748.       prot = "";                              // return 0
  749.   }
  750.  
  751.   return (toupper(subchr(prot, 0)));
  752.  
  753. }
  754.  
  755. //////////////////////////////////////////////////////////////////////////////
  756.  
  757. send_transfer_msg() {
  758.  
  759.   host_send("Ready to transfer file(s)... Press Ctrl-X at least twice to abort^M^J");
  760. }
  761.  
  762. //////////////////////////////////////////////////////////////////////////////
  763. // Determine the baud rate once a Carrier Detect Signal has been detected
  764. // Since no characters were read, the 'CONNECT' string should still be
  765. // in the receive buffer.
  766.  
  767. determine_baud() {
  768.  
  769.   int tconnect;
  770.   int tmark, stat, c;
  771.   int new_baud = 0;
  772.  
  773.   str cstring[20];
  774.  
  775.   printsc("Determining baud... ");
  776.  
  777.   track_free(0);                // clear all existing tracks
  778.  
  779.   tconnect = track(_connect_str, 0);  // check for connect string
  780.  
  781.   tmark = timer_start(30);      // wait up to 3 seconds for string
  782.  
  783.   while (!time_up(tmark)) {
  784.     if (!carrier()) {
  785.       track_free(0);            // clear all existing tracks
  786.       timer_free(tmark);        // free existing timer
  787.       return 0;
  788.     }
  789.  
  790.     if (cinp_cnt()) {
  791.       printc_trm(c=cGetC);      // does tracks too
  792. //      printc(c=cGetC);
  793. //      track_addChr(c);
  794.       }
  795.  
  796.     if (track_hit(0) != tConnect) continue;
  797.  
  798.     while (1) {
  799.       while (!cinp_cnt()) ;
  800.       if ((c=cgetc)>' ') break;
  801.       printc(c);
  802.       }
  803.     while(1) {
  804.       printc(c);
  805.       if ((c>='0') && (c<='9'))
  806.         new_baud = new_baud * 10 + c - '0';
  807.       else break;
  808.       while (!cinp_cnt) ;
  809.       c=cgetc();
  810.     }
  811.     printc(c);
  812.  
  813.     if (!new_baud) new_baud = 300;
  814.  
  815.     break;                      // have baud rate, get out
  816.   }
  817.  
  818.   track_free(0);                // clear all existing tracks
  819.   timer_free(tmark);            // free existing timer
  820.  
  821.   if (!new_baud) {              // time-up without CONNECT string
  822.     prints("Failed!");
  823.     return 0;
  824.   }
  825.  
  826. //  printn(new_baud);
  827. //  newLine();
  828.   setDCERate(new_baud);         // Let TFW know
  829.   return 1;                     // indicate success
  830.  
  831. }
  832.  
  833. //////////////////////////////////////////////////////////////////////////////
  834. // Allow user to read messages
  835. read_mssg()
  836. {
  837.  str read_fil[64], buf[64];
  838.  int mcode, rflag, position, i;
  839.  mcode=0;
  840.  host_send("^M^J Read all public mail (y/n): ");
  841.  i=toupper(host_input(1));
  842.  if (i=='Y') mcode=2;
  843.  else
  844.   {
  845.    host_send("^M^J Read mail to 'All' (y/n): ");
  846.    i=toupper(host_input(1));
  847.    if (i=='Y') mcode=1;
  848.   }
  849.  host_send("^M^J");
  850.  fseek(ndx_fil, 0, 0);
  851.  while (ndx_read()) {
  852.     rflag=0;
  853.     if ((strcmpi(mssg_to, current_caller)==0)
  854.      and (mssg_priv < 2)) rflag=1;
  855.     else
  856.      if ((strcmpi(mssg_to, "ALL")==0) and (mcode>0)
  857.       and (mssg_priv == 0)) rflag=1;
  858.      else
  859.       if ((mssg_priv==0) and (mcode==2)) rflag=1;
  860.     if (rflag)
  861.      {
  862.       host_send("^M^J  From: ");
  863.       host_send(mssg_from);
  864.       host_send("   To: ");
  865.       if (mssg_to==0) host_send("All");
  866.       else host_send(mssg_to);
  867.       host_send("   ");
  868.       date(mssg_time, read_fil);
  869.       host_send(read_fil);
  870.       host_send("^M^J  Subject: ");
  871.       host_send(mssg_subj);
  872.       host_send("^M^J^M^J   Read Message (y/n)");
  873.       i=host_input(1);
  874.       i=toupper(i);
  875.       host_send("^M^J");
  876.       if (i=='Y')
  877.        {
  878.         itos(mssg_num, buf);
  879.         read_fil=host_message;
  880.         strcat(read_fil, "M");
  881.         strcat(read_fil, buf);
  882.         strcat(read_fil, ".MSG");
  883.         type_file(read_fil);
  884.         host_send("^M^J");
  885.        }
  886.       if (strcmpi(mssg_to, current_caller)==0)
  887.        {
  888.         host_send(" Delete Message (y/n)");
  889.         i=host_input(1);
  890.         i=toupper(i);
  891.         if (i=='Y') delete_mssg(mssg_num);
  892.         host_send("^M^J");
  893.        }
  894.      }
  895.    }
  896. }
  897.  
  898. // Allow user to write messages
  899. write_mssg()
  900. {
  901.  str ans[85], fn[64], wrd[80];
  902.  int cnt, i, mssgdone, f;
  903.  f=fopen("edit.msg", 'w');
  904.  host_send("^M^J^M^J");
  905.  host_send(" Private message (y/n)");
  906.  do
  907.   i=toupper(host_input(1));
  908.  while ((i!='Y') and (i!='N'));
  909.  if (i=='Y') mssg_priv=1;
  910.  else mssg_priv=0;
  911.  host_send("^M^J To: ");
  912.  host_input_strn(mssg_to, 30, 1);
  913.  host_send("^M^J Subject: ");
  914.  host_input_strn(mssg_subj, 30, 1);
  915.  host_send("^M^J");
  916.  host_send(" Enter message:^M^J");
  917.  ANS=wrd=""; CNT=1;
  918.  MSSGDONE=0;
  919.  do
  920.   {
  921.    i=host_input(1);
  922.    ++CNT;
  923.    if (i==13)
  924.      {
  925.       strcat(ans, wrd);
  926.       wrd="";
  927.       host_send("^M^J");
  928.       IF (ANS=="") MSSGDONE=1;
  929.       strcat(ans, "^m");
  930.       fputs(ans, f);
  931.       ANS="";
  932.       CNT=1;
  933.      }
  934.    else
  935.    if (i==8)
  936.      {
  937.       CNT=CNT-2;
  938.       IF (CNT<0) CNT=0;
  939.       ELSE {
  940.        if (strlen(wrd)>0)
  941.         substr(wrd, 0, strlen(wrd)-1, wrd);
  942.        else
  943.         substr(ans, 0, strlen(ans)-1, ans);
  944.         host_send_c(i);
  945.        }
  946.      }
  947.    ELSE
  948.      {
  949.       strcat(wrd, i);
  950.       if ((i==' ') && (cnt<80)) {
  951.         strcat(ans, wrd);
  952.         wrd="";
  953.       }
  954.       IF (CNT>=80)
  955.         {
  956.          cnt=strlen(wrd);
  957.          do {
  958.            cnt=cnt-1;
  959.            host_send_c(8);
  960.           }
  961.          while (cnt>0);
  962.          cnt=strlen(wrd);
  963.          do {
  964.            cnt=cnt-1;
  965.            host_send_c(' ');
  966.           }
  967.          while (cnt>0);
  968.          host_send("^M^J");
  969.          strcat(ans, "^m");
  970.          fputs(ans, f);
  971.          host_send(wrd);
  972.          ANS=wrd;
  973.          wrd="";
  974.          CNT=strlen(ans)+1;
  975.         }
  976.      }
  977.   }
  978.  while (MSSGDONE==0);
  979.  host_send("^M^J");
  980.  fclose(f);
  981.  host_send(" Send Message? Y/n: ");
  982.  i='a';
  983.  do
  984.   i=toupper(host_input(1));
  985.  while ((i!='Y') and (i!='N'));
  986.  host_send("^M^J^M^J");
  987.  IF (i=='Y')
  988.    {
  989.     mssg_from=current_caller;
  990.     ans="";
  991.     do
  992.      {
  993.       ans=host_message;
  994.       strcat(ans, "M");
  995.       mssg_num=random(10000)*100+random(100);
  996.       itos(mssg_num, fn);
  997.       strcat(ans, fn);
  998.       strcat(ans, ".msg");
  999.       if (filefind(ans, 0)) ans="";
  1000.      }
  1001.     while (ans=="");
  1002.     frename("edit.msg", ans);
  1003.     fseek(ndx_fil, 0, 2);
  1004.     mssg_time=curtime();
  1005.     ndx_write(0);;
  1006.    }
  1007.  else
  1008.    {
  1009.     fdelete("edit.msg");
  1010.    }
  1011. }
  1012.  
  1013.  
  1014. // Mark message record for deletion and delete message file
  1015. delete_mssg(int m_num)
  1016. {
  1017.  int position;
  1018.  str filnam[64], buf[64];
  1019.  position=ftell(ndx_fil);
  1020.  if (position==0) position=filesize(ndx_fil);
  1021.  position=position-110;
  1022.  do
  1023.   {
  1024.    fseek(ndx_fil, position, 0);
  1025.    ndx_read();
  1026.    if (mssg_num==m_num)
  1027.     {
  1028.      mssg_priv=2;
  1029.      fseek(ndx_fil, position, 0);
  1030.      ndx_write(0);;
  1031.      // delete message file
  1032.      itos(mssg_num, filnam);
  1033.      filnam=strcat("M", filnam);
  1034.      buf=host_message;
  1035.      filnam=strcat(buf, filnam);
  1036.      strcat(filnam, ".msg");
  1037.      fdelete(filnam);
  1038.      return;
  1039.     }
  1040.    position=position-110;
  1041.   }
  1042.  while (position > 0);
  1043. }
  1044.  
  1045.  
  1046. // Delete old and marked messages
  1047. update_ndx_file()
  1048. {
  1049.  str filnam[80];  //the new temp ndx filename
  1050.  str buf[80];     //general purpose & old ndx filename
  1051.  int f, tim;
  1052.  prints("Updating Message Index File");
  1053.  filnam = host_message;
  1054.  strCat(filnam, "temp.ndx");
  1055.  f=fopen(filnam, "w");
  1056.  fseek(ndx_fil, 0, 0);
  1057.  ndx_read();
  1058.  mssg_time=tim=curtime();
  1059.  ndx_write(f);
  1060.  mssg_time=0;
  1061.  do {
  1062.   if (!ndx_read())
  1063.    {
  1064.     mssg_time=tim;
  1065.     mssg_priv=2;
  1066.    }
  1067.   else
  1068.    if ((tim-mssg_time) > 684800)
  1069.     {
  1070.      // delete Old files
  1071.      buf="M";
  1072.      itos(mssg_num, filnam);
  1073.      filnam=strcat(buf, filnam);
  1074.      buf=host_message;
  1075.      filnam=strcat(buf, filnam);
  1076.      strcat(filnam, ".msg");
  1077.      fdelete(filnam);
  1078.     }
  1079.  } while ((tim-mssg_time) > 684800);    // one week
  1080.  do {
  1081.   if (mssg_priv < 2) ndx_write(f);
  1082.  } while (ndx_read());
  1083.  fclose(f);
  1084.  fclose(ndx_fil);
  1085.  filnam=host_message;
  1086.  strcat(filnam, "temp.ndx");
  1087.  buf=host_message;
  1088.  strcat(buf, "message.ndx");
  1089.  fdelete(buf);
  1090.  frename(filnam, buf);
  1091.  ndx_fil=fopen(buf, "r+");
  1092. }
  1093.  
  1094.  
  1095. ndx_read() {
  1096.  str buf[110], buf2[10];
  1097.  int n;
  1098.  if (feof(ndx_fil)) return 0;
  1099.  fread(buf, 110, ndx_fil);
  1100.  substr(buf, 0, 9, buf2);
  1101.  mssg_num=stoi(buf2);
  1102.  substr(buf, 9, 1, buf2);
  1103.  mssg_priv=stoi(buf2);
  1104.  substr(buf, 10, 31, mssg_to);
  1105.  do {
  1106.   substr(mssg_to, 0, strlen(mssg_to)-1, mssg_to);
  1107.  } while (subchr(mssg_to, strlen(mssg_to)-1)==' ');
  1108.  substr(buf, 40 , 31, mssg_from);
  1109.  do {
  1110.   substr(mssg_from, 0, strlen(mssg_from)-1, mssg_from);
  1111.  } while (subchr(mssg_from, strlen(mssg_from)-1)==' ');
  1112.  substr(buf, 70, 10, buf2);
  1113.  mssg_time=stoi(buf2);
  1114.  substr(buf, 80, 30, mssg_subj);
  1115.  return 1;
  1116. }
  1117.  
  1118. ndx_write(int fl)
  1119. {
  1120.  str buf[30];
  1121.  int hold_ndx;
  1122.  if (fl!=0)
  1123.   {
  1124.    hold_ndx=ndx_fil;
  1125.    ndx_fil=fl;
  1126.   }
  1127.  itos(mssg_num, buf);
  1128.  if (strlen(buf)<9)
  1129.   do
  1130.    strcat(buf, " ");
  1131.   while (strlen(buf) < 9);
  1132.  fwrite(buf, 9, ndx_fil);
  1133.  itos(mssg_priv, buf);
  1134.  fwrite(buf, 1, ndx_fil);
  1135.  buf=mssg_to;
  1136.  if (strlen(buf) < 30)
  1137.   do
  1138.    strcat(buf, " ");
  1139.   while (strlen(buf) < 30);
  1140.  fwrite(buf, 30, ndx_fil);
  1141.  buf=mssg_from;
  1142.  if (strlen(buf) < 30)
  1143.   do
  1144.    strcat(buf, " ");
  1145.   while (strlen(buf) < 30);
  1146.  fwrite(buf, 30, ndx_fil);
  1147.  itos(mssg_time, buf);
  1148.  if (strlen(buf)<10)
  1149.   do
  1150.    strcat(buf, " ");
  1151.   while (strlen(buf) < 10);
  1152.  fwrite(buf, 10, ndx_fil);
  1153.  if (strlen(mssg_subj)<30)
  1154.   do
  1155.    strcat(mssg_subj, " ");
  1156.   while (strlen(mssg_subj) < 30);
  1157.  fwrite(mssg_subj, 30, ndx_fil);
  1158.  if (fl!=0) ndx_fil=hold_ndx;
  1159. }
  1160.  
  1161.  
  1162. //////////////////////////////////////////////////////////////////////////////
  1163.  
  1164. type_our_file(str fname) {
  1165.   int f;
  1166.   str s[144];
  1167.  
  1168.   if ((f=type_file(fname)) == -1) {
  1169.     s=our_dir;
  1170.     strcat(s,fname);
  1171.     f=type_file(s);
  1172.     }
  1173.   return f;
  1174. }
  1175.  
  1176. //////////////////////////////////////////////////////////////////////////////
  1177.  
  1178. type_file(str fname) {
  1179.  
  1180.   int f, r_a_fl;
  1181.   str s[80];
  1182.   str buf[255], fname_b[80], fname_x[80];
  1183.   int cnt, ichar;
  1184.   int lines_sent = 0;
  1185.  
  1186.   r_a_fl=0;
  1187. //  fname_x = our_dir;
  1188.   strCat(fname_x, fname);
  1189.   if (strposi(fname, "." )==-1)
  1190.   {
  1191.    r_a_fl=2;
  1192.    fname_b=fname_x;
  1193.    strcat(fname_b, ".rip");
  1194.    if ((rip_on) and (filefind(fname_b, 0) != 0)) {}
  1195.    else
  1196.     {
  1197.      r_a_fl=1;
  1198.      fname_b=fname_x;
  1199.      strcat(fname_b, ".ans");
  1200.      if ((ansi_on) and (filefind(fname_b, 0) != 0)) {}
  1201.      else
  1202.       {
  1203.        r_a_fl=0;
  1204.        fname_b=fname_x;
  1205.        strcat(fname_b, ".txt");
  1206.       }
  1207.     }
  1208.     fname=fname_b;
  1209.    }
  1210.    f = fopen(fname, "r");
  1211.    if (!f)
  1212.      return -1;
  1213.  
  1214.   host_send("^M^J^J");
  1215.  
  1216.   while (1) {
  1217.     if (carrier_counts)
  1218.       if (!carrier()) {
  1219.         connection_lost = 1;
  1220.         finished_caller = 1;
  1221.         fclose(f);
  1222.         return 0;
  1223.       }
  1224.  
  1225.   if (R_A_Fl > 0) {
  1226.     if ((cnt=fread(buf, strMaxLen(buf), f)) <= 0) {
  1227.       fclose(f);
  1228.       return 1;
  1229.       }
  1230.     setchr(buf, cnt, 0);
  1231.     }
  1232.   else {
  1233.     if (fgets(buf, 80, f) == -1) {
  1234.       fclose(f);
  1235.       return 1;
  1236.     }
  1237.   }
  1238.   host_send(buf);
  1239.   if (r_a_fl==0) {
  1240.     host_send("^M^J");
  1241.     ++lines_sent;
  1242.  
  1243.     if (lines_sent >= 22) {
  1244.       lines_sent = 0;
  1245.       host_send("[More]");
  1246.       host_input(1);
  1247.  
  1248.       if (finished_caller) {       // if user inactivity
  1249.         fclose(f);
  1250.         return 0;
  1251.       }
  1252.  
  1253.       host_send("^H ^H^H ^H^H ^H^H ^H^H ^H^H ^H^H ^H");
  1254.     }
  1255.   }
  1256.     while (cinp_cnt()) {
  1257.       ichar = cgetc();
  1258.       if (ichar == '^C' || ichar == '^K') {
  1259.         host_send("^M^J");
  1260.         fclose(f);
  1261.         return 1;
  1262.       }
  1263.     }
  1264.   }
  1265. }
  1266.  
  1267. //////////////////////////////////////////////////////////////////////////////
  1268.  
  1269. host_send(str outstr) {
  1270.  
  1271.   printsc_trm(outstr);
  1272.   if (!local_mode)
  1273.     cputs(outstr);
  1274.  
  1275. }
  1276.  
  1277. //////////////////////////////////////////////////////////////////////////////
  1278.  
  1279. host_send_c(int chr) {
  1280.  
  1281.   printc(chr);
  1282.   if (!local_mode)
  1283.     cputc(chr);
  1284.  
  1285. }
  1286.  
  1287. //////////////////////////////////////////////////////////////////////////////
  1288.  
  1289. host_input_strn(str buf, int maximum, int echoable) {
  1290.  
  1291.   int i = 0, key;
  1292.  
  1293.   while (1) {
  1294.     key = host_input(echoable);
  1295.     if (!key) {               // timeout or user disconnect
  1296.       setchr(buf, 0, 0);      // set string to empty
  1297.       return 0;               // indicate there is a problem
  1298.     }
  1299.  
  1300.     if (key == '^M') {
  1301. //      if (!echoable) host_send("^H ");
  1302.       break;
  1303.       }
  1304.     if (key == 127 || key == 8) {
  1305.       if (i) {
  1306.         --i;
  1307.         host_send_c(key);
  1308.       }
  1309.       continue;
  1310.     }
  1311.     if (i < maximum)
  1312.       setchr(buf, i, key);
  1313.     ++i;
  1314.     if (maximum<=1) break;  //hotkeys if buffer only holds one
  1315.   }
  1316.  
  1317.   if (i > maximum)
  1318.     i = maximum;
  1319.  
  1320.   setchr(buf, i, '^0');
  1321.  
  1322.   if (subchr(buf, 0))
  1323.     return 1;
  1324.   else
  1325.     return 0;
  1326.  
  1327. }
  1328.  
  1329. //////////////////////////////////////////////////////////////////////////////
  1330.  
  1331. host_input(int echoable) {
  1332.  
  1333.   int c, t;
  1334.  
  1335.   t = timer_start(2400);         // 4 minutes inactivity allowed
  1336.  
  1337.   while (1) {
  1338.     if (time_up(t) && !direct_connect) {
  1339.       host_send("^M^J^M^JInactivity period too long. Connection terminated!^M^J");
  1340.       if (carrier_counts)
  1341.         hangup();
  1342.       finished_caller = 1;
  1343.       kill_user = 1;
  1344.       break;
  1345.     }
  1346.  
  1347.     if (carrier_counts)
  1348.       if (!carrier()) {
  1349.         prints("^M^JConnection has been lost, call terminated.^M^J");
  1350.         connection_lost = 1;
  1351.         finished_caller = 1;
  1352.         break;
  1353.       }
  1354.     if ((c = inkey()) != 0) {
  1355.       if (c == 27) {             // ESC key, sysop wants to exit
  1356.         finished_caller = 1;
  1357.           exit_requested = 1;
  1358.           break;
  1359.       }
  1360.       else if (c == 0x4f00) {    // END key, terminate user
  1361.         prints("^M^JUser terminated!");
  1362.         ustamp("User terminated!", 1, 1);
  1363.         if (carrier_counts)
  1364.           hangup();
  1365.  
  1366.         finished_caller = 1;
  1367.         kill_user = 1;
  1368.         access_level = 0;
  1369.         break;
  1370.       }
  1371.  
  1372.       else if (c <= 255) {
  1373.         if (c != 8 && c != 127)
  1374.           if ((!echoable)&& c != 13)
  1375.             host_send_c('*');
  1376.           else
  1377.             host_send_c(c);
  1378.         break;
  1379.       }
  1380.     }
  1381.  
  1382.     if (!local_mode)
  1383.       if (cinp_cnt())  {
  1384.         c = cgetc();
  1385.         if (c != 8 && c != 127)
  1386.           if ((!echoable)&& c != 13)
  1387.             host_send_c('*');
  1388.           else
  1389.             host_send_c(c);
  1390.         break;
  1391.       }
  1392.   }
  1393.  
  1394.   timer_free(t);                 // free existing timer
  1395.   if (finished_caller)
  1396.     return 0;                    // return 0 - no character
  1397.  
  1398.   return c;                      // return received/pressed character
  1399. }
  1400.  
  1401. //////////////////////////////////////////////////////////////////////////////
  1402.  
  1403.  
  1404. //  This routine maintains an ASCII file in the Telix files directory called
  1405. //    WHPASS.TXT.  The format for each line is:
  1406.  
  1407. //    name;password;working_dir;access_level  (optional comment)
  1408.  
  1409. //    The name, password, working_dir, and access_level fields MUST be
  1410. //    separated by semicolons
  1411.  
  1412. //    The working_dir field is optional (but the semicolons before and after
  1413. //    it are _NOT_).  If there's no working_dir field, the default host
  1414. //    upload and download direcories are used.
  1415.  
  1416. //  The routine searches the file for a line on which the "name" field
  1417. //    matches the global variable "current_caller"  (not case sensitive).
  1418.  
  1419. //  If a match is found, and the user can type a password that matches
  1420. //    the "password" field (not case sensitive), the routine returns
  1421. //    the integer "access_level".
  1422.  
  1423. //  If no match is found, the user is given an opportunity to register
  1424. //    (at access level 1).
  1425.  
  1426. //  If the user registers, the file is updated with the new user name,
  1427. //    password, and access level (1), and the routine returns 1.
  1428.  
  1429. //  If the user does not register, or if the user cannot match the password
  1430. //    in the file in "maxtries",  or if the user registers and cannot match
  1431. //    the password he/she chose in "maxtries", the routine returns 0.
  1432.  
  1433. setup_user (int maxtries) {
  1434.   str password_file[64], line_from_file[127], password_from_file[16],
  1435.       name_from_file[31], temporary[16], typed_password[16],
  1436.       working_dir[64], last_char[1];
  1437.  
  1438.   int password_file_handle, field_length, field_start,
  1439.       found_password = 0, access_from_file, counter = 0,
  1440.       file_ends_in_control_z = 0, line_number = 0, length;
  1441.   password_file = our_dir;
  1442.   strcat (password_file, "WHPASS.TXT");
  1443.  
  1444.   for (counter = 1; counter <= maxtries; counter = counter + 1) {
  1445.                       // Try to open password file
  1446.     if (password_file_handle = fopen (password_file, "r")) {
  1447.                         // Read next line from file.
  1448.       while (fgets (line_from_file, 64, password_file_handle) != -1) {
  1449.                         // Check for ^Z termination
  1450.         if (line_from_file == "^Z") {
  1451.           file_ends_in_control_z = 1;
  1452.           break;
  1453.         }
  1454.         line_number = line_number + 1;
  1455.                       // allow for empty or comment lines
  1456.                       // comment lines begin with ';'
  1457.         if (!strlen(line_from_file) || strchr(line_from_file, 0, ';')) {
  1458.                       // If line is long enough . . .
  1459.           if (strlen (line_from_file) >= min_user_name+4) {
  1460.                       // Get length of name
  1461.             if ( (field_length = strchr (line_from_file, 0, ';')) > 0) {
  1462.                       // Get name
  1463.               substr (line_from_file, 0, field_length, name_from_file);
  1464.                       // If name matches . . . .
  1465.               if (strcmpi (name_from_file, current_caller) == 0) {
  1466.                       // Get password
  1467.                 field_start = field_length + 1;
  1468.                 if ( (field_length = strchr (line_from_file, field_start, ';') - field_start) > 0) {
  1469.                   substr (line_from_file, field_start, field_length, password_from_file);
  1470.                       // Get working directory
  1471.                   field_start = field_start + field_length + 1;
  1472.                   if ( (field_length = strchr (line_from_file, field_start, ';') - field_start) >= 0) {
  1473.                     substr (line_from_file, field_start, field_length, working_dir);
  1474.                       // Get access level
  1475.                     field_start = field_start + field_length + 1;
  1476.                     substr (line_from_file, field_start, 1, temporary);
  1477.                     access_from_file = stoi (temporary);
  1478.                       // Set flag that we got an old user
  1479.                     found_password = 1;
  1480.                     break;
  1481.                   }
  1482.                   else password_file_error (line_number, line_from_file, "no third semicolon");
  1483.                 }
  1484.                 else password_file_error (line_number, line_from_file, "no second semicolon");
  1485.               }
  1486.             }
  1487.             else password_file_error (line_number, line_from_file, "no first semicolon");
  1488.           }
  1489.           else password_file_error (line_number, line_from_file, "line too short");
  1490.         }
  1491.       }
  1492.       fclose (password_file_handle);
  1493.     }
  1494.     else if (password_file_handle = fopen(password_file, 'W')) {  // no password file. Make one.
  1495.       fputs(";WHPASS.TXT - WinHost user data file^M^J", password_file_handle);
  1496.       fputs(";format: <NAME>;<PASSWORD>;<WORK_DIR>;<ACCESS> <COMMENT>^M^J", password_file_handle);
  1497.       fclose(password_file_handle);
  1498.     }
  1499.  
  1500.     if (found_password)
  1501.       break;
  1502.     else {
  1503.       host_send ("^M^JNo user ^"");
  1504.       host_send (current_caller);
  1505.       host_send ("^" on file; ");
  1506.       host_send ("Re-type name? (y/n): ");
  1507.       host_input_strn (temporary, 1, 1);
  1508.       host_send ("^M^J");
  1509.  
  1510.       if (strcmpi(temporary, "y"))
  1511.         break;
  1512.       else
  1513.         get_user_name();
  1514.     }
  1515.   }
  1516.  
  1517.   if (found_password) {
  1518.                       // Password is on file; ask for it
  1519.     host_send ("Password: ");
  1520.     for (counter = 1; counter <= maxtries; ++counter) {
  1521.       host_input_strn (typed_password, 16, 0);
  1522.                       // If a match
  1523.       if (!strcmpi (typed_password, password_from_file)) {
  1524.         host_send ("^M^J");
  1525.           // If the user has a working directory ...
  1526.         if (strlen(working_dir)) {
  1527.             // Check for a "\" on the end and add it if necessary
  1528.           length = strlen(working_dir);
  1529.           substr (working_dir, length - 1, 1, last_char);
  1530.           if (strcmpi (last_char, "\"))
  1531.             strcat (working_dir, "\");
  1532.             // Establish download & upload directories
  1533.           strupper (working_dir);
  1534.           if (check_directory (working_dir)) {
  1535.             _down_dir = working_dir;
  1536.             _up_dir = working_dir;
  1537.             user_has_own_dir = 1;
  1538.           }
  1539.           else {
  1540.             prints ("Using defaults");
  1541.             ustamp (working_dir, 1, 0);
  1542.             ustamp (" does not exist, using default", 0, 1);
  1543.           }
  1544.         }
  1545.           // Return the user's access level
  1546.         return (access_from_file);
  1547.       }
  1548.       if (counter < maxtries) {
  1549.         host_send ("^M^JDoes not match password on file!");
  1550.         host_send ("^M^JRe-type name? (y/N): ");
  1551.         host_input_strn (temporary, 1, 1);
  1552.         host_send ("^M^J^J");
  1553.  
  1554.         if (!strcmpi (temporary, "y")) {
  1555.           get_user_name();
  1556.           host_send("Password: ");
  1557.           }
  1558.         else host_send("Re-type password: ");
  1559.       }
  1560.       else
  1561.         host_send ("^M^JMaximum number of tries exceeded!^M^J");
  1562.  
  1563.     }
  1564.   }
  1565.                       // Password is not on file
  1566.   else if (!closed_sys) {
  1567.                       // Offer chance to register
  1568. //    host_send ("No user  ^"");
  1569. //    host_send (current_caller);
  1570. //    host_send ("^"  found in user file.^M^J");
  1571.     host_send ("Do you want to register? (y/N): ");
  1572.     host_input_strn (temporary, 1, 1);
  1573.     host_send ("^M^J");
  1574.                       // If user doesn't want to register
  1575.     if (not ((temporary == "Y") || (temporary == "y")))
  1576.       return (0);
  1577.                       // If user wants to register
  1578.     host_send ("Pick a password (16 characters maximum): ");
  1579.     host_input_strn (password_from_file, 16, 0);
  1580.                       // Make sure password is right
  1581.     host_send ("^M^JRe-enter your password to verify: ");
  1582.     for (counter = 1; counter <= maxtries; counter = counter + 1) {
  1583.       host_input_strn (typed_password, 16, 0);
  1584.                       // If all is ok
  1585.       if (strcmpi (typed_password, password_from_file) == 0) {
  1586.                       // Build new line for password file
  1587.         line_from_file = current_caller;
  1588.         strcat (line_from_file, ";");
  1589.         strcat (line_from_file, password_from_file);
  1590.         strcat (line_from_file, ";;1 **NEW USER** ");
  1591.         date (curtime(), temporary);
  1592.         strcat (line_from_file, temporary);
  1593.                       // Open password file for appending
  1594.         password_file_handle = fopen(password_file, 'a');
  1595.         if (file_ends_in_control_z)
  1596.           fseek (password_file_handle, -1, 2);
  1597.                       // Now we can write the line
  1598.         fwrite (line_from_file, strlen (line_from_file), password_file_handle);
  1599.         fwrite ("^M^J", 2, password_file_handle);
  1600.         fclose (password_file_handle);
  1601.         host_send ("^M^J");
  1602.         return (1);   // Return access level
  1603.       }
  1604.       if (counter < maxtries)
  1605.         host_send ("^M^JDoes not match!  Please try again: ");
  1606.       else
  1607.         host_send ("^M^JMaximum number of tries exceeded!^M^J");
  1608.     }
  1609.   }
  1610.   return (0);
  1611. }
  1612.  
  1613. //////////////////////////////////////////////////////////////////////////////
  1614. // A routine to print an error message to the local screen when something
  1615. //    is wrong with the password file
  1616.  
  1617. password_file_error (int line_number, str line, str error_specifier) {
  1618.  
  1619.   str line_number_string[4];
  1620.  
  1621.   itos (line_number, line_number_string);
  1622.  
  1623.   prints ("");
  1624.   printsc ("Bad line ");
  1625.   printsc (line_number_string);
  1626.   prints (" in password file:");
  1627.   printsc ("   ^"");
  1628.   printsc (line);
  1629.   prints ("^"");
  1630.   prints (error_specifier);
  1631.  
  1632.   return (1);
  1633. }
  1634.  
  1635. //////////////////////////////////////////////////////////////////////////////
  1636. // returns TRUE if passed filespec is just a filename. Also handles the
  1637. // forward slash as a path separator.
  1638.  
  1639. just_filename(str filespec) {
  1640.  
  1641.   int slash, space;
  1642.  
  1643.   if (strpos(filespec, ":", 0) != -1)
  1644.     return 0;
  1645.   if (strpos(filespec, "\", 0) != -1)
  1646.     return 0;
  1647.   if ((slash = strpos(filespec, "/")) == -1)
  1648.     return 1;
  1649.  
  1650.   space = strpos(filespec, " ");
  1651.   if (space == -1)
  1652.     return 0;
  1653.   if (space < slash)
  1654.     return 1;
  1655.  
  1656.   return 0;
  1657.  
  1658. }
  1659.  
  1660. //////////////////////////////////////////////////////////////////////////////
  1661.  
  1662. host_show_directory (str dir_spec) {
  1663.   str file_name[13], f_name_ext[12], f_size_str[20], f_date_str[20],
  1664.       f_time_str[20], buffer[80], path[67], full_name[80],
  1665.       temp[26], hours_str[2], minutes_str[2], seconds_str[2];
  1666.  
  1667.   int file_exists, fsize, ftime, lines, dot_pos, bps, seconds,
  1668.       minutes, hours;
  1669.  
  1670.   bps = get_baud (1);
  1671.  
  1672.   fnstrip (dir_spec, 12, path);
  1673.  
  1674.   file_exists = FileFind (dir_spec, 0, file_name);
  1675.  
  1676.   if (!file_exists) {
  1677.     host_send ("^M^JNo matching file found.^M^J");
  1678.   }
  1679.   else {
  1680.     lines = 2;
  1681.     host_send ("        Name          Size      Date     Time^M^J");
  1682.   }
  1683.  
  1684.   while (file_exists) {
  1685.  
  1686.     // Get the file size, as a string, with commas where appropriate
  1687.     fsize = FileSize ("");
  1688.     ItoS (fsize, temp);
  1689.     insert_commas (temp, f_size_str);
  1690.  
  1691.     // Get the file date and time as a string
  1692.     ftime = FileTime ("");
  1693.     Date (ftime, f_date_str);
  1694.     Time (ftime, f_time_str);
  1695.  
  1696.     // Estimate how long it'll take to transfer the file with Zmodem
  1697.     seconds = (fsize*10)/bps;
  1698.     // Guess at about 95% efficiency
  1699.     seconds = seconds + seconds/20;
  1700.     if (seconds == 0) {
  1701.       seconds = 1;
  1702.     }
  1703.     minutes = seconds/60;
  1704.     seconds = seconds - minutes*60;
  1705.     hours = minutes/60;
  1706.     minutes = minutes - hours*60;
  1707.  
  1708.     // Convert the transfer time to a string
  1709.     if (seconds < 10) {
  1710.       ItoS (seconds, temp);
  1711.       seconds_str = "0";
  1712.       strcat (seconds_str, temp);
  1713.     }
  1714.     else {
  1715.       ItoS (seconds, seconds_str);
  1716.     }
  1717.     if (minutes < 10) {
  1718.       ItoS (minutes, temp);
  1719.       minutes_str = "0";
  1720.       strcat (minutes_str, temp);
  1721.     }
  1722.     else {
  1723.       ItoS (minutes, minutes_str);
  1724.     }
  1725.     ItoS (hours, hours_str);
  1726.  
  1727.     // Stuff the buffer with just enough spaces so the periods in the
  1728.     //  file names line up
  1729.     dot_pos = strpos (file_name, ".", 0);
  1730.     if (dot_pos > 0) {
  1731.       substr ("        ", 0, 8 - dot_pos, buffer);
  1732.     }
  1733.     else {
  1734.       substr ("        ", 0, 8 - strlen (file_name), buffer);
  1735.     }
  1736.  
  1737.     // Put the file name into the buffer
  1738.     strcat (buffer, file_name);
  1739.  
  1740.     // Append just enough spaces to the buffer to make the right sides of
  1741.     //  the file sizes line up
  1742.     substr ("              ", 0, 26 - strlen (buffer) - strlen (f_size_str), temp);
  1743.     strcat (buffer, temp);
  1744.  
  1745.     // Put the file size into the buffer
  1746.     strcat (buffer, f_size_str);
  1747.  
  1748.     // Put the file date and time into the buffer
  1749.     strcat (buffer, "  ");
  1750.     strcat (buffer, f_date_str);
  1751.     strcat (buffer, " ");
  1752.     strcat (buffer, f_time_str);
  1753.  
  1754.     // Put the transfer time into the buffer
  1755. //  if (hours < 10) {
  1756. //    strcat (buffer, "   ");
  1757. //  }
  1758. //  else {
  1759. //    strcat (buffer, "  ");
  1760. //  }
  1761. //  strcat (buffer, hours_str);
  1762. //  strcat (buffer, ":");
  1763. //  strcat (buffer, minutes_str);
  1764. //  strcat (buffer, ":");
  1765. //  strcat (buffer, seconds_str);
  1766.  
  1767.     // See if we've filled a screen yet ...
  1768.     if (lines > 23) {
  1769.       host_send ("[More]");
  1770.       host_input (1);
  1771.       lines = 0;
  1772.     }
  1773.     else {
  1774.       lines = lines + 1;
  1775.     }
  1776.  
  1777.     // Send the line
  1778.     host_send (buffer);
  1779.     host_send ("^M^J");
  1780.  
  1781.     file_exists = FileFind ("", 0, file_name);
  1782.   }
  1783.  
  1784. }
  1785.  
  1786. //////////////////////////////////////////////////////////////////////////////
  1787.  
  1788. get_extension(str file_name, str result) {
  1789.    int dot_pos;
  1790.    dot_pos = strpos (file_name, ".", 0);
  1791.    result = "";
  1792.    if (dot_pos > 0) {
  1793.      substr(file_name, dot_pos+1, 3, result);
  1794.    }
  1795. }
  1796.  
  1797. // Insert commas into a string representation of an integer, up to
  1798. //  999,999,999,999 (the largest SALT integer is 2,147,483,647)
  1799.  
  1800. insert_commas (str input, str output) {
  1801.  
  1802.   str tmp1[15], tmp2[15];
  1803.   int len, delta;
  1804.  
  1805.   output = input;
  1806.  
  1807.   for (delta = 3; delta <= 11; delta = delta + 4) {
  1808.     if ((len = strlen (output)) > delta) {
  1809.       substr (output, 0, len - delta, tmp1);
  1810.       substr (output, len - delta, 15, tmp2);
  1811.       output = tmp1;
  1812.       strcat (output, ",");
  1813.       strcat (output, tmp2);
  1814.     }
  1815.     else {
  1816.       break;
  1817.     }
  1818.   }
  1819. }
  1820.  
  1821. //////////////////////////////////////////////////////////////////////////////
  1822.  
  1823. send_goodbye () {
  1824.   str s[80];
  1825.  
  1826.   if (type_our_file("GOODBYE") == -1)
  1827.     host_send ("^M^JGoodbye^M^J");
  1828.  
  1829.   delay_scr(20);
  1830. }
  1831.  
  1832. //////////////////////////////////////////////////////////////////////////////
  1833.  
  1834. get_user_name() {
  1835.   int tries=5;
  1836.   str temporary[1];
  1837.  
  1838.   while (tries) {
  1839.     host_send("Please enter your full name: ");
  1840.     host_input_strn(current_caller, 30, 1);
  1841.     host_send("^M^J");
  1842.  
  1843.     if (finished_caller) {
  1844.       access_level = 0;
  1845.       return 0;
  1846.     }
  1847.  
  1848.     if (strlen(current_caller) >= min_user_name)
  1849.       break;
  1850.     else
  1851.       host_send ("Name too short!^M^J");
  1852.     --tries;
  1853.   }
  1854.   return (tries>0);
  1855. }
  1856.