@Override public void addContent(Request notifyRequest, SubscriptionRequest request) throws ParseException, InvalidArgumentException { String content = new String(request.getRequest().getRawContent(), StandardCharsets.UTF_8); UserPresence presence = presenceService.getPresence(request.getUser()); if (isEmpty(content)) { ContentTypeHeader contentTypeHeader = headerFactory.createContentTypeHeader("multipart", "mixed"); contentTypeHeader.setParameter(MultipartMimeContentImpl.BOUNDARY, SIPR_BOUNDARY); notifyRequest.setContent( getInitialMultipartContent(contentTypeHeader, presence).toString(), contentTypeHeader); } else { String eventResponse = getEventResponse(presence, content); presenceService.savePresence(presence); ContentTypeHeader eventHeader = getAsFeatureEventHeader(); notifyRequest.setContent(eventResponse, eventHeader); sender.sendNotifyToAllSubscribers(request, eventHeader, eventResponse); } }
/** * Process a request from a distant contact * * @param requestEvent the <tt>RequestEvent</tt> containing the newly received request. * @return <tt>true</tt> if the specified event has been handled by this processor and shouldn't * be offered to other processors registered for the same method; <tt>false</tt>, otherwise */ @Override public boolean processRequest(RequestEvent requestEvent) { synchronized (messageProcessors) { for (SipMessageProcessor listener : messageProcessors) if (!listener.processMessage(requestEvent)) return true; } // get the content String content = null; Request req = requestEvent.getRequest(); try { content = new String(req.getRawContent(), getCharset(req)); } catch (UnsupportedEncodingException ex) { if (logger.isDebugEnabled()) logger.debug("failed to convert the message charset"); content = new String(requestEvent.getRequest().getRawContent()); } // who sent this request ? FromHeader fromHeader = (FromHeader) requestEvent.getRequest().getHeader(FromHeader.NAME); if (fromHeader == null) { logger.error("received a request without a from header"); return false; } Contact from = opSetPersPresence.resolveContactID(fromHeader.getAddress().getURI().toString()); ContentTypeHeader ctheader = (ContentTypeHeader) req.getHeader(ContentTypeHeader.NAME); String ctype = null; String cencoding = null; if (ctheader == null) { ctype = DEFAULT_MIME_TYPE; } else { ctype = ctheader.getContentType() + "/" + ctheader.getContentSubType(); cencoding = ctheader.getParameter("charset"); } if (cencoding == null) cencoding = DEFAULT_MIME_ENCODING; Message newMessage = createMessage(content, ctype, cencoding, null); if (from == null) { if (logger.isDebugEnabled()) logger.debug( "received a message from an unknown contact: " + fromHeader.getAddress().getURI().toString()); // create the volatile contact from = opSetPersPresence.createVolatileContact(fromHeader.getAddress().getURI().toString()); } // answer ok try { Response ok = sipProvider.getMessageFactory().createResponse(Response.OK, requestEvent.getRequest()); SipStackSharing.getOrCreateServerTransaction(requestEvent).sendResponse(ok); } catch (ParseException exc) { logger.error("failed to build the response", exc); } catch (SipException exc) { logger.error("failed to send the response : " + exc.getMessage(), exc); } catch (InvalidArgumentException exc) { if (logger.isDebugEnabled()) logger.debug("Invalid argument for createResponse : " + exc.getMessage(), exc); } // fire an event MessageReceivedEvent msgReceivedEvt = new MessageReceivedEvent(newMessage, from, System.currentTimeMillis()); fireMessageEvent(msgReceivedEvt); return true; }
/** * Construct a <tt>Request</tt> represent a new message. * * @param to the <tt>Contact</tt> to send <tt>message</tt> to * @param message the <tt>Message</tt> to send. * @return a Message Request destined to the contact * @throws OperationFailedException if an error occurred during the creation of the request */ Request createMessageRequest(Contact to, Message message) throws OperationFailedException { Address toAddress = null; try { toAddress = sipProvider.parseAddressString(to.getAddress()); } catch (ParseException exc) { // Shouldn't happen logger.error("An unexpected error occurred while" + "constructing the address", exc); throw new OperationFailedException( "An unexpected error occurred while" + "constructing the address", OperationFailedException.INTERNAL_ERROR, exc); } // Call ID CallIdHeader callIdHeader = this.sipProvider.getDefaultJainSipProvider().getNewCallId(); // CSeq CSeqHeader cSeqHeader = null; try { // protect seqN synchronized (this) { cSeqHeader = this.sipProvider.getHeaderFactory().createCSeqHeader(seqN++, Request.MESSAGE); } } catch (InvalidArgumentException ex) { // Shouldn't happen logger.error("An unexpected error occurred while" + "constructing the CSeqHeadder", ex); throw new OperationFailedException( "An unexpected error occurred while" + "constructing the CSeqHeadder", OperationFailedException.INTERNAL_ERROR, ex); } catch (ParseException exc) { // shouldn't happen logger.error("An unexpected error occurred while" + "constructing the CSeqHeadder", exc); throw new OperationFailedException( "An unexpected error occurred while" + "constructing the CSeqHeadder", OperationFailedException.INTERNAL_ERROR, exc); } // FromHeader and ToHeader String localTag = SipMessageFactory.generateLocalTag(); FromHeader fromHeader = null; ToHeader toHeader = null; try { // FromHeader fromHeader = this.sipProvider .getHeaderFactory() .createFromHeader(sipProvider.getOurSipAddress(toAddress), localTag); // ToHeader toHeader = this.sipProvider.getHeaderFactory().createToHeader(toAddress, null); } catch (ParseException ex) { // these two should never happen. logger.error( "An unexpected error occurred while" + "constructing the FromHeader or ToHeader", ex); throw new OperationFailedException( "An unexpected error occurred while" + "constructing the FromHeader or ToHeader", OperationFailedException.INTERNAL_ERROR, ex); } // ViaHeaders ArrayList<ViaHeader> viaHeaders = this.sipProvider.getLocalViaHeaders(toAddress); // MaxForwards MaxForwardsHeader maxForwards = this.sipProvider.getMaxForwardsHeader(); // Content params ContentTypeHeader contTypeHeader; ContentLengthHeader contLengthHeader; try { contTypeHeader = this.sipProvider .getHeaderFactory() .createContentTypeHeader(getType(message), getSubType(message)); if (!DEFAULT_MIME_ENCODING.equalsIgnoreCase(message.getEncoding())) contTypeHeader.setParameter("charset", message.getEncoding()); contLengthHeader = this.sipProvider.getHeaderFactory().createContentLengthHeader(message.getSize()); } catch (ParseException ex) { // these two should never happen. logger.error("An unexpected error occurred while" + "constructing the content headers", ex); throw new OperationFailedException( "An unexpected error occurred while" + "constructing the content headers", OperationFailedException.INTERNAL_ERROR, ex); } catch (InvalidArgumentException exc) { // these two should never happen. logger.error( "An unexpected error occurred while" + "constructing the content length header", exc); throw new OperationFailedException( "An unexpected error occurred while" + "constructing the content length header", OperationFailedException.INTERNAL_ERROR, exc); } Request req; try { req = this.sipProvider .getMessageFactory() .createRequest( toHeader.getAddress().getURI(), Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader, toHeader, viaHeaders, maxForwards, contTypeHeader, message.getRawData()); } catch (ParseException ex) { // shouldn't happen logger.error("Failed to create message Request!", ex); throw new OperationFailedException( "Failed to create message Request!", OperationFailedException.INTERNAL_ERROR, ex); } req.addHeader(contLengthHeader); return req; }
public void onPublishEvent(RequestEvent event, ActivityContextInterface aci) { if (isTraceable(TraceLevel.FINEST)) { finest("onPublishEvent: PublishSbb received request:\n" + event.getRequest()); } Request request = event.getRequest(); ServerTransaction st = event.getServerTransaction(); String sipAddress = getCanonicalAddress(((ToHeader) request.getHeader(ToHeader.NAME)).getAddress().getURI()); // Check that the resource identified by the request-URI is one that this server is responsible // for // This will be achieved by checking that the resource has been registered with the Registrar try { if (getLocationService().getRegistration(sipAddress) == null) { sendErrorResponse( Response.NOT_FOUND, "Presentity identified by Request-URI '" + sipAddress + "' not registered with Registrar", st, request); return; } } catch (CreateException e) { warn("Error creating location service: ", e); } // Check that the event package is correct - should be 'presence' if (request.getHeader(EventHeader.NAME) != null) { String eventType = ((EventHeader) request.getHeader(EventHeader.NAME)).getEventType(); if (!eventType.equals("presence")) { sendErrorResponse( Response.BAD_EVENT, "PUBLISH request received with incorrect event package, package was '" + eventType + "', expected 'presence'", st, request); return; } } // Check for and validate SIP-If-Match header String eTag = null; String newETag = (new Integer((int) (Math.random() * 10000))).toString(); if ((SIPIfMatchHeader) request.getHeader(SIPIfMatchHeader.NAME) != null) { // Found a SIP-If-Match header, retrieve E-Tag SIPIfMatchHeader sipIfMatchHeader = (SIPIfMatchHeader) request.getHeader(SIPIfMatchHeader.NAME); eTag = sipIfMatchHeader.getETag(); if (isTraceable(TraceLevel.FINEST)) { finest("onPublishEvent: found E-Tag: " + eTag); } // Check that the entity-tag matches an entity-tag stored by the server if (!entityTagIsKnownByServer(sipAddress, eTag)) { if (isTraceable(TraceLevel.FINEST)) { finest("onPublishEvent: E-Tag '" + eTag + "' not recognised by server"); } sendErrorResponse( Response.CONDITIONAL_REQUEST_FAILED, "Entity-tag is not known to this server, value of entity-tag is: " + eTag, st, request); return; } } // Validate requested Expiry time long expiryTime = validateExpireTime(request); // Check for correct media type if (request.getContent() != null && request.getHeader(ContentTypeHeader.NAME) != null) { ContentTypeHeader contentTypeHeader = (ContentTypeHeader) request.getHeader(ContentTypeHeader.NAME); if (!contentTypeHeader.getContentType().equalsIgnoreCase("application") || (!contentTypeHeader.getContentSubType().equalsIgnoreCase("pidf+xml"))) { sendErrorResponse(Response.UNSUPPORTED_MEDIA_TYPE, "Uncrecognised media type", st, request); return; } } // Process the PUBLISH request String body = request.toString(); if (expiryTime == 0) { // this is a request to remove all stored presence information associated with this entity-tag if (eTag == null) { // this is a mal-formed request - can't remove presence information if it was never // published in the first place! sendErrorResponse( Response.BAD_REQUEST, "Received request to remove presence information, but no entity-tag was provided", st, request); return; } else { updatePresenceState( sipAddress, newETag, eTag, body, System.currentTimeMillis(), new Long(expiryTime)); } } else { // this is either an initial request, or a request to modify or refresh a previous publication // get the body of PUBLISH request, if it has one if (eTag == null) { // this an initial request, make sure there's a body containing some presence info if (request.getContent() != null) { updatePresenceState( sipAddress, newETag, null, body, System.currentTimeMillis(), System.currentTimeMillis() + (expiryTime * 1000)); } else { sendErrorResponse( Response.BAD_REQUEST, "Received initial PUBLISH request, but no presence information was provided", st, request); return; } } else { // this is either a request to refresh the publication (no body), or to modify or refresh // the published presence info updatePresenceState( sipAddress, newETag, eTag, (body != null ? body.toString() : null), System.currentTimeMillis(), System.currentTimeMillis() + (expiryTime * 1000)); } } // if this point is reached, all processing has been successfully undertaken, so return a 200 OK // response sendOkResponse(st, request, (int) expiryTime, newETag); }
public void sendMessage( String localSipURL, String remoteSipURL, String text, ChatSession chatSession) { try { DebugIM.println("IMMessageProcessing, ChatSession:" + chatSession); DebugIM.println("Sending a MESSAGE in progress to " + remoteSipURL); SipProvider sipProvider = imUA.getSipProvider(); MessageFactory messageFactory = imUA.getMessageFactory(); HeaderFactory headerFactory = imUA.getHeaderFactory(); AddressFactory addressFactory = imUA.getAddressFactory(); String proxyAddress = imUA.getProxyAddress(); SipURI requestURI = null; if (proxyAddress != null) { requestURI = addressFactory.createSipURI(null, proxyAddress); requestURI.setPort(imUA.getProxyPort()); requestURI.setTransportParam(imUA.getIMProtocol()); } else { requestURI = (SipURI) addressFactory.createURI(remoteSipURL); requestURI.setTransportParam(imUA.getIMProtocol()); } // Call-Id: CallIdHeader callIdHeader = null; // CSeq: CSeqHeader cseqHeader = null; // To header: ToHeader toHeader = null; // From Header: FromHeader fromHeader = null; // Via header String branchId = Utils.generateBranchId(); ViaHeader viaHeader = headerFactory.createViaHeader( imUA.getIMAddress(), imUA.getIMPort(), imUA.getIMProtocol(), branchId); Vector viaList = new Vector(); viaList.addElement(viaHeader); // MaxForwards header: MaxForwardsHeader maxForwardsHeader = headerFactory.createMaxForwardsHeader(70); Dialog dialog = chatSession.getDialog(); if (chatSession.isEstablishedSession()) { DebugIM.println( "DEBUG, IMMessageProcessing, sendMessage(), we get" + " the DIALOG from the ChatSession"); Address localAddress = dialog.getLocalParty(); Address remoteAddress = dialog.getRemoteParty(); // if (dialog.isServer()) { // We received the first MESSAGE fromHeader = headerFactory.createFromHeader(localAddress, dialog.getLocalTag()); toHeader = headerFactory.createToHeader(remoteAddress, dialog.getRemoteTag()); // } // else { // } int cseq = dialog.getLocalSequenceNumber(); DebugIM.println("the cseq number got from the dialog:" + cseq); cseqHeader = headerFactory.createCSeqHeader(cseq, "MESSAGE"); callIdHeader = dialog.getCallId(); } else { DebugIM.println( "DEBUG, IMMessageProcessing, sendMessage(), the " + " session has not been established yet! We create the first message"); // To header: Address toAddress = addressFactory.createAddress(remoteSipURL); // From Header: Address fromAddress = addressFactory.createAddress(localSipURL); // We have to initiate the dialog: means to create the From tag String localTag = Utils.generateTag(); fromHeader = headerFactory.createFromHeader(fromAddress, localTag); toHeader = headerFactory.createToHeader(toAddress, null); // CSeq: cseqHeader = headerFactory.createCSeqHeader(1, "MESSAGE"); // Call-ID: callIdCounter++; callIdHeader = (CallIdHeader) headerFactory.createCallIdHeader("nist-sip-im-message-callId" + callIdCounter); } // Content-Type: ContentTypeHeader contentTypeHeader = headerFactory.createContentTypeHeader("text", "plain"); contentTypeHeader.setParameter("charset", "UTF-8"); Request request = messageFactory.createRequest( requestURI, "MESSAGE", callIdHeader, cseqHeader, fromHeader, toHeader, viaList, maxForwardsHeader, contentTypeHeader, text); // Contact header: SipURI sipURI = addressFactory.createSipURI(null, imUA.getIMAddress()); sipURI.setPort(imUA.getIMPort()); sipURI.setTransportParam(imUA.getIMProtocol()); Address contactAddress = addressFactory.createAddress(sipURI); ContactHeader contactHeader = headerFactory.createContactHeader(contactAddress); request.setHeader(contactHeader); // ProxyAuthorization header if not null: ProxyAuthorizationHeader proxyAuthHeader = imUA.getProxyAuthorizationHeader(); if (proxyAuthHeader != null) request.setHeader(proxyAuthHeader); ClientTransaction clientTransaction = sipProvider.getNewClientTransaction(request); if (chatSession.isEstablishedSession()) { dialog.sendRequest(clientTransaction); DebugIM.println( "IMessageProcessing, sendMessage(), MESSAGE sent" + " using the dialog:\n" + request); } else { clientTransaction.sendRequest(); DebugIM.println( "IMessageProcessing, sendMessage(), MESSAGE sent" + " using a new client transaction:\n" + request); } } catch (Exception ex) { ex.printStackTrace(); } }
/** * Starts the process of handling a new sip subscription * * @param event * @param aci * @param eventPackage * @param eventId * @param expires * @param entityManager * @param childSbb */ public void newSipSubscription( RequestEvent event, ActivityContextInterface aci, String eventPackage, String eventId, int expires, SubscriptionControlDataSource dataSource, ImplementedSubscriptionControlSbbLocalObject childSbb) { // get subscription data from request Address fromAddress = ((FromHeader) event.getRequest().getHeader(FromHeader.NAME)).getAddress(); String subscriber = fromAddress.getURI().toString(); String subscriberDisplayName = fromAddress.getDisplayName(); Notifier notifier = new Notifier(event.getRequest().getRequestURI().toString()); // get content String content = null; String contentType = null; String contentSubtype = null; ContentTypeHeader contentTypeHeader = (ContentTypeHeader) event.getRequest().getHeader(ContentTypeHeader.NAME); if (contentTypeHeader != null) { contentType = contentTypeHeader.getContentType(); contentSubtype = contentTypeHeader.getContentSubType(); content = new String(event.getRequest().getRawContent()); } // create dialog if does not exists Dialog dialog = event.getDialog(); if (dialog == null) { try { dialog = sipSubscriptionHandler.sbb.getSipProvider().getNewDialog(event.getServerTransaction()); } catch (Exception e) { tracer.severe("Can't create dialog", e); // cleanup try { Response response = sipSubscriptionHandler .sbb .getMessageFactory() .createResponse(Response.SERVER_INTERNAL_ERROR, event.getRequest()); response = sipSubscriptionHandler.addContactHeader(response); event.getServerTransaction().sendResponse(response); } catch (Exception f) { tracer.severe("Can't send RESPONSE", f); } return; } } // if dialog id is null (cause it's a new dialog and no response was sent yet) then build it // manually String dialogId = dialog.getDialogId() != null ? dialog.getDialogId() : ((SIPRequest) event.getRequest()).getDialogId(true, dialog.getLocalTag()); SubscriptionKey key = new SubscriptionKey(dialogId, eventPackage, eventId); if (sipSubscriptionHandler.sbb.getConfiguration().getEventListSupportOn()) { // we need to find out if the notifier is a resource list int rlsResponse = sipSubscriptionHandler .sbb .getEventListSubscriptionHandler() .validateSubscribeRequest(subscriber, notifier, eventPackage, event); switch (rlsResponse) { case Response.NOT_FOUND: // the notifier is not a resource list, proceed with normal authorization means authorizeNewSipSubscription( event, aci, subscriber, subscriberDisplayName, notifier, key, expires, content, contentType, contentSubtype, false, dataSource, childSbb); break; case Response.OK: // the notifier is a resource list authorizeNewSipSubscription( event, aci, subscriber, subscriberDisplayName, notifier, key, expires, content, contentType, contentSubtype, true, dataSource, childSbb); break; default: // the rls request validation returned an error try { Response response = sipSubscriptionHandler .sbb .getMessageFactory() .createResponse(rlsResponse, event.getRequest()); response = sipSubscriptionHandler.addContactHeader(response); response.addHeader( sipSubscriptionHandler.sbb.getHeaderFactory().createRequireHeader("eventlist")); event.getServerTransaction().sendResponse(response); } catch (Exception f) { tracer.severe("Can't send RESPONSE", f); } return; } } else { authorizeNewSipSubscription( event, aci, subscriber, subscriberDisplayName, notifier, key, expires, content, contentType, contentSubtype, false, dataSource, childSbb); } }
/** * Implements {@link MethodProcessor#processRequest(RequestEvent)}. Handles only NOTIFY requests * because they are the only requests concerning event package subscribers and if the processing * of a given request requires event package-specific handling, delivers the request to the * matching Subscription instance. Examples of such event package-specific handling include * handling the termination of an existing Subscription and processing the bodies of the NOTIFY * requests for active Subscriptions. * * @param requestEvent a <tt>RequestEvent</tt> specifying the SIP <tt>Request</tt> to be processed * @return <tt>true</tt> if the SIP <tt>Request</tt> specified by <tt>requestEvent</tt> was * processed; otherwise, <tt>false</tt> */ @Override public boolean processRequest(RequestEvent requestEvent) { Request request = requestEvent.getRequest(); EventHeader eventHeader = (EventHeader) request.getHeader(EventHeader.NAME); if ((eventHeader == null) || !eventPackage.equalsIgnoreCase(eventHeader.getEventType())) { /* * We are not concerned by this request, perhaps another listener * is. So don't send a 489 / Bad event answer here. */ return false; } if (!Request.NOTIFY.equals(request.getMethod())) return false; if (logger.isDebugEnabled()) logger.debug("notify received"); SubscriptionStateHeader sstateHeader = (SubscriptionStateHeader) request.getHeader(SubscriptionStateHeader.NAME); // notify must contain one (rfc3265) if (sstateHeader == null) { logger.error("no subscription state in this request"); return false; } String sstate = sstateHeader.getState(); ServerTransaction serverTransaction = getOrCreateServerTransaction(requestEvent); // first handle the case of a contact still pending // it's possible if the NOTIFY arrives before the OK CallIdHeader callIdHeader = (CallIdHeader) request.getHeader(CallIdHeader.NAME); String callId = callIdHeader.getCallId(); Subscription subscription = getSubscription(callId); // see if the notify correspond to an existing subscription if ((subscription == null) && !SubscriptionStateHeader.TERMINATED.equalsIgnoreCase(sstate)) { if (logger.isDebugEnabled()) logger.debug("subscription not found for callId " + callId); // send a 481 response (rfc3625) Response response; try { response = protocolProvider .getMessageFactory() .createResponse(Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST, request); } catch (ParseException e) { logger.error("failed to create the 481 response", e); return false; } try { serverTransaction.sendResponse(response); } catch (SipException e) { logger.error("failed to send the response", e); } catch (InvalidArgumentException e) { // should not happen logger.error("invalid argument provided while trying to send the response", e); } return true; } // if we don't understand the content ContentTypeHeader ctheader = (ContentTypeHeader) request.getHeader(ContentTypeHeader.NAME); if ((ctheader != null) && !ctheader.getContentSubType().equalsIgnoreCase(contentSubType)) { // send a 415 response (rfc3261) Response response; try { response = protocolProvider .getMessageFactory() .createResponse(Response.UNSUPPORTED_MEDIA_TYPE, request); } catch (ParseException e) { logger.error("failed to create the OK response", e); return false; } // we want PIDF AcceptHeader acceptHeader; try { acceptHeader = protocolProvider.getHeaderFactory().createAcceptHeader("application", contentSubType); } catch (ParseException e) { // should not happen logger.error("failed to create the accept header", e); return false; } response.setHeader(acceptHeader); try { serverTransaction.sendResponse(response); } catch (SipException e) { logger.error("failed to send the response", e); } catch (InvalidArgumentException e) { // should not happen logger.error("invalid argument provided while trying" + " to send the response", e); } } // if the presentity doesn't want of us anymore if (SubscriptionStateHeader.TERMINATED.equalsIgnoreCase(sstate)) { // if we requested this end of subscription, subscription == null if (subscription != null) { removeSubscription(callId, subscription); subscription.processTerminatedRequest(requestEvent, sstateHeader.getReasonCode()); } } // send an OK response Response response; try { response = protocolProvider.getMessageFactory().createResponse(Response.OK, request); } catch (ParseException e) { logger.error("failed to create the OK response", e); return false; } try { serverTransaction.sendResponse(response); } catch (SipException e) { logger.error("failed to send the response", e); } catch (InvalidArgumentException e) { // should not happen logger.error("invalid argument provided while trying to send the response", e); } // transform the presence document in new presence status if (subscription != null) subscription.processActiveRequest(requestEvent, request.getRawContent()); return true; }