1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package net.sf.jhylafax.fax;
21
22 import gnu.hylafax.Job;
23 import gnu.inet.ftp.ServerResponseException;
24 import java.io.BufferedReader;
25 import java.io.FileInputStream;
26 import java.io.IOException;
27 import java.io.InputStreamReader;
28 import java.text.DateFormat;
29 import java.text.ParseException;
30 import java.text.SimpleDateFormat;
31 import java.util.Date;
32 import java.util.Locale;
33 import java.util.NoSuchElementException;
34 import java.util.StringTokenizer;
35 import java.util.TimeZone;
36 import net.sf.jhylafax.Settings;
37 import net.sf.jhylafax.fax.FaxJob.JobType;
38 import net.sf.jhylafax.fax.FaxJob.PageChopping;
39 import net.sf.jhylafax.fax.Modem.Volume;
40 import org.apache.commons.logging.Log;
41 import org.apache.commons.logging.LogFactory;
42
43
44
45
46
47
48 public class HylaFAXClientHelper extends Thread {
49
50
51
52
53
54
55 public final static String FILEFMT = "__FILEFMT |%d |%f |%g |%i |%l |%o |%p |%q |%r |%s |%m ";
56
57
58
59
60
61
62
63 public final static String JOBFMT = "__JOBFMT |%a |%b |%c |%e |%f |%g |%h |%i |%j |%k |%l |%m |%n |%o |%p |%q |%r |%t |%u |%v |%w |%x |%y |%z"
64 + " |%A |%B |%C |%D |%E |%F |%G |%H |%I |%J |%K |%L |%M |%N |%O |%P |%Q |%R |%S |%U |%V |%W |%X |%Y |%Z |%s ";
65
66 private final static Log logger = LogFactory.getLog(HylaFAXClientHelper.class);
67
68
69
70
71 public final static String MODEMFMT = "__MODEMFMT |%h |%l |%m |%n |%r |%s |%t |%v |%z ";
72
73
74
75
76 protected final static String QUEUE_SEPARATOR = "|";
77
78
79
80
81
82
83
84
85 public final static String RCVFMT = "__RCVFMT |%Y |%a |%b |%d |%e |%f |%h |%i |%j |%l |%n |%o |%p |%r |%s |%w |%z ";
86
87 private static DateFormat fileDateFormat = new SimpleDateFormat("MMM dd HH:mm:ss yyyy", Locale.ENGLISH);
88
89 public static void applyParameter(Job faxJob, FaxJob job) throws ServerResponseException, IOException
90 {
91
92 faxJob.setDialstring(job.getNumber());
93 if (job.getSender() != null && job.getSender().trim().length() > 0) {
94 faxJob.setFromUser(job.getSender());
95 }
96 faxJob.setKilltime("000259");
97 faxJob.setMaximumDials(job.getMaxDials());
98 faxJob.setMaximumTries(job.getMaxDials());
99 if (job.getNotifyAdress() != null && job.getNotifyAdress().trim().length() > 0) {
100 faxJob.setNotifyAddress(job.getNotifyAdress());
101 }
102 if (job.getNotify() != null) {
103 faxJob.setNotifyType(job.getNotify());
104 }
105 faxJob.setPageChop(Job.CHOP_DEFAULT);
106 faxJob.setPageWidth(job.getPageWidth());
107 faxJob.setPageLength(job.getPageLength());
108 faxJob.setPriority(job.getPriority());
109 faxJob.setProperty("SENDTIME", calculateTime(job.getSendTime(), Settings.TIMEZONE.getValue()));
110 faxJob.setVerticalResolution(job.getVerticalResolution());
111 }
112
113 public static String calculateTime(Date sendTime, String timeZoneID) {
114 if (sendTime == null) {
115 return "NOW";
116 }
117 else {
118 long date = sendTime.getTime();
119
120 TimeZone tz = TimeZone.getTimeZone(timeZoneID);
121
122
123
124 date -= tz.getRawOffset();
125 if (tz.inDaylightTime(sendTime)) {
126 date -= 3600 * 1000;
127 }
128
129 return new SimpleDateFormat("yyyyMMddHHmm").format(new Date(date));
130 }
131 }
132
133 private static JobType getJobType(char c)
134 {
135 switch (c) {
136 case 'P':
137 return JobType.PAGER;
138 default:
139 return JobType.FACSIMILE;
140 }
141 }
142
143 private final static String getNotify(char notify) {
144 switch (notify) {
145 case 'D' :
146 return Job.NOTIFY_DONE;
147 case 'Q' :
148 return Job.NOTIFY_REQUEUE;
149 case 'A' :
150 return Job.NOTIFY_ALL;
151 default :
152 return Job.NOTIFY_NONE;
153 }
154 }
155
156 private static PageChopping getPageChopping(char c)
157 {
158 switch (c) {
159 case 'D':
160 return PageChopping.DISABLED;
161 case 'A':
162 return PageChopping.ALL;
163 case 'L':
164 return PageChopping.LAST;
165 default:
166 return PageChopping.DEFAULT;
167 }
168 }
169
170 public final static FaxJob.State getState(char state) {
171 switch (state) {
172 case 'T' :
173 return FaxJob.State.SUSPENDED;
174 case 'P' :
175 return FaxJob.State.PENDING;
176 case 'S' :
177 return FaxJob.State.SLEEPING;
178 case 'B' :
179 return FaxJob.State.BLOCKED;
180 case 'W' :
181 return FaxJob.State.WAITING;
182 case 'D' :
183 return FaxJob.State.DONE;
184 case 'R' :
185 return FaxJob.State.RUNNING;
186 case 'F' :
187 return FaxJob.State.FAILED;
188 default :
189 return FaxJob.State.UNDEFINED;
190 }
191 }
192
193 private static Volume getVolume(char c)
194 {
195
196 return Volume.OFF;
197 }
198
199 public final static void initializeFromSettings(FaxJob job) {
200 job.setSender(Settings.FULLNAME.getValue());
201 job.setNotifyAdress(Settings.EMAIL.getValue());
202 job.setMaxDials(Settings.MAXDIALS.getValue());
203 job.setMaxTries(Settings.MAXTRIES.getValue());
204 job.setNotify(Settings.NOTIFICATION.getValue().getCommand());
205 job.setPageLength(Settings.PAPER.getValue().getHeight());
206 job.setPageWidth(Settings.PAPER.getValue().getWidth());
207 job.setPriority(Settings.PRIORITY.getValue());
208 job.setResolution(Settings.RESOLUTION.getValue().getLinesPerInch());
209 }
210
211 public static boolean isPostscript(String filename) throws IOException {
212 BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(filename)));
213 try {
214 return in.readLine().startsWith("%!");
215 }
216 finally {
217 try {
218 in.close();
219 } catch (IOException e) {
220 }
221 }
222 }
223
224 static int parseDuration(String s)
225 {
226 StringTokenizer t = new StringTokenizer(s, ":");
227 int duration = 0;
228 while (t.hasMoreTokens()) {
229 int n = Integer.parseInt(t.nextToken());
230 duration = duration * 60 + n;
231 }
232 return duration;
233 }
234
235 public final static Document parseFileFmt(String response) {
236 StringTokenizer st = new StringTokenizer(response, QUEUE_SEPARATOR);
237 StringTokenizer jf = new StringTokenizer(FILEFMT, QUEUE_SEPARATOR);
238 Document file = new Document();
239 while (st.hasMoreElements() && jf.hasMoreElements()) {
240 char c = jf.nextToken().charAt(1);
241 String s = st.nextToken().trim();
242 if (s.length() > 0) {
243 try {
244
245 switch (c) {
246 case 'a':
247 file.setLastAccessTime(fileDateFormat.parse(s));
248 break;
249 case 'c':
250 file.setCreationTime(fileDateFormat.parse(s));
251 break;
252 case 'd':
253 file.setDeviceNumber(Integer.parseInt(s, 8));
254 break;
255 case 'f':
256 file.setFilename(s);
257 break;
258 case 'g':
259 file.setGroupID(Integer.parseInt(s));
260 break;
261 case 'i':
262 file.setInodeNumber(Long.parseLong(s));
263 break;
264 case 'l':
265 file.setLinkCount(Integer.parseInt(s));
266 break;
267 case 'm':
268 file.setLastModificationTime(fileDateFormat.parse(s));
269 break;
270 case 'o':
271 file.setOwner(s);
272 break;
273 case 'p':
274
275 break;
276 case 'q':
277 file.setPermissions(s);
278 break;
279 case 'r':
280 file.setRootDeviceNumber(Integer.parseInt(s));
281 break;
282 case 's':
283 file.setFilesize(Long.parseLong(s));
284 break;
285 case 'u':
286 file.setOwnerID(Integer.parseInt(s));
287 break;
288 }
289 }
290 catch (NumberFormatException e) {
291 logger.info("Error parsing respone", e);
292 }
293 catch (ParseException e) {
294 logger.info("Error parsing response", e);
295 }
296 }
297 }
298 return file;
299 }
300
301 public final static Object parseFmt(String response) {
302 if (logger.isDebugEnabled()) logger.debug("Received: " + response);
303
304 if (response.trim().length() == 0) {
305
306 return null;
307 }
308 if (response.startsWith("__JOBFMT")) {
309 return parseJobFmt(response);
310 }
311 else if (response.startsWith("__RCVFMT")) {
312 return parseRcvFmt(response);
313 }
314 else if (response.startsWith("__FILEFMT")) {
315 return parseFileFmt(response);
316 }
317 else if (response.startsWith("__MODEMFMT")) {
318 return parseModemFmt(response);
319 }
320 else {
321 logger.error("Invalid response: " + response);
322 return null;
323 }
324 }
325
326 public final static FaxJob parseJobFmt(String response) {
327 StringTokenizer st = new StringTokenizer(response, QUEUE_SEPARATOR);
328 StringTokenizer jf = new StringTokenizer(JOBFMT, QUEUE_SEPARATOR);
329 FaxJob job = new FaxJob();
330 while (st.hasMoreElements() && jf.hasMoreElements()) {
331 char c = jf.nextToken().charAt(1);
332 String s = st.nextToken().trim();
333 if (s.length() > 0) {
334 try {
335 switch (c) {
336 case 'a' :
337 job.setState(getState(s.charAt(0)));
338 break;
339 case 'b':
340 job.setConsecutiveFailedTries(Integer.parseInt(s));
341 break;
342 case 'c':
343 job.setClientMachineName(s);
344 break;
345 case 'd' :
346 job.setDialsAttempted(Integer.parseInt(s));
347 break;
348 case 'e' :
349 job.setNumber(s);
350 break;
351 case 'f':
352 job.setConsecutiveFailedDials(Integer.parseInt(s));
353 break;
354 case 'g':
355 job.setGroupID(Integer.parseInt(s));
356 break;
357 case 'h':
358 job.setPageChopping(getPageChopping(s.charAt(0)));
359 break;
360 case 'i' :
361 job.setPriority((new Integer(s)).intValue());
362 break;
363 case 'j' :
364 job.setID((new Integer(s)).intValue());
365 break;
366 case 'k':
367 job.setKillTime(s);
368 break;
369 case 'l' :
370
371 break;
372 case 'm':
373 job.setAssignedModem(s);
374 break;
375 case 'n' :
376 job.setNotify(getNotify(s.charAt(0)));
377 break;
378 case 'o' :
379 job.setOwner(s);
380 break;
381 case 'p':
382 job.setPagesTransmitted(Integer.parseInt(s));
383 break;
384 case 'q':
385 job.setRetryTime(parseDuration(s));
386 break;
387 case 'r' :
388 job.setResolution((new Integer(s)).intValue());
389 break;
390 case 's' :
391 job.setLastError(s);
392 break;
393 case 't' :
394 job.setTriesAttempted((new Integer(s)).intValue());
395 break;
396 case 'u' :
397 job.setMaxTries((new Integer(s)).intValue());
398 break;
399 case 'v':
400 job.setClientDialString(s);
401 break;
402 case 'w' :
403 job.setPageWidth(Integer.parseInt(s));
404 break;
405 case 'x' :
406
407 break;
408 case 'z' :
409
410
411
412
413 break;
414 case 'A':
415 job.setDestinationSubAddress(s);
416 break;
417 case 'B':
418 job.setDestinationPassword(s);
419 break;
420 case 'C':
421 job.setDestinationCompanyName(s);
422 break;
423 case 'D' : {
424 StringTokenizer t = new StringTokenizer(s, ":");
425 job.setDialsAttempted(Integer.parseInt(t.nextToken()));
426 job.setMaxDials(Integer.parseInt(t.nextToken()));
427 break; }
428 case 'E':
429 job.setDesiredSignallingRate(s);
430 break;
431 case 'F':
432 job.setClientDialString(s);
433 break;
434 case 'G':
435 job.setDesiredMinScanline(s);
436 break;
437 case 'H':
438 job.setDesiredDataFormat(s);
439 break;
440 case 'I':
441 job.setClientSchedulingPriority(s);
442 break;
443 case 'J':
444 job.setClientJobTag(s);
445 break;
446 case 'K':
447 job.setDesiredECM(s);
448 break;
449 case 'L':
450 job.setDestinationLocation(s);
451 break;
452 case 'M':
453 job.setNotifyAdress(s);
454 break;
455 case 'N':
456 job.setUsePrivateTagLine("P".equals(s));
457 break;
458 case 'P' : {
459 StringTokenizer t = new StringTokenizer(s, ":");
460 job.setPagesTransmitted(Integer.parseInt(t.nextToken()));
461 job.setPageCount(Integer.parseInt(t.nextToken()));
462 break; }
463 case 'R':
464 job.setReceiver(s);
465 break;
466 case 'S':
467 job.setSender(s);
468 break;
469 case 'T':
470
471 break;
472 case 'U':
473 job.setChoppingThreshold(Double.parseDouble(s));
474 break;
475 case 'V':
476 job.setJobDoneOperation(s);
477 break;
478 case 'W':
479 job.setCommunicationIdentifier(s);
480 break;
481 case 'X':
482 job.setJobType(getJobType(s.charAt(0)));
483 break;
484 case 'Y': {
485 Date date = new SimpleDateFormat("yyyy/MM/dd HH.mm.ss").parse(s);
486 job.setSendTime(date);
487 break; }
488 case 'Z': {
489
490
491 Date date = new Date(Long.parseLong(s));
492
493 break; }
494 }
495 }
496 catch (ParseException e) {
497 logger.info("Error parsing response", e);
498 }
499 catch (NumberFormatException e) {
500 logger.info("Error parsing response", e);
501 }
502 catch (NoSuchElementException e) {
503 logger.info("Error parsing response", e);
504 }
505 }
506 }
507 return job;
508 }
509
510
511 public final static Modem parseModemFmt(String response) {
512 StringTokenizer st = new StringTokenizer(response, QUEUE_SEPARATOR);
513 StringTokenizer jf = new StringTokenizer(MODEMFMT, QUEUE_SEPARATOR);
514 Modem modem = new Modem();
515 while (st.hasMoreElements() && jf.hasMoreElements()) {
516 char c = jf.nextToken().charAt(1);
517 String s = st.nextToken().trim();
518 if (s.length() > 0) {
519 try {
520 switch (c) {
521 case 'h':
522 modem.setHostname(s);
523 break;
524 case 'l':
525 modem.setLocalIdentifier(s);
526 break;
527 case 'm':
528 modem.setCanonicalName(s);
529 break;
530 case 'n':
531 modem.setFaxNumber(s);
532 break;
533 case 'r':
534 modem.setMaxPagesPerCall(Integer.parseInt(s));
535 break;
536 case 's':
537 modem.setStatus(s);
538 break;
539 case 't': {
540 StringTokenizer t = new StringTokenizer(s, ":");
541 modem.setServerTracing(Integer.parseInt(t.nextToken()));
542 modem.setSessionTracing(Integer.parseInt(t.nextToken()));
543 break; }
544 case 'v':
545 modem.setSpeakerVolume(getVolume(s.charAt(0)));
546 break;
547 case 'z':
548 modem.setRunning("*".equals(s));
549 break;
550 }
551 }
552 catch (NumberFormatException e) {
553 logger.info("Error parsing respone", e);
554 }
555 catch (NoSuchElementException e) {
556 logger.info("Error parsing response", e);
557 }
558 }
559 }
560 return modem;
561 }
562
563 public final static ReceivedFax parseRcvFmt(String response) {
564 StringTokenizer st = new StringTokenizer(response, QUEUE_SEPARATOR);
565 StringTokenizer jf = new StringTokenizer(RCVFMT, QUEUE_SEPARATOR);
566 ReceivedFax fax = new ReceivedFax();
567 while (st.hasMoreElements() && jf.hasMoreElements()) {
568 char c = jf.nextToken().charAt(1);
569 String s = st.nextToken().trim();
570 if (s.length() > 0) {
571 try {
572 switch (c) {
573 case 'Y':
574 Date date = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss").parse(s);
575 fax.setReceivedTime(date);
576 break;
577 case 'a' :
578 fax.setSubAddress(s);
579 break;
580 case 'b' :
581 fax.setSignallingRate(Integer.parseInt(s));
582 break;
583 case 'd' :
584 fax.setDataFormat(s);
585 break;
586 case 'e' :
587 fax.setLastError(s);
588 break;
589 case 'f' :
590 fax.setFilename(s);
591 break;
592 case 'h' :
593 fax.setTimeSpent(parseDuration(s));
594 break;
595 case 'i' :
596 fax.setCallerIDName(s);
597 break;
598 case 'j' :
599 fax.setCallerIDNumber(s);
600 break;
601 case 'l' :
602
603 break;
604 case 'm' :
605
606 break;
607 case 'n' :
608 fax.setFilesize(Long.parseLong(s));
609 break;
610 case 'o' :
611 fax.setOwner(s);
612 break;
613 case 'p' :
614 fax.setPageCount(Integer.parseInt(s));
615 break;
616 case 'q' :
617 fax.setProtectionMode(Integer.parseInt(s));
618 break;
619 case 'r' :
620 fax.setResolution(Integer.parseInt(s));
621 break;
622 case 's' :
623 fax.setSender(s);
624 break;
625 case 't' :
626
627
628
629 break;
630 case 'w' :
631 fax.setPageWidth(Integer.parseInt(s));
632 break;
633 case 'z' :
634 fax.setReceiving(s.equals("*"));
635 break;
636 }
637 }
638 catch (ParseException e) {
639 logger.info("Error parsing response", e);
640 }
641 catch (NumberFormatException e) {
642 logger.info("Error parsing response", e);
643 }
644 }
645 }
646 return fax;
647 }
648
649 public static void setJobProperties(Job faxJob, FaxJob job) throws ServerResponseException, IOException
650 {
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669 }
670
671 }