net.sf.jhylafax.fax.HylaFAXClientHelper.java Source code

Java tutorial

Introduction

Here is the source code for net.sf.jhylafax.fax.HylaFAXClientHelper.java

Source

/**
 * JHylaFax - A java client for HylaFAX.
 *
 * Copyright (C) 2005 by Steffen Pingel <steffenp@gmx.de>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
package net.sf.jhylafax.fax;

import gnu.hylafax.Job;
import gnu.inet.ftp.ServerResponseException;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
import java.util.TimeZone;
import net.sf.jhylafax.Settings;
import net.sf.jhylafax.fax.FaxJob.JobType;
import net.sf.jhylafax.fax.FaxJob.PageChopping;
import net.sf.jhylafax.fax.Modem.Volume;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Provides static methods to handle the server communication.
 * 
 * @author Steffen Pingel
 */
public class HylaFAXClientHelper extends Thread {

    /**
     * The format used for docq, contains all valid tokens except %p.
     * 
     * <p>Note: %a, %c, %m adds a line break, therefore it needs to be last.
     */
    public final static String FILEFMT = "__FILEFMT |%d |%f |%g |%i |%l |%o |%p |%q |%r |%s |%m ";

    /**
     * The format used for sendq and doneq, contains all valid tokens except %T,
     * %Z, %z.
     * 
     * <p>Note: %s may contain line breaks, therefore it is last
     */
    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"
            + " |%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 ";

    private final static Log logger = LogFactory.getLog(HylaFAXClientHelper.class);

    /**
     * The format used for modem status, contains all valid tokens.
     */
    public final static String MODEMFMT = "__MODEMFMT |%h |%l |%m |%n |%r |%s |%t |%v |%z ";

    /**
     * The format strings need an additional space to avoid empty tokens.
     */
    protected final static String QUEUE_SEPARATOR = "|";

    /**
     * The format used for recvq, contains all valid tokens except %m, %t.
      * 
      * <p>%q has been removed as well since it causes some versions of HylaFAX 
      * to segfault (#1496477).
     */
    //public final static String RCVFMT = "__RCVFMT |%Y |%a |%b |%d |%e |%f |%h |%i |%j |%l |%n |%o |%p |%q |%r |%s |%w |%z ";
    public final static String RCVFMT = "__RCVFMT |%Y |%a |%b |%d |%e |%f |%h |%i |%j |%l |%n |%o |%p |%r |%s |%w |%z ";

    private static DateFormat fileDateFormat = new SimpleDateFormat("MMM dd HH:mm:ss yyyy", Locale.ENGLISH);

    public static void applyParameter(Job faxJob, FaxJob job) throws ServerResponseException, IOException {
        //faxJob.setChopThreshold(3);
        faxJob.setDialstring(job.getNumber());
        if (job.getSender() != null && job.getSender().trim().length() > 0) {
            faxJob.setFromUser(job.getSender());
        }
        faxJob.setKilltime("000259");
        faxJob.setMaximumDials(job.getMaxDials());
        faxJob.setMaximumTries(job.getMaxDials());
        if (job.getNotifyAdress() != null && job.getNotifyAdress().trim().length() > 0) {
            faxJob.setNotifyAddress(job.getNotifyAdress());
        }
        if (job.getNotify() != null) {
            faxJob.setNotifyType(job.getNotify());
        }
        faxJob.setPageChop(Job.CHOP_DEFAULT);
        faxJob.setPageWidth(job.getPageWidth());
        faxJob.setPageLength(job.getPageLength());
        faxJob.setPriority(job.getPriority());
        faxJob.setProperty("SENDTIME", calculateTime(job.getSendTime(), Settings.TIMEZONE.getValue()));
        faxJob.setVerticalResolution(job.getVerticalResolution());
    }

    public static String calculateTime(Date sendTime, String timeZoneID) {
        if (sendTime == null) {
            return "NOW";
        } else {
            long date = sendTime.getTime();

            TimeZone tz = TimeZone.getTimeZone(timeZoneID);
            //         tz.setStartRule(Calendar.MARCH, -1, Calendar.SUNDAY,  2*60*60*1000);
            //         tz.setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY,  2*60*60*1000);

            date -= tz.getRawOffset();
            if (tz.inDaylightTime(sendTime)) {
                date -= 3600 * 1000;
            }

            return new SimpleDateFormat("yyyyMMddHHmm").format(new Date(date));
        }
    }

    private static JobType getJobType(char c) {
        switch (c) {
        case 'P':
            return JobType.PAGER;
        default: // 'F'
            return JobType.FACSIMILE;
        }
    }

    private final static String getNotify(char notify) {
        switch (notify) {
        case 'D':
            return Job.NOTIFY_DONE;
        case 'Q':
            return Job.NOTIFY_REQUEUE;
        case 'A':
            return Job.NOTIFY_ALL;
        default:
            return Job.NOTIFY_NONE;
        }
    }

    private static PageChopping getPageChopping(char c) {
        switch (c) {
        case 'D':
            return PageChopping.DISABLED;
        case 'A':
            return PageChopping.ALL;
        case 'L':
            return PageChopping.LAST;
        default: // ' '
            return PageChopping.DEFAULT;
        }
    }

    public final static FaxJob.State getState(char state) {
        switch (state) {
        case 'T':
            return FaxJob.State.SUSPENDED;
        case 'P':
            return FaxJob.State.PENDING;
        case 'S':
            return FaxJob.State.SLEEPING;
        case 'B':
            return FaxJob.State.BLOCKED;
        case 'W':
            return FaxJob.State.WAITING;
        case 'D':
            return FaxJob.State.DONE;
        case 'R':
            return FaxJob.State.RUNNING;
        case 'F':
            return FaxJob.State.FAILED;
        default: // '?'
            return FaxJob.State.UNDEFINED;
        }
    }

    private static Volume getVolume(char c) {
        // TODO add switch
        return Volume.OFF;
    }

    public final static void initializeFromSettings(FaxJob job) {
        job.setSender(Settings.FULLNAME.getValue());
        job.setNotifyAdress(Settings.EMAIL.getValue());
        job.setMaxDials(Settings.MAXDIALS.getValue());
        job.setMaxTries(Settings.MAXTRIES.getValue());
        job.setNotify(Settings.NOTIFICATION.getValue().getCommand());
        job.setPageLength(Settings.PAPER.getValue().getHeight());
        job.setPageWidth(Settings.PAPER.getValue().getWidth());
        job.setPriority(Settings.PRIORITY.getValue());
        job.setResolution(Settings.RESOLUTION.getValue().getLinesPerInch());
    }

    public static boolean isPostscript(String filename) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(filename)));
        try {
            return in.readLine().startsWith("%!");
        } finally {
            try {
                in.close();
            } catch (IOException e) {
            }
        }
    }

    static int parseDuration(String s) {
        StringTokenizer t = new StringTokenizer(s, ":");
        int duration = 0;
        while (t.hasMoreTokens()) {
            int n = Integer.parseInt(t.nextToken());
            duration = duration * 60 + n;
        }
        return duration;
    }

    public final static Document parseFileFmt(String response) {
        StringTokenizer st = new StringTokenizer(response, QUEUE_SEPARATOR);
        StringTokenizer jf = new StringTokenizer(FILEFMT, QUEUE_SEPARATOR);
        Document file = new Document();
        while (st.hasMoreElements() && jf.hasMoreElements()) {
            char c = jf.nextToken().charAt(1);
            String s = st.nextToken().trim();
            if (s.length() > 0) {
                try {
                    // parse
                    switch (c) {
                    case 'a':
                        file.setLastAccessTime(fileDateFormat.parse(s));
                        break;
                    case 'c':
                        file.setCreationTime(fileDateFormat.parse(s));
                        break;
                    case 'd':
                        file.setDeviceNumber(Integer.parseInt(s, 8));
                        break;
                    case 'f':
                        file.setFilename(s);
                        break;
                    case 'g':
                        file.setGroupID(Integer.parseInt(s));
                        break;
                    case 'i':
                        file.setInodeNumber(Long.parseLong(s));
                        break;
                    case 'l':
                        file.setLinkCount(Integer.parseInt(s));
                        break;
                    case 'm':
                        file.setLastModificationTime(fileDateFormat.parse(s));
                        break;
                    case 'o':
                        file.setOwner(s);
                        break;
                    case 'p': // Fax-style protection flags (no group bits)
                        // 'q' is used instead
                        break;
                    case 'q':
                        file.setPermissions(s);
                        break;
                    case 'r':
                        file.setRootDeviceNumber(Integer.parseInt(s));
                        break;
                    case 's':
                        file.setFilesize(Long.parseLong(s));
                        break;
                    case 'u':
                        file.setOwnerID(Integer.parseInt(s));
                        break;
                    }
                } catch (NumberFormatException e) {
                    logger.info("Error parsing respone", e);
                } catch (ParseException e) {
                    logger.info("Error parsing response", e);
                }
            }
        }
        return file;
    }

    public final static Object parseFmt(String response) {
        if (logger.isDebugEnabled())
            logger.debug("Received: " + response);

        if (response.trim().length() == 0) {
            // work around a bug in HylaFax
            return null;
        }
        if (response.startsWith("__JOBFMT")) {
            return parseJobFmt(response);
        } else if (response.startsWith("__RCVFMT")) {
            return parseRcvFmt(response);
        } else if (response.startsWith("__FILEFMT")) {
            return parseFileFmt(response);
        } else if (response.startsWith("__MODEMFMT")) {
            return parseModemFmt(response);
        } else {
            logger.error("Invalid response: " + response);
            return null;
        }
    }

    public final static FaxJob parseJobFmt(String response) {
        StringTokenizer st = new StringTokenizer(response, QUEUE_SEPARATOR);
        StringTokenizer jf = new StringTokenizer(JOBFMT, QUEUE_SEPARATOR);
        FaxJob job = new FaxJob();
        while (st.hasMoreElements() && jf.hasMoreElements()) {
            char c = jf.nextToken().charAt(1);
            String s = st.nextToken().trim();
            if (s.length() > 0) {
                try {
                    switch (c) {
                    case 'a':
                        job.setState(getState(s.charAt(0)));
                        break;
                    case 'b':
                        job.setConsecutiveFailedTries(Integer.parseInt(s));
                        break;
                    case 'c':
                        job.setClientMachineName(s);
                        break;
                    case 'd':
                        job.setDialsAttempted(Integer.parseInt(s));
                        break;
                    case 'e':
                        job.setNumber(s);
                        break;
                    case 'f':
                        job.setConsecutiveFailedDials(Integer.parseInt(s));
                        break;
                    case 'g':
                        job.setGroupID(Integer.parseInt(s));
                        break;
                    case 'h':
                        job.setPageChopping(getPageChopping(s.charAt(0)));
                        break;
                    case 'i':
                        job.setPriority((new Integer(s)).intValue());
                        break;
                    case 'j':
                        job.setID((new Integer(s)).intValue());
                        break;
                    case 'k':
                        job.setKillTime(s);
                        break;
                    case 'l':
                        // FIXME 'any' job.setPageLength(Integer.parseInt(s));
                        break;
                    case 'm':
                        job.setAssignedModem(s);
                        break;
                    case 'n':
                        job.setNotify(getNotify(s.charAt(0)));
                        break;
                    case 'o':
                        job.setOwner(s);
                        break;
                    case 'p':
                        job.setPagesTransmitted(Integer.parseInt(s));
                        break;
                    case 'q':
                        job.setRetryTime(parseDuration(s));
                        break;
                    case 'r':
                        job.setResolution((new Integer(s)).intValue());
                        break;
                    case 's':
                        job.setLastError(s);
                        break;
                    case 't':
                        job.setTriesAttempted((new Integer(s)).intValue());
                        break;
                    case 'u':
                        job.setMaxTries((new Integer(s)).intValue());
                        break;
                    case 'v':
                        job.setClientDialString(s);
                        break;
                    case 'w':
                        job.setPageWidth(Integer.parseInt(s));
                        break;
                    case 'x':
                        // FIXME 'x/y' job.setMaxDials((new Integer(s)).intValue());
                        break;
                    case 'z':
                        // the handling code never worked correctly, use
                        // 'Y' instead
                        //Date date = parseDate(s, true);
                        //job.setSendTime(date);
                        break;
                    case 'A':
                        job.setDestinationSubAddress(s);
                        break;
                    case 'B':
                        job.setDestinationPassword(s);
                        break;
                    case 'C':
                        job.setDestinationCompanyName(s);
                        break;
                    case 'D': {
                        StringTokenizer t = new StringTokenizer(s, ":");
                        job.setDialsAttempted(Integer.parseInt(t.nextToken()));
                        job.setMaxDials(Integer.parseInt(t.nextToken()));
                        break;
                    }
                    case 'E':
                        job.setDesiredSignallingRate(s);
                        break;
                    case 'F':
                        job.setClientDialString(s);
                        break;
                    case 'G':
                        job.setDesiredMinScanline(s);
                        break;
                    case 'H':
                        job.setDesiredDataFormat(s);
                        break;
                    case 'I':
                        job.setClientSchedulingPriority(s);
                        break;
                    case 'J':
                        job.setClientJobTag(s);
                        break;
                    case 'K':
                        job.setDesiredECM(s);
                        break;
                    case 'L':
                        job.setDestinationLocation(s);
                        break;
                    case 'M':
                        job.setNotifyAdress(s);
                        break;
                    case 'N':
                        job.setUsePrivateTagLine("P".equals(s));
                        break;
                    case 'P': {
                        StringTokenizer t = new StringTokenizer(s, ":");
                        job.setPagesTransmitted(Integer.parseInt(t.nextToken()));
                        job.setPageCount(Integer.parseInt(t.nextToken()));
                        break;
                    }
                    case 'R':
                        job.setReceiver(s);
                        break;
                    case 'S':
                        job.setSender(s);
                        break;
                    case 'T': // Total # tries/maximum # tries
                        // %t, %u are used instead
                        break;
                    case 'U':
                        job.setChoppingThreshold(Double.parseDouble(s));
                        break;
                    case 'V':
                        job.setJobDoneOperation(s);
                        break;
                    case 'W':
                        job.setCommunicationIdentifier(s);
                        break;
                    case 'X':
                        job.setJobType(getJobType(s.charAt(0)));
                        break;
                    case 'Y': {
                        Date date = new SimpleDateFormat("yyyy/MM/dd HH.mm.ss").parse(s);
                        job.setSendTime(date);
                        break;
                    }
                    case 'Z': {
                        // should work, but for some reason calculates the
                        // wrong time, so 'Y' is used instead
                        Date date = new Date(Long.parseLong(s));
                        //job.setSendTime(date); 
                        break;
                    }
                    }
                } catch (ParseException e) {
                    logger.info("Error parsing response", e);
                } catch (NumberFormatException e) {
                    logger.info("Error parsing response", e);
                } catch (NoSuchElementException e) {
                    logger.info("Error parsing response", e);
                }
            }
        }
        return job;
    }

    public final static Modem parseModemFmt(String response) {
        StringTokenizer st = new StringTokenizer(response, QUEUE_SEPARATOR);
        StringTokenizer jf = new StringTokenizer(MODEMFMT, QUEUE_SEPARATOR);
        Modem modem = new Modem();
        while (st.hasMoreElements() && jf.hasMoreElements()) {
            char c = jf.nextToken().charAt(1);
            String s = st.nextToken().trim();
            if (s.length() > 0) {
                try {
                    switch (c) {
                    case 'h':
                        modem.setHostname(s);
                        break;
                    case 'l':
                        modem.setLocalIdentifier(s);
                        break;
                    case 'm':
                        modem.setCanonicalName(s);
                        break;
                    case 'n':
                        modem.setFaxNumber(s);
                        break;
                    case 'r':
                        modem.setMaxPagesPerCall(Integer.parseInt(s));
                        break;
                    case 's':
                        modem.setStatus(s);
                        break;
                    case 't': {
                        StringTokenizer t = new StringTokenizer(s, ":");
                        modem.setServerTracing(Integer.parseInt(t.nextToken()));
                        modem.setSessionTracing(Integer.parseInt(t.nextToken()));
                        break;
                    }
                    case 'v':
                        modem.setSpeakerVolume(getVolume(s.charAt(0)));
                        break;
                    case 'z':
                        modem.setRunning("*".equals(s));
                        break;
                    }
                } catch (NumberFormatException e) {
                    logger.info("Error parsing respone", e);
                } catch (NoSuchElementException e) {
                    logger.info("Error parsing response", e);
                }
            }
        }
        return modem;
    }

    public final static ReceivedFax parseRcvFmt(String response) {
        StringTokenizer st = new StringTokenizer(response, QUEUE_SEPARATOR);
        StringTokenizer jf = new StringTokenizer(RCVFMT, QUEUE_SEPARATOR);
        ReceivedFax fax = new ReceivedFax();
        while (st.hasMoreElements() && jf.hasMoreElements()) {
            char c = jf.nextToken().charAt(1);
            String s = st.nextToken().trim();
            if (s.length() > 0) {
                try {
                    switch (c) {
                    case 'Y':
                        Date date = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss").parse(s);
                        fax.setReceivedTime(date);
                        break;
                    case 'a':
                        fax.setSubAddress(s);
                        break;
                    case 'b':
                        fax.setSignallingRate(Integer.parseInt(s));
                        break;
                    case 'd':
                        fax.setDataFormat(s);
                        break;
                    case 'e':
                        fax.setLastError(s);
                        break;
                    case 'f':
                        fax.setFilename(s);
                        break;
                    case 'h':
                        fax.setTimeSpent(parseDuration(s));
                        break;
                    case 'i':
                        fax.setCallerIDName(s);
                        break;
                    case 'j':
                        fax.setCallerIDNumber(s);
                        break;
                    case 'l':
                        // FIXME '4294967295' fax.setPageLength(Integer.parseInt(s));
                        break;
                    case 'm': // Fax-style protection mode string
                        // 'q' is used instead
                        break;
                    case 'n':
                        fax.setFilesize(Long.parseLong(s));
                        break;
                    case 'o':
                        fax.setOwner(s);
                        break;
                    case 'p':
                        fax.setPageCount(Integer.parseInt(s));
                        break;
                    case 'q':
                        fax.setProtectionMode(Integer.parseInt(s));
                        break;
                    case 'r':
                        fax.setResolution(Integer.parseInt(s));
                        break;
                    case 's':
                        fax.setSender(s);
                        break;
                    case 't':
                        // the handling code never worked correctly
                        // 'Y' is used instead
                        //job.setSendTime(parseDate(s, false));
                        break;
                    case 'w':
                        fax.setPageWidth(Integer.parseInt(s));
                        break;
                    case 'z':
                        fax.setReceiving(s.equals("*"));
                        break;
                    }
                } catch (ParseException e) {
                    logger.info("Error parsing response", e);
                } catch (NumberFormatException e) {
                    logger.info("Error parsing response", e);
                }
            }
        }
        return fax;
    }

    public static void setJobProperties(Job faxJob, FaxJob job) throws ServerResponseException, IOException {
        /*
        job.setNumber(faxJob.getDialstring());
        job.setChopThreshold(faxJob.getChopThreshold());
        job.setDialstring(faxJob.getNumber());
        job.setSender(faxJob.getSender());
        job.setKilltime(faxJob.getKilltime());
        job.setMaxDials(faxJob.getMaximumDials());
        job.setMaxTries(faxJob.getMaximumTries());
        job.setNotifyAddress(faxJob.getNotifyAddress());
        job.setNotify(faxJob.getNotifyType());
        job.setPageChop(faxJob.getPageChop());
        job.setPaperWidth(faxJob.getPageWidth());
        job.setPaperHeight(faxJob.getPageLength());
        job.setPriority(faxJob.getPriority());
        job.setSendTime(faxJob.getRetrytime());
        job.setResolution(faxJob.getVerticalResolution());
        job.setDocumentNames(faxJob.getDocumentName());
        */
    }

}