1 /* $Id$ */
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"
27 #include "Sys.h"
28
29 #include <ctype.h>
30 #include <string.h>
31 #include <errno.h>
32
33 #if CONFIG_INETTRANSPORT
34 extern "C" {
35 #include <sys/socket.h>
36 #include <netinet/in.h>
37 #include <netdb.h> // XXX
38 }
39 #endif
40
41 #include "SendFaxClient.h"
42 #include "PageSize.h"
43 #include "FaxConfig.h"
44
45 #include "NLS.h"
46
SendFaxJob()47 SendFaxJob::SendFaxJob()
48 {
49 }
SendFaxJob(const SendFaxJob & other)50 SendFaxJob::SendFaxJob(const SendFaxJob& other)
51 : jobtag(other.jobtag)
52 , mailbox(other.mailbox)
53 , number(other.number)
54 , subaddr(other.subaddr)
55 , passwd(other.passwd)
56 , external(other.external)
57 , coverFile(other.coverFile)
58 , coverTemplate(other.coverTemplate)
59 , name(other.name)
60 , voicenumber(other.voicenumber)
61 , location(other.location)
62 , company(other.company)
63 , comments(other.comments)
64 , regarding(other.regarding)
65 , fromlocation(other.fromlocation)
66 , fromfax(other.fromfax)
67 , fromvoice(other.fromvoice)
68 , fromcompany(other.fromcompany)
69 , killTime(other.killTime)
70 , sendTime(other.sendTime)
71 , tagline(other.tagline)
72 , pageSize(other.pageSize)
73 , pageRange(other.pageRange)
74 {
75 notify = other.notify;
76 autoCover = other.autoCover;
77 coverIsTemp = other.coverIsTemp;
78 sendTagLine = other.sendTagLine;
79 useXVRes = other.useXVRes;
80 retryTime = other.retryTime;
81 hres = other.hres;
82 vres = other.vres;
83 pageWidth = other.pageWidth;
84 pageLength = other.pageLength;
85 maxRetries = other.maxRetries;
86 maxDials = other.maxDials;
87 priority = other.priority;
88 minsp = other.minsp;
89 desiredbr = other.desiredbr;
90 desiredst = other.desiredst;
91 desiredec = other.desiredec;
92 desireddf = other.desireddf;
93 pagechop = other.pagechop;
94 chopthreshold = other.chopthreshold;
95 pageRange = other.pageRange;
96 }
~SendFaxJob()97 SendFaxJob::~SendFaxJob()
98 {
99 if (coverFile != "" && coverIsTemp)
100 Sys::unlink(coverFile);
101 }
102
103 /*
104 * Configuration file support.
105 */
106 #define N(a) (sizeof (a) / sizeof (a[0]))
107
108 SendFaxJob::SFJ_stringtag SendFaxJob::strings[] = {
109 { "tagline", &SendFaxJob::tagline, NULL },
110 { "sendtime", &SendFaxJob::sendTime, NULL },
111 { "killtime", &SendFaxJob::killTime, FAX_TIMEOUT },
112 { "pagesize", &SendFaxJob::pageSize, "default" },
113 { "jobtag", &SendFaxJob::jobtag, NULL },
114 { "subaddress", &SendFaxJob::subaddr, NULL },
115 { "password", &SendFaxJob::passwd, NULL },
116 { "cover-template", &SendFaxJob::coverTemplate, NULL },
117 { "cover-comments", &SendFaxJob::comments, NULL },
118 { "cover-regarding", &SendFaxJob::regarding, NULL },
119 { "cover-company", &SendFaxJob::company, NULL },
120 { "cover-location", &SendFaxJob::location, NULL },
121 { "cover-voice", &SendFaxJob::voicenumber, NULL },
122 { "cover-from-location", &SendFaxJob::fromlocation, NULL },
123 { "cover-from-fax", &SendFaxJob::fromfax, NULL },
124 { "cover-from-voice", &SendFaxJob::fromvoice, NULL },
125 { "cover-from-company", &SendFaxJob::fromcompany, NULL },
126 { "pagerange", &SendFaxJob::pageRange, NULL },
127 };
128 SendFaxJob::SFJ_numbertag SendFaxJob::numbers[] = {
129 { "maxtries", &SendFaxJob::maxRetries, FAX_RETRIES },
130 { "maxdials", &SendFaxJob::maxDials, FAX_REDIALS },
131 };
132 SendFaxJob::SFJ_floattag SendFaxJob::floats[] = {
133 { "hres", &SendFaxJob::hres, 204. },
134 { "vres", &SendFaxJob::vres, FAX_DEFVRES },
135 { "pagewidth", &SendFaxJob::pageWidth, 0. },
136 { "pagelength", &SendFaxJob::pageLength, 0. },
137 { "chopthreshold", &SendFaxJob::chopthreshold, 3.0 },
138 };
139
140 void
setupConfig()141 SendFaxJob::setupConfig()
142 {
143 int i;
144
145 for (i = N(strings)-1; i >= 0; i--)
146 (*this).*strings[i].p = (strings[i].def ? strings[i].def : "");
147 for (i = N(numbers)-1; i >= 0; i--)
148 (*this).*numbers[i].p = numbers[i].def;
149 for (i = N(floats)-1; i >= 0; i--)
150 (*this).*floats[i].p = floats[i].def;
151
152 autoCover = true;
153 sendTagLine = false; // default is to use server config
154 useXVRes = false; // default is to use normal or fine
155 notify = FAX_DEFNOTIFY; // default notification
156 mailbox = "";
157 priority = FAX_DEFPRIORITY; // default transmit priority
158 minsp = (u_int) -1;
159 desiredbr = (u_int) -1;
160 desiredst = (u_int) -1;
161 desiredec = (u_int) -1;
162 desireddf = (u_int) -1;
163 retryTime = (u_int) -1;
164 pagechop = chop_default;
165 }
166
167 bool
setConfigItem(const char * tag,const char * value)168 SendFaxJob::setConfigItem(const char* tag, const char* value)
169 {
170 u_int ix;
171 if (FaxConfig::findTag(tag, (const FaxConfig::tags*) strings, N(strings), ix)) {
172 (*this).*strings[ix].p = value;
173 switch (ix) {
174 case 0: sendTagLine = true; break;
175 }
176 } else if (FaxConfig::findTag(tag, (const FaxConfig::tags*) numbers, N(numbers), ix)) {
177 (*this).*numbers[ix].p = atoi(value);
178 } else if (FaxConfig::findTag(tag, (const FaxConfig::tags*) floats, N(floats), ix)) {
179 (*this).*floats[ix].p = atof(value);
180 } else if (streq(tag, "autocoverpage"))
181 setAutoCoverPage(FaxConfig::getBoolean(value));
182 else if (streq(tag, "notify") || streq(tag, "notification"))
183 setNotification(value);
184 else if (streq(tag, "mailaddr"))
185 setMailbox(value);
186 else if (streq(tag, "priority"))
187 setPriority(value);
188 else if (streq(tag, "minspeed"))
189 setMinSpeed(value);
190 else if (streq(tag, "desiredspeed"))
191 setDesiredSpeed(value);
192 else if (streq(tag, "desiredmst"))
193 setDesiredMST(value);
194 else if (streq(tag, "desiredec"))
195 setDesiredEC(FaxConfig::getBoolean(value));
196 else if (streq(tag, "usexvres"))
197 setUseXVRes(FaxConfig::getBoolean(value));
198 else if (streq(tag, "desireddf"))
199 setDesiredDF(value);
200 else if (streq(tag, "retrytime"))
201 setRetryTime(value);
202 else if (streq(tag, "pagechop"))
203 setChopHandling(value);
204 else
205 return (false);
206 return (true);
207 }
208 #undef N
209
210 #define valeq(a,b) (strcasecmp(a,b)==0)
211 #define valneq(a,b,n) (strncasecmp(a,b,n)==0)
212
setDoneOp(const char * v)213 void SendFaxJob::setDoneOp(const char* v) { doneop = v; }
214
215 bool
setNotification(const char * v0)216 SendFaxJob::setNotification(const char* v0)
217 {
218 const char* v = v0;
219 if (valneq(v, "when", 4)) {
220 for (v += 4; isspace(*v); v++)
221 ;
222 }
223 if (valeq(v, "done"))
224 notify = when_done;
225 else if (valneq(v, "req", 3))
226 notify = when_requeued;
227 else if (valeq(v, "none") || valeq(v, "off"))
228 notify = no_notice;
229 else if (valeq(v, "default"))
230 notify = FAX_DEFNOTIFY;
231 else
232 return (false);
233 return (true);
234 }
setNotification(FaxNotify n)235 void SendFaxJob::setNotification(FaxNotify n) { notify = n; }
236 /*
237 * Create the mail address for a local user.
238 */
239 void
setMailbox(const char * user)240 SendFaxJob::setMailbox(const char* user)
241 {
242 fxStr acct(user);
243 if (acct != "" && acct.next(0, "@!") == acct.length()) {
244 static fxStr domainName;
245 if (domainName == "") {
246 char hostname[64];
247 (void) gethostname(hostname, sizeof (hostname));
248 #if CONFIG_INETTRANSPORT
249 struct hostent* hp = gethostbyname(hostname);
250 domainName = (hp ? hp->h_name : hostname);
251 #else
252 domainName = hostname;
253 #endif
254 }
255 mailbox = acct | "@" | domainName;
256 } else
257 mailbox = acct;
258 // strip leading & trailing white space
259 mailbox.remove(0, mailbox.skip(0, " \t"));
260 mailbox.resize(mailbox.skipR(mailbox.length(), " \t"));
261 }
setJobTag(const char * s)262 void SendFaxJob::setJobTag(const char* s) { jobtag = s; }
263
264 void
setRetryTime(const char * v)265 SendFaxJob::setRetryTime(const char* v)
266 {
267 char* cp;
268 u_int t = (u_int) strtoul(v, &cp, 10);
269 if (cp) {
270 while (isspace(*cp))
271 ;
272 if (strncasecmp(cp, "min", 3) == 0)
273 t *= 60;
274 else if (strncasecmp(cp, "hour", 4) == 0)
275 t *= 60*60;
276 else if (strncasecmp(cp, "day", 3) == 0)
277 t *= 24*60*60;
278 }
279 retryTime = t;
280 }
setRetryTime(u_int v)281 void SendFaxJob::setRetryTime(u_int v) { retryTime = v; }
setKillTime(const char * s)282 void SendFaxJob::setKillTime(const char* s) { killTime = s; }
setSendTime(const char * s)283 void SendFaxJob::setSendTime(const char* s) { sendTime = s; }
setMaxRetries(u_int n)284 void SendFaxJob::setMaxRetries(u_int n) { maxRetries = n; }
setMaxDials(u_int n)285 void SendFaxJob::setMaxDials(u_int n) { maxDials = n; }
286 void
setPriority(const char * pri)287 SendFaxJob::setPriority(const char* pri)
288 {
289 if (valeq(pri, "default") || valeq(pri, "normal"))
290 priority = FAX_DEFPRIORITY;
291 else if (valeq(pri, "bulk") || valeq(pri, "junk"))
292 priority = FAX_DEFPRIORITY + 4*16;
293 else if (valeq(pri, "low"))
294 priority = FAX_DEFPRIORITY + 4*16-1;
295 else if (valeq(pri, "high"))
296 priority = FAX_DEFPRIORITY - 4*16;
297 else
298 priority = atoi(pri);
299 }
setPriority(int p)300 void SendFaxJob::setPriority(int p) { priority = p; }
301
setTSI(const char * s)302 void SendFaxJob::setTSI(const char* s) { tsi = s; }
setDialString(const char * s)303 void SendFaxJob::setDialString(const char* s) { number = s; }
setSubAddress(const char * s)304 void SendFaxJob::setSubAddress(const char* s) { subaddr = s; }
setPassword(const char * s)305 void SendFaxJob::setPassword(const char* s) { passwd = s; }
setExternalNumber(const char * s)306 void SendFaxJob::setExternalNumber(const char* s) { external = s; }
307
setAutoCoverPage(bool b)308 void SendFaxJob::setAutoCoverPage(bool b) { autoCover = b; }
309 void
setCoverPageFile(const char * s,bool removeOnExit)310 SendFaxJob::setCoverPageFile(const char* s, bool removeOnExit)
311 {
312 if (coverFile != "" && removeOnExit)
313 Sys::unlink(coverFile);
314 coverFile = s;
315 coverIsTemp = removeOnExit;
316 }
setCoverTemplate(const char * s)317 void SendFaxJob::setCoverTemplate(const char* s) { coverTemplate = s; }
setCoverName(const char * s)318 void SendFaxJob::setCoverName(const char* s) { name = s; }
setCoverLocation(const char * s)319 void SendFaxJob::setCoverLocation(const char* s) { location = s; }
setCoverCompany(const char * s)320 void SendFaxJob::setCoverCompany(const char* s) { company = s; }
setCoverComments(const char * s)321 void SendFaxJob::setCoverComments(const char* s) { comments = s; }
setCoverRegarding(const char * s)322 void SendFaxJob::setCoverRegarding(const char* s) { regarding = s; }
setCoverVoiceNumber(const char * s)323 void SendFaxJob::setCoverVoiceNumber(const char* s) { voicenumber = s; }
setCoverFromLocation(const char * s)324 void SendFaxJob::setCoverFromLocation(const char* s) { fromlocation = s; }
setCoverFromFax(const char * s)325 void SendFaxJob::setCoverFromFax(const char* s) { fromfax = s; }
setCoverFromVoice(const char * s)326 void SendFaxJob::setCoverFromVoice(const char* s) { fromvoice = s; }
setCoverFromCompany(const char * s)327 void SendFaxJob::setCoverFromCompany(const char* s) { fromcompany = s; }
328
329 bool
setPageSize(const char * name)330 SendFaxJob::setPageSize(const char* name)
331 {
332 PageSizeInfo* info = PageSizeInfo::getPageSizeByName(name);
333 if (info) {
334 pageWidth = info->width();
335 pageLength = info->height();
336 pageSize = name;
337 delete info;
338 return (true);
339 } else
340 return (false);
341 }
setVResolution(float r)342 void SendFaxJob::setVResolution(float r) { vres = r; }
setHResolution(float r)343 void SendFaxJob::setHResolution(float r) { hres = r; }
344
345 int
getSpeed(const char * value) const346 SendFaxJob::getSpeed(const char* value) const
347 {
348 switch (atoi(value)) {
349 case 2400: return (0);
350 case 4800: return (1);
351 case 7200: return (2);
352 case 9600: return (3);
353 case 12000: return (4);
354 case 14400: return (5);
355 case 16800: return (6);
356 case 19200: return (7);
357 case 21600: return (8);
358 case 24000: return (9);
359 case 26400: return (10);
360 case 28800: return (11);
361 case 31200: return (12);
362 case 33600: return (13);
363 }
364 return (-1);
365 }
setMinSpeed(int v)366 void SendFaxJob::setMinSpeed(int v) { minsp = v; }
setMinSpeed(const char * v)367 void SendFaxJob::setMinSpeed(const char* v) { minsp = getSpeed(v); }
setDesiredSpeed(int v)368 void SendFaxJob::setDesiredSpeed(int v) { desiredbr = v; }
setDesiredSpeed(const char * v)369 void SendFaxJob::setDesiredSpeed(const char* v) { desiredbr = getSpeed(v); }
370 void
setDesiredMST(const char * v)371 SendFaxJob::setDesiredMST(const char* v)
372 {
373 if (valeq(v, "0ms"))
374 desiredst = 0;
375 else if (valeq(v, "5ms"))
376 desiredst = 1;
377 else if (valeq(v, "10ms2"))
378 desiredst = 2;
379 else if (valeq(v, "10ms"))
380 desiredst = 3;
381 else if (valeq(v, "20ms2"))
382 desiredst = 4;
383 else if (valeq(v, "20ms"))
384 desiredst = 5;
385 else if (valeq(v, "40ms2"))
386 desiredst = 6;
387 else if (valeq(v, "40ms"))
388 desiredst = 7;
389 else
390 desiredst = atoi(v);
391 }
setDesiredMST(int v)392 void SendFaxJob::setDesiredMST(int v) { desiredst = v; }
setDesiredEC(bool b)393 void SendFaxJob::setDesiredEC(bool b) { desiredec = b; }
setUseXVRes(bool b)394 void SendFaxJob::setUseXVRes(bool b) { useXVRes = b; }
395 void
setDesiredDF(const char * v)396 SendFaxJob::setDesiredDF(const char* v)
397 {
398 if (strcasecmp(v, "1d") == 0 || strcasecmp(v, "1dmh") == 0 || strcasecmp(v, "1dmr") == 0)
399 desireddf = 0;
400 else if (strcasecmp(v, "2d") == 0 || strcasecmp(v, "2dmr") == 0)
401 desireddf = 1;
402 else if (strcasecmp(v, "2dmruncomp") == 0)
403 desireddf = 1; // NB: force 2D w/o uncompressed
404 else if (strcasecmp(v, "2dmmr") == 0)
405 desireddf = 3;
406 else
407 desireddf = atoi(v);
408 }
setDesiredDF(int df)409 void SendFaxJob::setDesiredDF(int df) { desireddf = df; }
410
411 void
setTagLineFormat(const char * v)412 SendFaxJob::setTagLineFormat(const char* v)
413 {
414 tagline = v;
415 sendTagLine = true;
416 }
417
418 void
setChopHandling(const char * v)419 SendFaxJob::setChopHandling(const char* v)
420 {
421 if (strcasecmp(v, "none") == 0)
422 pagechop = chop_none;
423 else if (strcasecmp(v, "all") == 0)
424 pagechop = chop_all;
425 else if (strcasecmp(v, "last") == 0)
426 pagechop = chop_last;
427 else
428 pagechop = atoi(v);
429 }
setChopHandling(u_int v)430 void SendFaxJob::setChopHandling(u_int v) { pagechop = v; }
setChopThreshold(float v)431 void SendFaxJob::setChopThreshold(float v) { chopthreshold = v; }
setPageRange(const char * v)432 void SendFaxJob::setPageRange (const char* v) { pageRange = v; }
433
434 extern int
435 parseAtSyntax(const char* s, const struct tm& ref, struct tm& at0, fxStr& emsg);
436
437 #define CHECK(x) { if (!(x)) goto failure; }
438 #define CHECKCMD(x) CHECK(client.command(x) == COMPLETE)
439 #define CHECKPARM(a,b) CHECK(client.jobParm(a,b))
440 #define IFPARM(a,b,v) { if ((b) != (v)) CHECKPARM(a,b) }
441
442 bool
createJob(SendFaxClient & client,fxStr & emsg)443 SendFaxJob::createJob(SendFaxClient& client, fxStr& emsg)
444 {
445 if (!client.setCurrentJob("DEFAULT")) { // inherit from default
446 emsg = client.getLastResponse();
447 return (false);
448 }
449 if (!client.newJob(jobid, groupid, emsg)) // create new job on server
450 return (false);
451
452 time_t now = Sys::now();
453
454 CHECKPARM("FROMUSER", client.getSenderName())
455
456 struct tm tts;
457 if (sendTime != "") {
458 if (!parseAtSyntax(sendTime, *localtime(&now), tts, emsg)) {
459 emsg.insert(sendTime | ": ");
460 return (false);
461 }
462 now = mktime(&tts);
463 // NB: must send time relative to GMT
464 CHECK(client.jobSendTime(*gmtime(&now)))
465 } else
466 tts = *localtime(&now);
467 if (killTime != "") {
468 struct tm when;
469 if (!parseAtSyntax(killTime, tts, when, emsg)) {
470 emsg.insert(killTime | ": ");
471 return (false);
472 }
473 CHECK(client.jobLastTime(mktime(&when) - now))
474 }
475 if (retryTime != (u_int) -1)
476 CHECK(client.jobRetryTime(retryTime))
477 IFPARM("MODEM", client.getModem(), ""); // XXX should be per-job state
478 IFPARM("MAXDIALS", maxDials, (u_int) -1)
479 IFPARM("MAXTRIES", maxRetries, (u_int) -1)
480 CHECKPARM("SCHEDPRI", priority)
481 /*
482 * If the dialstring is different from the
483 * displayable number then pass both.
484 */
485 IFPARM("TSI", tsi, "")
486 IFPARM("EXTERNAL", external, number)
487 CHECKPARM("DIALSTRING", number)
488 IFPARM("SUBADDR", subaddr, "")
489 IFPARM("PASSWD", passwd, "")
490 CHECKPARM("NOTIFYADDR", mailbox)
491 IFPARM("TOUSER", name, "")
492 IFPARM("TOCOMPANY", company, "")
493 IFPARM("TOLOCATION", location, "")
494 IFPARM("TOVOICE", voicenumber, "")
495 IFPARM("FROMCOMPANY", fromcompany, "")
496 IFPARM("FROMLOCATION", fromlocation, "")
497 IFPARM("FROMVOICE", fromvoice, "")
498 IFPARM("REGARDING", regarding, "")
499 IFPARM("JOBINFO", jobtag, "")
500 CHECKPARM("VRES", (u_int) vres)
501 CHECKPARM("PAGEWIDTH", (u_int) pageWidth)
502 CHECKPARM("PAGELENGTH", (u_int) pageLength)
503 IFPARM("MINBR", minsp, (u_int) -1)
504 IFPARM("BEGBR", desiredbr, (u_int) -1)
505 IFPARM("BEGST", desiredst, (u_int) -1)
506 if (desiredec != (u_int) -1)
507 CHECKPARM("USEECM", (bool) desiredec)
508 if (desireddf != (u_int) -1) {
509 CHECKPARM("DATAFORMAT",
510 desireddf == 0 ? "g31d" :
511 desireddf == 1 ? "g32d" :
512 desireddf == 2 ? "g32dunc" :
513 desireddf == 3 ? "g4" :
514 "g31d")
515 }
516 if (sendTagLine) {
517 CHECKPARM("USETAGLINE", true)
518 CHECKPARM("TAGLINE", tagline)
519 }
520 if (useXVRes) {
521 CHECKPARM("USEXVRES", true)
522 }
523 if (doneop == "archive") {
524 CHECKPARM("DONEOP", "archive")
525 }
526 CHECKPARM("NOTIFY",
527 notify == when_done ? "done" :
528 notify == when_requeued ? "done+requeue" :
529 "none")
530 CHECKPARM("PAGECHOP",
531 pagechop == chop_default? "default" :
532 pagechop == chop_none ? "none" :
533 pagechop == chop_all ? "all" :
534 "last")
535 IFPARM("CHOPTHRESHOLD", chopthreshold, -1)
536 IFPARM("PAGERANGE", pageRange, "")
537 if (coverFile != "") {
538 int fd = Sys::open(coverFile, O_RDONLY);
539 if (fd < 0) {
540 emsg = fxStr::format(NLS::TEXT("%s: Can not open: %s"),
541 (const char*) coverFile, strerror(errno));
542 return (false); // XXX
543 }
544 fxStr coverDoc;
545 bool fileSent =
546 client.setFormat(FaxClient::FORM_PS)
547 && client.setType(FaxClient::TYPE_I) // XXX??? TYPE_A
548 && client.sendZData(fd, &FaxClient::storeTemp, coverDoc, emsg);
549 Sys::close(fd);
550 if (!fileSent) {
551 if (emsg == "")
552 emsg = NLS::TEXT("Document transfer failed: ") | client.getLastResponse();
553 return (false);
554 }
555 CHECK(client.jobCover(coverDoc))
556 }
557 /*
558 * Append documents and polling requests.
559 */
560 u_int i, n;
561 for (i = 0, n = client.getNumberOfFiles(); i < n; i++)
562 CHECK(client.jobDocument(client.getFileDocument(i)))
563 for (i = 0, n = client.getNumberOfPollRequests(); i < n; i++) {
564 fxStr sep, pwd;
565 client.getPollRequest(i, sep, pwd);
566 CHECK(client.jobPollRequest(sep, pwd))
567 }
568 return (true);
569 failure:
570 emsg = client.getLastResponse();
571 return (false);
572 }
573 #undef CHECKPARM
574 #undef IFPARM
575 #undef CHECKCMD
576 #undef CHECK
577
578 fxIMPLEMENT_ObjArray(SendFaxJobArray, SendFaxJob)
579