/** * Constructor * * @param parent IMS service * @param invite Initial INVITE request */ public TerminatingOne2OneChatSession(ImsService parent, SipRequest invite) { super(parent, PhoneUtils.extractNumberFromUri(SipUtils.getAssertedIdentity(invite))); // Set first message InstantMessage firstMsg = ChatUtils.getFirstMessage(invite); setFirstMesssage(firstMsg); // Create dialog path createTerminatingDialogPath(invite); // Set contribution ID String id = ChatUtils.getContributionId(invite); setContributionID(id); if (RcsSettings.getInstance().isCPMSupported()) { if (logger.isActivated()) { logger.info("TerminatingFOne2OneSession1 CPMS"); } setConversationID(ChatUtils.getCoversationId(invite)); setInReplyID(ChatUtils.getInReplyId(invite)); } if (logger.isActivated()) { logger.info("TerminatingOne2OneChatSession From: " + ChatUtils.getFromAias(invite)); logger.info("TerminatingOne2OneChatSession Display name: " + this.getRemoteDisplayName()); } setRemoteDisplayName(this.getRemoteDisplayName()); }
@Override public void onCreate() { // Set application context AndroidFactory.setApplicationContext(getApplicationContext()); // Instantiate the settings manager RcsSettings.createInstance(getApplicationContext()); // Set the logger properties Logger.activationFlag = RcsSettings.getInstance().isTraceActivated(); Logger.traceLevel = RcsSettings.getInstance().getTraceLevel(); // Set the terminal version TerminalInfo.setProductVersion(AppUtils.getApplicationVersion(this)); // Start the core startCore(); }
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.rcs_settings_presence_preferences); setTitle(R.string.rcs_settings_title_presence_settings); freetextEdit1 = (EditTextPreference) findPreference("edit_freetext1"); freetextEdit1.setPersistent(false); freetextEdit1.setOnPreferenceChangeListener(this); String txt1 = RcsSettings.getInstance().getPredefinedFreetext1(); freetextEdit1.setText(txt1); freetextEdit1.setTitle(txt1); freetextEdit2 = (EditTextPreference) findPreference("edit_freetext2"); freetextEdit2.setPersistent(false); freetextEdit2.setOnPreferenceChangeListener(this); String txt2 = RcsSettings.getInstance().getPredefinedFreetext2(); freetextEdit2.setText(txt2); freetextEdit2.setTitle(txt2); freetextEdit3 = (EditTextPreference) findPreference("edit_freetext3"); freetextEdit3.setPersistent(false); freetextEdit3.setOnPreferenceChangeListener(this); String txt3 = RcsSettings.getInstance().getPredefinedFreetext3(); freetextEdit3.setText(txt3); freetextEdit3.setTitle(txt3); freetextEdit4 = (EditTextPreference) findPreference("edit_freetext4"); freetextEdit4.setPersistent(false); freetextEdit4.setOnPreferenceChangeListener(this); String txt4 = RcsSettings.getInstance().getPredefinedFreetext4(); freetextEdit4.setText(txt4); freetextEdit4.setTitle(txt4); vibrateInvitation = (CheckBoxPreference) findPreference("presence_invitation_vibration"); vibrateInvitation.setPersistent(false); vibrateInvitation.setOnPreferenceChangeListener(this); vibrateInvitation.setChecked(RcsSettings.getInstance().isPhoneVibrateForPresenceInvitation()); }
public boolean onPreferenceChange(Preference preference, Object objValue) { if (preference.getKey().equals("edit_freetext1")) { String txt = (String) objValue; RcsSettings.getInstance().setPredefinedFreetext1(txt); freetextEdit1.setTitle(txt); } else if (preference.getKey().equals("edit_freetext2")) { String txt = (String) objValue; RcsSettings.getInstance().setPredefinedFreetext2(txt); freetextEdit2.setTitle(txt); } else if (preference.getKey().equals("edit_freetext3")) { String txt = (String) objValue; RcsSettings.getInstance().setPredefinedFreetext3(txt); freetextEdit3.setTitle(txt); } else if (preference.getKey().equals("edit_freetext4")) { String txt = (String) objValue; RcsSettings.getInstance().setPredefinedFreetext4(txt); freetextEdit4.setTitle(txt); } else if (preference.getKey().equals("presence_invitation_vibration")) { Boolean state = (Boolean) objValue; RcsSettings.getInstance().setPhoneVibrateForPresenceInvitation(state.booleanValue()); } return true; }
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Get subject subject = getIntent().getStringExtra("subject"); // Set title if ((subject == null) || (subject.length() == 0)) { setTitle(getString(R.string.title_chat_view_group)); } else { setTitle(getString(R.string.title_chat_view_group) + " " + subject); } // Set the message composer max length InputFilter[] filterArray = new InputFilter[1]; filterArray[0] = new InputFilter.LengthFilter(RcsSettings.getInstance().getMaxGroupChatMessageLength()); composeText.setFilters(filterArray); }
/** * Returns the configuration of video sharing service * * @return Configuration */ public VideoSharingServiceConfiguration getConfiguration() { return new VideoSharingServiceConfiguration( RcsSettings.getInstance().getMaxVideoShareDuration()); }
/** * IMS service session * * @author jexa7410 */ public abstract class ImsServiceSession extends Thread { /** Session invitation status */ public static final int INVITATION_NOT_ANSWERED = 0; public static final int INVITATION_ACCEPTED = 1; public static final int INVITATION_REJECTED = 2; /** M: add for MSRPoTLS */ protected static final String PROTOCOL_TLS = "TLS"; protected static final String PROTOCOL_TCP = "TCP"; /** M: Added to resolve the rich call 403 error.@{ */ private static final int INIT_CSEQUENCE_NUMBER = 1; /** @} */ /** IMS service */ private ImsService imsService; /** Session ID */ private String sessionId = SessionIdGenerator.getNewId(); /** Remote contact */ private String contact; /** Dialog path */ private SipDialogPath dialogPath = null; /** Authentication agent */ private SessionAuthenticationAgent authenticationAgent; /** Session invitation status */ protected int invitationStatus = INVITATION_NOT_ANSWERED; /** Wait user answer for session invitation */ protected Object waitUserAnswer = new Object(); /** Session listeners */ private Vector<ImsSessionListener> listeners = new Vector<ImsSessionListener>(); /** Session timer manager */ private SessionTimerManager sessionTimer = new SessionTimerManager(this); /** Ringing period (in seconds) */ private int ringingPeriod = RcsSettings.getInstance().getRingingPeriod(); /** Session interrupted flag */ private boolean sessionInterrupted = false; /** The logger */ private Logger logger = Logger.getLogger(this.getClass().getName()); /** * Constructor * * @param parent IMS service * @param contact Remote contact */ public ImsServiceSession(ImsService imsService, String contact) { this.imsService = imsService; this.contact = contact; this.authenticationAgent = new SessionAuthenticationAgent(imsService.getImsModule()); } /** Create originating dialog path */ public void createOriginatingDialogPath() { // Set Call-Id String callId = getImsService().getImsModule().getSipManager().getSipStack().generateCallId(); // Set the route path Vector<String> route = getImsService().getImsModule().getSipManager().getSipStack().getServiceRoutePath(); // Create a dialog path dialogPath = new SipDialogPath( getImsService().getImsModule().getSipManager().getSipStack(), callId, /** M: Added to resolve the rich call 403 error.@{ */ INIT_CSEQUENCE_NUMBER, /** @} */ getRemoteContact(), ImsModule.IMS_USER_PROFILE.getPublicUri(), getRemoteContact(), route); // Set the authentication agent in the dialog path dialogPath.setAuthenticationAgent(getAuthenticationAgent()); } /** M: Added to resolve the rich call 403 error.@{ */ /** Create originating dialog path */ public void createOriginatingDialogPath(String callId) { logger.debug("createOriginatingDialogPath(), callId = " + callId); // Set the route path Vector<String> route = getImsService().getImsModule().getSipManager().getSipStack().getServiceRoutePath(); // Create a dialog path dialogPath = new SipDialogPath( getImsService().getImsModule().getSipManager().getSipStack(), callId, INIT_CSEQUENCE_NUMBER, getRemoteContact(), ImsModule.IMS_USER_PROFILE.getPublicUri(), getRemoteContact(), route); // Set the authentication agent in the dialog path dialogPath.setAuthenticationAgent(getAuthenticationAgent()); } /** @} */ /** * Create terminating dialog path * * @param invite Incoming invite */ public void createTerminatingDialogPath(SipRequest invite) { // Set the call-id String callId = invite.getCallId(); // Set target String target = invite.getContactURI(); // Set local party String localParty = invite.getTo(); // Set remote party String remoteParty = invite.getFrom(); // Get the CSeq value long cseq = invite.getCSeq(); // Set the route path with the Record-Route Vector<String> route = SipUtils.routeProcessing(invite, false); // Create a dialog path dialogPath = new SipDialogPath( getImsService().getImsModule().getSipManager().getSipStack(), callId, cseq, target, localParty, remoteParty, route); // Set the INVITE request dialogPath.setInvite(invite); // Set the remote tag dialogPath.setRemoteTag(invite.getFromTag()); // Set the remote content part dialogPath.setRemoteContent(invite.getContent()); // Set the session timer expire dialogPath.setSessionExpireTime(invite.getSessionTimerExpire()); } /** * Add a listener for receiving events * * @param listener Listener */ public void addListener(ImsSessionListener listener) { listeners.add(listener); } /** Remove a listener */ public void removeListener(ImsSessionListener listener) { listeners.remove(listener); } /** Remove all listeners */ public void removeListeners() { listeners.removeAllElements(); } /** * Returns the event listeners * * @return Listeners */ public Vector<ImsSessionListener> getListeners() { return listeners; } /** * Get the session timer manager * * @return Session timer manager */ public SessionTimerManager getSessionTimerManager() { return sessionTimer; } /** * Is behind a NAT * * @return Boolean */ public boolean isBehindNat() { return getImsService().getImsModule().getCurrentNetworkInterface().isBehindNat(); } /** Start the session in background */ public void startSession() { // Add the session in the session manager imsService.addSession(this); // Start the session start(); } /** * Return the IMS service * * @return IMS service */ public ImsService getImsService() { return imsService; } /** * Return the session ID * * @return Session ID */ public String getSessionID() { return sessionId; } /** * Returns the remote contact * * @return String */ public String getRemoteContact() { return contact; } /** * Returns display name of the remote contact * * @return String */ public String getRemoteDisplayName() { String displayName = null; try { String from = getDialogPath().getInvite().getFrom(); displayName = PhoneUtils.extractDisplayNameFromUri(from); } catch (Exception e) { displayName = null; } return displayName; } /** * Get the dialog path of the session * * @return Dialog path object */ public SipDialogPath getDialogPath() { return dialogPath; } /** * Set the dialog path of the session * * @param dialog Dialog path */ public void setDialogPath(SipDialogPath dialog) { dialogPath = dialog; } /** * Returns the authentication agent * * @return Authentication agent */ public SessionAuthenticationAgent getAuthenticationAgent() { return authenticationAgent; } /** * Reject the session invitation * * @param code Error code */ public void rejectSession(int code) { if (logger.isActivated()) { logger.debug("Session invitation has been rejected"); } invitationStatus = INVITATION_REJECTED; // Unblock semaphore synchronized (waitUserAnswer) { waitUserAnswer.notifyAll(); } // Decline the invitation sendErrorResponse(getDialogPath().getInvite(), getDialogPath().getLocalTag(), code); // Remove the session in the session manager imsService.removeSession(this); } /** Accept the session invitation */ public void acceptSession() { if (logger.isActivated()) { logger.debug("Session invitation has been accepted"); } invitationStatus = INVITATION_ACCEPTED; // Unblock semaphore synchronized (waitUserAnswer) { waitUserAnswer.notifyAll(); } } /** * Wait session invitation answer * * @return Answer */ public int waitInvitationAnswer() { if (invitationStatus != INVITATION_NOT_ANSWERED) { return invitationStatus; } if (logger.isActivated()) { logger.debug("Wait session invitation answer"); } // Wait until received response or received timeout try { synchronized (waitUserAnswer) { waitUserAnswer.wait(ringingPeriod * 1000); } } catch (InterruptedException e) { sessionInterrupted = true; } return invitationStatus; } /** Interrupt session */ public void interruptSession() { if (logger.isActivated()) { logger.debug("Interrupt the session"); } try { // Unblock semaphore synchronized (waitUserAnswer) { waitUserAnswer.notifyAll(); } if (!isSessionInterrupted()) { // Interrupt thread interrupt(); } } catch (Exception e) { if (logger.isActivated()) { logger.error("Can't interrupt the session correctly", e); } } if (logger.isActivated()) { logger.debug("Session has been interrupted"); } } /** M: do not send SIP BYE when timeout to distinguish BOOTED from DEPARTED @{ */ /** Abort the session */ public void abortSessionWithoutBye() { if (logger.isActivated()) { logger.info("abortSessionWithoutBye() entry"); } // Interrupt the session interruptSession(); // Terminate session terminateSessionWithoutBy(); // Close media session closeMediaSession(); // Remove the current session getImsService().removeSession(this); // Notify listeners int size = getListeners().size(); for (int i = 0; i < size; i++) { getListeners().get(i).handleSessionAborted(); } } /** @} */ /** Abort the session */ public void abortSession() { if (logger.isActivated()) { logger.info("Abort the session"); } // Interrupt the session interruptSession(); // Terminate session terminateSession(); // Close media session closeMediaSession(); // Remove the current session getImsService().removeSession(this); // Notify listeners for (int i = 0; i < getListeners().size(); i++) { getListeners().get(i).handleSessionAborted(); } } /** M: do not send SIP BYE when timeout to distinguish BOOTED from DEPARTED @{ */ /** Terminate session */ public void terminateSessionWithoutBy() { if (dialogPath.isSessionTerminated()) { // Already terminated return; } // Stop session timer getSessionTimerManager().stop(); // Update dialog path dialogPath.sessionTerminated(); // Unblock semaphore (used for terminating side only) synchronized (waitUserAnswer) { waitUserAnswer.notifyAll(); } } /** @} */ /** Terminate session */ public void terminateSession() { if (logger.isActivated()) { logger.debug("Terminate the session"); } if (dialogPath.isSessionTerminated()) { // Already terminated return; } // Stop session timer getSessionTimerManager().stop(); // Update dialog path dialogPath.sessionTerminated(); // Unblock semaphore (used for terminating side only) synchronized (waitUserAnswer) { waitUserAnswer.notifyAll(); } try { // Terminate the session if (dialogPath.isSigEstablished()) { // Increment the Cseq number of the dialog path getDialogPath().incrementCseq(); // Send BYE without waiting a response getImsService().getImsModule().getSipManager().sendSipBye(getDialogPath()); } else { // Send CANCEL without waiting a response getImsService().getImsModule().getSipManager().sendSipCancel(getDialogPath()); } if (logger.isActivated()) { logger.debug("SIP session has been terminated"); } } catch (Exception e) { if (logger.isActivated()) { logger.error("Session termination has failed", e); } } } /** * Receive BYE request * * @param bye BYE request */ public void receiveBye(SipRequest bye) { if (logger.isActivated()) { logger.info("Receive a BYE message from the remote"); } // Close media session closeMediaSession(); // Update the dialog path status getDialogPath().sessionTerminated(); // Remove the current session getImsService().removeSession(this); // Stop session timer getSessionTimerManager().stop(); // Notify listeners for (int i = 0; i < getListeners().size(); i++) { getListeners().get(i).handleSessionTerminatedByRemote(); } } /** * Receive CANCEL request * * @param cancel CANCEL request */ public void receiveCancel(SipRequest cancel) { if (logger.isActivated()) { logger.info("Receive a CANCEL message from the remote"); } if (getDialogPath().isSigEstablished()) { if (logger.isActivated()) { logger.info( "Ignore the received CANCEL message from the remote (session already established)"); } return; } // Close media session closeMediaSession(); // Update dialog path getDialogPath().sessionCancelled(); // Send a 487 Request terminated try { if (logger.isActivated()) { logger.info("Send 487 Request terminated"); } SipResponse terminatedResp = SipMessageFactory.createResponse( getDialogPath().getInvite(), IdGenerator.getIdentifier(), 487); getImsService().getImsModule().getSipManager().sendSipResponse(terminatedResp); } catch (Exception e) { if (logger.isActivated()) { logger.error("Can't send 487 error response", e); } } // Remove the current session getImsService().removeSession(this); // Notify listeners for (int i = 0; i < getListeners().size(); i++) { getListeners().get(i).handleSessionTerminatedByRemote(); } // Request capabilities to the remote getImsService() .getImsModule() .getCapabilityService() .requestContactCapabilities(getDialogPath().getRemoteParty()); } /** * Receive re-INVITE request * * @param reInvite re-INVITE request */ public void receiveReInvite(SipRequest reInvite) { sessionTimer.receiveReInvite(reInvite); } /** * Receive UPDATE request * * @param update UPDATE request */ public void receiveUpdate(SipRequest update) { sessionTimer.receiveUpdate(update); } /** Close media session */ public abstract void closeMediaSession(); /** * Send a 180 Ringing response to the remote party * * @param request SIP request * @param localTag Local tag */ public void send180Ringing(SipRequest request, String localTag) { try { SipResponse progress = SipMessageFactory.createResponse(request, localTag, 180); getImsService().getImsModule().getSipManager().sendSipResponse(progress); } catch (Exception e) { if (logger.isActivated()) { logger.error("Can't send a 180 Ringing response"); } } } /** * Send an error response to the remote party * * @param request SIP request * @param localTag Local tag * @param code Response code */ public void sendErrorResponse(SipRequest request, String localTag, int code) { try { // Send error if (logger.isActivated()) { logger.info("Send " + code + " error response"); } SipResponse resp = SipMessageFactory.createResponse(request, localTag, code); getImsService().getImsModule().getSipManager().sendSipResponse(resp); } catch (Exception e) { if (logger.isActivated()) { logger.error("Can't send error response", e); } } } /** * Send a 603 "Decline" to the remote party * * @param request SIP request * @param localTag Local tag */ public void send603Decline(SipRequest request, String localTag) { try { // Send a 603 Decline error if (logger.isActivated()) { logger.info("Send 603 Decline"); } SipResponse resp = SipMessageFactory.createResponse(request, localTag, 603); getImsService().getImsModule().getSipManager().sendSipResponse(resp); } catch (Exception e) { if (logger.isActivated()) { logger.error("Can't send 603 Decline response", e); } } } /** * Send a 486 "Busy" to the remote party * * @param request SIP request * @param localTag Local tag */ public void send486Busy(SipRequest request, String localTag) { try { // Send a 486 Busy error if (logger.isActivated()) { logger.info("Send 486 Busy"); } SipResponse resp = SipMessageFactory.createResponse(request, localTag, 486); getImsService().getImsModule().getSipManager().sendSipResponse(resp); } catch (Exception e) { if (logger.isActivated()) { logger.error("Can't send 486 Busy response", e); } } } /** * Send a 415 "Unsupported Media Type" to the remote party * * @param request SIP request */ public void send415Error(SipRequest request) { try { if (logger.isActivated()) { logger.info("Send 415 Unsupported Media Type"); } SipResponse resp = SipMessageFactory.createResponse(request, 415); // TODO: set Accept-Encoding header getImsService().getImsModule().getSipManager().sendSipResponse(resp); } catch (Exception e) { if (logger.isActivated()) { logger.error("Can't send 415 error response", e); } } } /** * Create SDP setup offer (see RFC6135, RFC4145) * * @return Setup offer ("active" or "actpass") */ public String createSetupOffer() { if (isBehindNat()) { // Active mode by default if there is a NAT. Active/passive mode is // exchanged in order to be compatible with UE not supporting COMEDIA return "actpass"; } else { return "active"; } } /** * Create SDP setup answer (see RFC6135, RFC4145) * * @param offer setup offer * @return Setup answer ("active" or "passive") */ public String createSetupAnswer(String offer) { if (offer.equals("actpass")) { // Active mode by default if there is a NAT or AS IM return "active"; } else if (offer.equals("active")) { // Passive mode return "passive"; } else if (offer.equals("passive")) { // Active mode return "active"; } else { // Passive mode by default return "passive"; } } /** * Returns the response timeout (in seconds) * * @return Timeout */ public int getResponseTimeout() { return ringingPeriod + SipManager.TIMEOUT; } /** M: Added to resolve the rich call 403 error.@{ */ /** * Handle 403 error. First do re-register then send request again * * @param request The request was responded with 403 */ public void handle403Forbidden(SipRequest request) { if (logger.isActivated()) { logger.debug("handle403Forbidden() entry"); } boolean isRegistered = imsService .getImsModule() .getCurrentNetworkInterface() .getRegistrationManager() .registration(); if (logger.isActivated()) { logger.debug("re-register isRegistered: " + isRegistered); } if (isRegistered) { String callId = dialogPath.getCallId(); SipRequest invite = createSipInvite(callId); if (invite != null) { try { sendInvite(invite); } catch (SipException e) { if (logger.isActivated()) { logger.debug("re send sip request failed."); } e.printStackTrace(); } } else { if (logger.isActivated()) { logger.debug("handle403Forbidden() invite is null"); } } } if (logger.isActivated()) { logger.debug("handle403Forbidden() exit"); } } protected void sendInvite(SipRequest invite) throws SipException { logger.debug("ImsServiceSession::sendInvite(), do nothing in the parent class"); } protected SipRequest createSipInvite(String callId) { logger.debug("ImsServiceSession::createSipInvite(), do nothing in the parent class"); return null; } /** @} */ /** M: add for MSRPoTLS @{ */ protected String getCurrentProtocol() { if (logger.isActivated()) { logger.debug("getCurrentProtocol entry"); } String protocol = getImsService().getImsModule().getCurrentNetworkInterface().getMsrpProtocol(); if (logger.isActivated()) { logger.debug("getCurrentProtocol exit, protocol: " + protocol); } return protocol; } /** @} */ /** * Is session interrupted * * @return Boolean */ public boolean isSessionInterrupted() { return sessionInterrupted; } }
/** Start core */ public synchronized void startCore() { if (Core.getInstance() != null) { // Already started return; } try { if (logger.isActivated()) { logger.debug("Start RCS core service"); } // Send service intent Intent intent = new Intent(ClientApiIntents.SERVICE_STATUS); intent.putExtra("status", ClientApiIntents.SERVICE_STATUS_STARTING); getApplicationContext().sendBroadcast(intent); // Terminal version if (logger.isActivated()) { logger.info("RCS stack release is " + TerminalInfo.getProductVersion()); } // Instantiate the contacts manager ContactsManager.createInstance(getApplicationContext()); // Instantiate the rich messaging history RichMessaging.createInstance(getApplicationContext()); // Instantiate the rich call history RichCall.createInstance(getApplicationContext()); // Instantiate the IP call history IPCall.createInstance(getApplicationContext()); // Create the core Core.createCore(this); // Start the core Core.getInstance().startCore(); // Create multimedia directory on sdcard FileFactory.createDirectory(RcsSettings.getInstance().getPhotoRootDirectory()); FileFactory.createDirectory(RcsSettings.getInstance().getVideoRootDirectory()); FileFactory.createDirectory(RcsSettings.getInstance().getFileRootDirectory()); // Init CPU manager cpuManager.init(); // Register account changed event receiver if (accountChangedReceiver == null) { accountChangedReceiver = new AccountChangedReceiver(); // Register account changed broadcast receiver after a timeout of 2s (This is not done // immediately, as we do not want to catch // the removal of the account (creating and removing accounts is done asynchronously). We // can reasonably assume that no // RCS account deletion will be done by user during this amount of time, as he just started // his service. Handler handler = new Handler(); handler.postDelayed( new Runnable() { public void run() { registerReceiver( accountChangedReceiver, new IntentFilter("android.accounts.LOGIN_ACCOUNTS_CHANGED")); } }, 2000); } // Register SMS receiver for network initiated configuration if (reconfSMSReceiver == null) { reconfSMSReceiver = new HttpsProvisioningSMS(this); reconfSMSReceiver.registerSmsProvisioningReceiver( Integer.toString(HttpsProvisioningUtils.DEFAULT_SMS_PORT), null, null, null); } // Show a first notification addRcsServiceNotification(false, getString(R.string.rcs_core_loaded)); // Update GSMA client API GsmaUtils.setClientActivationState(getApplicationContext(), true); // Send service intent intent = new Intent(ClientApiIntents.SERVICE_STATUS); intent.putExtra("status", ClientApiIntents.SERVICE_STATUS_STARTED); getApplicationContext().sendBroadcast(intent); if (logger.isActivated()) { logger.info("RCS core service started with success"); } } catch (Exception e) { // Unexpected error if (logger.isActivated()) { logger.error("Can't instanciate the RCS core service", e); } // Send service intent Intent intent = new Intent(ClientApiIntents.SERVICE_STATUS); intent.putExtra("status", ClientApiIntents.SERVICE_STATUS_FAILED); getApplicationContext().sendBroadcast(intent); // Show error in notification bar addRcsServiceNotification(false, getString(R.string.rcs_core_failed)); // Exit service stopSelf(); } }
/** Background processing */ public void run() { try { if (logger.isActivated()) { logger.info("Initiate a new 1-1 chat session as terminating"); } // Send message delivery report if requested if ((ChatUtils.isImdnDeliveredRequested(getDialogPath().getInvite())) || (ChatUtils.isFileTransferOverHttp(getDialogPath().getInvite()))) { // Check notification disposition String msgId = ChatUtils.getMessageId(getDialogPath().getInvite()); if (msgId != null) { // Send message delivery status via a SIP MESSAGE getImdnManager() .sendMessageDeliveryStatusImmediately( getDialogPath().getRemoteParty(), msgId, ImdnDocument.DELIVERY_STATUS_DELIVERED, SipUtils.getRemoteInstanceID(getDialogPath().getInvite())); } } // Check if Auto-accept (FT HTTP force auto-accept for the chat session) if (RcsSettings.getInstance().isChatAutoAccepted() || ChatUtils.getHttpFTInfo(getDialogPath().getInvite()) != null) { if (logger.isActivated()) { logger.info("Auto accept chat invitation"); } } else { if (logger.isActivated()) { logger.info("Accept manually chat invitation"); } // Send a 180 Ringing response send180Ringing(getDialogPath().getInvite(), getDialogPath().getLocalTag()); // Wait invitation answer int answer = waitInvitationAnswer(); if (answer == ImsServiceSession.INVITATION_REJECTED) { if (logger.isActivated()) { logger.info("Session has been rejected by user"); } // Remove the current session getImsService().removeSession(this); // Notify listeners for (int i = 0; i < getListeners().size(); i++) { getListeners().get(i).handleSessionAborted(ImsServiceSession.TERMINATION_BY_USER); } return; } else if (answer == ImsServiceSession.INVITATION_NOT_ANSWERED) { if (logger.isActivated()) { logger.info("Session has been rejected on timeout"); } // Ringing period timeout send486Busy(getDialogPath().getInvite(), getDialogPath().getLocalTag()); // Remove the current session getImsService().removeSession(this); // Notify listeners for (int i = 0; i < getListeners().size(); i++) { getListeners().get(i).handleSessionAborted(ImsServiceSession.TERMINATION_BY_TIMEOUT); } return; } else if (answer == ImsServiceSession.INVITATION_CANCELED) { if (logger.isActivated()) { logger.info("Session has been canceled"); } return; } } // Parse the remote SDP part String remoteSdp = getDialogPath().getInvite().getSdpContent(); SdpParser parser = new SdpParser(remoteSdp.getBytes()); Vector<MediaDescription> media = parser.getMediaDescriptions(); MediaDescription mediaDesc = media.elementAt(0); MediaAttribute attr1 = mediaDesc.getMediaAttribute("path"); String remotePath = attr1.getValue(); String remoteHost = SdpUtils.extractRemoteHost(parser.sessionDescription, mediaDesc); int remotePort = mediaDesc.port; // Extract the "setup" parameter String remoteSetup = "passive"; MediaAttribute attr2 = mediaDesc.getMediaAttribute("setup"); if (attr2 != null) { remoteSetup = attr2.getValue(); } if (logger.isActivated()) { logger.info("Remote setup attribute is " + remoteSetup); } // Set setup mode String localSetup = createSetupAnswer(remoteSetup); if (logger.isActivated()) { logger.debug("Local setup attribute is " + localSetup); } // Set local port int localMsrpPort; if (localSetup.equals("active")) { localMsrpPort = 9; // See RFC4145, Page 4 } else { localMsrpPort = getMsrpMgr().getLocalMsrpPort(); } // Build SDP part String ntpTime = SipUtils.constructNTPtime(System.currentTimeMillis()); String ipAddress = getDialogPath().getSipStack().getLocalIpAddress(); String sdp = null; if (isSecureProtocolMessage()) { sdp = "v=0" + SipUtils.CRLF + "o=- " + ntpTime + " " + ntpTime + " " + SdpUtils.formatAddressType(ipAddress) + SipUtils.CRLF + "s=-" + SipUtils.CRLF + "c=" + SdpUtils.formatAddressType(ipAddress) + SipUtils.CRLF + "t=0 0" + SipUtils.CRLF + "m=message " + localMsrpPort + " " + getMsrpMgr().getLocalSocketProtocol() + " *" + SipUtils.CRLF + "a=accept-types:" + getAcceptTypes() + SipUtils.CRLF + "a=accept-wrapped-types:" + getWrappedTypes() + SipUtils.CRLF + "a=setup:" + localSetup + SipUtils.CRLF + "a=path:" + getMsrpMgr().getLocalMsrpPath() + SipUtils.CRLF + "a=fingerprint:" + KeyStoreManager.getFingerPrint() + SipUtils.CRLF + "a=sendrecv" + SipUtils.CRLF; } else { sdp = "v=0" + SipUtils.CRLF + "o=- " + ntpTime + " " + ntpTime + " " + SdpUtils.formatAddressType(ipAddress) + SipUtils.CRLF + "s=-" + SipUtils.CRLF + "c=" + SdpUtils.formatAddressType(ipAddress) + SipUtils.CRLF + "t=0 0" + SipUtils.CRLF + "m=message " + localMsrpPort + " " + getMsrpMgr().getLocalSocketProtocol() + " *" + SipUtils.CRLF + "a=accept-types:" + getAcceptTypes() + SipUtils.CRLF + "a=accept-wrapped-types:" + getWrappedTypes() + SipUtils.CRLF + "a=setup:" + localSetup + SipUtils.CRLF + "a=path:" + getMsrpMgr().getLocalMsrpPath() + SipUtils.CRLF + "a=sendrecv" + SipUtils.CRLF; } // Set the local SDP part in the dialog path getDialogPath().setLocalContent(sdp); // Test if the session should be interrupted if (isInterrupted()) { if (logger.isActivated()) { logger.info("Session has been interrupted: end of processing"); } return; } // Create the MSRP server session if (localSetup.equals("passive")) { // Passive mode: client wait a connection MsrpSession session = getMsrpMgr().createMsrpServerSession(remotePath, this); session.setFailureReportOption(false); session.setSuccessReportOption(false); // Open the connection Thread thread = new Thread() { public void run() { try { // Open the MSRP session getMsrpMgr().openMsrpSession(); // Send an empty packet sendEmptyDataChunk(); } catch (IOException e) { if (logger.isActivated()) { logger.error("Can't create the MSRP server session", e); } } } }; thread.start(); } // Create a 200 OK response if (logger.isActivated()) { logger.info("Send 200 OK"); } SipResponse resp = null; if (!RcsSettings.getInstance().isCPMSupported()) { resp = SipMessageFactory.create200OkInviteResponse(getDialogPath(), getFeatureTags(), sdp); } else { if (logger.isActivated()) { logger.info("TerminatingFOne2OneSession2 CPMS"); } resp = SipMessageFactory.createCpm200OkInviteResponse( getDialogPath(), getCpimFeatureTags(), sdp); } if (RcsSettings.getInstance().isCPMSupported()) { if (logger.isActivated()) { logger.info("TerminatingFOne2OneSession3 CPMS"); } if (getContributionID() != null) { resp.addHeader(ChatUtils.HEADER_CONTRIBUTION_ID, getContributionID()); } if (getConversationID() != null) { resp.addHeader(ChatUtils.HEADER_CONVERSATION_ID, getConversationID()); } if (getInReplyID() != null) { resp.addHeader(ChatUtils.HEADER_INREPLY_TO_CONTRIBUTION_ID, getInReplyID()); } } // The signalisation is established getDialogPath().sigEstablished(); // Send response SipTransactionContext ctx = getImsService().getImsModule().getSipManager().sendSipMessageAndWait(resp); // Analyze the received response if (ctx.isSipAck()) { // ACK received if (logger.isActivated()) { logger.info("ACK request received"); } // The session is established getDialogPath().sessionEstablished(); // Create the MSRP client session if (localSetup.equals("active")) { // Active mode: client should connect MsrpSession session = getMsrpMgr().createMsrpClientSession(remoteHost, remotePort, remotePath, this); session.setFailureReportOption(false); session.setSuccessReportOption(false); // Open the MSRP session getMsrpMgr().openMsrpSession(); // Send an empty packet sendEmptyDataChunk(); } // Notify listeners for (int i = 0; i < getListeners().size(); i++) { getListeners().get(i).handleSessionStarted(); } if (logger.isActivated()) { logger.info( "ABC ACK request received Dialog expire time: " + getDialogPath().getSessionExpireTime()); } // Start session timer if (getSessionTimerManager().isSessionTimerActivated(resp)) { getSessionTimerManager() .start(SessionTimerManager.UAS_ROLE, getDialogPath().getSessionExpireTime()); } // Start the activity manager getActivityManager().start(); } else { if (logger.isActivated()) { logger.info("No ACK received for INVITE"); } // No response received: timeout handleError(new ChatError(ChatError.SESSION_INITIATION_FAILED)); } } catch (Exception e) { if (logger.isActivated()) { logger.error("Session initiation has failed", e); } // Unexpected error handleError(new ChatError(ChatError.UNEXPECTED_EXCEPTION, e.getMessage())); } }
/** * IMS service session * * @author jexa7410 */ public abstract class ImsServiceSession extends Thread { /** Session invitation status */ public static final int INVITATION_NOT_ANSWERED = 0; public static final int INVITATION_ACCEPTED = 1; public static final int INVITATION_REJECTED = 2; public static final int INVITATION_CANCELED = 3; /** Session termination reason */ public static final int TERMINATION_BY_SYSTEM = 0; public static final int TERMINATION_BY_USER = 1; public static final int TERMINATION_BY_TIMEOUT = 2; /** IMS service */ private ImsService imsService; private NetworkSwitchInfo netSwitchInfo = new NetworkSwitchInfo(); /** Session ID */ private String sessionId = SessionIdGenerator.getNewId(); /** Remote contact */ private String contact; /** Remote display name */ private String remoteDisplayName = null; /** Conversation ID */ private static String mConversationId = "bcc642fe6a5347a64deb882d886c2c7a"; /** Remote display name */ private String remoteGroupDisplayName = null; /** Dialog path */ private SipDialogPath dialogPath = null; /** Authentication agent */ private SessionAuthenticationAgent authenticationAgent; /** Session invitation status */ protected int invitationStatus = INVITATION_NOT_ANSWERED; /** Wait user answer for session invitation */ protected Object waitUserAnswer = new Object(); /** Session listeners */ private Vector<ImsSessionListener> listeners = new Vector<ImsSessionListener>(); /** Session timer manager */ private SessionTimerManager sessionTimer = new SessionTimerManager(this); /** Update session manager */ protected UpdateSessionManager updateMgr; /** Ringing period (in seconds) */ private int ringingPeriod = RcsSettings.getInstance().getRingingPeriod(); /** Session interrupted flag */ private boolean sessionInterrupted = false; /** Session terminated by remote flag */ private boolean sessionTerminatedByRemote = false; /** The logger */ private Logger logger = Logger.getLogger(this.getClass().getName()); /** * Constructor * * @param parent IMS service * @param contact Remote contact */ public ImsServiceSession(ImsService imsService, String contact) { this.imsService = imsService; this.contact = contact; this.authenticationAgent = new SessionAuthenticationAgent(imsService.getImsModule()); this.updateMgr = new UpdateSessionManager(this); } /** Create originating dialog path */ public void createOriginatingDialogPath() { // Set Call-Id String callId = getImsService().getImsModule().getSipManager().getSipStack().generateCallId(); // Set the route path Vector<String> route = getImsService().getImsModule().getSipManager().getSipStack().getServiceRoutePath(); // Create a dialog path dialogPath = new SipDialogPath( getImsService().getImsModule().getSipManager().getSipStack(), callId, 1, getRemoteContact(), ImsModule.IMS_USER_PROFILE.getPublicAddress(), getRemoteContact(), route); // Set the authentication agent in the dialog path dialogPath.setAuthenticationAgent(getAuthenticationAgent()); } /** M: Added to resolve the rich call 403 error.@{ */ /** Create originating dialog path */ public void createOriginatingDialogPath(String callId) { logger.debug("createOriginatingDialogPath(), callId = " + callId); // Set the route path Vector<String> route = getImsService().getImsModule().getSipManager().getSipStack().getServiceRoutePath(); // Create a dialog path dialogPath = new SipDialogPath( getImsService().getImsModule().getSipManager().getSipStack(), callId, 1, getRemoteContact(), ImsModule.IMS_USER_PROFILE.getPublicUri(), getRemoteContact(), route); // Set the authentication agent in the dialog path dialogPath.setAuthenticationAgent(getAuthenticationAgent()); } /** @} */ /** * Create terminating dialog path * * @param invite Incoming invite */ public void createTerminatingDialogPath(SipRequest invite) { // Set the call-id String callId = invite.getCallId(); // Set target String target = invite.getContactURI(); // Set local party String localParty = invite.getTo(); // Set remote party String remoteParty = invite.getFrom(); // Get the CSeq value long cseq = invite.getCSeq(); // Set the route path with the Record-Route Vector<String> route = SipUtils.routeProcessing(invite, false); // Create a dialog path dialogPath = new SipDialogPath( getImsService().getImsModule().getSipManager().getSipStack(), callId, cseq, target, localParty, remoteParty, route); // Set the INVITE request dialogPath.setInvite(invite); // Set the remote tag dialogPath.setRemoteTag(invite.getFromTag()); // Set the remote content part dialogPath.setRemoteContent(invite.getContent()); // Set the session timer expire dialogPath.setSessionExpireTime(invite.getSessionTimerExpire()); } /** * Add a listener for receiving events * * @param listener Listener */ public void addListener(ImsSessionListener listener) { listeners.add(listener); } /** Remove a listener */ public void removeListener(ImsSessionListener listener) { listeners.remove(listener); } /** Remove all listeners */ public void removeListeners() { listeners.removeAllElements(); } /** * Returns the event listeners * * @return Listeners */ public Vector<ImsSessionListener> getListeners() { return listeners; } /** * Get the session timer manager * * @return Session timer manager */ public SessionTimerManager getSessionTimerManager() { return sessionTimer; } /** * Get the update session manager * * @return UpdateSessionManager */ public UpdateSessionManager getUpdateSessionManager() { return updateMgr; } /** * Is behind a NAT * * @return Boolean */ public boolean isBehindNat() { return getImsService().getImsModule().getCurrentNetworkInterface().isBehindNat(); } public boolean isSecureProtocolMessage() { return getImsService().getImsModule().getCurrentNetworkInterface().getIsSecureProtocol(); } /** Start the session in background */ public void startSession() { // Add the session in the session manager imsService.addSession(this); // Start the session start(); } /** * Return the IMS service * * @return IMS service */ public ImsService getImsService() { return imsService; } /** * Return the session ID * * @return Session ID */ public String getSessionID() { return sessionId; } /** * Returns the remote contact * * @return String */ public String getRemoteContact() { return contact; } /** * Returns display name of the remote contact * * @return String */ public String getRemoteDisplayName() { if (getDialogPath() == null) { return remoteDisplayName; } else { return SipUtils.getDisplayNameFromUri(getDialogPath().getInvite().getFrom()); } } /** * Returns display name of the remote contact * * @return String */ public String getGroupRemoteDisplayName() { return remoteGroupDisplayName; } /** * Set display name of the remote contact * * @param String */ public void setGroupRemoteDisplayName(String remoteGroupDisplayName) { this.remoteGroupDisplayName = remoteGroupDisplayName; } /** * Set display name of the remote contact * * @param String */ public void setRemoteDisplayName(String remoteDisplayName) { this.remoteDisplayName = remoteDisplayName; } /** * Get the dialog path of the session * * @return Dialog path object */ public SipDialogPath getDialogPath() { return dialogPath; } /** * Set the dialog path of the session * * @param dialog Dialog path */ public void setDialogPath(SipDialogPath dialog) { dialogPath = dialog; } /** * Returns the authentication agent * * @return Authentication agent */ public SessionAuthenticationAgent getAuthenticationAgent() { return authenticationAgent; } /** * Reject the session invitation * * @param code Error code */ public void rejectSession(int code) { if (logger.isActivated()) { logger.debug("Session invitation has been rejected"); } invitationStatus = INVITATION_REJECTED; // Unblock semaphore synchronized (waitUserAnswer) { waitUserAnswer.notifyAll(); } // Decline the invitation sendErrorResponse(getDialogPath().getInvite(), getDialogPath().getLocalTag(), code); // Remove the session in the session manager imsService.removeSession(this); } /** Accept the session invitation */ public void acceptSession() { if (logger.isActivated()) { logger.debug("Session invitation has been accepted"); } invitationStatus = INVITATION_ACCEPTED; // Unblock semaphore synchronized (waitUserAnswer) { waitUserAnswer.notifyAll(); } } /** * Wait session invitation answer * * @return Answer */ public int waitInvitationAnswer() { if (invitationStatus != INVITATION_NOT_ANSWERED) { return invitationStatus; } if (logger.isActivated()) { logger.info("Wait session invitation answer"); } // Wait until received response or received timeout try { synchronized (waitUserAnswer) { waitUserAnswer.wait(ringingPeriod * 1000); } } catch (InterruptedException e) { if (logger.isActivated()) { logger.info("ABC Wait session invitation answer1"); } sessionInterrupted = true; } return invitationStatus; } /** Interrupt session */ public void interruptSession() { if (logger.isActivated()) { logger.info("ABC Interrupt the session"); } try { // Unblock semaphore synchronized (waitUserAnswer) { waitUserAnswer.notifyAll(); } if (!isSessionInterrupted()) { if (logger.isActivated()) { logger.info("ABC Interrupt the session1"); } // Interrupt thread sessionInterrupted = true; interrupt(); } } catch (Exception e) { if (logger.isActivated()) { logger.error("Can't interrupt the session correctly", e); } } if (logger.isActivated()) { logger.debug("Session has been interrupted"); } } /** M: do not send SIP BYE when timeout to distinguish BOOTED from DEPARTED @{ */ /** Abort the session */ public void abortSessionWithoutBye() { if (logger.isActivated()) { logger.info("abortSessionWithoutBye() entry"); } // Interrupt the session interruptSession(); // Terminate session terminateSessionWithoutBy(); // Close media session closeMediaSession(); // Remove the current session getImsService().removeSession(this); // Notify listeners int size = getListeners().size(); for (int i = 0; i < size; i++) { getListeners().get(i).handleSessionAborted(0); } } /** @} */ /** * Abort the session * * @param reason Termination reason */ public void abortSession(int reason) { if (logger.isActivated()) { logger.info("ABC Abort the session " + reason); if ((netSwitchInfo.get_ims_off_by_network())) { logger.info("ABC Abort the session Network gone"); } } // Interrupt the session interruptSession(); if (!(netSwitchInfo.get_ims_off_by_network()) || !(this instanceof HttpFileTransferSession)) { // Terminate session terminateSession(reason); if (logger.isActivated()) { logger.info("ABC Abort the session " + reason); } // Close media session closeMediaSession(); // Remove the current session getImsService().removeSession(this); // Notify listeners for (int i = 0; i < getListeners().size(); i++) { getListeners().get(i).handleSessionAborted(reason); } if (netSwitchInfo.get_ims_off_by_network()) { netSwitchInfo.reset_ims_off_by_network(); } } if ((this instanceof HttpFileTransferSession)) { ((HttpFileTransferSession) this).pauseFileTransfer(); } } /** M: do not send SIP BYE when timeout to distinguish BOOTED from DEPARTED @{ */ /** Terminate session */ public void terminateSessionWithoutBy() { if (dialogPath.isSessionTerminated()) { // Already terminated return; } // Stop session timer getSessionTimerManager().stop(); // Update dialog path dialogPath.sessionTerminated(); // Unblock semaphore (used for terminating side only) synchronized (waitUserAnswer) { waitUserAnswer.notifyAll(); } } /** * Terminate session * * @param reason Reason */ public void terminateSession(int reason) { if (logger.isActivated()) { logger.debug("Terminate the session (reason " + reason + ")"); } if ((dialogPath == null) || dialogPath.isSessionTerminated()) { // Already terminated return; } // Stop session timer getSessionTimerManager().stop(); // Update dialog path if (reason == ImsServiceSession.TERMINATION_BY_USER) { dialogPath.sessionTerminated(200, "Call completed"); } else { dialogPath.sessionTerminated(); } // Unblock semaphore (used for terminating side only) synchronized (waitUserAnswer) { waitUserAnswer.notifyAll(); } try { // Terminate the session if (dialogPath.isSigEstablished()) { // Increment the Cseq number of the dialog path getDialogPath().incrementCseq(); // Send BYE without waiting a response getImsService().getImsModule().getSipManager().sendSipBye(getDialogPath()); } else { // Send CANCEL without waiting a response getImsService().getImsModule().getSipManager().sendSipCancel(getDialogPath()); } if (logger.isActivated()) { logger.debug("SIP session has been terminated"); } } catch (Exception e) { if (logger.isActivated()) { logger.error("Session termination has failed", e); } } if (this.getDialogPath().isSigEstablished() && reason != ImsServiceSession.TERMINATION_BY_USER) { for (int j = 0; j < getListeners().size(); j++) { final ImsSessionListener listener = getListeners().get(j); if (listener instanceof FileSharingSessionListener) { AsyncTask.execute( new Runnable() { @Override public void run() { try { Thread.sleep(3 * 1000); } catch (InterruptedException e) { // Nothing to do } ((FileSharingSessionListener) listener) .handleTransferError( new FileSharingError(FileSharingError.MEDIA_TRANSFER_FAILED)); } }); } } } } /** * Receive BYE request * * @param bye BYE request */ public void receiveBye(SipRequest bye) { if (logger.isActivated()) { logger.info("ABC Receive a BYE message from the remote"); } // Close media session closeMediaSession(); // Update the dialog path status getDialogPath().sessionTerminated(); sessionTerminatedByRemote = true; // Remove the current session getImsService().removeSession(this); // Stop session timer getSessionTimerManager().stop(); // Notify listeners for (int i = 0; i < getListeners().size(); i++) { getListeners().get(i).handleSessionTerminatedByRemote(); } } /** * Receive CANCEL request * * @param cancel CANCEL request */ public void receiveCancel(SipRequest cancel) { if (logger.isActivated()) { logger.info("ABC Receive a CANCEL message from the remote"); } if (getDialogPath().isSigEstablished()) { if (logger.isActivated()) { logger.info( "Ignore the received CANCEL message from the remote (session already established)"); } return; } // Close media session closeMediaSession(); // Update dialog path getDialogPath().sessionCancelled(); // Send a 487 Request terminated try { if (logger.isActivated()) { logger.info("Send 487 Request terminated"); } SipResponse terminatedResp = SipMessageFactory.createResponse( getDialogPath().getInvite(), getDialogPath().getLocalTag(), 487); getImsService().getImsModule().getSipManager().sendSipResponse(terminatedResp); } catch (Exception e) { if (logger.isActivated()) { logger.error("Can't send 487 error response", e); } } // Remove the current session getImsService().removeSession(this); // Set invitation status invitationStatus = ImsServiceSession.INVITATION_CANCELED; // Unblock semaphore synchronized (waitUserAnswer) { waitUserAnswer.notifyAll(); } // Notify listeners for (int i = 0; i < getListeners().size(); i++) { getListeners().get(i).handleSessionTerminatedByRemote(); } // Request capabilities to the remote getImsService() .getImsModule() .getCapabilityService() .requestContactCapabilities(getDialogPath().getRemoteParty()); } /** * Receive re-INVITE request * * @param reInvite re-INVITE request */ public void receiveReInvite(SipRequest reInvite) { // Session refresh management sessionTimer.receiveReInvite(reInvite); } /** * Receive UPDATE request * * @param update UPDATE request */ public void receiveUpdate(SipRequest update) { sessionTimer.receiveUpdate(update); } /** * Prepare media session * * @throws Exception */ public abstract void prepareMediaSession() throws Exception; // public abstract void setMsrpFtSupport(boolean ftSupport); /** * Start media session * * @throws Exception */ public abstract void startMediaSession() throws Exception; /** Close media session */ public abstract void closeMediaSession(); /** * Send a 180 Ringing response to the remote party * * @param request SIP request * @param localTag Local tag */ public void send180Ringing(SipRequest request, String localTag) { try { SipResponse progress = SipMessageFactory.createResponse(request, localTag, 180); getImsService().getImsModule().getSipManager().sendSipResponse(progress); } catch (Exception e) { if (logger.isActivated()) { logger.error("Can't send a 180 Ringing response"); } } } /** * Send an error response to the remote party * * @param request SIP request * @param localTag Local tag * @param code Response code */ public void sendErrorResponse(SipRequest request, String localTag, int code) { try { // Send error if (logger.isActivated()) { logger.info("Send " + code + " error response"); } SipResponse resp = SipMessageFactory.createResponse(request, localTag, code); getImsService().getImsModule().getSipManager().sendSipResponse(resp); } catch (Exception e) { if (logger.isActivated()) { logger.error("Can't send error response", e); } } } /** * Send a 603 "Decline" to the remote party * * @param request SIP request * @param localTag Local tag */ public void send603Decline(SipRequest request, String localTag) { try { // Send a 603 Decline error if (logger.isActivated()) { logger.info("Send 603 Decline"); } SipResponse resp = SipMessageFactory.createResponse(request, localTag, 603); getImsService().getImsModule().getSipManager().sendSipResponse(resp); } catch (Exception e) { if (logger.isActivated()) { logger.error("Can't send 603 Decline response", e); } } } /** * Send a 486 "Busy" to the remote party * * @param request SIP request * @param localTag Local tag */ public void send486Busy(SipRequest request, String localTag) { try { // Send a 486 Busy error if (logger.isActivated()) { logger.info("Send 486 Busy"); } SipResponse resp = SipMessageFactory.createResponse(request, localTag, 486); getImsService().getImsModule().getSipManager().sendSipResponse(resp); } catch (Exception e) { if (logger.isActivated()) { logger.error("Can't send 486 Busy response", e); } } } /** * Send a 415 "Unsupported Media Type" to the remote party * * @param request SIP request */ public void send415Error(SipRequest request) { try { if (logger.isActivated()) { logger.info("Send 415 Unsupported Media Type"); } SipResponse resp = SipMessageFactory.createResponse(request, 415); // TODO: set Accept-Encoding header getImsService().getImsModule().getSipManager().sendSipResponse(resp); } catch (Exception e) { if (logger.isActivated()) { logger.error("Can't send 415 error response", e); } } } /** * Create SDP setup offer (see RFC6135, RFC4145) * * @return Setup offer */ public String createSetupOffer() { if (isBehindNat()) { // Active mode by default if there is a NAT return "active"; } else { // Active/passive mode is exchanged in order to be compatible // with UE not supporting COMEDIA return "actpass"; } } /** * Create SDP setup offer for mobile to mobile (see RFC6135, RFC4145) * * @return Setup offer */ public String createMobileToMobileSetupOffer() { // Always active mode proposed here return "active"; } /** * Create SDP setup answer (see RFC6135, RFC4145) * * @param offer setup offer * @return Setup answer ("active" or "passive") */ public String createSetupAnswer(String offer) { if (offer.equals("actpass")) { // Active mode by default if there is a NAT or AS IM return "active"; } else if (offer.equals("active")) { // Passive mode return "passive"; } else if (offer.equals("passive")) { // Active mode return "active"; } else { // Passive mode by default return "passive"; } } /** * Returns the response timeout (in seconds) * * @return Timeout */ public int getResponseTimeout() { return ringingPeriod + SipManager.TIMEOUT; } /** * Is session interrupted * * @return Boolean */ public boolean isSessionInterrupted() { if (sessionInterrupted) { if (logger.isActivated()) { logger.info("ABC isSessionInterrupted1"); } } if (isInterrupted()) { if (logger.isActivated()) { logger.info("ABC isSessionInterrupted2"); } } if (getDialogPath() != null && getDialogPath().isSessionTerminated()) { if (logger.isActivated()) { logger.info("ABC isSessionInterrupted3"); } } return sessionInterrupted || isInterrupted() || (getDialogPath() != null && getDialogPath().isSessionTerminated()); } /** * Is session terminated by remote * * @return Boolean */ public boolean isSessionTerminatedByRemote() { return sessionTerminatedByRemote; } /** * Create an INVITE request * * @return the INVITE request * @throws SipException */ public abstract SipRequest createInvite() throws SipException; /** * Send INVITE message * * @param invite SIP INVITE * @throws SipException */ public void sendInvite(SipRequest invite) throws SipException { // Send INVITE request SipTransactionContext ctx = getImsService() .getImsModule() .getSipManager() .sendSipMessageAndWait(invite, getResponseTimeout()); // Analyze the received response if (ctx.isSipResponse()) { // A response has been received if (ctx.getStatusCode() == 200) { // 200 OK handle200OK(ctx.getSipResponse()); } else if (ctx.getStatusCode() == 404) { // 404 session not found handle404SessionNotFound(ctx.getSipResponse()); } else if (ctx.getStatusCode() == 407) { // 407 Proxy Authentication Required handle407Authentication(ctx.getSipResponse()); } else if (ctx.getStatusCode() == 422) { // 422 Session Interval Too Small handle422SessionTooSmall(ctx.getSipResponse()); } else if (ctx.getStatusCode() == 480) { // 480 Temporarily Unavailable handle480Unavailable(ctx.getSipResponse()); } else if (ctx.getStatusCode() == 486) { // 486 busy handle486Busy(ctx.getSipResponse()); } else if (ctx.getStatusCode() == 487) { // 487 Invitation cancelled handle487Cancel(ctx.getSipResponse()); } else { if (ctx.getStatusCode() == 603) { // 603 Invitation declined handle603Declined(ctx.getSipResponse()); } else // Other error response handleDefaultError(ctx.getSipResponse()); } } else { // No response received: timeout handleError( new ImsSessionBasedServiceError( ImsSessionBasedServiceError.SESSION_INITIATION_FAILED, "timeout")); } } /** * Handle 200 0K response * * @param resp 200 OK response */ public void handle200OK(SipResponse resp) { try { // 200 OK received if (logger.isActivated()) { logger.info("200 OK response received"); } // The signaling is established getDialogPath().sigEstablished(); // Set the remote tag getDialogPath().setRemoteTag(resp.getToTag()); // Set the target getDialogPath().setTarget(resp.getContactURI()); // Set the route path with the Record-Route header Vector<String> newRoute = SipUtils.routeProcessing(resp, true); getDialogPath().setRoute(newRoute); // Set the remote SDP part getDialogPath().setRemoteContent(resp.getContent()); Capabilities capabilities = CapabilityUtils.extractCapabilities(resp); if (capabilities != null && this instanceof GroupChatSession) { ((GroupChatSession) this).setMsrpFtSupport(capabilities.isFileTransferSupported()); } // Set the remote SIP instance ID ContactHeader remoteContactHeader = (ContactHeader) resp.getHeader(ContactHeader.NAME); if (remoteContactHeader != null) { getDialogPath() .setRemoteSipInstance(remoteContactHeader.getParameter(SipUtils.SIP_INSTANCE_PARAM)); } // Prepare Media Session prepareMediaSession(); // Send ACK request if (logger.isActivated()) { logger.info("Send ACK"); } getImsService().getImsModule().getSipManager().sendSipAck(getDialogPath()); // The session is established getDialogPath().sessionEstablished(); // Start Media Session startMediaSession(); // Notify listeners for (int i = 0; i < getListeners().size(); i++) { getListeners().get(i).handleSessionStarted(); } // Start session timer if (getSessionTimerManager().isSessionTimerActivated(resp)) { getSessionTimerManager() .start(resp.getSessionTimerRefresher(), resp.getSessionTimerExpire()); } } catch (Exception e) { // Unexpected error if (logger.isActivated()) { logger.error("Session initiation has failed", e); } handleError(new ImsServiceError(ImsServiceError.UNEXPECTED_EXCEPTION, e.getMessage())); } } /** * Handle default error * * @param resp Error response */ public void handleDefaultError(SipResponse resp) { // Default handle handleError( new ImsSessionBasedServiceError( ImsSessionBasedServiceError.SESSION_INITIATION_FAILED, resp.getStatusCode() + " " + resp.getReasonPhrase())); } /** M: Added to resolve the rich call 403 error.@{ */ /** * Handle 403 error. First do re-register then send request again * * @param request The request was responded with 403 */ public void handle403Forbidden(SipResponse resp) { if (logger.isActivated()) { logger.debug("handle403Forbidden() entry"); } boolean isRegistered = imsService .getImsModule() .getCurrentNetworkInterface() .getRegistrationManager() .registration(); if (logger.isActivated()) { logger.debug("re-register isRegistered: " + isRegistered); } if (isRegistered) { String callId = dialogPath.getCallId(); SipRequest invite = createSipInvite(callId); if (invite != null) { try { sendInvite(invite); } catch (SipException e) { if (logger.isActivated()) { logger.debug("re send sip request failed."); } e.printStackTrace(); } } else { if (logger.isActivated()) { logger.debug("handle403Forbidden() invite is null"); } } } if (logger.isActivated()) { logger.debug("handle403Forbidden() exit"); } handleDefaultError(resp); } /** * Handle 403 Forbidden * * @param resp 403 response */ // public void handle403Forbidden(SipResponse resp) { // handleDefaultError(resp); // } /** * Handle 404 Session Not Found * * @param resp 404 response */ public void handle404SessionNotFound(SipResponse resp) { handleDefaultError(resp); } /** * Handle 407 Proxy Authentication Required * * @param resp 407 response */ public void handle407Authentication(SipResponse resp) { try { if (logger.isActivated()) { logger.info("407 response received"); } // Set the remote tag getDialogPath().setRemoteTag(resp.getToTag()); // Update the authentication agent getAuthenticationAgent().readProxyAuthenticateHeader(resp); // Increment the Cseq number of the dialog path getDialogPath().incrementCseq(); // Create the invite request SipRequest invite = createInvite(); // Reset initial request in the dialog path getDialogPath().setInvite(invite); // Set the Proxy-Authorization header getAuthenticationAgent().setProxyAuthorizationHeader(invite); // Send INVITE request sendInvite(invite); } catch (Exception e) { if (logger.isActivated()) { logger.error("Session initiation has failed", e); } // Unexpected error handleError(new ImsServiceError(ImsServiceError.UNEXPECTED_EXCEPTION, e.getMessage())); } } /** * Handle 422 response * * @param resp 422 response */ public void handle422SessionTooSmall(SipResponse resp) { try { // 422 response received if (logger.isActivated()) { logger.info("422 response received"); } // Extract the Min-SE value int minExpire = SipUtils.getMinSessionExpirePeriod(resp); if (minExpire == -1) { if (logger.isActivated()) { logger.error("Can't read the Min-SE value"); } handleError( new ImsSessionBasedServiceError( ImsSessionBasedServiceError.UNEXPECTED_EXCEPTION, "No Min-SE value found")); return; } // Set the min expire value getDialogPath().setMinSessionExpireTime(minExpire); // Set the expire value getDialogPath().setSessionExpireTime(minExpire); // Increment the Cseq number of the dialog path getDialogPath().incrementCseq(); // Create a new INVITE with the right expire period if (logger.isActivated()) { logger.info("Send new INVITE"); } SipRequest invite = createInvite(); // Set the Authorization header getAuthenticationAgent().setAuthorizationHeader(invite); // Reset initial request in the dialog path getDialogPath().setInvite(invite); // Send INVITE request sendInvite(invite); } catch (Exception e) { if (logger.isActivated()) { logger.error("Session initiation has failed", e); } // Unexpected error handleError( new ImsSessionBasedServiceError( ImsSessionBasedServiceError.UNEXPECTED_EXCEPTION, e.getMessage())); } } protected SipRequest createSipInvite(String callId) { logger.debug("ImsServiceSession::createSipInvite(), do nothing in the parent class"); return null; } /** * Handle 480 Temporarily Unavailable * * @param resp 480 response */ public void handle480Unavailable(SipResponse resp) { handleDefaultError(resp); } /** * Handle 486 Busy * * @param resp 486 response */ public void handle486Busy(SipResponse resp) { handleDefaultError(resp); } /** * Handle 487 Cancel * * @param resp 487 response */ public void handle487Cancel(SipResponse resp) { handleError( new ImsSessionBasedServiceError( ImsSessionBasedServiceError.SESSION_INITIATION_CANCELLED, resp.getStatusCode() + " " + resp.getReasonPhrase())); } /** * Handle 603 Decline * * @param resp 603 response */ public void handle603Declined(SipResponse resp) { handleError( new ImsSessionBasedServiceError( ImsSessionBasedServiceError.SESSION_INITIATION_DECLINED, resp.getStatusCode() + " " + resp.getReasonPhrase())); } /** * Handle Error * * @param error ImsServiceError */ public abstract void handleError(ImsServiceError error); /** * Handle ReInvite Sip Response * * @param response Sip response to reInvite * @param int code response code * @param reInvite reInvite SIP request */ public void handleReInviteResponse(int code, SipResponse response, int requestType) {} /** * Handle User Answer in Response to Session Update notification * * @param int code response code * @param reInvite reInvite SIP request */ public void handleReInviteUserAnswer(int code, int requestType) {} /** * Handle ACK sent in Response to 200Ok ReInvite * * @param int code response code * @param reInvite reInvite SIP request */ public void handleReInviteAck(int code, int requestType) {} /** * Handle 407 Proxy Authent error ReInvite Response * * @param response reInvite SIP response * @param int requestType service context of reInvite */ public void handleReInvite407ProxyAuthent(SipResponse response, int serviceContext) {} public String buildReInviteSdpResponse(SipRequest ReInvite, int serviceContext) { return null; } }