/** * When a provider is added. As searching can be slow especially when handling special type of * messages (with subType) this need to be run in new Thread. * * @param provider ProtocolProviderService */ private void handleProviderAddedInSeparateThread( ProtocolProviderService provider, boolean isStatusChanged) { // lets check if we have cached recent messages for this provider, and // fire events if found and are newer synchronized (recentMessages) { List<ComparableEvtObj> cachedRecentMessages = getCachedRecentMessages(provider, isStatusChanged); if (cachedRecentMessages.isEmpty()) { // maybe there is no cached history for this // let's check // load it not from cache, but do a local search Collection<EventObject> res = messageHistoryService.findRecentMessagesPerContact( numberOfMessages, provider.getAccountID().getAccountUniqueID(), null, isSMSEnabled); List<ComparableEvtObj> newMsc = new ArrayList<ComparableEvtObj>(); processEventObjects(res, newMsc, isStatusChanged); addNewRecentMessages(newMsc); for (ComparableEvtObj msc : newMsc) { saveRecentMessageToHistory(msc); } } else addNewRecentMessages(cachedRecentMessages); } }
/** * Create a <tt>SourceContact</tt> from a <tt>GoogleContactsEntry</tt>. * * @param entry <tt>GoogleContactsEntry</tt> */ private void onGoogleContactsEntry(GoogleContactsEntry entry) { String displayName = entry.getFullName(); if (displayName == null || displayName.length() == 0) { if ((entry.getGivenName() == null || entry.getGivenName().length() == 0) && (entry.getFamilyName() == null || entry.getFamilyName().length() == 0)) { return; } displayName = entry.getGivenName() + " " + entry.getFamilyName(); } List<ContactDetail> contactDetails = getContactDetails(entry); if (!contactDetails.isEmpty()) { GenericSourceContact sourceContact = new GenericSourceContact(getContactSource(), displayName, contactDetails); try { byte img[] = GoogleContactsServiceImpl.downloadPhoto( ((GoogleContactsEntryImpl) entry).getPhotoLink(), getContactSource().getConnection().getGoogleService()); sourceContact.setImage(img); } catch (OutOfMemoryError oome) { // Ignore it, the image is not vital. } addQueryResult(sourceContact); } }
/** * Gets and formats the names of the peers in the call. * * @param maxLength maximum length of the filename * @return the name of the peer in the call formated */ private String getCallPeerName(int maxLength) { List<CallPeer> callPeers = call.getConference().getCallPeers(); CallPeer callPeer = null; String peerName = ""; if (!callPeers.isEmpty()) { callPeer = callPeers.get(0); if (callPeer != null) { peerName = callPeer.getDisplayName(); peerName = peerName.replaceAll("[^\\da-zA-Z\\_\\-@\\.]", ""); if (peerName.length() > maxLength) { peerName = peerName.substring(0, maxLength); } } } return peerName; }
/** * A provider has been removed. * * @param provider the ProtocolProviderService that has been unregistered. */ void handleProviderRemoved(ProtocolProviderService provider) { // lets remove the recent messages for this provider, and update // with recent messages for the available providers synchronized (recentMessages) { if (provider != null) { List<ComparableEvtObj> removedItems = new ArrayList<ComparableEvtObj>(); for (ComparableEvtObj msc : recentMessages) { if (msc.getProtocolProviderService().equals(provider)) removedItems.add(msc); } recentMessages.removeAll(removedItems); if (!recentMessages.isEmpty()) oldestRecentMessage = recentMessages.get(recentMessages.size() - 1).getTimestamp(); else oldestRecentMessage = null; if (recentQuery != null) { for (ComparableEvtObj msc : removedItems) { recentQuery.fireContactRemoved(msc); } } } // handleProviderRemoved can be invoked due to stopped // history service, if this is the case we do not want to // update messages if (!this.messageHistoryService.isHistoryLoggingEnabled()) return; // lets do the same as we enable provider // for all registered providers and finally fire events List<ComparableEvtObj> contactsToAdd = new ArrayList<ComparableEvtObj>(); for (ProtocolProviderService pps : messageHistoryService.getCurrentlyAvailableProviders()) { contactsToAdd.addAll(getCachedRecentMessages(pps, true)); } addNewRecentMessages(contactsToAdd); } }
/** * Gets the preferred <tt>ContactDetail</tt> for a specific <tt>OperationSet</tt>. * * @param operationSet the <tt>OperationSet</tt> to get the preferred <tt>ContactDetail</tt> for * @return the preferred <tt>ContactDetail</tt> for the specified <tt>operationSet</tt> * @see SourceContact#getPreferredContactDetail(Class) */ public ContactDetail getPreferredContactDetail(Class<? extends OperationSet> operationSet) { List<ContactDetail> contactDetails = getContactDetails(operationSet); return contactDetails.isEmpty() ? null : contactDetails.get(0); }
/** * Returns the default <tt>ContactDetail</tt> to use for any operations depending to the given * <tt>OperationSet</tt> class. * * @param opSetClass the <tt>OperationSet</tt> class we're interested in * @return the default <tt>ContactDetail</tt> to use for any operations depending to the given * <tt>OperationSet</tt> class */ public UIContactDetail getDefaultContactDetail(Class<? extends OperationSet> opSetClass) { List<UIContactDetail> details = getContactDetailsForOperationSet(opSetClass); return (details != null && !details.isEmpty()) ? details.get(0) : null; }
/** * Handles incoming messages and dispatches whatever events are necessary. * * @param packet the packet that we need to handle (if it is a message). */ public void processPacket(Packet packet) { if (!(packet instanceof org.jivesoftware.smack.packet.Message)) return; org.jivesoftware.smack.packet.Message msg = (org.jivesoftware.smack.packet.Message) packet; boolean isForwardedSentMessage = false; if (msg.getBody() == null) { CarbonPacketExtension carbonExt = (CarbonPacketExtension) msg.getExtension(CarbonPacketExtension.NAMESPACE); if (carbonExt == null) return; isForwardedSentMessage = (carbonExt.getElementName() == CarbonPacketExtension.SENT_ELEMENT_NAME); List<ForwardedPacketExtension> extensions = carbonExt.getChildExtensionsOfType(ForwardedPacketExtension.class); if (extensions.isEmpty()) return; ForwardedPacketExtension forwardedExt = extensions.get(0); msg = forwardedExt.getMessage(); if (msg == null || msg.getBody() == null) return; } Object multiChatExtension = msg.getExtension("x", "http://jabber.org/protocol/muc#user"); // its not for us if (multiChatExtension != null) return; String userFullId = isForwardedSentMessage ? msg.getTo() : msg.getFrom(); String userBareID = StringUtils.parseBareAddress(userFullId); boolean isPrivateMessaging = false; ChatRoom privateContactRoom = null; OperationSetMultiUserChatJabberImpl mucOpSet = (OperationSetMultiUserChatJabberImpl) jabberProvider.getOperationSet(OperationSetMultiUserChat.class); if (mucOpSet != null) privateContactRoom = mucOpSet.getChatRoom(userBareID); if (privateContactRoom != null) { isPrivateMessaging = true; } if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) logger.debug("Received from " + userBareID + " the message " + msg.toXML()); } Message newMessage = createMessage(msg.getBody(), DEFAULT_MIME_TYPE, msg.getPacketID()); // check if the message is available in xhtml PacketExtension ext = msg.getExtension("http://jabber.org/protocol/xhtml-im"); if (ext != null) { XHTMLExtension xhtmlExt = (XHTMLExtension) ext; // parse all bodies Iterator<String> bodies = xhtmlExt.getBodies(); StringBuffer messageBuff = new StringBuffer(); while (bodies.hasNext()) { String body = bodies.next(); messageBuff.append(body); } if (messageBuff.length() > 0) { // we remove body tags around message cause their // end body tag is breaking // the visualization as html in the UI String receivedMessage = messageBuff .toString() // removes body start tag .replaceAll("\\<[bB][oO][dD][yY].*?>", "") // removes body end tag .replaceAll("\\</[bB][oO][dD][yY].*?>", ""); // for some reason ' is not rendered correctly // from our ui, lets use its equivalent. Other // similar chars(< > & ") seem ok. receivedMessage = receivedMessage.replaceAll("'", "'"); newMessage = createMessage(receivedMessage, HTML_MIME_TYPE, msg.getPacketID()); } } PacketExtension correctionExtension = msg.getExtension(MessageCorrectionExtension.NAMESPACE); String correctedMessageUID = null; if (correctionExtension != null) { correctedMessageUID = ((MessageCorrectionExtension) correctionExtension).getCorrectedMessageUID(); } Contact sourceContact = opSetPersPresence.findContactByID((isPrivateMessaging ? userFullId : userBareID)); if (msg.getType() == org.jivesoftware.smack.packet.Message.Type.error) { // error which is multichat and we don't know about the contact // is a muc message error which is missing muc extension // and is coming from the room, when we try to send message to // room which was deleted or offline on the server if (isPrivateMessaging && sourceContact == null) { if (privateContactRoom != null) { XMPPError error = packet.getError(); int errorResultCode = ChatRoomMessageDeliveryFailedEvent.UNKNOWN_ERROR; if (error != null && error.getCode() == 403) { errorResultCode = ChatRoomMessageDeliveryFailedEvent.FORBIDDEN; } String errorReason = error.getMessage(); ChatRoomMessageDeliveryFailedEvent evt = new ChatRoomMessageDeliveryFailedEvent( privateContactRoom, null, errorResultCode, errorReason, new Date(), newMessage); ((ChatRoomJabberImpl) privateContactRoom).fireMessageEvent(evt); } return; } if (logger.isInfoEnabled()) logger.info("Message error received from " + userBareID); int errorResultCode = MessageDeliveryFailedEvent.UNKNOWN_ERROR; if (packet.getError() != null) { int errorCode = packet.getError().getCode(); if (errorCode == 503) { org.jivesoftware.smackx.packet.MessageEvent msgEvent = (org.jivesoftware.smackx.packet.MessageEvent) packet.getExtension("x", "jabber:x:event"); if (msgEvent != null && msgEvent.isOffline()) { errorResultCode = MessageDeliveryFailedEvent.OFFLINE_MESSAGES_NOT_SUPPORTED; } } } if (sourceContact == null) { sourceContact = opSetPersPresence.createVolatileContact(userFullId, isPrivateMessaging); } MessageDeliveryFailedEvent ev = new MessageDeliveryFailedEvent( newMessage, sourceContact, correctedMessageUID, errorResultCode); // ev = messageDeliveryFailedTransform(ev); if (ev != null) fireMessageEvent(ev); return; } putJidForAddress(userFullId, msg.getThread()); // In the second condition we filter all group chat messages, // because they are managed by the multi user chat operation set. if (sourceContact == null) { if (logger.isDebugEnabled()) logger.debug("received a message from an unknown contact: " + userBareID); // create the volatile contact sourceContact = opSetPersPresence.createVolatileContact(userFullId, isPrivateMessaging); } Date timestamp = new Date(); // Check for XEP-0091 timestamp (deprecated) PacketExtension delay = msg.getExtension("x", "jabber:x:delay"); if (delay != null && delay instanceof DelayInformation) { timestamp = ((DelayInformation) delay).getStamp(); } // check for XEP-0203 timestamp delay = msg.getExtension("delay", "urn:xmpp:delay"); if (delay != null && delay instanceof DelayInfo) { timestamp = ((DelayInfo) delay).getStamp(); } ContactResource resource = ((ContactJabberImpl) sourceContact).getResourceFromJid(userFullId); EventObject msgEvt = null; if (!isForwardedSentMessage) msgEvt = new MessageReceivedEvent( newMessage, sourceContact, resource, timestamp, correctedMessageUID, isPrivateMessaging, privateContactRoom); else msgEvt = new MessageDeliveredEvent(newMessage, sourceContact, timestamp); // msgReceivedEvt = messageReceivedTransform(msgReceivedEvt); if (msgEvt != null) fireMessageEvent(msgEvt); }
/** * Add the ComparableEvtObj, newly added will fire new, for existing fire update and when trimming * the list to desired length fire remove for those that were removed * * @param contactsToAdd */ private void addNewRecentMessages(List<ComparableEvtObj> contactsToAdd) { // now find object to fire new, and object to fire remove // let us find duplicates and fire update List<ComparableEvtObj> duplicates = new ArrayList<ComparableEvtObj>(); for (ComparableEvtObj msgToAdd : contactsToAdd) { if (recentMessages.contains(msgToAdd)) { duplicates.add(msgToAdd); // save update updateRecentMessageToHistory(msgToAdd); } } recentMessages.removeAll(duplicates); // now contacts to add has no duplicates, add them all boolean changed = recentMessages.addAll(contactsToAdd); if (changed) { Collections.sort(recentMessages); if (recentQuery != null) { for (ComparableEvtObj obj : duplicates) recentQuery.updateContact(obj, obj.getEventObject()); } } if (!recentMessages.isEmpty()) oldestRecentMessage = recentMessages.get(recentMessages.size() - 1).getTimestamp(); // trim List<ComparableEvtObj> removedItems = null; if (recentMessages.size() > numberOfMessages) { removedItems = new ArrayList<ComparableEvtObj>( recentMessages.subList(numberOfMessages, recentMessages.size())); recentMessages.removeAll(removedItems); } if (recentQuery != null) { // now fire, removed for all that were in the list // and now are removed after trim if (removedItems != null) { for (ComparableEvtObj msc : removedItems) { if (!contactsToAdd.contains(msc)) recentQuery.fireContactRemoved(msc); } } // fire new for all that were added, and not removed after trim for (ComparableEvtObj msc : contactsToAdd) { if ((removedItems == null || !removedItems.contains(msc)) && !duplicates.contains(msc)) { MessageSourceContact newSourceContact = new MessageSourceContact(msc.getEventObject(), MessageSourceService.this); newSourceContact.initDetails(msc.getEventObject()); recentQuery.addQueryResult(newSourceContact); } } // if recent messages were changed, indexes have change lets // fire event for the last element which will reorder the whole // group if needed. if (changed) recentQuery.fireContactChanged(recentMessages.get(recentMessages.size() - 1)); } }