PageRenderTime 43ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/hylafax-6.0.5/hfaxd/RecvQueue.c++

https://github.com/claymodel/voip-foip
C++ | 510 lines | 414 code | 19 blank | 77 comment | 92 complexity | f0f628e79c8d1eb695d207a526451466 MD5 | raw file
  1. /* $Id$ */
  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] != '\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. ri.callid.resize(i+1);
  171. while (cp[0] != '\0' && cp[0] != '\n') {
  172. ri.callid[i].append(cp[0]);
  173. cp++;
  174. }
  175. sanitize(ri.callid[i]);
  176. i++;
  177. }
  178. } else
  179. ri.sender = "<unknown>";
  180. #ifdef TIFFTAG_FAXSUBADDRESS
  181. if (TIFFGetField(tif, TIFFTAG_FAXSUBADDRESS, &cp)) {
  182. ri.subaddr = cp;
  183. sanitize(ri.subaddr);
  184. } else
  185. #endif
  186. ri.subaddr = "";
  187. fxStr date;
  188. if (TIFFGetField(tif, TIFFTAG_DATETIME, &cp)) { // time received
  189. date = cp;
  190. sanitize(date);
  191. }
  192. ri.time = 0;
  193. ri.npages = 0; // page count
  194. do {
  195. ri.npages++;
  196. #ifdef TIFFTAG_FAXRECVTIME
  197. if (TIFFGetField(tif, TIFFTAG_FAXRECVTIME, &v))
  198. ri.time += (u_int) v;
  199. #endif
  200. } while (TIFFReadDirectory(tif));
  201. TIFFClose(tif);
  202. return (true);
  203. }
  204. bool
  205. HylaFAXServer::isVisibleRecvQFile(const char* filename, const struct stat& sb)
  206. {
  207. return (strncmp(filename, "fax", 3) == 0) && (publicRecvQ || checkFileRights(R_OK, sb) );
  208. }
  209. RecvInfo*
  210. HylaFAXServer::getRecvInfo(const fxStr& qfile, const struct stat& sb)
  211. {
  212. RecvInfo* rip = recvq[qfile];
  213. if (!rip) {
  214. rip = new RecvInfo(qfile);
  215. if (!getRecvDocStatus(*rip)) {
  216. delete rip;
  217. return (NULL);
  218. }
  219. // NB: this will be wrong if the file is copied
  220. rip->recvTime = sb.st_mtime; // time recv completed
  221. recvq[qfile] = rip;
  222. } else if (rip->beingReceived && rip->recvTime < sb.st_mtime) {
  223. if (!getRecvDocStatus(*rip)) {
  224. recvq.remove(qfile);
  225. delete rip;
  226. return (NULL);
  227. }
  228. // NB: this will be wrong if the file is copied
  229. rip->recvTime = sb.st_mtime; // time recv completed
  230. }
  231. return (rip);
  232. }
  233. void
  234. HylaFAXServer::listRecvQ(FILE* fd, const SpoolDir& sd, DIR* dir)
  235. {
  236. KeyStringArray listing;
  237. /*
  238. * Use an absolute pathname when doing file
  239. * lookups to improve cache locality.
  240. */
  241. fxStr path(sd.pathname);
  242. struct dirent* dp;
  243. while ((dp = readdir(dir))) {
  244. struct stat sb;
  245. fxStr qfile(path | dp->d_name);
  246. RecvInfo* rip;
  247. if (!FileCache::update(qfile, sb))
  248. continue;
  249. if (!isVisibleRecvQFile(dp->d_name, sb))
  250. continue;
  251. rip = getRecvInfo(qfile, sb);
  252. if (rip) {
  253. if (recvSortFormat.length() == 0) {
  254. Rprintf(fd, recvFormat, *rip, sb);
  255. fputs("\r\n", fd);
  256. } else {
  257. fxStackBuffer buf;
  258. Rprintf(buf, recvFormat, *rip, sb);
  259. fxStr content(buf, buf.getLength());
  260. buf.reset();
  261. Rprintf(buf, recvSortFormat, *rip, sb);
  262. fxStr key(buf, buf.getLength());
  263. listing.append(KeyString(key, content));
  264. }
  265. }
  266. }
  267. if (listing.length() > 1)
  268. listing.qsort();
  269. for (u_int i = 0; i < listing.length(); i++)
  270. {
  271. fwrite(listing[i], listing[i].length(), 1, fd);
  272. fputs("\r\n", fd);
  273. }
  274. }
  275. void
  276. HylaFAXServer::listRecvQFile(FILE* fd, const SpoolDir& dir,
  277. const char* filename, const struct stat& sb)
  278. {
  279. RecvInfo* rip =
  280. getRecvInfo(fxStr::format("%s%s", dir.pathname, filename), sb);
  281. if (rip)
  282. Rprintf(fd, recvFormat, *rip, sb);
  283. else
  284. listUnixFile(fd, dir, filename, sb);
  285. }
  286. static const char rformat[] = {
  287. 'A', // A
  288. 'B', // B
  289. 'C', // C
  290. 'D', // D
  291. 'E', // E
  292. 'F', // F
  293. 'G', // G
  294. 'H', // H
  295. 'I', // I
  296. 'J', // J
  297. 'K', // K
  298. 'L', // L
  299. 'M', // M
  300. 'N', // N
  301. 'O', // O
  302. 'P', // P
  303. 'Q', // Q
  304. 'R', // R
  305. 'S', // S
  306. 'T', // T
  307. 'U', // U
  308. 'V', // V
  309. 'W', // W
  310. 'X', // X
  311. 's', // Y (tts in strftime %Y/%m/%d %H.%M.%S format)
  312. 'u', // Z (tts as decimal time_t)
  313. '[', // [
  314. '\\', // \ (must have something after the backslash)
  315. ']', // ]
  316. '^', // ^
  317. '_', // _
  318. '`', // `
  319. 's', // a (subaddr)
  320. 'u', // b (bitrate)
  321. 'c', // c
  322. 's', // d (data format)
  323. 's', // e (error a.k.a. reason)
  324. 's', // f (filename)
  325. 'g', // g
  326. 's', // h (time spent receiving)
  327. 's', // i (CIDName)
  328. 's', // j (CIDNumber)
  329. 'k', // k
  330. 'u', // l (pagelength)
  331. 's', // m (protection mode)
  332. 'u', // n (file size)
  333. 's', // o (owner)
  334. 'u', // p (npages)
  335. 'q', // q (UNIX-style protection mode)
  336. 'u', // r (resolution)
  337. 's', // s (sender TSI)
  338. 's', // t (time received)
  339. 'u', // u
  340. 'v', // v
  341. 'u', // w (pagewidth)
  342. 'x', // x
  343. 'y', // y
  344. 's' // z (``*'' if being received)
  345. };
  346. #define rounddown(x, y) (((x)/(y))*(y))
  347. /*
  348. * Return a compact notation for the specified
  349. * time. This notation is guaranteed to fit in
  350. * a 7-character field. We select one of 5
  351. * representations based on how close the time
  352. * is to ``now''.
  353. */
  354. const char*
  355. HylaFAXServer::compactRecvTime(time_t t)
  356. {
  357. time_t now = Sys::now();
  358. if (t < now) { // in the past
  359. static char buf[15];
  360. const struct tm* tm = cvtTime(t);
  361. if (t > rounddown(now, 24*60*60)) // today, use 19:37
  362. strftime(buf, sizeof (buf), "%H:%M", tm);
  363. else if (t > now-7*24*60*60) // within a week, use Sun 6pm
  364. strftime(buf, sizeof (buf), "%a%I%p", tm);
  365. else // over a week, use 25Dec95
  366. strftime(buf, sizeof (buf), "%d%b%y", tm);
  367. return (buf);
  368. } else
  369. return ("");
  370. }
  371. /*
  372. * Print a formatted string with fields filled in from
  373. * the specified received facsimile state. This
  374. * functionality is used to permit clients to get recv
  375. * queue state listings in preferred formats.
  376. */
  377. void
  378. HylaFAXServer::Rprintf(fxStackBuffer& buf, const char* fmt,
  379. const RecvInfo& ri, const struct stat& sb)
  380. {
  381. for (const char* cp = fmt; *cp; cp++) {
  382. if (*cp == '%') {
  383. #define MAXSPEC 20
  384. char fspec[MAXSPEC];
  385. char* fp = fspec;
  386. *fp++ = '%';
  387. char c = *++cp;
  388. if (c == '-')
  389. *fp++ = c, c = *++cp;
  390. if (isdigit(c)) {
  391. do {
  392. *fp++ = c;
  393. } while (isdigit(c = *++cp) && fp < &fspec[MAXSPEC-3]);
  394. }
  395. if (c == '.') {
  396. do {
  397. *fp++ = c;
  398. } while (isdigit(c = *++cp) && fp < &fspec[MAXSPEC-2]);
  399. }
  400. if (!isalpha(c)) {
  401. if (c == '%') // %% -> %
  402. buf.put(c);
  403. else
  404. buf.fput("%.*s%c", fp-fspec, fspec, c);
  405. continue;
  406. }
  407. fp[0] = rformat[c-'A']; // printf format string
  408. fp[1] = '\0';
  409. switch (c) {
  410. case 'a':
  411. buf.fput(fspec, (const char*) ri.subaddr);
  412. break;
  413. case 'b':
  414. buf.fput(fspec, ri.params.bitRate());
  415. break;
  416. case 'd':
  417. buf.fput(fspec, ri.params.dataFormatName());
  418. break;
  419. case 'e':
  420. buf.fput(fspec, (const char*) ri.reason);
  421. break;
  422. case 'f':
  423. fp = (char *) strrchr(ri.qfile, '/');
  424. buf.fput(fspec, fp ? fp+1 : (const char*) ri.qfile);
  425. break;
  426. case 'h':
  427. buf.fput(fspec, fmtTime(ri.time));
  428. break;
  429. case 'i':
  430. buf.fput(fspec, ri.callid.size() > CallID::NAME ? (const char*) ri.callid.id(CallID::NAME) : "");
  431. break;
  432. case 'j':
  433. buf.fput(fspec, ri.callid.size() > CallID::NUMBER ? (const char*) ri.callid.id(CallID::NUMBER) : "");
  434. break;
  435. case 'l':
  436. buf.fput(fspec, ri.params.pageLength());
  437. break;
  438. case 'm':
  439. case 'q':
  440. { char prot[8]; // XXX HP C++
  441. makeProt(sb, c == 'q', prot);
  442. buf.fput(fspec, prot);
  443. }
  444. break;
  445. case 'n':
  446. buf.fput(fspec, (u_int) sb.st_size); // XXX
  447. break;
  448. case 'o':
  449. buf.fput(fspec, userName((u_int) sb.st_gid));
  450. break;
  451. case 'p':
  452. buf.fput(fspec, ri.npages);
  453. break;
  454. case 'r':
  455. buf.fput(fspec, ri.params.verticalRes());
  456. break;
  457. case 's':
  458. buf.fput(fspec, (const char*) ri.sender);
  459. break;
  460. case 't':
  461. buf.fput(fspec, compactRecvTime(ri.recvTime));
  462. break;
  463. case 'w':
  464. buf.fput(fspec, ri.params.pageWidth());
  465. break;
  466. case 'z':
  467. buf.fput(fspec, ri.beingReceived ? "*" : " ");
  468. break;
  469. case 'Y':
  470. { char tbuf[30]; // XXX HP C++
  471. strftime(tbuf, sizeof (tbuf), "%Y/%m/%d %H.%M.%S",
  472. IS(USEGMT) ? gmtime(&ri.recvTime) : localtime(&ri.recvTime));
  473. buf.fput(fspec, tbuf);
  474. }
  475. break;
  476. case 'Z':
  477. buf.fput(fspec, ri.recvTime);
  478. break;
  479. }
  480. } else
  481. buf.put(*cp);
  482. }
  483. }
  484. void
  485. HylaFAXServer::Rprintf(FILE* fd, const char* fmt,
  486. const RecvInfo& ri, const struct stat& sb)
  487. {
  488. fxStackBuffer buf;
  489. Rprintf(buf, fmt, ri, sb);
  490. fwrite((const char*)buf, buf.getLength(), 1, fd);
  491. }