diff --git a/resources/languages/resources.properties b/resources/languages/resources.properties
index e957d025a..dff8f40ab 100644
--- a/resources/languages/resources.properties
+++ b/resources/languages/resources.properties
@@ -290,6 +290,7 @@ service.gui.INSERT_SMILEY=Insert smiley
service.gui.INCOMING_CALL=Incoming call received from: {0}
service.gui.INCOMING_CALL_STATUS=Incoming call
service.gui.INSTANT_MESSAGINGS=IMs
+service.gui.IM=IM
service.gui.INITIATING_CALL_STATUS=Initiating call
service.gui.INVITATION=Invitation text
service.gui.INVITATION_RECEIVED=Invitation received
@@ -441,6 +442,7 @@ service.gui.PUT_OFF_HOLD=Put off hold
service.gui.PUT_ON_HOLD=Put on hold
service.gui.QUIT=&Quit
service.gui.READY=Ready
+service.gui.RECENT_MESSAGES=Recent messages
service.gui.REASON=Reason
service.gui.RECEIVED={0} received
service.gui.RECONNECTION_LIMIT_EXCEEDED=You have have been disconnecting and reconnecting to the server too fast. The following account: User name: {0}, Server name: {1} is temporarily banned and would have to wait a bit before trying to login again.
@@ -1010,6 +1012,7 @@ plugin.generalconfig.ERROR_PORT_NUMBER=Wrong port number
plugin.generalconfig.CHECK_FOR_UPDATES=Check for updates on startup
plugin.generalconfig.STARTUP_CONFIG=Startup
plugin.generalconfig.LEAVE_CHATROOM_ON_WINDOW_CLOSE=Leave chat rooms when closing window
+plugin.generalconfig.SHOW_RECENT_MESSAGES=Show recent messages (depends on chat history)
plugin.generalconfig.REMOVE_SPECIAL_PHONE_SYMBOLS=Remove special symbols before calling phone numbers
plugin.generalconfig.ACCEPT_PHONE_NUMBER_WITH_ALPHA_CHARS=Convert letters in phone numbers
plugin.generalconfig.ACCEPT_PHONE_NUMBER_WITH_ALPHA_CHARS_EXAMPLE=e.g. +1-800-MYPHONE -> +1-800-694663
diff --git a/src/net/java/sip/communicator/impl/contactlist/MetaContactListServiceImpl.java b/src/net/java/sip/communicator/impl/contactlist/MetaContactListServiceImpl.java
index 6bd71b33b..c12e8175e 100644
--- a/src/net/java/sip/communicator/impl/contactlist/MetaContactListServiceImpl.java
+++ b/src/net/java/sip/communicator/impl/contactlist/MetaContactListServiceImpl.java
@@ -3668,6 +3668,6 @@ public void supportedOperationSetsChanged(ContactCapabilitiesEvent event)
*/
public int getSourceIndex()
{
- return 1;
+ return 2;
}
}
diff --git a/src/net/java/sip/communicator/impl/msghistory/MessageHistoryActivator.java b/src/net/java/sip/communicator/impl/msghistory/MessageHistoryActivator.java
index b9562f343..484c5c469 100644
--- a/src/net/java/sip/communicator/impl/msghistory/MessageHistoryActivator.java
+++ b/src/net/java/sip/communicator/impl/msghistory/MessageHistoryActivator.java
@@ -11,6 +11,8 @@
import net.java.sip.communicator.service.msghistory.*;
import net.java.sip.communicator.util.*;
+import org.jitsi.service.configuration.*;
+import org.jitsi.service.resources.*;
import org.osgi.framework.*;
/**
@@ -32,13 +34,23 @@ public class MessageHistoryActivator
/**
* The MessageHistoryService reference.
*/
- private MessageHistoryServiceImpl msgHistoryService = null;
+ private static MessageHistoryServiceImpl msgHistoryService = null;
+
+ /**
+ * The ResourceManagementService reference.
+ */
+ private static ResourceManagementService resourcesService;
/**
* The MetaContactListService reference.
*/
private static MetaContactListService metaCListService;
+ /**
+ * The ConfigurationService reference.
+ */
+ private static ConfigurationService configService;
+
/**
* The BundleContext of the service.
*/
@@ -114,4 +126,52 @@ public static MetaContactListService getContactListService()
}
return metaCListService;
}
+
+ /**
+ * Returns the MessageHistoryService registered to the bundle
+ * context.
+ * @return the MessageHistoryService registered to the bundle
+ * context
+ */
+ public static MessageHistoryServiceImpl getMessageHistoryService()
+ {
+ return msgHistoryService;
+ }
+
+ /**
+ * Returns the ResourceManagementService, through which we will
+ * access all resources.
+ *
+ * @return the ResourceManagementService, through which we will
+ * access all resources.
+ */
+ public static ResourceManagementService getResources()
+ {
+ if (resourcesService == null)
+ {
+ resourcesService
+ = ServiceUtils.getService(
+ bundleContext,
+ ResourceManagementService.class);
+ }
+ return resourcesService;
+ }
+
+ /**
+ * Returns the ConfigurationService obtained from the bundle
+ * context.
+ * @return the ConfigurationService obtained from the bundle
+ * context
+ */
+ public static ConfigurationService getConfigurationService()
+ {
+ if(configService == null)
+ {
+ configService
+ = ServiceUtils.getService(
+ bundleContext,
+ ConfigurationService.class);
+ }
+ return configService;
+ }
}
diff --git a/src/net/java/sip/communicator/impl/msghistory/MessageHistoryServiceImpl.java b/src/net/java/sip/communicator/impl/msghistory/MessageHistoryServiceImpl.java
index 1c05a6588..27c9e5baf 100644
--- a/src/net/java/sip/communicator/impl/msghistory/MessageHistoryServiceImpl.java
+++ b/src/net/java/sip/communicator/impl/msghistory/MessageHistoryServiceImpl.java
@@ -15,6 +15,7 @@
import java.util.*;
import net.java.sip.communicator.service.contactlist.*;
+import net.java.sip.communicator.service.contactsource.*;
import net.java.sip.communicator.service.history.*;
import net.java.sip.communicator.service.history.event.*;
import net.java.sip.communicator.service.history.event.ProgressEvent;
@@ -27,7 +28,6 @@
import net.java.sip.communicator.util.account.*;
import org.jitsi.service.configuration.*;
-import org.jitsi.service.resources.*;
import org.osgi.framework.*;
/**
@@ -84,13 +84,20 @@ public class MessageHistoryServiceImpl
private MessageHistoryPropertyChangeListener msgHistoryPropListener;
- private static ResourceManagementService resourcesService;
-
/**
* Indicates if history logging is enabled.
*/
private static boolean isHistoryLoggingEnabled;
+ /**
+ * The message source service, can be null if not enabled.
+ */
+ private MessageSourceService messageSourceService;
+
+ /**
+ * The message source service registration.
+ */
+ private ServiceRegistration messageSourceServiceReg = null;
/**
* Returns the history service.
@@ -342,15 +349,20 @@ public Collection findLast(MetaContact contact, int count)
* Returns the messages for the recently contacted count contacts.
*
* @param count contacts count
+ * @param providerToFilter can be filtered by provider, or null to
+ * search for all providers
+ * @param contactToFilter can be filtered by contac, or null to
+ * search for all contacts
* @return Collection of MessageReceivedEvents or MessageDeliveredEvents
* @throws RuntimeException
*/
- Collection findRecentMessagesPerContact(int count)
+ Collection findRecentMessagesPerContact(
+ int count, String providerToFilter, String contactToFilter)
throws RuntimeException
{
TreeSet result
= new TreeSet(
- new MessageEventComparator());
+ new MessageEventComparator(true));
List historyIDs=
this.historyService.getExistingHistories(
@@ -363,11 +375,31 @@ Collection findRecentMessagesPerContact(int count)
try
{
- // find contact for historyID
- Contact contact = getContactForHistory(id);
+ // this history id is: "messages", localId, account, remoteId
+ if(id.getID().length != 4)
+ continue;
+
+ // filter by protocol provider
+ String accountID = id.getID()[2].replace('_', ':');
+ if(providerToFilter != null
+ && !accountID.startsWith(providerToFilter))
+ {
+ continue;
+ }
+
+ if(contactToFilter != null
+ && !contactToFilter.equals(id.getID()[3]))
+ {
+ continue;
+ }
+
+ // find contact or chatroom for historyID
+ Object descriptor = getContactOrRoomByID(
+ accountID,
+ id.getID()[3]);
// skip not found contacts, disabled accounts and hidden one
- if(contact == null)
+ if(descriptor == null)
continue;
History history;
@@ -386,8 +418,20 @@ Collection findRecentMessagesPerContact(int count)
Iterator recs = reader.findLast(1);
while (recs.hasNext())
{
- result.add(convertHistoryRecordToMessageEvent(
- recs.next(), contact));
+ if(descriptor instanceof Contact)
+ {
+ EventObject o = convertHistoryRecordToMessageEvent(
+ recs.next(), (Contact) descriptor);
+
+ result.add(o);
+ }
+ if(descriptor instanceof ChatRoom)
+ {
+ EventObject o = convertHistoryRecordToMessageEvent(
+ recs.next(), (ChatRoom) descriptor);
+
+ result.add(o);
+ }
break;
}
}
@@ -401,21 +445,16 @@ Collection findRecentMessagesPerContact(int count)
}
/**
- * Founds the contact corresponding this HistoryID. Checks the account and
- * then searches for the contact.
+ * Founds the contact or chat room corresponding this HistoryID. Checks the
+ * account and then searches for the contact or chat room.
* Will skip hidden and disabled accounts.
*
- * @param id the history id.
- * @return
+ * @param accountID the account id.
+ * @param id the contact or room id.
+ * @return contact or chat room.
*/
- private Contact getContactForHistory(HistoryID id)
+ private Object getContactOrRoomByID(String accountID, String id)
{
- // this history id is: "messages", localId, account, remoteId
- if(id.getID().length != 4)
- return null;
-
- String accountID = id.getID()[2].replace('_', ':');
-
AccountID account = null;
for(AccountID acc : AccountUtils.getStoredAccounts())
{
@@ -443,7 +482,29 @@ private Contact getContactForHistory(HistoryID id)
if(opSetPresence == null)
return null;
- return opSetPresence.findContactByID(id.getID()[3]);
+ Contact contact = opSetPresence.findContactByID(id);
+
+ if(contact != null)
+ return contact;
+
+ OperationSetMultiUserChat opSetMuc =
+ pps.getOperationSet(OperationSetMultiUserChat.class);
+
+ if(opSetMuc == null)
+ return null;
+
+ try
+ {
+ // will remove the server part
+ id = id.substring(0, id.lastIndexOf('@'));
+
+ return opSetMuc.findRoom(id);
+ }
+ catch(Exception e)
+ {
+ //logger.error("Cannot find room", e);
+ return null;
+ }
}
/**
@@ -915,7 +976,8 @@ public void start(BundleContext bc)
// service, and if not do not register the service.
boolean isMessageHistoryEnabled = configService.getBoolean(
MessageHistoryService.PNAME_IS_MESSAGE_HISTORY_ENABLED,
- Boolean.parseBoolean(getResources().getSettingsString(
+ Boolean.parseBoolean(
+ MessageHistoryActivator.getResources().getSettingsString(
MessageHistoryService.PNAME_IS_MESSAGE_HISTORY_ENABLED))
);
@@ -944,6 +1006,31 @@ public void start(BundleContext bc)
}
}
+ /**
+ * Loads and registers the contact source service.
+ */
+ private void loadRecentMessages()
+ {
+ this.messageSourceService = new MessageSourceService();
+ messageSourceServiceReg = bundleContext.registerService(
+ ContactSourceService.class.getName(),
+ messageSourceService, null);
+ }
+
+ /**
+ * Unloads the contact source service.
+ */
+ private void stopRecentMessages()
+ {
+ if(messageSourceServiceReg != null)
+ {
+ messageSourceServiceReg.unregister();
+ messageSourceServiceReg = null;
+
+ this.messageSourceService = null;
+ }
+ }
+
/**
* Stops the service.
*
@@ -1342,6 +1429,9 @@ private void handleProviderAdded(ProtocolProviderService provider)
if (opSetIm != null)
{
opSetIm.addMessageListener(this);
+
+ if(this.messageSourceService != null)
+ opSetIm.addMessageListener(messageSourceService);
}
else
{
@@ -1355,6 +1445,9 @@ private void handleProviderAdded(ProtocolProviderService provider)
if (opSetSMS != null)
{
opSetSMS.addMessageListener(this);
+
+ if(this.messageSourceService != null)
+ opSetIm.addMessageListener(messageSourceService);
}
else
{
@@ -1377,12 +1470,26 @@ private void handleProviderAdded(ProtocolProviderService provider)
}
opSetMultiUChat.addPresenceListener(this);
+
+ if(messageSourceService != null)
+ opSetMultiUChat.addPresenceListener(messageSourceService);
}
else
{
if (logger.isTraceEnabled())
logger.trace("Service did not have a multi im op. set.");
}
+
+ OperationSetPresence opSetPresence =
+ provider.getOperationSet(OperationSetPresence.class);
+
+ if (opSetPresence != null && messageSourceService != null)
+ {
+ opSetPresence
+ .addContactPresenceStatusListener(messageSourceService);
+ opSetPresence
+ .addProviderPresenceStatusListener(messageSourceService);
+ }
}
/**
@@ -1399,6 +1506,9 @@ private void handleProviderRemoved(ProtocolProviderService provider)
if (opSetIm != null)
{
opSetIm.removeMessageListener(this);
+
+ if(this.messageSourceService != null)
+ opSetIm.removeMessageListener(messageSourceService);
}
OperationSetSmsMessaging opSetSMS =
@@ -1407,6 +1517,9 @@ private void handleProviderRemoved(ProtocolProviderService provider)
if (opSetSMS != null)
{
opSetSMS.removeMessageListener(this);
+
+ if(this.messageSourceService != null)
+ opSetIm.removeMessageListener(messageSourceService);
}
OperationSetMultiUserChat opSetMultiUChat =
@@ -1422,6 +1535,22 @@ private void handleProviderRemoved(ProtocolProviderService provider)
ChatRoom room = iter.next();
room.removeMessageListener(this);
}
+
+ opSetMultiUChat.removePresenceListener(this);
+
+ if(messageSourceService != null)
+ opSetMultiUChat.removePresenceListener(messageSourceService);
+ }
+
+ OperationSetPresence opSetPresence =
+ provider.getOperationSet(OperationSetPresence.class);
+
+ if (opSetPresence != null && messageSourceService != null)
+ {
+ opSetPresence
+ .removeContactPresenceStatusListener(messageSourceService);
+ opSetPresence
+ .removeProviderPresenceStatusListener(messageSourceService);
}
}
@@ -1438,11 +1567,19 @@ public void localUserPresenceChanged(LocalUserChatRoomPresenceChangeEvent evt)
LocalUserChatRoomPresenceChangeEvent.LOCAL_USER_JOINED)
{
if (!evt.getChatRoom().isSystem())
+ {
evt.getChatRoom().addMessageListener(this);
+
+ if(this.messageSourceService != null)
+ evt.getChatRoom().addMessageListener(messageSourceService);
+ }
}
else
{
evt.getChatRoom().removeMessageListener(this);
+
+ if(this.messageSourceService != null)
+ evt.getChatRoom().removeMessageListener(messageSourceService);
}
}
@@ -2116,30 +2253,6 @@ public Collection findLastMessagesBefore( ChatRoom room,
return resultAsList.subList(startIndex, resultAsList.size());
}
- /**
- * Get ResourceManagementService registered.
- *
- * @return ResourceManagementService
- */
- public static ResourceManagementService getResources()
- {
- if (resourcesService == null)
- {
- ServiceReference serviceReference
- = MessageHistoryActivator.bundleContext
- .getServiceReference(ResourceManagementService.class.getName());
-
- if(serviceReference == null)
- return null;
-
- resourcesService = (ResourceManagementService)
- MessageHistoryActivator.bundleContext
- .getService(serviceReference);
- }
-
- return resourcesService;
- }
-
/**
* A wrapper around HistorySearchProgressListener
* that fires events for MessageHistorySearchProgressListener
@@ -2254,6 +2367,18 @@ public Date getMessageReceivedDate()
private static class MessageEventComparator
implements Comparator
{
+ private final boolean reverseOrder;
+
+ MessageEventComparator(boolean reverseOrder)
+ {
+ this.reverseOrder = reverseOrder;
+ }
+
+ MessageEventComparator()
+ {
+ this(false);
+ }
+
public int compare(T o1, T o2)
{
Date date1;
@@ -2263,6 +2388,10 @@ public int compare(T o1, T o2)
date1 = ((MessageDeliveredEvent)o1).getTimestamp();
else if(o1 instanceof MessageReceivedEvent)
date1 = ((MessageReceivedEvent)o1).getTimestamp();
+ else if(o1 instanceof ChatRoomMessageDeliveredEvent)
+ date1 = ((ChatRoomMessageDeliveredEvent)o1).getTimestamp();
+ else if(o1 instanceof ChatRoomMessageReceivedEvent)
+ date1 = ((ChatRoomMessageReceivedEvent)o1).getTimestamp();
else
return 0;
@@ -2270,10 +2399,17 @@ else if(o1 instanceof MessageReceivedEvent)
date2 = ((MessageDeliveredEvent)o2).getTimestamp();
else if(o2 instanceof MessageReceivedEvent)
date2 = ((MessageReceivedEvent)o2).getTimestamp();
+ else if(o2 instanceof ChatRoomMessageDeliveredEvent)
+ date2 = ((ChatRoomMessageDeliveredEvent)o2).getTimestamp();
+ else if(o2 instanceof ChatRoomMessageReceivedEvent)
+ date2 = ((ChatRoomMessageReceivedEvent)o2).getTimestamp();
else
return 0;
- return date1.compareTo(date2);
+ if(reverseOrder)
+ return date2.compareTo(date1);
+ else
+ return date1.compareTo(date2);
}
}
@@ -2410,15 +2546,35 @@ private class MessageHistoryPropertyChangeListener
{
public void propertyChange(PropertyChangeEvent evt)
{
- String newPropertyValue = (String) evt.getNewValue();
- isHistoryLoggingEnabled
- = new Boolean(newPropertyValue).booleanValue();
+ if(evt.getPropertyName()
+ .equals(MessageHistoryService.PNAME_IS_MESSAGE_HISTORY_ENABLED))
+ {
+ String newPropertyValue = (String) evt.getNewValue();
+ isHistoryLoggingEnabled
+ = new Boolean(newPropertyValue).booleanValue();
- // If the message history is not enabled we stop here.
- if (isHistoryLoggingEnabled)
- loadMessageHistoryService();
- else
- stop(bundleContext);
+ // If the message history is not enabled we stop here.
+ if (isHistoryLoggingEnabled)
+ loadMessageHistoryService();
+ else
+ stop(bundleContext);
+ }
+ else if(evt.getPropertyName().equals(
+ MessageHistoryService.PNAME_IS_RECENT_MESSAGES_DISABLED))
+ {
+ String newPropertyValue = (String) evt.getNewValue();
+ boolean isDisabled
+ = new Boolean(newPropertyValue).booleanValue();
+
+ if(isDisabled)
+ {
+ stopRecentMessages();
+ }
+ else if(isHistoryLoggingEnabled)
+ {
+ loadRecentMessages();
+ }
+ }
}
}
@@ -2429,6 +2585,17 @@ public void propertyChange(PropertyChangeEvent evt)
*/
private void loadMessageHistoryService()
{
+ configService.addPropertyChangeListener(
+ MessageHistoryService.PNAME_IS_RECENT_MESSAGES_DISABLED,
+ msgHistoryPropListener);
+
+ boolean isRecentMessagesDisabled = configService.getBoolean(
+ MessageHistoryService.PNAME_IS_RECENT_MESSAGES_DISABLED,
+ false);
+
+ if(!isRecentMessagesDisabled)
+ loadRecentMessages();
+
// start listening for newly register or removed protocol providers
bundleContext.addServiceListener(this);
diff --git a/src/net/java/sip/communicator/impl/msghistory/MessageSourceContact.java b/src/net/java/sip/communicator/impl/msghistory/MessageSourceContact.java
new file mode 100644
index 000000000..cbd1d9c26
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/msghistory/MessageSourceContact.java
@@ -0,0 +1,416 @@
+/*
+ * 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.msghistory;
+
+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 java.util.*;
+
+/**
+ * Represents a contact source displaying a recent message for contact.
+ * @author Damian Minkov
+ */
+public class MessageSourceContact
+ extends DataObject
+ implements SourceContact,
+ Comparable
+{
+ /**
+ * The parent service.
+ */
+ private final MessageSourceService service;
+
+ /**
+ * The address.
+ */
+ private String address = null;
+
+ /**
+ * The display name.
+ */
+ private String displayName = null;
+
+ /**
+ * The protocol provider.
+ */
+ private ProtocolProviderService ppService = null;
+
+ /**
+ * The status.
+ */
+ private PresenceStatus status = null;
+
+ /**
+ * The image.
+ */
+ private byte[] image = null;
+
+ /**
+ * The message content.
+ */
+ private String messageContent = null;
+
+ /**
+ * A list of all contact details.
+ */
+ private final List contactDetails
+ = new LinkedList();
+
+ /**
+ * The contact instance.
+ */
+ private Contact contact = null;
+
+ /**
+ * The room instance.
+ */
+ private ChatRoom room = null;
+
+ /**
+ * The timestamp.
+ */
+ private Date timestamp = null;
+
+ /**
+ * The protocol provider.
+ * @return the protocol provider.
+ */
+ public ProtocolProviderService getProtocolProviderService()
+ {
+ return ppService;
+ }
+
+ /**
+ * Constructs MessageSourceContact.
+ * @param source the source event.
+ * @param service the message source service.
+ */
+ MessageSourceContact(EventObject source,
+ MessageSourceService service)
+ {
+ update(source);
+
+ if(source instanceof MessageDeliveredEvent
+ || source instanceof MessageReceivedEvent)
+ {
+ initDetails(false);
+ }
+ else if(source instanceof ChatRoomMessageDeliveredEvent
+ || source instanceof ChatRoomMessageReceivedEvent)
+ {
+ initDetails(true);
+ }
+
+ this.service = service;
+
+ if(this.messageContent != null
+ && this.messageContent.length() > 60)
+ {
+ // do not display too long texts
+ this.messageContent = this.messageContent.substring(0, 60);
+ this.messageContent += "...";
+ }
+ }
+
+ /**
+ * Updates fields.
+ * @param source the event object
+ */
+ void update(EventObject source)
+ {
+ if(source instanceof MessageDeliveredEvent)
+ {
+ MessageDeliveredEvent e = (MessageDeliveredEvent)source;
+
+ this.contact = e.getDestinationContact();
+
+ this.address = contact.getAddress();
+ this.displayName = contact.getDisplayName();
+ this.ppService = contact.getProtocolProvider();
+ this.image = contact.getImage();
+ this.status = contact.getPresenceStatus();
+ this.messageContent = e.getSourceMessage().getContent();
+ this.timestamp = e.getTimestamp();
+ }
+ else if(source instanceof MessageReceivedEvent)
+ {
+ MessageReceivedEvent e = (MessageReceivedEvent)source;
+
+ this.contact = e.getSourceContact();
+
+ this.address = contact.getAddress();
+ this.displayName = contact.getDisplayName();
+ this.ppService = contact.getProtocolProvider();
+ this.image = contact.getImage();
+ this.status = contact.getPresenceStatus();
+ this.messageContent = e.getSourceMessage().getContent();
+ this.timestamp = e.getTimestamp();
+ }
+ else if(source instanceof ChatRoomMessageDeliveredEvent)
+ {
+ ChatRoomMessageDeliveredEvent e
+ = (ChatRoomMessageDeliveredEvent)source;
+
+ this.room = e.getSourceChatRoom();
+
+ this.address = room.getIdentifier();
+ this.displayName = room.getName();
+ this.ppService = room.getParentProvider();
+ this.image = null;
+ this.status = null;
+ this.messageContent = e.getMessage().getContent();
+ this.timestamp = e.getTimestamp();
+ }
+ else if(source instanceof ChatRoomMessageReceivedEvent)
+ {
+ ChatRoomMessageReceivedEvent e
+ = (ChatRoomMessageReceivedEvent)source;
+
+ this.room = e.getSourceChatRoom();
+
+ this.address = room.getIdentifier();
+ this.displayName = room.getName();
+ this.ppService = room.getParentProvider();
+ this.image = null;
+ this.status = null;
+ this.messageContent = e.getMessage().getContent();
+ this.timestamp = e.getTimestamp();
+ }
+ }
+
+ /**
+ * We will the details for this source contact.
+ * Will skip OperationSetBasicInstantMessaging for chat rooms.
+ * @param isChatRoom is current source contact a chat room.
+ */
+ private void initDetails(boolean isChatRoom)
+ {
+ ContactDetail contactDetail =
+ new ContactDetail(
+ this.address,
+ this.displayName);
+
+ Map, ProtocolProviderService>
+ preferredProviders;
+
+ ProtocolProviderService preferredProvider
+ = this.ppService;
+
+ if (preferredProvider != null)
+ {
+ preferredProviders
+ = new Hashtable,
+ ProtocolProviderService>();
+
+ LinkedList> supportedOpSets
+ = new LinkedList>();
+
+ for(Class extends OperationSet> opset
+ : preferredProvider.getSupportedOperationSetClasses())
+ {
+ // skip opset IM as we want explicitly muc support
+ if(opset.equals(OperationSetPresence.class)
+ || opset.equals(OperationSetPersistentPresence.class)
+ || (isChatRoom
+ && opset.equals(
+ OperationSetBasicInstantMessaging.class)))
+ {
+ continue;
+ }
+
+ preferredProviders.put(opset, preferredProvider);
+
+ supportedOpSets.add(opset);
+ }
+
+ contactDetail.setPreferredProviders(preferredProviders);
+
+ contactDetail.setSupportedOpSets(supportedOpSets);
+ }
+
+ contactDetails.add(contactDetail);
+ }
+
+ @Override
+ public String getDisplayName()
+ {
+ if(this.displayName != null)
+ return this.displayName;
+ else
+ return MessageHistoryActivator.getResources()
+ .getI18NString("service.gui.UNKNOWN");
+ }
+
+ @Override
+ public String getContactAddress()
+ {
+ if(this.address != null)
+ return this.address;
+
+ return null;
+ }
+
+ @Override
+ public ContactSourceService getContactSource()
+ {
+ return service;
+ }
+
+ @Override
+ public String getDisplayDetails()
+ {
+ return messageContent;
+ }
+
+ /**
+ * Returns a list of available contact details.
+ * @return a list of available contact details
+ */
+ @Override
+ public List getContactDetails()
+ {
+ return new LinkedList(contactDetails);
+ }
+
+ /**
+ * Returns a list of all ContactDetails supporting the given
+ * OperationSet class.
+ * @param operationSet the OperationSet class we're looking for
+ * @return a list of all ContactDetails supporting the given
+ * OperationSet class
+ */
+ @Override
+ public List getContactDetails(
+ Class extends OperationSet> operationSet)
+ {
+ List res = new LinkedList();
+
+ for(ContactDetail det : contactDetails)
+ {
+ if(det.getPreferredProtocolProvider(operationSet) != null)
+ res.add(det);
+ }
+
+ return res;
+ }
+
+ /**
+ * Returns a list of all ContactDetails corresponding to the given
+ * category.
+ * @param category the OperationSet class we're looking for
+ * @return a list of all ContactDetails corresponding to the given
+ * category
+ */
+ @Override
+ public List getContactDetails(
+ ContactDetail.Category category)
+ throws OperationNotSupportedException
+ {
+ // We don't support category for message source history details,
+ // so we return null.
+ throw new OperationNotSupportedException(
+ "Categories are not supported for message source contact history.");
+ }
+
+ /**
+ * Returns the preferred ContactDetail for a given
+ * OperationSet class.
+ * @param operationSet the OperationSet class, for which we would
+ * like to obtain a ContactDetail
+ * @return the preferred ContactDetail for a given
+ * OperationSet class
+ */
+ @Override
+ public ContactDetail getPreferredContactDetail(
+ Class extends OperationSet> operationSet)
+ {
+ return contactDetails.get(0);
+ }
+
+ @Override
+ public byte[] getImage()
+ {
+ return image;
+ }
+
+ @Override
+ public boolean isDefaultImage()
+ {
+ return image == null;
+ }
+
+ @Override
+ public void setContactAddress(String contactAddress)
+ {}
+
+ @Override
+ public PresenceStatus getPresenceStatus()
+ {
+ return status;
+ }
+
+ /**
+ * Sets current status.
+ * @param status
+ */
+ public void setStatus(PresenceStatus status)
+ {
+ this.status = status;
+ }
+
+ @Override
+ public int getIndex()
+ {
+ return service.getIndex(this);
+ }
+
+ /**
+ * The contact.
+ * @return the contact.
+ */
+ public Contact getContact()
+ {
+ return contact;
+ }
+
+ /**
+ * The room.
+ * @return the room.
+ */
+ public ChatRoom getRoom()
+ {
+ return room;
+ }
+
+ /**
+ * The timestamp of the message.
+ * @return the timestamp of the message.
+ */
+ public Date getTimestamp()
+ {
+ return timestamp;
+ }
+
+ /**
+ * Compares two MessageSourceContacts.
+ * @param o the object to compare with
+ * @return 0, less than zero, greater than zero, if equals, less or greater.
+ */
+ @Override
+ public int compareTo(MessageSourceContact o)
+ {
+ if(o == null
+ || o.getTimestamp() == null)
+ return 1;
+
+ return o.getTimestamp()
+ .compareTo(getTimestamp());
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/msghistory/MessageSourceService.java b/src/net/java/sip/communicator/impl/msghistory/MessageSourceService.java
new file mode 100644
index 000000000..50dff396e
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/msghistory/MessageSourceService.java
@@ -0,0 +1,684 @@
+/*
+ * 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.msghistory;
+
+import net.java.sip.communicator.service.contactsource.*;
+import net.java.sip.communicator.service.history.*;
+import net.java.sip.communicator.service.history.records.*;
+import net.java.sip.communicator.service.muc.*;
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.service.protocol.event.*;
+import org.jitsi.util.*;
+
+import java.beans.*;
+import java.io.*;
+import java.text.*;
+import java.util.*;
+import java.util.regex.*;
+
+/**
+ * The source contact service. The will show most recent messages.
+ *
+ * @author Damian Minkov
+ */
+public class MessageSourceService
+ implements ContactSourceService,
+ ContactPresenceStatusListener,
+ ProviderPresenceStatusListener,
+ LocalUserChatRoomPresenceListener,
+ MessageListener,
+ ChatRoomMessageListener,
+ AdHocChatRoomMessageListener
+{
+ /**
+ * The logger for this class.
+ */
+ private static Logger logger = Logger
+ .getLogger(MessageSourceService.class);
+
+ /**
+ * The display name of this contact source.
+ */
+ private final String MESSAGE_HISTORY_NAME;
+
+ /**
+ * The type of the source service, the place to be shown in the ui.
+ */
+ private int sourceServiceType = RECENT_MESSAGES_TYPE;
+
+ /**
+ * Whether to show recent messages in history or in contactlist.
+ * By default we show it in contactlist.
+ */
+ private static final String IN_HISTORY_PROPERTY
+ = "net.java.sip.communicator.impl.msghistory.contactsrc.IN_HISTORY";
+
+ /**
+ * Property to control number of recent messages.
+ */
+ private static final String NUMBER_OF_RECENT_MSGS_PROP
+ = "net.java.sip.communicator.impl.msghistory.contactsrc.MSG_NUMBER";
+
+ /**
+ * Number of messages to show.
+ */
+ private int numberOfMessages = 10;
+
+ /**
+ * The structure to save recent messages list.
+ */
+ private static final String[] STRUCTURE_NAMES
+ = new String[] { "provider", "contact"};
+
+ /**
+ * The structure.
+ */
+ private static final HistoryRecordStructure recordStructure =
+ new HistoryRecordStructure(STRUCTURE_NAMES);
+
+ /**
+ * Recent messages history ID.
+ */
+ private static final HistoryID historyID = HistoryID.createFromRawID(
+ new String[] { "recent_messages"});
+
+ /**
+ * List of recent messages.
+ */
+ private List recentMessages = null;
+
+ /**
+ * The last query created.
+ */
+ private MessageHistoryContactQuery recentQuery = null;
+
+ /**
+ * Constructs MessageSourceService.
+ */
+ MessageSourceService()
+ {
+ if(MessageHistoryActivator.getConfigurationService()
+ .getBoolean(IN_HISTORY_PROPERTY , false))
+ {
+ sourceServiceType = HISTORY_TYPE;
+ }
+
+ MESSAGE_HISTORY_NAME = MessageHistoryActivator.getResources()
+ .getI18NString("service.gui.RECENT_MESSAGES");
+
+ numberOfMessages = MessageHistoryActivator.getConfigurationService()
+ .getInt(NUMBER_OF_RECENT_MSGS_PROP, numberOfMessages);
+ }
+
+ /**
+ * Returns the display name of this contact source.
+ * @return the display name of this contact source
+ */
+ @Override
+ public String getDisplayName()
+ {
+ return MESSAGE_HISTORY_NAME;
+ }
+
+ /**
+ * Returns default type to indicate that this contact source can be queried
+ * by default filters.
+ *
+ * @return the type of this contact source
+ */
+ @Override
+ public int getType()
+ {
+ return sourceServiceType;
+ }
+
+ /**
+ * Returns the index of the contact source in the result list.
+ *
+ * @return the index of the contact source in the result list
+ */
+ @Override
+ public int getIndex()
+ {
+ return 0;
+ }
+
+ /**
+ * Creates query for the given searchString.
+ * @param queryString the string to search for
+ * @return the created query
+ */
+ @Override
+ public ContactQuery createContactQuery(String queryString)
+ {
+ recentQuery =
+ (MessageHistoryContactQuery)createContactQuery(
+ queryString, numberOfMessages);
+
+ return recentQuery;
+ }
+
+ private List getRecentMessages()
+ {
+ if(recentMessages == null)
+ {
+ // find locally stored list of recent messages
+ // time, provider, contact
+ List cachedRecent
+ = getRecentMessagesFromHistory();
+
+ if(cachedRecent != null)
+ {
+ recentMessages = cachedRecent;
+
+ Collections.sort(recentMessages);
+
+ return recentMessages;
+ }
+
+ recentMessages = new LinkedList();
+
+ // If missing search and construct it and save it
+
+ MessageHistoryServiceImpl msgHistoryService =
+ MessageHistoryActivator.getMessageHistoryService();
+ Collection res = msgHistoryService
+ .findRecentMessagesPerContact(numberOfMessages, null, null);
+
+ for(EventObject obj : res)
+ {
+ recentMessages.add(
+ new MessageSourceContact(obj, MessageSourceService.this));
+ }
+ Collections.sort(recentMessages);
+
+ // save it
+ saveRecentMessagesToHistory();
+ }
+
+ return recentMessages;
+ }
+
+ /**
+ * Loads recent messages if saved in history.
+ * @return
+ */
+ private List getRecentMessagesFromHistory()
+ {
+ MessageHistoryServiceImpl msgService
+ = MessageHistoryActivator.getMessageHistoryService();
+ HistoryService historyService = msgService.getHistoryService();
+
+ List res
+ = new LinkedList();
+
+ // and load it
+ try
+ {
+ SimpleDateFormat sdf
+ = new SimpleDateFormat(HistoryService.DATE_FORMAT);
+
+ History history;
+ if (historyService.isHistoryExisting(historyID))
+ history = historyService.getHistory(historyID);
+ else
+ history
+ = historyService.createHistory(historyID, recordStructure);
+
+ Iterator recs
+ = history.getReader().findLast(numberOfMessages);
+ while(recs.hasNext())
+ {
+ HistoryRecord hr = recs.next();
+
+ String provider = null;
+ String contact = null;
+
+ for (int i = 0; i < hr.getPropertyNames().length; i++)
+ {
+ String propName = hr.getPropertyNames()[i];
+
+ if (propName.equals(STRUCTURE_NAMES[0]))
+ provider = hr.getPropertyValues()[i];
+ else if (propName.equals(STRUCTURE_NAMES[1]))
+ contact = hr.getPropertyValues()[i];
+ }
+
+ if(provider == null || contact == null)
+ return res;
+
+ for(EventObject ev : msgService.findRecentMessagesPerContact(
+ numberOfMessages, provider, contact))
+ {
+ res.add(new MessageSourceContact(ev, this));
+ }
+ }
+ }
+ catch(IOException ex)
+ {
+ logger.error("cannot create recent_messages history", ex);
+ return null;
+ }
+
+ return res;
+ }
+
+ /**
+ * Saves cached list of recent messages in history.
+ */
+ private void saveRecentMessagesToHistory()
+ {
+ HistoryService historyService = MessageHistoryActivator
+ .getMessageHistoryService().getHistoryService();
+
+ if (historyService.isHistoryExisting(historyID))
+ {
+ // delete it
+ try
+ {
+ historyService.purgeLocallyStoredHistory(historyID);
+ }
+ catch(IOException ex)
+ {
+ logger.error("Cannot delete recent_messages history", ex);
+ return;
+ }
+ }
+
+ // and create it
+ try
+ {
+ History history = historyService.createHistory(
+ historyID, recordStructure);
+
+ HistoryWriter writer = history.getWriter();
+ SimpleDateFormat sdf
+ = new SimpleDateFormat(HistoryService.DATE_FORMAT);
+
+ for(MessageSourceContact msc : recentMessages)
+ {
+ writer.addRecord(
+ new String[]
+ {
+ msc.getProtocolProviderService()
+ .getAccountID().getAccountUniqueID(),
+ msc.getContactAddress()
+ });
+ }
+ }
+ catch(IOException ex)
+ {
+ logger.error("cannot create recent_messages history", ex);
+ return;
+ }
+ }
+
+ /**
+ * Returns the index of the source contact, in the list of recent messages.
+ * @param messageSourceContact
+ * @return
+ */
+ int getIndex(MessageSourceContact messageSourceContact)
+ {
+ return recentMessages.indexOf(messageSourceContact);
+ }
+
+ /**
+ * Creates query for the given searchString.
+ * @param queryString the string to search for
+ * @param contactCount the maximum count of result contacts
+ * @return the created query
+ */
+ @Override
+ public ContactQuery createContactQuery(String queryString, int contactCount)
+ {
+ if(!StringUtils.isNullOrEmpty(queryString))
+ return null;
+
+ recentQuery = new MessageHistoryContactQuery(numberOfMessages);
+
+ return recentQuery;
+ }
+
+ /**
+ * Updates contact source contacts with status.
+ * @param evt the ContactPresenceStatusChangeEvent describing the status
+ */
+ @Override
+ public void contactPresenceStatusChanged(ContactPresenceStatusChangeEvent evt)
+ {
+ if(recentQuery == null)
+ return;
+
+ for(MessageSourceContact msgSC : getRecentMessages())
+ {
+ if(msgSC.getContact() != null
+ && msgSC.getContact().equals(evt.getSourceContact()))
+ {
+ msgSC.setStatus(evt.getNewStatus());
+ recentQuery.fireContactChanged(msgSC);
+ }
+ }
+ }
+
+ @Override
+ public void providerStatusChanged(ProviderPresenceStatusChangeEvent evt)
+ {
+ if(!evt.getNewStatus().isOnline())
+ return;
+
+ // now check for chat rooms as we are connected
+ MessageHistoryServiceImpl msgHistoryService =
+ MessageHistoryActivator.getMessageHistoryService();
+ Collection res = msgHistoryService
+ .findRecentMessagesPerContact(
+ numberOfMessages,
+ evt.getProvider().getAccountID().getAccountUniqueID(),
+ null);
+
+ List recentMessagesForProvider = new LinkedList();
+ for(MessageSourceContact msc : recentMessages)
+ {
+ if(msc.getProtocolProviderService().equals(evt.getProvider()))
+ recentMessagesForProvider.add(msc.getContactAddress());
+ }
+
+ List newContactSources
+ = new LinkedList();
+ for(EventObject obj : res)
+ {
+ if(obj instanceof ChatRoomMessageDeliveredEvent
+ || obj instanceof ChatRoomMessageReceivedEvent)
+ {
+ MessageSourceContact msc
+ = new MessageSourceContact(obj, MessageSourceService.this);
+
+ if(recentMessagesForProvider.contains(msc.getContactAddress()))
+ continue;
+
+ recentMessages.add(msc);
+ newContactSources.add(msc);
+
+ }
+ }
+
+ // sort
+ Collections.sort(recentMessages);
+
+ // and now fire events to update ui
+ if(recentQuery != null)
+ {
+ for(MessageSourceContact msc : newContactSources)
+ {
+ recentQuery.addQueryResult(msc);
+ }
+ }
+ }
+
+ @Override
+ public void providerStatusMessageChanged(PropertyChangeEvent evt)
+ {}
+
+ @Override
+ public void localUserPresenceChanged(
+ LocalUserChatRoomPresenceChangeEvent evt)
+ {
+ if(recentQuery == null)
+ return;
+
+ MessageSourceContact srcContact = null;
+ for(MessageSourceContact msg : getRecentMessages())
+ {
+ if(msg.getRoom() != null
+ && msg.getRoom().equals(evt.getChatRoom()))
+ {
+ srcContact = msg;
+ break;
+ }
+ }
+
+ if(srcContact == null)
+ return;
+
+ String eventType = evt.getEventType();
+
+ if (LocalUserChatRoomPresenceChangeEvent
+ .LOCAL_USER_JOINED.equals(eventType))
+ {
+ srcContact.setStatus(ChatRoomPresenceStatus.CHAT_ROOM_ONLINE);
+ recentQuery.fireContactChanged(srcContact);
+ }
+ else if ((LocalUserChatRoomPresenceChangeEvent
+ .LOCAL_USER_LEFT.equals(eventType)
+ || LocalUserChatRoomPresenceChangeEvent
+ .LOCAL_USER_KICKED.equals(eventType)
+ || LocalUserChatRoomPresenceChangeEvent
+ .LOCAL_USER_DROPPED.equals(eventType))
+ )
+ {
+ srcContact.setStatus(ChatRoomPresenceStatus.CHAT_ROOM_OFFLINE);
+ recentQuery.fireContactChanged(srcContact);
+ }
+ }
+
+ /**
+ * Handles new events.
+ *
+ * @param obj the event object
+ * @param provider the provider
+ * @param id the id of the source of the event
+ */
+ private void handle(EventObject obj,
+ ProtocolProviderService provider,
+ String id)
+ {
+ // check if provider - contact exist update message content
+ for(MessageSourceContact msc : recentMessages)
+ {
+ if(msc.getProtocolProviderService().equals(provider)
+ && msc.getContactAddress().equals(id))
+ {
+ // update
+ msc.update(obj);
+
+ if(recentQuery != null)
+ recentQuery.fireContactChanged(msc);
+
+ return;
+ }
+ }
+
+ // if missing create source contact
+ // and update recent messages, trim and sort
+ MessageSourceContact newSourceContact =
+ new MessageSourceContact(obj, MessageSourceService.this);
+ recentMessages.add(newSourceContact);
+
+ Collections.sort(recentMessages);
+
+ // trim
+ List removedItems = null;
+ if(recentMessages.size() > numberOfMessages)
+ {
+ removedItems = recentMessages.subList(
+ numberOfMessages, recentMessages.size());
+
+ recentMessages = recentMessages.subList(0, numberOfMessages);
+ }
+
+ // save
+ saveRecentMessagesToHistory();
+
+ // no query nothing to fire
+ if(recentQuery == null)
+ return;
+
+ // now fire
+ if(removedItems != null)
+ {
+ for(MessageSourceContact msc : removedItems)
+ {
+ recentQuery.fireContactRemoved(msc);
+ }
+ }
+
+ recentQuery.fireContactReceived(newSourceContact);
+ }
+
+ @Override
+ public void messageReceived(MessageReceivedEvent evt)
+ {
+ handle(
+ evt,
+ evt.getSourceContact().getProtocolProvider(),
+ evt.getSourceContact().getAddress());
+ }
+
+ @Override
+ public void messageDelivered(MessageDeliveredEvent evt)
+ {
+ handle(
+ evt,
+ evt.getDestinationContact().getProtocolProvider(),
+ evt.getDestinationContact().getAddress());
+ }
+
+ /**
+ * Not used.
+ * @param evt the MessageFailedEvent containing the ID of the
+ */
+ @Override
+ public void messageDeliveryFailed(MessageDeliveryFailedEvent evt)
+ {}
+
+ @Override
+ public void messageReceived(ChatRoomMessageReceivedEvent evt)
+ {
+ handle(
+ evt,
+ evt.getSourceChatRoom().getParentProvider(),
+ evt.getSourceChatRoom().getIdentifier());
+ }
+
+ @Override
+ public void messageDelivered(ChatRoomMessageDeliveredEvent evt)
+ {
+ handle(
+ evt,
+ evt.getSourceChatRoom().getParentProvider(),
+ evt.getSourceChatRoom().getIdentifier());
+ }
+
+ /**
+ * Not used.
+ * @param evt the ChatroomMessageDeliveryFailedEvent containing
+ */
+ @Override
+ public void messageDeliveryFailed(ChatRoomMessageDeliveryFailedEvent evt)
+ {}
+
+ @Override
+ public void messageReceived(AdHocChatRoomMessageReceivedEvent evt)
+ {
+ // TODO
+ }
+
+ @Override
+ public void messageDelivered(AdHocChatRoomMessageDeliveredEvent evt)
+ {
+ // TODO
+ }
+
+ /**
+ * Not used.
+ * @param evt the AdHocChatroomMessageDeliveryFailedEvent
+ */
+ @Override
+ public void messageDeliveryFailed(AdHocChatRoomMessageDeliveryFailedEvent evt)
+ {}
+
+ /**
+ * The contact query implementation.
+ */
+ private class MessageHistoryContactQuery
+ extends AsyncContactQuery
+ {
+ MessageHistoryContactQuery(int contactCount)
+ {
+ super(MessageSourceService.this,
+ Pattern.compile("",
+ Pattern.CASE_INSENSITIVE | Pattern.LITERAL),
+ false);
+ }
+
+ @Override
+ public void run()
+ {
+ for(MessageSourceContact rm : getRecentMessages())
+ {
+ addQueryResult(rm);
+ }
+ }
+
+ /**
+ * Notifies the ContactQueryListeners registered with this
+ * ContactQuery that a new SourceContact has been
+ * received.
+ *
+ * @param contact the SourceContact which has been received and
+ * which the registered ContactQueryListeners are to be notified
+ * about
+ */
+ public void fireContactReceived(SourceContact contact)
+ {
+ fireContactReceived(contact, false);
+ }
+
+ /**
+ * Notifies the ContactQueryListeners registered with this
+ * ContactQuery that a SourceContact has been
+ * changed.
+ *
+ * @param contact the SourceContact which has been changed and
+ * which the registered ContactQueryListeners are to be notified
+ * about
+ */
+ public void fireContactChanged(SourceContact contact)
+ {
+ super.fireContactChanged(contact);
+ }
+
+ /**
+ * Notifies the ContactQueryListeners registered with this
+ * ContactQuery that a SourceContact has been
+ * removed.
+ *
+ * @param contact the SourceContact which has been removed and
+ * which the registered ContactQueryListeners are to be notified
+ * about
+ */
+ public void fireContactRemoved(SourceContact contact)
+ {
+ super.fireContactRemoved(contact);
+ }
+
+ /**
+ * Adds a specific SourceContact to the list of
+ * SourceContacts to be returned by this ContactQuery in
+ * response to {@link #getQueryResults()}.
+ *
+ * @param sourceContact the SourceContact to be added to the
+ * queryResults of this ContactQuery
+ * @return true if the queryResults of this
+ * ContactQuery has changed in response to the call
+ */
+ public boolean addQueryResult(SourceContact sourceContact)
+ {
+ return super.addQueryResult(sourceContact);
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/msghistory/msghistory.manifest.mf b/src/net/java/sip/communicator/impl/msghistory/msghistory.manifest.mf
index e2ce2296b..b1f996a5f 100644
--- a/src/net/java/sip/communicator/impl/msghistory/msghistory.manifest.mf
+++ b/src/net/java/sip/communicator/impl/msghistory/msghistory.manifest.mf
@@ -14,7 +14,8 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.contactlist,
net.java.sip.communicator.service.contactsource,
net.java.sip.communicator.service.history.records,
- net.java.sip.communicator.util,
+ net.java.sip.communicator.service.muc,
+ net.java.sip.communicator.util, org.jitsi.util,
net.java.sip.communicator.util.account,
net.java.sip.communicator.service.protocol,
net.java.sip.communicator.service.protocol.icqconstants,
diff --git a/src/net/java/sip/communicator/service/contactsource/ContactSourceService.java b/src/net/java/sip/communicator/service/contactsource/ContactSourceService.java
index 37100305f..0ef7d41b4 100644
--- a/src/net/java/sip/communicator/service/contactsource/ContactSourceService.java
+++ b/src/net/java/sip/communicator/service/contactsource/ContactSourceService.java
@@ -35,6 +35,11 @@ public interface ContactSourceService
*/
public static final int CHAT_ROOM_TYPE = 3;
+ /**
+ * Type of a recent messages source.
+ */
+ public static final int RECENT_MESSAGES_TYPE = 4;
+
/**
* Returns the type of this contact source.
*
diff --git a/src/net/java/sip/communicator/service/msghistory/MessageHistoryService.java b/src/net/java/sip/communicator/service/msghistory/MessageHistoryService.java
index 8ca3f579d..218a04a7a 100644
--- a/src/net/java/sip/communicator/service/msghistory/MessageHistoryService.java
+++ b/src/net/java/sip/communicator/service/msghistory/MessageHistoryService.java
@@ -29,6 +29,14 @@ public interface MessageHistoryService
= "net.java.sip.communicator.service.msghistory."
+ "IS_MESSAGE_HISTORY_ENABLED";
+ /**
+ * Name of the property that indicates whether the recent messages is
+ * enabled.
+ */
+ public static final String PNAME_IS_RECENT_MESSAGES_DISABLED
+ = "net.java.sip.communicator.service.msghistory."
+ + "IS_RECENT_MESSAGES_DISABLED";
+
/**
* Name of the property that indicates whether the logging of messages is
* enabled.
diff --git a/src/net/java/sip/communicator/service/muc/MUCService.java b/src/net/java/sip/communicator/service/muc/MUCService.java
index b2b157371..c2a302552 100644
--- a/src/net/java/sip/communicator/service/muc/MUCService.java
+++ b/src/net/java/sip/communicator/service/muc/MUCService.java
@@ -278,6 +278,17 @@ public static OperationSetMultiUserChat getMultiUserChatOpSet(
: null;
}
+ /**
+ * 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 abstract ChatRoomWrapper findChatRoomWrapperFromChatRoomID(
+ String chatRoomID,
+ ProtocolProviderService pps);
+
/**
* Goes through the locally stored chat rooms list and for each
* {@link ChatRoomWrapper} tries to find the corresponding server stored