home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / gnu / fax-3.2.1 / lib / libfax / response.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-07-31  |  7.1 KB  |  292 lines

  1. /*
  2.   This file is part of the NetFax system.
  3.  
  4.   (c) Copyright 1989 by David M. Siegel and Sundar Narasimhan.
  5.       All rights reserved.
  6.  
  7.     This program is free software; you can redistribute it and/or modify
  8.     it under the terms of the GNU General Public License as published by
  9.     the Free Software Foundation.
  10.  
  11.     This program is distributed in the hope that it will be useful, 
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of 
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with this program; if not, write to the Free Software
  18.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19. */
  20.  
  21. #include <stdio.h>
  22. #include <strings.h>
  23.  
  24. #include "log.h"
  25. #include "c2proto.h"
  26. #include "read.h"
  27. #include "response.h"
  28.  
  29. static int parse_int_response(), parse_id_response(), parse_t30_response();
  30.  
  31. #define arg(f)  ((int)(&(((FaxModem *)NULL)->f)))
  32. #define sarg(f) ((int)(((FaxModem *)NULL)->f))
  33.  
  34. static struct _parse_switch {
  35.     int flag;
  36.     char *string;
  37.     int (*func)();
  38.     int offset;
  39. } parse_switch[] = {
  40.     {FAX_F_FCON, "+FCON", NULL, NULL},
  41.     {FAX_F_FNSF, "+FNSF", NULL, NULL},
  42.     {FAX_F_FCFR, "+FCFR", NULL, NULL},
  43.     {FAX_F_FHNG, "+FHNG", parse_int_response, arg(hangup_code)},
  44.     {FAX_F_FPTS, "+FPTS", parse_int_response, arg(ppr_code)},
  45.     {FAX_F_FET,  "+FET",  parse_int_response, arg(ppm_code)},
  46.     {FAX_F_FTSI, "+FTSI", parse_id_response,  sarg(ftsi_id)},
  47.     {FAX_F_FCSI, "+FCSI", parse_id_response,  sarg(fcsi_id)},
  48.     {FAX_F_FCSI, "+FCIG", parse_id_response,  sarg(fcig_id)},
  49.     {FAX_F_FDCS, "+FDCS", parse_t30_response, arg(fdcs_params)},
  50.     {FAX_F_FDCS, "+FDIS", parse_t30_response, arg(fdis_params)},
  51.     {FAX_F_FDCS, "+FDTC", parse_t30_response, arg(fdtc_params)},
  52. };
  53. #define parse_switch_len (sizeof(parse_switch)/sizeof(struct _parse_switch))
  54.  
  55. #undef arg
  56. #undef sarg
  57.  
  58. static int parse_t30_response(reply, offset)
  59.      char *reply;
  60.      char *offset;
  61. {
  62.     T30params *params = (T30params *)offset;
  63.  
  64.     if (strlen(reply) < 6)
  65.       return (-1);
  66.  
  67.     if (sscanf(reply+6, "%d,%d,%d,%d,%d,%d,%d,%d",
  68.            ¶ms->vr, ¶ms->br, ¶ms->wd, ¶ms->ln,
  69.            ¶ms->df, ¶ms->ec, ¶ms->bf, ¶ms->st) != 8)
  70.       return (-1);
  71.     
  72.     return (0);
  73. }
  74.  
  75. static int parse_id_response(reply, str)
  76.      char *reply;
  77.      char *str;
  78. {
  79.     char *fquote, *lquote;
  80.  
  81.     if ((fquote = index(reply, '"')) == NULL)
  82.       return (-1);
  83.  
  84.     if ((lquote = rindex(reply, '"')) == NULL)
  85.       return (-1);
  86.  
  87.     if (fquote == lquote)
  88.       return (-1);
  89.  
  90.     *lquote = '\0';
  91.     strcpy(str, fquote+1);
  92.  
  93.     return (0);
  94. }
  95.  
  96. static int parse_int_response(reply, offset)
  97.      char *reply;
  98.      char *offset;
  99. {
  100.     int *value = (int *)offset;
  101.     char *start = index(reply, ':');
  102.  
  103.     if (start == NULL)
  104.       return (-1);
  105.  
  106.     if (sscanf(start+1, "%d", value) != 1)
  107.       return (-1);
  108.  
  109.     return (0);
  110. }
  111.  
  112. /*
  113.   Parse a text response from the modem.  Update the flag for the response,
  114.   and process the message according to the switch, as defined above.
  115. */
  116. static int parse_text_response(f, reply)
  117.      FaxModem *f;
  118.      char *reply;
  119. {
  120.     int i;
  121.  
  122.     log(L_INFO, "parse_text_response: parsing: \"%s\"", reply);
  123.  
  124.     for (i = 0; i < parse_switch_len; i++) {
  125.     struct _parse_switch *p = &parse_switch[i];
  126.     if (strncmp(p->string, reply, strlen(p->string)) == 0) {
  127.         f->flags |= p->flag;
  128.         if (p->func != NULL) {
  129.         if ((*p->func)(reply, &((char *)f)[p->offset]) < 0)
  130.           log(L_NOTICE, "parse_text_response: error processing \"%s\"",
  131.               reply);
  132.         }
  133.         return (0);
  134.     }
  135.     }
  136.     
  137.     log(L_NOTICE, "parse_text_response: parse failed: \"%s\"", reply);
  138.     
  139.     return (-1);
  140. }
  141.  
  142. typedef enum {
  143.     RESPONSE_START,
  144.     RESPONSE_NUMERIC,
  145.     RESPONSE_TEXT,
  146.     RESPONSE_CONNECT,
  147.     RESPONSE_DONE,
  148. } response_state;
  149.  
  150. /*
  151.  * This function parses numeric and connect responses from the faxmodem.
  152.  * It is assumed that the modem is in numeric response mode.  We first
  153.  * parse the response from the passed in buf, and then we read more
  154.  * from the modem, if necessary.  We do this since some routines do
  155.  * read ahead.
  156.  *
  157.  * INPUTS: serial_fd   a serial stream file descriptor from which to read
  158.  *         response    a faxmodem_response structure
  159.  *
  160.  * It fills in any relevant slots of the faxmodem_response structure
  161.  * which is passed to it. 
  162.  *
  163.  * Responses are a single digit followed by <CR>.
  164.  */
  165. int get_modem_response_from_buf(f, timeout, buf, bufsize)
  166.      FaxModem *f;
  167.      int timeout;
  168.      char *buf;
  169.      int bufsize;
  170. {
  171.     response_state state = RESPONSE_START;
  172.     char reply[1024];
  173.     char *reply_ptr;
  174.     char c;
  175.  
  176.     log(L_DEBUG, "get_modem_reponse: entering with timeout %d", timeout);
  177.  
  178.     /* start with a clean status */
  179.     f->status = MODEM_STATUS_OK;
  180.  
  181.     /*
  182.      * Read in all responses, and figure out if we are getting a number
  183.      * result code (RESPONSE_NUMERIC) or text (RESPONSE_TEXT).
  184.      */
  185.     while (state != RESPONSE_DONE) {
  186.     int count;
  187.  
  188.     if (bufsize > 0) {
  189.         c = *(buf++);
  190.         bufsize--;
  191.         count = 1;
  192.     } else
  193.       count = tread(f->fd, &c, 1, timeout);
  194.     
  195.     switch (count) {
  196.       case -1:
  197.         f->status = MODEM_STATUS_FAILED;
  198.         return (-1);
  199.       case 0:
  200.         f->status = MODEM_STATUS_TIMEOUT;
  201.         return (-1);
  202.       default:
  203.         break;
  204.     }
  205.     
  206.     switch (state) {
  207.       case RESPONSE_START: 
  208.         reply_ptr = reply;
  209.         if (isdigit(c))  {
  210.         f->result = (int)(c - '0');
  211.         state = RESPONSE_NUMERIC;
  212.         } else if (c == '\r' || c == '\n') {
  213.         state = RESPONSE_START;
  214.         } else {
  215.         *reply_ptr++ = c;
  216.         state = RESPONSE_TEXT;
  217.         }
  218.         break;
  219.  
  220.       case RESPONSE_NUMERIC: 
  221.         if (c == '\r') {
  222.         log(L_INFO, "numeric response code: %d", f->result);
  223.         state = RESPONSE_DONE;
  224.         } else {
  225.         *reply_ptr++ = c;
  226.         state = RESPONSE_TEXT;
  227.         }
  228.         break;
  229.  
  230.       case RESPONSE_TEXT:
  231.         if (c == '\r' || c == '\n') {
  232.         state = RESPONSE_START;
  233.         *reply_ptr++ = '\0';
  234.         if (strncmp(reply, "CONNECT", 7) == 0)
  235.           state = RESPONSE_CONNECT;
  236.         else
  237.           parse_text_response(f, reply);
  238.         } else
  239.           *reply_ptr++ = c;
  240.         break;
  241.  
  242.       case RESPONSE_CONNECT:
  243.         if (c != '\n')
  244.           log(L_WARNING, "invalid connect message");
  245.         else
  246.           log(L_INFO, "received connect response");
  247.         f->flags |= FAX_F_CONNECT;
  248.         f->result = 0;
  249.         state = RESPONSE_DONE;
  250.         break;
  251.  
  252.       default: 
  253.         log(L_EMERG, "get_modem_response: illegal state");
  254.         abort();
  255.     }
  256.     }
  257.  
  258.     return (0);
  259. }
  260.  
  261. /*
  262.  * Since most routines are in sync with the modem, they simply call
  263.  * this convenience function.
  264.  */
  265. int get_modem_response(f, timeout)
  266.      FaxModem *f;
  267.      int timeout;
  268. {
  269.     return (get_modem_response_from_buf(f, timeout, NULL, 0));
  270. }
  271.  
  272. /*
  273.  * This function clears the state of the modem, and should only
  274.  * be called when starting a new fax session.  Other than that,
  275.  * the FaxModem structure will always hold the most complete
  276.  * information available for the current fax session.
  277.  */
  278. void init_modem_response(f)
  279.      FaxModem *f;
  280. {
  281.     f->status = MODEM_STATUS_OK;
  282.     f->flags = 0;
  283.     f->result = 0;
  284.     f->dialer_code = 0;
  285. }
  286.  
  287. /* ARGSUSED */
  288. void faxmodem_print_status(f)
  289.      FaxModem *f;
  290. {
  291. }
  292.