home *** CD-ROM | disk | FTP | other *** search
/ Gold Fish 2 / goldfish_vol2_cd1.bin / files / comm / misc / elcheapofax / faxcmd / libfax / rcs / response.c,v < prev    next >
Text File  |  1993-12-21  |  12KB  |  572 lines

  1. head    1.7;
  2. access;
  3. symbols
  4.     OCT93:1.7;
  5. locks;
  6. comment    @ * @;
  7.  
  8.  
  9. 1.7
  10. date    93.09.18.20.16.23;    author Rhialto;    state Exp;
  11. branches;
  12. next    1.6;
  13.  
  14. 1.6
  15. date    93.07.13.05.41.27;    author Rhialto;    state Exp;
  16. branches;
  17. next    1.5;
  18.  
  19. 1.5
  20. date    93.07.12.02.52.14;    author Rhialto;    state Exp;
  21. branches;
  22. next    1.4;
  23.  
  24. 1.4
  25. date    93.06.12.00.25.58;    author Rhialto;    state Exp;
  26. branches;
  27. next    1.3;
  28.  
  29. 1.3
  30. date    93.06.11.23.22.07;    author Rhialto;    state Exp;
  31. branches;
  32. next    1.2;
  33.  
  34. 1.2
  35. date    93.06.11.16.15.25;    author Rhialto;    state Exp;
  36. branches;
  37. next    1.1;
  38.  
  39. 1.1
  40. date    93.06.11.15.19.27;    author Rhialto;    state Exp;
  41. branches;
  42. next    ;
  43.  
  44.  
  45. desc
  46. @Parse modem responses, both normal and fax types.
  47. @
  48.  
  49.  
  50. 1.7
  51. log
  52. @Add FAX_F_FPOLL.
  53. @
  54. text
  55. @/* $Id: response.c,v 1.6 1993/07/13 05:41:27 Rhialto Exp $
  56.  * $Log: response.c,v $
  57.  * Revision 1.6  1993/07/13  05:41:27  Rhialto
  58.  * Now understands verbal response codes instead of non-standard
  59.  * numeric codes only.
  60.  *
  61.  * Revision 1.5  1993/07/12  02:52:14  Rhialto
  62.  * Allow both \r and \n at end of numeric responses.
  63.  *
  64.  * Revision 1.4  1993/06/12  00:25:58  Rhialto
  65.  * Simplify parsing of OK and CONNECT responses.
  66.  *
  67.  * Revision 1.3  1993/06/11  23:22:07  Rhialto
  68.  * Recognise numeric form of CONNECT message.
  69.  *
  70.  * Revision 1.2  1993/06/11  16:15:25  Rhialto
  71.  * First real RCS checkin
  72.  *
  73.  */
  74. /*
  75.   This file is part of the NetFax system.
  76.  
  77.   (c) Copyright 1989 by David M. Siegel and Sundar Narasimhan.
  78.       All rights reserved.
  79.  
  80.     This program is free software; you can redistribute it and/or modify
  81.     it under the terms of the GNU General Public License as published by
  82.     the Free Software Foundation.
  83.  
  84.     This program is distributed in the hope that it will be useful,
  85.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  86.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  87.     GNU General Public License for more details.
  88.  
  89.     You should have received a copy of the GNU General Public License
  90.     along with this program; if not, write to the Free Software
  91.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  92. */
  93.  
  94. #include <stdio.h>
  95. #include <string.h>
  96. #include <ctype.h>
  97. #include <stdlib.h>
  98.  
  99. #include "log.h"
  100. #include "c2proto.h"
  101. #include "read.h"
  102. #include "response.h"
  103.  
  104. static int parse_t30_response(char * reply, char * offset);
  105. static int parse_id_response(char * reply, char * str);
  106. static int parse_int_response(char * reply, char * offset);
  107. static int parse_text_response(FaxModem * f, char * reply);
  108. static int parse_3_response(char * reply, FaxModem * f);
  109. static int parse_4_response(char * reply, FaxModem * f);
  110. static int parse_6_response(char * reply, FaxModem * f);
  111. static int parse_7_response(char * reply, FaxModem * f);
  112. static int parse_8_response(char * reply, FaxModem * f);
  113.  
  114. #define arg(f)  ((int)(&(((FaxModem *)NULL)->f)))
  115. #define sarg(f) ((int)(((FaxModem *)NULL)->f))
  116.  
  117. static struct _parse_switch {
  118.     int flag;
  119.     char *string;
  120.     int (*func)(char *, char *);
  121.     int offset;
  122. } parse_switch[] = {
  123.     {FAX_F_FCON, "+FCON", NULL, 0},
  124.     {FAX_F_FNSF, "+FNSF", NULL, 0},
  125.     {FAX_F_FCFR, "+FCFR", NULL, 0},
  126.     {FAX_F_FHNG, "+FHNG", parse_int_response, arg(hangup_code)},
  127.     {FAX_F_FPTS, "+FPTS", parse_int_response, arg(ppr_code)},
  128.     {FAX_F_FET,  "+FET",  parse_int_response, arg(ppm_code)},
  129.     {FAX_F_FTSI, "+FTSI", parse_id_response,  sarg(ftsi_id)},
  130.     {FAX_F_FCSI, "+FCSI", parse_id_response,  sarg(fcsi_id)},
  131.     {FAX_F_FCSI, "+FCIG", parse_id_response,  sarg(fcig_id)},
  132.     {FAX_F_FDCS, "+FDCS", parse_t30_response, arg(fdcs_params)},
  133.     {FAX_F_FDCS, "+FDIS", parse_t30_response, arg(fdis_params)},
  134.     {FAX_F_FDCS, "+FDTC", parse_t30_response, arg(fdtc_params)},
  135.     {FAX_F_FPOLL,"+FPOLL", NULL, 0},
  136.     {0,          "CED", NULL, NULL}, /* some faxes send this */
  137.     {0,          "NO CARRIER", parse_3_response, 0},
  138.     {0,          "ERROR", parse_4_response, 0},
  139.     {0,          "NO DIALTONE", parse_6_response, 0},
  140.     {0,          "BUSY", parse_7_response, 0},
  141.     {0,          "NO ANSWER", parse_8_response, 0},
  142. };
  143. #define parse_switch_len (sizeof(parse_switch)/sizeof(struct _parse_switch))
  144.  
  145. #undef arg
  146. #undef sarg
  147.  
  148. static int parse_t30_response(reply, offset)
  149.      char *reply;
  150.      char *offset;
  151. {
  152.     T30params *params = (T30params *)offset;
  153.  
  154.     if (strlen(reply) < 6)
  155.       return (-1);
  156.  
  157.     if (sscanf(reply+6, "%d,%d,%d,%d,%d,%d,%d,%d",
  158.            ¶ms->vr, ¶ms->br, ¶ms->wd, ¶ms->ln,
  159.            ¶ms->df, ¶ms->ec, ¶ms->bf, ¶ms->st) != 8)
  160.       return (-1);
  161.  
  162.     return (0);
  163. }
  164.  
  165. static int parse_id_response(reply, str)
  166.      char *reply;
  167.      char *str;
  168. {
  169.     char *fquote, *lquote;
  170.  
  171.     if ((fquote = strchr(reply, '"')) == NULL) {
  172.     /* return (-1); */
  173.     lquote = reply + 7;
  174.     /*printf("sharp mode, scanning %s.\n", lquote);*/
  175.     while (*lquote == ' ')
  176.         lquote++;
  177.     strcpy(str, lquote);
  178.  
  179.     return (0);
  180.     }
  181.  
  182.     if ((lquote = strrchr(reply, '"')) == NULL)
  183.       return (-1);
  184.  
  185.     if (fquote == lquote)
  186.       return (-1);
  187.  
  188.     *lquote = '\0';
  189.     strcpy(str, fquote+1);
  190.  
  191.     return (0);
  192. }
  193.  
  194. static int parse_int_response(reply, offset)
  195.      char *reply;
  196.      char *offset;
  197. {
  198.     int *value = (int *)offset;
  199.     char *start = strchr(reply, ':');
  200.  
  201.     if (start == NULL)
  202.       return (-1);
  203.  
  204.     if (sscanf(start+1, "%d", value) != 1)
  205.       return (-1);
  206.  
  207.     return (0);
  208. }
  209.  
  210. static int parse_3_response(char * reply, FaxModem * f)
  211. {
  212.     f->result = RESULT_NO_CARRIER;
  213. }
  214.  
  215. static int parse_4_response(char * reply, FaxModem * f)
  216. {
  217.     f->result = RESULT_ERROR;
  218. }
  219.  
  220. static int parse_6_response(char * reply, FaxModem * f)
  221. {
  222.     f->result = RESULT_NO_DIALTONE;
  223. }
  224.  
  225. static int parse_7_response(char * reply, FaxModem * f)
  226. {
  227.     f->result = RESULT_BUSY;
  228. }
  229.  
  230. static int parse_8_response(char * reply, FaxModem * f)
  231. {
  232.     f->result = RESULT_NO_ANSWER;
  233. }
  234.  
  235. /*
  236.   Parse a text response from the modem.  Update the flag for the response,
  237.   and process the message according to the switch, as defined above.
  238. */
  239. static int parse_text_response(f, reply)
  240.      FaxModem *f;
  241.      char *reply;
  242. {
  243.     int i;
  244.  
  245.     log(L_INFO, "parse_text_response: parsing: \"%s\"", reply);
  246.  
  247.     for (i = 0; i < parse_switch_len; i++) {
  248.     struct _parse_switch *p = &parse_switch[i];
  249.     if (strncmp(p->string, reply, strlen(p->string)) == 0) {
  250.         f->flags |= p->flag;
  251.         if (p->func != NULL) {
  252.         if ((*p->func)(reply, &((char *)f)[p->offset]) < 0) {
  253.           log(L_NOTICE, "parse_text_response: error processing \"%s\"",
  254.               reply);
  255.           return -1;
  256.         }
  257.         }
  258.         return (0);
  259.     }
  260.     }
  261.  
  262.     log(L_NOTICE, "parse_text_response: parse failed: \"%s\"", reply);
  263.  
  264.     return (-1);
  265. }
  266.  
  267. typedef enum {
  268.     RESPONSE_START,
  269.     RESPONSE_NUMERIC,
  270.     RESPONSE_TEXT,
  271.     RESPONSE_DONE,
  272. } response_state;
  273.  
  274. /*
  275.  * This function parses numeric and connect responses from the faxmodem.
  276.  * It is assumed that the modem is in numeric response mode.  We first
  277.  * parse the response from the passed in buf, and then we read more
  278.  * from the modem, if necessary.  We do this since some routines do
  279.  * read ahead.
  280.  *
  281.  * INPUTS: serial_fd   a serial stream file descriptor from which to read
  282.  *       response    a faxmodem_response structure
  283.  *
  284.  * It fills in any relevant slots of the faxmodem_response structure
  285.  * which is passed to it.
  286.  *
  287.  * Responses are a single digit followed by <CR>.
  288.  */
  289. int get_modem_response_from_buf(f, timeout, buf, bufsize)
  290.      FaxModem *f;
  291.      int timeout;
  292.      char *buf;
  293.      int bufsize;
  294. {
  295.     response_state state = RESPONSE_START;
  296.     char reply[1024];
  297.     char *reply_ptr;
  298.     char c;
  299.  
  300.     log(L_DEBUG, "get_modem_reponse: entering with timeout %d", timeout);
  301.  
  302.     /* start with a clean status */
  303.     f->status = MODEM_STATUS_OK;
  304.     f->result = 0;
  305.  
  306.     /*
  307.      * Read in all responses, and figure out if we are getting a number
  308.      * result code (RESPONSE_NUMERIC) or text (RESPONSE_TEXT).
  309.      */
  310.     while (state != RESPONSE_DONE) {
  311.     int count;
  312.  
  313.     if (bufsize > 0) {
  314.         c = *(buf++);
  315.         bufsize--;
  316.         count = 1;
  317.     } else
  318.       count = tread(f->fd, &c, 1, timeout);
  319.  
  320.     switch (count) {
  321.       case -1:
  322.         f->status = MODEM_STATUS_FAILED;
  323.         return (-1);
  324.       case 0:
  325.         f->status = MODEM_STATUS_TIMEOUT;
  326.         return (-1);
  327.       default:
  328.         break;
  329.     }
  330.  
  331.     switch (state) {
  332.     case RESPONSE_START:
  333.         reply_ptr = reply;
  334.         if (isdigit(c))  {
  335.         f->result = (int)(c - '0');
  336.         state = RESPONSE_NUMERIC;
  337.         } else if (c == '\r' || c == '\n') {
  338.         state = RESPONSE_START;
  339.         } else {
  340.         *reply_ptr++ = c;
  341.         state = RESPONSE_TEXT;
  342.         }
  343.         break;
  344.  
  345.     case RESPONSE_NUMERIC:
  346.         /* Numeric responses (not allowed by the spec anyway)
  347.          * apparently only end in \r, not in \r\n
  348.          */
  349.         if (c == '\r' || c == '\n') {
  350.         log(L_INFO, "numeric response code: %d", f->result);
  351.         if (f->result == RESULT_CONNECT)
  352.             goto connect;
  353.         state = RESPONSE_DONE;
  354.         } else {
  355.         *reply_ptr++ = c;
  356.         state = RESPONSE_TEXT;
  357.         }
  358.         break;
  359.  
  360.     case RESPONSE_TEXT:
  361.         if (c == '\n') {
  362.         state = RESPONSE_START;
  363.         *reply_ptr++ = '\0';
  364.         if (strncmp(reply, "CONNECT", 7) == 0) {
  365.         connect:
  366.             log(L_INFO, "received connect response");
  367.             f->flags |= FAX_F_CONNECT;
  368.             f->result = 1;
  369.             state = RESPONSE_DONE;
  370.         } else if (strncmp(reply, "OK", 2) == 0) {
  371.             f->result = 0;
  372.             state = RESPONSE_DONE;
  373.         } else {
  374.             parse_text_response(f, reply);
  375.             if (f->result)
  376.                 state = RESPONSE_DONE;
  377.         }
  378.         } else
  379.         *reply_ptr++ = c;
  380.         break;
  381.  
  382.     default:
  383.         log(L_EMERG, "get_modem_response: illegal state");
  384.         abort();
  385.     }
  386.     }
  387.  
  388.     return (0);
  389. }
  390.  
  391. /*
  392.  * Since most routines are in sync with the modem, they simply call
  393.  * this convenience function.
  394.  */
  395. int get_modem_response(f, timeout)
  396.      FaxModem *f;
  397.      int timeout;
  398. {
  399.     return (get_modem_response_from_buf(f, timeout, NULL, 0));
  400. }
  401.  
  402. /*
  403.  * This function clears the state of the modem, and should only
  404.  * be called when starting a new fax session.  Other than that,
  405.  * the FaxModem structure will always hold the most complete
  406.  * information available for the current fax session.
  407.  */
  408. void init_modem_response(f)
  409.      FaxModem *f;
  410. {
  411.     f->status = MODEM_STATUS_OK;
  412.     f->flags = 0;
  413.     f->result = 0;
  414.     f->dialer_code = 0;
  415. }
  416.  
  417. /* ARGSUSED */
  418. void faxmodem_print_status(f)
  419.      FaxModem *f;
  420. {
  421. }
  422. @
  423.  
  424.  
  425. 1.6
  426. log
  427. @Now understands verbal response codes instead of non-standard
  428. numeric codes only.
  429. @
  430. text
  431. @d1 1
  432. a1 1
  433. /* $Id: response.c,v 1.5 1993/07/12 02:52:14 Rhialto Exp $
  434. d3 4
  435. d81 1
  436. @
  437.  
  438.  
  439. 1.5
  440. log
  441. @Allow both \r and \n at end of numeric responses.
  442. @
  443. text
  444. @d1 1
  445. a1 1
  446. /* $Id: response.c,v 1.4 1993/06/12 00:25:58 Rhialto Exp $
  447. d3 3
  448. d50 5
  449. d65 3
  450. a67 3
  451.     {FAX_F_FCON, "+FCON", NULL, NULL},
  452.     {FAX_F_FNSF, "+FNSF", NULL, NULL},
  453.     {FAX_F_FCFR, "+FCFR", NULL, NULL},
  454. d78 5
  455. d151 25
  456. d245 1
  457. d309 3
  458. d314 5
  459. a318 4
  460.         } else if (strncmp(reply, "OK", 2) == 0) {
  461.           state = RESPONSE_DONE;
  462.         } else
  463.           parse_text_response(f, reply);
  464. d320 1
  465. a320 1
  466.           *reply_ptr++ = c;
  467. @
  468.  
  469.  
  470. 1.4
  471. log
  472. @Simplify parsing of OK and CONNECT responses.
  473. @
  474. text
  475. @d1 1
  476. a1 1
  477. /* $Id: response.c,v 1.3 1993/06/11 23:22:07 Rhialto Exp $
  478. d3 3
  479. d248 4
  480. a251 1
  481.         if (c == '\r') {
  482. @
  483.  
  484.  
  485. 1.3
  486. log
  487. @Recognise numeric form of CONNECT message.
  488. @
  489. text
  490. @d1 1
  491. a1 1
  492. /* $Id: response.c,v 1.2 1993/06/11 16:15:25 Rhialto Exp $
  493. d3 3
  494. d152 1
  495. a152 1
  496.         if ((*p->func)(reply, &((char *)f)[p->offset]) < 0)
  497. d155 2
  498. a170 1
  499.     RESPONSE_CONNECT,
  500. d257 1
  501. a257 1
  502.         if (c == '\r' || c == '\n') {
  503. d260 9
  504. a268 3
  505.         if (strncmp(reply, "CONNECT", 7) == 0)
  506.           state = RESPONSE_CONNECT; /* assume \r then \n for this to work */
  507.         else
  508. a271 12
  509.         break;
  510.  
  511.     case RESPONSE_CONNECT:
  512.         if (c != '\n')
  513.             log(L_WARNING, "invalid connect message");
  514.         else {
  515.         connect:
  516.             log(L_INFO, "received connect response");
  517.         }
  518.         f->flags |= FAX_F_CONNECT;
  519.         f->result = 0;
  520.         state = RESPONSE_DONE;
  521. @
  522.  
  523.  
  524. 1.2
  525. log
  526. @First real RCS checkin
  527. @
  528. text
  529. @d1 5
  530. a5 2
  531. /* $Id$
  532.  * $Log$
  533. d227 1
  534. a227 1
  535.       case RESPONSE_START:
  536. d240 1
  537. a240 1
  538.       case RESPONSE_NUMERIC:
  539. d243 2
  540. d252 1
  541. a252 1
  542.       case RESPONSE_TEXT:
  543. d257 1
  544. a257 1
  545.           state = RESPONSE_CONNECT;
  546. d264 1
  547. a264 1
  548.       case RESPONSE_CONNECT:
  549. d266 5
  550. a270 3
  551.           log(L_WARNING, "invalid connect message");
  552.         else
  553.           log(L_INFO, "received connect response");
  554. d276 1
  555. a276 1
  556.       default:
  557. @
  558.  
  559.  
  560. 1.1
  561. log
  562. @Initial revision
  563. @
  564. text
  565. @d1 3
  566. d60 1
  567. d90 10
  568. a99 2
  569.     if ((fquote = strchr(reply, '"')) == NULL)
  570.       return (-1);
  571. @
  572.