home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume26 / pcomm-2.0.2 / part04 / dial.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-13  |  9.1 KB  |  462 lines

  1. /*
  2.  * The routines that dial the modem and listen for the return codes.
  3.  */
  4.  
  5. #define HZ    60
  6.  
  7. #include <stdio.h>
  8. #include <ctype.h>
  9. #include "config.h"
  10. #include "dial_dir.h"
  11. #include "misc.h"
  12. #include "modem.h"
  13. #include "param.h"
  14.  
  15. #ifdef BSD
  16. #include <sys/time.h>
  17. #else /* BSD */
  18. #include <sys/types.h>
  19. #include <sys/times.h>
  20. #endif /* BSD */
  21.  
  22. #ifdef UNIXPC
  23. #include <sys/phone.h>
  24. #endif /* UNIXPC */
  25.  
  26. static void do_pause();
  27. static int match();
  28.  
  29. /*
  30.  * Get the dial string ready, send it to the modem.  The parameter is not
  31.  * the actual entry number, it is an index into the queue.
  32.  */
  33.  
  34. void
  35. dial_it(num)
  36. int num;
  37. {
  38.     int i, skip;
  39.     char s[100], number[40], *strcpy(), *strcat(), *n, *strchr();
  40.     void send_str();
  41. #ifdef UNIXPC
  42.     extern int fd;
  43.     struct updata pbuf;
  44.     unsigned int sleep();
  45. #endif /* UNIXPC */
  46.  
  47.     /*
  48.      * Create the string to be sent to the modem.  The long distance
  49.      * codes are added if they are requested.
  50.      */
  51.     s[0] = '\0';
  52.     strcpy(s, modem->dial[modem->m_cur]);
  53.  
  54.     switch (dir->q_ld[num]) {
  55.         case 0:            /* no ld code requested */
  56.             break;
  57.         case '+':
  58.             strcat(s, param->ld_plus);
  59.             break;
  60.         case '-':
  61.             strcat(s, param->ld_minus);
  62.             break;
  63.         case '@':
  64.             strcat(s, param->ld_at);
  65.             break;
  66.         case '#':
  67.             strcat(s, param->ld_pound);
  68.             break;
  69.     }
  70.     /*
  71.      * Purify the phone number by removing all the pretty characters
  72.      * that don't need to be sent to the modem.  Typically the "-",
  73.      * "(", ")", and space characters are just for looks.  To prevent
  74.      * this action, prepend a "\" to the character.
  75.      */
  76.     i = 0;
  77.     skip = 0;
  78.     n = dir->number[dir->q_num[num]];
  79.     while (*n) {
  80.         if (*n == '\\' && !skip) {
  81.             skip++;
  82.             n++;
  83.             continue;
  84.         }
  85.         if (!strchr("-() ", *n) || skip)
  86.             number[i++] = *n;
  87.         n++;
  88.         skip = 0;
  89.     }
  90.     number[i] = '\0';
  91.                     /* add it to the string */
  92.     strcat(s, number);
  93.     strcat(s, modem->suffix[modem->m_cur]);
  94. #ifdef DEBUG
  95.     fprintf(stderr, "raw dial string: \"%s\"\n", s);
  96. #endif /* DEBUG */
  97.  
  98. #ifdef UNIXPC
  99.                     /* special case for OBM */
  100.     if (!strcmp(modem->mname[modem->m_cur], "OBM")) {
  101.                     /* prepare the modem */
  102.         pbuf.c_lineparam = DATA|DTMF;
  103.         pbuf.c_waitdialtone = 5;
  104.         pbuf.c_linestatus = 0;
  105.         pbuf.c_feedback = SPEAKERON|NORMSPK;
  106.         pbuf.c_waitflash = 500;
  107.         ioctl(fd, PIOCSETP, &pbuf);
  108.         sleep(1);
  109.                     /* connect the dialer */
  110.         ioctl(fd, PIOCRECONN);
  111.         sleep(2);
  112.                     /* dial each digit */
  113.         n = s;
  114.         while (*n) {
  115.                     /* switch tone/pulse dialing? */
  116.             switch (*n) {
  117.                 case '^':
  118.                     pbuf.c_lineparam = DATA|PULSE;
  119.                     ioctl(fd, PIOCSETP, &pbuf);
  120.                     break;
  121.                 case '%':
  122.                     pbuf.c_lineparam = DATA|DTMF;
  123.                     ioctl(fd, PIOCSETP, &pbuf);
  124.                     break;
  125.                 default:
  126.                     ioctl(fd, PIOCDIAL, n);
  127.                     break;
  128.             }
  129.             n++;
  130.         }
  131.         /*
  132.          * It seems that the OBM doesn't always talk reliably to
  133.          * other types of modems (most notibly Telebits).  Here
  134.          * is some witchcraft to fix the problem.
  135.          */
  136.         ioctl(fd, PIOCOVSPD);
  137.         return;
  138.     }
  139. #endif /* UNIXPC */
  140.  
  141.     send_str(s, SLOW);
  142.     return;
  143. }
  144.  
  145. /*
  146.  * Send a string to the modem.  Performs all the character synonym
  147.  * translations.
  148.  */
  149.  
  150. void
  151. send_str(s, slow)
  152. char *s;
  153. int slow;
  154. {
  155.     extern int fd;
  156.     int skip, has_pause;
  157.     char *strchr();
  158.     unsigned int sleep();
  159.                     /* empty string? */
  160.     if (s == NULL || *s == '\0')
  161.         return;
  162.  
  163.                     /* contains a pause? */
  164.     has_pause = 0;
  165.     if (strchr(s, '~'))
  166.         has_pause++;
  167.  
  168.     tty_flush(fd, 1);
  169.     /*
  170.      * Change the character synonyms to their real values.  Writes
  171.      * the characters to the modem.  To remove the special meaning
  172.      * of one of the characters, prepend a "\" to it.
  173.      */
  174.     skip = 0;
  175.     while (*s) {
  176.                     /* send the literal character */
  177.         if (skip) {
  178.             skip = 0;
  179.             write(fd, s, 1);
  180.             if (has_pause || slow)
  181.                 tty_drain(fd);
  182.             if (slow)
  183.                 do_pause();
  184. #ifdef DEBUG
  185.             fprintf(stderr, "send_str: \"%c\", %02x, %03o, %d\n", *s, *s, *s, *s);
  186. #endif /* DEBUG */
  187.             s++;
  188.             continue;
  189.         }
  190.                     /* turn off the special meaning */
  191.         if (*s == '\\') {
  192.             skip++;
  193.             s++;
  194.             continue;
  195.         }
  196.                     /* pause synonym */
  197.         if (*s == param->pause_char) {
  198.             sleep(1);
  199.             s++;
  200.             continue;
  201.         }
  202.                     /* carriage return synonym */
  203.         if (*s == param->cr_char)
  204.             *s = '\r';
  205.                     /* 2 character control sequence */
  206.         if (*s == param->ctrl_char) {
  207.             s++;
  208.                     /* premature EOF? */
  209.             if (*s == '\0')
  210.                 break;
  211.                     /* upper and lower case */
  212.             if (*s > '_')
  213.                 *s -= 96;
  214.             else
  215.                 *s -= 64;
  216.         }
  217.                     /* escape synonym */
  218.         if (*s == param->esc_char)
  219.             *s = ESC;
  220.                     /* modem break synonym */
  221.         if (*s == param->brk_char) {
  222.             tty_break(fd);
  223.             sleep(1);
  224.             s++;
  225.             continue;
  226.         }
  227.  
  228.         write(fd, s, 1);
  229. #ifdef DEBUG
  230.         fprintf(stderr, "send_str: \"%c\", %02x, %03o, %d\n", *s, *s, *s, *s);
  231. #endif /* DEBUG */
  232.         /*
  233.          * Because the pause char makes the timing critical, we
  234.          * wait until the buffer is clear before we continue.
  235.          */
  236.         if (has_pause || slow)
  237.             tty_drain(fd);
  238.         if (slow)
  239.             do_pause();
  240.         s++;
  241.     }
  242.     return;
  243. }
  244.  
  245. /*
  246.  * Read the result codes coming back from the modem.  Test for the 7
  247.  * "connect" strings and the 4 "no connect" strings.  Return the connected
  248.  * baud rate (as a string) or the error message.
  249.  */
  250.  
  251. char *
  252. read_codes(tic)
  253. int tic;
  254. {
  255.     int i, j, k;
  256.     char c;
  257.     static char rc_buf[512];
  258.     static int rc_index;
  259. #ifdef UNIXPC
  260.     extern int fd;
  261.     unsigned int sleep();
  262.     struct updata pbuf;
  263.                     /* special case for OBM */
  264.     if (!strcmp(modem->mname[modem->m_cur], "OBM")) {
  265.         ioctl(fd, PIOCGETP, &pbuf);
  266.  
  267.         /*
  268.          * The OBM doesn't use a return message to announce the
  269.          * connection to a remote, so we fake one.  The 1200
  270.          * is quite arbitrary... it is not an indicator of the
  271.          * connected baud rate.
  272.          */
  273.         if (pbuf.c_linestatus & MODEMCONNECTED)
  274.             return("1200");
  275.  
  276.         sleep(1);
  277.         return(NULL);
  278.     }
  279. #endif /* UNIXPC */
  280.     if (tic == 0)
  281.         rc_index = 0;
  282.                     /* search for key words */
  283.     for (; rc_index<511; rc_index++) {
  284.         if ((i = getc_line(1)) <= 0)
  285.             return(NULL);
  286.  
  287.         c = i & 0x7f;
  288. #ifdef DEBUG
  289.         fprintf(stderr, "read_codes: \"%c\", %02x, %03o, %d\n", c, c, c, c);
  290. #endif /* DEBUG */
  291.                     /* no NULLs please */
  292.         if (c == '\0') {
  293.             if (rc_index)
  294.                 rc_index--;
  295.             continue;
  296.         }
  297.         rc_buf[rc_index] = c;
  298.         rc_buf[rc_index+1] = '\0';
  299.                     /* the connect strings */
  300.         if (match(rc_buf, modem->con_3[modem->m_cur]))
  301.             return("300");
  302.  
  303.         if (match(rc_buf, modem->con_12[modem->m_cur]))
  304.             return("1200");
  305.  
  306.         if (match(rc_buf, modem->con_24[modem->m_cur]))
  307.             return("2400");
  308.  
  309.         if (match(rc_buf, modem->con_48[modem->m_cur]))
  310.             return("4800");
  311.  
  312.         if (match(rc_buf, modem->con_96[modem->m_cur]))
  313.             return("9600");
  314.  
  315.         if (match(rc_buf, modem->con_192[modem->m_cur]))
  316.             return("19200");
  317.  
  318.         if (match(rc_buf, modem->con_384[modem->m_cur]))
  319.             return("38400");
  320.  
  321.                     /* the no connect strings */
  322.         if (match(rc_buf, modem->no_con1[modem->m_cur]))
  323.             return(modem->no_con1[modem->m_cur]);
  324.  
  325.         if (match(rc_buf, modem->no_con2[modem->m_cur]))
  326.             return(modem->no_con2[modem->m_cur]);
  327.  
  328.         if (match(rc_buf, modem->no_con3[modem->m_cur]))
  329.             return(modem->no_con3[modem->m_cur]);
  330.  
  331.         if (match(rc_buf, modem->no_con4[modem->m_cur]))
  332.             return(modem->no_con4[modem->m_cur]);
  333.         /*
  334.          * OK.. this is the tricky part.  What if the modem returns
  335.          * the connected rate (in lieu of the DTE rate)?  For
  336.          * example, the message is "CONNECT 14400", but the DTE
  337.          * is locked at 38400.
  338.          */
  339.         if (modem->lock_sp[modem->t_cur]) {
  340.             for (j=0; j<512; j++) {
  341.                 if (rc_buf[j] == '\0')
  342.                     break;
  343.                 if (isdigit(rc_buf[j])) {
  344.                     k = atoi(&rc_buf[j]);
  345.                     switch(k) {
  346.                         case 7200:
  347.                             return("7200");
  348.                         case 12000:
  349.                             return("12000");
  350.                         case 14400:
  351.                             return("14400");
  352.                     }
  353.                     break;
  354.                 }
  355.             }
  356.         }
  357.                     
  358.     }
  359.                     /* ran out of buffer? */
  360.     return("ERROR");
  361. }
  362.  
  363. /*
  364.  * Test for a match between two character strings.  A non-zero return code
  365.  * means that s2 was found at the end of s1.
  366.  */
  367.  
  368. static int
  369. match(s1, s2)
  370. char *s1, *s2;
  371. {
  372.     register int i;
  373.     int skip, diff;
  374.     char new[40];
  375.                     /* if no string to match */
  376.     if (*s2 == '\0')
  377.         return(0);
  378.                     /* translate synonyms */
  379.     i = 0;
  380.     skip = 0;
  381.     while (*s2) {
  382.                     /* literal character */
  383.         if (skip) {
  384.             skip = 0;
  385.             new[i++] = *s2;
  386.             s2++;
  387.             continue;
  388.         }
  389.                     /* turn off the special meaning */
  390.         if (*s2 == '\\') {
  391.             skip++;
  392.             s2++;
  393.             continue;
  394.         }
  395.                     /* carriage return synonym */
  396.         if (*s2 == param->cr_char)
  397.             *s2 = '\r';
  398.  
  399.                     /* 2 character control sequence */
  400.         if (*s2 == param->ctrl_char) {
  401.             s2++;
  402.             if (*s2 == '\0')
  403.                 break;
  404.             if (*s2 > '_')
  405.                 *s2 -= 96;
  406.             else
  407.                 *s2 -= 64;
  408.         }
  409.                     /* escape synonym */
  410.         if (*s2 == param->esc_char)
  411.             *s2 = ESC;
  412.  
  413.         new[i++] = *s2;
  414.         s2++;
  415.     }
  416.     new[i] = '\0';
  417.  
  418.     diff = strlen(s1) - strlen(new);
  419.                     /* is it possible? */
  420.     if (diff < 0)
  421.         return(0);
  422.                     /* test it out */
  423.     if (!strcmp(&s1[diff], new))
  424.         return(1);
  425.     return(0);
  426. }
  427.  
  428. /*
  429.  * Apparently some modems can't take input at the rated speed while
  430.  * in the command mode.  Therefore, a 0.10 sec pause a required between
  431.  * characters.
  432.  */
  433.  
  434. static void
  435. do_pause()
  436. {
  437. #ifdef HAVE_USLEEP
  438.     usleep(100000);
  439. #else /* HAVE_USLEEP */
  440.                 /* Hey! I know these routines are a hack */
  441. #ifdef BSD
  442.     struct timeval tv;
  443.     struct timezone tz;
  444.     double t1;
  445.  
  446.     gettimeofday(&tv, &tz);
  447.     t1 = tv.tv_sec + (tv.tv_usec / 1000000.0);
  448.     do
  449.         gettimeofday(&tv, &tz);
  450.     while ((tv.tv_sec + (tv.tv_usec / 1000000.0) - t1) < 0.1);
  451. #else /* BSD */
  452.     struct tms t;
  453.     long t1;
  454.  
  455.     t1 = times(&t);
  456.     while ((times(&t) - t1) < HZ/10)
  457.         ;
  458. #endif /* BSD */
  459. #endif /* HAVE_USLEEP */
  460.     return;
  461. }
  462.