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