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