www.pudn.com > d4j.zip > simpleVM.java


// simpleVM: a simple EWD app for a voice mail 
 
/* 
 * Copyright (c) 1999 Carlos G Mendioroz. 
 * 
 *  This file is part of D4J. 
 * 
 *  D4J is free software; you can redistribute it and/or 
 *  modify it under the terms of the GNU Lesser General Public 
 *  License as published by the Free Software Foundation; either 
 *  version 2 of the License, or (at your option) any later version. 
 * 
 *  D4J 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 
 *  Lesser General Public License for more details. 
 * 
 *  You should have received a copy of the GNU Lesser General Public 
 *  License along with this library; if not, write to the 
 *  Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
 *  Boston, MA  02111-1307, USA. 
 * 
 * Report problems and direct all questions to: 
 * 
 *  tron@acm.org 
 */ 
 
import local.dialogic.*; 
import java.util.*; 
import java.io.*; 
 
public class simpleVM implements Application { 
    Call call; 
    Properties props; 
    Voice vdev; 
    String home, folder; 
    long code = 99999; 
    TPT tptDigit, tptRectime, tptNone; 
 
    public void handleCall(Call call, Properties props) 
    { 
 
        this.call = call; 
        this.props = props; 
        vdev = call.channel().getVoice(); 
        EVT evt; 
 
        call.accept(4); 
 
    /* Read config from props */ 
        try { 
            home = (String)props.getProperty("HOME"); 
        } catch (Exception e) {} 
        if (home == null) 
            home = "."; 
        home += File.separator; 
        try { 
            folder = (String)props.getProperty("FOLDER"); 
        } catch (Exception e) {} 
        if (folder == null) 
            folder = "."; 
        folder = home + folder + File.separator; 
        try { 
            code = Long.parseLong((String)props.getProperty("CODE")); 
        } catch (Exception e) {} 
 
    /* Set up some TPTs */ 
 
        // Record message TPT: max 30s, or 2 secs silence, 4 seconds at start 
        tptRectime = new TPT(TPT.MAXSIL, 20, TPT.EDGE|TPT.USE|TPT.SETINIT, 40); 
        tptRectime.add(TPT.MAXTIME, 300, 0, 0); 
 
        // See if code is tried while playing prompt 
        tptDigit = new TPT(TPT.DIGMASK, 0xffff, TPT.LEVEL, 0); 
 
        // while playing messages, terminate only by EOF 
        tptNone = new TPT(); 
 
    /* Do the work */ 
 
        // See if we have Caller-ID and if so display it 
        if (call.channel() instanceof AnalogChannel) { 
            AnalogChannel ac = (AnalogChannel) call.channel(); 
            if (ac.getCallerIdEnabled()) { 
                try { 
                    System.out.print("Caller-ID "); 
                    System.out.println("is <" + call.ani() + ">"); 
 
                    int frameType = ac.callerIdFrameType(); 
                    switch (frameType) { 
                        // Enable the appropriate section of code below depending on the line technology 
                        //* Caller-ID handling 
                        case Dialogic.CLASSFRAME_MDM: 
                            System.out.println("Frame type is CLASS MDM"); 
                            System.out.print("time "); 
                            System.out.print("<" + ac.callerIdExtended(Dialogic.MCLASS_DATETIME) + ">"); 
                            System.out.print(" DN "); 
                            System.out.print("<" + ac.callerIdExtended(Dialogic.MCLASS_DN) + ">"); 
                            System.out.print(" DDN "); 
                            System.out.print("<" + ac.callerIdExtended(Dialogic.MCLASS_DDN) + ">"); 
                            System.out.print(" name "); 
                            System.out.print("<" + ac.callerIdExtended(Dialogic.MCLASS_NAME) + ">"); 
                            System.out.print(" rdir "); 
                            System.out.print("<" + ac.callerIdExtended(Dialogic.MCLASS_REDIRECT) + ">"); 
                            System.out.print(" qual "); 
                            System.out.println("<" + ac.callerIdExtended(Dialogic.MCLASS_QUALIFIER) + ">"); 
                            break; 
 
                        case Dialogic.CLASSFRAME_SDM: 
                            System.out.println("Frame type is CLASS SDM"); 
                            System.out.println("Submessages not available"); 
                            break; 
                        //*/ 
 
                        /* CLIP handling 
                        case Dialogic.CLIPFRAME_MDM: 
                            System.out.println("Frame type is CLIP MDM"); 
                            System.out.print("time "); 
                            System.out.print("<" + ac.callerIdExtended(Dialogic.CLIP_DATETIME) + ">"); 
                            System.out.print(" DN "); 
                            System.out.print("<" + ac.callerIdExtended(Dialogic.CLIP_DN) + ">"); 
                            System.out.print(" DDN "); 
                            System.out.print("<" + ac.callerIdExtended(Dialogic.CLIP_DDN) + ">"); 
                            System.out.print(" name "); 
                            System.out.print("<" + ac.callerIdExtended(Dialogic.CLIP_NAME) + ">"); 
                            System.out.print(" type "); 
                            System.out.println("<" + ac.callerIdExtended(Dialogic.CLIP_CALLTYPE) + ">"); 
                            break; 
                        //*/ 
 
                        /* ACLIP Handling 
                        case Dialogic.ACLIPFRAME_MDM: 
                            System.out.println("Frame type is ACLIP MDM"); 
                            System.out.print("time "); 
                            System.out.print("<" + ac.callerIdExtended(Dialogic.MACLIP_DATETIME) + ">"); 
                            System.out.print(" DN "); 
                            System.out.print("is <" + ac.callerIdExtended(Dialogic.MACLIP_DN) + ">"); 
                            System.out.print(" DDN "); 
                            System.out.print("<" + ac.callerIdExtended(Dialogic.MACLIP_DDN) + ">"); 
                            System.out.print(" name "); 
                            System.out.print("<" + ac.callerIdExtended(Dialogic.MACLIP_NAME) + ">"); 
                            System.out.print("rdir "); 
                            System.out.println("<" + ac.callerIdExtended(Dialogic.MACLIP_REDIRECT) + ">"); 
                            break; 
 
                        case Dialogic.ACLIPFRAME_SDM: 
                            System.out.println("Frame type is ACLIP SDM"); 
                            System.out.println("Submessages not available"); 
                            break; 
                        //*/ 
 
                        /* JCLIP Handling 
                        case Dialogic.JCLIPFRAME_MDM: 
                            System.out.println("Frame type is JCLIP MDM"); 
                            System.out.print("time "); 
                            System.out.print("<" + ac.callerIdExtended(Dialogic.JCLIP_DN) + ">"); 
                            System.out.print("DDN "); 
                            System.out.println("<" + ac.callerIdExtended(Dialogic.JCLIP_DDN) + ">"); 
                            break; 
                        //*/ 
 
                    } 
                    System.out.println("End of Caller-ID information."); 
                } catch (RuntimeException e) { 
                    System.out.println(); 
                    System.out.println(e); 
                } 
            } 
        } 
 
        // Play prompt 
        play(folder+"prompt.vox", tptDigit); 
        if ((call.channel().lastEvent().termmsk & EVT.TM_DIGIT) != 0) { 
            // dtmf, i.e. code try 
            if (authenticate()) 
                tellmessages(); 
            return; 
        } 
 
        // Record message. Name derived from time! 
        File message = null; 
        try { 
            message = newFile(folder); 
            vdev.record(new IOTT(message.getPath(), true), 
                    tptRectime, Dialogic.SR_8|Dialogic.RM_TONE); 
        } catch (IOException ioe) { 
            System.out.println("Message error: "+ioe + " (" + message.getPath() + ")"); 
            //if (message != null && message.exists()) 
            //    message.delete(); 
            return; 
        } 
        try { 
            vdev.waitIdle(); 
        } catch (ChannelException ce) { 
            // Ok to hangup after leaving message 
        }; 
        // Erase if too short, usually some that calls and hangs up on beep. 
        if (message.length() < 4000) 
            message.delete(); 
    } 
 
    /** 
     * authenticate() : check credentials. 
     */ 
    private boolean authenticate() { 
        int tries = 0; 
        while (tries++ < 3) { 
            long code = getNumber(vdev, 4, 4, false); 
            if (code == this.code) 
                return true; 
             play(home+"badcode.vox", tptNone); 
        } 
        return false; 
    } 
 
    /** 
     * tellmessages() : play back recorded messages 
     */ 
    private void tellmessages() { 
        PLFolder messages = new PLFolder(folder); 
        int total = messages.size(); 
        for (int i = 0; i < total; ) { 
            play(folder + messages.fileAt(i), tptNone); 
            play(home+"menu.vox", tptDigit); 
            String op = vdev.getdig(tptDigit); 
            vdev.waitIdle(); 
            if (op.length() == 0) 
                // No input ?? assume repeat 
                continue; 
            switch(op.charAt(0)) { 
            case '1': 
                // repeat 
                break; 
            case '2': 
                // Erase 
                File messFile = new File(folder+messages.fileAt(i)); 
                messFile.delete(); 
            case '3': 
                // Keep: 
                i++; 
                break; 
            default: 
                // Bad input, should tell him... 
                break; 
            } 
        } 
        play(home+"nomore.vox", tptNone); 
    } 
 
    /** 
     * newFile(directory) 
     * Make a new file in a directory. Take care of name clashes... 
     */ 
    private File newFile(String directory) throws IOException { 
        Date now = new Date(); 
        RandomAccessFile raf; 
        File temp, f; 
 
        temp = new File(directory, "newfile.tmp"); 
 
        StringBuffer basename = new StringBuffer("@"); 
        int d = now.getMonth() * 31 + now.getDate(); 
        if (d < 10) basename.append("0"); 
        if (d < 100) basename.append("0"); 
        basename.append(d); 
        d = now.getHours(); 
        if (d < 10) basename.append("0"); 
        basename.append(d); 
        d = now.getMinutes(); 
        if (d < 10) basename.append("0"); 
        basename.append(d); 
        basename.append("."); 
        d = now.getSeconds(); 
        if (d < 10) basename.append("0"); 
        basename.append(d); 
        basename.append(" "); 
 
        for (d = 0; d < 36; d++) { 
            // Create a unique file 
            // Lots of trouble because of lack of create() sys call. 
            if (d < 10) 
                basename.setCharAt(11, (char)('0' + d)); 
            else 
                basename.setCharAt(11, (char)('a' - 10 + d)); 
            f = new File(directory, basename.toString()); 
            if (f.exists()) continue; 
 
            do { 
                try { 
                    raf = new RandomAccessFile(temp, "rw"); 
                    raf.close(); 
                    // Rename to f, if succeeds, then its ok 
                    if (temp.renameTo(f)) 
                        return f; 
                } catch (IOException ioe) { 
                    // Somebody is using it now ? 
                    try { Thread.currentThread().sleep(100); 
                    } catch (InterruptedException ie) { 
                        throw new RuntimeException("newFile interrupted"); 
                    } 
                    continue; 
                } 
            } while (!temp.exists()); // May be some one used ours ? 
        } 
        temp.delete(); 
        throw new IOException("newFile: too many new files"); 
    } 
 
    /** 
     * getNumber(dx, min length, max length, do beep) 
     * ask for a numeric input with standard sintaxis (i.e. * clears, # ends) 
     */ 
    public static long getNumber(Voice v, int min, int max, boolean bip) { 
        // Input of digits: 
        // end if * or # at once, first digit at 4 secs max, next at 2 
        TPT fdigTpt = new TPT(TPT.DIGMASK, 0xffff, TPT.LEVEL, 0); 
        fdigTpt.add(TPT.MAXTIME, 40, 0, 0); 
 
        TPT ndigTpt = new TPT(TPT.DIGMASK, TPT.DM_P|TPT.DM_S, TPT.LEVEL, 0); 
        ndigTpt.add(TPT.MAXIDDTIME, 10, 0, 0); 
        ndigTpt.add(TPT.MAXDTMF, max-1, TPT.LEVEL|TPT.USE, 0); 
 
 
        if (bip) { 
            v.playtone(new TNGEN(1000, -10, 20), new TPT()); 
            v.cleardig(); 
        } 
 
        String dig = v.getdig(fdigTpt); 
        if (dig.length() == 0) { 
            // No input ? 
            throw new NumberFormatException("No input"); 
        } 
        if (dig.charAt(0) == '#') { 
            // ?? 
            return 0; 
        } 
        if (dig.charAt(0) == '*') { 
            // clear ? 
            v.cleardig(); 
            dig = ""; 
        } 
        for (int i = 0; i < 3; i++) { 
            dig += v.getdig(ndigTpt); 
            int len = dig.length(); 
            if (len == 0) { 
                continue; 
            } 
 
            switch(dig.charAt(len-1)) { 
            case '*': 
                v.cleardig(); 
                dig = ""; 
                continue; 
            case '#': 
                if (len == 1) 
                    return 0; 
                return Long.parseLong(dig.substring(0, len-1)); 
            default: 
                if (len < min) 
                    continue; 
                return Long.parseLong(dig.substring(0, len)); 
            } 
        } 
        throw new NumberFormatException("Bad input"); 
    } 
 
 
   private void play(String file, TPT tpt) { 
        try { 
            IOTT iott = new IOTT(file); 
            vdev.play(iott, tpt, Dialogic.SR_8); 
            vdev.waitIdle(); 
            iott.close(); 
        } catch (IOException e) { 
            System.out.println("Play error"); 
            return; 
        } 
    } 
 
    /** 
     * PLFolder: small class to deal with messages in a folder 
     */ 
 
    class PLFolder extends Object implements FilenameFilter { 
        File directory; 
        String files[] = null; 
 
        public PLFolder(String dirName) { 
            directory = new File(dirName); 
            if (!directory.isDirectory()) 
                throw new RuntimeException("Invalid directory name"); 
        } 
 
        public int size() { 
            if (files == null) init(); 
            return files.length; 
        } 
 
        public String fileAt(int n) { 
            if (files == null) init(); 
            if (n >= size()) 
                throw new IndexOutOfBoundsException("PLFolder: not so many files"); 
            return files[n]; 
        } 
 
        private void init() { 
            files = directory.list(this); 
        } 
 
        public boolean accept(File dir, String name) { 
            return name.charAt(0) == '@'; 
        } 
    } 
}