faxmodem.c
上传用户:weiyuanprp
上传日期:2020-05-20
资源大小:1169k
文件大小:9k
源码类别:

传真(Fax)编程

开发平台:

C/C++

  1. /* $Id: faxmodem.c,v 1.4 2006/06/22 15:06:36 faxguy Exp $ */
  2. /*
  3.  * Copyright (c) 1995-1996 Sam Leffler
  4.  * Copyright (c) 1995-1996 Silicon Graphics, Inc.
  5.  *
  6.  * Permission to use, copy, modify, distribute, and sell this software and 
  7.  * its documentation for any purpose is hereby granted without fee, provided
  8.  * that (i) the above copyright notices and this permission notice appear in
  9.  * all copies of the software and related documentation, and (ii) the names of
  10.  * Sam Leffler and Silicon Graphics may not be used in any advertising or
  11.  * publicity relating to the software without the specific, prior written
  12.  * permission of Sam Leffler and Silicon Graphics.
  13.  * 
  14.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  15.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  16.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  17.  * 
  18.  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
  19.  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
  20.  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  21.  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
  22.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
  23.  * OF THIS SOFTWARE.
  24.  */
  25. #include <string.h>
  26. #include <stdio.h>
  27. #include <syslog.h>
  28. #include <stdarg.h>
  29. #include <errno.h>
  30. #include <fcntl.h>
  31. #include <stdlib.h>
  32. #include <unistd.h>
  33. #include <ctype.h>
  34. #include "config.h"
  35. #include "port.h"
  36. static void
  37. fatal(char* fmt, ...)
  38. {
  39.     va_list ap;
  40.     va_start(ap, fmt);
  41.     if (isatty(fileno(stderr))) {
  42.         vfprintf(stderr, fmt, ap);
  43.         putc('n', stderr);
  44.     } else {
  45.         vsyslog(LOG_ERR, fmt, ap);
  46.     }
  47.     va_end(ap);
  48.     exit(-1);
  49. }
  50. #define BIT(i) (1<<(i))
  51. int fxmin(int a, int b)          { return (a < b) ? a : b; }
  52. const char OPAREN = '(';
  53. const char CPAREN = ')';
  54. const char COMMA = ',';
  55. const char SPACE = ' ';
  56. /*
  57.  * Parse a Class 2 parameter range string.  This is very
  58.  * forgiving because modem vendors do not exactly follow
  59.  * the syntax specified in the "standard".  Try looking
  60.  * at some of the responses given by rev ~4.04 of the
  61.  * ZyXEL firmware (for example)!
  62.  *
  63.  * NB: We accept alphanumeric items but don't return them
  64.  *     in the parsed range so that modems like the ZyXEL 2864
  65.  *     that indicate they support ``Class Z'' are handled.
  66.  */
  67. int
  68. vparseRange(const char* cp, int masked, int nargs, ... )
  69. {
  70.     int b = 1;
  71.     va_list ap;
  72.     va_start(ap, nargs);
  73.     while (nargs-- > 0) {
  74. char matchc;
  75. int acceptList;
  76. int mask;
  77. while (cp[0] == SPACE)
  78.     cp++;
  79. if (cp[0] == OPAREN) { /* (<items>) */
  80.     matchc = CPAREN;
  81.     acceptList = 1;
  82.     cp++;
  83. } else if (isalnum(cp[0])) { /* <item> */
  84.     matchc = COMMA;
  85.     acceptList = (nargs == 0);
  86. } else { /* skip to comma */
  87.     b = 0;
  88.     break;
  89. }
  90. mask = 0;
  91. while (cp[0] && cp[0] != matchc) {
  92.     int v;
  93.     int r;
  94.     if (cp[0] == SPACE) { /* ignore white space */
  95. cp++;
  96. continue;
  97.     }
  98.     if (!isalnum(cp[0])) {
  99. b = 0;
  100. goto done;
  101.     }
  102.     if (isdigit(cp[0])) {
  103. v = 0;
  104. do {
  105.     v = v*10 + (cp[0] - '0');
  106. } while (isdigit((++cp)[0]));
  107.     } else {
  108. v = -1; /* XXX skip item below */
  109. while (isalnum((++cp)[0]))
  110.     ;
  111.     }
  112.     r = v;
  113.     if (cp[0] == '-') { /* <low>-<high> */
  114. cp++;
  115. if (!isdigit(cp[0])) {
  116.     b = 0;
  117.     goto done;
  118. }
  119. r = 0;
  120. do {
  121.     r = r*10 + (cp[0] - '0');
  122. } while (isdigit((++cp)[0]));
  123.     } else if (cp[0] == '.') { /* <d.b> */
  124. cp++;
  125. while (isdigit(cp[0])) /* XXX */
  126.     cp++;
  127. v++, r++; /* XXX 2.0 -> 3 */
  128.     }
  129.     if (v != -1) { /* expand range or list */
  130. if ((BIT(nargs) & masked) == BIT(nargs)) {
  131.     /*
  132.      * These are pre-masked values. T.32 Table 21 gives valid
  133.      * values as: 00, 01, 02, 04, 08, 10, 20, 40 (hex).
  134.      *
  135.      * Some modems may say "(00-7F)" when what's meant is
  136.      * "(00-40)" or simply "(7F)".
  137.      */
  138.     if (v == 00 && r == 127)
  139. v = r = 127;
  140.     if (v == r)
  141. mask = v;
  142.     else {
  143. r = fxmin(r, 64); /* clamp to valid range */
  144. mask = 0;
  145. for (; v <= r; v++)
  146.     if (v == 0 || v == 1 || v == 2 || v == 4 || v == 8 || v == 16 || v == 32 || v == 64)
  147. mask += v;
  148.     }
  149. }
  150. else {
  151. r = fxmin(r, 31); /* clamp to valid range */
  152. for (; v <= r; v++)
  153.     mask |= 1<<v;
  154. }
  155.     }
  156.     if (acceptList && cp[0] == COMMA) /* (<item>,<item>...) */
  157. cp++;
  158. }
  159. *va_arg(ap, int*) = mask;
  160. if (cp[0] == matchc)
  161.     cp++;
  162. if (matchc == CPAREN && cp[0] == COMMA)
  163.     cp++;
  164.     }
  165. done:
  166.     va_end(ap);
  167.     return (b);
  168. }
  169. /*
  170.  * Class 2 Fax Modem Definitions.
  171.  */
  172. #define VR_ALL (BIT(7)-1)
  173. #define BR_ALL (BIT(6)-1) /* don't encode > 14.4 Kbps */
  174. #define WD_ALL (BIT(5)-1)
  175. #define LN_ALL (BIT(3)-1)
  176. #define DF_ALL (BIT(4)-1)
  177. #define EC_DISABLE 0
  178. #define EC_ALL (BIT(5)-1)
  179. #define BF_ALL (BIT(2)-1)
  180. #define ST_ALL (BIT(8)-1)
  181. /*
  182.  * Parse a Class 2 parameter specification and
  183.  * return a string with the encoded information.
  184.  * This should encode identically as does
  185.  * Class2Params::encodeCaps().
  186.  */
  187. int
  188. parseCapabilities(const char* cp, u_int* caps)
  189. {
  190.     /* we are limited to 32 bits, thus BR_ALL is restricted above */
  191.     int vr, br, wd, ln, df, ec, bf, st;
  192.     
  193.     /*
  194.      * reversed, count-down style bitmask: used to tell vparseRange
  195.      * which capabilities are 'true' bitmask (not just max bit);
  196.      * right now they are vr and bf (ie: vr is 7th position considering
  197.      * the list in reversed order and base 0)
  198.      */
  199.     int masked = (1 << 7) + (1 << 1);
  200.     
  201.     if (vparseRange(cp, masked, 8, &vr,&br,&wd,&ln,&df,&ec,&bf,&st)) {
  202. *caps = (vr&VR_ALL)
  203.      | ((br&BR_ALL)<<8)
  204.      | ((wd&WD_ALL)<<14)
  205.      | ((ln&LN_ALL)<<19)
  206.      | ((df&DF_ALL)<<22)
  207.      | ((ec&EC_DISABLE)<<26)
  208.      | (((ec&EC_ALL) != 0 ? 1 : 0)<<27)
  209.      | ((bf&BF_ALL)<<28)
  210.      | ((st&ST_ALL)<<30)
  211.      ;
  212. return (1);
  213.     } else
  214. return (0);
  215. }
  216. #undef BIT
  217. extern int cvtFacility(const char*, int*);
  218. int
  219. main(int argc, char** argv)
  220. {
  221.     extern int optind;
  222.     extern char* optarg;
  223.     int fifo, c;
  224.     char* spooldir = FAX_SPOOLDIR;
  225.     u_int caps;
  226.     char canpoll = 'P'; /* can poll by default */
  227.     char devname[80];
  228.     int cmdlen, pdevlen;
  229.     char cmd[80];
  230.     const char* usage = "[-c fax-capabilities] [-p] [-P] [-u priority] [-q queue-dir]";
  231.     char* cp;
  232.     int facility = LOG_DAEMON;
  233.     int priority = -1;
  234.     (void) cvtFacility(LOG_FAX, &facility);
  235.     openlog(argv[0], LOG_PID|LOG_ODELAY, facility);
  236.     /*
  237.      * Setup defaults:
  238.      *
  239.      * (vr),(br),(wd),(ln),(df),(ec),(bf),(st)
  240.      * where,
  241.      * vr vertical resolution
  242.      * br bit rate
  243.      * wd page width
  244.      * ln page length
  245.      * df data compression
  246.      * ec error correction
  247.      * bf binary file transfer
  248.      * st scan time/line
  249.      */
  250.     parseCapabilities("(0,1),(0-3),(0-4),(0-2),(0),(0),(0),(0-7)", &caps);
  251.     while ((c = getopt(argc, argv, "c:q:u:pP")) != -1)
  252. switch (c) {
  253. case 'c':
  254.     if (!parseCapabilities(optarg, &caps))
  255. fatal("Syntax error parsing Class 2 capabilities string "%s"",
  256.     optarg);
  257.     break;
  258. case 'p':
  259. case 'P':
  260.     canpoll = c;
  261.     break;
  262. case 'q':
  263.     spooldir = optarg;
  264.     break;
  265. case 'u':
  266.     priority = atoi(optarg);
  267.     break;
  268. case '?':
  269.     fatal("usage: %s %s modem", argv[0], usage);
  270.     /*NOTREACHED*/
  271. }
  272.     if (optind != argc-1) {
  273.         fatal("Missing modem device.nusage: %s %s modem", argv[0], usage);
  274.     }
  275.     pdevlen = strlen(_PATH_DEV);
  276.     if (strncmp(argv[optind], _PATH_DEV, pdevlen) == 0) {
  277.         if (strlen(argv[optind] + pdevlen) < sizeof(devname)) {
  278.             strcpy(devname, argv[optind] + pdevlen);
  279.         } else {
  280.             fatal("Argument is too long: %s", argv[optind] + pdevlen);
  281.         }
  282.     } else {
  283.         if (strlen(argv[optind]) < sizeof(devname)) {
  284.             strcpy(devname, argv[optind]);
  285.         } else {
  286.             fatal("Argument is too long: %s", argv[optind]);
  287.         }
  288.     }
  289.     for (cp = devname; (cp = strchr(cp, '/')); *cp++ = '_')
  290. ;
  291.     if (chdir(spooldir) < 0) {
  292.         fatal("%s: chdir: %s", spooldir, strerror(errno));
  293.     }
  294.     fifo = open(FAX_FIFO, O_WRONLY|O_NDELAY);
  295.     if (fifo < 0) {
  296.         fatal("%s: open: %s", FAX_FIFO, strerror(errno));
  297.     }
  298.     if (priority != -1) {
  299.         cmdlen = snprintf(cmd, sizeof(cmd), "+%s:R%c%08x:%x", devname, canpoll, caps, priority);
  300.     } else {
  301.         cmdlen = snprintf(cmd, sizeof(cmd), "+%s:R%c%08x", devname, canpoll, caps);
  302.     }
  303.     if (cmdlen < 0 || cmdlen > sizeof(cmd) || write(fifo, cmd, cmdlen) != cmdlen) {
  304.         fatal("%s: FIFO write failed for command (%s)",
  305.             argv[0], strerror(errno));
  306.     }
  307.     (void) close(fifo);
  308.     return 0;
  309. }