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

传真(Fax)编程

开发平台:

C/C++

  1. /* $Id: FileTransfer.c++,v 1.5 2008/01/26 19:18:28 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.  * File transfer commands.
  28.  */
  29. #include "HylaFAXServer.h"
  30. #include "Sys.h"
  31. #include "config.h"
  32. #include "zlib.h"
  33. #include "tiffio.h"
  34. #include <ctype.h>
  35. #include <limits.h>
  36. #ifdef HAVE_STDINT_H
  37. #include <stdint.h>
  38. #endif
  39. #ifndef CHAR_BIT
  40. #ifdef NBBY
  41. #define CHAR_BIT NBBY
  42. #else
  43. #define CHAR_BIT 8
  44. #endif
  45. #endif /* CHAR_BIT */
  46. static  const char* typenames[] =  { "ASCII", "EBCDIC", "Image", "Local" };
  47. static  const char* strunames[] =  { "File", "Record", "Page", "TIFF" };
  48. static  const char* modenames[] =  { "Stream", "Block", "Compressed", "ZIP" };
  49. /*
  50.  * Record a file transfer in the log file.
  51.  */
  52. void
  53. HylaFAXServer::logTransfer(const char* direction,
  54.     const SpoolDir& sd, const char* pathname, time_t start)
  55. {
  56.     time_t now = Sys::now();
  57.     time_t xferfaxtime = now - start;
  58.     if (xferfaxtime == 0)
  59. xferfaxtime++;
  60.     const char* filename = strrchr(pathname, '/');
  61.     fxStr msg(fxStr::format("%.24st%lut%st%lut%s/%st%st%sn"
  62. , ctime(&now)
  63. , (u_long) xferfaxtime
  64. , (const char*) remotehost
  65. , (u_long) byte_count
  66. , sd.pathname, filename ? filename+1 : pathname
  67. , direction
  68. , (const char*) the_user
  69.     ));
  70.     (void) Sys::write(xferfaxlog, msg, msg.length());
  71. }
  72. bool
  73. HylaFAXServer::restartSend(FILE* fd, off_t marker)
  74. {
  75.     if (type == TYPE_A) { // restart based on line count
  76. int c;
  77. while ((c = getc(fd)) != EOF)
  78.     if (c == 'n' && --marker == 0)
  79. return (true);
  80. return (false);
  81.     } else // restart based on file offset
  82. return (lseek(fileno(fd), marker, SEEK_SET) == marker);
  83. }
  84. /*
  85.  * RETRieve a file.
  86.  */
  87. void
  88. HylaFAXServer::retrieveCmd(const char* name)
  89. {
  90.     struct stat sb;
  91.     SpoolDir* sd = fileAccess(name, R_OK, sb);
  92.     if (sd) {
  93. FILE* fd = fopen(name, "r");
  94. if (fd != NULL) {
  95.     if (restart_point && !restartSend(fd, restart_point)) {
  96. perror_reply(550, name, errno);
  97.     } else {
  98. time_t start_time = Sys::now();
  99. int code;
  100. FILE* dout = openDataConn("w", code);
  101. if (dout != NULL) {
  102.     file_size = sb.st_size;
  103.     reply(code, "%s for %s (%lu bytes).",
  104. dataConnMsg(code), name, (u_long) file_size);
  105.     if (sendData(fd, dout))
  106. reply(226, "Transfer complete.");
  107.     if (TRACE(OUTXFERS) && xferfaxlog != -1)
  108. logTransfer("o", *sd, name, start_time);
  109.     closeDataConn(dout);
  110. }
  111.     }
  112.     fclose(fd);
  113. } else if (errno != 0)
  114.     perror_reply(550, name, errno);
  115. else
  116.     reply(550, "%s: Cannot open file.", name);
  117.     }
  118. }
  119. /*
  120.  * TIFF Directory Template used in returning
  121.  * a single IFD/image from a TIFF file.
  122.  */
  123. typedef struct {
  124.     TIFFDirEntry SubFileType;
  125.     TIFFDirEntry ImageWidth;
  126.     TIFFDirEntry ImageLength;
  127.     TIFFDirEntry BitsPerSample;
  128.     TIFFDirEntry Compression;
  129.     TIFFDirEntry Photometric;
  130.     TIFFDirEntry FillOrder;
  131.     TIFFDirEntry StripOffsets;
  132.     TIFFDirEntry Orientation;
  133.     TIFFDirEntry SamplesPerPixel;
  134.     TIFFDirEntry RowsPerStrip;
  135.     TIFFDirEntry StripByteCounts;
  136.     TIFFDirEntry XResolution;
  137.     TIFFDirEntry YResolution;
  138.     TIFFDirEntry Options; // T4 or T6
  139.     TIFFDirEntry ResolutionUnit;
  140.     TIFFDirEntry PageNumber;
  141.     TIFFDirEntry BadFaxLines;
  142.     TIFFDirEntry CleanFaxData;
  143.     TIFFDirEntry ConsecutiveBadFaxLines;
  144.     uint32 link; // offset to next directory
  145.     uint32 xres[2]; // X resolution indirect value
  146.     uint32 yres[2]; // Y resolution indirect value
  147. } DirTemplate;
  148. /*
  149.  * RETrieve one Page from a file.  For now the
  150.  * file must be a TIFF image; we might try to
  151.  * handle PostScript at a later time (but don't
  152.  * hold your breath as there's not much reason).
  153.  */
  154. void
  155. HylaFAXServer::retrievePageCmd(const char* name)
  156. {
  157.     TIFF* tif = cachedTIFF;
  158.     if (tif != NULL && streq(name, TIFFFileName(tif))) {
  159. /*
  160.  * Reuse the cached open file.  If no directory
  161.  * has been specified with a REST command then
  162.  * return the next consecutive directory in the file.
  163.  */
  164. if (restart_point == 0) // advance to next directory
  165.     restart_point = TIFFCurrentDirectory(tif)+1;
  166.     } else {
  167. if (tif) // close cached handle
  168.     TIFFClose(tif), cachedTIFF = NULL;
  169. tif = openTIFF(name);
  170.     }
  171.     if (tif != NULL) {
  172. if (restart_point && !TIFFSetDirectory(tif, (tdir_t) restart_point)) {
  173.     reply(550, "%s: Unable to access directory %lu.",
  174. name, (u_long) restart_point);
  175. } else {
  176.     time_t start_time = Sys::now();
  177.     int code;
  178.     FILE* dout = openDataConn("w", code);
  179.     if (dout != NULL) {
  180. /*
  181.  * Calculate "file size" by totalling up the
  182.  * amount of image data and then adding in
  183.  * the expected data for the TIFF headers.
  184.  */
  185. uint32* sb;
  186. TIFFGetField(tif, TIFFTAG_STRIPBYTECOUNTS, &sb);
  187. file_size = sizeof (DirTemplate) +
  188.     sizeof (TIFFHeader) + sizeof (uint16);
  189. for (tstrip_t s = 0, ns = TIFFNumberOfStrips(tif); s < ns; s++)
  190.     file_size += sb[s];
  191. reply(code, "%s for %s (%lu bytes).",
  192.     dataConnMsg(code), name, (u_long) file_size);
  193. if (sendTIFFData(tif, dout))
  194.     reply(226, "Transfer complete.");
  195. if (TRACE(OUTXFERS) && xferfaxlog != -1) {
  196.     struct stat sb;
  197.     SpoolDir* sd = fileAccess(name, R_OK, sb);
  198.     logTransfer("o", *sd, name, start_time);
  199. }
  200. closeDataConn(dout);
  201.     }
  202. }
  203. cachedTIFF = tif;
  204.     }
  205. }
  206. /*
  207.  * Open a file that is expected to hold a TIFF image.
  208.  */
  209. TIFF*
  210. HylaFAXServer::openTIFF(const char* name)
  211. {
  212.     struct stat sb;
  213.     SpoolDir* sd = fileAccess(name, R_OK, sb);
  214.     if (sd) {
  215. int fd = Sys::open(name, O_RDONLY);
  216. if (fd >= 0) {
  217.     union {
  218. char buf[512];
  219. TIFFHeader h;
  220.     } b;
  221.     ssize_t cc = Sys::read(fd, (char*) &b, sizeof (b));
  222.     if (cc > (ssize_t)sizeof (b.h) && b.h.tiff_version == TIFF_VERSION &&
  223.       (b.h.tiff_magic == TIFF_BIGENDIAN ||
  224.        b.h.tiff_magic == TIFF_LITTLEENDIAN)) {
  225. (void) lseek(fd, 0L, SEEK_SET); // rewind
  226. TIFF* tif = TIFFFdOpen(fd, name, "r");
  227. if (tif != NULL)
  228.     return (tif);
  229. else
  230.     reply(550, "%s: Incomplete or invalid TIFF file.", name);
  231.     } else
  232. reply(550, "%s: Not a TIFF file.", name);
  233.     Sys::close(fd);
  234. } else if (errno != 0)
  235.     perror_reply(550, name, errno);
  236. else
  237.     reply(550, "%s: Cannot open file.", name);
  238.     }
  239.     return (NULL);
  240. }
  241. /*
  242.  * Tranfer the current directory's contents of "tif" to "fdout".
  243.  */
  244. bool
  245. HylaFAXServer::sendTIFFData(TIFF* tif, FILE* fdout)
  246. {
  247.     state |= S_TRANSFER;
  248.     if (setjmp(urgcatch) != 0) {
  249. state &= ~S_TRANSFER;
  250. return (false);
  251.     }
  252. #define PACK(a,b) (((a)<<8)|(b))
  253.     switch (PACK(type,mode)) {
  254.     case PACK(TYPE_I,MODE_S):
  255.     case PACK(TYPE_L,MODE_S):
  256. if (sendTIFFHeader(tif, fileno(fdout)) &&
  257.     sendITIFFData(tif, fileno(fdout))) {
  258.     state &= ~S_TRANSFER;
  259.     return (true);
  260. }
  261. break;
  262.     default:
  263. reply(550, "TYPE %s, MODE %s not implemented."
  264.     , typenames[type]
  265.     , modenames[mode]
  266. );
  267. break;
  268.     }
  269. #undef PACK
  270.     state &= ~S_TRANSFER;
  271.     return (false);
  272. }
  273. static void
  274. getLong(TIFF* tif, TIFFDirEntry& de)
  275. {
  276.     TIFFGetField(tif, de.tdir_tag, &de.tdir_offset);
  277. }
  278. static void
  279. getShort(TIFF* tif, TIFFDirEntry& de)
  280. {
  281.     uint16 v;
  282.     TIFFGetField(tif, de.tdir_tag, &v);
  283.     de.tdir_offset = (uint32) v;
  284. }
  285. /*
  286.  * Send a TIFF header and IFD for the current directory
  287.  * in the open TIFF file.  The image data is expected to
  288.  * immediately follow this information (i.e. the value of
  289.  * the StripByteOffsets tag is setup to point to the offset
  290.  * immediately after this data) and it is assumed that
  291.  * all image data is concatenated into a single strip.
  292.  */
  293. bool
  294. HylaFAXServer::sendTIFFHeader(TIFF* tif, int fdout)
  295. {
  296.     static DirTemplate templ = {
  297. #define TIFFdiroff(v) 
  298.     (uint32) (sizeof (TIFFHeader) + sizeof (uint16) + 
  299.       (intptr_t) &(((DirTemplate*) 0)->v))
  300. { TIFFTAG_SUBFILETYPE, TIFF_LONG, 1 },
  301. { TIFFTAG_IMAGEWIDTH, TIFF_LONG, 1 },
  302. { TIFFTAG_IMAGELENGTH, TIFF_LONG,  1 },
  303. { TIFFTAG_BITSPERSAMPLE, TIFF_SHORT, 1,  1 },
  304. { TIFFTAG_COMPRESSION, TIFF_SHORT, 1 },
  305. { TIFFTAG_PHOTOMETRIC, TIFF_SHORT, 1 },
  306. { TIFFTAG_FILLORDER, TIFF_SHORT, 1 },
  307. { TIFFTAG_STRIPOFFSETS, TIFF_LONG, 1, TIFFdiroff(yres[2]) },
  308. { TIFFTAG_ORIENTATION, TIFF_SHORT, 1 },
  309. { TIFFTAG_SAMPLESPERPIXEL, TIFF_SHORT, 1,  1 },
  310. { TIFFTAG_ROWSPERSTRIP, TIFF_LONG, 1, (uint32) -1 },
  311. { TIFFTAG_STRIPBYTECOUNTS, TIFF_LONG, 1 },
  312. { TIFFTAG_XRESOLUTION, TIFF_RATIONAL, 1, TIFFdiroff(xres[0]) },
  313. { TIFFTAG_YRESOLUTION, TIFF_RATIONAL, 1, TIFFdiroff(yres[0]) },
  314. { TIFFTAG_GROUP3OPTIONS, TIFF_LONG, 1 },
  315. { TIFFTAG_RESOLUTIONUNIT, TIFF_SHORT, 1 },
  316. { TIFFTAG_PAGENUMBER, TIFF_SHORT, 2 },
  317. { TIFFTAG_BADFAXLINES, TIFF_LONG, 1 },
  318. { TIFFTAG_CLEANFAXDATA, TIFF_SHORT, 1 },
  319. { TIFFTAG_CONSECUTIVEBADFAXLINES,TIFF_LONG, 1 },
  320. 0, // next directory
  321. { 0, 1 }, { 0, 1 }, // x+y resolutions
  322.     };
  323. #define NTAGS ((TIFFdiroff(link)-TIFFdiroff(SubFileType)) / sizeof (TIFFDirEntry))
  324.     /*
  325.      * Construct the TIFF header for this IFD using
  326.      * the preconstructed template above.  We extract
  327.      * the necessary information from the open TIFF file.
  328.      * In case it's not obvious, this code assumes a lot
  329.      * of things about the contents of the TIFF file.
  330.      */
  331.     struct {
  332. TIFFHeader h;
  333. uint16 dircount;
  334. u_char dirstuff[sizeof (templ)];
  335.     } buf;
  336.     union { int32 i; char c[4]; } u; u.i = 1;
  337.     buf.h.tiff_magic = (u.c[0] == 0 ? TIFF_BIGENDIAN : TIFF_LITTLEENDIAN);
  338.     buf.h.tiff_version = TIFF_VERSION;
  339.     buf.h.tiff_diroff = sizeof (TIFFHeader);
  340.     buf.dircount = (uint16) NTAGS;
  341.     getLong(tif, templ.SubFileType);
  342.     getLong(tif, templ.ImageWidth);
  343.     getLong(tif, templ.ImageLength);
  344.     getShort(tif, templ.Compression);
  345.     getShort(tif, templ.Photometric);
  346.     getShort(tif, templ.FillOrder);
  347.     getShort(tif, templ.Orientation);
  348.     templ.StripByteCounts.tdir_offset = (uint32) file_size - sizeof (buf);
  349.     float res;
  350.     TIFFGetField(tif, TIFFTAG_XRESOLUTION, &res);
  351. templ.xres[0] = (uint32) res;
  352.     TIFFGetField(tif, TIFFTAG_YRESOLUTION, &res);
  353. templ.yres[0] = (uint32) res;
  354.     if (templ.Compression.tdir_offset == COMPRESSION_CCITTFAX3) {
  355. templ.Options.tdir_tag = TIFFTAG_GROUP3OPTIONS;
  356. getLong(tif, templ.Options);
  357.     } else if (templ.Compression.tdir_offset == COMPRESSION_CCITTFAX4) {
  358. templ.Options.tdir_tag = TIFFTAG_GROUP4OPTIONS;
  359. getLong(tif, templ.Options);
  360.     }
  361.     getShort(tif, templ.ResolutionUnit);
  362.     TIFFGetField(tif, TIFFTAG_PAGENUMBER,  &templ.PageNumber.tdir_offset);
  363.     getLong(tif, templ.BadFaxLines);
  364.     getShort(tif, templ.CleanFaxData);
  365.     getLong(tif, templ.ConsecutiveBadFaxLines);
  366.     if (buf.h.tiff_magic == TIFF_BIGENDIAN) {
  367. TIFFDirEntry* dp = &templ.SubFileType;
  368. for (u_int i = 0; i < NTAGS; i++) {
  369.     if (dp->tdir_type == TIFF_SHORT)
  370. dp->tdir_offset <<= 16;
  371.     dp++;
  372. }
  373.     }
  374.     memcpy(buf.dirstuff, &templ, sizeof (templ));
  375.     if (write(fdout, (const char*) &buf, sizeof (buf)) != sizeof (buf)) {
  376. perror_reply(426, "Data connection", errno);
  377. return (false);
  378.     } else {
  379. byte_count += sizeof (buf);
  380. return (true);
  381.     }
  382. #undef NTAGS
  383. #undef offsetof
  384. }
  385. /*
  386.  * Send the raw image data for the current directory
  387.  * in the open TIFF file.  If multiple strips are
  388.  * present in the file they are concatenated w/o
  389.  * consideration for any padding that might be present
  390.  * or might be needed.
  391.  */
  392. bool
  393. HylaFAXServer::sendITIFFData(TIFF* tif, int fdout)
  394. {
  395.     uint32* sb;
  396.     (void) TIFFGetField(tif, TIFFTAG_STRIPBYTECOUNTS, &sb);
  397.     tdata_t buf = _TIFFmalloc(sb[0]);
  398.     tsize_t bsize = sb[0];
  399.     for (tstrip_t s = 0, ns = TIFFNumberOfStrips(tif); s < ns; s++) {
  400. tsize_t cc = sb[s];
  401. if (cc > bsize) {
  402.     buf = _TIFFrealloc(buf, cc);
  403.     bsize = cc;
  404. }
  405. if (buf == NULL) {
  406.     reply(551, "Error allocating intermediate buffer");
  407.     return (false);
  408. }
  409. if (TIFFReadRawStrip(tif, s, buf, cc) != cc) {
  410.     reply(551, "Error reading input file at strip %u", s);
  411.     goto bad;
  412. }
  413. if (write(fdout, buf, (u_int) cc) != cc) {
  414.     perror_reply(426, "Data connection", errno);
  415.     goto bad;
  416. }
  417. byte_count += cc;
  418.     }
  419.     _TIFFfree(buf);
  420.     return (true);
  421. bad:
  422.     _TIFFfree(buf);
  423.     return (false);
  424. }
  425. const char*
  426. HylaFAXServer::dataConnMsg(int code)
  427. {
  428.     return (code == 125 ?
  429.  "Using existing data connection" : "Opening new data connection");
  430. }
  431. void
  432. HylaFAXServer::closeDataConn(FILE* fd)
  433. {
  434.     fclose(fd);
  435.     data = -1;
  436.     pdata = -1;
  437. }
  438. /*
  439.  * STORe a file.
  440.  */
  441. void
  442. HylaFAXServer::storeCmd(const char* name, const char* mode)
  443. {
  444.     struct stat sb;
  445.     SpoolDir* sd = fileAccess(name, W_OK, sb);
  446.     if (sd) {
  447. // check filename for magic characters
  448. for (const char* cp = name; *cp; cp++)
  449.     if (isspace(*cp) || !isgraph(*cp)) {
  450. reply(553, "Bad filename; includes invalid character.");
  451. return;
  452.     }
  453. mode_t omask = umask(027);
  454. FILE* fout = fopen(name, restart_point ? "r+w" : mode);
  455. if (fout != NULL) {
  456.     setFileOwner(name);
  457.     if (restart_point &&
  458.       lseek(fileno(fout), restart_point, SEEK_SET) != restart_point)
  459. perror_reply(550, name, errno);
  460.     else {
  461. time_t start_time = Sys::now();
  462. int code;
  463. FILE* din = openDataConn("r", code);
  464. if (din != NULL) {
  465.     reply(code, "%s for %s.", dataConnMsg(code), name);
  466.     file_size = -1;
  467.     if (recvData(din, fout))
  468. reply(226, "Transfer complete.");
  469.     if (TRACE(INXFERS) && xferfaxlog != -1)
  470. logTransfer("i", *sd, name, start_time);
  471.     closeDataConn(din);
  472. }
  473.     }
  474.     fclose(fout);
  475. } else
  476.     perror_reply(553, name, errno);
  477. (void) umask(omask);
  478.     }
  479. }
  480. /*
  481.  * STOU (STOre Unique) file.
  482.  * STOT (STOre unique Temporary) file.
  483.  *
  484.  * STOT differs from STOU in that files created with STOT
  485.  * are automatically unlinked when the process terminates
  486.  * while files created with STOU are not.  STOT is intended
  487.  * for clients creating documents that are to be sent and
  488.  * then expunged.  STOU is for documents that are intended
  489.  * be shared across multiple sessions.
  490.  */
  491. void
  492. HylaFAXServer::storeUniqueCmd(bool isTemp)
  493. {
  494.     fxStr emsg;
  495.     u_int seqnum = getDocumentNumber(emsg);
  496.     if (seqnum != (u_int) -1) {
  497. fxStr filename = fxStr::format("/%s/doc%u.%s"
  498.     , isTemp ? FAX_TMPDIR : FAX_DOCDIR
  499.     , seqnum
  500.     , formats[form].suffix
  501. );
  502. FILE* fout = fopen(filename, "w");
  503. if (fout != NULL) {
  504.     setFileOwner(filename);
  505.     FileCache::chmod(filename, 0640); // sync cache
  506.     if (isTemp)
  507. tempFiles.append(filename);
  508.     time_t start_time = Sys::now();
  509.     int code;
  510.     FILE* din = openDataConn("r", code);
  511.     if (din != NULL) {
  512. reply(code, "FILE: %s (%s).", (const char*) filename,
  513.     dataConnMsg(code));
  514. file_size = -1;
  515. if (recvData(din, fout))
  516.     reply(226, "Transfer complete (FILE: %s).",
  517. (const char*) filename);
  518. if (TRACE(INXFERS) && xferfaxlog != -1)
  519.     logTransfer("i"
  520. , *dirLookup(isTemp ? "/" FAX_TMPDIR : "/" FAX_DOCDIR)
  521. , filename
  522. , start_time
  523.     );
  524. closeDataConn(din);
  525.     }
  526.     fclose(fout);
  527. } else
  528.     perror_reply(553, filename, errno);
  529.     } else
  530. reply(553, "%s", (const char*)emsg);
  531. }
  532. /*
  533.  * Tranfer the contents of "fdin" to "fdout".
  534.  */
  535. bool
  536. HylaFAXServer::sendData(FILE* fdin, FILE* fdout)
  537. {
  538.     state |= S_TRANSFER;
  539.     if (setjmp(urgcatch) != 0) {
  540. state &= ~S_TRANSFER;
  541. return (false);
  542.     }
  543. #define PACK(a,b) (((a)<<8)|(b))
  544.     switch (PACK(type,mode)) {
  545.     case PACK(TYPE_I,MODE_S):
  546.     case PACK(TYPE_L,MODE_S):
  547. if (sendIData(fileno(fdin), fileno(fdout))) {
  548.     state &= ~S_TRANSFER;
  549.     return (true);
  550. }
  551. break;
  552.     case PACK(TYPE_I,MODE_Z):
  553.     case PACK(TYPE_L,MODE_Z):
  554. if (sendZData(fileno(fdin), fileno(fdout))) {
  555.     state &= ~S_TRANSFER;
  556.     return (true);
  557. }
  558. break;
  559.     case PACK(TYPE_A,MODE_S):
  560. for (;;) {
  561.     int c = getc(fdin);
  562.     if (c == EOF) {
  563. fflush(fdout);
  564. if (ferror(fdout)) {
  565.     perror_reply(426, "Data Connection", errno);
  566.     break;
  567. }
  568. if (ferror(fdin)) {
  569.     perror_reply(551, "Error on input file", errno);
  570.     break;
  571. }
  572. state &= ~S_TRANSFER;
  573. return (true);
  574.     }
  575.     byte_count++;
  576.     if (c == 'n') { // n -> rn
  577. if (ferror(fdout)) { // check at the end of each line
  578.     perror_reply(426, "Data connection", errno);
  579.     break;
  580. }
  581. putc('r', fdout);
  582.     }
  583.     putc(c, fdout);
  584. }
  585. break;
  586.     default:
  587. reply(550, "TYPE %s, MODE %s not implemented."
  588.     , typenames[type]
  589.     , modenames[mode]
  590. );
  591. break;
  592.     }
  593. #undef PACK
  594.     state &= ~S_TRANSFER;
  595.     return (false);
  596. }
  597. bool
  598. HylaFAXServer::sendIData(int fdin, int fdout)
  599. {
  600.     char buf[16*1024];
  601.     for (;;) {
  602. int cc = read(fdin, buf, sizeof (buf));
  603. if (cc == 0)
  604.     return (true);
  605. if (cc < 0) {
  606.     perror_reply(551, "Error reading input file", errno);
  607.     break;
  608. }
  609. if (write(fdout, buf, cc) != cc) {
  610.     perror_reply(426, "Data connection", errno);
  611.     break;
  612. }
  613. byte_count += cc;
  614.     }
  615.     return (false);
  616. }
  617. bool
  618. HylaFAXServer::sendZData(int fdin, int fdout)
  619. {
  620.     z_stream zstream;
  621.     zstream.zalloc = NULL;
  622.     zstream.zfree = NULL;
  623.     zstream.opaque = NULL;
  624.     zstream.data_type = Z_BINARY;
  625.     if (deflateInit(&zstream, Z_DEFAULT_COMPRESSION) == Z_OK) {
  626. char obuf[16*1024];
  627. zstream.next_out = (Bytef*) obuf;
  628. zstream.avail_out = sizeof (obuf);
  629. int cc;
  630. for (;;) {
  631.     char buf[16*1024];
  632.     cc = read(fdin, buf, sizeof (buf));
  633.     if (cc == 0)
  634. break;
  635.     if (cc < 0) {
  636. perror_reply(551, "Error reading input file", errno);
  637. goto bad;
  638.     }
  639.     zstream.next_in = (Bytef*) buf;
  640.     zstream.avail_in = cc;
  641.     do {
  642. if (deflate(&zstream, Z_NO_FLUSH) != Z_OK) {
  643.     reply(452, "Compressor error: %s", zstream.msg);
  644.     goto bad;
  645. }
  646. if (zstream.avail_out == 0) {
  647.     if (write(fdout, obuf, sizeof (obuf)) != sizeof (obuf)) {
  648. perror_reply(426, "Data connection", errno);
  649. goto bad;
  650.     }
  651.     byte_count += sizeof (obuf);
  652.     zstream.next_out = (Bytef*) obuf;
  653.     zstream.avail_out = sizeof (obuf);
  654. }
  655.     } while (zstream.avail_in > 0);
  656. }
  657. int state;
  658. do {
  659.     switch (state = deflate(&zstream, Z_FINISH)) {
  660.     case Z_STREAM_END:
  661.     case Z_OK:
  662. if (zstream.avail_out != sizeof (obuf)) {
  663.     cc = sizeof (obuf) - zstream.avail_out;
  664.     if (write(fdout, obuf, cc) != cc) {
  665. perror_reply(426, "Data connection", errno);
  666. goto bad;
  667.     }
  668.     byte_count += cc;
  669.     zstream.next_out = (Bytef*) obuf;
  670.     zstream.avail_out = sizeof (obuf);
  671. }
  672. break;
  673.     default:
  674. reply(426, "Compressor error: %s", zstream.msg);
  675. goto bad;
  676.     }
  677. } while (state != Z_STREAM_END);
  678. deflateEnd(&zstream);
  679. return (true);
  680. bad:
  681. deflateEnd(&zstream);
  682.     } else
  683. reply(452, "Can not initialize compression library: %s", zstream.msg);
  684.     return (false);
  685. }
  686. /*
  687.  * Transfer data from peer to file.
  688.  */
  689. bool
  690. HylaFAXServer::recvData(FILE* fdin, FILE* fdout)
  691. {
  692.     state |= S_TRANSFER;
  693.     if (setjmp(urgcatch) != 0) {
  694. state &= ~S_TRANSFER;
  695. return (false);
  696.     }
  697. #define PACK(a,b) (((a)<<8)|(b))
  698.     switch (PACK(type,mode)) {
  699.     case PACK(TYPE_I,MODE_S):
  700.     case PACK(TYPE_L,MODE_S):
  701. if (recvIData(fileno(fdin), fileno(fdout))) {
  702.     state &= ~S_TRANSFER;
  703.     return (true);
  704. }
  705. break;
  706.     case PACK(TYPE_I,MODE_Z):
  707.     case PACK(TYPE_L,MODE_Z):
  708. if (recvZData(fileno(fdin), fileno(fdout))) {
  709.     state &= ~S_TRANSFER;
  710.     return (true);
  711. }
  712. break;
  713.     case PACK(TYPE_A,MODE_S):
  714. for (;;) {
  715.     int c = getc(fdin);
  716.     if (c == EOF) {
  717. fflush(fdout);
  718. if (ferror(fdin)) {
  719.     perror_reply(426, "Data Connection", errno);
  720.     break;
  721. }
  722. if (ferror(fdout)) {
  723.     perror_reply(452, "Error writing output file", errno);
  724.     break;
  725. }
  726. state &= ~S_TRANSFER;
  727. return (true);
  728.     }
  729.     byte_count++;
  730.     if (c == 'r') { // rn -> n
  731. if (ferror(fdout)) { // check at the end of each line
  732.     perror_reply(452, "Error writing output file", errno);
  733.     break;
  734. }
  735. c = getc(fdin);
  736. if (c != 'n') {
  737.     putc('r', fdout);
  738.     if (c == EOF)
  739. continue;
  740. }
  741. byte_count++;
  742.     }
  743.     putc(c, fdout);
  744. }
  745. break;
  746.     default:
  747. reply(550, "TYPE %s, MODE %s not implemented."
  748.     , typenames[type]
  749.     , modenames[mode]
  750. );
  751. break;
  752.     }
  753. #undef PACK
  754.     state &= ~S_TRANSFER;
  755.     return (false);
  756. }
  757. bool
  758. HylaFAXServer::recvIData(int fdin, int fdout)
  759. {
  760.     char buf[16*1024]; // XXX better if page-aligned
  761.     for (;;) {
  762. int cc = read(fdin, buf, sizeof (buf));
  763. if (cc == 0)
  764.     return (true);
  765. if (cc < 0) {
  766.     perror_reply(426, "Data Connection", errno);
  767.     break;
  768. }
  769. if (write(fdout, buf, cc) != cc) {
  770.     perror_reply(452, "Error writing output file", errno);
  771.     break;
  772. }
  773. byte_count += cc;
  774.     }
  775.     return (false);
  776. }
  777. bool
  778. HylaFAXServer::recvZData(int fdin, int fdout)
  779. {
  780.     z_stream zstream;
  781.     zstream.zalloc = NULL;
  782.     zstream.zfree = NULL;
  783.     zstream.opaque = NULL;
  784.     zstream.data_type = Z_BINARY;
  785.     if (inflateInit(&zstream) == Z_OK) {
  786. char obuf[16*1024];
  787. zstream.next_out = (Bytef*) obuf;
  788. zstream.avail_out = sizeof (obuf);
  789. for (;;) {
  790.     char buf[16*1024];
  791.     int cc = read(fdin, buf, sizeof (buf));
  792.     if (cc == 0) {
  793. size_t occ = sizeof (obuf) - zstream.avail_out;
  794. if (occ > 0 && write(fdout, obuf, occ) != (ssize_t)occ) {
  795.     perror_reply(452, "Error writing output file", errno);
  796.     break;
  797. }
  798. (void) inflateEnd(&zstream);
  799. return (true);
  800.     }
  801.     if (cc < 0) {
  802. perror_reply(426, "Data Connection", errno);
  803. break;
  804.     }
  805.     byte_count += cc;
  806.     zstream.next_in = (Bytef*) buf;
  807.     zstream.avail_in = cc;
  808.     do {
  809. int state = inflate(&zstream, Z_PARTIAL_FLUSH);
  810. if (state == Z_STREAM_END)
  811.     break;
  812. if (state != Z_OK) {
  813.     reply(452, "Decoding error: %s", zstream.msg);
  814.     goto bad;
  815. }
  816. size_t occ = sizeof (obuf) - zstream.avail_out;
  817. if (write(fdout, obuf, occ) != (ssize_t)occ) {
  818.     perror_reply(452, "Error writing output file", errno);
  819.     goto bad;
  820. }
  821. zstream.next_out = (Bytef*) obuf;
  822. zstream.avail_out = sizeof (obuf);
  823.     } while (zstream.avail_in > 0);
  824. }
  825. bad:
  826. (void) inflateEnd(&zstream);
  827.     } else
  828. reply(452, "Can not initialize decoder: %s", zstream.msg);
  829.     return (false);
  830. }
  831. void
  832. HylaFAXServer::formHelpCmd(void)
  833. {
  834.     lreply(211, "Supported file formats:");
  835.     for (u_int i = 0, n = N(formats); i < n; i++)
  836. lreply(211, "%8s%s  %s"
  837.     , formats[i].name
  838.     , formats[i].supported ? " " : "*"
  839.     , formats[i].help
  840. );
  841.     reply(211, "Formats marked with a * are not supported.");
  842. }
  843. void
  844. HylaFAXServer::formCmd(const char* name)
  845. {
  846.     fxStr f(name);
  847.     f.raisecase();
  848.     for (u_int i = 0, n = N(formats); i < n; i++)
  849. if (f == formats[i].name) {
  850.     if (formats[i].supported) {
  851. form = i;
  852. reply(200, "Format set to %s.", (const char*) f);
  853.     } else
  854. reply(504, "Format %s not supported.", (const char*) f);
  855.     return;
  856. }
  857.     reply(504, "Unknown format %s.", name);
  858. }
  859. #undef N
  860. void
  861. HylaFAXServer::typeCmd(const char* name)
  862. {
  863.     if (strcasecmp(name, "I") == 0)
  864. type = TYPE_I;
  865.     else if (strcasecmp(name, "A") == 0)
  866. type = TYPE_A;
  867.     else if (strcasecmp(name, "L") == 0)
  868. type = TYPE_L;
  869.     else {
  870. reply(504, "Type %s not supported.", name);
  871. return;
  872.     }
  873.     reply(200, "Type set to %s.", typenames[type]);
  874. }
  875. void
  876. HylaFAXServer::modeCmd(const char* name)
  877. {
  878.     if (strcasecmp(name, "S") == 0)
  879. mode = MODE_S;
  880.     else if (strcasecmp(name, "Z") == 0)
  881. mode = MODE_Z;
  882.     else {
  883. reply(504, "Mode %s not supported.", name);
  884. return;
  885.     }
  886.     reply(200, "Mode set to %s.", modenames[mode]);
  887. }
  888. void
  889. HylaFAXServer::struCmd(const char* name)
  890. {
  891.     if (strcasecmp(name, "F") == 0)
  892. stru = STRU_F;
  893.     else if (strcasecmp(name, "T") == 0)
  894. stru = STRU_T;
  895.     else {
  896. reply(504, "Structure %s not supported.", name);
  897. return;
  898.     }
  899.     reply(200, "Structure set to %s.", strunames[stru]);
  900. }
  901. void
  902. HylaFAXServer::printTransferStatus(FILE* fd)
  903. {
  904.     if (restart_point)
  905. fprintf(fd, "    Data transfer restart pending at %lurn", 
  906.     (u_long) restart_point);
  907.     fprintf(fd, "    TYPE: %s", typenames[type]);
  908.     if (type == TYPE_L)
  909.         fprintf(fd, " %d", CHAR_BIT);
  910.     fprintf(fd, "; STRU: %s; MODE: %s; FORM: %srn"
  911. , strunames[stru]
  912. , modenames[mode]
  913. , formats[form].name
  914.     );
  915. }