package com.jphonelite;
/*
* Settings.java
*
* Created on Mar 22, 2010, 6:03 PM
*
* @author pquiring
*
*/
import java.io.*;
import java.util.*;
import org.xml.sax.XMLReader;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.helpers.XMLReaderFactory;
import org.xml.sax.helpers.DefaultHandler;
import android.util.*;
import javaforce.*;
import javaforce.voip.*;
/** Keeps current settings and provides methods to load/save settings to an XML file. */
public class Settings implements Cloneable {
public static Settings current;
public static class Line implements Cloneable {
public int same; //0-5 (-1=disabled) (ignored for lines[0])
public String name, user, auth, pass, host;
public Line() {
same = 0;
name = new String();
user = new String();
auth = new String();
pass = new String();
host = new String();
}
}
public Line lines[];
public String dndCodeOn;
public String dndCodeOff;
public boolean usePublish = false;
public static boolean aa, ac; //not saved
public boolean use_g711u = true; //G.711u (North America)
public boolean use_g711a = false; //G.711a (Europe)
public boolean use_g729a = false; //requires super FAST cpu (samsung moment 800Mhz too slow - it uses 20ms just to encode one frame)
public boolean use_g722 = false; //G.722 (16k) HD
public boolean speakerMode = false;
public int speakerThreshold = 1000; //0-32k
public int speakerDelay = 1250; //ms (1.25sec = ouch)
public boolean reinvite = true;
//for some reason implementing Cloneable didn't work
public Settings clone() {
Settings c = new Settings();
c.lines = new Line[6];
for(int a=0;a<6;a++) {
c.lines[a] = new Line();
c.lines[a].same = lines[a].same;
c.lines[a].name = "" + lines[a].name;
c.lines[a].user = "" + lines[a].user;
c.lines[a].auth = "" + lines[a].auth;
c.lines[a].pass = "" + lines[a].pass;
c.lines[a].host = "" + lines[a].host;
}
c.dndCodeOn = "" + dndCodeOn;
c.dndCodeOff = "" + dndCodeOff;
c.usePublish = usePublish;
c.use_g711u = use_g711u;
c.use_g711a = use_g711a;
c.use_g729a = use_g729a;
c.use_g722 = use_g722;
c.speakerMode = speakerMode;
c.speakerThreshold = speakerThreshold;
c.speakerDelay = speakerDelay;
return c;
}
public Settings() {
super();
lines = new Line[6];
for(int a=0;a<6;a++) lines[a] = new Line();
lines[0].same = -1;
dndCodeOn = "*78"; //asterisk feature code to activate DND
dndCodeOff = "*79"; //asterisk feature code to deactivate DND
}
public static void loadSettings() {
String fn = "/sdcard/.jphone.xml";
current = new Settings();
try {
FileReader r = new FileReader(fn);
SettingsSAX sax = new SettingsSAX();
Xml.parse(r, sax);
r.close();
JFLog.log("loadSettings successful!");
} catch (Exception e) {
JFLog.log("loadSettings Exception:", e);
current = new Settings();
}
//validate config
for(int a=0;a<6;a++) {
if ((current.lines[a].same > 5) || (current.lines[a].same < -1)) current.lines[a].same = -1;
}
}
private static void write(OutputStream os, String str) throws Exception {
os.write(str.getBytes());
}
public static void saveSettings() {
String fn = "/sdcard/.jphone.xml";
try {
FileOutputStream fos = new FileOutputStream(fn);
write(fos, "<?xml version=\"1.0\"?>");
write(fos, "<settings>");
for(int a=0;a<6;a++) {
write(fos, "<line>");
write(fos, "<same>" + current.lines[a].same + "</same>");
write(fos, "<name>" + current.lines[a].name + "</name>");
write(fos, "<user>" + current.lines[a].user + "</user>");
write(fos, "<auth>" + current.lines[a].auth + "</auth>");
write(fos, "<pass>" + current.lines[a].pass + "</pass>");
write(fos, "<host>" + current.lines[a].host + "</host>");
write(fos, "</line>");
}
write(fos, "<dndCodeOn>" + current.dndCodeOn + "</dndCodeOn>");
write(fos, "<dndCodeOff>" + current.dndCodeOff + "</dndCodeOff>");
write(fos, "<use_g729a>" + current.use_g729a + "</use_g729a>");
write(fos, "<use_g711u>" + current.use_g711u + "</use_g711u>");
write(fos, "<use_g711a>" + current.use_g711a + "</use_g711a>");
write(fos, "<use_g722>" + current.use_g722 + "</use_g722>");
write(fos, "<speakerMode>" + current.speakerMode + "</speakerMode>");
write(fos, "<speakerThreshold>" + current.speakerThreshold + "</speakerThreshold>");
write(fos, "<speakerDelay>" + current.speakerDelay + "</speakerDelay>");
write(fos, "</settings>");
fos.close();
} catch (Exception e) {
JFLog.log("saveSettings:", e);
}
}
/** Encodes a password with some simple steps. */
public static String encodePassword(String password) {
char ca[] = password.toCharArray();
int sl = ca.length;
if (sl == 0) return "";
char tmp;
for(int p=0;p<sl/2;p++) {
tmp = ca[p];
ca[p] = ca[sl-p-1];
ca[sl-p-1] = tmp;
}
StringBuffer out = new StringBuffer();
for(int p=0;p<sl;p++) {
ca[p] ^= 0xaa;
if (ca[p] < 0x10) out.append("0");
out.append(Integer.toString(ca[p], 16));
}
//System.out.println("e1=" + out.toString());
Random r = new Random();
char key = (char)(r.nextInt(0xef) + 0x10);
char outkey = key;
ca = out.toString().toCharArray();
sl = ca.length;
for(int p=0;p<sl;p++) {
ca[p] ^= key;
key ^= ca[p];
}
out = new StringBuffer();
for(int a=0;a<4;a++) {
out.append(Integer.toString(r.nextInt(0xef) + 0x10, 16));
}
out.append(Integer.toString(outkey, 16));
for(int p=0;p<sl;p++) {
if (ca[p] < 0x10) out.append("0");
out.append(Integer.toString(ca[p], 16));
}
for(int a=0;a<4;a++) {
out.append(Integer.toString(r.nextInt(0xef) + 0x10, 16));
}
return out.toString();
}
public static String encodePassword(char password[]) {
return encodePassword(new String(password));
}
/** Decodes a password. */
public static String decodePassword(String crypto) {
int sl = crypto.length();
if (sl < 10) return null;
char key = (char)(int)Integer.valueOf(crypto.substring(8,10), 16);
char newkey;
crypto = crypto.substring(10, sl - 8);
int cl = (sl - 18) / 2;
char ca[] = new char[cl];
for(int p=0;p<cl;p++) {
ca[p] = (char)(int)Integer.valueOf(crypto.substring(p*2, p*2+2), 16);
newkey = (char)(key ^ ca[p]);
ca[p] ^= key;
key = newkey;
}
crypto = new String(ca);
//System.out.println("d1=" + crypto);
cl = crypto.length() / 2;
ca = new char[cl];
for(int p=0;p<cl;p++) {
ca[p] = (char)(int)Integer.valueOf(crypto.substring(p*2, p*2+2), 16);
}
for(int p=0;p<cl;p++) {
ca[p] ^= 0xaa;
}
char tmp;
for(int p=0;p<cl/2;p++) {
tmp = ca[p];
ca[p] = ca[cl-p-1];
ca[cl-p-1] = tmp;
}
return new String(ca);
}
public static String getPassword(String pass) {
if (pass.startsWith("crypto(") && pass.endsWith(")")) {
if (pass.charAt(8) != ',') return ""; //bad function
if (pass.charAt(7) != '1') return ""; //unknown crypto type
try {
String decoded = decodePassword(pass.substring(9, pass.length() - 1));
if (decoded == null) decoded = "";
return decoded;
} catch (Exception e) {}
} else {
return pass;
}
return "";
}
public String[] getAudioCodecs() {
ArrayList<String> list = new ArrayList<String>();
if (use_g729a) list.add(RTP.CODEC_G729a.name);
if (use_g711u) list.add(RTP.CODEC_G711u.name);
if (use_g711a) list.add(RTP.CODEC_G711a.name);
if (use_g722) list.add(RTP.CODEC_G722.name);
return list.toArray(new String[list.size()]);
}
public boolean hasAudioCodec(Codec codec) {
String codecs[] = getAudioCodecs();
if (codecs == null) return false;
for(int a=0;a<codecs.length;a++) {
if (codecs[a].equals(codec.name)) return true;
}
return false;
}
//DefaultHandler members
private static class SettingsSAX extends DefaultHandler {
private int line;
private enum Tag {
none, line, dndon, dndoff, same, name, user, auth, pass, host, speakerMode, speakerThreshold, speakerDelay,
g729a, g711u, g711a, g722
}
private Tag tag;
public void startDocument () {
line = -1;
tag = Tag.none;
}
public void endDocument () {}
public void startElement (String uri, String name, String qName, Attributes atts) {
if (name.equals("line")) {line++; tag = Tag.line; return;}
if (name.equals("same")) {tag = Tag.same; return;}
if (name.equals("name")) {tag = Tag.name; return;}
if (name.equals("user")) {tag = Tag.user; return;}
if (name.equals("auth")) {tag = Tag.auth; return;}
if (name.equals("host")) {tag = Tag.host; return;}
if (name.equals("pass")) {tag = Tag.pass; return;}
if (name.equals("dndCodeOn")) {tag = Tag.dndon; return;}
if (name.equals("dndCodeOff")) {tag = Tag.dndoff; return;}
if (name.equals("use_g729a")) {tag = Tag.g729a; return;}
if (name.equals("use_g711a")) {tag = Tag.g711a; return;}
if (name.equals("use_g711u")) {tag = Tag.g711u; return;}
if (name.equals("use_g722")) {tag = Tag.g722; return;}
if (name.equals("speakerMode")) {tag = Tag.speakerMode; return;}
if (name.equals("speakerThreshold")) {tag = Tag.speakerThreshold; return;}
if (name.equals("speakerDelay")) {tag = Tag.speakerDelay; return;}
}
public void endElement (String uri, String name, String qName) {
tag = Tag.none;
}
public void characters (char ch[], int start, int length) {
String str = new String(ch,start,length);
switch (tag) {
case same:
current.lines[line].same = Integer.valueOf(str);
break;
case name:
current.lines[line].name = str;
break;
case user:
current.lines[line].user = str;
break;
case auth:
current.lines[line].auth = str;
break;
case host:
current.lines[line].host = str;
break;
case pass:
current.lines[line].pass = str;
break;
case dndon:
current.dndCodeOn = str;
break;
case dndoff:
current.dndCodeOff = str;
break;
case g729a:
current.use_g729a = str.equals("true");
break;
case g711a:
current.use_g711a = str.equals("true");
break;
case g711u:
current.use_g711u = str.equals("true");
break;
case g722:
current.use_g722 = str.equals("true");
break;
case speakerMode:
current.speakerMode = str.equals("true");
break;
case speakerThreshold:
try {
current.speakerThreshold = Integer.valueOf(str);
} catch (Exception e1) {
current.speakerThreshold = 1000;
}
break;
case speakerDelay:
try {
current.speakerDelay = Integer.valueOf(str);
} catch (Exception e1) {
current.speakerDelay = 1250;
}
break;
}
}
}
}