package org.mobicents.ipbx.session; import java.util.Iterator; import java.util.LinkedList; import java.util.Timer; import java.util.TimerTask; import javax.faces.application.FacesMessage; import javax.faces.context.FacesContext; import javax.persistence.EntityManager; import javax.servlet.sip.Address; import javax.servlet.sip.SipApplicationSession; import javax.servlet.sip.SipFactory; import javax.servlet.sip.SipServletRequest; import javax.servlet.sip.SipSession; import javax.servlet.sip.URI; import javax.servlet.sip.SipSession.State; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.In; import org.jboss.seam.annotations.Logger; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; import org.jboss.seam.log.Log; import org.mobicents.ipbx.entity.CallState; import org.mobicents.ipbx.entity.PstnGatewayAccount; import org.mobicents.ipbx.entity.Registration; import org.mobicents.ipbx.entity.User; import org.mobicents.ipbx.session.call.model.CallParticipant; import org.mobicents.ipbx.session.call.model.CallParticipantManager; import org.mobicents.ipbx.session.call.model.Conference; import org.mobicents.ipbx.session.call.model.ConferenceManager; import org.mobicents.ipbx.session.call.model.CurrentWorkspaceState; import org.mobicents.ipbx.session.call.model.WorkspaceStateManager; import org.mobicents.ipbx.session.configuration.PbxConfiguration; import org.mobicents.ipbx.session.security.SimpleSipAuthenticator; @Name("callAction") @Scope(ScopeType.STATELESS) public class CallAction { @Logger private static Log log; @In(required=false,value="user") User user; @In DataLoader dataLoader; @In(create=true) SimpleSipAuthenticator sipAuthenticator; @In SipFactory sipFactory; @In EntityManager entityManager; @In(required=false) CurrentWorkspaceState currentWorkspaceState; public static final String PR_JNDI_NAME = "media/trunk/PacketRelay/$"; public void dialParticipant(final CallParticipant participant) { Conference conf = participant.getConference(); String fromUri = getAuthUri(participant); if(fromUri == null) fromUri = conf.getConferenceUri(); try { // Don't use this because we might call it from SIP context (faces context not available) //FacesContext context = FacesContext.getCurrentInstance(); //ConvergedHttpSession session = (ConvergedHttpSession) context.getExternalContext().getSession(false); //SipApplicationSession appSession = session.getApplicationSession();//sipFactory.createApplicationSession(); SipApplicationSession appSession = sipFactory.createApplicationSession(); Address from = sipFactory.createAddress(fromUri); Address to = sipFactory.createAddress(participant.getUri()); URI requestURI = sipFactory.createURI(participant.getUri()); SipServletRequest request = sipFactory.createRequest(appSession, "INVITE", from, to); SipSession sipSession = request.getSession(); log.info("DIALCONNECTION " + sipSession.toString()); sipSession.setAttribute("participant", participant); if(user != null) request.getSession().setAttribute("user", user); participant.setCallState(CallState.CONNECTING); request.setRequestURI(requestURI); sipSession.setAttribute("inviteRequest", request); participant.setInitialRequest(request); String timeout = PbxConfiguration.getProperty("pbx.call.timeout"); new Timer().schedule(new TimeoutTask(participant), Integer.parseInt(timeout)) ; String initiatorUser = participant.getName(); // If we are running in a web context the web user is the initiator if(user != null) { initiatorUser = user.getName(); } WorkspaceStateManager.instance().getWorkspace(initiatorUser).setOutgoing(participant); for(CallParticipant cp : conf.getParticipants()) { if(cp.getName().equals(participant.getName())) { if(!cp.getName().equals(initiatorUser)) { WorkspaceStateManager.instance().getWorkspace(cp.getName()).setIncoming(participant); } } } request.send(); } catch (Exception e) { log.error("Error", e); } } private String getAuthUri(CallParticipant cp) { PstnGatewayAccount account = cp.getPstnGatewayAccount(); if(account == null) return null; String uri = "sip:" + account.getUsername() + "@" + account.getHostname(); return uri; } /** * Establish call with all uris registered for the user under the supplied uri * * @param toUri */ public void establishCallByUser(String toUri) { User detectedUser = null; if(!toUri.startsWith("sip:")) { boolean charDetected = false; for(int q=0; q<toUri.length(); q++) { if(toUri.charAt(q)>'A' && toUri.charAt(q)<'z') { charDetected = true; } } if(charDetected) { detectedUser = (User) entityManager.createQuery( "SELECT user FROM User user where user.name=:username") .setParameter("username", toUri).getSingleResult(); } } LinkedList<CallParticipant> fromParticipants = new LinkedList<CallParticipant>(); Registration toRegistration = null; if(detectedUser == null){ toRegistration = sipAuthenticator.findRegistration(toUri); } User fromUser = entityManager.find(User.class, this.user.getId()); Conference conf = null; boolean alreadyInCall = false; // Determine if we are in any calls right now. If yes, take a conference // endpoint to join the outgoing call String[] callableUris = fromUser.getCallableUris(); for(String uri : callableUris) { CallParticipant p = CallParticipantManager.instance().getExistingCallParticipant(uri); if(p != null) { if(p.getConference() != null && p.getCallState().equals(CallState.INCALL)) { alreadyInCall = true; conf = p.getConference(); fromParticipants.add(p); } } } // If there are no active calls just create a new conference where the // conversation will take place if(conf == null) { conf = ConferenceManager.instance().getNewConference(); //Add the participants selected in the My Phones panel for(String uri : fromUser.getCallableUris()) { CallParticipant fromParticipant = CallParticipantManager.instance().getCallParticipant(uri); fromParticipant.setName(fromUser.getName()); fromParticipant.setConference(conf); fromParticipants.add(fromParticipant); } } // Some error checking - if no active phones, don't call and remind the user to select a phone if(fromParticipants.size()==0) { try { FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("No phone selected", "You must register a phone and select it from the menu")); } catch (Exception e) {} return; } // Call the guy on all possible phones String[] toCallableUris = null; if(toRegistration != null) { toCallableUris = toRegistration.getUser().getCallableUris(); } if(detectedUser != null) { toCallableUris = detectedUser.getCallableUris(); } if(toCallableUris == null || toCallableUris.length == 0) { toCallableUris = new String[] {toUri}; try { FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("The remote user has no active phones. Trying to call directly...", "The remote user has no active phones. Trying to call directly...")); } catch (Exception e) {} } for(String uri : toCallableUris) { CallParticipant toParticipant = CallParticipantManager.instance().getCallParticipant(uri); toParticipant.setConference(conf); String remoteUserName = "Unknown user"; if(toRegistration != null) remoteUserName = toRegistration.getUser().getName(); if(detectedUser != null) remoteUserName = detectedUser.getName(); toParticipant.setName(remoteUserName); dialParticipant(toParticipant); } // Call my phones if there is no ongoing call if(!alreadyInCall) { Iterator<CallParticipant> iterator = fromParticipants.iterator(); while(iterator.hasNext()) { CallParticipant next = iterator.next(); next.setName(fromUser.getName()); dialParticipant(next); } } else { try { FacesContext.getCurrentInstance().addMessage(null, new FacesMessage( "The remote user is already in a call. He will be asked to take you in the call.", "The remote user is already in a call. He will be asked to take you in the call.")); } catch (Exception e) {} } } /** * Establish call with all uris registered for the user under the supplied uri * * @param toUri */ public void establishCallToRegisteredPhone(String toUri) { Conference conf = currentWorkspaceState.getConference(); // Call the guy on all possible phones String[] toCallableUris = new String[] {toUri}; for(String uri : toCallableUris) { CallParticipant toParticipant = CallParticipantManager.instance().getCallParticipant(uri); toParticipant.setConference(conf); String remoteUserName = user.getName(); toParticipant.setName(remoteUserName); dialParticipant(toParticipant); } } static class TimeoutTask extends TimerTask { private CallParticipant participant; public TimeoutTask(CallParticipant participant) { this.participant = participant; } public void run () { try { boolean active = this.participant.getInitialRequest().getSession().getState().equals(State.CONFIRMED); if(!active) { WorkspaceStateManager.instance().getWorkspace(participant.getName()).endCall(participant); } } catch (Exception ex) { // No important } } } }