package org.ifsoft.lync.ucwa;
import java.util.*;
import java.util.concurrent.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.security.cert.Certificate;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.SessionPacketRouter;
import org.jivesoftware.openfire.auth.UnauthorizedException;
import org.jivesoftware.openfire.net.VirtualConnection;
import org.jivesoftware.openfire.session.LocalClientSession;
import org.jivesoftware.openfire.spi.ConnectionConfiguration;
import org.xmpp.packet.Packet;
import org.dom4j.*;
import org.xmpp.packet.*;
import org.ifsoft.skype.SkypeClient;
/*
Handles the virtual xmpp session for a specific lync user/contact
*/
public class LyncConnection extends VirtualConnection
{
private static Logger Log = LoggerFactory.getLogger( "LyncConnection" );
private String remoteAddr;
private JID jid;
private String hostName;
private String username;
private LocalClientSession session;
private boolean isSecure = false;
private boolean online = false;
private ConcurrentHashMap<String, String> conferences;
public LyncConnection(JID jid, String hostName ) {
this.username = JID.escapeNode(jid.getNode());
this.remoteAddr = username + "@" + getDomain() + "/" + username;
this.hostName = hostName;
this.jid = jid;
this.conferences = new ConcurrentHashMap<String, String>();
}
public boolean isSecure() {
return isSecure;
}
public void setSecure(boolean isSecure) {
this.isSecure = isSecure;
}
public void closeVirtualConnection()
{
Log.info("LyncConnection - close ");
}
public byte[] getAddress() {
return remoteAddr.getBytes();
}
public String getHostAddress() {
return remoteAddr;
}
public String getHostName() {
return ( hostName != null ) ? hostName : "0.0.0.0";
}
public void systemShutdown() {
}
public void deliver(Packet packet) // xmpp --> lync
{
try {
Log.info( remoteAddr + " deliver : " + packet );
if (packet instanceof Message) deliver ((Message) packet);
if (packet instanceof Presence) deliver ((Presence) packet);
} catch ( Exception e ) {
Log.error( "An error occurred while attempting to route the packet : ", e );
}
}
private void deliver(Presence presence)
{
Log.info("deliver\n" + presence.toString());
String conference = presence.getFrom().getNode();
Element joined = presence.getChildElement("joined", "urn:xmpp:rayo:colibri:1");
Element unjoined = presence.getChildElement("unjoined", "urn:xmpp:rayo:colibri:1");
Element inviteaccepted = presence.getChildElement("inviteaccepted", "urn:xmpp:rayo:colibri:1");
Element invitecompleted = presence.getChildElement("invitecompleted", "urn:xmpp:rayo:colibri:1");
if (inviteaccepted != null)
{
Log.info("deliver inviteaccepted " + conference);
if (conferences.containsKey(conference) == false) // lync -> xmpp audio accept followed by join
{
String from = inviteaccepted.attributeValue("from");
try {
String participant = (new JID(from)).getNode();
conferences.put(conference, participant);
Log.info("deliver inviteaccepted " + conference + " locked to " + participant);
} catch (Exception e) {
}
}
} else if (invitecompleted != null) {
Log.info("deliver invitecompleted " + conference);
if (conferences.containsKey(conference))
{
String from = invitecompleted.attributeValue("from");
try {
String participant = (new JID(from)).getNode();
if (username.equals(participant)) // remove lync audio flag when user hangs up
{
conferences.remove(conference);
Log.info("deliver invitecompleted " + conference + " unlocked " + participant);
}
} catch (Exception e) {
}
}
} else if (joined != null) {
Log.info("deliver joined " + conference);
if (conferences.containsKey(conference) == false) // add lync audio whenever any traderlynk user adds audio
{
String mixer = joined.attributeValue("mixer-name");
String nickname = joined.attributeValue("nickname");
String participant = joined.attributeValue("participant");
boolean audio = "true".equals(joined.attributeValue("audio"));
boolean video = "true".equals(joined.attributeValue("video"));
Log.info("deliver joined" + mixer + " " + nickname + " " + participant + " " + audio + " " + video);
try {
//component.makePhoneCall(mixer, presence.getTo(), nickname);
} catch (Exception e) {
Log.error("LyncConnection deliver", e);
}
conferences.put(conference, nickname); // set audio flag
}
return;
} else if (unjoined != null) {
Log.info("deliver unjoined " + conference);
if (conferences.containsKey(conference))
{
String from = unjoined.attributeValue("nickname");
try {
String participant = (new JID(from)).getNode();
if (username.equals(participant)) // remove lync audio flag when user hangs up
{
conferences.remove(conference);
Log.info("deliver unjoined " + conference + " unlocked " + participant);
}
} catch (Exception e) {
}
}
} else {
String jidFrom = presence.getFrom().toBareJID();
SkypeClient ucwaClient = null; //plugin.getSkypeClient(jidFrom);
if (ucwaClient != null)
{
Presence.Type ptype = presence.getType();
Presence.Show stype = presence.getShow();
String status = presence.getStatus();
String availability = null;
if (stype == Presence.Show.chat) {
availability = "Online";
}
else if (stype == Presence.Show.away) {
availability = "BeRightBack";
}
else if (stype == Presence.Show.xa) {
availability = "Away";
}
else if (stype == Presence.Show.dnd) {
availability = "Busy";
}
else if (ptype == Presence.Type.unavailable) {
availability = "Off work";
} else
availability = "Online";
if (availability != null) ucwaClient.setPresence(availability);
if (status != null) ucwaClient.setNote(status);
}
}
}
private void deliver(Message message)
{
Log.info("deliver\n" + message.toString());
String username = message.getFrom().getResource();
String roomId = message.getFrom().getNode();
if (username == null) // conference invite ?
{
Element element = message.getChildElement("x", "http://jabber.org/protocol/muc#user");
if(element != null)
{
JID jidFrom = new JID(element.element("invite").attributeValue("from"));
SkypeClient ucwaClient = null; //LyncConnection.plugin.getSkypeClient(jidFrom.toBareJID());
if (ucwaClient != null) // join room on xmpp side
{
String node = JID.unescapeNode(message.getTo().getNode());
String sip = node;
if (node.indexOf("@") == -1) sip = node + "@" + ucwaClient.getDomain(); // use SIP domain, not XMPP domain in dev. Should be the same in production
Presence presence = new Presence();
presence.setTo(message.getFrom() + "/" + node);
presence.setFrom(message.getTo() + "/" + node);
presence.addChildElement("x", "http://jabber.org/protocol/muc");
//component.sendPacket(presence);
ucwaClient.sendInvite(sip, roomId, "TraderLynk");
}
}
} else if (username.indexOf("@") == -1) {
String jidFrom = username + "@" + getDomain();
SkypeClient ucwaClient = null; //plugin.getSkypeClient(jidFrom);
if (ucwaClient != null)
{
String node = JID.unescapeNode(message.getTo().getNode());
String sip = node;
if (node.indexOf("@") == -1) sip = node + "@" + ucwaClient.getDomain(); // use SIP domain, not XMPP domain in dev. Should be the same in production
Element element = message.getChildElement("x", "jabber:x:event");
if(element != null)
{
if (element.element("composing") != null)
{
}
if (element.element("idle") != null)
{
}
}
String text = message.getBody();
if (text != null && ! "".equals(text))
{
ucwaClient.sendMessage(sip, text);
}
}
}
}
public void deliverRawText(String data) // xmpp --> lync raw text TODO
{
Log.error( "deliverRawText\n" + data);
}
@Override public ConnectionConfiguration getConfiguration()
{
// TODO Here we run into an issue with the ConnectionConfiguration introduced in Openfire 4:
// it is not extensible in the sense that unforeseen connection types can be added.
// For now, null is returned, as this object is likely to be unused (its lifecycle is
// not managed by a ConnectionListener instance).
return null;
}
public Certificate[] getPeerCertificates() {
return null;
}
private String getDomain() {
return XMPPServer.getInstance().getServerInfo().getXMPPDomain();
}
}