Added `-[NSArray validateAsPropertyList]` and `-[NSDictionary validateAsPropertyList...
[adiumx.git] / Source / BGICLogImportController.m
blob366f0bddafb8d6904f0bb2d1087485f5a7776933
1 /* 
2 * Adium is the legal property of its developers, whose names are listed in the copyright file included
3  * with this source distribution.
4  * 
5  * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
6  * General Public License as published by the Free Software Foundation; either version 2 of the License,
7  * or (at your option) any later version.
8  * 
9  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
10  * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
11  * Public License for more details.
12  * 
13  * You should have received a copy of the GNU General Public License along with this program; if not,
14  * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
15  */
17 #import "BGICLogImportController.h"
18 #import "AIXMLAppender.h"
19 #import "AILoggerPlugin.h"
20 #import "AICoreComponentLoader.h"
21 #import <Adium/AIHTMLDecoder.h>
22 #import <Adium/AILoginControllerProtocol.h>
23 #import <AIUtilities/NSCalendarDate+ISO8601Unparsing.h>
24 #import <AIUtilities/AIFileManagerAdditions.h>
26 // InstantMessage and other iChat transcript classes are from Spiny Software's Logorrhea, used with permission.
27 #import "InstantMessage.h"
28 #import "Presentity.h"
30 //#define LOG_TO_TEST
31 #define TEST_LOGGING_LOCATION [@"~/Desktop/testLog" stringByExpandingTildeInPath]
33 @implementation BGICLogImportController
35 /* an iChat log importer needs to be set up with a destination pair, specified as @"service.account" to match current representation(s) in PATH_LOGS */
36 -(id)initWithDestination:(NSString *)newSAPair
38         self = [super init];
39         if(self)
40                 importServiceAccountPair = [newSAPair copy];
41         return self;
44 -(void)dealloc
46         [importServiceAccountPair release];
47         [super dealloc];
50 -(BOOL)createNewLogForPath:(NSString *)fullPath 
52         AIHTMLDecoder *xhtmlDecoder = [[AIHTMLDecoder alloc] initWithHeaders:NO
53                                                                                                                                 fontTags:YES
54                                                                                                                    closeFontTags:YES
55                                                                                                                            colorTags:YES
56                                                                                                                            styleTags:YES
57                                                                                                                   encodeNonASCII:YES
58                                                                                                                         encodeSpaces:NO
59                                                                                                            attachmentsAsText:YES
60                                                                                            onlyIncludeOutgoingImages:NO
61                                                                                                                   simpleTagsOnly:NO
62                                                                                                                   bodyBackground:NO
63                                                                                                          allowJavascriptURLs:YES];
64         [xhtmlDecoder setGeneratesStrictXHTML:YES];
65         [xhtmlDecoder setUsesAttachmentTextEquivalents:YES];
66         
67         // read the raw file into an array for working against, two different formats have been employed by iChat, based on available classes
68         fullPath = [[NSFileManager defaultManager] pathByResolvingAlias:fullPath];
70         NSArray *rawChat;
71         
72         @try 
73         {
74                 rawChat =  ([[fullPath pathExtension] isEqual:@"ichat"] ?
75                                         [NSKeyedUnarchiver unarchiveObjectWithFile:fullPath] :
76                                         [NSUnarchiver unarchiveObjectWithFile:fullPath]);
77         }
78         @catch (NSException *releaseException)
79         {
80                 NSLog(@"Could not open iChat log at %@: %@", fullPath, releaseException);
81                 rawChat = nil;
82         }
83         
84         if (!rawChat) return NO;
86         NSString *preceedingPath = nil;
87         
88 #ifndef LOG_TO_TEST
89         preceedingPath = [[[[adium loginController] userDirectory] stringByAppendingPathComponent:PATH_LOGS] stringByExpandingTildeInPath];
90 #else
91         preceedingPath = TEST_LOGGING_LOCATION;
92 #endif
93         
94         /*
95         [rawChat objectAtIndex:0],
96                 TEST_ACCOUNT, // this has to be matched somehow, I can't see a way offhand through as iChat stores the originating party 
97         */
98         NSString *parentPath = [preceedingPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@/%@", 
99                 importServiceAccountPair, // see commented code above for a brittle methodology
100                 [[[rawChat objectAtIndex:3] objectAtIndex:0] senderID] // this is improperly brittle and imprecise
101                 ]];
102         
103         // create a new xml parser for logs
104         NSString *documentPath = [parentPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@ (%@).chatlog", [[[rawChat objectAtIndex:3] objectAtIndex:0] senderID], [[[[rawChat objectAtIndex:2] objectAtIndex:0] date] dateWithCalendarFormat:@"%Y-%m-%dT%H.%M.%S%z" timeZone:nil]]];
105         AIXMLAppender *appender = [AIXMLAppender documentWithPath:documentPath];
106         [appender setFullSyncAfterEachAppend:NO];
108         // set up the initial layout of the xml log
109         [appender initializeDocumentWithRootElementName:@"chat"
110                                                                           attributeKeys:[NSArray arrayWithObjects:@"xmlns", @"account", @"service", nil]
111                                                                         attributeValues:[NSArray arrayWithObjects:
112                                                                                 XML_LOGGING_NAMESPACE,
113                                                                                 [[[rawChat objectAtIndex:3] objectAtIndex:0] senderID],
114                                                                                 [rawChat objectAtIndex:0],
115                                                                                 //                                                                              [[chat account] UID], // pulled from iChat transcript
116                                                                                 //                                                                              [[chat account] serviceID], // pulled from iChat transcript
117                                                                                 nil]];  
118         
119         // sequentially add the messages from the iChat transcript sans attributed text features
120         for(int i = 0; i < [[rawChat objectAtIndex:2] count]; i++)
121         {
122                 NSMutableArray *attributeKeys = [NSMutableArray arrayWithObjects:@"sender", @"time", nil];
123                 NSMutableArray *attributeValues = [NSMutableArray arrayWithObjects:
124                         ([[(InstantMessage *)[[rawChat objectAtIndex:2] objectAtIndex:i] sender] senderID] != nil ? [[(InstantMessage *)[[rawChat objectAtIndex:2] objectAtIndex:i] sender] senderID] : @""), 
125                         [[[(InstantMessage *)[[rawChat objectAtIndex:2] objectAtIndex:i] date] dateWithCalendarFormat:nil timeZone:nil] ISO8601DateString], 
126                         nil];
127                 
128                 NSMutableString *chatContents = [[[xhtmlDecoder encodeHTML:[[[rawChat objectAtIndex:2] objectAtIndex:i] text] imagesPath:nil] mutableCopy] autorelease];
129                 
130                 [appender addElementWithName:(![[[(InstantMessage *)[[rawChat objectAtIndex:2] objectAtIndex:i] sender] senderID] isEqual:@""] ? @"message" : @"event")
131                                           escapedContent:chatContents
132                                            attributeKeys:([attributeValues count] == 2 ? attributeKeys : nil)
133                                          attributeValues:([attributeValues count] == 2 ? attributeValues : nil)];
134         }
135         
136         //Force this log to disk immediately
137         [appender performFullSync];
138         
139         if ([[NSFileManager defaultManager] fileExistsAtPath:documentPath]) {
140                 [(AILoggerPlugin *)[[adium componentLoader] pluginWithClassName:@"AILoggerPlugin"] markLogDirtyAtPath:documentPath];
141                 return YES;
143         } else {
144                 return NO;
145         }
148 @end