package org.ifsoft.openlink.component; import java.net.*; import java.io.*; import java.util.*; import java.util.concurrent.*; import org.dom4j.Document; import org.dom4j.DocumentHelper; import org.dom4j.Element; import org.jivesoftware.openfire.http.HttpBindManager; import org.jivesoftware.openfire.SessionManager; import org.jivesoftware.openfire.session.LocalClientSession; import org.jivesoftware.openfire.session.Session; import org.jivesoftware.openfire.RoutingTable; import org.jivesoftware.openfire.XMPPServer; import org.jivesoftware.openfire.PrivateStorage; import org.jivesoftware.openfire.user.UserManager; import org.jivesoftware.openfire.user.User; import org.jivesoftware.openfire.vcard.*; import org.jivesoftware.openfire.cluster.ClusterManager; import org.jivesoftware.util.JiveGlobals; import org.jivesoftware.openfire.roster.Roster; import org.jivesoftware.openfire.roster.RosterItem; import org.jivesoftware.openfire.roster.RosterManager; import org.xmpp.component.Component; import org.xmpp.component.AbstractComponent; import org.xmpp.component.ComponentException; import org.xmpp.component.ComponentManager; import org.xmpp.component.ComponentManagerFactory; import org.xmpp.packet.IQ; import org.xmpp.packet.JID; import org.xmpp.packet.Message; import org.xmpp.packet.Packet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.ifsoft.openlink.*; import org.ifsoft.openlink.commands.*; import net.sf.json.*; public class OpenlinkComponent extends AbstractTSComponent implements OpenlinkConstants { private static final Logger Log = LoggerFactory.getLogger(OpenlinkComponent.class); private ComponentManager componentManager; private JID componentJID = null; private PrivateStorage privateStorage; private UserManager userManager; private RosterManager rosterManager; private SessionManager sessionManager; private OpenlinkCommandManager openlinkManger; public Map<String, OpenlinkUserInterest> openlinkInterests; public Map<String, OpenlinkUser> traderLyncUserTable; public Map<String, OpenlinkInterest> traderLyncInterests; public Map<String, OpenlinkInterest> callInterests; public Map<String, OpenlinkUser> userProfiles; public TelephoneNumberFormatter telephoneNumberFormatter; public Site site; private Vector<OpenlinkUser> sortedProfiles; private Timer timer = null; static public OpenlinkComponent self; //------------------------------------------------------- // // // //------------------------------------------------------- public OpenlinkComponent(Site site) { super(16, 1000, true); this.site = site; this.componentJID = new JID(getName() + "." + getDomain()); sortedProfiles = new Vector<OpenlinkUser>(); self = this; Log.info( "["+ site.getName() + "] OpenlinkComponent Initialised"); } public void componentEnable() { privateStorage = XMPPServer.getInstance().getPrivateStorage(); userManager = XMPPServer.getInstance().getUserManager(); rosterManager = XMPPServer.getInstance().getRosterManager(); sessionManager = XMPPServer.getInstance().getSessionManager(); componentManager = ComponentManagerFactory.getComponentManager(); openlinkManger = new OpenlinkCommandManager(); openlinkInterests = Collections.synchronizedMap( new HashMap<String, OpenlinkUserInterest>()); traderLyncUserTable = Collections.synchronizedMap( new HashMap<String, OpenlinkUser>()); traderLyncInterests = Collections.synchronizedMap( new HashMap<String, OpenlinkInterest>()); callInterests = Collections.synchronizedMap( new HashMap<String, OpenlinkInterest>()); userProfiles = Collections.synchronizedMap( new HashMap<String, OpenlinkUser>()); timer = new Timer(); Log.info( "["+ site.getName() + "] Creating telephoneNumberFormatter object"); setupTelephoneNumberFormatter(); Log.info( "["+ site.getName() + "] Creating user profiles"); getUserProfiles(); openlinkManger.addCommand(new GetProfiles(this)); openlinkManger.addCommand(new GetProfile(this)); openlinkManger.addCommand(new GetInterests(this)); openlinkManger.addCommand(new GetInterest(this)); openlinkManger.addCommand(new GetFeatures(this)); openlinkManger.addCommand(new MakeCall(this)); openlinkManger.addCommand(new IntercomCall(this)); openlinkManger.addCommand(new RequestAction(this)); openlinkManger.addCommand(new SetFeature(this)); openlinkManger.addCommand(new QueryFeatures(this)); openlinkManger.addCommand(new ManageVoiceBridge(this)); } public void componentDestroyed() { try { openlinkManger.stop(); if (timer != null) { timer.cancel(); timer = null; } } catch(Exception e) { Log.error(e.toString()); } } public void setupTelephoneNumberFormatter() { Log.info( "["+ site.getName() + "] setupTelephoneNumberFormatter"); try { String pname = site.getName().toLowerCase(); String country = JiveGlobals.getProperty(Properties.Openlink_PBX_COUNTRY_CODE + "." + pname, Locale.getDefault().getCountry()); String pbxAccessDigits = JiveGlobals.getProperty(Properties.Openlink_PBX_ACCESS_DIGITS + "." + pname, "9"); String areaCode = JiveGlobals.getProperty(Properties.Openlink_AREA_CODE + "." + pname, "0207"); String pbxNumberLength = JiveGlobals.getProperty(Properties.Openlink_PBX_NUMBER_LENGTH + "." + pname, "5"); telephoneNumberFormatter = new TelephoneNumberFormatter(new Locale("en", country)); telephoneNumberFormatter.setExtensionNumberLength(Integer.parseInt(pbxNumberLength)); telephoneNumberFormatter.setOutsideAccess(pbxAccessDigits); telephoneNumberFormatter.setAreaCode(areaCode); telephoneNumberFormatter.setLocale(new Locale("en", country)); } catch (Exception e) { Log.error( "["+ site.getName() + "] setupTelephoneNumberFormatter " + e); } } public String formatCanonicalNumber(String dialDigits) { String canonicalNumber = dialDigits; try { canonicalNumber = telephoneNumberFormatter.formatCanonicalNumber(dialDigits); } catch (Exception e) { Log.error( "["+ site.getName() + "] formatCanonicalNumber " + e); } return canonicalNumber; } public String formatDialableNumber(String cononicalNumber) { String dialableNumber = cononicalNumber; try { dialableNumber = telephoneNumberFormatter.formatDialableNumber(cononicalNumber); } catch (Exception e) { cononicalNumber = formatCanonicalNumber(cononicalNumber); try { dialableNumber = telephoneNumberFormatter.formatDialableNumber(cononicalNumber); } catch (Exception e1) { Log.error( "["+ site.getName() + "] formatDialableNumber " + e1); } } return dialableNumber; } //------------------------------------------------------- // // // //------------------------------------------------------- @Override public String getDescription() { return "TraderLynk Component"; } @Override public String getName() { return "traderlynk"; } @Override public String getDomain() { return XMPPServer.getInstance().getServerInfo().getXMPPDomain(); } @Override public void postComponentStart() { } @Override public void postComponentShutdown() { } public JID getComponentJID() { return new JID(getName() + "." + getDomain()); } public String getSiteName() { if (site == null) return ""; else return site.getName(); } public int getUserCount() { return traderLyncUserTable.values().size(); } public List<OpenlinkUser> getUsers(int startIndex, int numResults) { List<OpenlinkUser> profiles = new ArrayList<OpenlinkUser>(); int counter = 0; if (startIndex == 0 || sortedProfiles.size() == 0) { sortedProfiles = new Vector<OpenlinkUser>(traderLyncUserTable.values()); Collections.sort(sortedProfiles); } Iterator it = sortedProfiles.iterator(); while( it.hasNext() ) { OpenlinkUser traderLyncUser = (OpenlinkUser)it.next(); if (counter > (startIndex + numResults)) { break; } if (counter >= startIndex) { profiles.add(traderLyncUser); } counter++; } return profiles; } //------------------------------------------------------- // // // //------------------------------------------------------- public void interceptMessage(Message received) { //traderLyncLinkService.interceptMessage(received); } @Override protected void handleMessage(Message received) { Log.info("["+ site.getName() + "] handleMessage \n"+ received.toString()); } @Override protected void handleIQResult(IQ iq) { Log.info("["+ site.getName() + "] handleIQResult \n"+ iq.toString()); Element element = iq.getChildElement(); if (element != null) { String namespace = element.getNamespaceURI(); if("http://jabber.org/protocol/pubsub#owner".equals(namespace)) { Element subscriptions = element.element("subscriptions"); if (subscriptions != null) { String node = subscriptions.attributeValue("node"); Log.info("["+ site.getName() + "] handleIQResult found subscription node " + node); if (openlinkInterests.containsKey(node)) { Log.info("["+ site.getName() + "] handleIQResult found user interest " + node); OpenlinkUserInterest traderLyncUserInterest = openlinkInterests.get(node); for ( Iterator<Element> i = subscriptions.elementIterator( "subscription" ); i.hasNext(); ) { Element subscription = (Element) i.next(); JID jid = new JID(subscription.attributeValue("jid")); String sub = subscription.attributeValue("subscription"); OpenlinkSubscriber traderLyncSubscriber = traderLyncUserInterest.getSubscriber(jid); traderLyncSubscriber.setSubscription(sub); setSubscriberDetails(jid, traderLyncSubscriber); Log.info("["+ site.getName() + "] handleIQResult added subscriber " + jid); } } } } } } private void setSubscriberDetails(JID jid, OpenlinkSubscriber traderLyncSubscriber) { if (userManager.isRegisteredUser(jid.getNode())) { User user = null; try { user = userManager.getUser(jid.getNode()); } catch(Exception e) { } if (user != null) { //traderLyncSubscriber.setOnline(presenceManager.isAvailable(user)); traderLyncSubscriber.setName(user.getName()); traderLyncSubscriber.setJID(jid); // we need the full JID including resource to get session object } } } @Override protected void handleIQError(IQ iq) { String xml = iq.toString(); if (xml.indexOf("<create node=") == -1) Log.info("["+ site.getName() + "] handleIQError \n"+ iq.toString()); } @Override public IQ handleDiscoInfo(IQ iq) { JID jid = iq.getFrom(); Element child = iq.getChildElement(); String node = child.attributeValue("node"); IQ iq1 = IQ.createResultIQ(iq); iq1.setType(org.xmpp.packet.IQ.Type.result); iq1.setChildElement(iq.getChildElement().createCopy()); Element queryElement = iq1.getChildElement(); Element identity = queryElement.addElement("identity"); queryElement.addElement("feature").addAttribute("var",NAMESPACE_DISCO_INFO); queryElement.addElement("feature").addAttribute("var",NAMESPACE_XMPP_PING); identity.addAttribute("category", "component"); identity.addAttribute("name", "traderLync"); if (node == null) // Disco discovery of openlink { identity.addAttribute("type", "command-list"); queryElement.addElement("feature").addAttribute("var", "http://jabber.org/protocol/commands"); queryElement.addElement("feature").addAttribute("var", "http://xmpp.org/protocol/openlink:01:00:00"); queryElement.addElement("feature").addAttribute("var", "http://xmpp.org/protocol/openlink:01:00:00#tsc"); } else { // Disco discovery of Openlink command OpenlinkCommand command = openlinkManger.getCommand(node); if (command != null && command.hasPermission(jid)) { identity.addAttribute("type", "command-node"); queryElement.addElement("feature").addAttribute("var", "http://jabber.org/protocol/commands"); queryElement.addElement("feature").addAttribute("var", "http://xmpp.org/protocol/openlink:01:00:00"); } } //Log.info("["+ site.getName() + "] handleDiscoInfo "+ iq1.toString()); return iq1; } @Override public IQ handleDiscoItems(IQ iq) { JID jid = iq.getFrom(); Element child = iq.getChildElement(); String node = child.attributeValue("node"); IQ iq1 = IQ.createResultIQ(iq); iq1.setType(org.xmpp.packet.IQ.Type.result); iq1.setChildElement(iq.getChildElement().createCopy()); Element queryElement = iq1.getChildElement(); Element identity = queryElement.addElement("identity"); identity.addAttribute("category", "component"); identity.addAttribute("name", "openlink"); identity.addAttribute("type", "command-list"); if ("http://jabber.org/protocol/commands".equals(node)) { for (OpenlinkCommand command : openlinkManger.getCommands()) { // Only include commands that the sender can invoke (i.e. has enough permissions) if (command.hasPermission(jid)) { Element item = queryElement.addElement("item"); item.addAttribute("jid", componentJID.toString()); item.addAttribute("node", command.getCode()); item.addAttribute("name", command.getLabel()); } } } //Log.info("["+ site.getName() + "] handleDiscoItems "+ iq1.toString()); return iq1; } @Override public IQ handleIQGet(IQ iq) { return handleIQPacket(iq); } @Override public IQ handleIQSet(IQ iq) { return handleIQPacket(iq); } private IQ handleIQPacket(IQ iq) { Log.info("["+ site.getName() + "] handleIQPacket \n"+ iq.toString()); Element element = iq.getChildElement(); IQ iq1 = IQ.createResultIQ(iq); iq1.setType(org.xmpp.packet.IQ.Type.result); iq1.setChildElement(iq.getChildElement().createCopy()); if (element != null) { String namespace = element.getNamespaceURI(); if("http://jabber.org/protocol/commands".equals(namespace)) iq1 = openlinkManger.process(iq); } return iq1; } //------------------------------------------------------- // // // //------------------------------------------------------- public String makeCallDefault(Element newCommand, JID jid, String handset, String privacy, String autoHold, String dialDigits) { return makeCallDefault(newCommand, jid, handset, privacy, autoHold, dialDigits, null); } public String makeCallDefault(Element newCommand, JID jid, String handset, String privacy, String autoHold, String dialDigits, String callId) { Log.info( "["+ site.getName() + "] makeCallDefault "+ jid + " " + handset + " " + dialDigits + " " + privacy); String errorMessage = "No default profile found"; try { if (dialDigits != null && !"".equals(dialDigits)) { dialDigits = makeDialableNumber(dialDigits); if (dialDigits == null || "".equals(dialDigits)) { errorMessage = "Destination is not a dialable number"; return errorMessage; } } boolean foundDefaultProfile = false; String userName = jid.getNode(); Iterator<OpenlinkUser> it = traderLyncUserTable.values().iterator(); while( it.hasNext() ) { OpenlinkUser traderLyncUser = (OpenlinkUser)it.next(); if (userName.equals(traderLyncUser.getUserId()) && "true".equals(traderLyncUser.getDefault())) { foundDefaultProfile = true; handset = handset == null ? traderLyncUser.getHandsetNo() : handset; privacy = privacy == null ? traderLyncUser.getLastPrivacy() : privacy; autoHold = autoHold == null ? (traderLyncUser.autoHold() ? "true" : "false") : autoHold; if (traderLyncUser.getDefaultInterest() != null) { traderLyncUser.setWaitingInterest(null); errorMessage = makeOutgoingCall(traderLyncUser.getDefaultInterest().getUserInterests().get(traderLyncUser.getUserNo()), dialDigits, handset, callId); } else errorMessage = "no default interest found"; break; } } if (foundDefaultProfile == false) errorMessage = "no default profile found"; } catch(Exception e) { Log.error("makeCallDefault " + e); e.printStackTrace(); errorMessage = "Internal error - " + e.toString(); } return errorMessage; } public String makeCall(Element newCommand, String userInterest, String handset, String privacy, String autoHold, String dialDigits) { return makeCall(newCommand, userInterest, handset, privacy, autoHold, dialDigits, null); } public String makeCall(Element newCommand, String userInterest, String handset, String privacy, String autoHold, String dialDigits, String callId) { Log.info( "["+ site.getName() + "] makeCall "+ userInterest + " " + dialDigits + " " + callId); String errorMessage = "Interest not found"; try { if (openlinkInterests.containsKey(userInterest)) { OpenlinkUserInterest traderLyncUserInterest = openlinkInterests.get(userInterest); OpenlinkUser traderLyncUser = traderLyncUserInterest.getUser(); handset = handset == null ? traderLyncUser.getHandsetNo() : handset; privacy = privacy == null ? traderLyncUser.getLastPrivacy() : privacy; if ("D".equals(traderLyncUserInterest.getInterest().getInterestType())) { if (dialDigits != null && !"".equals(dialDigits)) { dialDigits = makeDialableNumber(dialDigits); if (dialDigits == null || "".equals(dialDigits)) { errorMessage = "Destination is not a dialable number"; return errorMessage; } } errorMessage = makeOutgoingCall(traderLyncUserInterest, dialDigits, handset, callId); } else if ("L".equals(traderLyncUserInterest.getInterest().getInterestType())) { String digits = traderLyncUserInterest.getInterest().getInterestValue(); if (digits.startsWith("tel:")) digits = digits.substring(4); errorMessage = makeOutgoingCall(traderLyncUserInterest, digits, handset, callId); } } } catch(Exception e) { Log.error("makeCall " + e); e.printStackTrace(); errorMessage = "Internal error - " + e.toString(); } return errorMessage; } private String makeOutgoingCall(OpenlinkUserInterest traderLyncUserInterest, String dialDigits, String handset, String callId) { Log.info( "["+ site.getName() + "] makeOutgoingCall "+ traderLyncUserInterest.getInterest().getInterestValue() + " " + dialDigits + " " + callId); String deviceNo = traderLyncUserInterest.getUser().getDeviceNo(); String username = traderLyncUserInterest.getUser().getUserId(); String errorMessage = null; try { if (callId == null) callId = username + "-" + System.currentTimeMillis(); errorMessage = null; //sendSkype4BRequest(traderLyncUserInterest, "startPhoneAudio", username, dialDigits, callId, handset); if (errorMessage == null) { callInterests.put(callId, traderLyncUserInterest.getInterest()); if (deviceNo != null) { //connectHandsetLine(deviceNo, callId); } outgoingCallNotification(username, callId, true, dialDigits, traderLyncUserInterest.getInterest().getInterestLabel()); } } catch(Exception e) { Log.error("makeOutgoingCall ", e); errorMessage = "Internal error - " + e.toString(); } return errorMessage; } public String intercomCall(Element newCommand, String profileID, JID to, String groupID) { Log.info( "["+ site.getName() + "] intercomCall "+ profileID + " -> " + to + " => " + groupID); String errorMessage = null; try { OpenlinkUser fromUser = getOpenlinkProfile(profileID); if (groupID == null) { OpenlinkUser toUser = getOpenlinkUser(to); //traderLyncLinkService.platformIntercomCall(fromUser.getDeviceNo(), toUser.getUserNo()); } else { //traderLyncLinkService.groupIntercomCall(fromUser.getDeviceNo(), groupID); } //errorMessage = waitForFirstEvent(newCommand, fromUser, true, "0"); } catch(Exception e) { Log.error("["+ site.getName() + "] intercomCall " + e); e.printStackTrace(); errorMessage = "Internal error - " + e.toString(); } return errorMessage; } private boolean isValidAction(OpenlinkCall traderLyncCall, String validAction) { boolean valid = false; Iterator it4 = traderLyncCall.getValidActions().iterator(); while( it4.hasNext() ) { String action = (String)it4.next(); if (action.equals(validAction)) { valid = true; break; } } return valid; } public String processUserAction(Element command, String userInterest, String action, String callID, String value1) { Log.info( "["+ site.getName() + "] processUserAction " + userInterest + " " + action + " " + callID + " " + value1); String errorMessage = null; try { if (openlinkInterests.containsKey(userInterest)) { OpenlinkUserInterest traderLyncUserInterest = openlinkInterests.get(userInterest); OpenlinkInterest traderLyncInterest = traderLyncUserInterest.getInterest(); OpenlinkUser traderLyncUser = traderLyncUserInterest.getUser(); OpenlinkCall traderLyncCall = traderLyncUserInterest.getCallById(callID); if (traderLyncCall != null) { traderLyncCall.published = true; Log.info( "[" + site.getName() + "] processUserAction"); if (isValidAction(traderLyncCall, action)) { if ("AnswerCall".equals(action) || "JoinCall".equals(action) || "RetrieveCall".equals(action)) { if (traderLyncUser.getDeviceNo() != null && !"0.0.0.0".equals(traderLyncUser.getDeviceNo())) { if ("D".equals(traderLyncInterest.getInterestType())) { errorMessage = null; //sendSkype4BRequest(traderLyncUserInterest, "resumePhoneAudio", traderLyncUser.getUserNo(), null, callID, null); if (errorMessage == null) { Iterator it = traderLyncInterest.getUserInterests().values().iterator(); while( it.hasNext() ) { OpenlinkUserInterest eachInterest = (OpenlinkUserInterest)it.next(); if (eachInterest.getUser().getUserNo().equals(traderLyncUser.getUserNo())) { eachInterest.handleCallConnected(callID); } else { eachInterest.handleCallBusy(callID); } } publishOpenlinkCallEvent(traderLyncInterest); } } else if ("L".equals(traderLyncInterest.getInterestType())) { makeCall(null, userInterest, traderLyncUser.getHandsetNo(), null, null, userInterest); } if (traderLyncUser.autoPrivate()) { //Thread.sleep(500); //traderLyncLinkService.privateCall(traderLyncUser.getDeviceNo(), traderLyncUser.getHandsetNo(), "Y"); } } else { errorMessage = "User device not online"; } } if ("ClearConnection".equals(action)) { errorMessage = null; //sendSkype4BRequest(traderLyncUserInterest, "stopPhoneAudio", traderLyncUser.getUserNo(), null, callID, null); if (errorMessage == null) { Iterator it = traderLyncInterest.getUserInterests().values().iterator(); while( it.hasNext() ) { OpenlinkUserInterest eachInterest = (OpenlinkUserInterest)it.next(); eachInterest.handleConnectionCleared(callID); } publishOpenlinkCallEvent(traderLyncInterest); } deleteEvents(traderLyncInterest, callID); } if ("PrivateCall".equals(action)) { //traderLyncLinkService.privateCall(traderLyncCall.getConsole(), traderLyncCall.getHandset(), "Y"); } if ("PublicCall".equals(action)) { //traderLyncLinkService.privateCall(traderLyncCall.getConsole(), traderLyncCall.getHandset(), "N"); } if ("SendDigits".equals(action)) { value1 = makeDialableNumber(value1); if (value1 == null || "".equals(value1)) { errorMessage = "A dialable number is required for SendDigits"; } else { //traderLyncLinkService.dialDigits(traderLyncCall.getLine(), value1); } } if ("SendDigit".equals(action)) { if (value1 != null && value1.length() > 0) { //traderLyncLinkService.dialDigit(traderLyncCall.getConsole(), traderLyncCall.getHandset(), value1.substring(0, 1)); //traderLyncLinkService.publishOpenlinkUserCallEvent(traderLyncUserInterest); // no event, so we force pub-sub of current event } else errorMessage = "A dialable digit must be provided for SendDigit action"; } if ("ClearCall".equals(action)) { errorMessage = null; //sendSkype4BRequest(traderLyncUserInterest, "stopPhoneAudio", traderLyncUser.getUserNo(), null, callID, null); if (errorMessage == null) { Iterator it = traderLyncInterest.getUserInterests().values().iterator(); while( it.hasNext() ) { OpenlinkUserInterest eachInterest = (OpenlinkUserInterest)it.next(); eachInterest.handleConnectionCleared(callID); } publishOpenlinkCallEvent(traderLyncInterest); } deleteEvents(traderLyncInterest, callID); } if ("ConferenceCall".equals(action)) { //traderLyncLinkService.joinELC(traderLyncCall.getConsole()); } if ("ClearConference".equals(action)) { //traderLyncLinkService.clearELC(traderLyncCall.getConsole()); //traderLyncLinkService.clearLine(traderLyncCall.getLine()); } if ("IntercomTransfer".equals(action)) { try { OpenlinkUser newOpenlinkUser = getOpenlinkUser(new JID(value1)); if (newOpenlinkUser != null) { //traderLyncLinkService.traderLyncTransferCall(traderLyncCall.getConsole(), traderLyncCall.getHandset(), traderLyncUser.getUserNo()); } else errorMessage = value1 + " is either not a valid user or logged into a device"; } catch (Exception e) { errorMessage = value1 + " is not a valid user identity"; } } if ("ConsultationCall".equals(action)) { if (!traderLyncCall.transferFlag) { value1 = makeDialableNumber(value1); if (value1 == null || "".equals(value1)) { errorMessage = "A dialable number must be provided for ConsultationCall action"; } else { traderLyncCall.previousCalledNumber = traderLyncCall.proceedingDigits; // store old called number. traderLyncCall.previousCalledLabel = traderLyncCall.proceedingDigitsLabel; //traderLyncLinkService.transferCall(traderLyncCall.getConsole(), traderLyncCall.getHandset(), traderLyncCall.getLine(), value1); traderLyncCall.transferFlag = true; } } else { //traderLyncLinkService.ringRecall(traderLyncCall.getConsole(), traderLyncCall.getHandset()); // terminate current ConsultationCall traderLyncCall.transferFlag = false; if (traderLyncCall.previousCalledNumber != null) { Iterator<OpenlinkUserInterest> it3 = traderLyncUserInterest.getInterest().getUserInterests().values().iterator(); while( it3.hasNext() ) { OpenlinkUserInterest theUserInterest = (OpenlinkUserInterest)it3.next(); OpenlinkCall theCall = theUserInterest.getCallByLine(traderLyncCall.getLine()); if (theCall != null) { theCall.proceedingDigits = traderLyncCall.previousCalledNumber; theCall.proceedingDigitsLabel = traderLyncCall.previousCalledLabel; } } } } traderLyncCall.setValidActions(); //traderLyncLinkService.publishOpenlinkUserCallEvent(traderLyncUserInterest); // no event, so we force pub-sub of current event } if ("TransferCall".equals(action)) { if (traderLyncCall.transferFlag) { //traderLyncLinkService.clearCall(traderLyncCall.getConsole(), traderLyncCall.getHandset()); traderLyncCall.transferFlag = false; } else errorMessage = "ConsultationCall must be done before TransferCall"; } if ("SingleStepTransfer".equals(action)) { value1 = makeDialableNumber(value1); if (value1 == null || "".equals(value1)) { errorMessage = "A dialable number must be provided for a SingleStepTransfer action"; } else { //traderLyncLinkService.transferCall(traderLyncCall.getConsole(), traderLyncCall.getHandset(), traderLyncCall.getLine(), value1); //traderLyncLinkService.clearCall(traderLyncCall.getConsole(), traderLyncCall.getHandset()); } } if ("AddThirdParty".equals(action)) { value1 = makeDialableNumber(value1); if (value1 == null || "".equals(value1)) { errorMessage = "A dialable number must be provided for a AddThirdParty action"; } else { //errorMessage = traderLyncLinkService.addExternalCall(traderLyncCall.getLine(), value1); } } if ("RemoveThirdParty".equals(action)) { //errorMessage = traderLyncLinkService.removeExternalCall(traderLyncCall.getLine(), makeDialableNumber(value1)); } if ("HoldCall".equals(action)) { if (traderLyncUser.getDeviceNo() != null && !"0.0.0.0".equals(traderLyncUser.getDeviceNo())) { errorMessage = null; //sendSkype4BRequest(traderLyncUserInterest, "holdPhoneAudio", traderLyncUser.getUserNo(), null, callID, null); if (errorMessage == null) { Iterator it = traderLyncInterest.getUserInterests().values().iterator(); while( it.hasNext() ) { OpenlinkUserInterest eachInterest = (OpenlinkUserInterest)it.next(); eachInterest.handleCallHeld(callID); } publishOpenlinkCallEvent(traderLyncInterest); } } else { errorMessage = "User device not online"; } } if ("StartVoiceDrop".equals(action)) { //VMessage message = getVMId(traderLyncUser, value1); //if (message == null) //{ // errorMessage = "A valid voice message feature Id must be provided for a StartVoiceDrop action"; //} else { //String exten = traderLyncVmsService.getVMExtenToDial(traderLyncUser, message.getId(), message.getName()); //errorMessage = traderLyncLinkService.addExternalCall(traderLyncCall.getLine(), makeDialableNumber(exten)); //} } if ("StopVoiceDrop".equals(action)) { //Message message = getVMId(traderLyncUser, value1); //if (message == null) //{ // errorMessage = "A valid voice message feature Id must be provided for a StartVoiceDrop action"; //} else { //String exten = traderLyncVmsService.getVMExtenToDial(traderLyncUser, message.getId(), message.getName()); //errorMessage = traderLyncLinkService.removeExternalCall(traderLyncCall.getLine(), makeDialableNumber(exten)); //} } } else errorMessage = "Action is not valid"; } else errorMessage = "Call id not found"; } else errorMessage = "Interest not found"; } catch(Exception e) { Log.error("["+ site.getName() + "] processUserAction " + e); e.printStackTrace(); errorMessage = "Request Action internal error - " + e.toString(); } if (errorMessage != null && command != null) { Element note = command.addElement("note"); note.addAttribute("type", "error"); note.setText("Request Action - " + errorMessage); } return errorMessage; } public String setFeature(Element newCommand, String profileID, String featureID, String value1, String value2) { Log.info( "["+ site.getName() + "] setFeature " + profileID + " " + featureID + " " + value1 + " " + value2); String errorMessage = null; try { if (value1 != null && value1.length() > 0) { OpenlinkUser traderLyncUser = getOpenlinkProfile(profileID); if (traderLyncUser != null) { if ("hs_1".equals(featureID)) { if (validateTrueFalse(value1)) traderLyncUser.setHandsetNo("true".equals(value1.toLowerCase()) ? "1" : "2"); else errorMessage = "value1 is not true or false"; } else if ("hs_2".equals(featureID)) { if (validateTrueFalse(value1)) traderLyncUser.setHandsetNo("true".equals(value1.toLowerCase()) ? "2" : "1"); else errorMessage = "value1 is not true or false"; } else if ("priv_1".equals(featureID)) { if (validateTrueFalse(value1)) traderLyncUser.setAutoPrivate("true".equals(value1.toLowerCase())); else errorMessage = "value1 is not true or false"; } else if ("hold_1".equals(featureID)) { if (validateTrueFalse(value1)) traderLyncUser.setAutoHold("true".equals(value1.toLowerCase())); else errorMessage = "value1 is not true or false"; } else if ("callback_1".equals(featureID)) { if (validateTrueFalse(value1)) { if ("true".equals(value1.toLowerCase())) { if (value2 != null && !"".equals(value2)) { String dialableNumber = makeDialableNumber(value2); if (dialableNumber != null && !"".equals(dialableNumber)) { traderLyncUser.setCallback(dialableNumber); OpenlinkCallback traderLyncCallback = null; //traderLyncLinkService.allocateCallback(traderLyncUser); if (traderLyncCallback == null) errorMessage = "unable to allocate a virtual turret"; } else errorMessage = "value2 is not a dialable number"; } else { if (traderLyncUser.getCallback() != null) { OpenlinkCallback traderLyncCallback = null; //traderLyncLinkService.allocateCallback(traderLyncUser); if (traderLyncCallback == null) errorMessage = "unable to allocate a callback"; } else errorMessage = "calback destination is missing"; } } else { //traderLyncLinkService.freeCallback(traderLyncUser.getUserNo()); traderLyncUser.setPhoneCallback(null); } } else errorMessage = "value1 is not true or false"; } else if ("fwd_1".equals(featureID)) // call forward { if (openlinkInterests.containsKey(value1)) // value is interest id { OpenlinkUserInterest traderLyncUserInterest = openlinkInterests.get(value1); if (traderLyncUser.getUserNo().equals(traderLyncUser.getUserNo())) { if ("D".equals(traderLyncUserInterest.getInterest().getInterestType())) { String pname = site.getName().toLowerCase(); String pbxFWDCodePrefix = JiveGlobals.getProperty(Properties.Openlink_PBX_FWD_CODE_PREFIX + "." + pname, "*41"); String pbxFWDCodeSuffix = JiveGlobals.getProperty(Properties.Openlink_PBX_FWD_CODE_SUFFIX + "." + pname, ""); String pbxFWDCodeCancel = JiveGlobals.getProperty(Properties.Openlink_PBX_FWD_CODE_CANCEL + "." + pname, "*41"); String dialDigits = null; if (value2 == null || "".equals(value2)) { dialDigits = pbxFWDCodeCancel; errorMessage = doCallForward(dialDigits, traderLyncUserInterest, newCommand); if (errorMessage == null) { Iterator<OpenlinkUserInterest> iter2 = traderLyncUserInterest.getInterest().getUserInterests().values().iterator(); while( iter2.hasNext() ) { OpenlinkUserInterest theUserInterest = (OpenlinkUserInterest)iter2.next(); theUserInterest.setCallFWD("false"); } traderLyncUser.setLastCallForward(""); } } else { String dialableNumber = makeDialableNumber(value2); if (dialableNumber != null && !"".equals(dialableNumber)) { dialDigits = pbxFWDCodePrefix + dialableNumber + pbxFWDCodeSuffix; errorMessage = doCallForward(dialDigits, traderLyncUserInterest, newCommand); if (errorMessage == null) { Iterator<OpenlinkUserInterest> iter2 = traderLyncUserInterest.getInterest().getUserInterests().values().iterator(); while( iter2.hasNext() ) { OpenlinkUserInterest theUserInterest = (OpenlinkUserInterest)iter2.next(); theUserInterest.setCallFWD("true"); theUserInterest.setCallFWDDigits(value2); } traderLyncUser.setLastCallForwardInterest(value1); traderLyncUser.setLastCallForward(value2); } } else errorMessage = "value2 is not a dialable number"; } } else errorMessage = "CallForward requires a directory number interest"; } else errorMessage = "Interest does not belong to this profile"; } else errorMessage = "Interest not found"; } else errorMessage = "Feature not found"; } else errorMessage = "Profile not found"; } else errorMessage = "Input1 is missing"; } catch(Exception e) { Log.error("["+ site.getName() + "] setFeature " + e); e.printStackTrace(); errorMessage = "Internal error - " + e.toString(); } return errorMessage; } private String doCallForward(String dialDigits, OpenlinkUserInterest traderLyncUserInterest, Element newCommand) { String errorMessage = null; //traderLyncUserInterest.getUser().selectCallset(this, traderLyncUserInterest.getInterest().getCallset(), traderLyncUserInterest.getUser().getHandsetNo(), "true", "true", dialDigits); //errorMessage = waitForFirstEvent(newCommand, traderLyncUserInterest.getUser(), false, traderLyncUserInterest.getUser().getHandsetNo()); //traderLyncLinkService.clearCall(traderLyncUserInterest.getUser().getDeviceNo(), traderLyncUserInterest.getUser().getHandsetNo()); return errorMessage; } public String manageVoiceBridge(Element newCommand, JID userJID, List<Object[]> actions) { Log.info( "["+ site.getName() + "] manageVoiceMessage " + userJID + " "); String errorMessage = ""; List<String> actionList = new ArrayList<String>(); try { if (actions != null && actions.size() > 0) { Iterator it = actions.iterator(); while( it.hasNext() ) { Object[] action = (Object[])it.next(); String name = (String) action[0]; String value1 = (String) action[1]; String value2 = (String) action[2]; String thisErrorMessage = null; //traderLyncLinkService.manageCallParticipant(userJID, value1, name, value2); if (thisErrorMessage == null) { if ("MakeCall".equalsIgnoreCase(name)) { actionList.add(value1); } } else { errorMessage = errorMessage + thisErrorMessage + "; "; } } if (actionList.size() > 0) { //traderLyncLinkService.handlePostBridge(actionList); } } else errorMessage = "Voice message features are missing"; } catch(Exception e) { Log.error("["+ site.getName() + "] manageVoiceBridge " + e); e.printStackTrace(); errorMessage = "Internal error - " + e.toString(); } return errorMessage.length() == 0 ? null : errorMessage; } public String manageVoiceMessage(Element newCommand, String profileID, String featureId, String action, String value1) { Log.info( "["+ site.getName() + "] manageVoiceMessage " + profileID + " " + featureId + " " + action + " " + value1); String errorMessage = null; try { if (action != null && action.length() > 0) { OpenlinkUser traderLyncUser = getOpenlinkProfile(profileID); if (traderLyncUser != null) { action = action.toLowerCase(); if ("record".equals(action)) { } else if ("edit".equals(action)) { } else if ("playback".equals(action)) { } else if ("delete".equals(action)) { } else if ("save".equals(action)) { } else if ("archive".equals(action)) { } else errorMessage = "Action not supported"; } else errorMessage = "Profile not found"; } else errorMessage = "Action is missing"; } catch(Exception e) { Log.error("["+ site.getName() + "] manageVoiceMessage " + e); e.printStackTrace(); errorMessage = "Internal error - " + e.toString(); } return errorMessage; } private void addVoiceMessageExtension(Element newCommand, String exten, OpenlinkUser traderLyncUser, String msgId) { Element iodata = newCommand.addElement("iodata", "urn:xmpp:tmp:io-data"); iodata.addAttribute("type","output"); Element devicestatus = iodata.addElement("out").addElement("devicestatus", "http://xmpp.org/protocol/openlink:01:00:00#device-status"); devicestatus.addElement("profile").setText(traderLyncUser.getProfileName()); Element feature = devicestatus.addElement("features").addElement("feature").addAttribute("id", msgId); Element voicemessage = feature.addElement("voicemessage").addAttribute("xmlns", "http://xmpp.org/protocol/openlink:01:00:00/features#voice-message"); voicemessage.addElement("msglen"); voicemessage.addElement("status").setText("ok"); voicemessage.addElement("statusdescriptor"); voicemessage.addElement("state"); if (exten == null || exten.length() == 0) voicemessage.addElement("exten"); else voicemessage.addElement("exten").setText(exten); } //------------------------------------------------------- // // // //------------------------------------------------------- public List<OpenlinkUser> getOpenlinkProfiles(JID jid) { List<OpenlinkUser> traderLyncUsers = new ArrayList(); String userName = jid.getNode(); if (jid.getDomain().indexOf(getDomain()) > -1) { Iterator<OpenlinkUser> it = traderLyncUserTable.values().iterator(); while( it.hasNext() ) { OpenlinkUser traderLyncUser = (OpenlinkUser)it.next(); if (userName.equals(traderLyncUser.getUserId())) { traderLyncUsers.add(traderLyncUser); } } } return traderLyncUsers; } public OpenlinkUser getOpenlinkUser(JID jid) { return getOpenlinkUser(jid.getNode()); } public OpenlinkUser getOpenlinkUser(String userName) { Iterator<OpenlinkUser> it = traderLyncUserTable.values().iterator(); while( it.hasNext() ) { OpenlinkUser traderLyncUser = (OpenlinkUser)it.next(); if (userName.equals(traderLyncUser.getUserId()) && !"0.0.0.0".equals(traderLyncUser.getDeviceNo())) { return traderLyncUser; } } return null; } public OpenlinkUser getOpenlinkProfile(String profileID) { OpenlinkUser traderLyncUser = null; if (traderLyncUserTable.containsKey(profileID)) { traderLyncUser = traderLyncUserTable.get(profileID); } return traderLyncUser; } public OpenlinkUserInterest getOpenlinkInterest(String userInterest) { OpenlinkUserInterest traderLyncUserInterest = null; if (openlinkInterests.containsKey(userInterest)) { traderLyncUserInterest = openlinkInterests.get(userInterest); } return traderLyncUserInterest; } public String getSiteID() { return String.valueOf(site.getSiteID()); } public void sendPacket(Packet packet) { try { componentManager.sendPacket(this, packet); } catch (Exception e) { Log.error("Exception occured while sending packet." + e); } } public void getInterestSubscriptions() { Log.info( "["+ site.getName() + "] getInterestSubscriptions"); try { Iterator<OpenlinkUser> iter = traderLyncUserTable.values().iterator(); while(iter.hasNext()) { OpenlinkUser traderLyncUser = (OpenlinkUser)iter.next(); Iterator<OpenlinkInterest> iter2 = traderLyncUser.getInterests().values().iterator(); while( iter2.hasNext() ) { OpenlinkInterest traderLyncInterest = (OpenlinkInterest)iter2.next(); getInterestSubscriptions(traderLyncInterest, traderLyncUser.getUserNo()); } } } catch(Exception e) { Log.error("["+ site.getName() + "] getInterestSubscriptions " + e); } } //------------------------------------------------------- // // // //------------------------------------------------------- public boolean validateTrueFalse(String value1) { boolean valid = false; String flag = value1.toLowerCase(); if ("true".equals(flag) || "false".equals(flag)) { valid = true; } return valid; } public String makeDialableNumber(String digits) { String dialableNumber = null; if ((digits != null && !"".equals(digits)) || digits.startsWith("sip:") || digits.startsWith("tel:")) { dialableNumber = digits; /* String cononicalNumber = formatCanonicalNumber(convertAlpha(digits)); if (cononicalNumber != null && !"".equals(cononicalNumber)) { dialableNumber = formatDialableNumber(cononicalNumber); } */ Log.info( "["+ site.getName() + "] makeDialableNumber " + digits + "=>" + dialableNumber); } return dialableNumber; } private String convertAlpha(String input) { int inputlength = input.length(); input = input.toLowerCase(); String phonenumber = ""; for (int i = 0; i < inputlength; i++) { int character = input.charAt(i); switch(character) { case '+': phonenumber+="+";break; case '*': phonenumber+="*";break; case '#': phonenumber+="#";break; case '0': phonenumber+="0";break; case '1': phonenumber+="1";break; case '2': phonenumber+="2";break; case '3': phonenumber+="3";break; case '4': phonenumber+="4";break; case '5': phonenumber+="5";break; case '6': phonenumber+="6";break; case '7': phonenumber+="7";break; case '8': phonenumber+="8";break; case '9': phonenumber+="9";break; case 'a': case 'b': case 'c': phonenumber+="2";break; case 'd': case 'e': case 'f': phonenumber+="3";break; case 'g': case 'h': case 'i': phonenumber+="4";break; case 'j': case 'k': case 'l': phonenumber+="5";break; case 'm': case 'n': case 'o': phonenumber+="6";break; case 'p': case 'q': case 'r': case 's': phonenumber+="7";break; case 't': case 'u': case 'v': phonenumber+="8";break; case 'w': case 'x': case 'y': case 'z': phonenumber+="9";break; } } return (phonenumber); } public boolean isComponent(JID jid) { final RoutingTable routingTable = XMPPServer.getInstance().getRoutingTable(); if (routingTable != null) { return routingTable.hasComponentRoute(jid); } return false; } public void setRefreshCacheInterval() { Log.info( "["+ site.getName() + "] setRefreshCacheInterval "); try { } catch (Exception e) { Log.error("["+ site.getName() + "] setRefreshCacheInterval " + e); } } //------------------------------------------------------- // // // //------------------------------------------------------- private void getUserProfiles() { try { Collection<User> users = userManager.getUsers(); Iterator it = users.iterator(); while( it.hasNext() ) { User user = (User)it.next(); String userEmail = user.getEmail(); String userPhone = user.getProperties().get("wirelynk.phone.other") != null ? user.getProperties().get("wirelynk.phone.other") : (userEmail != null && userEmail.indexOf(";fsu=") > -1 ? userEmail : ""); String userId = user.getUsername(); //getUserNo(user.getEmail()); if(userId != null && userId.equals(JiveGlobals.getProperty("wirelynk.default.username", "wirelynk")) == false && userPhone.indexOf(";wl=") == -1 && userPhone.indexOf(";ddi=") == -1 && userPhone.indexOf(";lid=") == -1) { Log.info( "["+ site.getName() + "] getUserProfiles - user profile " + user.getUsername()); OpenlinkUser traderLyncUser = new OpenlinkUser(); traderLyncUser.setUserName(user.getName()); traderLyncUser.setUserId(userId); traderLyncUser.setUserNo(user.getUsername()); traderLyncUser.setSiteName(getName()); traderLyncUser.setSiteID(1); traderLyncUser.setHandsetNo("1"); //traderLyncUser.setDeviceType("wirelynk"); createInterest(traderLyncUser, userId, "D", user.getName(), "true", userId); if (userProfiles.containsKey(userId) == false) { traderLyncUser.setDefault("true"); userProfiles.put(userId, traderLyncUser); } traderLyncUserTable.put(traderLyncUser.getUserNo(), traderLyncUser); Roster roster = rosterManager.getRoster(user.getUsername()); List<RosterItem> rosterItems = new ArrayList<RosterItem>(roster.getRosterItems()); Collections.sort(rosterItems, new RosterItemComparator()); for (RosterItem rosterItem : rosterItems) { try { String interestNode = rosterItem.getJid().getNode(); User itemUser = userManager.getUser(interestNode); String itemEmail = itemUser.getEmail(); String phone = itemUser.getProperties().get("wirelynk.phone.other") != null ? itemUser.getProperties().get("wirelynk.phone.other") : (itemEmail != null && itemEmail.indexOf(";fsu=") > -1 ? itemEmail : ""); if (phone.indexOf(";wl=") > -1 && (phone.indexOf(";ddi=") > -1 || phone.indexOf(";lid=") > -1) && userId.equals(interestNode) == false && interestNode.equals(JiveGlobals.getProperty("wirelynk.default.username", "wirelynk")) == false) { createInterest(traderLyncUser, interestNode, "L", rosterItem.getNickname(), "false", phone); } } catch (Exception e) { Log.error( "["+ site.getName() + "] " + "Error in getProfiles ",e); } } createPubsubNode(user.getUsername() + "@" + getDomain()); } } } catch (Exception e) { Log.error( "["+ site.getName() + "] " + "Error in getProfiles ",e); } } private void createInterest(OpenlinkUser traderLyncUser, String interestNode, String interestType, String nickname, String defaultInterest, String interestValue) { Log.info( "["+ site.getName() + "] createInterest " + interestNode); OpenlinkInterest traderLyncInterest = null; if (traderLyncInterests.containsKey(interestNode)) { traderLyncInterest = traderLyncInterests.get(interestNode); } else { traderLyncInterest = new OpenlinkInterest(interestNode); } traderLyncInterest.setInterestType(interestType); traderLyncInterest.setSiteName(getName()); traderLyncInterest.setInterestLabel(nickname); traderLyncInterest.setInterestValue(interestValue); traderLyncInterests.put(interestNode, traderLyncInterest); if (defaultInterest.equals("true")) { traderLyncUser.setDefaultInterest(traderLyncInterest); } OpenlinkUserInterest traderLyncUserInterest = traderLyncInterest.addUserInterest(traderLyncUser, defaultInterest); traderLyncUser.addInterest(traderLyncInterest); openlinkInterests.put(interestNode + traderLyncUser.getUserNo(), traderLyncUserInterest); createPubsubNode(traderLyncInterest.getInterestId() + traderLyncUser.getUserNo()); getInterestSubscriptions(traderLyncInterest, traderLyncUser.getUserNo()); } //------------------------------------------------------- // // // //------------------------------------------------------- private String getUserNo(String email) { if (email != null) { int pos = email.indexOf("@"); if ( pos > -1) { return email.substring(0, pos); } else { return email; } } else return null; } private String getTelVoiceNumber(Element vCard, String work, String voice) { String telVoiceNumber = null; for ( Iterator i = vCard.elementIterator( "TEL" ); i.hasNext(); ) { Element tel = (Element) i.next(); //Log.info( "["+ site.getName() + "] getTelVoiceNumber - tel " + tel.asXML()); if (tel.element(work) != null && tel.element(voice) != null) { Element number = tel.element("NUMBER"); if (number != null) { //Log.info( "["+ site.getName() + "] getTelVoiceNumber - number " + number.getText()); telVoiceNumber = number.getText(); break; } } } return telVoiceNumber; } //------------------------------------------------------- // // // //------------------------------------------------------- public void outgoingCallNotification(String requester, String callId, boolean connected, String dialDigits, String label) { Log.info( "["+ site.getName() + "] outgoingCallNotification " + requester + " " + callId); try { if (callInterests.containsKey(callId)) { OpenlinkInterest callInterest = callInterests.get(callId); Iterator<OpenlinkUserInterest> it4 = callInterest.getUserInterests().values().iterator(); while( it4.hasNext() ) { OpenlinkUserInterest userInterest = (OpenlinkUserInterest)it4.next(); if (connected) { if (requester.equals(userInterest.getUser().getUserNo())) { userInterest.handleCallOutgoing("CallOriginated", callId, dialDigits, label); userInterest.handleCallOutgoing("CallDelivered", callId, dialDigits, label); userInterest.handleCallOutgoing("CallEstablished", callId, dialDigits, label); } else { userInterest.handleCallOutgoing("CallBusy", callId, dialDigits, label); } } else { userInterest.handleConnectionCleared(callId); } } publishOpenlinkCallEvent(callInterest); if (!connected) { //deleteEvents(callInterest, callId); } } } catch (Exception e) { Log.error( "["+ site.getName() + "] " + "Error in outgoingCallNotification ", e); } } /* public void notifyConferenceMonitors(ConferenceEvent conferenceEvent) { if ("IncomingCallsConference".equals(conferenceEvent.getConferenceId()) == false) { Log.info( "["+ site.getName() + "] notifyConferenceMonitors " + conferenceEvent.toString()); try { if (conferenceEvent.equals(ConferenceEvent.MEMBER_LEFT) || conferenceEvent.equals(ConferenceEvent.MEMBER_JOINED)) { Log.info( "["+ site.getName() + "] notifyConferenceMonitors looking for call " + conferenceEvent.getCallId() + " " + conferenceEvent.getMemberCount()); CallHandler callHandler = CallHandler.findCall(conferenceEvent.getCallId()); if (callHandler != null) { Log.info( "["+ site.getName() + "] notifyConferenceMonitors found call handler " + callHandler); CallParticipant callParticipant = callHandler.getCallParticipant(); if (callParticipant != null && callParticipant.getDeviceAddress() != null) { Log.info( "["+ site.getName() + "] notifyConferenceMonitors found device " + callParticipant.getDeviceAddress()); Iterator<OpenlinkUser> iter = traderLyncUserTable.values().iterator(); while(iter.hasNext()) { OpenlinkUser traderLyncUser = (OpenlinkUser)iter.next(); if (callParticipant.getDeviceAddress().equals(traderLyncUser.getDeviceNo())) { if (conferenceEvent.equals(ConferenceEvent.MEMBER_JOINED)) { Log.info( "["+ site.getName() + "] notifyConferenceMonitors setting device callid " + traderLyncUser.getUserNo() + " " + conferenceEvent.getCallId()); traderLyncUser.setHandsetCallId(conferenceEvent.getCallId()); } else { Log.info( "["+ site.getName() + "] notifyConferenceMonitors resetting device callid " + traderLyncUser.getUserNo() + " " + conferenceEvent.getCallId()); traderLyncUser.setHandsetCallId(null); } break; } } // set call state if (callInterests.containsKey(conferenceEvent.getConferenceId())) { // conf id is our far party call id OpenlinkInterest callInterest = callInterests.get(conferenceEvent.getConferenceId()); Log.info( "["+ site.getName() + "] notifyConferenceMonitors found far party " + callInterest.getInterestValue()); Iterator it = callInterest.getUserInterests().values().iterator(); while( it.hasNext() ) { OpenlinkUserInterest traderLyncUserInterest = (OpenlinkUserInterest)it.next(); handleCallState(conferenceEvent, traderLyncUserInterest); } publishOpenlinkCallEvent(callInterest); if (conferenceEvent.getMemberCount() == 1 && conferenceEvent.equals(ConferenceEvent.MEMBER_LEFT) && ConferenceManager.getLastMember(conferenceEvent.getConferenceId()).isConferenceMuted() == false) { // held callers are muted. orphan participant wil NOT be muted and should be disconnected Log.info( "["+ site.getName() + "] notifyConferenceMonitors tearing down " + conferenceEvent.getConferenceId()); CallHandler.hangup(conferenceEvent.getConferenceId(), "User requested call termination"); deleteEvents(callInterest, conferenceEvent.getConferenceId()); ConferenceManager.endConference(conferenceEvent.getConferenceId()); } } } } } } catch (Exception e) { Log.error( "["+ site.getName() + "] " + "Error in notifyConferenceMonitors " + e); e.printStackTrace(); } } } */ //------------------------------------------------------- // // // //------------------------------------------------------- /* private void handleCallState(ConferenceEvent conferenceEvent, OpenlinkUserInterest traderLyncUserInterest) { Log.info( "["+ site.getName() + "] handleCallState " + traderLyncUserInterest.getUser().getUserNo() + " " + conferenceEvent.getMemberCount()); OpenlinkInterest traderLyncInterest = traderLyncUserInterest.getInterest(); OpenlinkUser traderLyncUser = traderLyncUserInterest.getUser(); CallHandler callHandlerFarParty = CallHandler.findCall(conferenceEvent.getConferenceId()); // get far party call objects if (callHandlerFarParty != null && callHandlerFarParty.getCallParticipant() != null) { CallParticipant callParticipantFarParty = callHandlerFarParty.getCallParticipant(); String activeUser = callParticipantFarParty.getRequester(); if (conferenceEvent.getMemberCount() == 2) { Log.info( "["+ site.getName() + "] handleCallState 2 participants " + activeUser); // far party and a single user left, find user and set as connected, everyone else busy if (conferenceEvent.equals(ConferenceEvent.MEMBER_JOINED)) { if (activeUser.equals(traderLyncUser.getUserNo())) { traderLyncUserInterest.handleCallConnected(conferenceEvent.getConferenceId()); } else { traderLyncUserInterest.handleCallBusy(conferenceEvent.getConferenceId()); } } else { // participant left, find last remaining participant if (activeUser.equals(traderLyncUser.getUserNo()) == false && traderLyncUser.getHandsetCallId() != null) { traderLyncUserInterest.handleCallConnected(conferenceEvent.getConferenceId()); } else { traderLyncUserInterest.handleCallBusy(conferenceEvent.getConferenceId()); } } } else if (conferenceEvent.getMemberCount() == 1) { Log.info( "["+ site.getName() + "] handleCallState 1 participant " + traderLyncUser.getHandsetCallId()); if (conferenceEvent.equals(ConferenceEvent.MEMBER_JOINED) && traderLyncUser.getHandsetCallId() != null) { // new joiner is a device (handset/speaker), we should be connected traderLyncUserInterest.handleCallConnected(conferenceEvent.getConferenceId()); } } else { // just change state of new joiner, everyone else keep old state Log.info( "["+ site.getName() + "] handleCallState multiple participants " + traderLyncUser.getUserNo()); if (conferenceEvent.equals(ConferenceEvent.MEMBER_JOINED) && activeUser.equals(traderLyncUser.getUserNo())) { traderLyncUserInterest.handleCallConferenced(conferenceEvent.getConferenceId()); } } } } */ public void logRecordEvent(OpenlinkUserInterest userInterest, JSONObject eventJSON, String callId, String direction) { Log.info("logRecordEvent " + callId + "\n" + eventJSON); OpenlinkCall traderLyncCall = userInterest.getCallById(callId); if (traderLyncCall != null) { traderLyncCall.line = (eventJSON.has("recording") ? eventJSON.getString("recording") : ""); traderLyncCall.direction = direction; if (eventJSON.has("name")) traderLyncCall.ddi = eventJSON.getString("name"); if (eventJSON.has("label")) traderLyncCall.ddiLabel = eventJSON.getString("label"); if (eventJSON.has("number")) { String conference = eventJSON.getString("number"); traderLyncCall.setCLI(conference); traderLyncCall.setCLILabel(conference); } userInterest.logCall(traderLyncCall, getDomain(), 0); } } public void sendUserInterestEvent(String username, JSONObject eventJSON) { Log.info("sendUserInterestEvent " + username + "\n" + eventJSON); String state = eventJSON.getString("state"); String privateWire = eventJSON.getString("name"); String label = eventJSON.getString("label"); String callId = privateWire + username; if (traderLyncInterests.containsKey(privateWire)) { OpenlinkInterest callInterest = traderLyncInterests.get(privateWire); if (callInterests.containsKey(callId) == false) { callInterests.put(callId, callInterest); } if (callInterest.getUserInterests().containsKey(username)) { OpenlinkUserInterest userInterest = callInterest.getUserInterests().get(username); boolean processed = false; if (state.equals("ringing")) { String from = privateWire; String to = privateWire; if (eventJSON.has("from")) from = eventJSON.getString("from"); if (eventJSON.has("to")) from = eventJSON.getString("to"); userInterest.handleCallIncoming(callId, from, to); logRecordEvent(userInterest, eventJSON, callId, "Incoming"); processed = true; } if (state.equals("originated")) { String dialDigits = privateWire; userInterest.handleCallOutgoing("CallOriginated", callId, dialDigits, label); userInterest.handleCallOutgoing("CallDelivered", callId, dialDigits, label); processed = true; } if (state.equals("connected") || state.equals("answered")) { userInterest.handleCallConnected(callId); if (state.equals("connected")) logRecordEvent(userInterest, eventJSON, callId, "Outgoing"); processed = true; } if (state.equals("conferenced")) { userInterest.handleCallConferenced(callId); processed = true; } if (state.equals("busy")) { userInterest.handleCallBusy(callId); processed = true; } if (state.equals("idle")) { userInterest.handleConnectionCleared(callId); processed = true; } if (state.equals("held")) { userInterest.handleCallHeld(callId); processed = true; } if (processed) { publishOpenlinkUserCallEvent(userInterest); } if (state.equals("idle")) { userInterest.removeCallById(callId); } } } } public void handleCallIncomingPW(String callId, String privateWire, String from, String to) { OpenlinkInterest lineInterest = getInterest(callId, privateWire); if (lineInterest!= null) { Iterator<OpenlinkUserInterest> it = lineInterest.getUserInterests().values().iterator(); while(it.hasNext()) { OpenlinkUserInterest userInterest = (OpenlinkUserInterest)it.next(); userInterest.handleCallIncoming(callId, from, to); } publishOpenlinkCallEvent(lineInterest); } } private OpenlinkInterest getInterest(String callId, String privateWire) { Log.info( "["+ site.getName() + "] getInterest " + callId + " " + privateWire); OpenlinkInterest callInterest = null; if (callInterests.containsKey(callId)) callInterest = callInterests.get(callId); else { if (traderLyncInterests.containsKey(privateWire)) { callInterest = traderLyncInterests.get(privateWire); } if (callInterest != null) { callInterests.put(callId, callInterest); } } return callInterest; } private void deleteEvents(OpenlinkInterest callInterest, String callId) { Log.info( "["+ site.getName() + "] deleteEvents " + callId); Iterator<OpenlinkUserInterest> it4 = callInterest.getUserInterests().values().iterator(); while( it4.hasNext() ) { OpenlinkUserInterest userInterest = (OpenlinkUserInterest)it4.next(); OpenlinkCall traderLyncCall = userInterest.removeCallById(callId); if (traderLyncCall != null) { userInterest.logCall(traderLyncCall, getDomain(), 0); } } callInterests.remove(callId); } //------------------------------------------------------- // // // //------------------------------------------------------- public synchronized void publishOpenlinkCallEvent(OpenlinkInterest traderLyncInterest) { if ((ClusterManager.isClusteringEnabled() && ClusterManager.isSeniorClusterMember()) || !ClusterManager.isClusteringEnabled()) { Log.info( "["+ site.getName() + "] publishOpenlinkCallEvent - interest " + traderLyncInterest.getInterestId()); Iterator it = traderLyncInterest.getUserInterests().values().iterator(); while( it.hasNext() ) { OpenlinkUserInterest traderLyncUserInterest = (OpenlinkUserInterest)it.next(); publishOpenlinkUserCallEvent(traderLyncUserInterest); } } } public synchronized void publishOpenlinkUserCallEvent(OpenlinkUserInterest traderLyncUserInterest) { if ((ClusterManager.isClusteringEnabled() && ClusterManager.isSeniorClusterMember()) || !ClusterManager.isClusteringEnabled()) { Log.info( "["+ site.getName() + "] publishOpenlinkUserEvent - user interest " + traderLyncUserInterest.getInterestName() + " enabled: " + traderLyncUserInterest.getUser().enabled()); if (traderLyncUserInterest.getUser().enabled()) { if (traderLyncUserInterest.canPublish(this)) { publishOpenlinkUserInterestEvent(traderLyncUserInterest.getInterest(), traderLyncUserInterest); } updateCacheContent(traderLyncUserInterest); } } } private void publishOpenlinkUserInterestEvent(OpenlinkInterest traderLyncInterest, OpenlinkUserInterest traderLyncUserInterest) { Log.info( "["+ site.getName() + "] publishOpenlinkUserInterestEvent - scan user interest " + traderLyncUserInterest.getUser().getUserId() + " " + traderLyncUserInterest.getInterest().getInterestId()); if (!"0.0.0.0".equals(traderLyncUserInterest.getUser().getDeviceNo())) { Log.info( "["+ site.getName() + "] publishOpenlinkUserInterestEvent - publish user interest " + traderLyncUserInterest.getUser().getUserId() + " " + traderLyncUserInterest.getInterest().getInterestId()); String interestNode = traderLyncInterest.getInterestId() + traderLyncUserInterest.getUser().getUserNo(); IQ iq = new IQ(IQ.Type.set); iq.setFrom(getName() + "." + getDomain()); iq.setTo("pubsub." + getDomain()); Element pubsub = iq.setChildElement("pubsub", "http://jabber.org/protocol/pubsub"); Element publish = pubsub.addElement("publish").addAttribute("node", interestNode); Element item = publish.addElement("item").addAttribute("id", interestNode); Element calls = item.addElement("callstatus", "http://xmpp.org/protocol/openlink:01:00:00#call-status"); boolean busy = traderLyncUserInterest.getBusyStatus(); calls.addAttribute("busy", busy ? "true" : "false"); if ("true".equals(traderLyncUserInterest.getCallFWD())) { calls.addAttribute("fwd", traderLyncUserInterest.getCallFWDDigits()); } addOpenlinkCallsEvents(traderLyncInterest, traderLyncUserInterest, calls); if (calls.nodeCount() > 0) { sendPacket(iq); } JID profileJID = new JID(traderLyncUserInterest.getUser().getUserNo() + "@" + getDomain() + "/traderlync"); Session session = (LocalClientSession) XMPPServer.getInstance().getSessionManager().getSession(profileJID); if (session != null) { } } } private void updateCacheContent(OpenlinkUserInterest traderLyncUserInterest) { Log.info( "["+ site.getName() + "] updateCacheContent - user interest " + traderLyncUserInterest.getInterestName()); Iterator it2 = traderLyncUserInterest.getCalls().values().iterator(); while( it2.hasNext() ) { OpenlinkCall traderLyncCall = (OpenlinkCall)it2.next(); } } private void addOpenlinkCallsEvents(OpenlinkInterest traderLyncInterest, OpenlinkUserInterest traderLyncUserInterest, Element calls) { Log.info( "["+ site.getName() + "] addOpenlinkCallsEvents - user interest " + traderLyncUserInterest.getInterestName()); Iterator it2 = traderLyncUserInterest.getCalls().values().iterator(); while( it2.hasNext() ) { OpenlinkCall traderLyncCall = (OpenlinkCall)it2.next(); if (!"Unknown".equals(traderLyncCall.getState()) && !traderLyncCall.deleted) { Element call = calls.addElement("call"); addOpenlinkCallEvents(traderLyncInterest, traderLyncUserInterest, call, traderLyncCall); } } } public synchronized void addOpenlinkCallEvents(OpenlinkInterest traderLyncInterest, OpenlinkUserInterest traderLyncUserInterest, Element call, OpenlinkCall traderLyncCall) { Log.info( "["+ site.getName() + "] addOpenlinkCallEvents - user interest " + traderLyncUserInterest.getInterestName() + " " + traderLyncCall.getCallID()); call.addElement("id").setText(traderLyncCall.getCallID()); call.addElement("profile").setText(traderLyncUserInterest.getUser().getProfileName()); call.addElement("interest").setText(traderLyncUserInterest.getInterestName()); call.addElement("changed").setText(traderLyncCall.getStatus()); call.addElement("state").setText(traderLyncCall.getState()); call.addElement("direction").setText(traderLyncCall.getDirection()); Element caller = call.addElement("caller"); caller.addElement("number").setText(traderLyncCall.getCallerNumber(traderLyncInterest.getInterestType())); caller.addElement("name").setText(traderLyncCall.getCallerName(traderLyncInterest.getInterestType())); Element called = call.addElement("called"); called.addElement("number").setText(traderLyncCall.getCalledNumber(traderLyncInterest.getInterestType())); called.addElement("name").setText(traderLyncCall.getCalledName(traderLyncInterest.getInterestType())); call.addElement("duration").setText(String.valueOf(traderLyncCall.getDuration())); Element actions = call.addElement("actions"); Iterator it4 = traderLyncCall.getValidActions().iterator(); while( it4.hasNext() ) { String action = (String)it4.next(); actions.addElement(action); } Element features = call.addElement("features"); addFeature(features, "priv_1", "Y".equals(traderLyncCall.getPrivacy()) ? "true" : "false"); addFeature(features, "hs_1", "1".equals(traderLyncCall.getHandset()) ? "true" : "false"); addFeature(features, "hs_2", "2".equals(traderLyncCall.getHandset()) ? "true" : "false"); /* if (traderLyncUserInterest.getUser().getCallback() != null && isCallbackAvailable() && traderLyncUserInterest.getUser().getCallbackActive()) { addFeature(features, "callback_1", traderLyncUserInterest.getUser().getCallback()); } */ Element participants = call.addElement("participants"); Iterator it3 = traderLyncInterest.getUserInterests().values().iterator(); while( it3.hasNext() ) { OpenlinkUserInterest traderLyncParticipant = (OpenlinkUserInterest)it3.next(); if (!"0.0.0.0".equals(traderLyncParticipant.getUser().getDeviceNo())) { OpenlinkCall participantCall = traderLyncParticipant.getCallByLine(traderLyncCall.getLine()); if (participantCall != null) { Element participant = participants.addElement("participant"); participant.addAttribute("jid", traderLyncParticipant.getUser().getUserId() + "@" + getDomain()); participant.addAttribute("type", participantCall.getParticipation()); participant.addAttribute("direction", participantCall.getDirection()); if (participantCall.firstTimeStamp != 0) { participant.addAttribute("timestamp", String.valueOf(new Date(participantCall.firstTimeStamp))); } } } } } private void addFeature(Element features, String id, String value) { Element feature = features.addElement("feature"); feature.addAttribute("id", id); feature.setText(value); } public synchronized void publishOpenlinkUserDeviceEvent(OpenlinkUser traderLyncUser) { Log.info( "["+ site.getName() + "] publishOpenlinkUserDeviceEvent - " + traderLyncUser.getUserId()); if (!"0.0.0.0".equals(traderLyncUser.getDeviceNo())) { OpenlinkInterest traderLyncInterest = traderLyncUser.getDefaultInterest(); if (traderLyncInterest != null) { String interestNode = traderLyncInterest.getInterestId() + traderLyncUser.getUserNo(); IQ iq = new IQ(IQ.Type.set); iq.setFrom(getName() + "." + getDomain()); iq.setTo("pubsub." + getDomain()); Element pubsub = iq.setChildElement("pubsub", "http://jabber.org/protocol/pubsub"); Element publish = pubsub.addElement("publish").addAttribute("node", interestNode); Element item = publish.addElement("item").addAttribute("id", interestNode); Element device = item.addElement("devicestatus", "http://xmpp.org/protocol/openlink:01:00:00#device-status"); Element features = device.addElement("features"); addFeature(features, "icom_1", traderLyncUser.intercom() ? "true" : "false"); sendPacket(iq); } } } public void createPubsubNode(String interestNode) { //Log.info("["+site.getName()+"] createPubsubNode - " + interestNode); String domain = getDomain(); IQ iq1 = new IQ(IQ.Type.set); iq1.setFrom(getName() + "." + domain); iq1.setTo("pubsub." + domain); Element pubsub1 = iq1.setChildElement("pubsub", "http://jabber.org/protocol/pubsub"); Element create = pubsub1.addElement("create").addAttribute("node", interestNode); Element configure = pubsub1.addElement("configure"); Element x = configure.addElement("x", "jabber:x:data").addAttribute("type", "submit"); Element field1 = x.addElement("field"); field1.addAttribute("var", "FORM_TYPE"); field1.addAttribute("type", "hidden"); field1.addElement("value").setText("http://jabber.org/protocol/pubsub#node_config"); //Element field2 = x.addElement("field"); //field2.addAttribute("var", "pubsub#persist_items"); //field2.addElement("value").setText("1"); Element field3 = x.addElement("field"); field3.addAttribute("var", "pubsub#max_items"); field3.addElement("value").setText("1"); Log.info("createPubsubNode " + iq1.toString()); sendPacket(iq1); } public void getInterestSubscriptions(OpenlinkInterest traderLyncInterest, String userNo) { String interestNode = traderLyncInterest.getInterestId() + userNo; String domain = getDomain(); Log.info("["+site.getName()+"] getInterestSubscriptions - " + interestNode); IQ iq2 = new IQ(IQ.Type.get); iq2.setFrom(getName() + "." + domain); iq2.setTo("pubsub." + domain); Element pubsub2 = iq2.setChildElement("pubsub", "http://jabber.org/protocol/pubsub#owner"); Element subscriptions = pubsub2.addElement("subscriptions").addAttribute("node", interestNode); Log.info("subscriptions " + iq2.toString()); sendPacket(iq2); } class RosterItemComparator implements Comparator<RosterItem> { public int compare(RosterItem itemA, RosterItem itemB) { return itemA.getJid().toBareJID().compareTo(itemB.getJid().toBareJID()); } } //------------------------------------------------------- // // // //------------------------------------------------------- public void loadProfile(String userName) { Log.info("["+site.getName()+"] loadProfile - " + userName); try { Document document = DocumentHelper.parseText("<traderlyncprofile xmlns=\"http://xmpp.org/protocol/traderlync#user-profile-device\"></traderlyncprofile>"); Element searchElement = document.getRootElement(); Element foundElement = XMPPServer.getInstance().getPrivateStorage().get(userName, searchElement); if (foundElement != null) { if (foundElement.element("ipaddress") != null) { String ipAddress = foundElement.element("ipaddress").getText(); String hostName = foundElement.element("host").getText(); String macAddress = foundElement.element("mac").getText(); String userAgent = foundElement.element("agent").getText(); String expansionMod1 = foundElement.element("exten1").getText(); String expansionMod2 = foundElement.element("exten2").getText(); String expansionMod3 = foundElement.element("exten3").getText(); Log.info("["+site.getName()+"] loadProfile - " + userName + " " + macAddress + " " + hostName + " " + ipAddress + " " + userAgent + " " + expansionMod1 + " " + expansionMod2 + " " + expansionMod3); OpenlinkUser traderLyncUser = getOpenlinkProfile(userName); } } } catch (Exception e) { Log.error("["+site.getName()+"] loadProfile - " + e); } } public void unloadProfile(String userName) { Log.info("["+site.getName()+"] unloadProfile - " + userName); } }