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