Index: /Tags/Release-1.2/AILogSizeSort.h
===================================================================
--- /Tags/Release-1.2/AILogSizeSort.h	(revision 24)
+++ /Tags/Release-1.2/AILogSizeSort.h	(revision 24)
@@ -0,0 +1,41 @@
+/* 
+ * $Id$
+ *
+ * Adium is the legal property of its developers, whose names are listed in the copyright file included
+ * with this source distribution.
+ *
+ * This plugin is copyright (c) 2008 Jon Chambers.  The plugin's official site is:
+ * http://projects.eatthepath.com/sort-by-log-size-plugin/
+ * 
+ * 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/AISortController.h>
+#import <Adium/AIListContact.h>
+
+@interface AILogSizeSort : AISortController
+{
+	NSMutableDictionary *logSizeCache;
+}
+
+// Cache operations
+-(void)createCacheEntryIfNil:(AIListContact *)listContact;
+-(void)removeCacheEntry:(AIListContact *)listContact;
+
+// Event handlers
+-(void)contentObjectAdded:(NSNotification *)notification;
+
+// Log operations
+-(unsigned long long)getCachedLogSize:(AIListContact *)listContact;
++(unsigned long long)getContactLogSize:(AIListContact *)listContact;
+
+@end
Index: /Tags/Release-1.2/SortByLogSizePlugin_Prefix.pch
===================================================================
--- /Tags/Release-1.2/SortByLogSizePlugin_Prefix.pch	(revision 2)
+++ /Tags/Release-1.2/SortByLogSizePlugin_Prefix.pch	(revision 2)
@@ -0,0 +1,7 @@
+//
+// Prefix header for all source files of the 'SortByLogSizePlugin' target in the 'SortByLogSizePlugin' project.
+//
+
+#ifdef __OBJC__
+    #import <Cocoa/Cocoa.h>
+#endif
Index: /Tags/Release-1.2/Info.plist
===================================================================
--- /Tags/Release-1.2/Info.plist	(revision 18)
+++ /Tags/Release-1.2/Info.plist	(revision 18)
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>AIMinimumAdiumVersionRequirement</key>
+	<string>1.3</string>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>English</string>
+	<key>CFBundleExecutable</key>
+	<string>${EXECUTABLE_NAME}</string>
+	<key>CFBundleIconFile</key>
+	<string></string>
+	<key>CFBundleIdentifier</key>
+	<string>com.eatthepath.${PRODUCT_NAME:identifier}</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>${PRODUCT_NAME}</string>
+	<key>CFBundlePackageType</key>
+	<string>BNDL</string>
+	<key>CFBundleSignature</key>
+	<string>AdIM</string>
+	<key>CFBundleVersion</key>
+	<string>1.1</string>
+	<key>NSPrincipalClass</key>
+	<string>ABSortByLogSizePlugin</string>
+</dict>
+</plist>
Index: /Tags/Release-1.2/ABSortByLogSizePlugin.h
===================================================================
--- /Tags/Release-1.2/ABSortByLogSizePlugin.h	(revision 16)
+++ /Tags/Release-1.2/ABSortByLogSizePlugin.h	(revision 16)
@@ -0,0 +1,28 @@
+/* 
+ * $Id$
+ *
+ * Adium is the legal property of its developers, whose names are listed in the copyright file included
+ * with this source distribution.
+ *
+ * This plugin is copyright (c) 2008 Jon Chambers.  The plugin's official site is:
+ * http://projects.eatthepath.com/sort-by-log-size-plugin/
+ * 
+ * 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/AIPlugin.h>
+
+@interface ABSortByLogSizePlugin : AIPlugin
+{
+}
+
+@end
Index: /Tags/Release-1.2/AILogSizeSort.m
===================================================================
--- /Tags/Release-1.2/AILogSizeSort.m	(revision 26)
+++ /Tags/Release-1.2/AILogSizeSort.m	(revision 26)
@@ -0,0 +1,331 @@
+/* 
+ * $Id$
+ *
+ * Adium is the legal property of its developers, whose names are listed in the copyright file included
+ * with this source distribution.
+ *
+ * This plugin is copyright (c) 2008 Jon Chambers.  The plugin's official site is:
+ * http://projects.eatthepath.com/sort-by-log-size-plugin/
+ * 
+ * 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/AIPlugin.h>
+#import <Adium/AISharedAdium.h>
+
+#import <AIUtilities/AIStringUtilities.h>
+
+#import <Adium/AIAdiumProtocol.h>
+#import <Adium/AIContentControllerProtocol.h>
+#import <Adium/AIContactControllerProtocol.h>
+#import <Adium/AIListObject.h>
+#import <Adium/AIMetaContact.h>
+
+#import <Adium/AIChat.h>
+#import <Adium/AIContentObject.h>
+#import <Adium/AIContentMessage.h>
+
+#import "AILogSizeSort.h"
+#import "AILoggerPlugin.h"
+
+@implementation AILogSizeSort
+
+#pragma mark AISortController obligations
+
+/*!
+ * @brief Did become active first time
+ *
+ * Called only once; gives the sort controller an opportunity to set defaults and load preferences lazily.
+ */
+- (void)didBecomeActiveFirstTime
+{
+	logSizeCache = [[NSMutableDictionary alloc] init];
+	
+	// Listen for content addition notifications
+	[[NSNotificationCenter defaultCenter] addObserver:self 
+											 selector:@selector(contentObjectAdded:) 
+												 name:Content_ContentObjectAdded 
+											   object:nil];
+}
+
+/*!
+ * @brief Non-localized identifier
+ */
+- (NSString *)identifier{
+    return @"Log size";
+}
+
+/*!
+ * @brief Localized display name
+ */
+- (NSString *)displayName{
+    return AILocalizedString(@"Sort Contacts by Log Size", nil);
+}
+
+/*!
+ * @brief Properties which, when changed, should trigger a resort
+ */
+- (NSSet *)statusKeysRequiringResort{
+	return nil;
+}
+
+/*!
+ * @brief Attribute keys which, when changed, should trigger a resort
+ */
+- (NSSet *)attributeKeysRequiringResort{
+	return nil;
+}
+
+#pragma mark Configuration
+
+/*!
+ * @brief Window title when configuring the sort
+ *
+ * Subclasses should provide a title for configuring the sort only if configuration is possible.
+ * @result Localized title. If nil, the menu item will be disabled.
+ */
+- (NSString *)configureSortWindowTitle{
+	return nil;
+}
+
+/*!
+ * @brief Nib name for configuration
+ */
+- (NSString *)configureNibName{
+	return nil;
+}
+
+/*!
+ * @brief View did load
+ */
+- (void)viewDidLoad{
+}
+
+/*!
+ * @brief Preference changed
+ *
+ * Sort controllers should live update as preferences change.
+ */
+- (IBAction)changePreference:(id)sender
+{
+}
+
+/*!
+ * @brief Allow users to manually sort groups
+ */
+-(BOOL)canSortManually
+{
+	return YES;
+}
+
+#pragma mark Cache operations
+
+/*!
+ * @brief Creates and populates a new cache entry for a contact if needed
+ */
+-(void)createCacheEntryIfNil:(AIListContact *)listContact
+{
+	// Check for a match on the account name; create a new sub-dictionary if needed
+	if([logSizeCache valueForKey:[[listContact account] explicitFormattedUID]] == nil)
+	{
+		[logSizeCache setValue:[[NSMutableDictionary alloc] init] forKey:[[listContact account] explicitFormattedUID]];
+	}
+	
+	NSMutableDictionary *accountDictionary = [logSizeCache valueForKey:[[listContact account] explicitFormattedUID]];
+	
+	// If we don't already have a valid log size cached for this contact, create one
+	if([accountDictionary valueForKey:[listContact UID]] == nil)
+	{
+		[accountDictionary setValue:[NSNumber numberWithUnsignedLongLong:[AILogSizeSort getContactLogSize:listContact]] forKey: [listContact UID]];
+	}
+}
+
+/*!
+ * @brief Invalidates a cached log size for a list contact
+ */
+-(void)removeCacheEntry:(AIListContact *)listContact
+{
+	if([listContact isMemberOfClass:[AIMetaContact class]])
+	{
+		// Recurse!  Invalidate each sub-contact's cache entry.
+		id contact;
+		
+		NSEnumerator *contactEnumerator = [[(AIMetaContact *)listContact uniqueContainedObjects] objectEnumerator];
+		
+		while(contact = [contactEnumerator nextObject])
+		{
+			[self removeCacheEntry:contact];
+		}
+	}
+	else
+	{
+		// Bail out if we don't know about the group this contact is in (there's nothing for us to do
+		// anyway).
+		if([logSizeCache valueForKey:[[listContact account] explicitFormattedUID]] == nil) { return; }
+		
+		// Remove the cache entry for the dirty account.
+		[(NSMutableDictionary *)[logSizeCache valueForKey:[[listContact account] explicitFormattedUID]] setValue:nil forKey:[listContact UID]];
+	}
+}
+
+#pragma mark Event handlers
+
+/*!
+ * @brief Handles content send/receive events
+ *
+ * Handles content send/receive events.  For one-on-one chats, the cached log size for a contact is
+ * invalidated (forcing a recalculation on the next sorting cycle).
+ */
+-(void)contentObjectAdded:(NSNotification *)notification
+{
+	AIChat *chat = [notification object];
+	
+	if(![chat isGroupChat])
+	{
+		[self removeCacheEntry:[chat listObject]];
+	}
+}
+
+#pragma mark Log operations
+
+/*!
+ * @brief Returns the cached log size for a list contact
+ */
+-(unsigned long long)getCachedLogSize:(AIListContact *)listContact
+{
+	[self createCacheEntryIfNil:listContact];
+	
+	NSMutableDictionary *accountDictionary = [logSizeCache valueForKey:[[listContact account] explicitFormattedUID]];
+	return [[accountDictionary valueForKey:[listContact UID]] unsignedLongLongValue];
+}
+
+/*!
+ * @brief Returns the total aggregate log size for a contact
+ *
+ * Returns the total aggregate log size for a contact.  For meta-contacts, the
+ * total log file size of all sub-contacts is returned.  If no log exists or if
+ * something else goes wrong, 0 is returned.
+ *
+ * @param listContact an AIListContact for which to retrieve a total log file size
+ * @return the total log file size in bytes or 0 if an error occurred
+ */
++(unsigned long long)getContactLogSize:(AIListContact *)listContact
+{
+	NSFileManager *fileManager = [NSFileManager defaultManager];
+	
+	if([listContact isMemberOfClass:[AIMetaContact class]])
+	{
+		// Recurse through all sub-contacts
+		id contact;
+		unsigned long long size = 0;
+		
+		NSEnumerator *contactEnumerator = [[(AIMetaContact *)listContact uniqueContainedObjects] objectEnumerator];
+
+		while(contact = [contactEnumerator nextObject])
+		{
+			size += [AILogSizeSort getContactLogSize:contact];
+		}
+		
+		return size;
+	}
+	else
+	{
+		// Find the path to the directory containing the log files for this contact
+		NSString *path = [[AILoggerPlugin logBasePath] stringByAppendingPathComponent:[AILoggerPlugin relativePathForLogWithObject:[listContact UID] onAccount: [listContact account]]];
+		
+		// Grab an enumerator for all log files for this contact
+		NSDirectoryEnumerator *dirEnum = [[NSFileManager defaultManager] enumeratorAtPath:path];
+		NSString *file;
+		
+		unsigned long long size = 0;
+		
+		while(file = [dirEnum nextObject])
+		{
+			NSDictionary *fileAttributes = [fileManager fileAttributesAtPath:[path stringByAppendingPathComponent:file] traverseLink:YES];
+			
+			if (fileAttributes != nil)
+			{
+				NSNumber *fileSize;
+				if(fileSize = [fileAttributes objectForKey:NSFileSize])
+				{
+					size += [fileSize unsignedLongLongValue];
+				}
+			}
+		}
+		
+		return size;
+	}
+}
+
+#pragma mark Sorting
+
+/*!
+ * @brief Sort by log size
+ */
+NSComparisonResult logSizeSort(id objectA, id objectB, BOOL groups, id<AIContainingObject> container)
+{
+	if(groups)
+	{
+		// Keep groups in manual order (borrowed from ESStatusSort)
+		if ([container orderIndexForObject:objectA] > [container orderIndexForObject:objectB])
+		{
+			return NSOrderedDescending;
+		}
+		else
+		{
+			return NSOrderedAscending;
+		}
+	}
+	
+	// Get a reference to one and only AILogSizeSort instance.  If this sorting method is being
+	// called, it should always be the case that AILogSizeSort is the active sort controller.
+	AISortController *sortController = [AISortController activeSortController];
+	
+	unsigned long long sizeA = 0;
+	unsigned long long sizeB = 0;
+	
+	// Attempt to use cached log sizes if possible, but fall back to dumber methods if something
+	// unforeseen happens.
+	if([sortController isMemberOfClass:[AILogSizeSort class]])
+	{
+		sizeA = [(AILogSizeSort *)sortController getCachedLogSize:objectA];
+		sizeB = [(AILogSizeSort *)sortController getCachedLogSize:objectB];
+	}
+	else
+	{
+		sizeA = [AILogSizeSort getContactLogSize:objectA];
+		sizeB = [AILogSizeSort getContactLogSize:objectB];
+	}
+
+	if(sizeB == sizeA)
+	{
+		// Fall back to basic alphabetical sorting in the event of a tie.
+		return [[objectA displayName] caseInsensitiveCompare:[objectB displayName]];
+	}
+	else if(sizeA > sizeB)
+	{
+		// There's a clear winner; run with it.
+		return NSOrderedAscending;
+	}
+	else
+	{
+		return NSOrderedDescending;
+	}
+}
+
+/*!
+ * @brief Sort function
+ */
+- (sortfunc)sortFunction{
+	return &logSizeSort;
+}
+@end
Index: /Tags/Release-1.2/SortByLogSizePlugin.xcodeproj/project.pbxproj
===================================================================
--- /Tags/Release-1.2/SortByLogSizePlugin.xcodeproj/project.pbxproj	(revision 27)
+++ /Tags/Release-1.2/SortByLogSizePlugin.xcodeproj/project.pbxproj	(revision 27)
@@ -0,0 +1,330 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 45;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		8D5B49B4048680CD000E48DA /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7ADFEA557BF11CA2CBB /* Cocoa.framework */; };
+		FC1983600E900AF10021C71E /* AILogSizeSort.m in Sources */ = {isa = PBXBuildFile; fileRef = FC19835F0E900AF10021C71E /* AILogSizeSort.m */; };
+		FC22EC220FD36AAD00754E18 /* Adium.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FC22EC200FD36AAD00754E18 /* Adium.framework */; };
+		FC22EC230FD36AAD00754E18 /* AIUtilities.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FC22EC210FD36AAD00754E18 /* AIUtilities.framework */; };
+		FC22EC270FD36ACF00754E18 /* FriBidi.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FC22EC260FD36ACF00754E18 /* FriBidi.framework */; };
+		FC2CD0D40FD4A09E009FD00C /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = FC2CD0D30FD4A09E009FD00C /* Localizable.strings */; };
+		FCB319740E8FF80C00D88232 /* ABSortByLogSizePlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = FCB319730E8FF80C00D88232 /* ABSortByLogSizePlugin.m */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+		089C1672FE841209C02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
+		089C167FFE841241C02AAC07 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
+		1058C7ADFEA557BF11CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
+		32DBCF630370AF2F00C91783 /* SortByLogSizePlugin_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SortByLogSizePlugin_Prefix.pch; sourceTree = "<group>"; };
+		8D5B49B6048680CD000E48DA /* SortByLogSizePlugin.AdiumPlugin */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SortByLogSizePlugin.AdiumPlugin; sourceTree = BUILT_PRODUCTS_DIR; };
+		8D5B49B7048680CD000E48DA /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		D2F7E65807B2D6F200F64583 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = "<absolute>"; };
+		FC19835E0E900AF10021C71E /* AILogSizeSort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AILogSizeSort.h; sourceTree = "<group>"; };
+		FC19835F0E900AF10021C71E /* AILogSizeSort.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AILogSizeSort.m; sourceTree = "<group>"; };
+		FC1985880E90600B0021C71E /* AILoggerPlugin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AILoggerPlugin.h; sourceTree = "<group>"; };
+		FC22EC200FD36AAD00754E18 /* Adium.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Adium.framework; path = "../adium-1.4/build/Debug/Adium.framework"; sourceTree = SOURCE_ROOT; };
+		FC22EC210FD36AAD00754E18 /* AIUtilities.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AIUtilities.framework; path = "../adium-1.4/build/Debug/AIUtilities.framework"; sourceTree = SOURCE_ROOT; };
+		FC22EC260FD36ACF00754E18 /* FriBidi.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FriBidi.framework; path = "../adium-1.4/build/Debug/FriBidi.framework"; sourceTree = SOURCE_ROOT; };
+		FC2CD0D50FD4A0AF009FD00C /* en */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
+		FCB319720E8FF80C00D88232 /* ABSortByLogSizePlugin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ABSortByLogSizePlugin.h; sourceTree = "<group>"; };
+		FCB319730E8FF80C00D88232 /* ABSortByLogSizePlugin.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ABSortByLogSizePlugin.m; sourceTree = "<group>"; };
+		FCDC9E790FD4B9F300B2F353 /* es */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; };
+		FCDC9E7A0FD4BA0B00B2F353 /* fr */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = "<group>"; };
+		FCDC9E7B0FD4BA1700B2F353 /* is */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = is; path = is.lproj/Localizable.strings; sourceTree = "<group>"; };
+		FCDC9E7E0FD4BA7100B2F353 /* sv */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = "<group>"; };
+		FCDC9E7F0FD4BA8600B2F353 /* de */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		8D5B49B3048680CD000E48DA /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				8D5B49B4048680CD000E48DA /* Cocoa.framework in Frameworks */,
+				FC22EC220FD36AAD00754E18 /* Adium.framework in Frameworks */,
+				FC22EC230FD36AAD00754E18 /* AIUtilities.framework in Frameworks */,
+				FC22EC270FD36ACF00754E18 /* FriBidi.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		089C166AFE841209C02AAC07 /* SortByLogSizePlugin */ = {
+			isa = PBXGroup;
+			children = (
+				08FB77AFFE84173DC02AAC07 /* Classes */,
+				32C88E010371C26100C91783 /* Other Sources */,
+				089C167CFE841241C02AAC07 /* Resources */,
+				089C1671FE841209C02AAC07 /* Frameworks and Libraries */,
+				19C28FB8FE9D52D311CA2CBB /* Products */,
+			);
+			name = SortByLogSizePlugin;
+			sourceTree = "<group>";
+		};
+		089C1671FE841209C02AAC07 /* Frameworks and Libraries */ = {
+			isa = PBXGroup;
+			children = (
+				FC22EC260FD36ACF00754E18 /* FriBidi.framework */,
+				FC22EC200FD36AAD00754E18 /* Adium.framework */,
+				FC22EC210FD36AAD00754E18 /* AIUtilities.framework */,
+				1058C7ACFEA557BF11CA2CBB /* Linked Frameworks */,
+				1058C7AEFEA557BF11CA2CBB /* Other Frameworks */,
+			);
+			name = "Frameworks and Libraries";
+			sourceTree = "<group>";
+		};
+		089C167CFE841241C02AAC07 /* Resources */ = {
+			isa = PBXGroup;
+			children = (
+				8D5B49B7048680CD000E48DA /* Info.plist */,
+				FC2CD0D30FD4A09E009FD00C /* Localizable.strings */,
+			);
+			name = Resources;
+			sourceTree = "<group>";
+		};
+		08FB77AFFE84173DC02AAC07 /* Classes */ = {
+			isa = PBXGroup;
+			children = (
+				FC1985880E90600B0021C71E /* AILoggerPlugin.h */,
+				FCB319720E8FF80C00D88232 /* ABSortByLogSizePlugin.h */,
+				FCB319730E8FF80C00D88232 /* ABSortByLogSizePlugin.m */,
+				FC19835E0E900AF10021C71E /* AILogSizeSort.h */,
+				FC19835F0E900AF10021C71E /* AILogSizeSort.m */,
+			);
+			name = Classes;
+			sourceTree = "<group>";
+		};
+		1058C7ACFEA557BF11CA2CBB /* Linked Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				1058C7ADFEA557BF11CA2CBB /* Cocoa.framework */,
+			);
+			name = "Linked Frameworks";
+			sourceTree = "<group>";
+		};
+		1058C7AEFEA557BF11CA2CBB /* Other Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				089C167FFE841241C02AAC07 /* AppKit.framework */,
+				D2F7E65807B2D6F200F64583 /* CoreData.framework */,
+				089C1672FE841209C02AAC07 /* Foundation.framework */,
+			);
+			name = "Other Frameworks";
+			sourceTree = "<group>";
+		};
+		19C28FB8FE9D52D311CA2CBB /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				8D5B49B6048680CD000E48DA /* SortByLogSizePlugin.AdiumPlugin */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		32C88E010371C26100C91783 /* Other Sources */ = {
+			isa = PBXGroup;
+			children = (
+				32DBCF630370AF2F00C91783 /* SortByLogSizePlugin_Prefix.pch */,
+			);
+			name = "Other Sources";
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+		8D5B49AC048680CD000E48DA /* SortByLogSizePlugin */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 1DEB913A08733D840010E9CD /* Build configuration list for PBXNativeTarget "SortByLogSizePlugin" */;
+			buildPhases = (
+				8D5B49AF048680CD000E48DA /* Resources */,
+				8D5B49B1048680CD000E48DA /* Sources */,
+				8D5B49B3048680CD000E48DA /* Frameworks */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = SortByLogSizePlugin;
+			productInstallPath = "$(HOME)/Library/Bundles";
+			productName = SortByLogSizePlugin;
+			productReference = 8D5B49B6048680CD000E48DA /* SortByLogSizePlugin.AdiumPlugin */;
+			productType = "com.apple.product-type.bundle";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		089C1669FE841209C02AAC07 /* Project object */ = {
+			isa = PBXProject;
+			buildConfigurationList = 1DEB913E08733D840010E9CD /* Build configuration list for PBXProject "SortByLogSizePlugin" */;
+			compatibilityVersion = "Xcode 3.1";
+			hasScannedForEncodings = 1;
+			knownRegions = (
+				English,
+				Japanese,
+				French,
+				German,
+				en,
+				fr,
+				de,
+				es,
+				is,
+				sv,
+			);
+			mainGroup = 089C166AFE841209C02AAC07 /* SortByLogSizePlugin */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				8D5B49AC048680CD000E48DA /* SortByLogSizePlugin */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+		8D5B49AF048680CD000E48DA /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				FC2CD0D40FD4A09E009FD00C /* Localizable.strings in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+		8D5B49B1048680CD000E48DA /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				FCB319740E8FF80C00D88232 /* ABSortByLogSizePlugin.m in Sources */,
+				FC1983600E900AF10021C71E /* AILogSizeSort.m in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXVariantGroup section */
+		FC2CD0D30FD4A09E009FD00C /* Localizable.strings */ = {
+			isa = PBXVariantGroup;
+			children = (
+				FCDC9E7F0FD4BA8600B2F353 /* de */,
+				FC2CD0D50FD4A0AF009FD00C /* en */,
+				FCDC9E790FD4B9F300B2F353 /* es */,
+				FCDC9E7A0FD4BA0B00B2F353 /* fr */,
+				FCDC9E7B0FD4BA1700B2F353 /* is */,
+				FCDC9E7E0FD4BA7100B2F353 /* sv */,
+			);
+			name = Localizable.strings;
+			sourceTree = "<group>";
+		};
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+		1DEB913B08733D840010E9CD /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				COPY_PHASE_STRIP = NO;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"\"$(SRCROOT)\"",
+					"\"$(SRCROOT)/../adium-1.4/build/Debug\"",
+				);
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_ENABLE_FIX_AND_CONTINUE = YES;
+				GCC_MODEL_TUNING = G5;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PRECOMPILE_PREFIX_HEADER = YES;
+				GCC_PREFIX_HEADER = SortByLogSizePlugin_Prefix.pch;
+				GCC_PREPROCESSOR_DEFINITIONS = DEBUG_BUILD;
+				INFOPLIST_FILE = Info.plist;
+				INSTALL_PATH = "$(HOME)/Library/Bundles";
+				OTHER_LDFLAGS = (
+					"-undefined",
+					dynamic_lookup,
+				);
+				PRODUCT_NAME = SortByLogSizePlugin;
+				WRAPPER_EXTENSION = AdiumPlugin;
+			};
+			name = Debug;
+		};
+		1DEB913C08733D840010E9CD /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"\"$(SRCROOT)\"",
+					"\"$(SRCROOT)/../adium-1.4/build/Debug\"",
+				);
+				GCC_MODEL_TUNING = G5;
+				GCC_OPTIMIZATION_LEVEL = s;
+				GCC_PRECOMPILE_PREFIX_HEADER = YES;
+				GCC_PREFIX_HEADER = SortByLogSizePlugin_Prefix.pch;
+				INFOPLIST_FILE = Info.plist;
+				INSTALL_PATH = "$(HOME)/Library/Bundles";
+				OTHER_LDFLAGS = (
+					"-undefined",
+					dynamic_lookup,
+				);
+				PRODUCT_NAME = SortByLogSizePlugin;
+				WRAPPER_EXTENSION = AdiumPlugin;
+			};
+			name = Release;
+		};
+		1DEB913F08733D840010E9CD /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+				GCC_C_LANGUAGE_STANDARD = c99;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				PREBINDING = NO;
+				SDKROOT = macosx10.5;
+			};
+			name = Debug;
+		};
+		1DEB914008733D840010E9CD /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+				GCC_C_LANGUAGE_STANDARD = c99;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				PREBINDING = NO;
+				SDKROOT = macosx10.5;
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		1DEB913A08733D840010E9CD /* Build configuration list for PBXNativeTarget "SortByLogSizePlugin" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				1DEB913B08733D840010E9CD /* Debug */,
+				1DEB913C08733D840010E9CD /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		1DEB913E08733D840010E9CD /* Build configuration list for PBXProject "SortByLogSizePlugin" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				1DEB913F08733D840010E9CD /* Debug */,
+				1DEB914008733D840010E9CD /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = 089C1669FE841209C02AAC07 /* Project object */;
+}
Index: /Tags/Release-1.2/ABSortByLogSizePlugin.m
===================================================================
--- /Tags/Release-1.2/ABSortByLogSizePlugin.m	(revision 27)
+++ /Tags/Release-1.2/ABSortByLogSizePlugin.m	(revision 27)
@@ -0,0 +1,60 @@
+/* 
+ * $Id$
+ *
+ * Adium is the legal property of its developers, whose names are listed in the copyright file included
+ * with this source distribution.
+ *
+ * This plugin is copyright (c) 2008 Jon Chambers.  The plugin's official site is:
+ * http://projects.eatthepath.com/sort-by-log-size-plugin/
+ * 
+ * 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 "ABSortByLogSizePlugin.h"
+#import "AILogSizeSort.h"
+
+#import <Adium/AISharedAdium.h>
+#import <Adium/AIContactControllerProtocol.h>
+#import <AIUtilities/AIStringUtilities.h>
+
+@implementation ABSortByLogSizePlugin
+
+- (void)installPlugin
+{
+	[AISortController registerSortController:[[[AILogSizeSort alloc] init] autorelease]];
+}
+
+- (void)uninstallPlugin 
+{
+}
+
+- (NSString *)pluginAuthor
+{
+	return @"Jon Chambers";
+}
+
+- (NSString *)pluginVersion
+{
+	return @"1.2";
+}
+
+- (NSString *)pluginDescription
+{
+	return AILocalizedString(@"Allows the Adium contact list to be sorted by chat transcript file size.", nil);
+}
+
+- (NSString *)pluginURL
+{
+	return @"http://projects.eatthepath.com/sort-by-log-size-plugin/";
+}
+
+@end
Index: /Tags/Release-1.2/AILoggerPlugin.h
===================================================================
--- /Tags/Release-1.2/AILoggerPlugin.h	(revision 25)
+++ /Tags/Release-1.2/AILoggerPlugin.h	(revision 25)
@@ -0,0 +1,105 @@
+/* 
+ * 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.
+ */
+
+
+#define PATH_LOGS                       @"/Logs"
+#define LOGGING_DEFAULT_PREFS           @"LoggingDefaults"
+
+#define PREF_GROUP_LOGGING              @"Logging"
+#define KEY_LOGGER_ENABLE               @"Enable Logging"
+
+#define PREF_KEYPATH_LOGGER_ENABLE		PREF_GROUP_LOGGING @"." KEY_LOGGER_ENABLE
+
+#define XML_LOGGING_NAMESPACE		@"http://purl.org/net/ulf/ns/0.4-02"
+
+@class AIAccount, AIHTMLDecoder, AIChat, AILoggerPreferences;
+
+@interface AILoggerPlugin : AIPlugin {
+    AILoggerPreferences                 *preferences;
+    
+    //Current logging settings
+    BOOL				observingContent;
+    BOOL				logHTML;
+
+	NSMutableDictionary					*activeAppenders;
+	NSMutableDictionary					*appenderCloseTimers;
+	
+	AIHTMLDecoder						*xhtmlDecoder;
+	NSDictionary						*statusTranslation;
+	
+    //Log viewer menu items
+    NSMenuItem                          *logViewerMenuItem;
+    NSMenuItem                          *viewContactLogsMenuItem;
+    NSMenuItem                          *viewContactLogsContextMenuItem;
+	NSMenuItem							*viewGroupLogsContextMenuItem;
+
+    //Log content search index
+	BOOL				logIndexingEnabled; //Does this system use log indexing?
+    SKIndexRef			index_Content;	
+
+    //Dirty all information (First build of the dirty cache)
+    BOOL				stopIndexingThreads;    //Set to YES to abort a dirty all or clean
+    BOOL				suspendDirtyArraySave;  //YES to prevent saving of the dirty index	
+	BOOL				isFlushingIndex;
+    NSLock				*indexingThreadLock;	//Locked by the plugin when a dirty all or clean thread is running
+
+	//Locked by the plugin while the index is being modified
+	NSConditionLock		*logWritingLock;
+	//Locked by the plugin while the index is being closed
+    NSConditionLock		*logClosingLock;
+	
+    //Array of dirty logs / Logs that need re-indexing.  (Locked access)
+    NSMutableArray		*dirtyLogArray;
+    NSLock				*dirtyLogLock;
+    
+    //Indexing progress
+    NSInteger					logsToIndex;
+    NSInteger					logsIndexed;
+	NSInteger					logIndexingPauses;
+    
+}
+
+//Paths
++ (NSString *)logBasePath;
++ (NSString *)relativePathForLogWithObject:(NSString *)object onAccount:(AIAccount *)account;
+
+//Message History
++ (NSArray *)sortedArrayOfLogFilesForChat:(AIChat *)chat;
+
+//Log viewer
+- (void)showLogViewerAndReindex:(id)sender;
+- (void)showLogViewerToSelectedContact:(id)sender;
+- (void)showLogViewerToSelectedContextContact:(id)sender;
+
+//Log indexing
+- (void)initLogIndexing;
+- (void)prepareLogContentSearching;
+- (void)cleanUpLogContentSearching;
+- (SKIndexRef)logContentIndex;
+- (void)markLogDirtyAtPath:(NSString *)path forChat:(AIChat *)chat;
+- (void)markLogDirtyAtPath:(NSString *)path;
+- (BOOL)getIndexingProgress:(NSUInteger *)complete outOf:(NSUInteger *)total;
+
+- (void)stopIndexingThreads;
+- (void)dirtyAllLogs;
+- (void)cleanDirtyLogs;
+- (void)pauseIndexing;
+- (void)resumeIndexing;
+
+- (void)removePathsFromIndex:(NSSet *)paths;
+
+@end
+
