⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 filetransfer.c++

📁 fax相关的东西
💻 C++
📖 第 1 页 / 共 2 页
字号:
/*	$Id: FileTransfer.c++,v 1.14 2006/04/23 20:17:52 darren Exp $ *//* * Copyright (c) 1995-1996 Sam Leffler * Copyright (c) 1995-1996 Silicon Graphics, Inc. * HylaFAX is a trademark of Silicon Graphics * * Permission to use, copy, modify, distribute, and sell this software and  * its documentation for any purpose is hereby granted without fee, provided * that (i) the above copyright notices and this permission notice appear in * all copies of the software and related documentation, and (ii) the names of * Sam Leffler and Silicon Graphics may not be used in any advertising or * publicity relating to the software without the specific, prior written * permission of Sam Leffler and Silicon Graphics. *  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.   *  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE  * OF THIS SOFTWARE. *//* * File transfer commands. */#include "HylaFAXServer.h"#include "Sys.h"#include "config.h"#include "zlib.h"#include "tiffio.h"#include <ctype.h>#include <limits.h>#ifdef HAVE_STDINT_H#include <stdint.h>#endif#ifndef CHAR_BIT#ifdef NBBY#define	CHAR_BIT	NBBY#else#define	CHAR_BIT	8#endif#endif /* CHAR_BIT */#define	HAVE_PSLEVEL2	false#define	HAVE_PCL5	falsestatic struct {    const char*	name;		// protocol token name    bool	supported;	// true if format is supported    const char*	suffix;		// file suffix    const char* help;		// help string for HELP FORM command} formats[] = {{ "TIFF", true,		 "tif", "Tagged Image File Format, Class F only" },{ "PS",	  true,		 "ps",  "Adobe PostScript Level I" },{ "PS2",  HAVE_PSLEVEL2, "ps",  "Adobe PostScript Level II" },{ "PCL",  HAVE_PCL5,	 "pcl", "HP Printer Control Language (PCL), Version 5"},{ "PDF",  true,		 "pdf", "Adobe Portable Document Format" },};static 	const char* typenames[] =  { "ASCII", "EBCDIC", "Image", "Local" };static 	const char* strunames[] =  { "File", "Record", "Page", "TIFF" };static 	const char* modenames[] =  { "Stream", "Block", "Compressed", "ZIP" };#define	N(a)	(sizeof (a) / sizeof (a[0]))/* * Record a file transfer in the log file. */voidHylaFAXServer::logTransfer(const char* direction,    const SpoolDir& sd, const char* pathname, time_t start){    time_t now = Sys::now();    time_t xferfaxtime = now - start;    if (xferfaxtime == 0)	xferfaxtime++;    const char* filename = strrchr(pathname, '/');    fxStr msg(fxStr::format("%.24s\t%lu\t%s\t%lu\t%s/%s\t%s\t%s\n"	, ctime(&now)	, (u_long) xferfaxtime	, (const char*) remotehost	, (u_long) byte_count	, sd.pathname, filename ? filename+1 : pathname	, direction	, (const char*) the_user    ));    (void) Sys::write(xferfaxlog, msg, msg.length());}boolHylaFAXServer::restartSend(FILE* fd, off_t marker){    if (type == TYPE_A) {			// restart based on line count	int c;	while ((c = getc(fd)) != EOF)	    if (c == '\n' && --marker == 0)		return (true);	return (false);    } else					// restart based on file offset	return (lseek(fileno(fd), marker, SEEK_SET) == marker);}/* * RETRieve a file. */voidHylaFAXServer::retrieveCmd(const char* name){    struct stat sb;    SpoolDir* sd = fileAccess(name, R_OK, sb);    if (sd) {	FILE* fd = fopen(name, "r");	if (fd != NULL) {	    if (restart_point && !restartSend(fd, restart_point)) {		perror_reply(550, name, errno);	    } else {		time_t start_time = Sys::now();		int code;		FILE* dout = openDataConn("w", code);		if (dout != NULL) {		    file_size = sb.st_size;		    reply(code, "%s for %s (%lu bytes).",			dataConnMsg(code), name, (u_long) file_size);		    if (sendData(fd, dout))			reply(226, "Transfer complete.");		    if (TRACE(OUTXFERS) && xferfaxlog != -1)			logTransfer("o", *sd, name, start_time);		    closeDataConn(dout);		}	    }	    fclose(fd);	} else if (errno != 0)	    perror_reply(550, name, errno);	else	    reply(550, "%s: Cannot open file.", name);    }}/* * TIFF Directory Template used in returning * a single IFD/image from a TIFF file. */typedef struct {    TIFFDirEntry	SubFileType;    TIFFDirEntry	ImageWidth;    TIFFDirEntry	ImageLength;    TIFFDirEntry	BitsPerSample;    TIFFDirEntry	Compression;    TIFFDirEntry	Photometric;    TIFFDirEntry	FillOrder;    TIFFDirEntry	StripOffsets;    TIFFDirEntry	Orientation;    TIFFDirEntry	SamplesPerPixel;    TIFFDirEntry	RowsPerStrip;    TIFFDirEntry	StripByteCounts;    TIFFDirEntry	XResolution;    TIFFDirEntry	YResolution;    TIFFDirEntry	Options;		// T4 or T6    TIFFDirEntry	ResolutionUnit;    TIFFDirEntry	PageNumber;    TIFFDirEntry	BadFaxLines;    TIFFDirEntry	CleanFaxData;    TIFFDirEntry	ConsecutiveBadFaxLines;    uint32		link;			// offset to next directory    uint32		xres[2];		// X resolution indirect value    uint32		yres[2];		// Y resolution indirect value} DirTemplate;/* * RETrieve one Page from a file.  For now the * file must be a TIFF image; we might try to * handle PostScript at a later time (but don't * hold your breath as there's not much reason). */voidHylaFAXServer::retrievePageCmd(const char* name){    TIFF* tif = cachedTIFF;    if (tif != NULL && streq(name, TIFFFileName(tif))) {	/*	 * Reuse the cached open file.  If no directory	 * has been specified with a REST command then	 * return the next consecutive directory in the file.	 */	if (restart_point == 0)			// advance to next directory	    restart_point = TIFFCurrentDirectory(tif)+1;    } else {	if (tif)				// close cached handle	    TIFFClose(tif), cachedTIFF = NULL;	tif = openTIFF(name);    }    if (tif != NULL) {	if (restart_point && !TIFFSetDirectory(tif, (tdir_t) restart_point)) {	    reply(550, "%s: Unable to access directory %lu.",		name, (u_long) restart_point);	} else {	    time_t start_time = Sys::now();	    int code;	    FILE* dout = openDataConn("w", code);	    if (dout != NULL) {		/*		 * Calculate "file size" by totalling up the		 * amount of image data and then adding in		 * the expected data for the TIFF headers.		 */		uint32* sb;		TIFFGetField(tif, TIFFTAG_STRIPBYTECOUNTS, &sb);		file_size = sizeof (DirTemplate) +		    sizeof (TIFFHeader) + sizeof (uint16);		for (tstrip_t s = 0, ns = TIFFNumberOfStrips(tif); s < ns; s++)		    file_size += sb[s];		reply(code, "%s for %s (%lu bytes).",		    dataConnMsg(code), name, (u_long) file_size);		if (sendTIFFData(tif, dout))		    reply(226, "Transfer complete.");		if (TRACE(OUTXFERS) && xferfaxlog != -1) {		    struct stat sb;		    SpoolDir* sd = fileAccess(name, R_OK, sb);		    logTransfer("o", *sd, name, start_time);		}		closeDataConn(dout);	    }	}	cachedTIFF = tif;    }}/* * Open a file that is expected to hold a TIFF image. */TIFF*HylaFAXServer::openTIFF(const char* name){    struct stat sb;    SpoolDir* sd = fileAccess(name, R_OK, sb);    if (sd) {	int fd = Sys::open(name, O_RDONLY);	if (fd >= 0) {	    union {		char buf[512];		TIFFHeader h;	    } b;	    ssize_t cc = Sys::read(fd, (char*) &b, sizeof (b));	    if (cc > (ssize_t)sizeof (b.h) && b.h.tiff_version == TIFF_VERSION &&	      (b.h.tiff_magic == TIFF_BIGENDIAN ||	       b.h.tiff_magic == TIFF_LITTLEENDIAN)) {		(void) lseek(fd, 0L, SEEK_SET);		// rewind		TIFF* tif = TIFFFdOpen(fd, name, "r");		if (tif != NULL)		    return (tif);		else		    reply(550, "%s: Incomplete or invalid TIFF file.", name);	    } else		reply(550, "%s: Not a TIFF file.", name);	    Sys::close(fd);	} else if (errno != 0)	    perror_reply(550, name, errno);	else	    reply(550, "%s: Cannot open file.", name);    }    return (NULL);}/* * Tranfer the current directory's contents of "tif" to "fdout". */boolHylaFAXServer::sendTIFFData(TIFF* tif, FILE* fdout){    state |= S_TRANSFER;    if (setjmp(urgcatch) != 0) {	state &= ~S_TRANSFER;	return (false);    }#define	PACK(a,b)	(((a)<<8)|(b))    switch (PACK(type,mode)) {    case PACK(TYPE_I,MODE_S):    case PACK(TYPE_L,MODE_S):	if (sendTIFFHeader(tif, fileno(fdout)) &&	    sendITIFFData(tif, fileno(fdout))) {	    state &= ~S_TRANSFER;	    return (true);	}	break;    default:	reply(550, "TYPE %s, MODE %s not implemented."	    , typenames[type]	    , modenames[mode]	);	break;    }#undef PACK    state &= ~S_TRANSFER;    return (false);}static voidgetLong(TIFF* tif, TIFFDirEntry& de){    TIFFGetField(tif, de.tdir_tag, &de.tdir_offset);}static voidgetShort(TIFF* tif, TIFFDirEntry& de){    uint16 v;    TIFFGetField(tif, de.tdir_tag, &v);    de.tdir_offset = (uint32) v;}/* * Send a TIFF header and IFD for the current directory * in the open TIFF file.  The image data is expected to * immediately follow this information (i.e. the value of * the StripByteOffsets tag is setup to point to the offset * immediately after this data) and it is assumed that * all image data is concatenated into a single strip. */boolHylaFAXServer::sendTIFFHeader(TIFF* tif, int fdout){    static DirTemplate templ = {#define	TIFFdiroff(v) \    (uint32) (sizeof (TIFFHeader) + sizeof (uint16) + \      (intptr_t) &(((DirTemplate*) 0)->v))	{ TIFFTAG_SUBFILETYPE,		TIFF_LONG,	1 },	{ TIFFTAG_IMAGEWIDTH,		TIFF_LONG,	1 },	{ TIFFTAG_IMAGELENGTH,		TIFF_LONG, 	1 },	{ TIFFTAG_BITSPERSAMPLE,	TIFF_SHORT,	1,  1 },	{ TIFFTAG_COMPRESSION,		TIFF_SHORT,	1 },	{ TIFFTAG_PHOTOMETRIC,		TIFF_SHORT,	1 },	{ TIFFTAG_FILLORDER,		TIFF_SHORT,	1 },	{ TIFFTAG_STRIPOFFSETS,		TIFF_LONG,	1, TIFFdiroff(yres[2]) },	{ TIFFTAG_ORIENTATION,		TIFF_SHORT,	1 },	{ TIFFTAG_SAMPLESPERPIXEL,	TIFF_SHORT,	1,  1 },	{ TIFFTAG_ROWSPERSTRIP,		TIFF_LONG,	1, (uint32) -1 },	{ TIFFTAG_STRIPBYTECOUNTS,	TIFF_LONG,	1 },	{ TIFFTAG_XRESOLUTION,		TIFF_RATIONAL,	1, TIFFdiroff(xres[0]) },	{ TIFFTAG_YRESOLUTION,		TIFF_RATIONAL,	1, TIFFdiroff(yres[0]) },	{ TIFFTAG_GROUP3OPTIONS,	TIFF_LONG,	1 },	{ TIFFTAG_RESOLUTIONUNIT,	TIFF_SHORT,	1 },	{ TIFFTAG_PAGENUMBER,		TIFF_SHORT,	2 },	{ TIFFTAG_BADFAXLINES,		TIFF_LONG,	1 },	{ TIFFTAG_CLEANFAXDATA,		TIFF_SHORT,	1 },	{ TIFFTAG_CONSECUTIVEBADFAXLINES,TIFF_LONG,	1 },	0,					// next directory	{ 0, 1 }, { 0, 1 },			// x+y resolutions    };#define	NTAGS	((TIFFdiroff(link)-TIFFdiroff(SubFileType)) / sizeof (TIFFDirEntry))    /*     * Construct the TIFF header for this IFD using     * the preconstructed template above.  We extract     * the necessary information from the open TIFF file.     * In case it's not obvious, this code assumes a lot     * of things about the contents of the TIFF file.     */    struct {	TIFFHeader h;	uint16	dircount;	u_char	dirstuff[sizeof (templ)];    } buf;    union { int32 i; char c[4]; } u; u.i = 1;    buf.h.tiff_magic = (u.c[0] == 0 ? TIFF_BIGENDIAN : TIFF_LITTLEENDIAN);    buf.h.tiff_version = TIFF_VERSION;    buf.h.tiff_diroff = sizeof (TIFFHeader);    buf.dircount = (uint16) NTAGS;    getLong(tif, templ.SubFileType);    getLong(tif, templ.ImageWidth);    getLong(tif, templ.ImageLength);    getShort(tif, templ.Compression);    getShort(tif, templ.Photometric);    getShort(tif, templ.FillOrder);    getShort(tif, templ.Orientation);    templ.StripByteCounts.tdir_offset = (uint32) file_size - sizeof (buf);    float res;    TIFFGetField(tif, TIFFTAG_XRESOLUTION, &res);	templ.xres[0] = (uint32) res;    TIFFGetField(tif, TIFFTAG_YRESOLUTION, &res);	templ.yres[0] = (uint32) res;    if (templ.Compression.tdir_offset == COMPRESSION_CCITTFAX3) {	templ.Options.tdir_tag = TIFFTAG_GROUP3OPTIONS;	getLong(tif, templ.Options);    } else if (templ.Compression.tdir_offset == COMPRESSION_CCITTFAX4) {	templ.Options.tdir_tag = TIFFTAG_GROUP4OPTIONS;	getLong(tif, templ.Options);    }    getShort(tif, templ.ResolutionUnit);    TIFFGetField(tif, TIFFTAG_PAGENUMBER,  &templ.PageNumber.tdir_offset);    getLong(tif, templ.BadFaxLines);    getShort(tif, templ.CleanFaxData);    getLong(tif, templ.ConsecutiveBadFaxLines);    if (buf.h.tiff_magic == TIFF_BIGENDIAN) {	TIFFDirEntry* dp = &templ.SubFileType;	for (u_int i = 0; i < NTAGS; i++) {	    if (dp->tdir_type == TIFF_SHORT)		dp->tdir_offset <<= 16;	    dp++;	}    }    memcpy(buf.dirstuff, &templ, sizeof (templ));    if (write(fdout, (const char*) &buf, sizeof (buf)) != sizeof (buf)) {	perror_reply(426, "Data connection", errno);	return (false);    } else {	byte_count += sizeof (buf);	return (true);    }#undef NTAGS#undef offsetof}/* * Send the raw image data for the current directory * in the open TIFF file.  If multiple strips are * present in the file they are concatenated w/o * consideration for any padding that might be present * or might be needed. */boolHylaFAXServer::sendITIFFData(TIFF* tif, int fdout){    uint32* sb;    (void) TIFFGetField(tif, TIFFTAG_STRIPBYTECOUNTS, &sb);    tdata_t buf = _TIFFmalloc(sb[0]);    tsize_t bsize = sb[0];    for (tstrip_t s = 0, ns = TIFFNumberOfStrips(tif); s < ns; s++) {	tsize_t cc = sb[s];	if (cc > bsize) {	    buf = _TIFFrealloc(buf, cc);	    bsize = cc;	}	if (buf == NULL) {	    reply(551, "Error allocating intermediate buffer");	    return (false);	}	if (TIFFReadRawStrip(tif, s, buf, cc) != cc) {	    reply(551, "Error reading input file at strip %u", s);	    goto bad;	}	if (write(fdout, buf, (u_int) cc) != cc) {	    perror_reply(426, "Data connection", errno);	    goto bad;	}	byte_count += cc;    }    _TIFFfree(buf);    return (true);bad:    _TIFFfree(buf);    return (false);}const char*HylaFAXServer::dataConnMsg(int code){    return (code == 125 ?	 "Using existing data connection" : "Opening new data connection");}voidHylaFAXServer::closeDataConn(FILE* fd){    fclose(fd);    data = -1;    pdata = -1;}/* * STORe a file. */voidHylaFAXServer::storeCmd(const char* name, const char* mode){    struct stat sb;    SpoolDir* sd = fileAccess(name, W_OK, sb);    if (sd) {	// check filename for magic characters	for (const char* cp = name; *cp; cp++)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -