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

传真(Fax)编程

开发平台:

C/C++

  1. /* $Id: RecvQueue.c++,v 1.11 2008/04/05 18:06:33 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 received facsimile.
  28.  */
  29. #include "HylaFAXServer.h"
  30. #include "Sys.h"
  31. #include "Socket.h"
  32. #include "tiffio.h"
  33. #include <ctype.h>
  34. #include <sys/file.h>
  35. RecvInfo::RecvInfo()
  36. {
  37.     beingReceived = false;
  38.     recvTime = 0;
  39. }
  40. RecvInfo::RecvInfo(const char* qf)
  41. {
  42.     qfile = qf;
  43.     beingReceived = false;
  44.     recvTime = 0;
  45. }
  46. RecvInfo::~RecvInfo() {}
  47. fxIMPLEMENT_StrKeyPtrValueDictionary(RecvInfoDict, RecvInfo*)
  48. /*
  49.  * This tests whether the tif file is a "fax" image.
  50.  * Traditional fax images are MH, MR, MMR, but some can
  51.  * be JPEG, JBIG, and possibly others.  So we use
  52.  * TIFFTAG_FAXRECVPARAMS as a "fax" image identifier,
  53.  * and if it's not there, then we resort to traditional
  54.  * tactics.
  55.  */
  56. static bool
  57. isFAXImage(TIFF* tif)
  58. {
  59. #ifdef TIFFTAG_FAXRECVPARAMS
  60.     uint32 v;
  61.     if (TIFFGetField(tif, TIFFTAG_FAXRECVPARAMS, &v) && v != 0)
  62. return (true);
  63. #endif
  64.     uint16 w;
  65.     if (TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &w) && w != 1)
  66. return (false);
  67.     if (TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &w) && w != 1)
  68. return (false);
  69.     if (!TIFFGetField(tif, TIFFTAG_COMPRESSION, &w) ||
  70.       (w != COMPRESSION_CCITTFAX3 && w != COMPRESSION_CCITTFAX4))
  71. return (false);
  72.     if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &w) ||
  73.       (w != PHOTOMETRIC_MINISWHITE && w != PHOTOMETRIC_MINISBLACK))
  74. return (false);
  75.     return (true);
  76. }
  77. /*
  78.  * Construct receive information from a file's contents.
  79.  */
  80. bool
  81. HylaFAXServer::getRecvDocStatus(RecvInfo& ri)
  82. {
  83.     int fd = Sys::open(ri.qfile, O_RDWR); // RDWR for flock emulation
  84.     if (fd < 0)
  85. return (false);
  86.     /*
  87.      * Files that are being received are locked
  88.      * for exclusive use by faxgetty.  
  89.      */
  90.     ri.beingReceived = (flock(fd, LOCK_SH|LOCK_NB) < 0 && errno == EWOULDBLOCK);
  91.     TIFF* tif = TIFFFdOpen(fd, ri.qfile, "r");
  92.     if (!tif) {
  93. Sys::close(fd);
  94. /*
  95.  * File may not have an IFD written yet,
  96.  * if it's locked just assume so...
  97.  */
  98. return (ri.beingReceived);
  99.     }
  100.     /*
  101.      * We know that faxgetty will write received
  102.      * data in only a limited set for formats.
  103.      */
  104.     if (!isFAXImage(tif)) {
  105. TIFFClose(tif);
  106. return (false);
  107.     }
  108.     /*
  109.      * Should be a received facsimile, build up status.
  110.      * Note that certain information was not recorded
  111.      * in older versions of the software; thus the careful
  112.      * checks for certain tags and their values.
  113.      */
  114.     uint32 v;
  115. #ifdef TIFFTAG_FAXRECVPARAMS
  116.     if (TIFFGetField(tif, TIFFTAG_FAXRECVPARAMS, &v))
  117. ri.params.decode((u_int) v); // page transfer params
  118.     else {
  119. #endif
  120.     float vres = 3.85; // XXX default
  121.     if (TIFFGetField(tif, TIFFTAG_YRESOLUTION, &vres)) {
  122. uint16 resunit = RESUNIT_INCH; // TIFF spec default
  123. TIFFGetField(tif, TIFFTAG_RESOLUTIONUNIT, &resunit);
  124. if (resunit == RESUNIT_INCH)
  125.     vres /= 25.4;
  126. if (resunit == RESUNIT_NONE)
  127.     vres /= 720.0; // postscript units ?
  128.     }
  129.     float hres = 8.03; // XXX default
  130.     if (TIFFGetField(tif, TIFFTAG_XRESOLUTION, &hres)) {
  131. uint16 resunit = RESUNIT_INCH; // TIFF spec default
  132. TIFFGetField(tif, TIFFTAG_RESOLUTIONUNIT, &resunit);
  133. if (resunit == RESUNIT_INCH)
  134.     hres /= 25.4;
  135. if (resunit == RESUNIT_NONE)
  136.     hres /= 720.0; // postscript units ?
  137.     }
  138.     ri.params.setRes((u_int) hres, (u_int) vres); // resolution
  139.     TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &v);
  140.     ri.params.setPageWidthInPixels((u_int) v); // page width
  141.     TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &v);
  142.     ri.params.setPageLengthInMM((u_int)(v / vres)); // page length
  143. #ifdef TIFFTAG_FAXRECVPARAMS
  144.     }
  145. #endif
  146.     char* cp;
  147. #ifdef TIFFTAG_FAXDCS
  148.     if (TIFFGetField(tif, TIFFTAG_FAXDCS, &cp) && strncmp(cp, "00 00 00", 8) != 0) {
  149. // cannot trust br from faxdcs as V.34-Fax does not provide it there
  150. u_int brhold = ri.params.br;
  151. fxStr faxdcs(cp);
  152. sanitize(faxdcs);
  153. ri.params.asciiDecode((const char*) faxdcs); // params per Table 2/T.30
  154. ri.params.setFromDCS(ri.params);
  155. ri.params.br = brhold;
  156.     }
  157. #endif
  158.     ri.sender = "";
  159.     CallID empty_callid;
  160.     ri.callid = empty_callid;
  161.     if (TIFFGetField(tif, TIFFTAG_IMAGEDESCRIPTION, &cp)) {
  162. while (cp[0] != '' && cp[0] != 'n') { // sender 
  163.     ri.sender.append(cp[0]);
  164.     cp++;
  165. }
  166. sanitize(ri.sender);
  167. u_int i = 0;
  168. while (cp[0] == 'n') {
  169.     cp++;
  170.     if (strchr(cp, 't') && (!strchr(cp, 'n') || strchr(cp, 't') < strchr(cp, 'n'))) {
  171. // skip over the label part
  172. while (cp[0] != '' && cp[0] != 't') cp++;
  173. if (cp[0] == 't') cp++;
  174.     }
  175.     ri.callid.resize(i+1);
  176.     while (cp[0] != '' && cp[0] != 'n') {
  177. ri.callid[i].append(cp[0]);
  178. cp++;
  179.     }
  180.     sanitize(ri.callid[i]);
  181.     i++;
  182. }
  183.     } else
  184. ri.sender = "<unknown>";
  185. #ifdef TIFFTAG_FAXSUBADDRESS
  186.     if (TIFFGetField(tif, TIFFTAG_FAXSUBADDRESS, &cp)) {
  187. ri.subaddr = cp;
  188. sanitize(ri.subaddr);
  189.     } else
  190. #endif
  191. ri.subaddr = "";
  192.     fxStr date;
  193.     if (TIFFGetField(tif, TIFFTAG_DATETIME, &cp)) { // time received
  194. date = cp;
  195. sanitize(date);
  196.     }
  197.     ri.time = 0;
  198.     ri.npages = 0; // page count
  199.     do {
  200. ri.npages++;
  201. #ifdef TIFFTAG_FAXRECVTIME
  202. if (TIFFGetField(tif, TIFFTAG_FAXRECVTIME, &v))
  203.     ri.time += (u_int) v;
  204. #endif
  205.     } while (TIFFReadDirectory(tif));
  206.     TIFFClose(tif);
  207.     return (true);
  208. }
  209. #define A_READ   004
  210. #define A_WRITE  002
  211. #define A_MODIFY 001
  212. bool
  213. HylaFAXServer::isVisibleRecvQFile(const char* filename, const struct stat& sb)
  214. {
  215.     if (strncmp(filename, "fax", 3) == 0 || strncmp(filename, FAX_SEQF, 4) == 0) {
  216. if (recvqProtection & A_READ) // other/public access
  217.     return (true);
  218. if (IS(PRIVILEGED) && ((recvqProtection>>3) & A_READ)) // administrative access
  219.     return (true);
  220. if (((u_int) sb.st_gid == uid) && ((recvqProtection>>6) & A_READ)) // owner access
  221.     return (true);
  222.     }
  223.     return (false);
  224. }
  225. RecvInfo*
  226. HylaFAXServer::getRecvInfo(const fxStr& qfile, const struct stat& sb)
  227. {
  228.     RecvInfo* rip = recvq[qfile];
  229.     if (!rip) {
  230. rip = new RecvInfo(qfile);
  231. if (!getRecvDocStatus(*rip)) {
  232.     delete rip;
  233.     return (NULL);
  234. }
  235. // NB: this will be wrong if the file is copied
  236. rip->recvTime = sb.st_mtime; // time recv completed
  237. recvq[qfile] = rip;
  238.     } else if (rip->beingReceived && rip->recvTime < sb.st_mtime) {
  239. if (!getRecvDocStatus(*rip)) {
  240.     recvq.remove(qfile);
  241.     delete rip;
  242.     return (NULL);
  243. }
  244. // NB: this will be wrong if the file is copied
  245. rip->recvTime = sb.st_mtime; // time recv completed
  246.     }
  247.     return (rip);
  248. }
  249. void
  250. HylaFAXServer::listRecvQ(FILE* fd, const SpoolDir& sd, DIR* dir)
  251. {
  252.     /*
  253.      * Use an absolute pathname when doing file
  254.      * lookups to improve cache locality.
  255.      */
  256.     fxStr path(sd.pathname);
  257.     fxStrArray files;
  258.     struct dirent* dp;
  259.     while ((dp = readdir(dir))) {
  260. files.append(dp->d_name);
  261.     }
  262.     files.qsort();
  263.     for (u_int i = 0, n = files.length(); i < n; i++) {
  264. fxStr qfile(path | files[i]);
  265. struct stat sb;
  266. if (FileCache::update(qfile, sb)) {
  267.     if (!isVisibleRecvQFile(files[i], sb))
  268. continue;
  269.     RecvInfo* rip;
  270.     if ((rip = getRecvInfo(qfile, sb))) {
  271. Rprintf(fd, recvFormat, *rip, sb);
  272. fputs("rn", fd);
  273.     }
  274. }
  275.     }
  276. }
  277. void
  278. HylaFAXServer::listRecvQFile(FILE* fd, const SpoolDir& dir,
  279.     const char* filename, const struct stat& sb)
  280. {
  281.     RecvInfo* rip =
  282. getRecvInfo(fxStr::format("%s%s", dir.pathname, filename), sb);
  283.     if (rip)
  284. Rprintf(fd, recvFormat, *rip, sb);
  285.     else
  286. listUnixFile(fd, dir, filename, sb);
  287. }
  288. static const char rformat[] = {
  289.     'A', // A
  290.     'B', // B
  291.     'C', // C
  292.     'D', // D
  293.     'E', // E
  294.     'F', // F
  295.     'G', // G
  296.     'H', // H
  297.     'I', // I
  298.     'J', // J
  299.     'K', // K
  300.     'L', // L
  301.     'M', // M
  302.     'N', // N
  303.     'O', // O
  304.     'P', // P
  305.     'Q', // Q
  306.     'R', // R
  307.     'S', // S
  308.     'T', // T
  309.     'U', // U
  310.     'V', // V
  311.     'W', // W
  312.     'u', // X (beingReceived as 1 or 0)
  313.     's', // Y (recvTime in strftime %Y:%m:%d %H:%M:%S format)
  314.     'u', // Z (recvTime as decimal time_t)
  315.     '[', // [
  316.     '\', //  (must have something after the backslash)
  317.     ']', // ]
  318.     '^', // ^
  319.     '_', // _
  320.     '`', // `
  321.     's', // a (subaddr)
  322.     'u', // b (bitrate)
  323.     'c', // c
  324.     's', // d (data format)
  325.     's', // e (error a.k.a. reason)
  326.     's', // f (filename)
  327.     'g', // g
  328.     's', // h (time spent receiving)
  329.     's', // i (CIDName)
  330.     's', // j (CIDNumber)
  331.     'k', // k
  332.     'u', // l (pagelength)
  333.     's', // m (protection mode)
  334.     'u', // n (file size)
  335.     's', // o (owner)
  336.     'u', // p (npages)
  337.     'q', // q (UNIX-style protection mode)
  338.     'u', // r (resolution)
  339.     's', // s (sender TSI)
  340.     's', // t (time received)
  341.     'u', // u
  342.     'v', // v
  343.     'u', // w (pagewidth)
  344.     'x', // x
  345.     'y', // y
  346.     's' // z (``*'' if being received)
  347. };
  348. #define rounddown(x, y) (((x)/(y))*(y))
  349. /*
  350.  * Return a compact notation for the specified
  351.  * time.  This notation is guaranteed to fit in
  352.  * a 7-character field.  We select one of 5
  353.  * representations based on how close the time
  354.  * is to ``now''.
  355.  */
  356. const char*
  357. HylaFAXServer::compactRecvTime(time_t t)
  358. {
  359.     time_t now = Sys::now();
  360.     if (t < now) { // in the past
  361. static char buf[15];
  362. const struct tm* tm = cvtTime(t);
  363. if (t > rounddown(now, 24*60*60)) // today, use 19:37
  364.     strftime(buf, sizeof (buf), "%H:%M", tm);
  365. else if (t > now-7*24*60*60) // within a week, use Sun 6pm
  366.     strftime(buf, sizeof (buf), "%a%I%p", tm);
  367. else // over a week, use 25Dec95
  368.     strftime(buf, sizeof (buf), "%d%b%y", tm);
  369. return (buf);
  370.     } else
  371. return ("");
  372. }
  373. /*
  374.  * Print a formatted string with fields filled in from
  375.  * the specified received facsimile state.  This
  376.  * functionality is used to permit clients to get recv
  377.  * queue state listings in preferred formats.
  378.  */
  379. void
  380. HylaFAXServer::Rprintf(FILE* fd, const char* fmt,
  381.     const RecvInfo& ri, const struct stat& sb)
  382. {
  383.     for (const char* cp = fmt; *cp; cp++) {
  384. if (*cp == '%') {
  385. #define MAXSPEC 20
  386.     char fspec[MAXSPEC];
  387.     char* fp = fspec;
  388.     *fp++ = '%';
  389.     char c = *++cp;
  390.     if (c == '-')
  391. *fp++ = c, c = *++cp;
  392.     if (isdigit(c)) {
  393. do {
  394.     *fp++ = c;
  395. } while (isdigit(c = *++cp) && fp < &fspec[MAXSPEC-3]);
  396.     }
  397.     if (c == '.') {
  398. do {
  399.     *fp++ = c;
  400. } while (isdigit(c = *++cp) && fp < &fspec[MAXSPEC-2]);
  401.     }
  402.     if (!isalpha(c)) {
  403. if (c == '%') // %% -> %
  404.     putc(c, fd);
  405. else
  406.     fprintf(fd, "%.*s%c", fp-fspec, fspec, c);
  407. continue;
  408.     }
  409.     fp[0] = rformat[c-'A']; // printf format string
  410.     fp[1] = '';
  411.     switch (c) {
  412.     case 'a':
  413. fprintf(fd, fspec, (const char*) ri.subaddr);
  414. break;
  415.     case 'b':
  416. fprintf(fd, fspec, ri.params.bitRate());
  417. break;
  418.     case 'd':
  419. fprintf(fd, fspec, ri.params.dataFormatName());
  420. break;
  421.     case 'e':
  422. fprintf(fd, fspec, (const char*) ri.reason);
  423. break;
  424.     case 'f':
  425. fp = (char *) strrchr(ri.qfile, '/');
  426. fprintf(fd, fspec, fp ? fp+1 : (const char*) ri.qfile);
  427. break;
  428.     case 'h':
  429. fprintf(fd, fspec, fmtTime(ri.time));
  430. break;
  431.     case 'i':
  432. fprintf(fd, fspec, ri.callid.size() > CallID::NAME ? (const char*) ri.callid.id(CallID::NAME) : "");
  433. break;
  434.     case 'j':
  435. fprintf(fd, fspec, ri.callid.size() > CallID::NUMBER ? (const char*) ri.callid.id(CallID::NUMBER) : "");
  436. break;
  437.     case 'l':
  438. fprintf(fd, fspec, ri.params.pageLength());
  439. break;
  440.     case 'm':
  441.     case 'q':
  442. { char prot[8]; // XXX HP C++
  443.   makeProt(sb, c == 'q', prot);
  444.   fprintf(fd, fspec, prot);
  445. }
  446. break;
  447.     case 'n':
  448. fprintf(fd, fspec, (u_int) sb.st_size); // XXX
  449. break;
  450.     case 'o':
  451. fprintf(fd, fspec, userName((u_int) sb.st_gid));
  452. break;
  453.     case 'p':
  454. fprintf(fd, fspec, ri.npages);
  455. break;
  456.     case 'r':
  457. fprintf(fd, fspec, ri.params.verticalRes());
  458. break;
  459.     case 's':
  460. fprintf(fd, fspec, (const char*) ri.sender);
  461. break;
  462.     case 't':
  463. fprintf(fd, fspec, compactRecvTime(ri.recvTime));
  464. break;
  465.     case 'w':
  466. fprintf(fd, fspec, ri.params.pageWidth());
  467. break;
  468.     case 'z':
  469. fprintf(fd, fspec, ri.beingReceived ? "*" : " ");
  470. break;
  471.     case 'X':
  472. fprintf(fd, fspec, ri.beingReceived);
  473. break;
  474.     case 'Y':
  475. { char buf[30]; // XXX HP C++
  476.   strftime(buf, sizeof (buf), "%Y:%m:%d %H:%M:%S",
  477. IS(USEGMT) ? gmtime(&ri.recvTime) : localtime(&ri.recvTime));
  478.   fprintf(fd, fspec, buf);
  479. }
  480. break;
  481.     case 'Z':
  482. fprintf(fd, fspec, (u_int) ri.recvTime);
  483. break;
  484.     }
  485. } else
  486.     putc(*cp, fd);
  487.     }
  488. }