home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 3 Comm / 03-Comm.zip / mincom15.zip / dial.c < prev    next >
C/C++ Source or Header  |  1993-10-20  |  21KB  |  1,000 lines

  1. /*
  2.  * This file is part of the Minicom Communications Program,
  3.  * written by Miquel van Smoorenburg 1991/1992/1993.
  4.  */
  5. #include <sys/types.h>
  6. #if defined (_POSIX_SOURCE) || defined(_BSD43)
  7. #  include <unistd.h>
  8. #  include <stdlib.h>
  9. #  ifdef _MINIX
  10. #    undef NULL
  11. #  endif
  12. #endif
  13. #if defined(_BSD43) || defined (_SYSV)
  14. #  define NOSTREAMS
  15. #  include <sys/file.h>
  16. #endif
  17. #include <string.h>
  18. #ifdef _MINIX
  19. #  undef NULL
  20. #endif
  21. #include <stdio.h>
  22. #include <sys/stat.h>
  23. #ifdef linux
  24. #  include <sys/ioctl.h>
  25. #  include <sys/kd.h>
  26. #  include <sys/time.h>
  27. #endif
  28. #include "keyboard.h"
  29. #include "window.h"
  30. #include "minicom.h"
  31. #include "vt100.h"
  32. #include "configsym.h"
  33.  
  34. /* Dialing directory. */
  35. struct dialent {
  36.   char name[32];
  37.   char number[16];
  38.   char script[16];
  39.   char username[32];
  40.   char password[32];
  41.   char term;
  42.   char baud[8];
  43.   char parity[2];
  44.   char dialtype;
  45.   char localecho;
  46.   char bits[2];
  47.   struct dialent *next;
  48. };
  49.  
  50. /* Version info. */
  51. #define DIALMAGIC 0x55AA
  52. struct dver {
  53.   short magic;
  54.   short version;
  55.   short size;
  56.   short res1;
  57.   short res2;
  58.   short res3;
  59.   short res4;
  60. };
  61.  
  62. #define dialentno(di, no) ((struct dialent *)((char *)(di) + ((no) * sizeof(struct dialent))))  
  63.  
  64. static struct dialent *dialents;
  65. static int nrents = 1;
  66. static int newtype;
  67. /* Access to ".daildir" denied? */
  68. static int dendd = 0;
  69.  
  70. /*
  71.  * Functions to talk to the modem.
  72.  */
  73.  
  74. /*
  75.  * Send a string to the modem.
  76.  */
  77. void mputs(s)
  78. char *s;
  79. {
  80.   char c;
  81.  
  82.   while(*s) {
  83.       if (*s == '^' && (*(s + 1))) {
  84.           s++;
  85.           if (*s == '^')
  86.               c = *s;
  87.           else
  88.               c = (*s) & 31;
  89.       } else
  90.           c = *s;
  91.       if (c == '~')
  92.           sleep(1);
  93.       else    
  94.           write(portfd, &c, 1);
  95.       s++;
  96.   }
  97. }
  98.   
  99. /*
  100.  * Initialize the modem.
  101.  */ 
  102. void modeminit()
  103. {
  104.   WIN *w;
  105.  
  106.   if (P_MINIT[0] == '\0') return;
  107.  
  108.   w = tell("Initializing Modem");
  109.   m_dtrtoggle(portfd);
  110.   mputs(P_MINIT);
  111.   wclose(w, 1);
  112. }
  113.  
  114. /*
  115.  * Reset the modem.
  116.  */
  117. void modemreset()
  118. {
  119.   WIN *w;
  120.  
  121.   if (P_MRESET[0] == '\0') return;
  122.  
  123.   w = tell("Resetting Modem");
  124.   mputs(P_MRESET);
  125.   sleep(1);
  126.   wclose(w, 1);
  127. }
  128.  
  129. /*
  130.  * Hang the line up.
  131.  */
  132. void hangup()
  133. {
  134.   WIN *w;
  135.  
  136.   w = tell("Hanging up");
  137.  
  138.   if (P_MDROPDTR[0] == 'Y') {
  139.       m_dtrtoggle(portfd);
  140.       /* Sometimes the minix tty driver does not see
  141.        * that DCD has dropped.
  142.        * (This is a kludge!)
  143.        */
  144.       m_setdcd(portfd, 0);
  145.   } else {
  146.       mputs(P_MHANGUP);
  147.       sleep(1);
  148.   }
  149.   /* If we don't have DCD support fake DCD dropped */
  150.   bogus_dcd = 0;
  151.   wclose(w, 1);
  152. }
  153.  
  154. /*
  155.  * This seemed to fit best in this file
  156.  * Send a break signal.
  157.  */
  158. void sendbreak()
  159. {
  160.   WIN *w;
  161.   
  162.   w = tell("Sending BREAK");
  163.   wcursor(w, CNONE);
  164.  
  165.   m_break(portfd);
  166.   wclose(w, 1);
  167. }
  168.   
  169. WIN *dialwin;
  170. int dialtime;
  171.  
  172. #if defined (__linux__) && defined(_SELECT)
  173.  
  174. /*
  175.  * Play music until key is pressed.
  176.  */
  177. void music()
  178. {
  179.   int x, i, k;
  180.   int consolefd = 0;
  181.  
  182.   /* If we're in X, we have to explicitly use the console */
  183.   if (strncmp(getenv("TERM"), "xterm", 5) == 0 &&
  184.     strcmp(getenv("DISPLAY"), ":0.0") == 0) {
  185.     consolefd = open("/dev/console", O_WRONLY);
  186.     if (consolefd < 0) consolefd = 0;
  187.   }
  188.  
  189.   /* Tell keyboard handler what we want. */
  190.   keyboard(KSIGIO, 0);
  191.  
  192.   /* And loop forever :-) */
  193.   for(i = 0; i < 9; i++) {
  194.     k = 2000 - 200 * (i % 3);
  195.     (void) ioctl(consolefd, KIOCSOUND, k);
  196.  
  197.     /* Check keypress with timeout 160 ms */
  198.     x = check_io(-1, 0, 160, NULL, NULL);
  199.     if (x & 2) break;
  200.   }
  201.   (void) ioctl(consolefd, KIOCSOUND, 0);
  202.  
  203.   /* Wait for keypress and absorb it */
  204.   while((x & 2) == 0) x = check_io(-1, 0, 10000, NULL, NULL);
  205.   (void) keyboard(KGETKEY, 0);
  206. }
  207. #endif
  208.  
  209. /*
  210.  * The dial has failed. Tell user.
  211.  * Count down until retrytime and return.
  212.  */
  213. static int dialfailed(s, rtime)
  214. char *s;
  215. int rtime;
  216. {
  217.   int f, x;
  218.  
  219.   wlocate(dialwin, 1, 5);
  220.   wprintf(dialwin, "    No connection: %s.\n", s);
  221.   if (rtime < 0) {
  222.       wprintf(dialwin, "   Press any key to continue..    ");
  223.     if (check_io(-1, 0, 10000, NULL, NULL) & 2) 
  224.         (void) keyboard(KGETKEY, 0);
  225.       return(0);
  226.   }
  227.   wprintf(dialwin, "     Retry in %2d seconds         ", rtime);
  228.   
  229.   for(f = rtime - 1; f >= 0; f--) {
  230.     x = check_io(-1, 0, 1000, NULL, NULL);
  231.     if (x & 2) {
  232.         /* Key pressed - absorb it. */
  233.         (void) keyboard(KGETKEY, 0);
  234.         return(-1);
  235.     }
  236.       wlocate(dialwin, 14, 6);
  237.       wprintf(dialwin, "%2d ", f);
  238.   }
  239.   sleep(1); /* Allow modem time to hangup if redial time == 0 */
  240.   wlocate(dialwin, 1, 5);
  241.   wprintf(dialwin, "                              \n");
  242.   wprintf(dialwin, "                        ");
  243.   return(0);
  244. }
  245.  
  246. /*
  247.  * Dial a number, and display the name.
  248.  */
  249. int dial(name, num, keypress, dialtype)
  250. char *name;
  251. char *num;
  252. int keypress;
  253. int dialtype;
  254. {
  255.   char *s, *t;
  256.   int f, x, nb, retst = -1;
  257.   int modidx, retries = 0;
  258.   int maxretries = 1, rdelay = 45;
  259.   char *reason = "Max retries";
  260.   time_t now, last;
  261.   char buf[128];
  262.   char modbuf[128];
  263.  
  264.   dialwin = wopen(18, 9, 62, 15, BSINGLE, stdattr, MFG, MBG, 0, 0, 1);
  265.   wtitle(dialwin, TMID, "Autodial");
  266.   wcursor(dialwin, CNONE);
  267.  
  268.   wputs(dialwin, "\n");
  269.   wprintf(dialwin, " Dialing : %s\n", name);
  270.   wprintf(dialwin, "      At : %s\n", num);
  271.   wredraw(dialwin, 1);
  272.  
  273.   /* Tell keyboard routines we need them. */
  274.   keyboard(KSIGIO, 0);
  275.  
  276.   maxretries = atoi(P_MRETRIES);
  277.   if (maxretries <= 0) maxretries = 1;
  278.   rdelay = atoi(P_MRDELAY);
  279.   if (rdelay < 0) rdelay = 0;
  280.  
  281.   /* Main retry loop of dial() */
  282. MainLoop:
  283.   while(++retries <= maxretries) {
  284.  
  285.     /* Calculate dial time */
  286.     dialtime = atoi(P_MDIALTIME);
  287.     if (dialtime == 0) dialtime = 45;
  288.     time(&now);
  289.     last = now;
  290.  
  291.       /* Show used time */
  292.     wlocate(dialwin, 0, 3);
  293.     wprintf(dialwin, "    Time : %-3d", dialtime);
  294.     if (maxretries > 1) wprintf(dialwin, "     Attempt #%d", retries);
  295.     wputs(dialwin, "\n\n\n Press any key to cancel dialing");
  296.     
  297.     /* Start the dial */
  298.     m_flush(portfd);
  299.     switch(dialtype) {
  300.         case 0:
  301.             mputs(P_MDIALPRE);
  302.             mputs(num);
  303.             mputs(P_MDIALSUF);
  304.             break;
  305.         case 1:
  306.             mputs(P_MDIALPRE2);
  307.             mputs(num);
  308.             mputs(P_MDIALSUF2);
  309.             break;
  310.         case 2:
  311.             mputs(P_MDIALPRE3);
  312.             mputs(num);
  313.             mputs(P_MDIALSUF3);
  314.             break;
  315.     }
  316.  
  317.     /* Wait 'till the modem says something */
  318.     modbuf[0] = 0;
  319.     modidx = 0;
  320.     s = buf;
  321.     buf[0] = 0;
  322.     while(dialtime > 0) {
  323.         if (*s == 0) {
  324.         x = check_io(portfd, 0, 1000, buf, NULL);
  325.         s = buf;
  326.         }
  327.         if (x & 2) {
  328.         /* Key was pressed - cancelled. */
  329.         mputs(P_MDIALCAN);
  330.         (void) keyboard(KGETKEY, 0);
  331.         (void) keyboard(KSTOP, 0);
  332.         wclose(dialwin, 1);
  333.         return(retst);
  334.         }
  335.         if (x & 1) {
  336.         /* Data available from the modem. Put in buffer. */
  337.         if (*s == '\r' || *s == '\n') {
  338.             /* We look for [\r\n]STRING[\r\n] */
  339.             modbuf[modidx] = 0;
  340.             modidx = 0;
  341.         } else if (modidx < 127) {
  342.             /* Normal character. Add. */
  343.             modbuf[modidx++] = *s;
  344.             modbuf[modidx] = 0;
  345.         }
  346.         /* Skip to next received char */
  347.         if (*s) s++;
  348.         /* Only look when we got a whole line. */
  349.         if (modidx == 0 &&
  350.             !strncmp(modbuf, P_MCONNECT, strlen(P_MCONNECT))) {
  351.             retst = 0;
  352.             /* Try to do auto-bauding */
  353.             if (sscanf(s + strlen(P_MCONNECT), "%d", &nb) == 1)
  354.                 retst = nb;
  355.  
  356.             /* Try to figure out if this system supports DCD */
  357.             f = m_getdcd(portfd);
  358.             bogus_dcd = 1;
  359.  
  360.             wlocate(dialwin, 1, 6);
  361.             if (keypress) {
  362.                 wputs(dialwin,
  363.                      "Connected. Press any key to continue");
  364. #if defined (__linux__) && defined(_SELECT)
  365.                 music();
  366. #else
  367.                 x = check_io(-1, 0, 0, NULL, NULL);
  368.                 if ((x & 2) == 2)
  369.                     (void) keyboard(KGETKEY, 0);
  370. #endif
  371.             }
  372.             keyboard(KSTOP, 0);
  373.             wclose(dialwin, 1);
  374.             dialwin = NIL_WIN;
  375.             return(retst);
  376.         }
  377.         for(f = 0; f < 3; f++) {
  378.             if (f == 0) t = P_MNOCON1;
  379.             if (f == 1) t = P_MNOCON2;
  380.             if (f == 2) t = P_MNOCON3;
  381.             if (f == 3) t = P_MNOCON4;
  382.             if ((*t) && (!strncmp(modbuf, t, strlen(t)))) {
  383.                 if (retries < maxretries) {
  384.                     x = dialfailed(t, rdelay);
  385.                     if (x < 0) {
  386.                         keyboard(KSTOP, 0);
  387.                         wclose(dialwin, 1);
  388.                         return(retst);
  389.                     }
  390.                 }
  391.                 if (maxretries == 1) reason = t;
  392.                 goto MainLoop;
  393.             }
  394.         }
  395.         }
  396.  
  397.         /* Do timer routines here. */
  398.         time(&now);
  399.         if (last != now) {
  400.         dialtime -= (now - last);
  401.         if (dialtime < 0) dialtime = 0;
  402.         wlocate(dialwin, 11, 3);
  403.         wprintf(dialwin, "%-3d  ", dialtime);
  404.         if (dialtime <= 0) {
  405.             reason = "Timeout";
  406.             retst = -1;
  407.             if (retries < maxretries) {
  408.                 x = dialfailed(reason, rdelay);
  409.                 if (x < 0) {
  410.                     keyboard(KSTOP, 0);
  411.                     wclose(dialwin, 1);
  412.                     return(retst);
  413.                 }
  414.             }
  415.         }
  416.         }
  417.         last = now;
  418.     }
  419.   } /* End of main while cq MainLoop */    
  420.   dialfailed(reason, -1);
  421.   keyboard(KSTOP, 0);
  422.   wclose(dialwin, 1);
  423.   return(retst);
  424. }
  425.  
  426. /*
  427.  * Create an empty entry.
  428.  */
  429. static struct dialent *mkstdent()
  430. {
  431.   struct dialent *d;
  432.   
  433.   d = (struct dialent *)malloc(sizeof (struct dialent));
  434.   
  435.   if (d == (struct dialent *)0) return(d);
  436.  
  437.   d->name[0] = 0;
  438.   d->number[0] = 0;
  439.   d->script[0] = 0;
  440.   d->username[0] = 0;
  441.   d->password[0] = 0;
  442.   d->term = 1;
  443.   d->dialtype = 0;
  444.   d->localecho = 0;
  445.   strcpy(d->baud, DEF_BAUD);
  446.   strcpy(d->bits, "8");
  447.   strcpy(d->parity, "N");
  448.   d->next = (struct dialent *)0;
  449.  
  450.   return(d);
  451. }
  452.  
  453. /*
  454.  * Read in the dialing directory from $HOME/.dialdir
  455.  */
  456. int readdialdir()
  457. {
  458.   long size;
  459.   FILE *fp;
  460.   char dfile[256];
  461.   static int didread = 0;
  462.   int f;
  463.   struct dialent *d, *prev = (struct dialent *)0;
  464.   struct stat stt;
  465.   struct dver dial_ver;
  466.  
  467.   if (didread) return(0);
  468.   didread = 1;
  469.   nrents = 1;
  470.  
  471.   /* Construct path */
  472.   sprintf(dfile, "%s/.dialdir", homedir);
  473.  
  474.   /* Check if it's readable IF it exists */
  475.   if (stat(dfile, &stt) >= 0 && access(dfile, R_OK) < 0) {
  476.     werror("Cannot open ~/.dialdir: permission denied");
  477.     dialents = mkstdent();
  478.     dendd = 1;
  479.     return(0);
  480.   }
  481.   if ((fp = fopen(dfile, "r")) == (FILE *)NULL) {
  482.       dialents = mkstdent();
  483.       return(0);
  484.   }
  485.   /* Get size of the file */
  486.   fseek(fp, 0L, SEEK_END);
  487.   size = ftell(fp);
  488.   if (size == 0) {
  489.       dialents = mkstdent();
  490.       fclose(fp);
  491.       return(0);
  492.   }
  493.  
  494.   /* Get version of the dialing directory */
  495.   fseek(fp, 0L, SEEK_SET);
  496.   fread(&dial_ver, sizeof(dial_ver), 1, fp);
  497.   if (dial_ver.magic != DIALMAGIC) {
  498.     /* First version without version info. */
  499.     dial_ver.version = 0;
  500.     fseek(fp, 0L, SEEK_SET);
  501.   } else
  502.     size -= sizeof(dial_ver);
  503.  
  504.   if (size % sizeof(struct dialent) != 0) {
  505.       werror("Phonelist garbled");
  506.       fclose(fp);
  507.       unlink(dfile);
  508.       dialents = mkstdent();
  509.       return(-1);
  510.   }
  511.  
  512.   /* Read in the dialing entries */
  513.   nrents = size / sizeof(struct dialent);
  514.   if (nrents == 0) {
  515.     dialents = mkstdent();
  516.     nrents = 1;
  517.     fclose(fp);
  518.     return(0);
  519.   }
  520.   for(f = 1; f <= nrents; f++) {
  521.       if ((d = (struct dialent *)malloc(sizeof (struct dialent))) ==
  522.           (struct dialent *)0) {
  523.               if(f == 1)
  524.                 dialents = mkstdent();
  525.             else
  526.                 prev->next = (struct dialent *)0;
  527.  
  528.               werror("Out of memory while reading dialing directory");
  529.             fclose(fp);
  530.               return(-1);
  531.       }
  532.       fread((char *)d, sizeof(struct dialent), (size_t)1, fp);
  533.       if (prev != (struct dialent *)0)
  534.           prev->next = d;
  535.       else
  536.           dialents = d;
  537.       prev = d;
  538.     /* Adjust for version. */
  539.     if (dial_ver.version == 0) {
  540.         d->dialtype = 0;
  541.         d->localecho = 0;
  542.     }
  543.   }
  544.   d->next = (struct dialent *)0;
  545.   fclose(fp);
  546.   return(0);
  547. }
  548.  
  549. /*
  550.  * Write the new $HOME/.dialdir
  551.  */
  552. static void writedialdir()
  553. {
  554.   struct dialent *d;
  555.   char dfile[256];
  556.   FILE *fp;
  557.   int ret;
  558.   struct dver dial_ver;
  559.  
  560.   /* Make no sense if access denied */
  561.   if (dendd) return;
  562.  
  563.   sprintf(dfile, "%s/.dialdir", homedir);
  564.  
  565.   if ((ret = waccess(dfile)) < 0 || (fp = fopen(dfile, "w")) == (FILE *)0) {
  566.       werror("Can't write to ~/.dialdir");
  567.     dendd = 1;
  568.       return;
  569.   }
  570.   if (ret == A_OK_NOTEXIST) {
  571. #ifndef DEBUG
  572.       /* FIXME: should use fchown and fchmod */
  573. #ifndef HAS_FCHOWN
  574.     chown(dfile, real_uid, real_gid);
  575.     chmod(dfile, 0600);
  576. #else
  577.     fchown(fileno(fp), real_uid, real_gid);
  578.     fchmod(fileno(fp), 0600);
  579. #endif
  580. #endif
  581.   }
  582.   d = dialents;
  583.   /* Set up version info. */
  584.   dial_ver.magic = DIALMAGIC;
  585.   dial_ver.version = 1;
  586.   fwrite(&dial_ver, sizeof(dial_ver), 1, fp);
  587.  
  588.   /* Write dialing directory */
  589.   while(d) {
  590.       if (fwrite(d, sizeof(struct dialent), (size_t)1, fp) != 1) {
  591.           werror("Error writing ~/.dialdir!");
  592.           fclose(fp);
  593.           return;
  594.       }
  595.       d = d->next;
  596.   }
  597.   fclose(fp);
  598. }
  599.  
  600.  
  601. /*
  602.  * Get entry "no" in list.
  603.  */
  604. static struct dialent *getno(no)
  605. int no;
  606. {
  607.   struct dialent *d;
  608.   
  609.   d = dialents;
  610.   
  611.   if (no >= nrents) return((struct dialent *)NULL);
  612.  
  613.   while(no--) d = d->next;
  614.   return(d);
  615. }
  616.  
  617. static char *te[] = { "VT100", "MINIX", "ANSI " };
  618.  
  619. /*
  620.  * Edit an entry.
  621.  */
  622. static void dedit(d)
  623. struct dialent *d;
  624. {
  625.   WIN *w;
  626.   int c;
  627.   
  628.   w = wopen(5, 5, 75, 15, BDOUBLE, stdattr, MFG, MBG, 0, 0, 1);
  629.   wprintf(w, " A -   Name               : %s\n", d->name);
  630.   wprintf(w, " B -   Number             : %s\n", d->number);
  631.   wprintf(w, " C -   Dial string #      : %d\n", d->dialtype + 1);
  632.   wprintf(w, " D -   Local echo         : %s\n", yesno(d->localecho));
  633.   wprintf(w, " E -   Script             : %s\n", d->script);
  634.   wprintf(w, " F -   Username           : %s\n", d->username);
  635.   wprintf(w, " G -   Password           : %s\n", d->password);
  636.   wprintf(w, " H -   Terminal Emulation : %s\n", te[d->term - 1]);
  637.   wprintf(w, " I -   Line Settings      : %s %s%s1",
  638.       d->baud, d->bits, d->parity);
  639.   wlocate(w, 4, 11);
  640.   wputs(w, "Change which setting? ");
  641.   wredraw(w, 1);
  642.  
  643.   while(1) {
  644.       wlocate(w, 26, 11);
  645.       c = getch();
  646.       if (c >= 'a') c -= 32;
  647.       switch(c) {
  648.         case '\033':
  649.         case '\r':
  650.       case '\n':
  651.           wclose(w, 1);
  652.           return;
  653.       case 'A':
  654.           wlocate(w, 28, 0);
  655.           (void) wgets(w, d->name, 31, 32);
  656.           break;
  657.       case 'B':
  658.           wlocate(w, 28, 1);
  659.           (void) wgets(w, d->number, 15, 16);
  660.           break;
  661.     case 'C':
  662.         d->dialtype = (d->dialtype + 1) % 3;
  663.         wlocate(w, 28, 2);
  664.         wprintf(w, "%d", d->dialtype + 1);
  665.         wflush();
  666.         break;
  667.     case 'D':
  668.         d->localecho = !d->localecho;
  669.         wlocate(w, 28, 3);
  670.         wprintf(w, "%s", yesno(d->localecho));
  671.         wflush();
  672.         break;
  673.       case 'E':
  674.           wlocate(w, 28, 4);
  675.           (void) wgets(w, d->script, 15, 16);    
  676.           break;
  677.       case 'F':
  678.           wlocate(w, 28, 5);
  679.           (void) wgets(w, d->username, 31, 32);
  680.           break;
  681.       case 'G':
  682.           wlocate(w, 28, 6);
  683.           (void) wgets(w, d->password, 31, 32);
  684.           break;    
  685.       case 'H':
  686.           d->term = (d->term % 3) + 1;
  687.           wlocate(w, 28, 7);
  688.           wputs(w, te[d->term - 1]);    
  689.           break;
  690.       case 'I':
  691.           get_bbp(d->baud, d->bits, d->parity);
  692.           wlocate(w, 28, 8);
  693.           wprintf(w, "%s %s%s1  ", d->baud, d->bits, d->parity);
  694.           break;
  695.       default:
  696.           break;
  697.       }
  698.   }
  699. }
  700.  
  701. static WIN *dsub;
  702. static char *what =  "  Dial    Add     Edit   Remove ";
  703. static int dprev;
  704.  
  705. /*
  706.  * Highlight a choice in the horizontal menu.
  707.  */
  708. static void dhili(k)
  709. int k;
  710. {
  711.   if (k == dprev) return;
  712.  
  713.   if (dprev >= 0) {
  714.       wlocate(dsub, 22 + 8*dprev, 0);
  715.     if (!useattr) {
  716.         wputs(dsub, " ");
  717.     } else {
  718.           wsetattr(dsub, A_REVERSE | stdattr);
  719.           wprintf(dsub, "%8.8s", what + 8*dprev);
  720.     }
  721.   }
  722.   dprev = k;
  723.   wlocate(dsub, 22 + 8*k, 0);
  724.   if (!useattr) {
  725.     wputs(dsub, ">");
  726.   } else {
  727.     wsetattr(dsub, stdattr);
  728.     wprintf(dsub, "%8.8s", what + 8*k);
  729.   }
  730. }
  731.  
  732.   
  733. static char *fmt = "\r %2d  %-16.16s %-16.16s%5s %s%s1    %-6.6s %-15.15s\n";
  734.  
  735. /*
  736.  * Print the dialing directory. Only draw from "cur" to bottom.
  737.  */
  738. static void prdir(dialw, top, cur)
  739. WIN *dialw;
  740. int top, cur;
  741. {
  742.   int f, start;
  743.   struct dialent *d;
  744.  
  745.   start = cur - top;
  746.   dirflush = 0;
  747.   wlocate(dialw, 0, start + 1);
  748.   for(f = start; f < 16; f++) {
  749.       d = getno(f + top);
  750.       if (d == (struct dialent *)0) break;
  751.       wprintf(dialw, fmt, f+1+top, d->name, d->number,
  752.           d->baud, d->bits, d->parity, te[d->term - 1], d->script);
  753.   }
  754.   dirflush = 1;
  755.   wflush();
  756. }
  757.  
  758. /* Little menu. */
  759. static char *d_yesno[] = { "   Yes  ", "   No   ", CNULL };
  760.  
  761. /*
  762.  * Ask for a number and if <enter> is given go to the
  763.  * dialing directory
  764.  */
  765. void dialdir()
  766. {
  767.   WIN *w;
  768.   struct dialent *d, *d1, *d2;
  769.   static int cur = 0;
  770.   static int ocur = 0;
  771.   int subm = 0;
  772.   int quit = 0;
  773.   static int top = 0;
  774.   int c, nb;
  775.   char buf[32];
  776.   int pgud = 0;
  777.   int first = 1;
  778.  
  779.   dprev = -1;
  780.  
  781.   w = wopen(0, LINES - 1, COLS - 1, LINES - 1, BNONE, A_REVERSE, WHITE, BLACK, 1, 0, 1);
  782.  
  783.   wputs(w, " Number to dial: (enter for dialing directory) ");
  784.   buf[0] = 0;
  785.   if (wgets(w, buf, 19, 32) < 0) {
  786.       wclose(w, 1);
  787.       return;
  788.   }
  789.   wclose(w, 1);
  790.   if (buf[0] != 0) {
  791.       (void) dial("Manually entered number", buf, 1, 0);
  792.       return;
  793.   }
  794.   
  795.   /* Allright, draw the dialing directory! */
  796.   
  797.   dirflush = 0;
  798.   dsub = wopen(2, 22, 77, 22, BNONE, A_REVERSE | stdattr, MFG, MBG, 0, 0, 1);
  799.   w = wopen(3, 2, 76, 19, BSINGLE, stdattr, MFG, MBG, 0, 0, 1);
  800.   wcursor(w, CNONE);
  801.   wtitle(w, TMID, "Dialing Directory");
  802.   wputs(w, "     Name               Number       Line Format Terminal Script\n");
  803.   wlocate(dsub, 22, 0);
  804.   wputs(dsub, what);
  805.  
  806.   wsetregion(w, 1, w->ys - 1);
  807.   w->doscroll = 0;
  808.  
  809.   prdir(w, top, top);  
  810.   wlocate(w, 14, 17);
  811.   wputs(w, "( Press Escape to exit.. )");
  812.   dhili(subm);
  813.   dirflush = 1;
  814.   wredraw(dsub, 1);
  815.  
  816. again:  
  817.   wcurbar(w, cur + 1 - top, A_REVERSE | stdattr);
  818.   if (first) {
  819.       wredraw(w, 1);
  820.       first = 0;
  821.   }
  822.   while(!quit) {
  823.       d = getno(cur);
  824.       switch(c = getch()) {
  825.           case K_UP:
  826.           case 'k':
  827.               cur -= (cur > 0);
  828.               break;
  829.           case K_DN:
  830.           case 'j':
  831.               cur += (cur < nrents - 1);
  832.               break;
  833.           case K_LT:
  834.           case 'h':
  835.             subm--;
  836.             if (subm < 0) subm = 3;
  837.               break;
  838.           case K_RT:
  839.           case 'l':
  840.               subm = (subm + 1) % 4;
  841.               break;
  842.           case K_PGUP:
  843.           case '\002': /* Control-B */
  844.               pgud = 1;
  845.               quit = 1;
  846.               break;    
  847.           case K_PGDN:
  848.           case '\006': /* Control-F */
  849.               pgud = 2;
  850.               quit = 1;
  851.               break;    
  852.           case '\033':
  853.           case '\r':
  854.           case '\n':
  855.               quit = 1;
  856.               break;
  857.           default:
  858.               break;
  859.       }
  860.       /* Decide if we have to delete the cursor bar */
  861.       if (cur != ocur || quit) wcurbar(w, ocur + 1 - top, A_NORMAL | stdattr);
  862.           
  863.       if (cur < top) {
  864.           top--;
  865.           prdir(w, top, top);    
  866.     }
  867.     if (cur - top > 15) {
  868.         top++;
  869.           prdir(w, top, top);    
  870.     }
  871.       if (cur != ocur) wcurbar(w, cur + 1 - top, A_REVERSE | stdattr);
  872.       ocur = cur;
  873.       dhili(subm);
  874.   }
  875.   quit = 0;
  876.   /* ESC means quit */
  877.   if (c == '\033') {
  878.       writedialdir();
  879.     wclose(w, 1);
  880.     wclose(dsub, 1);
  881.     return;
  882.   }
  883.   /* Page up or down ? */
  884.   if (pgud == 1) { /* Page up */
  885.       ocur = top;
  886.       top -= 16;
  887.       if (top < 0) top = 0;
  888.       cur = top;
  889.       pgud = 0;
  890.       if (ocur != top) prdir(w, top, cur);
  891.       ocur = cur;
  892.     goto again;
  893.   }
  894.   if (pgud == 2) { /* Page down */
  895.       ocur = top;
  896.       if (top < nrents - 16) {
  897.         top += 16;
  898.         if (top > nrents - 16) top = nrents - 16;
  899.         cur = top;
  900.     } else
  901.         cur = nrents - 1;    
  902.     pgud = 0;
  903.     if (ocur != top) prdir(w, top, cur);
  904.     ocur = cur;
  905.     goto again;
  906.   }
  907.   
  908.   /* Dial an entry */
  909.   if (subm == 0) {
  910.       wclose(w, 1);
  911.       wclose(dsub, 1);
  912.       writedialdir();
  913.       strcpy(P_BAUDRATE, d->baud);
  914.       strcpy(P_PARITY, d->parity);
  915.       strcpy(P_BITS, d->bits);
  916.     m_setparms(portfd, P_BAUDRATE, P_PARITY, P_BITS);
  917.       mode_status();
  918.       newtype = d->term;
  919.     vt_set(-1, -1, NULL, -1, -1, d->localecho, -1);
  920.     local_echo = d->localecho;
  921.       if ((nb = dial(d->name, d->number, d->script[0] ? 0 : 1,
  922.             d->dialtype)) < 0) return;
  923.  
  924.       /* Did we detect a baudrate , and can we set it? */
  925.       if (P_MAUTOBAUD[0] == 'Y' && nb) {
  926.           sprintf(P_BAUDRATE, "%d", nb);
  927.         m_setparms(portfd, P_BAUDRATE, P_PARITY, P_BITS);
  928.       } else
  929.           nb = 0;
  930.       if (newtype != terminal)
  931.           init_emul(newtype);
  932.       else if (nb)
  933.           mode_status();
  934.       if (d->script[0]) runscript(0, d->script, d->username, d->password);
  935.     /* Remember _what_ we dialed.. */
  936.     dial_name = d->name;
  937.     dial_number = d->number;
  938.       return;
  939.   }
  940.   /* Add / insert an entry */
  941.   if (subm == 1) {
  942.       d1 = mkstdent();
  943.       if (d1 == (struct dialent *)0) {
  944.           wbell();
  945.           goto again;
  946.       }
  947.       cur++;
  948.       ocur = cur;
  949.       d2 = d->next;
  950.       d->next = d1;
  951.       d1->next = d2;
  952.       
  953.       nrents++;
  954.       if (cur - top > 15) {
  955.           top++;
  956.           prdir(w, top, top);
  957.       } else {
  958.           prdir(w, top, cur);
  959.     }
  960.   }
  961.  
  962.   /* Edit an entry */
  963.   if (subm == 2) {
  964.       dedit(d);
  965.       wlocate(w, 0, cur + 1 - top);
  966.       wprintf(w, fmt, cur+1, d->name, d->number,
  967.           d->baud, d->bits, d->parity, te[d->term - 1], d->script);
  968.   }
  969.   
  970.   /* Delete an entry from the list */
  971.   if (subm == 3 && ask("Remove entry?", d_yesno) == 0) {
  972.       if (nrents == 1) {
  973.           free((char *)d);
  974.           d = dialents = mkstdent();
  975.           prdir(w, top, top);
  976.           goto again;
  977.       }
  978.       if (cur == 0)
  979.           dialents = d->next;
  980.       else
  981.           getno(cur - 1)->next = d->next;
  982.       free((char *)d);
  983.       nrents--;
  984.       if (cur - top == 0 && top == nrents) {
  985.           top--;
  986.           cur--;
  987.           prdir(w, top, top);
  988.       } else {
  989.           if (cur == nrents) cur--;
  990.         prdir(w, top, cur);
  991.       }
  992.     if (nrents - top <= 15) {
  993.         wlocate(w, 0, nrents - top + 1);
  994.         wclreol(w);
  995.     }
  996.       ocur = cur;
  997.   }
  998.   goto again;
  999. }
  1000.