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

传真(Fax)编程

开发平台:

C/C++

  1. /* $Id: Status.c++,v 1.2 2007/12/02 18:56:09 faxguy Exp $ */
  2. /*
  3.  * Copyright (c) 1995-1996 Sam Leffler
  4.  * Copyright (c) 1995-1996 Silicon Graphics, Inc.
  5.  * HylaFAX is a trademark of Silicon Graphics
  6.  *
  7.  * Permission to use, copy, modify, distribute, and sell this software and 
  8.  * its documentation for any purpose is hereby granted without fee, provided
  9.  * that (i) the above copyright notices and this permission notice appear in
  10.  * all copies of the software and related documentation, and (ii) the names of
  11.  * Sam Leffler and Silicon Graphics may not be used in any advertising or
  12.  * publicity relating to the software without the specific, prior written
  13.  * permission of Sam Leffler and Silicon Graphics.
  14.  * 
  15.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  16.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  17.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  18.  * 
  19.  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
  20.  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
  21.  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  22.  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
  23.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
  24.  * OF THIS SOFTWARE.
  25.  */
  26. /*
  27.  * Support related to server status.
  28.  */
  29. #include "HylaFAXServer.h"
  30. #include "Sys.h"
  31. #include "config.h"
  32. #include <ctype.h>
  33. #include <sys/file.h>
  34. class ModemConfig : public FaxConfig {
  35. public:
  36.     enum { // ClassModem::SpeakerVolume
  37. OFF = 0, // nothing
  38. QUIET = 1, // somewhere near a dull chirp
  39. LOW = 2, // normally acceptable
  40. MEDIUM = 3, // heard above a stereo
  41. HIGH = 4 // ear splitting
  42.     };
  43.     u_int speakerVolume; // volume control
  44.     u_int tracingLevel; // tracing level w/o session
  45.     u_int logTracingLevel; // tracing level during session
  46.     u_int maxRecvPages; // max pages to accept on receive
  47.     fxStr localIdentifier; // to use in place of FAXNumber
  48.     fxStr FAXNumber; // phone number
  49.     fxStr modemName; // canonical modem name
  50.     bool isGettyRunning; // true if faxgetty responds via FIFO
  51.     fxStr status; // from status file
  52.     ModemConfig(const char* name);
  53.     ~ModemConfig() {};
  54.     bool setConfigItem(const char* tag, const char* value);
  55.     void configError(const char* fmt, ...);
  56.     void configTrace(const char* fmt, ...);
  57.     void checkGetty(const char* fifoFile);
  58. };
  59. ModemConfig::ModemConfig(const char* name) : modemName(name)
  60. {
  61.     HylaFAXServer::canonModem(modemName);
  62.     maxRecvPages = (u_int) -1;
  63.     tracingLevel = 0;
  64.     logTracingLevel = 0;
  65.     speakerVolume = QUIET;
  66. }
  67. void ModemConfig::configError(const char*, ...) {}
  68. void ModemConfig::configTrace(const char*, ...) {}
  69. void
  70. ModemConfig::checkGetty(const char* fifoFile)
  71. {
  72.     int fifo;
  73.     Sys::close(fifo = Sys::open(fifoFile, O_WRONLY|O_NDELAY));
  74.     isGettyRunning = (fifo != -1);
  75. }
  76. bool
  77. ModemConfig::setConfigItem(const char* tag, const char* value)
  78. {
  79.     if (streq(tag, "faxnumber"))
  80. FAXNumber = value;
  81.     else if (streq(tag, "localidentifier"))
  82. localIdentifier = value;
  83.     else if (streq(tag, "speakervolume")) { // XXX duplicates code elsewhere
  84. if (strcasecmp(value, "off") == 0)
  85.     speakerVolume = OFF;
  86. else if (strcasecmp(value, "quiet") == 0)
  87.     speakerVolume = QUIET;
  88. else if (strcasecmp(value, "low") == 0)
  89.     speakerVolume = LOW;
  90. else if (strcasecmp(value, "medium") == 0)
  91.     speakerVolume = MEDIUM;
  92. else
  93.     speakerVolume = HIGH;
  94.     } else if (streq(tag, "tracinglevel"))
  95. tracingLevel = getNumber(value);
  96.     else if (streq(tag, "logtracinglevel"))
  97. logTracingLevel = getNumber(value);
  98.     else if (streq(tag, "maxrecvpages"))
  99. maxRecvPages = getNumber(value);
  100.     return (true); // avoid complaints
  101. }
  102. void
  103. HylaFAXServer::listStatus(FILE* fd, const SpoolDir& sd, DIR* dir)
  104. {
  105.     /*
  106.      * Check scheduler status.
  107.      */
  108.     int fifo;
  109.     Sys::close(fifo = Sys::open("/" FAX_FIFO, O_WRONLY|O_NDELAY));
  110.     fprintf(fd, "HylaFAX scheduler on %s: %srn"
  111. , (const char*) hostname
  112. , fifo != -1 ? "Running" : "Not running"
  113.     );
  114.     /*
  115.      * Cross-check entries in the status directory
  116.      * against the other files required for an operating
  117.      * modem.  There must be a configuration file and,
  118.      * if there is a faxgetty process running, there must
  119.      * be a FIFO special file in the root filesystem.
  120.      */
  121.     fxStr path(sd.pathname);
  122.     struct stat sb;
  123.     fxStr fifoPrefix("/" FAX_FIFO ".");
  124.     fxStrArray files;
  125.     struct dirent* dp;
  126.     while ((dp = readdir(dir))) {
  127. files.append(dp->d_name);
  128.     }
  129.     files.qsort();
  130.     for (u_int i = 0, n = files.length(); i < n; i++) {
  131. fxStr statusFile(path | files[i]);
  132. if (!FileCache::update(statusFile, sb) || !S_ISREG(sb.st_mode))
  133.     continue;
  134. // verify there is a modem config file
  135. fxStr configFile = fxStr::format("/" FAX_CONFIG ".%s", (const char*) files[i]);
  136. if (!FileCache::lookup(configFile, sb) || !S_ISREG(sb.st_mode))
  137.     continue;
  138. fxStr fifoFile(fifoPrefix | files[i]);
  139. if (!FileCache::lookup(fifoFile, sb) || !S_ISFIFO(sb.st_mode))
  140.     continue;
  141. ModemConfig config(files[i]);
  142. config.readConfig(configFile); // read config file
  143. config.checkGetty(fifoFile); // check for faxgetty
  144. getServerStatus(statusFile, config.status); // XXX
  145. Mprintf(fd, modemFormat, config);
  146. fputs("rn", fd);
  147.     }
  148. }
  149. void
  150. HylaFAXServer::listStatusFile(FILE* fd, const SpoolDir& dir,
  151.     const char* filename, const struct stat& sb)
  152. {
  153.     listUnixFile(fd, dir, filename, sb);
  154. }
  155. void
  156. HylaFAXServer::getServerStatus(const char* fileName, fxStr& status)
  157. {
  158.     int fd = Sys::open(fileName, O_RDONLY);
  159.     if (fd > 0) {
  160.         struct stat sb;
  161.         (void) Sys::fstat(fd, sb);
  162.         status.resize((u_int) sb.st_size);
  163.         char* buff = new char[sb.st_size];
  164.         int n = Sys::read(fd, buff, (size_t) sb.st_size);
  165.         status = buff;
  166.         Sys::close(fd);
  167.         if (n > 0 && status[n-1] == 'n') n--;
  168.         if (n == 0) {
  169.             status = "No status (empty file)";
  170.         } else {
  171.             status.resize(n);
  172.         }
  173.         delete [] buff;
  174.     } else {
  175.         status = "No status (cannot open file)";
  176.     }
  177. }
  178. static const char mformat[] = {
  179.     'a', // a
  180.     'b', // b
  181.     'c', // c
  182.     'd', // d
  183.     'e', // e
  184.     'f', // f
  185.     'g', // g
  186.     's', // h (hostname)
  187.     'i', // i
  188.     'j', // j
  189.     'k', // k
  190.     's', // l (local identifier)
  191.     's', // m (canonical modem name)
  192.     's', // n (phone number)
  193.     'o', // o
  194.     'p', // p
  195.     'q', // q
  196.     's', // r (max recv pages)
  197.     's', // s (status information)
  198.     's', // t (server/session tracing level)
  199.     'x', // u (server tracing level)
  200.     'c', // v (speaker volume)
  201.     'w', // w
  202.     'x', // x
  203.     'y', // y
  204.     'c' // z (``*'' if faxgetty is running)
  205. };
  206. /*
  207.  * Print a formatted string with fields filled in from
  208.  * the specified modem state.  This functionality is
  209.  * used to permit clients to get modem status listings
  210.  * in preferred formats.
  211.  */
  212. void
  213. HylaFAXServer::Mprintf(FILE* fd, const char* fmt, const ModemConfig& config)
  214. {
  215.     for (const char* cp = fmt; *cp; cp++) {
  216. if (*cp == '%') {
  217. #define MAXSPEC 20
  218.     char fspec[MAXSPEC];
  219.     char* fp = fspec;
  220.     *fp++ = '%';
  221.     char c = *++cp;
  222.     if (c == '-')
  223. *fp++ = c, c = *++cp;
  224.     if (isdigit(c)) {
  225. do {
  226.     *fp++ = c;
  227. } while (isdigit(c = *++cp) && fp < &fspec[MAXSPEC-3]);
  228.     }
  229.     if (c == '.') {
  230. do {
  231.     *fp++ = c;
  232. } while (isdigit(c = *++cp) && fp < &fspec[MAXSPEC-2]);
  233.     }
  234.     if (!islower(c)) {
  235. if (c == '%') // %% -> %
  236.     putc(c, fd);
  237. else
  238.     fprintf(fd, "%.*s%c", fp-fspec, fspec, c);
  239. continue;
  240.     }
  241.     fp[0] = mformat[c-'a']; // printf format string
  242.     fp[1] = '';
  243.     switch (c) {
  244.     case 'h':
  245. fprintf(fd, fspec, (const char*) hostname);
  246. break;
  247.     case 'l':
  248. fprintf(fd, fspec, (const char*) config.localIdentifier);
  249. break;
  250.     case 'm':
  251. fprintf(fd, fspec, (const char*) config.modemName);
  252. break;
  253.     case 'n':
  254. fprintf(fd, fspec, (const char*) config.FAXNumber);
  255. break;
  256.     case 'r':
  257.         /* 
  258.         * this is not used for some reason ie -1 represents infinite
  259. * if (config.maxRecvPages == (u_int) -1) {
  260. *    tmp = "INF";
  261. * } else {
  262. *    tmp = fxStr::format("%u", config.maxRecvPages);
  263.         * }
  264.         */
  265. fprintf(fd, fspec, config.maxRecvPages);
  266. break;
  267.     case 's':
  268. fprintf(fd, fspec, (const char*) config.status);
  269. break;
  270.             case 't': {
  271.             fxStr tmp = fxStr::format("%05x:%05x",
  272.                         config.tracingLevel&0xfffff,
  273.                         config.logTracingLevel&0xfffff);
  274.                     fprintf(fd, fspec, (const char*)tmp);
  275.                 }
  276.         break;
  277.     case 'v':
  278. fprintf(fd, fspec, " QLMH"[config.speakerVolume]);
  279. break;
  280.     case 'z':
  281. fprintf(fd, fspec, config.isGettyRunning ? '*' : ' ');
  282. break;
  283.     }
  284. } else
  285.     putc(*cp, fd);
  286.     }
  287. }
  288. void
  289. HylaFAXServer::nlstStatus(FILE* fd, const SpoolDir& sd, DIR* dir)
  290. {
  291.     /*
  292.      * Cross-check entries in the status directory
  293.      * against the other files required for an operating
  294.      * modem.  There must be a configuration file and,
  295.      * if there is a faxgetty process running, there must
  296.      * be a FIFO special file in the root filesystem.
  297.      */
  298.     fxStr path(sd.pathname);
  299.     struct stat sb;
  300.     fxStr fifoPrefix("/" FAX_FIFO ".");
  301.     fxStrArray files;
  302.     struct dirent* dp;
  303.     while ((dp = readdir(dir))) {
  304. files.append(dp->d_name);
  305.     }
  306.     files.qsort();
  307.     for (u_int i = 0, n = files.length(); i < n; i++) {
  308. fxStr statusFile(path | files[i]);
  309. if (!FileCache::update(statusFile, sb) || !S_ISREG(sb.st_mode))
  310.     continue;
  311. // verify there is a modem config file
  312. fxStr configFile = fxStr::format("/" FAX_CONFIG ".%s", (const char*) files[i]);
  313. if (!FileCache::lookup(configFile, sb) || !S_ISREG(sb.st_mode))
  314.     continue;
  315. fxStr fifoFile(fifoPrefix | files[i]);
  316. if (!FileCache::lookup(fifoFile, sb) || !S_ISFIFO(sb.st_mode))
  317.     continue;
  318. ModemConfig config(files[i]);
  319. config.readConfig(configFile); // read config file
  320. config.checkGetty(fifoFile); // check for faxgetty
  321. getServerStatus(statusFile, config.status); // XXX
  322. Mprintf(fd, "%mrn", config);
  323.     }
  324. }