From 91efde96a1fbb5dd7c535ca5b4f17518fb4d89f8 Mon Sep 17 00:00:00 2001 From: Benoit Pradelle Date: Tue, 16 Oct 2007 13:04:38 +0000 Subject: [PATCH] Fix many problems with SIMPLE presence documents: - it's now possible to have no in a presence document - no more problem with namespaces (RPID and PIDF) - activities are now correctly parsed - take into account even when there is no or Thanks a lot to Ralph Weires who noticed and corrected these problems --- .../sip/OperationSetPresenceSipImpl.java | 263 +++++++++++------- 1 file changed, 158 insertions(+), 105 deletions(-) diff --git a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetPresenceSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetPresenceSipImpl.java index 757899ee5..bf7b69b6d 100644 --- a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetPresenceSipImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetPresenceSipImpl.java @@ -223,6 +223,9 @@ public class OperationSetPresenceSipImpl private static final String NS_BUSY_ELT = "rpid:busy"; private static final String OTP_ELEMENT = "on-the-phone"; private static final String NS_OTP_ELT = "rpid:on-the-phone"; + + // namespace wildcard + private static final String ANY_NS = "*"; /** * Creates an instance of this operation set keeping a reference to the @@ -3590,7 +3593,8 @@ public void setPidfPresenceStatus(String presenceDoc) logger.debug("parsing:\n" + presenceDoc); // - NodeList presList = doc.getElementsByTagName(PRESENCE_ELEMENT); + NodeList presList = doc.getElementsByTagNameNS(NS_VALUE, + PRESENCE_ELEMENT); if (presList.getLength() == 0) { logger.error("no presence element in this document"); return; @@ -3612,7 +3616,8 @@ public void setPidfPresenceStatus(String presenceDoc) // ignore namespaces here SipStatusEnum personStatus = null; - NodeList personList = presence.getElementsByTagName(PERSON_ELEMENT); + NodeList personList = presence.getElementsByTagNameNS(ANY_NS, + PERSON_ELEMENT); if (personList.getLength() > 1) { logger.error("more than one person in this document"); @@ -3622,13 +3627,13 @@ public void setPidfPresenceStatus(String presenceDoc) if (personList.getLength() > 0) { Node personNode = personList.item(0); if (personNode.getNodeType() != Node.ELEMENT_NODE) { - logger.error("the person node is not and element"); + logger.error("the person node is not an element"); return; } Element person = (Element) personNode; NodeList activityList = - person.getElementsByTagName(ACTIVITY_ELEMENT); + person.getElementsByTagNameNS(ANY_NS, ACTIVITY_ELEMENT); if (activityList.getLength() > 0) { Element activity = null; // find the first correct activity @@ -3640,24 +3645,37 @@ public void setPidfPresenceStatus(String presenceDoc) } activity = (Element) activityNode; - - // convert the activity in a SC status - if (activity.getNodeName().equals(AWAY_ELEMENT)) { - personStatus = SipStatusEnum.AWAY; - break; - } else if (activity.getNodeName().equals(BUSY_ELEMENT)) { - personStatus = SipStatusEnum.BUSY; - break; - } else if (activity.getNodeName().equals(OTP_ELEMENT)) { - personStatus = SipStatusEnum.ON_THE_PHONE; - break; + + NodeList statusList = activity.getChildNodes(); + for (int j = 0; j < statusList.getLength(); j++) + { + Node statusNode = statusList.item(j); + if (statusNode.getNodeType() == Node.ELEMENT_NODE) + { + String statusname = statusNode.getLocalName(); + if (statusname.equals(AWAY_ELEMENT)) { + personStatus = SipStatusEnum.AWAY; + break; + } + else if (statusname.equals(BUSY_ELEMENT)) { + personStatus = SipStatusEnum.BUSY; + break; + } + else if (statusname.equals(OTP_ELEMENT)) { + personStatus = SipStatusEnum.ON_THE_PHONE; + break; + } + } } + if (personStatus != null) + break; } } } // - NodeList tupleList = presence.getElementsByTagName(TUPLE_ELEMENT); + NodeList tupleList = presence.getElementsByTagNameNS(NS_VALUE, + TUPLE_ELEMENT); for (int i = 0; i < tupleList.getLength(); i++) { Node tupleNode = tupleList.item(i); @@ -3668,70 +3686,90 @@ public void setPidfPresenceStatus(String presenceDoc) Element tuple = (Element) tupleNode; // - NodeList contactList = tuple.getElementsByTagName( + NodeList contactList = tuple.getElementsByTagNameNS(NS_VALUE, CONTACT_ELEMENT); - - // there should normally be only one contact per tuple (RFC3863) - for (int j = 0; j < contactList.getLength(); j++) { - Node contactNode = contactList.item(j); - - if (contactNode.getNodeType() != Node.ELEMENT_NODE) { - continue; + + // we use a vector here and not an unique contact to handle an + // error case where many contacts are associated with a status + // Vector + Vector sipcontact = new Vector(1, 3); + String contactID = null; + if (contactList.getLength() == 0) + { + // use the entity attribute of the presence node + contactID = XMLUtils.getAttribute( + presNode, ENTITY_ATTRIBUTE); + // also accept entity URIs starting with pres: instead of sip: + if (contactID.startsWith("pres:")) + contactID = contactID.substring("pres:".length()); + Contact tmpContact = resolveContactID(contactID); + if (tmpContact != null) { + sipcontact.add(tmpContact); } + } + else + { + // this is normally not permitted by RFC3863 + for (int j = 0; j < contactList.getLength(); j++) { + Node contactNode = contactList.item(j); - Element contact = (Element) contactNode; - ContactSipImpl sipcontact = (ContactSipImpl) - resolveContactID(getTextContent(contact)); - - if (sipcontact == null) { - logger.debug("no contact found for id: " + - getTextContent(contact)); - continue; - } + if (contactNode.getNodeType() != Node.ELEMENT_NODE) { + continue; + } + + Element contact = (Element) contactNode; - // if we use RPID, simply ignore the standard PIDF status - if (personStatus != null) { - changePresenceStatusForContact(sipcontact, personStatus); - continue; + contactID = getTextContent(contact); + Contact tmpContact = resolveContactID(contactID); + if (tmpContact != null) { + sipcontact.add(tmpContact); + } } - - // - NodeList statusList = tuple.getElementsByTagName( - STATUS_ELEMENT); - if (statusList.getLength() == 0) { - logger.debug("no status in this tuple"); - continue; + } + + if (sipcontact.isEmpty()) { + logger.debug("no contact found for id: " + contactID); + continue; + } + + // if we use RPID, simply ignore the standard PIDF status + if (personStatus != null) { + for (int j = 0; j < sipcontact.size(); j++) { + changePresenceStatusForContact( + (ContactSipImpl) sipcontact.get(j), + personStatus); } - - // in case of many status, just consider the last one - // this is normally not permitted by RFC3863 - int index = statusList.getLength() - 1; - Node statusNode = null; - do { - Node temp = statusList.item(index); - if (temp.getNodeType() == Node.ELEMENT_NODE) { - statusNode = temp; - break; - } - index--; - } while (index >= 0); - - if (statusNode == null) { - logger.debug("no valid status in this tuple"); + continue; + } + + // + NodeList statusList = tuple.getElementsByTagNameNS(NS_VALUE, + STATUS_ELEMENT); + + // in case of many status, just consider the last one + // this is normally not permitted by RFC3863 + int index = statusList.getLength() - 1; + Node statusNode = null; + do { + Node temp = statusList.item(index); + if (temp.getNodeType() == Node.ELEMENT_NODE) { + statusNode = temp; break; } - + index--; + } while (index >= 0); + + Element basic = null; + + if (statusNode == null) { + logger.debug("no valid status in this tuple"); + } else { Element status = (Element) statusNode; - + // - NodeList basicList = status.getElementsByTagName( + NodeList basicList = status.getElementsByTagNameNS(NS_VALUE, BASIC_ELEMENT); - - if (basicList.getLength() == 0) { - logger.debug("no in this status"); - continue; - } - + // in case of many basic, just consider the last one // this is normally not permitted by RFC3863 index = basicList.getLength() - 1; @@ -3744,59 +3782,74 @@ public void setPidfPresenceStatus(String presenceDoc) } index--; } while (index >= 0); - + if (basicNode == null) { logger.debug("no valid in this status"); - break; + } else { + basic = (Element) basicNode; } + } - Element basic = (Element) basicNode; - - // search for a that can define a more precise - // status this is not recommended by RFC3863 but some im - // clients use this. - NodeList noteList = tuple.getElementsByTagName(NOTE_ELEMENT); + // search for a that can define a more precise + // status this is not recommended by RFC3863 but some im + // clients use this. + NodeList noteList = tuple.getElementsByTagNameNS(NS_VALUE, + NOTE_ELEMENT); - boolean changed = false; - for (int k = 0; k < noteList.getLength() && !changed; k++) - { - Node noteNode = noteList.item(k); + boolean changed = false; + for (int k = 0; k < noteList.getLength() && !changed; k++) + { + Node noteNode = noteList.item(k); - if (noteNode.getNodeType() != Node.ELEMENT_NODE) { - continue; - } + if (noteNode.getNodeType() != Node.ELEMENT_NODE) { + continue; + } - Element note = (Element) noteNode; + Element note = (Element) noteNode; - String state = getTextContent(note); + String state = getTextContent(note); - Iterator states = SipStatusEnum.supportedStatusSet(); - while (states.hasNext()) { - SipStatusEnum current = (SipStatusEnum) states.next(); + Iterator states = SipStatusEnum.supportedStatusSet(); + while (states.hasNext()) { + SipStatusEnum current = (SipStatusEnum) states.next(); - if (current.getStatusName().equalsIgnoreCase(state)) { - changed = true; - changePresenceStatusForContact(sipcontact, + if (current.getStatusName().equalsIgnoreCase(state)) { + changed = true; + for (int j = 0; j < sipcontact.size(); j++) { + changePresenceStatusForContact( + (ContactSipImpl) sipcontact.get(j), current); - break; } + break; } } + } - if (changed == false) { - if (getTextContent(basic).equalsIgnoreCase(ONLINE_STATUS)) - { - changePresenceStatusForContact(sipcontact, - SipStatusEnum.ONLINE); - } else if (getTextContent(basic).equalsIgnoreCase( - OFFLINE_STATUS)) - { - changePresenceStatusForContact(sipcontact, - SipStatusEnum.OFFLINE); + if (changed == false && basic != null) { + if (getTextContent(basic).equalsIgnoreCase(ONLINE_STATUS)) + { + for (int j = 0; j < sipcontact.size(); j++) { + changePresenceStatusForContact( + (ContactSipImpl) sipcontact.get(j), + SipStatusEnum.ONLINE); + } + } else if (getTextContent(basic).equalsIgnoreCase( + OFFLINE_STATUS)) + { + for (int j = 0; j < sipcontact.size(); j++) { + changePresenceStatusForContact( + (ContactSipImpl) sipcontact.get(j), + SipStatusEnum.OFFLINE); } } + } else { + if (changed == false) { + logger.debug("no suitable presence state found in this " + + "tuple"); + } } - } + } // for each + } /** @@ -4218,7 +4271,7 @@ public void registrationStateChanged(RegistrationStateChangeEvent evt) forcePollContact(contact); } } - + // create a new Timer (the last one has been cancelled) timer = new Timer(true);