/* * Copyright 2006-2010 Daniel Henninger. All rights reserved. * * This software is published under the terms of the GNU Public License (GPL), * a copy of which is included in this distribution. */ package net.sf.kraken.protocols.simple; import java.io.ByteArrayInputStream; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.apache.log4j.Logger; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; /** * This class performs conversions between presence packets of XMPP and SIMPLE formats. * <br> * By now, SIP presence comforms with <a href="http://www.ietf.org/rfc/rfc4480.txt">RFC4480</a>. * @author Patrick Siu * @author Daniel Henninger */ public class SimplePresence { static Logger Log = Logger.getLogger(SimplePresence.class); /** * Tuple status of the presence packet. * @author Patrick Siu * @version 0.0.1 */ public enum TupleStatus { OPEN ("open"), CLOSED("closed"); private String status; public static TupleStatus getTupleStatus(String tupleStatusString) throws IllegalArgumentException { for (TupleStatus t : values()) { if (t.toString().equalsIgnoreCase(tupleStatusString)) return t; } throw new IllegalArgumentException("There is no matching TupleStatus for this String."); } private TupleStatus(String status) { this.status = status; } public boolean isOpen() { return status.equals("open"); } @Override public String toString() { return status; } } /** * Represents the rpid of the status packet. * <br><br> * Refer to <a href="http://www.ietf.org/rfc/rfc4480.txt">RFC4480</a> for details of these statuses. * @author Patrick Siu * @version 0.0.1 */ public enum Rpid { APPOINTMENT ("appointment"), AWAY ("away"), BREAKFAST ("breakfast"), BUSY ("busy"), DINNER ("dinner"), HOLIDAY ("holiday"), IN_TRANSIT ("in-transit"), LOOKING_FOR_WORK ("looking-for-work"), LUNCH ("lunch"), MEAL ("meal"), MEETING ("meeting"), ON_THE_PHONE ("on-the-phone"), OTHER ("other"), PERFORMANCE ("performance"), PERMANENT_ABSENCE("permanent-absence"), PLAYING ("playing"), PRESENTATION ("presentation"), SHOPPING ("shopping"), SLEEPING ("sleeping"), SPECTATOR ("spectator"), STEERING ("steering"), TRAVEL ("travel"), TV ("tv"), UNKNOWN ("unknown"), VACATION ("vacation"), WORKING ("working"), WORSHIP ("worship"); private String desc; public static Rpid getRpid(String rpidString) throws IllegalArgumentException { for (Rpid r : values()) { if (r.toString().equalsIgnoreCase(rpidString)) return r; } throw new IllegalArgumentException("There is no matching Rpid for the String."); } private Rpid(String desc) { this.desc = desc; } /** * Overridden to return the string description of the constant. */ @Override public String toString() { return desc; } } private TupleStatus tupleStatus; private Rpid rpid; private String dmNote; private String entity; /** * Constructor. */ public SimplePresence() { this.tupleStatus = TupleStatus.OPEN; this.rpid = Rpid.UNKNOWN; this.dmNote = ""; this.entity = ""; } public SimplePresence(TupleStatus tupleStatus) { this.tupleStatus = tupleStatus; this.rpid = Rpid.UNKNOWN; this.dmNote = ""; this.entity = ""; } public void setRpid(Rpid rpid) { this.rpid = rpid; } public void setDmNote(String dmNote) { this.dmNote = dmNote; } public void setEntity(String entity) { this.entity = entity; } public void setTupleStatus(TupleStatus tupleStatus) { this.tupleStatus = tupleStatus; } public Rpid getRpid() { return this.rpid; } public String getDmNote() { return this.dmNote; } public TupleStatus getTupleStatus() { return this.tupleStatus; } private String getEightLength(int hash) { StringBuffer buffer = new StringBuffer(Integer.toHexString(hash)); while (buffer.length() < 8) { buffer.insert(0, "0"); } return new String(buffer); } public String toXML() { return "<?xml version='1.0' encoding='UTF-8'?>" + "<presence xmlns='urn:ietf:params:xml:ns:pidf'" + " xmlns:dm='urn:ietf:params:xml:ns:pidf:data-model'" + " xmlns:rpid='urn:ietf:params:xml:ns:pidf:rpid'" + " xmlns:c='urn:ietf:params:xml:ns:pidf:cipid'" + " entity='" + entity + "'>" + "<tuple id='t" + getEightLength(tupleStatus.hashCode()) + "'><status><basic>" + tupleStatus.toString() + "</basic></status></tuple>" + "<dm:person id='p" + getEightLength(this.hashCode()) + "'><rpid:activities><rpid:" + rpid.toString() + "/></rpid:activities>" + // "<tuple><status><basic>" + tupleStatus.toString() + "</basic></status></tuple>" + // "<dm:person><rpid:activities><rpid:" + rpid.toString() + "/></rpid:activities>" + ((dmNote != null && !dmNote.equals("")) ? "<dm:note>" + dmNote + "</dm:note>" : "") + "</dm:person>" + "</presence>"; // DocumentFactory docFactory = DocumentFactory.getInstance(); // // Document xmlDocument = docFactory.createDocument(); // Element rootElement = docFactory.createDocument().addElement("presence"); // // rootElement.addAttribute("xmlns", "urn:ietf:params:xml:ns:pidf"); // rootElement.addAttribute(new QName("xmlns", "dm"), "urn:ietf:params:xml:ns:pidf:data-model"); // rootElement.addAttribute(new QName("xmlns", "rpid"), "urn:ietf:params:xml:ns:pidf:rpid"); // rootElement.addAttribute(new QName("xmlns", "c"), "urn:ietf:params:xml:ns:pidf:cipid"); // rootElement.addAttribute("entity", entity); // // Element tupleElement = rootElement.addElement("tuple"); // tupleElement.addAttribute("id", "t" + Integer.toHexString(this.hashCode())); // tupleElement.addElement("status").addElement("basic").setText(this.tupleStatus.toString()); // // Element personElement = rootElement.addElement(new QName("dm", "person")); // personElement.addAttribute("id", "p" + Integer.toHexString(this.hashCode())); // personElement.addElement(new QName("rpid", "activities")).addElement("rpid:" + this.rpid.toString()); // // if (this.dmNote != null && !this.dmNote.trim().equals("")) { // personElement.addElement("dm:note").setText(this.dmNote); // } // // return xmlDocument.asXML(); // return result; } // public Presence convertSIPPresenceToXMPP(String sipPresence) { // Presence xmppPresence = new Presence(); // // SAXParser saxParser; // try { // SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); // saxParser = saxParserFactory.newSAXParser(); // // } catch (Exception e) { // Log.debug("Unable to load parser to parse SIP presence to XMPP Presence.", e); // return xmppPresence; // } // // return xmppPresence; // } // public String convertXMPPPresenceToSIP(Presence xmppPresence) { // String sipPresence = ""; // String basic = "open"; // String rpid = "unknown"; // String dmNote = ""; // // if (!xmppPresence.isAvailable()) { // // Prepare "closed" basic presence. // basic = "closed"; // } else { // Presence.Show xmppPresenceShow = xmppPresence.getShow(); // if (xmppPresenceShow.equals(Presence.Show.away)) { // rpid = "away"; // } else if (xmppPresenceShow.equals(Presence.Show.chat)) { // rpid = "away"; // } else if (xmppPresenceShow.equals(Presence.Show.dnd)) { // rpid = "busy"; // } else if (xmppPresenceShow.equals(Presence.Show.xa)) { // rpid = "away"; // } else { // rpid = ""; // } // } // // sipPresence = "<?xml version='1.0' encoding='UTF-8'?>" // + "<presence xmlns='urn:ietf:params:xml:ns:pidf' xmlns:dm='urn:ietf:params:xml:ns:pidf:data-model' " // + "xmlns:rpid='urn:ietf:params:xml:ns:pidf:rpid' xmlns:c='urn:ietf:params:xml:ns:pidf:cipid' " // + "entity='pres:sip:sipdemo1@192.168.1.199'>" // + "<tuple><status><basic>" + basic + "</basic></status></tuple>" // + "<dm:person id='p3e32d940'><rpid:activities><rpid:" + rpid + "/></rpid:activities></dm:person></presence>"; // // return sipPresence; // } public void parse(String simplePresenceXml) throws Exception { SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); SAXParser saxParser = saxParserFactory.newSAXParser(); ByteArrayInputStream bais = new ByteArrayInputStream(simplePresenceXml.getBytes()); saxParser.parse(bais, new SimplePresenceParser()); bais.close(); } public static SimplePresence parseSimplePresence(String simplePresenceXml) throws Exception { SimplePresence simplePresenceObject = new SimplePresence(); simplePresenceObject.parse(simplePresenceXml); return simplePresenceObject; } class SimplePresenceParser extends DefaultHandler { // private boolean isStartTag = false; private boolean isPresence = false; private boolean isStatus = false; private boolean isStatusType = false; private boolean isStatusName = false; String elementName = null; String paramName = null; String userName = null; String statusType = null; String statusName = null; public SimplePresenceParser() { } @Override public void startElement(String namespaceURI, String sName, String qName, Attributes attrs) throws SAXException { // isStartTag = true; elementName = (!sName.equals(""))? sName : qName; if(elementName.equals("presence")) { isPresence = true; if (attrs.getIndex("entity") >= 0) { entity = attrs.getValue("entity"); } } else if(elementName.equals("basic")) { isStatus = true; } else if(elementName.equals("rpid:user-input")) { isStatusType = true; } else if(elementName.startsWith("rpid:")) { try { String temp = elementName.substring(elementName.indexOf("rpid:") + 5); if(!temp.equals("activities")) { try { rpid = Rpid.getRpid(temp); } catch (IllegalArgumentException ex) { Log.debug(ex); // Ignore the exception. Leave it as "unknown". } } } catch (Exception ex) { Log.debug(ex); } } else if(elementName.equals("dm:note")) { isStatusName = true; } if (isPresence) { // for(int i = 0; i < attrs.getLength(); i++) { // if(attrs.getQName(i).equals("entity")) { // userName = attrs.getValue(i).substring(attrs.getValue(i).indexOf("sip:")); // } // } } } @Override public void characters(char buf[], int offset, int len) throws SAXException { String data = new String(buf, offset, len); if (isStatus) { try { tupleStatus = TupleStatus.getTupleStatus(data); } catch (IllegalArgumentException ex) { // Ignore } } else if (isStatusType) { // statusType = data; } else if (isStatusName) { dmNote = data; // if (rpid.compareTo(Rpid.UNKNOWN) == 0) { // try { // rpid = Rpid.getRpid(data); // } // catch (IllegalArgumentException ex) { // // Ignore the exception. Leave it as "unknown". // } // } // statusName = data; } } @Override public void endElement(String namespaceURI, String sName, String qName) throws SAXException { // isStartTag = false; elementName = (!sName.equals(""))? sName : qName; if(elementName.equals("presence")) { isPresence = false; } else if(elementName.equals("basic")) { isStatus = false; } else if(elementName.equals("rpid:user-input")) { isStatusType = false; } else if(elementName.equals("dm:note")) { isStatusName = false; } } @Override public void endDocument() throws SAXException { // obj.setUser(userName); // obj.setType(statusType); // obj.setStatus(statusName); } } }