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

传真(Fax)编程

开发平台:

C/C++

  1. /* $Id: faxcover.c++,v 1.4 2008/04/26 22:34:28 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 "StrArray.h"
  27. #include "FaxDB.h"
  28. #include "config.h"
  29. #include "PageSize.h"
  30. #include "Sys.h"
  31. #include <stdarg.h>
  32. #include <ctype.h>
  33. #include <pwd.h>
  34. #include <sys/file.h>
  35. class faxCoverApp {
  36. private:
  37.     fxStr appName; // for error messages
  38.     fxStr cover; // prototype cover sheet
  39.     fxStr dbName; // .faxdb filename
  40.     FaxDB* db; // fax machine database
  41.     fxStr toName; // to person's name
  42.     fxStr toFaxNumber; // to's fax number
  43.     fxStr toVoiceNumber; // to's voice number
  44.     fxStr toLocation; // to's geographical location
  45.     fxStr toCompany; // to's company/institution
  46.     fxStr fromFaxNumber; // sender's fax number
  47.     fxStr fromVoiceNumber; // sender's voice number
  48.     fxStr fromLocation; // sender's geographical location
  49.     fxStr fromCompany; // sender's company/institution
  50.     fxStr fromMailAddr; // sender's email address
  51.     fxStr regarding; // fax is regarding...
  52.     fxStr comments; // general comments
  53.     fxStr sender; // sender's identity
  54.     fxStr pageCount; // # pages, not counting cover page
  55.     fxStr dateFmt; // strftime format string
  56.     float pageWidth; // page width (mm)
  57.     float pageLength; // page length (mm)
  58.     int maxcomments; // max # of comment lines
  59.     int maxlencomments; // max length of comment lines
  60.     static const char* prologue;
  61.     fxStr tildeExpand(const fxStr& filename);
  62.     void setupPageSize(const char* name);
  63.     void emitToDefs(const char* to, FaxDBRecord* rec);
  64.     void emitFromDefs(FaxDBRecord* rec);
  65.     void emitCommentDefs();
  66.     void emitDateDefs();
  67.     void coverDef(const char* tag, const char* value);
  68.     void makeCoverSheet();
  69.     void usage();
  70.     void printError(const char* va_alist ...);
  71. public:
  72.     faxCoverApp();
  73.     ~faxCoverApp();
  74.     void initialize(int argc, char** argv);
  75.     void open();
  76. };
  77. faxCoverApp::faxCoverApp()
  78.     : cover(FAX_COVER)
  79.     , dbName("~/.faxdb")
  80.     , dateFmt("%a %b %d %Y, %H:%M %Z")
  81. {
  82.     db = 0;
  83.     maxcomments = 20;
  84.     maxlencomments = 35;
  85. }
  86. faxCoverApp::~faxCoverApp()
  87. {
  88. }
  89. void
  90. faxCoverApp::initialize(int argc, char** argv)
  91. {
  92.     extern char* optarg;
  93.     int c;
  94.     appName = argv[0];
  95.     u_int l = appName.length();
  96.     appName = appName.tokenR(l, '/');
  97.     const char* cp = getenv("FAXCOVER");
  98.     if (cp && *cp)
  99. cover = cp;
  100.     setupPageSize("default");
  101.     while ((c = Sys::getopt(argc, argv, "C:D:L:M:N:V:X:n:t:f:c:p:l:m:r:s:v:x:z:")) != -1)
  102. switch (c) {
  103. case 's': // page size
  104.     setupPageSize(optarg);
  105.     break;
  106. case 'C': // cover sheet
  107.     cover = optarg;
  108.     break;
  109. case 'D': // date format string
  110.     dateFmt = optarg;
  111.     break;
  112. case 'L': // sender's geographic location
  113.     fromLocation = optarg;
  114.     break;
  115. case 'M': // sender's email address
  116.     fromMailAddr = optarg;
  117.     break;
  118. case 'N': // sender's fax number
  119.     fromFaxNumber = optarg;
  120.     break;
  121. case 'V': // sender's voice number
  122.     fromVoiceNumber = optarg;
  123.     break;
  124. case 'X': // sender's company/institution
  125.     fromCompany = optarg;
  126.     break;
  127. case 'm': // max # comment lines
  128.     maxcomments = atoi(optarg);
  129.     break;
  130. case 'z': // max length comment lines
  131.     maxlencomments = atoi(optarg);
  132.     break;
  133. case 'n': // fax number
  134.     toFaxNumber = optarg;
  135.     break;
  136. case 'r': // regarding
  137.     regarding = optarg;
  138.     break;
  139. case 't': // to identity
  140.     toName = optarg;
  141.     break;
  142. case 'f': // from identity
  143.     sender = optarg;
  144.     break;
  145. case 'c': // comments
  146.     comments = optarg;
  147.     break;
  148. case 'p': // page count
  149.     pageCount = optarg;
  150.     break;
  151. case 'l': // to's location
  152.     toLocation = optarg;
  153.     break;
  154. case 'v': // to's voice phone number
  155.     toVoiceNumber = optarg;
  156.     break;
  157. case 'x': // to's company
  158.     toCompany = optarg;
  159.     break;
  160. case '?':
  161.     usage();
  162. }
  163.     if (sender == "" || toFaxNumber == "")
  164. usage();
  165. }
  166. extern void fxFatal(const char* fmt, ...);
  167. void
  168. faxCoverApp::setupPageSize(const char* name)
  169. {
  170.     PageSizeInfo* info = PageSizeInfo::getPageSizeByName(name);
  171.     if (!info)
  172. fxFatal("Unknown page size "%s"", name);
  173.     pageWidth = info->width();
  174.     pageLength = info->height();
  175.     delete info;
  176. }
  177. void
  178. faxCoverApp::open()
  179. {
  180.     if (!db)
  181. db = new FaxDB(tildeExpand(dbName));
  182.     makeCoverSheet();
  183. }
  184. void
  185. faxCoverApp::usage()
  186. {
  187.     fxFatal("usage: %s"
  188. " [-t to]"
  189. " [-c comments]"
  190. " [-p #pages]"
  191. " [-l to-location]"
  192. " [-m maxcomments]"
  193. " [-z maxlencomments]"
  194. " [-r regarding]"
  195. " [-v to-voice-number]"
  196. " [-x to-company]"
  197. " [-C template-file]"
  198. " [-D date-format]"
  199. " [-L from-location]"
  200. " [-M from-mail-address]"
  201. " [-N from-fax-number]"
  202. " [-V from-voice-number]"
  203. " [-X from-company]"
  204. " [-s pagesize]"
  205. " -f from"
  206. " -n fax-number"
  207. , (const char*) appName);
  208. }
  209. const char* faxCoverApp::prologue = "
  210. /wordbreak ( ) defn
  211. /linebreak (\n) defn
  212. /doLine {n
  213. % <line> <width> <height> <x> <y> doLine <width> <height> <x> <y>n
  214.     2 copy moveto 5 -1 rolln
  215.     wordbreakn
  216.     {n
  217.         search {n
  218.             dup stringwidth pop currentpoint pop add 7 index 6 index add gt {n
  219.                 6 3 roll 2 index sub 2 copy moveto 6 3 rolln
  220.             } ifn
  221.             show wordbreak shown
  222.         }{n
  223.             dup stringwidth pop currentpoint pop add 5 index 4 index add gt {n
  224.                 3 1 roll 3 index sub 2 copy moveto 3 -1 rolln
  225.             } ifn
  226.             show exitn
  227.         } ifelsen
  228.     } loopn
  229.     2 index sub 2 copy moveton
  230. } defn
  231. /BreakIntoLines {n
  232. % <width> <height> <x> <y> <text> BreakIntoLinesn
  233.     linebreakn
  234.     {n
  235.          search {n
  236.              7 3 roll doLine 6 -2 rolln
  237.          }{n
  238.              5 1 roll doLine exitn
  239.          } ifelsen
  240.     } loopn
  241.     pop pop pop popn
  242. } defn
  243. /BreakIntoCommentX {n
  244. % <maxlines> <text> BreakIntoCommentX -n
  245.     /cbuf (Comment ) defn
  246.     0 exchn
  247.     linebreak { search { 4 -1 roll 1 add 4 2 roll }{ exch 1 add exit } ifelse } loopn
  248.     dup dup 2 add 1 rolln
  249.     -1 1 { cbuf exch 7 exch 48 add put cbuf cvn exch def } forn
  250.     1 add exch 1 exch { cbuf exch 7 exch 48 add put cbuf cvn () def } forn
  251. } defn
  252. /XtoCommentsX {n
  253. % <X> XtoCommentsX <commentsX>n
  254.     3 string cvs (comments) dup length dup 4 1 rolln
  255.     2 index length add string dup 0 4 -1 rolln
  256.     putinterval dup 4 -2 roll putintervaln
  257. } defn
  258. /BreakIntoCommentsX {n
  259. % <maxlines> <text> BreakIntoCommentsX -n
  260.     exch 1 1 3 2 rolln
  261.     { XtoCommentsX cvn () def } forn
  262.     dup length string copy 0 1 index 0 4 1 rolln
  263.     {   linebreak 0 get eq {n
  264.             exch dup 0 3 index getinterval 4 -1 roll 1 add dup 5 1 rolln
  265.             XtoCommentsX cvn exch def dup length 2 index sub 1 subn
  266.             2 index 1 add exch getinterval exch pop 0n
  267.         }{ 1 add } ifelsen
  268.         dup MaxLenComments gt {n
  269.             exch MaxLenComments 1 sub -1 0 {n
  270.                 2 copy get wordbreak 0 get eq {n
  271.                     mark 4 1 rolln
  272.                     {   2 copy 1 add 1 index length 1 index 1 add subn
  273.                         getinterval 5 -1 roll search { 3 -2 roll pop pop } ifn
  274.                         length MaxLenComments gt { 4 -1 roll execn
  275.                         }{ false } ifelsen
  276.                     }n
  277.                     { true }n
  278.                     5 1 roll linebreak 1 index wordbreak 7 3 roll execn
  279.                     counttomark 1 add 4 roll cleartomark { pop exit } ifn
  280.                     2 copy 1 add 0 exch getinterval 5 -1 rolln
  281.                     1 add dup 6 1 roll XtoCommentsX cvn exch defn
  282.                     2 copy 1 add 1 index length 1 index sub getintervaln
  283.                     3 -1 roll pop 3 -2 roll 1 add sub exch exitn
  284.                 } ifn
  285.                 popn
  286.             } forn
  287.             exch dup MaxLenComments gt {n
  288.                 pop dup 0 MaxLenComments getinterval 3 -1 rolln
  289.                 1 add dup 4 1 roll XtoCommentsX cvn exch defn
  290.                 dup length MaxLenComments subn
  291.                 MaxLenComments exch getinterval 1n
  292.             } ifn
  293.         }ifn
  294.     } foralln
  295.     pop exch 1 add XtoCommentsX cvn exch defn
  296. } defn
  297. ";
  298. void
  299. faxCoverApp::makeCoverSheet()
  300. {
  301.     int fd;
  302.     if (cover.length() > 0 && cover[0] != '/') {
  303. fd = Sys::open(tildeExpand("~/" | cover), O_RDONLY);
  304. if (fd < 0)
  305.     fd = Sys::open(fxStr(FAX_LIBDATA) | "/" | cover, O_RDONLY);
  306.     } else
  307. fd = Sys::open(cover, O_RDONLY);
  308.     if (fd < 0) {
  309. printError( "Could not locate prototype cover sheet "%s"",
  310.     (const char*) cover);
  311. return;
  312.     }
  313.     printf("%%!PS-Adobe-2.0 EPSF-2.0n");
  314.     printf("%%%%Creator: faxcovern");
  315.     printf("%%%%Title: HylaFAX Cover Sheetn");
  316.     time_t t = time(0);
  317.     printf("%%%%CreationDate: %s", ctime(&t));
  318.     printf("%%%%Origin: 0 0n");
  319.     printf("%%%%BoundingBox: 0 0 %.0f %.0fn",
  320. (pageWidth/25.4)*72, (pageLength/25.4)*72);
  321.     printf("%%%%Pages: 1 +1n");
  322.     printf("%%%%EndCommentsn");
  323.     printf("%%%%BeginPrologn");
  324.     printf("%i dict beginn", maxcomments*2 + 80);
  325.     printf("%s", prologue);
  326.     emitToDefs(toName, toName != "" ? db->find(toName) : (FaxDBRecord*) NULL);
  327.     printf("/pageWidth %.2f defn", pageWidth);
  328.     printf("/pageLength %.2f defn", pageLength);
  329.     emitFromDefs(db->find(sender));
  330.     coverDef("page-count", pageCount);
  331.     emitDateDefs();
  332.     coverDef("regarding", regarding);
  333.     emitCommentDefs();
  334.     printf("/MaxComments %i defn", maxcomments);
  335.     printf("MaxComments comments BreakIntoCommentXn");
  336.     printf("/MaxLenComments %i defn", maxlencomments);
  337.     printf("MaxComments comments BreakIntoCommentsXn");
  338.     printf("%%%%EndPrologn");
  339.     printf("%%%%Page: "1" 1n");
  340.     // copy prototype cover page
  341.     char buf[16*1024];
  342.     int n, ignore;
  343.     while ((n = read(fd, buf, sizeof (buf))) > 0) 
  344. ignore = fwrite(buf, n, 1, stdout);
  345.     Sys::close(fd);
  346.     printf("nendn");
  347. }
  348. void
  349. faxCoverApp::emitToDefs(const char* to, FaxDBRecord* rec)
  350. {
  351.     if (rec) {
  352. to = rec->find(FaxDB::nameKey);
  353. if (toCompany == "")
  354.     toCompany = rec->find("Company");
  355. if (toLocation == "")
  356.     toLocation = rec->find("Location");
  357. if (toVoiceNumber == "") {
  358.     toVoiceNumber = rec->find("Voice-Number");
  359.     if (toVoiceNumber != "") {
  360. fxStr areaCode(rec->find("Area-Code"));
  361. if (areaCode != "")
  362.     toVoiceNumber.insert("1-" | areaCode | "-");
  363.     }
  364. }
  365.     }
  366.     coverDef("to", to);
  367.     coverDef("to-company", toCompany);
  368.     coverDef("to-location", toLocation);
  369.     coverDef("to-voice-number", toVoiceNumber);
  370.     coverDef("to-fax-number", toFaxNumber);
  371. }
  372. void
  373. faxCoverApp::emitFromDefs(FaxDBRecord* rec)
  374. {
  375.     if (rec) {
  376. fromCompany = rec->find("Company");
  377. fromLocation = rec->find("Location");
  378. fromFaxNumber = rec->find(FaxDB::numberKey);
  379. fromVoiceNumber = rec->find("Voice-Number");
  380. fromMailAddr = rec->find("Mail-Address");
  381. fxStr areaCode(rec->find("Area-Code"));
  382. if (areaCode != "") {
  383.     if (fromFaxNumber != "")
  384. fromFaxNumber.insert("1-" | areaCode | "-");
  385.     if (fromVoiceNumber != "")
  386. fromVoiceNumber.insert("1-" | areaCode | "-");
  387. }
  388.     }
  389.     coverDef("from", sender);
  390.     coverDef("from-fax-number", fromFaxNumber);
  391.     coverDef("from-voice-number", fromVoiceNumber);
  392.     coverDef("from-company", fromCompany);
  393.     coverDef("from-location", fromLocation);
  394.     coverDef("from-mail-address", fromMailAddr);
  395. }
  396. void
  397. faxCoverApp::emitCommentDefs()
  398. {
  399.     /*
  400.      * Fix up new line characters.
  401.      */
  402.     u_int crlf = comments.find(0, "\n", (u_int) 0);
  403.     while ( crlf < comments.length()) {
  404.         comments.remove(crlf, 2);
  405.         comments.insert('n', crlf);
  406.         crlf = comments.find(0, "\n", (u_int) 0);
  407.     }
  408.     coverDef("comments", comments);
  409. }
  410. void
  411. faxCoverApp::emitDateDefs()
  412. {
  413.     time_t t = time(0);
  414.     char date[128];
  415.     strftime(date, sizeof (date), dateFmt, localtime(&t));
  416.     coverDef("todays-date", date);
  417. }
  418. void
  419. faxCoverApp::coverDef(const char* tag, const char* value)
  420. {
  421.     printf("/%s (", tag);
  422.     for (const char* cp = value; *cp; cp++) {
  423. if (*cp == '(' || *cp == ')' || *cp == '\')
  424.     putchar('\');
  425. putchar(*cp);
  426.     }
  427.     printf(") defn");
  428. }
  429. fxStr
  430. faxCoverApp::tildeExpand(const fxStr& filename)
  431. {
  432.     fxStr path(filename);
  433.     if (filename.length() > 1 && filename[0] == '~') {
  434.         path.remove(0);
  435.         struct passwd* pwd = getpwuid(getuid());
  436.         if (!pwd) {
  437.             fxFatal("Can not figure out who you are.");
  438.         }
  439.         char* cp = pwd->pw_dir;
  440.     path.insert(cp);
  441.     }
  442.     return (path);
  443. }
  444. void
  445. faxCoverApp::printError(const char* va_alist ...)
  446. #define fmt va_alist
  447. {
  448.     va_list ap;
  449.     va_start(ap, va_alist);
  450.     fprintf(stderr, "%s: ", (const char*) appName);
  451.     vfprintf(stderr, fmt, ap);
  452.     va_end(ap);
  453.     fprintf(stderr, ".n");
  454. }
  455. #undef fmt
  456. int
  457. main(int argc, char** argv)
  458. {
  459.     faxCoverApp app;
  460.     app.initialize(argc, argv);
  461.     app.open();
  462.     return 0;
  463. }