adium 3734:fb2bd8210feb: XMPP-MUC: Check log files for last acti...

commits at adium.im commits at adium.im
Mon Mar 14 12:42:48 UTC 2011


details:	http://hg.adium.im/adium/rev/fb2bd8210feb
revision:	3734:fb2bd8210feb
branch:		HistoricMUCMessages
author:		Thijs Alkemade <thijsalkemade at gmail.com>
date:		Mon Mar 14 13:40:18 2011 +0100

XMPP-MUC: Check log files for last activity in a channel when rejoining, to request only the necessary historic messages.

Anything that indicates the user has received messages up to then can be used (so a <status /> or <message />). It takes that tag's timestamp, and requests everything from one second after that.

This does not guarantee no double messages or shown or no messages being lost: messages are being logged with the local timestamp, and the server has its own timestamp, which can differ a lot. I think this is the best solution that doesn't require merging the histories.

diffs (411 lines):

diff -r 8285f249de36 -r fb2bd8210feb Plugins/Purple Service/SLPurpleCocoaAdapter.m
--- a/Plugins/Purple Service/SLPurpleCocoaAdapter.m	Fri Mar 11 12:41:22 2011 +0100
+++ b/Plugins/Purple Service/SLPurpleCocoaAdapter.m	Mon Mar 14 13:40:18 2011 +0100
@@ -591,12 +591,12 @@
 					}
 					
 					if (chat.lastMessageDate) {
-						
-						NSTimeInterval sinceLastMessage = [chat.lastMessageDate timeIntervalSince1970];
-						
-						NSString *historySince = [[NSDate dateWithTimeIntervalSince1970:sinceLastMessage + 1.0f] descriptionWithCalendarFormat:@"%Y-%m-%dT%H:%M:%SZ"
-																																	  timeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]
-																																		locale:nil];
+
+						NSString *historySince = [[NSDate dateWithTimeInterval:1.0f sinceDate:chat.lastMessageDate]
+                                                  descriptionWithCalendarFormat:@"%Y-%m-%dT%H:%M:%SZ"
+                                                                       timeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]
+                                                                         locale:nil];
+
 						g_hash_table_replace(components, g_strdup("history_since"), g_strdup([historySince UTF8String]));
 					} else {
 						AILogWithSignature(@"No last message found for history on %@", chat);
diff -r 8285f249de36 -r fb2bd8210feb Source/AIChatController.m
--- a/Source/AIChatController.m	Fri Mar 11 12:41:22 2011 +0100
+++ b/Source/AIChatController.m	Mon Mar 14 13:40:18 2011 +0100
@@ -33,6 +33,8 @@
 #import <AIUtilities/AIArrayAdditions.h>
 #import <AIUtilities/AIMenuAdditions.h>
 
+#import "DCMessageContextDisplayPlugin.h"
+
 #define SHOW_JOIN_LEAVE_TITLE		AILocalizedString(@"Show Join/Leave Messages", nil)
 
 @interface AIChatController ()
@@ -433,6 +435,13 @@
 		chat.identifier = identifier;
 		chat.isGroupChat = YES;
 		chat.chatCreationDictionary = chatCreationInfo;
+
+		NSArray *lastActivity = [[DCMessageContextDisplayPlugin sharedInstance] contextForChat:chat lines:1 alsoStatus:TRUE];
+        
+		if (lastActivity.count > 0) {
+			chat.lastMessageDate = [[lastActivity objectAtIndex:0] date];
+		}
+
 		/* Negative preference so (default == NO) -> showing join/leave messages */
 		chat.showJoinLeave = ![[[adium preferenceController] preferenceForKey:[NSString stringWithFormat:@"HideJoinLeave-%@", name]
 																	    group:PREF_GROUP_STATUS_PREFERENCES] boolValue];		
diff -r 8285f249de36 -r fb2bd8210feb Source/DCMessageContextDisplayPlugin.h
--- a/Source/DCMessageContextDisplayPlugin.h	Fri Mar 11 12:41:22 2011 +0100
+++ b/Source/DCMessageContextDisplayPlugin.h	Mon Mar 14 13:40:18 2011 +0100
@@ -36,4 +36,9 @@
 	DCMessageContextDisplayPreferences  *preferences;
 }
 
++ (DCMessageContextDisplayPlugin *)sharedInstance;
+
+- (NSArray *)contextForChat:(AIChat *)chat;
+- (NSArray *)contextForChat:(AIChat *)chat lines:(NSInteger)linesLeftToFind alsoStatus:(BOOL)alsoStatus;
+
 @end
diff -r 8285f249de36 -r fb2bd8210feb Source/DCMessageContextDisplayPlugin.m
--- a/Source/DCMessageContextDisplayPlugin.m	Fri Mar 11 12:41:22 2011 +0100
+++ b/Source/DCMessageContextDisplayPlugin.m	Mon Mar 14 13:40:18 2011 +0100
@@ -16,10 +16,10 @@
 
 #import <Adium/AIContentControllerProtocol.h>
 #import "DCMessageContextDisplayPlugin.h"
-#import "DCMessageContextDisplayPreferences.h"
 #import <AIUtilities/AIDictionaryAdditions.h>
 #import <Adium/AIChat.h>
 #import <Adium/AIContentContext.h>
+#import <Adium/AIContentStatus.h>
 #import <Adium/AIService.h>
 
 //Old school
@@ -41,6 +41,8 @@
 
 #define RESTORED_CHAT_CONTEXT_LINE_NUMBER 50
 
+static DCMessageContextDisplayPlugin *sharedInstance = nil;
+
 /**
  * @class DCMessageContextDisplayPlugin
  * @brief Component to display in-window message history
@@ -52,10 +54,16 @@
 							object:(AIListObject *)object preferenceDict:(NSDictionary *)prefDict firstTime:(BOOL)firstTime;
 - (NSArray *)contextForChat:(AIChat *)chat;
 - (void)addContextDisplayToWindow:(NSNotification *)notification;
++ (DCMessageContextDisplayPlugin *)sharedInstance;
 @end
 
 @implementation DCMessageContextDisplayPlugin
 
++ (DCMessageContextDisplayPlugin *)sharedInstance
+{
+	return sharedInstance;
+}
+
 /**
  * @brief Install
  */
@@ -70,6 +78,8 @@
 	
 	//Observe preference changes for whether or not to display message history
 	[adium.preferenceController registerPreferenceObserver:self forGroup:PREF_GROUP_CONTEXT_DISPLAY];
+	
+	sharedInstance = self;
 }
 
 /**
@@ -141,28 +151,34 @@
  */
 - (NSArray *)contextForChat:(AIChat *)chat
 {
-	//If there's no log there, there's no message history. Bail out.
-	NSArray *logPaths = [AILoggerPlugin sortedArrayOfLogFilesForChat:chat];
-	
-	if(!logPaths) return nil;
-	
 	NSInteger linesLeftToFind = 0;
 
-	AIHTMLDecoder *decoder = [AIHTMLDecoder decoder];
-
-	NSString *logObjectUID = chat.name;
-	if (!logObjectUID) logObjectUID = chat.listObject.UID;
-	logObjectUID = [logObjectUID safeFilenameString];
-
-	NSString *baseLogPath = [[AILoggerPlugin logBasePath] stringByAppendingPathComponent:
-		[AILoggerPlugin relativePathForLogWithObject:logObjectUID onAccount:chat.account]];	
-
 	if ([chat boolValueForProperty:@"Restored Chat"] && linesToDisplay < RESTORED_CHAT_CONTEXT_LINE_NUMBER) {
 		linesLeftToFind = MAX(linesLeftToFind, RESTORED_CHAT_CONTEXT_LINE_NUMBER);
 	} else {
 		linesLeftToFind = linesToDisplay;		
 	}
-			
+	
+	return [self contextForChat:chat lines:linesLeftToFind alsoStatus:NO];
+}
+
+- (NSArray *)contextForChat:(AIChat *)chat lines:(NSInteger)linesLeftToFind alsoStatus:(BOOL)alsoStatus
+{
+	//If there's no log there, there's no message history. Bail out.
+	NSArray *logPaths = [AILoggerPlugin sortedArrayOfLogFilesForChat:chat];
+	
+	if(!logPaths || linesLeftToFind == 0) return nil;
+	
+	NSString *logObjectUID = chat.name;
+	if (!logObjectUID) logObjectUID = chat.listObject.UID;
+	logObjectUID = [logObjectUID safeFilenameString];
+	
+	AIHTMLDecoder *decoder = [AIHTMLDecoder decoder];
+	
+	NSString *baseLogPath = [[AILoggerPlugin logBasePath] stringByAppendingPathComponent:
+							 [AILoggerPlugin relativePathForLogWithObject:logObjectUID onAccount:chat.account]];	
+
+	
 	//Initialize a place to store found messages
 	NSMutableArray *outerFoundContentContexts = [NSMutableArray arrayWithCapacity:linesLeftToFind]; 
 
@@ -220,6 +236,7 @@
 						   [NSValue valueWithPointer:&linesLeftToFind], @"LinesLeftToFindValue",
 						   foundMessages, @"FoundMessages",
 						   elementStack, @"ElementStack",
+                           [NSNumber numberWithBool:alsoStatus], @"AlsoAllowStatus",
 						   nil];
 			[parser setContextInfo:(void *)contextInfo];
 		}
@@ -312,7 +329,7 @@
 	NSMutableDictionary *contextInfo = [parser contextInfo];
 	NSMutableArray *elementStack = [contextInfo objectForKey:@"ElementStack"];
 	
-	if ([elementName isEqualToString:@"message"]) {
+	if ([elementName isEqualToString:@"message"] || ([[contextInfo valueForKey:@"AlsoAllowStatus"] boolValue] && [elementName isEqualToString:@"status"])) {
 		[elementStack insertObject:[AIXMLElement elementWithName:elementName] atIndex:0U];
 	}
 	else if ([elementStack count]) {
@@ -396,7 +413,22 @@
 			} else {
 				NSLog(@"Null message context display time for %@",element);
 			}
-		}
+		} else if ([[contextInfo valueForKey:@"AlsoAllowStatus"] boolValue] && [elementName isEqualToString:@"status"]) {
+            
+			AIChat          *chat = [contextInfo objectForKey:@"Chat"];
+			
+			NSDictionary	*attributes = [element attributes];
+			NSString		*timeString = [attributes objectForKey:@"time"];
+			
+			if (timeString) {
+				NSCalendarDate *timeVal = [NSCalendarDate calendarDateWithString:timeString];
+                
+                AIContentStatus *status = [[AIContentStatus alloc] initWithChat:chat source:nil destination:nil date:timeVal];
+                
+                [foundMessages insertObject:status atIndex:0];
+                [status release];
+            }
+        }
 		
 		[elementStack removeObjectAtIndex:0U];
 		if ([foundMessages count] == *linesLeftToFind) {
diff -r 8285f249de36 -r fb2bd8210feb Source/DCMessageContextDisplayPreferences.h
--- a/Source/DCMessageContextDisplayPreferences.h	Fri Mar 11 12:41:22 2011 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-/* 
- * Adium is the legal property of its developers, whose names are listed in the copyright file included
- * with this source distribution.
- * 
- * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
- * General Public License as published by the Free Software Foundation; either version 2 of the License,
- * or (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
- * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
- * Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License along with this program; if not,
- * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- */
-
-#import <Adium/AIPreferencePane.h>
-
- at interface DCMessageContextDisplayPreferences : AIPreferencePane {
-    IBOutlet	NSButton		*checkBox_showContext;
-	IBOutlet	NSButtonCell	*radioButton_always;
-	IBOutlet	NSButtonCell	*radioButton_haveTalked;
-	IBOutlet	NSButtonCell	*radioButton_haveNotTalked;
-		
-	IBOutlet	NSMatrix		*matrix_radioButtons;
-	
-	IBOutlet	NSTextField		*textField_linesToDisplay;
-	IBOutlet	NSTextField		*textField_haveTalkedDays;
-	IBOutlet	NSTextField		*textField_haveNotTalkedDays;
-	
-	IBOutlet	NSPopUpButton   *menu_haveTalkedUnits;
-	IBOutlet	NSPopUpButton   *menu_haveNotTalkedUnits;
-	
-	IBOutlet	NSStepper		*stepper_linesToDisplay;
-	IBOutlet	NSStepper		*stepper_haveTalkedDays;
-	IBOutlet	NSStepper		*stepper_haveNotTalkedDays;
-}
-
-- (IBAction)changePreference:(id)sender;
-
- at end
diff -r 8285f249de36 -r fb2bd8210feb Source/DCMessageContextDisplayPreferences.m
--- a/Source/DCMessageContextDisplayPreferences.m	Fri Mar 11 12:41:22 2011 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,160 +0,0 @@
-/* 
- * Adium is the legal property of its developers, whose names are listed in the copyright file included
- * with this source distribution.
- * 
- * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
- * General Public License as published by the Free Software Foundation; either version 2 of the License,
- * or (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
- * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
- * Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License along with this program; if not,
- * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- */
-
-#import "DCMessageContextDisplayPlugin.h"
-#import "DCMessageContextDisplayPreferences.h"
-#import <AIUtilities/AIDictionaryAdditions.h>
-#import <AIUtilities/AIMenuAdditions.h>
-#import <AIUtilities/AIImageAdditions.h>
-
-typedef enum {
-	AIMessageHistory_Always = 0,
-	AIMessageHistory_HaveTalkedInInterval,
-	AIMessageHistory_HaveNotTalkedInInterval
-} AIMessageHistoryDisplayPref;
-
- at interface DCMessageContextDisplayPreferences (PRIVATE)
-- (NSMenu *)intervalUnitsMenu;
- at end
-
- at implementation DCMessageContextDisplayPreferences
-
-//Preference pane properties
-- (AIPreferenceCategory)category{
-    return AIPref_Advanced;
-}
-- (NSString *)label{
-    return AILocalizedString(@"Message History",nil);
-}
-- (NSString *)nibName{
-    return @"MessageContextDisplayPrefs";
-}
-- (NSImage *)image{
-	return [NSImage imageNamed:@"pref-messagehistory" forClass:[self class]];
-}
-
-
-//Configure the preference view
-- (void)viewDidLoad
-{
-    NSDictionary	*preferenceDict = [adium.preferenceController preferencesForGroup:PREF_GROUP_CONTEXT_DISPLAY];
-    
-    // Set the values of the controls and fields
-    [checkBox_showContext setState:[[preferenceDict objectForKey:KEY_DISPLAY_CONTEXT] boolValue]];
-	[textField_linesToDisplay setIntegerValue:[[preferenceDict objectForKey:KEY_DISPLAY_LINES] integerValue]];
-	[textField_haveTalkedDays setIntegerValue:[[preferenceDict objectForKey:KEY_HAVE_TALKED_DAYS] integerValue]];
-	[textField_haveNotTalkedDays setIntegerValue:[[preferenceDict objectForKey:KEY_HAVE_NOT_TALKED_DAYS] integerValue]];
-	[matrix_radioButtons selectCellAtRow:[[preferenceDict objectForKey:KEY_DISPLAY_MODE] integerValue] column:0];
-	
-	NSMenu	*intervalUnitsMenu = [self intervalUnitsMenu];
-	[menu_haveTalkedUnits setMenu:intervalUnitsMenu];
-	[menu_haveNotTalkedUnits setMenu:[[intervalUnitsMenu copy] autorelease]];
-
-	[menu_haveTalkedUnits selectItemAtIndex:[[preferenceDict objectForKey:KEY_HAVE_TALKED_UNITS] integerValue]];
-	[menu_haveNotTalkedUnits selectItemAtIndex:[[preferenceDict objectForKey:KEY_HAVE_NOT_TALKED_UNITS] integerValue]];
-
-	[self configureControlDimming];
-}
-
-- (IBAction)changePreference:(id)sender
-{
-	if ( sender == checkBox_showContext ) {
-		[adium.preferenceController setPreference:[NSNumber numberWithBool:[sender state]]
-											 forKey:KEY_DISPLAY_CONTEXT
-											  group:PREF_GROUP_CONTEXT_DISPLAY];
-		[self configureControlDimming];
-		
-	} else if ( sender == textField_linesToDisplay ) {
-		
-		[adium.preferenceController setPreference:[NSNumber numberWithInteger:[sender integerValue]]
-											 forKey:KEY_DISPLAY_LINES
-											  group:PREF_GROUP_CONTEXT_DISPLAY];
-	} else if ( sender == textField_haveTalkedDays ) {
-		[adium.preferenceController setPreference:[NSNumber numberWithInteger:[sender integerValue]]
-											 forKey:KEY_HAVE_TALKED_DAYS
-											  group:PREF_GROUP_CONTEXT_DISPLAY];
-	} else if (sender == textField_haveNotTalkedDays ) {
-		[adium.preferenceController setPreference:[NSNumber numberWithInteger:[sender integerValue]]
-											 forKey:KEY_HAVE_NOT_TALKED_DAYS
-											  group:PREF_GROUP_CONTEXT_DISPLAY];
-	} else if ( sender == matrix_radioButtons ) {
-		[adium.preferenceController setPreference:[NSNumber numberWithInteger:[sender selectedRow]]
-											 forKey:KEY_DISPLAY_MODE
-											  group:PREF_GROUP_CONTEXT_DISPLAY];
-		[self configureControlDimming];
-	} else if ( sender == menu_haveTalkedUnits ) {
-		[adium.preferenceController setPreference:[NSNumber numberWithInteger:[sender indexOfSelectedItem]]
-											 forKey:KEY_HAVE_TALKED_UNITS
-											  group:PREF_GROUP_CONTEXT_DISPLAY];
-	} else if ( sender == menu_haveNotTalkedUnits ) {
-		[adium.preferenceController setPreference:[NSNumber numberWithInteger:[sender indexOfSelectedItem]]
-											 forKey:KEY_HAVE_NOT_TALKED_UNITS
-											  group:PREF_GROUP_CONTEXT_DISPLAY];
-	}
-	
-}
-
-- (void)configureControlDimming
-{
-	NSInteger		selectedRow = [matrix_radioButtons selectedRow];
-	BOOL	contextEnabled =[checkBox_showContext state];
-		
-	[textField_linesToDisplay setEnabled:contextEnabled];
-	[stepper_linesToDisplay setEnabled:contextEnabled];
-	
-	[textField_haveTalkedDays setEnabled:contextEnabled];
-	[stepper_haveTalkedDays setEnabled:contextEnabled];
-	[textField_haveNotTalkedDays setEnabled:contextEnabled];
-	[stepper_haveNotTalkedDays setEnabled:contextEnabled];
-	
-	[menu_haveTalkedUnits setEnabled:contextEnabled];
-	[menu_haveNotTalkedUnits setEnabled:contextEnabled];
-	
-	[matrix_radioButtons setEnabled:contextEnabled];
-	
-	if ( [checkBox_showContext state] ) {
-		switch ( selectedRow ) {
-			case AIMessageHistory_Always:
-				[textField_haveTalkedDays setEnabled:NO];
-				[stepper_haveTalkedDays setEnabled:NO];
-				[textField_haveNotTalkedDays setEnabled:NO];
-				[stepper_haveNotTalkedDays setEnabled:NO];
-				[menu_haveTalkedUnits setEnabled:NO];
-				[menu_haveNotTalkedUnits setEnabled:NO];
-				break;
-				
-			case AIMessageHistory_HaveTalkedInInterval:
-				[textField_haveTalkedDays setEnabled:YES];
-				[stepper_haveTalkedDays setEnabled:YES];
-				[textField_haveNotTalkedDays setEnabled:NO];
-				[stepper_haveNotTalkedDays setEnabled:NO];
-				[menu_haveTalkedUnits setEnabled:YES];
-				[menu_haveNotTalkedUnits setEnabled:NO];
-				break;
-				
-			case AIMessageHistory_HaveNotTalkedInInterval:
-				[textField_haveTalkedDays setEnabled:NO];
-				[stepper_haveTalkedDays setEnabled:NO];
-				[textField_haveNotTalkedDays setEnabled:YES];
-				[stepper_haveNotTalkedDays setEnabled:YES];
-				[menu_haveTalkedUnits setEnabled:NO];
-				[menu_haveNotTalkedUnits setEnabled:YES];
-		}
-	}
-}
-
-
- at end




More information about the commits mailing list