/* * 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 gov.nist.javax.sip.address.SipUri; import java.lang.ref.WeakReference; import javax.sip.ClientTransaction; import javax.sip.Dialog; import javax.sip.DialogTerminatedEvent; import javax.sip.IOExceptionEvent; import javax.sip.RequestEvent; import javax.sip.ResponseEvent; import javax.sip.ServerTransaction; import javax.sip.SipListener; import javax.sip.TimeoutEvent; import javax.sip.TransactionTerminatedEvent; import javax.sip.address.Address; import javax.sip.address.SipURI; import javax.sip.address.URI; import javax.sip.header.CSeqHeader; import javax.sip.header.ContactHeader; import javax.sip.header.ExpiresHeader; import javax.sip.header.FromHeader; import javax.sip.header.SubscriptionStateHeader; import javax.sip.header.ToHeader; import javax.sip.message.Request; import javax.sip.message.Response; import net.sf.kraken.type.TransportLoginStatus; import org.apache.log4j.Logger; import org.jivesoftware.util.NotFoundException; import org.xmpp.packet.JID; import org.xmpp.packet.Presence; /** * A listener for a SIMPLE session. * <br><br> * Instances of this class serve as an assistant to SimpleSession objects, * carrying out works of receiving messages or responses from the SIP server * or another remote client. * * @author Patrick Siu * @author Daniel Henninger */ public class SimpleListener implements SipListener { static Logger Log = Logger.getLogger(SimpleListener.class); /** * Stores the SIMPLE session object to which this listener belongs. */ private WeakReference<SimpleSession> mySimpleSessionRef; /** * Returns the Simple session this listener is attached to. * * @return Simple session we are attached to. */ public SimpleSession getSession() { return mySimpleSessionRef.get(); } /** * Stores the XMPP server username using this SIMPLE session listener. * <br><br> * The storage is for logging purpose. */ private String myUsername; /** * Constructor. * @param mySimpleSession The SIMPLE session object to which this listener belongs. */ public SimpleListener(SimpleSession mySimpleSession) { this.mySimpleSessionRef = new WeakReference<SimpleSession>(mySimpleSession); this.myUsername = mySimpleSession.getJID().getNode(); } public void processRequest(RequestEvent requestEvent) { ServerTransaction serverTransaction = requestEvent.getServerTransaction(); Dialog dialog = null; if (serverTransaction != null) { Log.debug("SimpleListener(" + myUsername + ").processRequest: Getting dialog"); dialog = serverTransaction.getDialog(); } int responseCode = 200; Log.debug("SimpleListener(" + myUsername + ").processRequest: Received a request event: \n" + requestEvent.getRequest().toString()); String fromAddr = ""; Request request = requestEvent.getRequest(); if (request.getHeader(FromHeader.NAME) != null) { FromHeader fromHeader = (FromHeader) request.getHeader(FromHeader.NAME); Address fromAddress = fromHeader.getAddress(); // String displayName = fromAddress.getDisplayName(); URI fromUri = fromAddress.getURI(); if (fromUri != null) { if (fromUri.isSipURI()) { SipURI fromSipUri = (SipURI) fromUri; fromAddr = fromSipUri.getUser() + "@" + fromSipUri.getHost(); } else { fromAddr = fromUri.toString(); } } } Log.debug("SimpleListener(" + myUsername + ").processRequest: FromAddr = " + fromAddr); Log.debug("SimpleListener(" + myUsername + ").processRequest: Request method = '" + request.getMethod() + "'"); if (request.getMethod().equals(Request.MESSAGE)) { Log.debug("SimpleListener(" + myUsername + ").processRequest: Starting MESSAGE request handling process."); JID senderJid = getSession().getTransport().convertIDToJID(fromAddr); String msgContent = new String((byte []) request.getContent()); Log.debug("SimpleListener(" + myUsername + ").processRequest: Forwarding MESSAGE request as XMPP message, setting from = " + senderJid + " and content = '" + msgContent + "'"); getSession().getTransport().sendMessage(getSession().getJID(), senderJid, msgContent); getSession().sendResponse(responseCode, request, serverTransaction); } else if (request.getMethod().equals(Request.NOTIFY)) { SubscriptionStateHeader subscriptionStateHeader = (SubscriptionStateHeader) request.getHeader(SubscriptionStateHeader.NAME); Log.debug("SimpleListener(" + myUsername + ").processRequest: NOTIFY request handling process started."); if (subscriptionStateHeader.getState().equalsIgnoreCase(SubscriptionStateHeader.ACTIVE)) { Log.debug("SimpleListener(" + myUsername + ").processRequest: NOTIFY Active!"); int expires = subscriptionStateHeader.getExpires(); Log.debug("SimpleListener(" + myUsername + ").processRequest: NOTIFY Expiry = " + expires); try { if (expires > 0) { String content = ""; if (request.getContent() != null) content = new String((byte []) request.getContent()); if (content.length() > 0) { SimplePresence simplePresence = SimplePresence.parseSimplePresence(content); try { SimpleBuddy buddy = getSession().getBuddyManager().getBuddy(getSession().getTransport().convertIDToJID(fromAddr)); String verboseStatus = null; if (simplePresence.getTupleStatus().isOpen()) { switch (simplePresence.getRpid()) { case ON_THE_PHONE: // TODO: Translate this verboseStatus = "On Phone"; } } buddy.setPresenceAndStatus(((SimpleTransport)getSession().getTransport()).convertSIPStatusToXMPP(simplePresence), verboseStatus); } catch (NotFoundException e) { // Not in our contact list. Ignore. Log.debug("SIMPLE: Received presense notification for contact we don't care about: "+fromAddr); } } } else { Presence p = new Presence(); p.setType(Presence.Type.unsubscribed); p.setTo(getSession().getJID()); p.setFrom(getSession().getTransport().convertIDToJID(fromAddr)); getSession().getTransport().sendPacket(p); } Log.debug("SimpleListener(" + myUsername + ").processRequest: Sending XMPP presence packet."); } catch (Exception ex) { Log.debug("SimpleListener(" + myUsername + ").processRequest: Exception occured when processing NOTIFY packet...", ex); } } else if (subscriptionStateHeader.getState().equalsIgnoreCase(SubscriptionStateHeader.TERMINATED)) { Presence p = new Presence(); p.setType(Presence.Type.unsubscribed); p.setTo(getSession().getJID()); p.setFrom(getSession().getTransport().convertIDToJID(fromAddr)); getSession().getTransport().sendPacket(p); } getSession().sendResponse(responseCode, request, serverTransaction); } else if (request.getMethod().equals(Request.SUBSCRIBE)) { Log.debug("SimpleListener for " + myUsername + ": SUBSCRIBE request handling process."); ServerTransaction transaction = getSession().sendResponse(202, request, serverTransaction); Log.debug("SimpleListener for " + myUsername + ": SUBSCRIBE should be followed by a NOTIFY"); // Send NOTIFY packet. try { if (transaction != null) getSession().sendNotify(transaction.getDialog()); else getSession().sendNotify(dialog); } catch (Exception e) { Log.debug("SimpleListener for " + myUsername + ": Unable to prepare NOTIFY packet.", e); } } } public void processResponse(ResponseEvent responseEvent) { if (responseEvent.getClientTransaction() != null) { Log.debug("SimpleListener for " + myUsername + ": Getting client transaction..."); ClientTransaction clientTransaction = responseEvent.getClientTransaction(); Dialog clientDialog = clientTransaction.getDialog(); getSession().printDialog(clientDialog); } Log.debug("SimpleListener for " + myUsername + ": Received a response event: " + responseEvent.getResponse().toString()); // String fromAddr = ""; String toAddr = ""; Response response = responseEvent.getResponse(); // if (response.getHeader(FromHeader.NAME) != null) { // FromHeader fromHeader = (FromHeader) response.getHeader(FromHeader.NAME); // URI fromUri = fromHeader.getAddress().getURI(); // if (fromUri instanceof SipUri) // fromAddr = ((SipUri) fromUri).getUser() + "@" + ((SipUri) fromUri).getHost(); // else // fromAddr = fromUri.toString(); // } if (response.getHeader(ToHeader.NAME) != null) { ToHeader toHeader = (ToHeader) response.getHeader(ToHeader.NAME); URI toUri = toHeader.getAddress().getURI(); if (toUri instanceof SipUri) toAddr = ((SipUri) toUri).getUser() + "@" + ((SipUri) toUri).getHost(); else toAddr = toUri.toString(); } if (response.getHeader(CSeqHeader.NAME) != null) { String method = ((CSeqHeader) response.getHeader(CSeqHeader.NAME)).getMethod(); if (method.equals(Request.REGISTER)) { if (response.getStatusCode() / 100 == 2) { int expires = 0; if (response.getHeader(ContactHeader.NAME) != null) { expires = ((ContactHeader) response.getHeader(ContactHeader.NAME)).getExpires(); } else if (response.getHeader(ExpiresHeader.NAME) != null) { expires = ((ExpiresHeader) response.getHeader(ExpiresHeader.NAME)).getExpires(); } if (expires > 0) { Log.debug("SimpleListener(" + myUsername + ").processResponse: " + getSession().getRegistration().getUsername() + " log in successful!"); getSession().sipUserLoggedIn(); } else { if (getSession().getLoginStatus().equals(TransportLoginStatus.LOGGING_OUT)) { Log.debug("SimpleListener(" + myUsername + ").processResponse: " + getSession().getRegistration().getUsername() + " log out successful!"); getSession().sipUserLoggedOut(); getSession().removeStack(); } } } } if (method.equals(Request.SUBSCRIBE)) { if (response.getStatusCode() / 100 == 2) { Log.debug("SimpleListener for " + myUsername + ": Handling SUBSCRIBE acknowledgement!!"); int expires = 0; if (response.getHeader(ContactHeader.NAME) != null) { expires = ((ContactHeader) response.getHeader(ContactHeader.NAME)).getExpires(); } if (response.getHeader(ExpiresHeader.NAME) != null) { expires = ((ExpiresHeader) response.getHeader(ExpiresHeader.NAME)).getExpires(); } // Presence presence = new Presence(); // presence.setFrom(getSession().getTransport().convertIDToJID(toAddr)); // presence.setTo(getSession().getJID()); if (expires > 0) { // Confirm subscription of roster item getSession().contactSubscribed(toAddr); } else { // Confirm unsubscription of roster item getSession().contactUnsubscribed(toAddr); } Log.debug("SimpleListener for " + myUsername + ": Handled SUBSCRIBE acknowledgement!!"); } } } } public void processTimeout(TimeoutEvent timeoutEvent) { Log.debug("SimpleListener for " + myUsername + " received a timeout event: " + timeoutEvent.getTimeout().toString()); // timeoutEvent.getTimeout(). // Should we try to resend the packet? } public void processIOException(IOExceptionEvent iOExceptionEvent) { Log.debug("SimpleListener for " + myUsername + " received an IOException event: " + iOExceptionEvent.toString()); } public void processTransactionTerminated(TransactionTerminatedEvent transactionTerminatedEvent) { Log.debug("SimpleListener(" + myUsername + "): Received a TransactionTerminatedEvent [" + transactionTerminatedEvent.hashCode() + "]"); // Should we obtain the transaction and log down the tranaction terminated? } public void processDialogTerminated(DialogTerminatedEvent dialogTerminatedEvent) { Log.debug("SimpleListener for " + myUsername + " received a dialog terminated event: " + dialogTerminatedEvent.getDialog().getDialogId()); } @Override public void finalize() { try { super.finalize(); } catch (Throwable e) { // Hrm } Log.debug("SimpleListener for " + myUsername + " is being shut down!!"); } }