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

传真(Fax)编程

开发平台:

C/C++

  1. /* $Id: sendfax.c++,v 1.13 2009/09/29 11:46:01 faxguy Exp $ */
  2. /*
  3.  * Copyright (c) 1990-1996 Sam Leffler
  4.  * Copyright (c) 1991-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. #include "config.h" //for BR_14400 definition
  27. #include "class2.h" //for BR_14400 definition
  28. #include "SendFaxClient.h"
  29. #include "FaxDB.h"
  30. #include "Sys.h"
  31. #include "config.h"
  32. #include <ctype.h> // isspace()
  33. #if HAS_LOCALE
  34. extern "C" {
  35. #include <locale.h>
  36. }
  37. #endif
  38. class sendFaxApp : public SendFaxClient {
  39. private:
  40.     fxStr appName; // for error messages
  41.     fxStr stdinTemp; // temp file for collecting from pipe
  42.     FaxDB* db;
  43.     static fxStr dbName;
  44.     void addDestination(const char* cp);
  45.     void addDestinationsFromFile(const char* filename);
  46.     void copyToTemporary(int fin, fxStr& tmpl);
  47.     void fatal(const char* fmt ...);
  48.     void usage();
  49. public:
  50.     sendFaxApp();
  51.     ~sendFaxApp();
  52.     bool run(int argc, char** argv);
  53. };
  54. fxStr sendFaxApp::dbName("~/.faxdb");
  55. sendFaxApp::sendFaxApp()
  56. {
  57.     db = NULL;
  58. }
  59. sendFaxApp::~sendFaxApp()
  60. {
  61.     if (stdinTemp != "") Sys::unlink(stdinTemp);
  62.     delete db;
  63. }
  64. bool
  65. sendFaxApp::run(int argc, char** argv)
  66. {
  67.     extern int optind;
  68.     extern char* optarg;
  69.     int c;
  70.     char *owner = NULL;
  71.     char *pass = NULL;
  72.     bool optionsUsed = true;
  73.     appName = argv[0];
  74.     u_int l = appName.length();
  75.     appName = appName.tokenR(l, '/');
  76.     resetConfig();
  77.     readConfig(FAX_SYSCONF);
  78.     readConfig(FAX_LIBDATA "/sendfax.conf");
  79.     readConfig(FAX_USERCONF);
  80.     bool waitForJob = false;
  81.     int verbose = 0;
  82.     SendFaxJob& proto = getProtoJob();
  83.     db = new FaxDB(tildeExpand(dbName));
  84.     while ((c = Sys::getopt(argc, argv, "a:b:B:c:C:d:e:f:F:h:i:I:k:M:o:O:P:r:s:S:t:T:u:U:V:W:x:X:y:Y:z:123lmnpvwADEGNR")) != -1) {
  85.         if (c != 'h')
  86.             optionsUsed = false;
  87.         switch (c) {
  88.         case '1': // restrict to 1D-encoded data
  89.             proto.setDesiredDF(0);
  90.             break;
  91.         case '2': // restrict to 2D-encoded data
  92.             proto.setDesiredDF(1);
  93.             break;
  94.         case '3': // restrict to MMR-encoded data
  95.             proto.setDesiredDF(3);
  96.             break;
  97.         case 'a': // time at which to transmit job
  98.             proto.setSendTime(optarg);
  99.                 break;
  100.         case 'A': // archive job
  101.             proto.setDoneOp("archive");
  102.             break;
  103.         case 'b': // minimum transfer speed
  104.             proto.setMinSpeed(optarg);
  105.             break;
  106.         case 'B': // desired transmit speed
  107.             proto.setDesiredSpeed(optarg);
  108.             break;
  109.         case 'C': // cover page: template file
  110.             proto.setCoverTemplate(optarg);
  111.             break;
  112.         case 'c': // cover page: comment field
  113.             proto.setCoverComments(optarg);
  114.             break;
  115.         case 'D': // notify when done
  116.             proto.setNotification("when done");
  117.             break;
  118.         case 'd': // destination name and number
  119.             optionsUsed = true;
  120.             addDestination(optarg);
  121.             break;
  122. case 'e': // sender's Caller*ID Name
  123.     proto.setFaxName(optarg);
  124.     break;
  125.         case 'E': // disable use of ECM
  126.             proto.setDesiredEC(EC_DISABLE);
  127.             break;
  128.         case 'F': // override tag line format string
  129.             proto.setTagLineFormat(optarg);
  130.             break;
  131.         case 'f': // sender's identity
  132.             setFromIdentity(optarg);
  133.             break;
  134.         case 'G': // extended resolutions
  135.             proto.setUseXVRes(true);
  136.             break;
  137.         case 'h': // server's host
  138.             setHost(optarg);
  139.             break;
  140.         case 'I': // fixed retry time
  141.             proto.setRetryTime(optarg);
  142.             break;
  143.         case 'i': // user-specified job identifier
  144.             proto.setJobTag(optarg);
  145.             break;
  146.         case 'k': // time to kill job
  147.             proto.setKillTime(optarg);
  148.             break;
  149.         case 'l': // low resolution
  150.             proto.setVResolution(98.);
  151.             break;
  152.         case 'M': // desired min-scanline time
  153.             proto.setDesiredMST(optarg);
  154.             break;
  155.         case 'm': // fine resolution
  156.             proto.setVResolution(196.);
  157.             break;
  158.         case 'n': // no cover sheet
  159.             proto.setAutoCoverPage(false);
  160.             break;
  161.         case 'N': // no notification
  162.             proto.setNotification("none");
  163.             break;
  164. case 'o': // specify owner:pass
  165.     {
  166. char* pp = strchr(optarg, ':');
  167. if (pp && *(pp + 1) != '') {
  168.     *pp = '';
  169.     pass = pp + 1;
  170. }
  171.     }
  172.     owner = optarg;
  173.     break;
  174. case 'O':
  175.     {
  176. char* op = strchr(optarg, ':');
  177. if (op && *(op + 1) != '') {
  178.     *op = '';
  179.     if (strncmp(optarg, "skippedpages", 12) == 0) {
  180. proto.setSkippedPages(atoi(++op));
  181.     } else if (strncmp(optarg, "skippages", 9) == 0) {
  182. proto.setSkipPages(atoi(++op));
  183.     } else if (strncmp(optarg, "nocountcover", 12) == 0) {
  184. proto.setNoCountCover(atoi(++op));
  185.     } else if (strncmp(optarg, "serverdocover", 13) == 0) {
  186. proto.setServerDoCover(FaxConfig::getBoolean(++op));
  187.     } else if (strncmp(optarg, "ignoremodembusy", 15) == 0) {
  188. proto.setIgnoreModemBusy(FaxConfig::getBoolean(++op));
  189.     } else if (strncmp(optarg, "config", 6) == 0) {
  190. readConfigItem(++op);
  191.     }
  192. }
  193.     }
  194.     break;
  195.         case 'p': // submit polling request
  196.             addPollRequest();
  197.             break;
  198.         case 'P': // set scheduling priority
  199.             proto.setPriority(optarg);
  200.             break;
  201.         case 'r': // cover sheet: regarding field
  202.             proto.setCoverRegarding(optarg);
  203.             break;
  204.         case 'R': // notify when requeued or done
  205.             proto.setNotification("when requeued");
  206.             break;
  207.         case 's': // set page size
  208.             proto.setPageSize(optarg);
  209.             break;
  210.         case 'S': // set TSI
  211.             proto.setTSI(optarg);
  212.             break;
  213.         case 't': // times to retry sending
  214.             proto.setMaxRetries(atoi(optarg));
  215.             break;
  216.         case 'T': // times to dial telephone
  217.             proto.setMaxDials(atoi(optarg));
  218.             break;
  219. case 'u': // sender's Caller*ID Number (for tagline also)
  220.     proto.setFaxNumber(optarg);
  221.     break;
  222.         case 'U': // cover page: sender's voice number
  223.             proto.setCoverFromVoice(optarg);
  224.             break;
  225.         case 'v': // verbose mode
  226.             verbose++;
  227.             setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
  228.             SendFaxClient::setVerbose(true); // type rules & basic operation
  229.             FaxClient::setVerbose(verbose > 1); // protocol tracing
  230.             break;
  231.         case 'V': // cover sheet: voice number field
  232.             proto.setCoverVoiceNumber(optarg);
  233.             break;
  234.         case 'w': // wait for job to complete
  235.             waitForJob = true;
  236.             break;
  237.         case 'W': // cover page: sender's fax number
  238.             proto.setCoverFromFax(optarg);
  239.             break;
  240.         case 'x': // cover page: to's company
  241.             proto.setCoverCompany(optarg);
  242.             break;
  243.         case 'X': // cover page: sender's company
  244.             proto.setCoverFromCompany(optarg);
  245.             break;
  246.         case 'y': // cover page: to's location
  247.             proto.setCoverLocation(optarg);
  248.             break;
  249.         case 'Y': // cover page: sender's location
  250.             proto.setCoverFromLocation(optarg);
  251.             break;
  252.         case 'z': // destinations from file
  253.             optionsUsed = true;
  254.             addDestinationsFromFile(optarg);
  255.             break;
  256.         case '?':
  257.             usage();
  258.             /*NOTREACHED*/
  259.         }
  260.     }
  261.     if (getNumberOfJobs() == 0) {
  262.         fprintf(stderr, "%s: No destination specified.n",
  263.             (const char*) appName);
  264.         usage();
  265.     }
  266.     if (!optionsUsed) {
  267. fprintf(stderr, "%s: Unused options after last destination.n",
  268.     (const char*) appName);
  269. usage();
  270.     }
  271.     if (optind < argc) {
  272.         for (; optind < argc; optind++) {
  273.             addFile(argv[optind]);
  274.         }
  275.     } else if (getNumberOfPollRequests() == 0) {
  276.         copyToTemporary(fileno(stdin), stdinTemp);
  277.         addFile(stdinTemp);
  278.     }
  279.     bool status = false;
  280.     fxStr emsg;
  281.     if (callServer(emsg)) {
  282.         status = login(owner, pass, emsg)
  283.             && prepareForJobSubmissions(emsg)
  284.             && submitJobs(emsg);
  285.         if (status && waitForJob) {
  286.             if (getNumberOfJobs() > 1) {
  287.                 printWarning("can only wait for one job (right now),"
  288.                     " waiting for job %s.", (const char*) getCurrentJob());
  289.             }
  290.             jobWait(getCurrentJob());
  291.         }
  292.         hangupServer();
  293.     }
  294.     if (!status) printError("%s", (const char*) emsg);
  295.     return (status);
  296. }
  297. void
  298. sendFaxApp::usage()
  299. {
  300.     fxFatal("usage: %s [options] [files]n"
  301.         "(Read the manual page; it's too complicated)", (const char*) appName);
  302. }
  303. /*
  304.  * Add a destination; parse ``person@number#subaddress'' syntax.
  305.  * T.33 Appendix I suggests that ``#'' be used to tag a subaddress.
  306.  */
  307. void
  308. sendFaxApp::addDestination(const char* cp)
  309. {
  310.     fxStr recipient;
  311.     const char* tp = strchr(cp, '@');
  312.     if (tp) {
  313. recipient = fxStr(cp, tp-cp);
  314. cp = tp+1;
  315.     } else {
  316. recipient = "";
  317.     }
  318.     fxStr subaddress;
  319.     size_t sublen = 0;
  320.     const char* ap = strchr(cp, '#');
  321.     if (ap) {
  322. ap = ap+1;
  323. subaddress = fxStr(ap);
  324. sublen = strlen(subaddress) + 1;
  325.     } else {
  326. subaddress = "";
  327.     }
  328.     fxStr dest(cp, strlen(cp) - sublen);
  329.     if (db && dest.length() > 0) {
  330.         fxStr name;
  331.         FaxDBRecord* r = db->find(dest, &name);
  332.         if (r) {
  333.             if (recipient == "")
  334.             recipient = name;
  335.             dest = r->find(FaxDB::numberKey);
  336.         }
  337.     }
  338.     if (dest.length() == 0) {
  339.         fatal("Null destination for "%s"", cp);
  340.     }
  341.     SendFaxJob& job = addJob();
  342.     job.setDialString(dest);
  343.     job.setCoverName(recipient);
  344.     job.setSubAddress(subaddress);
  345.     if(job.getDesiredSpeed() > BR_14400 && job.getDesiredEC() == EC_DISABLE) {
  346.         printWarning("ECM disabled, limiting job to 14400 bps.");
  347.         job.setDesiredSpeed(BR_14400);
  348.     }
  349. }
  350. /*
  351.  * Add a destinations form file
  352.  */
  353. void
  354. sendFaxApp::addDestinationsFromFile(const char* filename)
  355. {
  356.     FILE* destfile;
  357.     char dest[256];
  358.     char *cp;
  359.     if ((destfile = fopen(filename, "r")) != NULL) {
  360. while (fgets(dest, sizeof(dest), destfile)) {
  361.             for (cp = strchr(dest, ''); cp>dest && isspace(cp[-1]); cp--);
  362.             *cp='';
  363.     if (dest[0] != '#' && dest[0] != '')
  364. addDestination(dest);
  365. }
  366.     } else {
  367. fatal("%s: no such file", filename);
  368.     }
  369. }
  370. /*
  371.  * Copy data from fin to a temporary file.
  372.  */
  373. void
  374. sendFaxApp::copyToTemporary(int fin, fxStr& tmpl)
  375. {
  376.     const char* templ = _PATH_TMP "/sndfaxXXXXXX";
  377.     char* buff = strcpy(new char[strlen(templ) + 1], templ);
  378.     int fd = Sys::mkstemp(buff);
  379.     tmpl = buff;
  380.     delete [] buff;
  381.     if (fd < 0) {
  382.         fatal("%s: Can not create temporary file", (const char*) tmpl);
  383.     }
  384.     int cc, total = 0;
  385.     char buf[16*1024];
  386.     while ((cc = Sys::read(fin, buf, sizeof (buf))) > 0) {
  387.         if (Sys::write(fd, buf, cc) != cc) {
  388.             Sys::unlink(tmpl);
  389.             fatal("%s: write error", (const char*) tmpl);
  390.         }
  391.         total += cc;
  392.     }
  393.     Sys::close(fd);
  394.     if (total == 0) {
  395.         Sys::unlink(tmpl);
  396.         tmpl = "";
  397.         fatal("No input data; transmission aborted");
  398.     }
  399. }
  400. #include <signal.h>
  401. static sendFaxApp* app = NULL;
  402. static void
  403. cleanup()
  404. {
  405.     sendFaxApp* a = app;
  406.     app = NULL;
  407.     delete a;
  408. }
  409. static void
  410. sigDone(int)
  411. {
  412.     cleanup();
  413.     exit(-1);
  414. }
  415. int
  416. main(int argc, char** argv)
  417. {
  418. #ifdef LC_CTYPE
  419.     setlocale(LC_CTYPE, ""); // for <ctype.h> calls
  420. #endif
  421. #ifdef LC_TIME
  422.     setlocale(LC_TIME, ""); // for strftime calls
  423. #endif
  424.     signal(SIGHUP, fxSIGHANDLER(sigDone));
  425.     signal(SIGINT, fxSIGHANDLER(sigDone));
  426.     signal(SIGTERM, fxSIGHANDLER(sigDone));
  427.     signal(SIGCHLD, fxSIGHANDLER(SIG_DFL));     // by YC
  428.     app = new sendFaxApp;
  429.     if (!app->run(argc, argv)) sigDone(0);
  430.     signal(SIGHUP, fxSIGHANDLER(SIG_IGN));
  431.     signal(SIGINT, fxSIGHANDLER(SIG_IGN));
  432.     signal(SIGTERM, fxSIGHANDLER(SIG_IGN));
  433.     cleanup();
  434.     return (0);
  435. }
  436. static void
  437. vfatal(FILE* fd, const char* fmt, va_list ap)
  438. {
  439.     vfprintf(fd, fmt, ap);
  440.     va_end(ap);
  441.     fputs(".n", fd);
  442.     sigDone(0);
  443. }
  444. void
  445. fxFatal(const char* va_alist ...)
  446. #define fmt va_alist
  447. {
  448.     va_list ap;
  449.     va_start(ap, fmt);
  450.     vfatal(stderr, fmt, ap);
  451.     /*NOTTEACHED*/
  452. }
  453. #undef fmt
  454. void
  455. sendFaxApp::fatal(const char* va_alist ...)
  456. #define fmt va_alist
  457. {
  458.     fprintf(stderr, "%s: ", (const char*) appName);
  459.     va_list ap;
  460.     va_start(ap, fmt);
  461.     vfatal(stderr, fmt, ap);
  462.     /*NOTTEACHED*/
  463. }
  464. #undef fmt