/*
* 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!!");
}
}