diff --git a/build.xml b/build.xml index a8d0fb6db..a69c5e09a 100644 --- a/build.xml +++ b/build.xml @@ -1086,7 +1086,8 @@ bundle-globalshortcut,bundle-plugin-msofficecomm,bundle-libjitsi, bundle-customcontactactions, bundle-phonenumbercontactsource, bundle-demuxcontactsource, bundle-muc, - bundle-desktoputil,bundle-globaldisplaydetails, + bundle-desktoputil,bundle-globaldisplaydetails, + bundle-usersearch, bundle-plugin-propertieseditor,bundle-plugin-accountinfo, bundle-guava,bundle-hsql"/> @@ -2874,6 +2875,15 @@ javax.swing.event, javax.swing.border"/> + + + + + + + diff --git a/lib/felix.client.run.properties b/lib/felix.client.run.properties index 2a45a4729..834617bb0 100644 --- a/lib/felix.client.run.properties +++ b/lib/felix.client.run.properties @@ -196,6 +196,7 @@ felix.auto.start.67= \ reference:file:sc-bundles/plugin-certconfig.jar \ reference:file:sc-bundles/phonenumbercontactsource.jar \ reference:file:sc-bundles/demuxcontactsource.jar \ + reference:file:sc-bundles/usersearch.jar \ reference:file:sc-bundles/propertieseditor.jar # Level 68 is for profiler4j. Either don't use it or change the build.xml file diff --git a/lib/installer-exclude/smack.manifest.mf b/lib/installer-exclude/smack.manifest.mf index cccc76701..0323a503e 100644 --- a/lib/installer-exclude/smack.manifest.mf +++ b/lib/installer-exclude/smack.manifest.mf @@ -39,6 +39,7 @@ Export-Package: org.jivesoftware.smack, org.jivesoftware.smackx.jingle.listeners, org.jivesoftware.smackx.filetransfer, org.jivesoftware.smackx.provider, + org.jivesoftware.smackx.search, org.jivesoftware.smack.sasl, org.xmlpull.v1, org.xmlpull.mxp1, diff --git a/resources/languages/resources.properties b/resources/languages/resources.properties index 1256585c3..ba86dd855 100644 --- a/resources/languages/resources.properties +++ b/resources/languages/resources.properties @@ -1251,6 +1251,9 @@ plugin.updatechecker.DIALOG_NOUPDATE=Your version is up to date. plugin.updatechecker.DIALOG_NOUPDATE_TITLE=No new version plugin.updatechecker.DIALOG_MISSING_UPDATE=Update Installer is missing. +# usersearch +plugin.usersearch.USER_SEARCH=User search + # whiteboard plugin.whiteboard.TITLE=Whiteboard [Beta] plugin.whiteboard.MENU_ITEM=Whiteboard diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeCellRenderer.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeCellRenderer.java index 2bb6a1dd9..d063cf702 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeCellRenderer.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeCellRenderer.java @@ -324,12 +324,12 @@ public void actionPerformed(ActionEvent e) (MetaContact) contactDescriptor.getDescriptor()); } else if(((SourceContact) contactDescriptor.getDescriptor()) - .getContactDetails(OperationSetMultiUserChat.class) + .getContactDetails(OperationSetMultiUserChat.class) != null) { SourceContact contact = (SourceContact) contactDescriptor.getDescriptor(); - ChatRoomWrapper room + ChatRoomWrapper room = GuiActivator.getMUCService() .findChatRoomWrapperFromSourceContact(contact); if(room != null) @@ -425,11 +425,9 @@ public Component getTreeCellRendererComponent(JTree tree, Object value, { UIContactImpl contact = ((ContactNode) value).getContactDescriptor(); - + if((contact.getDescriptor() instanceof SourceContact) && - ((SourceContact)contact.getDescriptor()) - .getPreferredContactDetail(OperationSetMultiUserChat.class) - != null) + GuiActivator.getMUCService().isMUCSourceContact((SourceContact)contact.getDescriptor())) { setBackground(Constants.CHAT_ROOM_ROW_COLOR); } @@ -535,7 +533,7 @@ else if (value instanceof GroupNode) statusIcon = expanded ? openedGroupIcon : closedGroupIcon; - + if(groupItem != treeContactList.getRootUIGroup()) { this.statusLabel.setIcon( @@ -547,7 +545,7 @@ else if (value instanceof GroupNode) { this.statusLabel.setIcon(null); } - + // We have no photo icon for groups. this.rightLabel.setIcon(null); this.rightLabel.setText(""); @@ -562,8 +560,8 @@ else if (value instanceof GroupNode) this.initDisplayDetails(groupItem.getDisplayDetails()); this.initButtonsPanel(groupItem); - this.setToolTipText((groupItem.getDescriptor() != null) ? - groupItem.getDescriptor().toString() : + this.setToolTipText((groupItem.getDescriptor() != null) ? + groupItem.getDescriptor().toString() : groupItem.getDisplayName()); } @@ -846,7 +844,7 @@ private void initButtonsPanel(UIContact uiContact) if (uiContact.getDescriptor() instanceof MetaContact) imContact = uiContact.getDefaultContactDetail( OperationSetBasicInstantMessaging.class); - + if(imContact == null) imContact = uiContact.getDefaultContactDetail( OperationSetMultiUserChat.class); diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/PresenceFilter.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/PresenceFilter.java index 3ffe6b71c..fd68c3d23 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/PresenceFilter.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/PresenceFilter.java @@ -42,13 +42,13 @@ public class PresenceFilter * directly to the contact list without firing events. */ private static final int INITIAL_CONTACT_COUNT = 30; - + /** - * Preferences for the external contact sources. Lists the type of contact - * contact sources that will be displayed in the filter and the order of the + * Preferences for the external contact sources. Lists the type of contact + * contact sources that will be displayed in the filter and the order of the * contact sources. */ - private static Map contactSourcePreferences + private static Map contactSourcePreferences = new HashMap(); /** @@ -61,7 +61,7 @@ public PresenceFilter() } /** - * Initializes the contact source preferences. The preferences are for the + * Initializes the contact source preferences. The preferences are for the * visibility of the contact source and their order. */ private void initContactSourcePreferences() @@ -71,7 +71,7 @@ private void initContactSourcePreferences() //The chat room sources will be ordered before the meta contact list. contactSourcePreferences.put(ContactSourceService.CHAT_ROOM_TYPE, 0); } - + /** * Applies this filter. This filter is applied over the * MetaContactListService. @@ -88,33 +88,33 @@ public void applyFilter(FilterQuery filterQuery) for(int cssType : contactSourcePreferences.keySet()) { - Iterator filterSources + Iterator filterSources = GuiActivator.getContactList().getContactSources(cssType) .iterator(); - + while (filterSources.hasNext()) { UIContactSource filterSource = filterSources.next(); - + Integer prefValue = contactSourcePreferences.get(cssType); - //We are setting the index from contactSourcePreferences map to - //the contact source. This index is set to reorder the sources + //We are setting the index from contactSourcePreferences map to + //the contact source. This index is set to reorder the sources //in the contact list. if(prefValue != null) filterSource.setContactSourceIndex(prefValue); - + ContactSourceService sourceService = filterSource.getContactSourceService(); - - ContactQuery contactQuery + + ContactQuery contactQuery = sourceService.createContactQuery(null); - + // Add this query to the filterQuery. filterQuery.addContactQuery(contactQuery); - + contactQuery.addContactQueryListener( GuiActivator.getContactList()); - + contactQuery.start(); } } @@ -124,7 +124,7 @@ public void applyFilter(FilterQuery filterQuery) query.addContactQueryListener(GuiActivator.getContactList()); int resultCount = 0; - + addMatching(GuiActivator.getContactListService().getRoot(), query, resultCount); @@ -221,8 +221,7 @@ public boolean isMatching(SourceContact contact) return isShowOffline || contact.getPresenceStatus().isOnline() - || (contact.getPreferredContactDetail(OperationSetMultiUserChat.class) - != null); + || GuiActivator.getMUCService().isMUCSourceContact(contact); } /** @@ -284,12 +283,12 @@ private void addMatching( MetaContactGroup metaGroup, if(isMatching(metaContact)) { - + resultCount++; if (resultCount <= INITIAL_CONTACT_COUNT) { UIGroup uiGroup = null; - + if (!MetaContactListSource.isRootGroup(metaGroup)) { synchronized (metaGroup) @@ -309,7 +308,7 @@ private void addMatching( MetaContactGroup metaGroup, UIContactImpl newUIContact; synchronized (metaContact) { - newUIContact + newUIContact = MetaContactListSource.getUIContact(metaContact); if (newUIContact == null) @@ -318,7 +317,7 @@ private void addMatching( MetaContactGroup metaGroup, .createUIContact(metaContact); } } - + GuiActivator.getContactList().addContact( newUIContact, uiGroup, diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/SourceContactRightButtonMenu.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/SourceContactRightButtonMenu.java index 81f7fb853..8aa4e558e 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/SourceContactRightButtonMenu.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/SourceContactRightButtonMenu.java @@ -93,8 +93,7 @@ private void initItems() add(initCallMenu()); // Only create the menu if the add contact functionality is enabled. - if ((sourceContact.getPreferredContactDetail( - OperationSetMultiUserChat.class) == null) + if (!GuiActivator.getMUCService().isMUCSourceContact(sourceContact) && !ConfigurationUtils.isAddContactDisabled()) { addContactComponent @@ -103,8 +102,8 @@ private void initItems() if (addContactComponent != null) add(addContactComponent); - - for(JMenuItem item : + + for(JMenuItem item : sourceUIContact.getContactCustomActionMenuItems(true)) { add(item); diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/TreeContactList.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/TreeContactList.java index beb9e1fdf..d2089c2e8 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/TreeContactList.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/TreeContactList.java @@ -164,7 +164,7 @@ public class TreeContactList * The container, where this contact list component is added. */ private ContactListContainer parentCLContainer; - + /** * The Contacts group instance. */ @@ -213,7 +213,7 @@ public TreeContactList(ContactListContainer clContainer) */ public void contactReceived(ContactReceivedEvent event) { - + final SourceContact sourceContact = event.getContact(); ContactSourceService contactSource @@ -223,7 +223,7 @@ public void contactReceived(ContactReceivedEvent event) if (sourceUI == null) return; - + UIContact uiContact = sourceUI.createUIContact(sourceContact); @@ -303,10 +303,10 @@ public void contactChanged(ContactChangedEvent event) synchronized (uiContact) { contactNode = ((UIContactImpl) uiContact).getContactNode(); - + if (contactNode == null) return; - + nodeChanged(contactNode); } @@ -324,7 +324,7 @@ public void contactChanged(ContactChangedEvent event) if (groupNode == null) return; } - + groupNode.sort(treeModel); } } @@ -356,7 +356,7 @@ public void metaContactReceived(MetaContactQueryEvent event) UIContactImpl newUIContact; synchronized (metaContact) { - newUIContact + newUIContact = MetaContactListSource.getUIContact(metaContact); if (newUIContact == null) @@ -365,13 +365,13 @@ public void metaContactReceived(MetaContactQueryEvent event) .createUIContact(metaContact); } } - + addContact( event.getQuerySource(), newUIContact, uiGroup, true); - + } /** @@ -480,7 +480,7 @@ public void setActiveContact(MetaContact metaContact, boolean isActive) if (contactNode == null) return; } - + contactNode.setActive(isActive); if (isActive) @@ -495,7 +495,7 @@ public void setActiveContact(MetaContact metaContact, boolean isActive) activeContacts.remove(contactNode); treeModel.nodeChanged(contactNode); - + } /** @@ -563,22 +563,22 @@ else if (group instanceof UIGroupImpl) if (groupNode == null) { GroupNode parentNode = treeModel.getRoot(); - + if (isGroupSorted) groupNode = parentNode.sortedAddContactGroup(contactImpl); else groupNode = parentNode.addContactGroup(contactImpl); - + if(group.getSourceIndex() < GuiActivator.getContactListService() - .getSourceIndex() && rootUIGroup == null - && (!(treeModel.getRoot().getChildAfter(groupNode) + .getSourceIndex() && rootUIGroup == null + && (!(treeModel.getRoot().getChildAfter(groupNode) instanceof GroupNode))) { createMetaUIRootGroup(); } } } - + } if (groupNode == null) @@ -591,7 +591,7 @@ else if (group instanceof UIGroupImpl) ContactNode contactNode = null; UIContactImpl contactImpl = (UIContactImpl) contact; - + synchronized (contactImpl) { if(contactImpl.getContactNode() != null) @@ -603,8 +603,8 @@ else if (group instanceof UIGroupImpl) contactNode = groupNode.sortedAddContact(contactImpl); else contactNode = groupNode.addContact(contactImpl); - - if(rootUIGroup == null && groupNode == treeModel.getRoot() + + if(rootUIGroup == null && groupNode == treeModel.getRoot() && treeModel.getRoot().getChildBefore(contactNode) instanceof GroupNode) { createMetaUIRootGroup(); @@ -623,9 +623,9 @@ else if (group instanceof UIGroupImpl) */ public UIGroupImpl getRootUIGroup() { - return rootUIGroup; + return rootUIGroup; } - + /** * Creates UI group for the root meta contact group. */ @@ -633,82 +633,82 @@ private void createMetaUIRootGroup() { if(rootUIGroup != null) return; - + rootUIGroup = new UIGroupImpl() { private GroupNode groupNode = null; - + @Override public boolean isGroupCollapsed() { return true; } - + @Override public int getSourceIndex() { return GuiActivator.getContactListService().getSourceIndex(); } - + @Override public Component getRightButtonMenu() { return null; } - + @Override public UIGroup getParentGroup() { return null; } - + @Override public String getId() { return null; } - + @Override public String getDisplayName() { return GuiActivator.getResources() .getI18NString("service.gui.CONTACTS"); } - + @Override public Object getDescriptor() { return null; } - + @Override public int countOnlineChildContacts() { return -1; } - + @Override public int countChildContacts() { return -1; } - + @Override public void setGroupNode(GroupNode groupNode) { this.groupNode = groupNode; } - + @Override public GroupNode getGroupNode() { return groupNode; } }; - + treeModel.getRoot().sortedAddContactGroup(rootUIGroup); } - + /** * Removes the UI group associated with the root meta contact group. */ @@ -717,7 +717,7 @@ private void removeMetaUIRootGroup() if(rootUIGroup == null) return; GroupNode parentNode = treeModel.getRoot(); - + parentNode.removeContactGroup(rootUIGroup); rootUIGroup = null; } @@ -824,9 +824,9 @@ public void run() // Nothing more to do here if we didn't find the parent. if (parentGroupNode == null) return; - + parentGroupNode.removeContact((UIContactImpl) contact); - + // If the parent group is empty remove it. if (removeEmptyGroup && parentGroupNode.getChildCount() == 0) { @@ -836,12 +836,12 @@ public void run() { parent.removeContactGroup(parentGroup); } - + } } - - if(rootUIGroup != null - && (treeModel.getRoot().getChildAfter(rootUIGroup.getGroupNode()) + + if(rootUIGroup != null + && (treeModel.getRoot().getChildAfter(rootUIGroup.getGroupNode()) instanceof GroupNode || treeModel.getRoot().getChildBefore( (rootUIGroup).getGroupNode()) == null)) { @@ -886,7 +886,7 @@ public void run() treeModel.nodeChanged(((UIContactImpl) contact).getContactNode()); } - + } /** @@ -1015,7 +1015,7 @@ public Collection getContacts(final UIGroup group) return null; GroupNode groupNode; - + if (group == null) groupNode = treeModel.getRoot(); else @@ -1024,12 +1024,12 @@ public Collection getContacts(final UIGroup group) { groupNode = ((UIGroupImpl) group).getGroupNode(); } - + } if (groupNode == null) return null; - + Collection contactNodes = groupNode.getContacts(); if (contactNodes == null) @@ -1768,12 +1768,12 @@ public void startSelectedContactChat() .startChat((MetaContact) uiContact.getDescriptor()); } else if(((SourceContact) uiContact.getDescriptor()) - .getContactDetails(OperationSetMultiUserChat.class) + .getContactDetails(OperationSetMultiUserChat.class) != null) { SourceContact contact = (SourceContact) uiContact.getDescriptor(); - ChatRoomWrapper room + ChatRoomWrapper room = GuiActivator.getMUCService() .findChatRoomWrapperFromSourceContact(contact); if(room != null) @@ -1896,7 +1896,7 @@ private void initContactSources() else contactSources.add(extContactSource); } - + } GuiActivator.bundleContext.addServiceListener( @@ -2123,7 +2123,7 @@ public void contactChanged(ContactChangedEvent event) ContactSourceService contactSource = sourceContact.getContactSource(); - UIContactSource sourceUI + UIContactSource sourceUI = getContactSource(contactSource); if (sourceUI == null) @@ -2132,15 +2132,15 @@ public void contactChanged(ContactChangedEvent event) UIContact uiContact = sourceUI.getUIContact(sourceContact); - if(uiContact == null + if(uiContact == null || !(uiContact instanceof UIContactImpl)) return; - + synchronized (uiContact) { - ContactNode contactNode + ContactNode contactNode = ((UIContactImpl) uiContact).getContactNode(); - + if (contactNode != null) nodeChanged(contactNode); } @@ -2151,7 +2151,7 @@ public void contactChanged(ContactChangedEvent event) contactSource).createContactQuery(filterPattern); loadedQueries.add(query); - + query.start(); // If the image search has been canceled from one of the @@ -2263,7 +2263,9 @@ public static JMenuItem createAddContactMenu(SourceContact sourceContact) { JMenuItem addContactComponentTmp = null; - List details = sourceContact.getContactDetails(); + List details + = sourceContact.getContactDetails( + OperationSetPersistentPresence.class); final String displayName = sourceContact.getDisplayName(); if (details.size() == 1) @@ -2512,11 +2514,11 @@ public void run() { if (!(uiContact instanceof UIContactImpl)) return; - + setSelectionPath(new TreePath( ((UIContactImpl) uiContact).getContactNode().getPath())); } - + } /** @@ -2546,7 +2548,7 @@ public void run() setSelectionPath(new TreePath( ((UIGroupImpl) uiGroup).getGroupNode().getPath())); } - + } /** diff --git a/src/net/java/sip/communicator/impl/muc/MUCCustomContactActionService.java b/src/net/java/sip/communicator/impl/muc/MUCCustomContactActionService.java index b566b932e..419e3788c 100644 --- a/src/net/java/sip/communicator/impl/muc/MUCCustomContactActionService.java +++ b/src/net/java/sip/communicator/impl/muc/MUCCustomContactActionService.java @@ -582,6 +582,9 @@ public byte[] getIcon() @Override public String getText(SourceContact actionSource) { + if(!(actionSource instanceof ChatRoomSourceContact)) + return ""; + if(!name.equals("open_automatically")) return text; @@ -653,6 +656,8 @@ public boolean isSelected(SourceContact contact) { ChatRoomWrapper chatRoomWrapper = MUCActivator.getMUCService() .findChatRoomWrapperFromSourceContact(contact); + if(chatRoomWrapper == null) + return false; return chatRoomWrapper.isAutojoin(); } diff --git a/src/net/java/sip/communicator/impl/muc/MUCServiceImpl.java b/src/net/java/sip/communicator/impl/muc/MUCServiceImpl.java index 7b0194868..9a2dac203 100644 --- a/src/net/java/sip/communicator/impl/muc/MUCServiceImpl.java +++ b/src/net/java/sip/communicator/impl/muc/MUCServiceImpl.java @@ -22,24 +22,24 @@ /** * The MUCServiceImpl class implements the service for the chat rooms. - * + * * @author Hristo Terezov */ public class MUCServiceImpl extends MUCService { - + /** * The list of persistent chat rooms. */ private final ChatRoomListImpl chatRoomList = new ChatRoomListImpl(); - + /** * The Logger used by the MUCServiceImpl class and its * instances for logging output. */ private static Logger logger = Logger.getLogger(MUCServiceImpl.class); - + /** * Called to accept an incoming invitation. Adds the invitation chat room * to the list of chat rooms and joins it. @@ -59,27 +59,27 @@ public void acceptInvitation(ChatRoomInvitation invitation) /** * Adds a change listener to the ChatRoomList. - * + * * @param l the listener. */ public void addChatRoomListChangeListener(ChatRoomListChangeListener l) { chatRoomList.addChatRoomListChangeListener(l); } - + /** * Removes a change listener to the ChatRoomList. - * + * * @param l the listener. */ public void removeChatRoomListChangeListener(ChatRoomListChangeListener l) { chatRoomList.removeChatRoomListChangeListener(l); } - + /** * Fires a ChatRoomListChangedEvent event. - * + * * @param chatRoomWrapper the chat room. * @param eventID the id of the event. */ @@ -88,7 +88,7 @@ public void fireChatRoomListChangedEvent( ChatRoomWrapper chatRoomWrapper, { chatRoomList.fireChatRoomListChangedEvent(chatRoomWrapper, eventID); } - + /** * Joins the given chat room with the given password and manages all the @@ -100,7 +100,7 @@ public void fireChatRoomListChangedEvent( ChatRoomWrapper chatRoomWrapper, * @param rememberPassword if true the password should be saved. * @param isFirstAttempt is this the first attempt to join room, used * to check whether to show some error messages - * @param subject the subject which will be set to the room after the user + * @param subject the subject which will be set to the room after the user * join successful. */ private void joinChatRoom( ChatRoomWrapper chatRoomWrapper, @@ -115,7 +115,7 @@ private void joinChatRoom( ChatRoomWrapper chatRoomWrapper, if(chatRoom == null) { MUCActivator.getAlertUIService().showAlertDialog( - MUCActivator.getResources().getI18NString("service.gui.WARNING"), + MUCActivator.getResources().getI18NString("service.gui.WARNING"), MUCActivator.getResources().getI18NString( "service.gui.CHAT_ROOM_NOT_CONNECTED", new String[]{chatRoomWrapper.getChatRoomName()})); @@ -160,7 +160,7 @@ public void joinChatRoom( ChatRoomWrapper chatRoomWrapper, * @param chatRoomWrapper the chat room to join. * @param nickName the nickname we choose for the given chat room. * @param password the password. - * @param subject the subject which will be set to the room after the user + * @param subject the subject which will be set to the room after the user * join successful. */ public void joinChatRoom( ChatRoomWrapper chatRoomWrapper, @@ -185,7 +185,7 @@ public void joinChatRoom( ChatRoomWrapper chatRoomWrapper, .start(); } - + /** * Join chat room. * @param chatRoomWrapper @@ -230,7 +230,7 @@ public void joinChatRoom( ChatRoom chatRoom, = chatRoomList.findServerWrapperFromProvider( chatRoom.getParentProvider()); - chatRoomWrapper + chatRoomWrapper = new ChatRoomWrapperImpl(parentProvider, chatRoom); chatRoomList.addChatRoom(chatRoomWrapper); @@ -273,19 +273,19 @@ public void joinChatRoom( String chatRoomName, { ChatRoomWrapper chatRoomWrapper = chatRoomList.findChatRoomWrapperFromChatRoom(chatRoom); - + if(chatRoomWrapper == null) { ChatRoomProviderWrapper parentProvider = chatRoomList .findServerWrapperFromProvider( chatRoom.getParentProvider()); - - chatRoomWrapper + + chatRoomWrapper = new ChatRoomWrapperImpl(parentProvider, chatRoom); - + chatRoomList.addChatRoom(chatRoomWrapper); - + fireChatRoomListChangedEvent( chatRoomWrapper, ChatRoomListChangeEvent.CHAT_ROOM_ADDED); @@ -328,7 +328,7 @@ public ChatRoomWrapper createChatRoom( roomName, protocolProvider, contacts, reason, true, persistent, isPrivate); } - + /** * Creates a chat room, by specifying the chat room name, the parent * protocol provider and eventually, the contacts invited to participate in @@ -387,17 +387,17 @@ public ChatRoomWrapper createChatRoom( ChatRoom chatRoom = null; try { - - - HashMap roomProperties = + + + HashMap roomProperties = new HashMap(); roomProperties.put("isPrivate", isPrivate); chatRoom = groupChatOpSet.createChatRoom(roomName, roomProperties); - + if(join) { chatRoom.join(); - + for(String contact : contacts) chatRoom.invite(contact, reason); } @@ -437,7 +437,7 @@ public ChatRoomWrapper createChatRoom( if(chatRoomWrapper == null) { - chatRoomWrapper + chatRoomWrapper = new ChatRoomWrapperImpl(parentProvider, chatRoom); chatRoomWrapper.setPersistent(persistent); chatRoomList.addChatRoom(chatRoomWrapper); @@ -467,7 +467,7 @@ public ChatRoomWrapper createPrivateChatRoom( return this.createChatRoom( null, protocolProvider, contacts, reason, persistent, true); } - + /** * Returns existing chat rooms for the given chatRoomProvider. @@ -480,7 +480,7 @@ public List getExistingChatRooms( { if (chatRoomProvider == null) return null; - + ProtocolProviderService protocolProvider = chatRoomProvider.getProtocolProvider(); @@ -493,7 +493,7 @@ public List getExistingChatRooms( if (groupChatOpSet == null) return null; - + List chatRooms = null; try { @@ -511,10 +511,10 @@ public List getExistingChatRooms( logger.trace("Failed to obtain existing chat rooms for server: " + protocolProvider.getAccountID().getService(), e); } - + return chatRooms; } - + /** * Rejects the given invitation with the specified reason. * @@ -529,7 +529,7 @@ public void rejectInvitation( OperationSetMultiUserChat multiUserChatOpSet, { multiUserChatOpSet.rejectInvitation(invitation, reason); } - + /** * Leaves the given chat room. * @@ -569,7 +569,7 @@ public ChatRoomWrapper leaveChatRoom(ChatRoomWrapper chatRoomWrapper) chatRoomWrapper.getParentProvider().getProtocolProvider(), chatRoomWrapper.getChatRoomID(), GlobalStatusEnum.OFFLINE_STATUS); - + return existChatRoomWrapper; } @@ -601,14 +601,14 @@ private class JoinChatRoomTask private final String nickName; private final byte[] password; - + private final boolean rememberPassword; private final boolean isFirstAttempt; - + private final String subject; - - private ResourceManagementService resources + + private ResourceManagementService resources = MUCActivator.getResources(); JoinChatRoomTask( ChatRoomWrapper chatRoomWrapper, @@ -641,14 +641,14 @@ private class JoinChatRoomTask } this.rememberPassword = rememberPassword; } - + JoinChatRoomTask( ChatRoomWrapper chatRoomWrapper, String nickName, byte[] password) { this(chatRoomWrapper, nickName, password, false, true, null); } - + JoinChatRoomTask( ChatRoomWrapper chatRoomWrapper, String nickName, byte[] password, @@ -658,7 +658,7 @@ private class JoinChatRoomTask } /** - * @override {@link Thread}{@link #run()} to perform all asynchronous + * @override {@link Thread}{@link #run()} to perform all asynchronous * tasks. */ @Override @@ -791,7 +791,7 @@ else if(SUBSCRIPTION_ALREADY_EXISTS.equals(returnCode)) new String[]{chatRoomWrapper.getChatRoomName()}); } - if (!SUCCESS.equals(returnCode) && + if (!SUCCESS.equals(returnCode) && !AUTHENTICATION_FAILED.equals(returnCode)) { MUCActivator.getAlertUIService().showAlertPopup( @@ -804,7 +804,7 @@ else if(SUBSCRIPTION_ALREADY_EXISTS.equals(returnCode)) { chatRoomWrapper.savePassword(new String(password)); } - + if(subject != null) { try @@ -819,9 +819,9 @@ else if(SUBSCRIPTION_ALREADY_EXISTS.equals(returnCode)) } } } - + /** - * Finds the ChatRoomWrapper instance associated with the + * Finds the ChatRoomWrapper instance associated with the * source contact. * @param contact the source contact. * @return the ChatRoomWrapper instance. @@ -833,17 +833,17 @@ public ChatRoomWrapper findChatRoomWrapperFromSourceContact( return null; ChatRoomSourceContact chatRoomContact = (ChatRoomSourceContact) contact; return chatRoomList.findChatRoomWrapperFromChatRoomID( - chatRoomContact.getChatRoomID(), chatRoomContact.getProvider()); + chatRoomContact.getChatRoomID(), chatRoomContact.getProvider()); } - + /** - * Finds the ChatRoomWrapper instance associated with the + * Finds the ChatRoomWrapper instance associated with the * chat room. * @param chatRoomID the id of the chat room. * @param pps the provider of the chat room. * @return the ChatRoomWrapper instance. */ - public ChatRoomWrapper findChatRoomWrapperFromChatRoomID(String chatRoomID, + public ChatRoomWrapper findChatRoomWrapperFromChatRoomID(String chatRoomID, ProtocolProviderService pps) { return chatRoomList.findChatRoomWrapperFromChatRoomID(chatRoomID, pps); @@ -851,34 +851,34 @@ public ChatRoomWrapper findChatRoomWrapperFromChatRoomID(String chatRoomID, /** * Searches for chat room wrapper in chat room list by chat room. - * + * * @param chatRoom the chat room. * @param create if true and the chat room wrapper is not found new * chatRoomWrapper is created. * @return found chat room wrapper or the created chat room wrapper. */ @Override - public ChatRoomWrapper getChatRoomWrapperByChatRoom(ChatRoom chatRoom, + public ChatRoomWrapper getChatRoomWrapperByChatRoom(ChatRoom chatRoom, boolean create) { ChatRoomWrapper chatRoomWrapper = chatRoomList.findChatRoomWrapperFromChatRoom(chatRoom); - + if ((chatRoomWrapper == null) && create) { ChatRoomProviderWrapper parentProvider = chatRoomList.findServerWrapperFromProvider( chatRoom.getParentProvider()); - - chatRoomWrapper + + chatRoomWrapper = new ChatRoomWrapperImpl( parentProvider, chatRoom); - + chatRoomList.addChatRoom(chatRoomWrapper); } return chatRoomWrapper; } - + /** * Goes through the locally stored chat rooms list and for each * {@link ChatRoomWrapper} tries to find the corresponding server stored @@ -901,13 +901,13 @@ public void synchronizeOpSetWithLocalContactList( { chatRoomProvider = chatRoomList.addRegisteredChatProvider(protocolProvider); } - + if (chatRoomProvider != null) { chatRoomProvider.synchronizeProvider(); } } - + /** * Returns an iterator to the list of chat room providers. * @@ -917,7 +917,7 @@ public Iterator getChatRoomProviders() { return chatRoomList.getChatRoomProviders(); } - + /** * Removes the given ChatRoom from the list of all chat rooms. * @@ -938,7 +938,7 @@ public void addChatRoomProviderWrapperListener( { chatRoomList.addChatRoomProviderWrapperListener(listener); } - + /** * Removes the ChatRoomProviderWrapperListener to the listener list. * @@ -949,7 +949,7 @@ public void removeChatRoomProviderWrapperListener( { chatRoomList.removeChatRoomProviderWrapperListener(listener); } - + /** * Returns the ChatRoomProviderWrapper that correspond to the * given ProtocolProviderService. If the list doesn't contain a @@ -964,7 +964,7 @@ public ChatRoomProviderWrapper findServerWrapperFromProvider( { return chatRoomList.findServerWrapperFromProvider(protocolProvider); } - + /** * Returns the ChatRoomWrapper that correspond to the given * ChatRoom. If the list of chat rooms doesn't contain a @@ -978,10 +978,10 @@ public ChatRoomWrapper findChatRoomWrapperFromChatRoom(ChatRoom chatRoom) { return chatRoomList.findChatRoomWrapperFromChatRoom(chatRoom); } - + /** * Opens a chat window for the chat room. - * + * * @param room the chat room. */ public void openChatRoom(ChatRoomWrapper room) @@ -990,7 +990,7 @@ public void openChatRoom(ChatRoomWrapper room) { room = createChatRoom( room.getChatRoomName(), - room.getParentProvider().getProtocolProvider(), + room.getParentProvider().getProtocolProvider(), new ArrayList(),"", false, false, true); // leave the chatroom because getChatRoom().isJoined() returns true @@ -1007,22 +1007,22 @@ public void openChatRoom(ChatRoomWrapper room) .getParentProvider().getProtocolProvider(), room .getChatRoomID(), "userNickName"); String subject = null; - + if (savedNick == null) { String[] joinOptions = ChatRoomJoinOptionsDialog.getJoinOptions( - room.getParentProvider().getProtocolProvider(), + room.getParentProvider().getProtocolProvider(), room.getChatRoomID(), getDefaultNickname( room.getParentProvider().getProtocolProvider())); savedNick = joinOptions[0]; subject = joinOptions[1]; - + } - + if (savedNick != null) { - joinChatRoom(room, savedNick, null, + joinChatRoom(room, savedNick, null, subject); } else @@ -1031,7 +1031,7 @@ public void openChatRoom(ChatRoomWrapper room) MUCActivator.getUIService().openChatRoomWindow(room); } - + /** * Returns default nickname for chat room based on the given provider. * @param pps the given protocol provider service @@ -1042,13 +1042,13 @@ public String getDefaultNickname(ProtocolProviderService pps) final OperationSetServerStoredAccountInfo accountInfoOpSet = pps.getOperationSet( OperationSetServerStoredAccountInfo.class); - + String displayName = ""; if (accountInfoOpSet != null) { displayName = AccountInfoUtils.getDisplayName(accountInfoOpSet); } - + if(displayName == null || displayName.length() == 0) { displayName = MUCActivator.getGlobalDisplayDetailsService() @@ -1064,14 +1064,14 @@ public String getDefaultNickname(ProtocolProviderService pps) } } } - + return displayName; } - + /** - * Returns instance of the ServerChatRoomContactSourceService + * Returns instance of the ServerChatRoomContactSourceService * contact source. - * @return instance of the ServerChatRoomContactSourceService + * @return instance of the ServerChatRoomContactSourceService * contact source. */ public ContactSourceService getServerChatRoomsContactSourceForProvider( @@ -1079,4 +1079,15 @@ public ContactSourceService getServerChatRoomsContactSourceForProvider( { return new ServerChatRoomContactSourceService(pps); } + + /** + * Returns true if the contact is ChatRoomSourceContact + * + * @param contact the contact + * @return true if the contact is ChatRoomSourceContact + */ + public boolean isMUCSourceContact(SourceContact contact) + { + return (contact instanceof ChatRoomSourceContact); + } } diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetUserSearchJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetUserSearchJabberImpl.java new file mode 100644 index 000000000..a883272e1 --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetUserSearchJabberImpl.java @@ -0,0 +1,279 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.protocol.jabber; + +import java.util.*; + +import org.jivesoftware.smack.*; +import org.jivesoftware.smackx.*; +import org.jivesoftware.smackx.ReportedData.*; + +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.service.protocol.event.*; +import net.java.sip.communicator.util.*; + +/** + * This operation set provides utility methods for user search implementation. + * + * @author Hristo Terezov + */ +public class OperationSetUserSearchJabberImpl + implements OperationSetUserSearch, RegistrationStateChangeListener +{ + /** + * The logger. + */ + private static final Logger logger = + Logger.getLogger(OperationSetUserSearchJabberImpl.class); + + /** + * The UserSearchManager instance which actually implements the + * user search. + */ + private UserSearchManager searchManager = null; + + /** + * The ProtocolProviderService instance. + */ + private ProtocolProviderServiceJabberImpl provider; + + /** + * The user search service name. + */ + private String serviceName = null; + + /** + * Whether the user search service is enabled or not. + */ + private Boolean userSearchEnabled = false; + + /** + * A list of UserSearchProviderListener listeners which will be + * notified when the provider user search feature is enabled or disabled. + */ + private List listeners + = new ArrayList(); + + /** + * The property name of the user search service name. + */ + private static final String USER_SEARCH_SERVICE_NAME + = "USER_SEARCH_SERVICE_NAME"; + + /** + * Constructs new OperationSetUserSearchJabberImpl instance. + * @param provider the provider associated with the operation set. + */ + protected OperationSetUserSearchJabberImpl( + ProtocolProviderServiceJabberImpl provider) + { + this.provider = provider; + serviceName = provider.getAccountID().getAccountPropertyString( + USER_SEARCH_SERVICE_NAME, ""); + if(serviceName.equals("")) + { + provider.addRegistrationStateChangeListener(this); + } + else + { + setUserSearchEnabled(true); + } + } + + /** + * Sets the userSearchEnabled property and fires + * UserSearchProviderEvent event. + * + * @param isEnabled the value to be set. + */ + private void setUserSearchEnabled(boolean isEnabled) + { + userSearchEnabled = isEnabled; + int type = (isEnabled? UserSearchProviderEvent.PROVIDER_ADDED + : UserSearchProviderEvent.PROVIDER_REMOVED); + fireUserSearchProviderEvent(new UserSearchProviderEvent(provider, type)); + } + + /** + * Fires UserSearchProviderEvent event. + * @param event the event to be fired. + */ + private void fireUserSearchProviderEvent(UserSearchProviderEvent event) + { + List tmpListeners; + synchronized (listeners) + { + tmpListeners = new ArrayList(listeners); + } + for(UserSearchProviderListener l : tmpListeners) + l.onUserSearchProviderEvent(event); + } + + @Override + public void registrationStateChanged(RegistrationStateChangeEvent evt) + { + if(evt.getNewState().equals(RegistrationState.REGISTERED)) + { + discoverSearchService(); + } + else if(evt.getNewState() == RegistrationState.UNREGISTERED + || evt.getNewState() == RegistrationState.AUTHENTICATION_FAILED + || evt.getNewState() == RegistrationState.CONNECTION_FAILED) + { + synchronized (userSearchEnabled) + { + setUserSearchEnabled(false); + } + } + } + + /** + * Tries to discover the user search service name. + */ + private void discoverSearchService() + { + new Thread() + { + public void run() + { + synchronized (userSearchEnabled) + { + List serviceNames + = UserSearchManager.getAvailableServiceNames( + provider); + if(!serviceNames.isEmpty()) + { + serviceName = serviceNames.get(0); + setUserSearchEnabled(true); + } + else + { + setUserSearchEnabled(false); + } + } + + }; + }.start(); + } + + /** + * Creates the UserSearchManager instance. + */ + public void createSearchManager() + { + if(searchManager == null) + { + searchManager + = new UserSearchManager(provider.getConnection(), serviceName); + } + } + + /** + * Releases the UserSearchManager instance. + */ + public void removeSearchManager() + { + searchManager = null; + } + + /** + * Performs user search for the searched string and returns the JIDs of the + * found contacts. + * + * @param searchedString the text we want to query the server. + * @return the list of found JIDs + */ + public List search(String searchedString) + { + ReportedData data = null; + try + { + data = searchManager.searchForString(searchedString); + } + catch (XMPPException e) + { + logger.error(e); + return null; + } + + if(data == null) + { + logger.error("No data have been received from server."); + return null; + } + Iterator columns = data.getColumns(); + Iterator rows = data.getRows(); + if(columns == null || rows == null) + { + logger.error("The received data is corrupted."); + return null; + } + + Column jidColumn = null; + while(columns.hasNext()) + { + Column tmpCollumn = columns.next(); + if(tmpCollumn.getType().equals(FormField.TYPE_JID_SINGLE)) + { + jidColumn = tmpCollumn; + break; + } + } + + if(jidColumn == null) + { + logger.error("No jid collumn provided by the server."); + return null; + } + List result = new ArrayList(); + while(rows.hasNext()) + { + Row row = rows.next(); + result.add((String)row.getValues(jidColumn.getVariable()).next()); + } + return result; + } + + /** + * Adds UserSearchProviderListener instance to the list of + * listeners. + * + * @param l the listener to be added + */ + public void addUserSearchProviderListener(UserSearchProviderListener l) + { + synchronized (listeners) + { + if(!listeners.contains(l)) + listeners.add(l); + } + } + + /** + * Removes UserSearchProviderListener instance from the list of + * listeners. + * + * @param l the listener to be removed + */ + public void removeUserSearchProviderListener(UserSearchProviderListener l) + { + synchronized (listeners) + { + listeners.remove(l); + } + } + + /** + * Returns true if the user search service is enabled. + * + * @return true if the user search service is enabled. + */ + public boolean isEnabled() + { + return userSearchEnabled; + } +} diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java index d06553bd9..2b1c983b4 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java @@ -220,6 +220,12 @@ public class ProtocolProviderServiceJabberImpl private static final String XMPP_DSCP_PROPERTY = "net.java.sip.communicator.impl.protocol.XMPP_DSCP"; + /** + * Indicates if user search is disabled. + */ + private static final String IS_USER_SEARCH_DISABLED_PROPERTY + = "USER_SEARCH_DISABLED"; + /** * Google voice domain name. */ @@ -1858,6 +1864,14 @@ protected void initialize(String screenname, addSupportedOperationSet(OperationSetCusaxUtils.class, opsetCusaxCusaxUtils); + boolean isUserSearchDisabled = accountID.getAccountPropertyBoolean( + IS_USER_SEARCH_DISABLED_PROPERTY, true); + if(!isUserSearchDisabled) + { + addSupportedOperationSet(OperationSetUserSearch.class, + new OperationSetUserSearchJabberImpl(this)); + } + isInitialized = true; } } diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/ProviderManagerExt.java b/src/net/java/sip/communicator/impl/protocol/jabber/ProviderManagerExt.java index 32e73e4ca..71b50d9bf 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/ProviderManagerExt.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/ProviderManagerExt.java @@ -6,6 +6,7 @@ */ package net.java.sip.communicator.impl.protocol.jabber; +import net.java.sip.communicator.impl.protocol.jabber.extensions.usersearch.*; import net.java.sip.communicator.util.*; import org.jivesoftware.smack.packet.*; @@ -139,8 +140,7 @@ public void load() LastActivity.class); // - //addProvider("query", "jabber:iq:search", - // org.jivesoftware.smackx.search.UserSearch.Provider.class); + addProvider("query", "jabber:iq:search",UserSearchProvider.class); // //addProvider("sharedgroup", "http://www.jivesoftware.org/protocol/sharedgroup", diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/UserSearchManager.java b/src/net/java/sip/communicator/impl/protocol/jabber/UserSearchManager.java new file mode 100644 index 000000000..10975d78a --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/jabber/UserSearchManager.java @@ -0,0 +1,185 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.protocol.jabber; + +import net.java.sip.communicator.impl.protocol.jabber.extensions.usersearch.*; + +import org.jivesoftware.smack.*; +import org.jivesoftware.smack.filter.*; +import org.jivesoftware.smack.packet.*; +import org.jivesoftware.smackx.*; +import org.jivesoftware.smackx.packet.*; + +import java.util.*; + +/** + * The UserSearchManager implements the user search (XEP-0055). It + * implements searching a contacts by string. + * + * @author Hristo Terezov + */ +public class UserSearchManager { + /** + * The object that represents the connection to the server. + */ + private Connection con; + + /** + * Last received search form from the server. + */ + private UserSearchIQ userSearchForm = null; + + /** + * The user search service name. + */ + private String searchService; + + /** + * Creates a new UserSearchManager. + * + * @param con the Connection to use. + * @param searchService the user search service name. + */ + public UserSearchManager(Connection con, String searchService) { + this.con = con; + this.searchService = searchService; + } + + /** + * Returns a list with the available user search service names for a given + * provider. + * @param provider the provider. + * @return a list with the available user search service names for a given + * provider. + */ + public static List getAvailableServiceNames( + ProtocolProviderServiceJabberImpl provider) + { + final List searchServices = new ArrayList(); + ScServiceDiscoveryManager discoManager = provider.getDiscoveryManager(); + DiscoverItems items; + try + { + items = discoManager.discoverItems( + provider.getConnection().getServiceName()); + } + catch (XMPPException e) + { + return searchServices; + } + Iterator iter = items.getItems(); + while (iter.hasNext()) + { + DiscoverItems.Item item = iter.next(); + try + { + DiscoverInfo info; + info = discoManager.discoverInfo(item.getEntityID()); + + if (info.containsFeature("jabber:iq:search") + && !info.containsFeature("http://jabber.org/protocol/muc")) + { + searchServices.add(item.getEntityID()); + } + } + catch (Exception e) { + continue; + } + } + return searchServices; + } + + /** + * Returns the form to fill out to perform a search. + * + * @return the form to fill out to perform a search. + * @throws XMPPException thrown if a server error has occurred. + */ + private void getSearchForm() throws XMPPException { + UserSearchIQ search = new UserSearchIQ(); + search.setType(IQ.Type.GET); + search.setTo(searchService); + + PacketCollector collector = con.createPacketCollector( + new PacketIDFilter(search.getPacketID())); + con.sendPacket(search); + + IQ response = (IQ) collector.nextResult( + SmackConfiguration.getPacketReplyTimeout()); + + // Cancel the collector. + collector.cancel(); + if (response == null) { + throw new XMPPException("No response from server on status set."); + } + if (response.getError() != null) { + throw new XMPPException(response.getError()); + } + userSearchForm = (UserSearchIQ)response; + } + + /** + * Performs user search for the searched string. + * + * @param searchedString + * @return the ReportedData instance which represents the search + * results. + * @throws XMPPException thrown if a server error has occurred. + */ + public ReportedData searchForString(String searchedString) throws XMPPException + { + if(userSearchForm == null) + getSearchForm(); + UserSearchIQ search = new UserSearchIQ(); + search.setType(IQ.Type.SET); + search.setTo(searchService); + + Form form = userSearchForm.getAnswerForm(); + if(form != null) + { + Iterator fields = form.getFields(); + while (fields.hasNext()) + { + FormField formField = fields.next(); + if(formField.getType().equals(FormField.TYPE_BOOLEAN)) + { + form.setAnswer(formField.getVariable(), true); + } + else if(formField.getType().equals(FormField.TYPE_TEXT_SINGLE)) + { + form.setAnswer(formField.getVariable(), searchedString); + } + } + search.setForm(form.getDataFormToSend()); + } + else + { + for(String field : userSearchForm.getFields()) + search.addField(field, searchedString); + } + + PacketCollector collector = con.createPacketCollector( + new PacketIDFilter(search.getPacketID())); + + con.sendPacket(search); + + UserSearchIQ response = (UserSearchIQ) collector.nextResult( + SmackConfiguration.getPacketReplyTimeout()); + + // Cancel the collector. + collector.cancel(); + if (response == null) { + throw new XMPPException("No response from server on status set."); + } + if (response.getError() != null) { + throw new XMPPException(response.getError()); + } + + return response.getData(); + } + +} diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/usersearch/UserSearchIQ.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/usersearch/UserSearchIQ.java new file mode 100644 index 000000000..03b191eda --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/usersearch/UserSearchIQ.java @@ -0,0 +1,135 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.protocol.jabber.extensions.usersearch; + +import java.util.*; + +import org.jivesoftware.smack.packet.*; +import org.jivesoftware.smack.util.*; +import org.jivesoftware.smackx.*; +import org.jivesoftware.smackx.packet.*; + +/** + * Implements the IQ packets for user search (XEP-0055) + * + * @author Hristo Terezov + */ +public class UserSearchIQ extends IQ { + /** + * This field represents the result of the search. + */ + private ReportedData data; + + /** + * This map stores the supported fields that are not defined in the data + * form and their values. + */ + private Map simpleFieldsNames + = new HashMap(); + + @Override + public String getChildElementXML() { + StringBuilder buf = new StringBuilder(); + buf.append(""); + if(getExtension("x", "jabber:x:data") != null) + { + buf.append(getExtensionsXML()); + } + else + { + buf.append(getItemsToSearch()); + } + buf.append(""); + return buf.toString(); + } + + /** + * Sets the data property of the class. + * @param data the data to be set. + */ + public void setData(ReportedData data) + { + this.data = data; + } + + /** + * Returns the data property of the class. + * @return + */ + public ReportedData getData() + { + ReportedData data = ReportedData.getReportedDataFrom(this); + if(data == null) + return this.data; + return data; + } + + /** + * Adds filter field to the IQ packet and value for the field. + * @param field the field name. + * @param value the value of the field. + */ + public void addField(String field, String value) + { + simpleFieldsNames.put(field, value); + } + + /** + * Returns XML string with the fields that are not included in the data form + * @return XML string with the fields that are not included in the data form + */ + private String getItemsToSearch() { + StringBuilder buf = new StringBuilder(); + + if (simpleFieldsNames.isEmpty()) { + return ""; + } + + for (String name : simpleFieldsNames.keySet()) + { + String value = simpleFieldsNames.get(name); + if (value != null && value.trim().length() > 0) { + buf.append("<").append(name).append(">") + .append(StringUtils.escapeForXML(value)).append(""); + } + } + + return buf.toString(); + } + + /** + * Returns the names of the fields that are not included in the data form. + * @return the field names. + */ + public Set getFields() + { + return simpleFieldsNames.keySet(); + } + + /** + * Creates and returns answer form. + * @return the answer form. + */ + public Form getAnswerForm() + { + Form form = Form.getFormFrom(this); + if(form == null) + return null; + return form.createAnswerForm(); + } + + /** + * Sets data form in the IQ packet. + * @param form the form to be set. + */ + public void setForm(DataForm form) + { + addExtension(form); + } + +} diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/usersearch/UserSearchProvider.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/usersearch/UserSearchProvider.java new file mode 100644 index 000000000..fb55d1312 --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/usersearch/UserSearchProvider.java @@ -0,0 +1,145 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.protocol.jabber.extensions.usersearch; + +import java.util.*; + +import org.jivesoftware.smack.packet.*; +import org.jivesoftware.smack.provider.*; +import org.jivesoftware.smack.util.*; +import org.jivesoftware.smackx.*; +import org.jivesoftware.smackx.ReportedData.*; +import org.xmlpull.v1.*; + +/** + * Internal Search service Provider. It parses the UserSeachIQ packets. + */ +public class UserSearchProvider implements IQProvider +{ + public IQ parseIQ(XmlPullParser parser) throws Exception + { + UserSearchIQ search = new UserSearchIQ(); + boolean done = false; + + while (!done) + { + int eventType = parser.next(); + if (eventType == XmlPullParser.START_TAG + && parser.getName().equals("item")) + { + search.setData(parseItems(parser)); + return search; + } + else if (eventType == XmlPullParser.START_TAG + && parser.getName().equals("instructions")) + { + continue; + } + else if (eventType == XmlPullParser.START_TAG + && !parser.getNamespace().equals("jabber:x:data")) + { + search.addField(parser.getName(), null); + + } + else if (eventType == XmlPullParser.START_TAG + && parser.getNamespace().equals("jabber:x:data")) + { + // Otherwise, it must be a packet extension. + search.addExtension(PacketParserUtils.parsePacketExtension( + parser.getName(), parser.getNamespace(), parser)); + + } + else if (eventType == XmlPullParser.END_TAG) + { + if (parser.getName().equals("query")) + done = true; + } + } + + return search; + } + + /** + * Parses the items from the result packet. + * @param parser the parser. + * @return ReportedData instance with the search results. + * @throws Exception if parser error occurred. + */ + protected ReportedData parseItems(XmlPullParser parser) throws Exception + { + ReportedData data = new ReportedData(); + data.addColumn( + new ReportedData.Column("JID", "jid", FormField.TYPE_JID_SINGLE)); + + boolean done = false; + + List fields + = new ArrayList(); + + while (!done) + { + if (parser.getAttributeCount() > 0) + { + String jid = parser.getAttributeValue("", "jid"); + List valueList = new ArrayList(); + valueList.add(jid); + ReportedData.Field field = new ReportedData.Field("jid", valueList); + fields.add(field); + } + + int eventType = parser.next(); + + if (eventType == XmlPullParser.START_TAG + && parser.getName().equals("item")) + { + fields = new ArrayList(); + } + else if (eventType == XmlPullParser.END_TAG + && parser.getName().equals("item")) + { + ReportedData.Row row = new ReportedData.Row(fields); + data.addRow(row); + } + else if (eventType == XmlPullParser.START_TAG) + { + String name = parser.getName(); + String value = parser.nextText(); + + List valueList = new ArrayList(); + valueList.add(value); + ReportedData.Field field + = new ReportedData.Field(name, valueList); + fields.add(field); + + boolean exists = false; + Iterator cols = data.getColumns(); + while (cols.hasNext()) + { + ReportedData.Column column = cols.next(); + if (column.getVariable().equals(name)) + exists = true; + } + + // Column name should be the same + if (!exists) + { + ReportedData.Column column = new ReportedData.Column( + name, name, "text-single"); + data.addColumn(column); + } + } + else if (eventType == XmlPullParser.END_TAG) + { + if (parser.getName().equals("query")) + done = true; + } + + } + + return data; + } +} diff --git a/src/net/java/sip/communicator/plugin/usersearch/UserSearchActivator.java b/src/net/java/sip/communicator/plugin/usersearch/UserSearchActivator.java new file mode 100644 index 000000000..893688119 --- /dev/null +++ b/src/net/java/sip/communicator/plugin/usersearch/UserSearchActivator.java @@ -0,0 +1,376 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. See terms of license at gnu.org. + */ +package net.java.sip.communicator.plugin.usersearch; + +import java.util.*; + +import net.java.sip.communicator.service.contactsource.*; +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.service.protocol.event.*; +import net.java.sip.communicator.util.*; + +import org.jitsi.service.resources.ResourceManagementService; +import org.osgi.framework.*; + +/** + * Activates the user search plugin which includes the user search contact + * source. + * + * @author Hristo Terezov + */ +public class UserSearchActivator + implements BundleActivator +{ + /** + * List with the available protocol providers that may support user search. + */ + private static LinkedList userSearchProviders; + + /** + * The bundle context. + */ + public static BundleContext bundleContext; + + /** + * A listener for + */ + private static UserSearchProviderStateListener userSeachListener = null; + + /** + * A list with providers that support user search. + */ + private static LinkedList supportedProviders + = new LinkedList(); + + /** + * A list of listeners that will be notified about adding and removing + * providers that support user search. + */ + private static LinkedList listeners + = new LinkedList(); + + /** + * The ServiceRegistration instance for the contact source. + */ + private static ServiceRegistration contactSourceRegistration = null; + + /** + * The Logger used by the + * UserSearchActivator class for logging output. + */ + private static Logger logger = Logger.getLogger(UserSearchActivator.class); + + /** + * Contact source instance. + */ + private static UserSearchContactSource userSearchContactSource = null; + + /** + * The resource service. + */ + private static ResourceManagementService resources = null; + + /** + * Initializes a list of all currently providers and a list with the + * providers that support user search. + */ + public static void initUserSearchProviders() + { + if (userSearchProviders != null) + return; + + userSearchProviders = new LinkedList(); + + bundleContext.addServiceListener(new ProtocolProviderRegListener()); + + ServiceReference[] serRefs = null; + try + { + // get all registered provider factories + serRefs + = bundleContext.getServiceReferences( + ProtocolProviderFactory.class.getName(), + null); + } + catch (InvalidSyntaxException e) + { + logger.error("LoginManager : " + e); + } + + if (serRefs != null) + { + for (ServiceReference serRef : serRefs) + { + ProtocolProviderFactory providerFactory + = (ProtocolProviderFactory) + bundleContext.getService(serRef); + + ProtocolProviderService protocolProvider; + + for (AccountID accountID + : providerFactory.getRegisteredAccounts()) + { + serRef = providerFactory.getProviderForAccount(accountID); + + protocolProvider + = (ProtocolProviderService) bundleContext + .getService(serRef); + + handleProviderAdded(protocolProvider); + + } + } + } + return; + } + + /** + * Returns the list of providers that support user search. + * @return the list of providers that support user search. + */ + public static LinkedList getSupportedProviders() + { + return supportedProviders; + } + + /** + * Adds new UserSearchSupportedProviderListener to the list of + * listeners. + * @param listener the listener to be added. + */ + public static void addUserSearchSupportedProviderListener( + UserSearchSupportedProviderListener listener) + { + synchronized (listeners) + { + if(!listeners.contains(listener)) + listeners.add(listener); + } + } + + /** + * Removes UserSearchSupportedProviderListener from the list of + * listeners. + * @param listener the listener to be removed. + */ + public static void removeUserSearchSupportedProviderListener( + UserSearchSupportedProviderListener listener) + { + synchronized (listeners) + { + listeners.remove(listener); + } + } + + /** + * Listens for ProtocolProviderService registrations. + */ + private static class ProtocolProviderRegListener + implements ServiceListener + { + public void serviceChanged(ServiceEvent event) + { + ServiceReference serviceRef = event.getServiceReference(); + + // if the event is caused by a bundle being stopped, we don't want to + // know + if (serviceRef.getBundle().getState() == Bundle.STOPPING) + { + return; + } + + Object service = bundleContext.getService(serviceRef); + + // we don't care if the source service is not a protocol provider + if (!(service instanceof ProtocolProviderService)) + { + return; + } + + switch (event.getType()) + { + case ServiceEvent.REGISTERED: + handleProviderAdded((ProtocolProviderService) service); + break; + case ServiceEvent.UNREGISTERING: + handleProviderRemoved((ProtocolProviderService) service); + break; + } + } + } + + /** + * Handles the registration of a new ProtocolProviderService. Adds + * the given protocolProvider to the list of queried providers. + * + * @param protocolProvider the ProtocolProviderService to add + */ + private static void handleProviderAdded( + ProtocolProviderService protocolProvider) + { + if (protocolProvider.getOperationSet( + OperationSetServerStoredContactInfo.class) != null + && !userSearchProviders.contains(protocolProvider)) + { + OperationSetUserSearch opSet + = protocolProvider.getOperationSet(OperationSetUserSearch.class); + if(opSet == null) + return; + if(userSeachListener == null) + userSeachListener = new UserSearchProviderStateListener(); + opSet.addUserSearchProviderListener(userSeachListener); + if(opSet.isEnabled()) + addSupportedProvider(protocolProvider); + userSearchProviders.add(protocolProvider); + } + } + + /** + * Handles the un-registration of a ProtocolProviderService. + * Removes the given protocolProvider from the list of queried + * providers. + * + * @param protocolProvider the ProtocolProviderService to remove + */ + private static void handleProviderRemoved( + ProtocolProviderService protocolProvider) + { + if (userSearchProviders.contains(protocolProvider)) + { + userSearchProviders.remove(protocolProvider); + removeSupportedProvider(protocolProvider); + if(userSeachListener == null) + return; + OperationSetUserSearch opSet + = protocolProvider.getOperationSet(OperationSetUserSearch.class); + if(opSet == null) + return; + opSet.removeUserSearchProviderListener(userSeachListener); + } + + } + + /** + * Adds provider to the list of providers that support user search. + * @param provider the provider to be added + */ + private static void addSupportedProvider(ProtocolProviderService provider) + { + if(!supportedProviders.contains(provider)) + { + supportedProviders.add(provider); + LinkedList tmpListeners; + synchronized (listeners) + { + tmpListeners + = new LinkedList( + listeners); + } + + for(UserSearchSupportedProviderListener l : tmpListeners) + { + l.providerAdded(provider); + } + if(supportedProviders.size() == 1) + { + if(userSearchContactSource == null) + userSearchContactSource = new UserSearchContactSource(); + //register contact source + contactSourceRegistration = bundleContext.registerService( + ContactSourceService.class.getName(), + userSearchContactSource , + null); + } + } + + } + + /** + * Removes provider from the list of providers that support user search. + * @param provider the procider to be removed. + */ + private static void removeSupportedProvider( + ProtocolProviderService provider) + { + if(supportedProviders.contains(provider)) + { + supportedProviders.remove(provider); + for(UserSearchSupportedProviderListener l : listeners) + { + l.providerRemoved(provider); + } + + if(supportedProviders.isEmpty() + && contactSourceRegistration != null) + { + contactSourceRegistration.unregister(); + contactSourceRegistration = null; + } + } + } + + @Override + public void start(BundleContext context) throws Exception + { + bundleContext = context; + + initUserSearchProviders(); + + } + + @Override + public void stop(BundleContext context) throws Exception + { + userSeachListener = null; + userSearchProviders.clear(); + supportedProviders.clear(); + listeners.clear(); + contactSourceRegistration = null; + userSearchContactSource = null; + } + + /** + * Returns a reference to the ResourceManagementService implementation + * currently registered in the bundle context or null if no such + * implementation was found. + * + * @return a reference to a ResourceManagementService implementation + * currently registered in the bundle context or null if no such + * implementation was found. + */ + public static ResourceManagementService getResources() + { + if (resources == null) + { + resources + = ServiceUtils.getService( + bundleContext, ResourceManagementService.class); + } + + return resources; + } + + /** + * Listens for added or removed providers that support user search. + */ + private static class UserSearchProviderStateListener + implements UserSearchProviderListener + { + @Override + public void onUserSearchProviderEvent(UserSearchProviderEvent event) + { + if(event.getType() == UserSearchProviderEvent.PROVIDER_ADDED) + { + addSupportedProvider(event.getProvider()); + } + else if(event.getType() == UserSearchProviderEvent.PROVIDER_REMOVED) + { + removeSupportedProvider(event.getProvider()); + } + } + } + +} diff --git a/src/net/java/sip/communicator/plugin/usersearch/UserSearchContactSource.java b/src/net/java/sip/communicator/plugin/usersearch/UserSearchContactSource.java new file mode 100644 index 000000000..762c577d8 --- /dev/null +++ b/src/net/java/sip/communicator/plugin/usersearch/UserSearchContactSource.java @@ -0,0 +1,64 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. See terms of license at gnu.org. + */ +package net.java.sip.communicator.plugin.usersearch; + +import net.java.sip.communicator.service.contactsource.*; + +/** + * The user search contact source. + * + * @author Hristo Terezov + */ +public class UserSearchContactSource + implements ContactSourceService +{ + + /** + * The time to wait before actually start the searching. If the query is + * canceled before the timeout the query won't be started. + */ + public static final long QUERY_DELAY = 500; + + /** + * Returns the type of this contact source. + * + * @return the type of this contact source + */ + public int getType() + { + return SEARCH_TYPE; + } + + @Override + public String getDisplayName() + { + return UserSearchActivator.getResources().getI18NString( + "plugin.usersearch.USER_SEARCH"); + } + + @Override + public ContactQuery createContactQuery(String queryString) + { + return createContactQuery(queryString, -1); + } + + @Override + public ContactQuery createContactQuery(String queryString, int contactCount) + { + if(queryString == null) + queryString = ""; + + UserSearchQuery query = new UserSearchQuery(queryString, this); + return query; + } + + @Override + public int getIndex() + { + return 0; + } + +} diff --git a/src/net/java/sip/communicator/plugin/usersearch/UserSearchQuery.java b/src/net/java/sip/communicator/plugin/usersearch/UserSearchQuery.java new file mode 100644 index 000000000..0ba1fcb56 --- /dev/null +++ b/src/net/java/sip/communicator/plugin/usersearch/UserSearchQuery.java @@ -0,0 +1,295 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.plugin.usersearch; + +import java.util.*; +import java.util.regex.*; + +import net.java.sip.communicator.service.contactsource.*; +import net.java.sip.communicator.service.protocol.*; + +/** + * The UserSearchQuery is a query over + * UserSearchContactSource. + */ +public class UserSearchQuery + extends AsyncContactQuery + implements UserSearchSupportedProviderListener +{ + /** + * The query string. + */ + private String queryString; + + /** + * A list with the found contacts. + */ + private List contacts + = new LinkedList(); + + /** + * A list of providers that are already displayed. + */ + private List displayedProviders + = new LinkedList(); + + /** + * The number of the listeners added to the query. + */ + private int contactQueryListenersCount = 0; + + /** + * Creates an instance of ChatRoomQuery by specifying + * the parent contact source, the query string to match and the maximum + * result contacts to return. + * + * @param queryString the query string to match + * @param contactSource the parent contact source + */ + public UserSearchQuery(String queryString, + UserSearchContactSource contactSource) + { + super(contactSource, + Pattern.compile(queryString, Pattern.CASE_INSENSITIVE + | Pattern.LITERAL), true); + this.queryString = queryString; + + } + + @Override + protected void run() + { + try + { + Thread.sleep(UserSearchContactSource.QUERY_DELAY); + } + catch (InterruptedException e) + { } + if(getStatus() == QUERY_CANCELED) + return; + + for(ProtocolProviderService provider : + UserSearchActivator.getSupportedProviders()) + { + providerAdded(provider); + } + } + + /** + * Handles provider addition. + * + * @param provider the provider that was added. + */ + public void providerAdded(ProtocolProviderService provider) + { + synchronized (displayedProviders) + { + if(displayedProviders.contains(provider)) + return; + displayedProviders.add(provider); + } + + OperationSetUserSearch opSetUserSearch + = provider.getOperationSet( + OperationSetUserSearch.class); + if(opSetUserSearch == null) + { + return; + } + opSetUserSearch.createSearchManager(); + List jidList = opSetUserSearch.search(queryString); + if(jidList == null || jidList.isEmpty()) + return; + + List> supportedOpSets + = new ArrayList>(1); + supportedOpSets.add(OperationSetPersistentPresence.class); + + ContactDetail detail = new ContactDetail(queryString); + + for(String jid : jidList) + { + List contactDetails + = new LinkedList(); + + ContactDetail jidDetail = new ContactDetail(jid); + jidDetail.setSupportedOpSets(supportedOpSets); + + contactDetails.add(jidDetail); + + contactDetails.add(detail); + + UserSearchContact contact + = new UserSearchContact( + this, + getContactSource(), + jid, + contactDetails, + provider); + contact.setContactAddress(jid); + synchronized (contacts) + { + contacts.add(contact); + } + + fireContactReceived(contact); + } + } + + /** + * Handles provider removal. + * + * @param provider the provider that was removed. + */ + public void providerRemoved(ProtocolProviderService provider) + { + synchronized (displayedProviders) + { + displayedProviders.remove(provider); + } + + OperationSetUserSearch opSetUserSearch + = provider.getOperationSet( + OperationSetUserSearch.class); + if(opSetUserSearch == null) + return; + opSetUserSearch.removeSearchManager(); + List tmpContacts; + synchronized (contacts) + { + tmpContacts = new LinkedList(contacts); + } + for(UserSearchContact contact : tmpContacts) + { + if(contact.getProvider().equals(provider)) + { + synchronized (contacts) + { + contacts.remove(contact); + } + fireContactRemoved(contact); + } + } + } + + /** + * Releases the resources of the query. + */ + private void dispose() + { + UserSearchActivator.removeUserSearchSupportedProviderListener(this); + + synchronized (contacts) + { + contacts.clear(); + } + + synchronized (displayedProviders) + { + displayedProviders.clear(); + } + } + + /** + * Cancels this ContactQuery. + * + * @see ContactQuery#cancel() + */ + public void cancel() + { + dispose(); + + super.cancel(); + } + + /** + * If query has status changed to cancel, let's clear listeners. + * @param status {@link ContactQuery#QUERY_CANCELED}, + * {@link ContactQuery#QUERY_COMPLETED} + */ + public void setStatus(int status) + { + if(status == QUERY_CANCELED) + dispose(); + + super.setStatus(status); + } + + @Override + public void addContactQueryListener(ContactQueryListener l) + { + super.addContactQueryListener(l); + contactQueryListenersCount++; + if(contactQueryListenersCount == 1) + { + UserSearchActivator.addUserSearchSupportedProviderListener(this); + } + } + + @Override + public void removeContactQueryListener(ContactQueryListener l) + { + super.removeContactQueryListener(l); + contactQueryListenersCount--; + if(contactQueryListenersCount == 0) + { + dispose(); + } + } + + /** + * A specific user search source contact. + */ + private class UserSearchContact + extends SortedGenericSourceContact + { + /** + * The provider associated with the contact. + */ + private ProtocolProviderService provider; + + public UserSearchContact(ContactQuery parentQuery, + ContactSourceService cSourceService, String displayName, + List contactDetails, + ProtocolProviderService provider) + { + super(parentQuery, cSourceService, displayName, contactDetails); + this.provider = provider; + } + + /** + * Returns the provider associated with the contact. + * @return the provider associated with the contact. + */ + public ProtocolProviderService getProvider() + { + return provider; + } + + } + @Override + public List getQueryResults() + { + List queryResults; + synchronized (contacts) + { + queryResults = new LinkedList(contacts); + } + return queryResults; + } + + @Override + public int getQueryResultCount() + { + synchronized (contacts) + { + return contacts.size(); + } + } + +} + diff --git a/src/net/java/sip/communicator/plugin/usersearch/UserSearchSupportedProviderListener.java b/src/net/java/sip/communicator/plugin/usersearch/UserSearchSupportedProviderListener.java new file mode 100644 index 000000000..759df1a2f --- /dev/null +++ b/src/net/java/sip/communicator/plugin/usersearch/UserSearchSupportedProviderListener.java @@ -0,0 +1,31 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.plugin.usersearch; + +import net.java.sip.communicator.service.protocol.*; + +/** + * A interface for a listener that will be notified when providers that support + * user search are added or removed. + * @author Hristo Terezov + */ +public interface UserSearchSupportedProviderListener +{ + /** + * Handles provider addition. + * + * @param provider the provider that was added. + */ + public void providerAdded(ProtocolProviderService provider); + + /** + * Handles provider removal. + * + * @param provider the provider that was removed. + */ + public void providerRemoved(ProtocolProviderService provider); +} diff --git a/src/net/java/sip/communicator/plugin/usersearch/usersearch.manifest.mf b/src/net/java/sip/communicator/plugin/usersearch/usersearch.manifest.mf new file mode 100644 index 000000000..30c377cb0 --- /dev/null +++ b/src/net/java/sip/communicator/plugin/usersearch/usersearch.manifest.mf @@ -0,0 +1,12 @@ +Bundle-Activator: net.java.sip.communicator.plugin.usersearch.UserSearchActivator +Bundle-Name: User search contact source +Bundle-Description: User search contact source +Bundle-Vendor: jitsi.org +Bundle-Version: 0.0.1 +Bundle-SymbolicName: net.java.sip.communicator.plugin.usersearch +Import-Package: org.osgi.framework, + net.java.sip.communicator.service.contactsource, + net.java.sip.communicator.service.protocol, + net.java.sip.communicator.service.protocol.event, + net.java.sip.communicator.util, + org.jitsi.service.resources diff --git a/src/net/java/sip/communicator/service/muc/MUCService.java b/src/net/java/sip/communicator/service/muc/MUCService.java index 7728370ea..b2b157371 100644 --- a/src/net/java/sip/communicator/service/muc/MUCService.java +++ b/src/net/java/sip/communicator/service/muc/MUCService.java @@ -13,47 +13,47 @@ import net.java.sip.communicator.util.*; /** - * The MUC service provides interface for the chat rooms. It connects the GUI + * The MUC service provides interface for the chat rooms. It connects the GUI * with the protcol. - * + * * @author Hristo Terezov */ public abstract class MUCService { /** - * The value for chat room configuration property to open automatically on - * activity + * The value for chat room configuration property to open automatically on + * activity */ public static String OPEN_ON_ACTIVITY = "on_activity"; - + /** - * The value for chat room configuration property to open automatically on - * message + * The value for chat room configuration property to open automatically on + * message */ public static String OPEN_ON_MESSAGE = "on_message"; - + /** - * The value for chat room configuration property to open automatically on - * important messages. + * The value for chat room configuration property to open automatically on + * important messages. */ public static String OPEN_ON_IMPORTANT_MESSAGE = "on_important_message"; - + /** * Map for the auto open configuration values and their text representation */ public static Map autoOpenConfigValuesTexts = new HashMap(); - + static { - autoOpenConfigValuesTexts.put(OPEN_ON_ACTIVITY, + autoOpenConfigValuesTexts.put(OPEN_ON_ACTIVITY, "service.gui.OPEN_ON_ACTIVITY"); - autoOpenConfigValuesTexts.put(OPEN_ON_MESSAGE, + autoOpenConfigValuesTexts.put(OPEN_ON_MESSAGE, "service.gui.OPEN_ON_MESSAGE"); - autoOpenConfigValuesTexts.put(OPEN_ON_IMPORTANT_MESSAGE, + autoOpenConfigValuesTexts.put(OPEN_ON_IMPORTANT_MESSAGE, "service.gui.OPEN_ON_IMPORTANT_MESSAGE"); } - + /** * Sets chat room open automatically property * @param pps the provider @@ -69,7 +69,7 @@ public static void setChatRoomAutoOpenOption( pps, chatRoomId, "openAutomatically", value); } - + /** * Returns the value of the chat room open automatically property * @param pps the provider @@ -87,13 +87,13 @@ public static String getChatRoomAutoOpenOption( /** * Fires a ChatRoomListChangedEvent event. - * + * * @param chatRoomWrapper the chat room. * @param eventID the id of the event. */ public abstract void fireChatRoomListChangedEvent( ChatRoomWrapper chatRoomWrapper, int eventID); - + /** * Joins the given chat room with the given password and manages all the * exceptions that could occur during the join process. @@ -101,12 +101,12 @@ public abstract void fireChatRoomListChangedEvent( * @param chatRoomWrapper the chat room to join. * @param nickName the nickname we choose for the given chat room. * @param password the password. - * @param subject the subject which will be set to the room after the user + * @param subject the subject which will be set to the room after the user * join successful. */ public abstract void joinChatRoom( ChatRoomWrapper chatRoomWrapper, String nickName, byte[] password, String subject); - + /** * Creates a chat room, by specifying the chat room name, the parent * protocol provider and eventually, the contacts invited to participate in @@ -122,9 +122,9 @@ public abstract void joinChatRoom( ChatRoomWrapper chatRoomWrapper, public abstract ChatRoomWrapper createChatRoom(String roomName, ProtocolProviderService protocolProvider, Collection contacts, String reason, boolean persistent); - - - + + + /** * Creates a private chat room, by specifying the parent * protocol provider and eventually, the contacts invited to participate in @@ -139,8 +139,8 @@ public abstract ChatRoomWrapper createChatRoom(String roomName, public abstract ChatRoomWrapper createPrivateChatRoom( ProtocolProviderService protocolProvider, Collection contacts, String reason, boolean persistent); - - + + /** * Creates a chat room, by specifying the chat room name, the parent * protocol provider and eventually, the contacts invited to participate in @@ -158,7 +158,7 @@ public abstract ChatRoomWrapper createPrivateChatRoom( public abstract ChatRoomWrapper createChatRoom(String roomName, ProtocolProviderService protocolProvider, Collection contacts, String reason, boolean join, boolean persistent, boolean isPrivate); - + /** * Joins the room with the given name though the given chat room provider. * @@ -167,7 +167,7 @@ public abstract ChatRoomWrapper createChatRoom(String roomName, */ public abstract void joinChatRoom( String chatRoomName, ChatRoomProviderWrapper chatRoomProvider); - + /** * Returns existing chat rooms for the given chatRoomProvider. * @param chatRoomProvider the ChatRoomProviderWrapper, which @@ -176,8 +176,8 @@ public abstract void joinChatRoom( String chatRoomName, */ public abstract List getExistingChatRooms( ChatRoomProviderWrapper chatRoomProvider); - - + + /** * Called to accept an incoming invitation. Adds the invitation chat room * to the list of chat rooms and joins it. @@ -185,7 +185,7 @@ public abstract List getExistingChatRooms( * @param invitation the invitation to accept. */ public abstract void acceptInvitation(ChatRoomInvitation invitation); - + /** * Rejects the given invitation with the specified reason. * @@ -197,7 +197,7 @@ public abstract List getExistingChatRooms( public abstract void rejectInvitation( OperationSetMultiUserChat multiUserChatOpSet, ChatRoomInvitation invitation, String reason); - + /** * Determines whether a specific ChatRoom is private i.e. * represents a one-to-one conversation which is not a channel. Since the @@ -229,7 +229,7 @@ public static boolean isPrivate(ChatRoom chatRoom) } return false; } - + /** * Leaves the given chat room. * @@ -239,18 +239,18 @@ public static boolean isPrivate(ChatRoom chatRoom) public abstract ChatRoomWrapper leaveChatRoom(ChatRoomWrapper chatRoomWrapper); /** - * Finds ChatRoomWrapper instance associated with the given source + * Finds ChatRoomWrapper instance associated with the given source * contact. * @param contact the contact. - * @return ChatRoomWrapper instance associated with the given + * @return ChatRoomWrapper instance associated with the given * source contact. */ public abstract ChatRoomWrapper findChatRoomWrapperFromSourceContact( SourceContact contact); - + /** * Searches for chat room wrapper in chat room list by chat room. - * + * * @param chatRoom the chat room. * @param create if true and the chat room wrapper is not found new * chatRoomWrapper is created. @@ -258,7 +258,7 @@ public abstract ChatRoomWrapper findChatRoomWrapperFromSourceContact( */ public abstract ChatRoomWrapper getChatRoomWrapperByChatRoom( ChatRoom chatRoom, boolean create); - + /** * Returns the multi user chat operation set for the given protocol provider. * @@ -277,7 +277,7 @@ public static OperationSetMultiUserChat getMultiUserChatOpSet( ? (OperationSetMultiUserChat) opSet : null; } - + /** * Goes through the locally stored chat rooms list and for each * {@link ChatRoomWrapper} tries to find the corresponding server stored @@ -292,21 +292,21 @@ public static OperationSetMultiUserChat getMultiUserChatOpSet( public abstract void synchronizeOpSetWithLocalContactList( ProtocolProviderService protocolProvider, final OperationSetMultiUserChat opSet); - + /** * Returns an iterator to the list of chat room providers. * * @return an iterator to the list of chat room providers. */ public abstract Iterator getChatRoomProviders(); - + /** * Removes the given ChatRoom from the list of all chat rooms. * * @param chatRoomWrapper the ChatRoomWrapper to remove */ public abstract void removeChatRoom(ChatRoomWrapper chatRoomWrapper); - + /** * Adds a ChatRoomProviderWrapperListener to the listener list. * @@ -314,7 +314,7 @@ public abstract void synchronizeOpSetWithLocalContactList( */ public abstract void addChatRoomProviderWrapperListener( ChatRoomProviderWrapperListener listener); - + /** * Removes the ChatRoomProviderWrapperListener to the listener list. * @@ -322,7 +322,7 @@ public abstract void addChatRoomProviderWrapperListener( */ public abstract void removeChatRoomProviderWrapperListener( ChatRoomProviderWrapperListener listener); - + /** * Returns the ChatRoomProviderWrapper that correspond to the * given ProtocolProviderService. If the list doesn't contain a @@ -334,7 +334,7 @@ public abstract void removeChatRoomProviderWrapperListener( */ public abstract ChatRoomProviderWrapper findServerWrapperFromProvider( ProtocolProviderService protocolProvider); - + /** * Returns the ChatRoomWrapper that correspond to the given * ChatRoom. If the list of chat rooms doesn't contain a @@ -346,14 +346,14 @@ public abstract ChatRoomProviderWrapper findServerWrapperFromProvider( */ public abstract ChatRoomWrapper findChatRoomWrapperFromChatRoom( ChatRoom chatRoom); - + /** * Opens a chat window for the chat room. - * + * * @param room the chat room. */ public abstract void openChatRoom(ChatRoomWrapper room); - + /** * Returns default nickname for chat room based on the given provider. * @param pps the given protocol provider service @@ -361,14 +361,21 @@ public abstract ChatRoomWrapper findChatRoomWrapperFromChatRoom( */ public abstract String getDefaultNickname( ProtocolProviderService pps); - + /** - * Returns instance of the ServerChatRoomContactSourceService + * Returns instance of the ServerChatRoomContactSourceService * contact source. - * @return instance of the ServerChatRoomContactSourceService + * @return instance of the ServerChatRoomContactSourceService * contact source. */ - public abstract ContactSourceService + public abstract ContactSourceService getServerChatRoomsContactSourceForProvider(ChatRoomProviderWrapper pps); + /** + * Returns true if the contact is ChatRoomSourceContact + * + * @param contact the contact + * @return true if the contact is ChatRoomSourceContact + */ + public abstract boolean isMUCSourceContact(SourceContact contact); } diff --git a/src/net/java/sip/communicator/service/protocol/OperationSetUserSearch.java b/src/net/java/sip/communicator/service/protocol/OperationSetUserSearch.java new file mode 100644 index 000000000..d5e4759b9 --- /dev/null +++ b/src/net/java/sip/communicator/service/protocol/OperationSetUserSearch.java @@ -0,0 +1,62 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.service.protocol; + +import java.util.*; + +import net.java.sip.communicator.service.protocol.event.*; + +/** + * This operation set provides interface for user search service. + * + * @author Hristo Terezov + */ +public interface OperationSetUserSearch + extends OperationSet +{ + /** + * Creates the search manager. + */ + public void createSearchManager(); + + /** + * Removes search manager. + */ + public void removeSearchManager(); + + /** + * Performs user search for the searched string and returns the contact + * addresses of the found contacts. + * + * @param searchedString the text we want to query the server. + * @return the list of found contact addresses. + */ + public List search(String searchedString); + + /** + * Returns true if the user search service is enabled. + * + * @return true if the user search service is enabled. + */ + public boolean isEnabled(); + + /** + * Adds UserSearchProviderListener instance to the list of + * listeners. + * + * @param l the listener to be added + */ + public void addUserSearchProviderListener(UserSearchProviderListener l); + + /** + * Removes UserSearchProviderListener instance from the list of + * listeners. + * + * @param l the listener to be removed + */ + public void removeUserSearchProviderListener(UserSearchProviderListener l); +} diff --git a/src/net/java/sip/communicator/service/protocol/event/UserSearchProviderEvent.java b/src/net/java/sip/communicator/service/protocol/event/UserSearchProviderEvent.java new file mode 100644 index 000000000..763c7db9a --- /dev/null +++ b/src/net/java/sip/communicator/service/protocol/event/UserSearchProviderEvent.java @@ -0,0 +1,69 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. See terms of license at gnu.org. + */ +package net.java.sip.communicator.service.protocol.event; + +import java.util.EventObject; + +import net.java.sip.communicator.service.protocol.*; + +/** + * Notifies UserSearchProviderListener that a provider that supports + * user search is added or removed. + * @author Hristo Terezov + */ +public class UserSearchProviderEvent + extends EventObject +{ + /** + * The serial ID. + */ + private static final long serialVersionUID = -1285649707213476360L; + + /** + * A type that indicates that the provider is added. + */ + public static int PROVIDER_ADDED = 0; + + /** + * A type that indicates that the provider is removed. + */ + public static int PROVIDER_REMOVED = 1; + + /** + * The type of the event. + */ + private final int type; + + /** + * Constructs new UserSearchProviderEvent event. + * @param provider the provider. + * @param type the type of the event. + */ + public UserSearchProviderEvent(ProtocolProviderService provider, int type) + { + super(provider); + this.type = type; + } + + /** + * Returns the provider associated with the event. + * @return the provider associated with the event. + */ + public ProtocolProviderService getProvider() + { + return (ProtocolProviderService) getSource(); + } + + /** + * Returns the type of the event. + * @return the type of the event. + */ + public int getType() + { + return type; + } + +} diff --git a/src/net/java/sip/communicator/service/protocol/event/UserSearchProviderListener.java b/src/net/java/sip/communicator/service/protocol/event/UserSearchProviderListener.java new file mode 100644 index 000000000..a3ed0ff60 --- /dev/null +++ b/src/net/java/sip/communicator/service/protocol/event/UserSearchProviderListener.java @@ -0,0 +1,20 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. See terms of license at gnu.org. + */ +package net.java.sip.communicator.service.protocol.event; + +/** + * An interface for listener that will be notified when provider that supports + * user search is added or removed. + * @author Hristo Terezov + */ +public interface UserSearchProviderListener +{ + /** + * Notifies the listener with UserSearchProviderEvent event. + * @param event the event + */ + public void onUserSearchProviderEvent(UserSearchProviderEvent event); +}