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) == '@';
}
}
}