pt_BR strings updates
[adiumx.git] / Source / BGICImportController.m
blobba56c5648d9b48556af5b477b74e035ee4694e26
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 "BGICImportController.h"
18 #import "BGICLogImportController.h"
20 #import <AIUtilities/AIFileManagerAdditions.h>
22 #import "AIStatusController.h"
23 #import "AIStatusGroup.h"
24 #import "AIAccountController.h"
26 #import "ESAIMService.h"
27 #import "ESDotMacService.h"
28 #import "ESJabberService.h"
29 #import "AWBonjourService.h"
31 #define ICHAT_LOCATION [@"~/Documents/iChats/" stringByExpandingTildeInPath]
33 @interface BGICImportController (PRIVATE)
34 -(void)startLogImport;
35 -(void)populateAccountPicker;
36 -(void)deleteAllFromiChat;
37 -(void)importAccountsForService:(NSString *)serviceName;
38 -(void)importLogs;
39 -(void)importStatuses;
40 -(void)addStatusFromString:(NSString *)statusString isAway:(BOOL)shouldBeAway withGroup:(AIStatusGroup *)parentGroup;
41 @end
43 @implementation BGICImportController (PRIVATE)
45 -(void)startLogImport
47         [backButton setEnabled:NO];
48         [importProgress startAnimation:importProgress];
49         [importDetails setStringValue:@"Gathering list of transcripts..."];
50         [loggingPanes selectTabViewItemWithIdentifier:@"import"];
51         [cancelImportButton setHidden:NO];
52         fullDump = [[[NSFileManager defaultManager] subpathsAtPath:ICHAT_LOCATION] retain];
53         dumpCount = [fullDump count];
54         dumpLoop = 0;
55         currentStep--;
56         cancelImport = NO;
57         [self performSelector:@selector(importLogs) withObject:nil afterDelay:0.15];    
60 // loop the accounts in Adium and add them to the popup.
61 // This selection will be used for the log folder target (service.account in PATH_LOGS to be exact)
62 -(void)populateAccountPicker
64         [accountSelectionPopup removeAllItems];
65         
66         if(accountsArray == nil)
67                 accountsArray = [[NSMutableArray alloc] init];
68         else
69                 [accountsArray removeAllObjects];
70         
71         NSArray *accountsAvailable = [[adium accountController] accounts];
72         
73         if([accountsAvailable count] > 0)
74         {
75                 [accountSelectionPopup setHidden:NO];
77                 for(int accountLoop = 0; accountLoop < [accountsAvailable count]; accountLoop++)
78                 {
79                         AIAccount *currentAccount = [accountsAvailable objectAtIndex:accountLoop];
80                         [accountSelectionLabel setStringValue:@"Please select an account to import your transcripts into:"];
81                         [accountSelectionPopup addItemWithTitle:[NSString stringWithFormat:@"%@ (%@)", [currentAccount formattedUID], [currentAccount serviceID]]];
82                         [accountsArray addObject:[NSString stringWithFormat:@"%@.%@", [currentAccount serviceID], [currentAccount formattedUID]]];
83                 }               
84         }
85         else
86         {
87                 // no accounts are present so we'll error this phase out
88                 currentStep--;
89                 [accountSelectionLabel setStringValue:@"Importing transcripts requires at least 1 account to be present."];
90                 [accountSelectionPopup setHidden:YES];
91                 [backButton setEnabled:YES];
92                 [proceedButton setEnabled:YES];
93         }
96 // loop through the iChat log paths and move them all to the Trash
97 -(void)deleteAllFromiChat
98 {       
99         for(int deleteLoop = 0; deleteLoop < [fullDump count]; deleteLoop++)
100         {
101                 NSString *logPath = [fullDump objectAtIndex:deleteLoop];
102                 
103                 if([logPath rangeOfString:@"DS_Store"].length == 0)
104                 {
105                         [[NSFileManager defaultManager] trashFileAtPath:[[ICHAT_LOCATION stringByAppendingPathComponent:logPath] stringByExpandingTildeInPath]];
106                 }                       
107         }       
108         
109         [importDetails setStringValue:@"Your iChat transcripts have been removed."];
110         [proceedButton setEnabled:YES];
113 -(void)importAccountsForService:(NSString *)serviceName
115         // com.apple.iChat.AIM.plist -> accounts on AIM
116         NSDictionary *rawPrefsFile = [NSDictionary dictionaryWithContentsOfFile:[[NSString stringWithFormat:@"~/Library/Preferences/com.apple.iChat.%@.plist", serviceName] stringByExpandingTildeInPath]];
117         NSArray *accountsFromRaw = [[rawPrefsFile valueForKey:@"Accounts"] allValues];
118                 
119         NSEnumerator *serviceEnum = [[[adium accountController] services] objectEnumerator];
120         AIService *service = nil;
121         
122         // we'll grab these momentarily and use judiciously afterwards, Bonjour is external to this to method, unlike the others
123         ESAIMService *aimService = nil;
124         ESDotMacService *macService = nil;
125         ESJabberService *jabberService = nil;   
126                                         
127         while ((service = [serviceEnum nextObject]) != nil)
128         {
129                 if([[service serviceID] isEqual:@"AIM"])
130                         aimService = (ESAIMService *)service;
131                 if([[service serviceID] isEqual:@"Mac"])
132                         macService = (ESDotMacService *)service;
133                 if([[service serviceID] isEqual:@"Jabber"])
134                         jabberService = (ESJabberService *)service;
135                 if([[service serviceID] isEqual:@"Bonjour"])
136                         bonjourService = (AWBonjourService *)service;
137         }       
138         
139         for(int accountLoop = 0; accountLoop < [accountsFromRaw count]; accountLoop++)
140         {
141                 if(![serviceName isEqual:@"SubNet"])
142                 {
143                         NSDictionary *currentAccount = [accountsFromRaw objectAtIndex:accountLoop];
144                         
145                         NSString *accountName = [currentAccount objectForKey:@"LoginAs"];
146                         
147                         AIAccount *newAcct = [[adium accountController] createAccountWithService:
148                                 ([serviceName isEqual:@"Jabber"] ? (AIService *)jabberService : ([accountName rangeOfString:@"mac.com"].length > 0 ? (AIService *)macService : (AIService *)aimService))
149                                                                                                                                                                  UID:accountName];
150                         if(newAcct == nil)
151                                 continue;
152                         
153                         NSNumber *autoLogin = [currentAccount objectForKey:@"AutoLogin"];
154                         [newAcct setPreference:autoLogin
155                                                         forKey:@"Online"
156                                                          group:GROUP_ACCOUNT_STATUS];
157                         
158                         NSString *serverHost = [currentAccount objectForKey:@"ServerHost"];
159                         if([serverHost length] > 0)
160                                 [newAcct setPreference:serverHost
161                                                                 forKey:KEY_CONNECT_HOST
162                                                                  group:GROUP_ACCOUNT_STATUS];   
163                         
164                         NSNumber *serverPort = [currentAccount objectForKey:@"ServerPort"];
165                         if(serverPort)
166                                 [newAcct setPreference:serverPort
167                                                                 forKey:KEY_CONNECT_PORT
168                                                                  group:GROUP_ACCOUNT_STATUS];
169                         
170                         [[adium accountController] addAccount:newAcct];                         
171                 }
172                 else
173                 {
174                         blockForBonjour = YES;                  
175                         
176                         // iChat stores only the fact that the Default (username) account should be used and whether to auto-login
177                         NSDictionary *currentAccount = [accountsFromRaw objectAtIndex:accountLoop];
178                         bonjourAutoLogin = [[currentAccount objectForKey:@"AutoLogin"] boolValue];
180                         // Adium, however, has a more flexible Bonjour account configuration and we have to take this into account.
181                         [NSApp beginSheet:bonjourNamePromptWindow modalForWindow:[self window] modalDelegate:nil didEndSelector:nil contextInfo:nil];
182                         
183                 }
184         }
187 -(void)importLogs 
189         if(dumpLoop == 0)
190         {
191                 [importProgress setIndeterminate:NO];
192                 [importProgress setMaxValue:dumpCount];
193                 [importProgress setMinValue:0];
194                 [deleteLogsButton setHidden:YES];
195                 [cancelImportButton setHidden:NO];
196         }
197         
198         if(dumpLoop >= dumpCount)
199         {
200                 [importProgress setIndeterminate:YES];
201                 [importProgress stopAnimation:importProgress];
202                 [importDetails setStringValue:@"Transcript importing complete."];
203                 [importProgress setHidden:YES];
204                 [proceedButton setEnabled:YES];
205                 [deleteLogsButton setHidden:NO];
206                 [backButton setEnabled:YES];
207                 [cancelImportButton setHidden:YES];
208         }
209         else
210         {
211                 NSString *logPath = [fullDump objectAtIndex:dumpLoop];
212                 
213                 if(logImporter == nil)
214                         logImporter = [[BGICLogImportController alloc] initWithDestination:destinationAccount];
215                 
216                 [importProgress setDoubleValue:dumpLoop];
217                 [importDetails setStringValue:[NSString stringWithFormat:@"Now importing transcript %i of %i - %@...", dumpLoop, dumpCount, [logPath stringByDeletingPathExtension]]];
218                 
219                 if([logPath rangeOfString:@"DS_Store"].length == 0)
220                 {
221                         // pass the current log's path over and let the log conversion class do it's work
222                         [logImporter createNewLogForPath:[[ICHAT_LOCATION stringByAppendingPathComponent:logPath] stringByExpandingTildeInPath]];
223                 }
224         }
226         if(dumpLoop < dumpCount && cancelImport == NO) {
227                 [self performSelector:@selector(importLogs) withObject:nil afterDelay:0.10];
228         }
229                 
230         if(cancelImport)
231         {
232                 [importDetails setStringValue:[NSString stringWithFormat:@"Transcript importing cancelled. %i of %i transcripts already imported.", dumpLoop, dumpCount]];
233                 [importProgress setIndeterminate:YES];
234                 [importProgress stopAnimation:importProgress];
235                 [importProgress setHidden:YES];
236                 [cancelImportButton setHidden:YES];
237                 [backButton setEnabled:YES];
238                 [proceedButton setEnabled:YES];
239         }
240         
241         dumpLoop++;
244 -(void)importStatuses
246         // iChat (on 10.4 at least) stores custom statuses in a couple of arrays in it's plist
247         NSDictionary *ichatPrefs = [NSDictionary dictionaryWithContentsOfFile:[@"~/Library/Preferences/com.apple.iChat.plist" stringByExpandingTildeInPath]];
248                 
249         // loop through the availables and add them
250         NSArray *customAvailable = [ichatPrefs objectForKey:@"CustomAvailableMessages"];
251         
252         [importStatusDetails setStringValue:[NSString stringWithFormat:@"Now importing %i Available messages...", [customAvailable count]]];
253         
254         AIStatusGroup *availableGroup = nil;
255         
256         // optionally create a status group for collecting them together
257         if([createStatusGroupsButton state] == NSOnState)
258         {
259                 availableGroup = [AIStatusGroup statusGroup];
260                 [availableGroup setTitle:@"iChat Available Messages"];
261                 [availableGroup setStatusType:AIAvailableStatusType];
262                 // add to the set
263                 [[[adium statusController] rootStateGroup] addStatusItem:availableGroup atIndex:-1];
264         }
266         for(int availableLoop = 0; availableLoop < [customAvailable count]; availableLoop++)
267         {
268                 [self addStatusFromString:[customAvailable objectAtIndex:availableLoop] isAway:NO withGroup:availableGroup];
269         }
270         
271         AIStatusGroup *awayGroup = nil;
272         
273         // optionally create a status group for collecting them together
274         if([createStatusGroupsButton state] == NSOnState)
275         {
276                 awayGroup = [AIStatusGroup statusGroup];
277                 [awayGroup setTitle:@"iChat Away Messages"];
278                 [awayGroup setStatusType:AIAwayStatusType];
279                 // add to the set
280                 [[[adium statusController] rootStateGroup] addStatusItem:awayGroup atIndex:-1];
281         }       
283         // loop through the aways and add them
284         NSArray *customAways = [ichatPrefs objectForKey:@"CustomAwayMessages"];
285         
286         [importStatusDetails setStringValue:[NSString stringWithFormat:@"Now importing %i Away messages...", [customAways count]]];
288         for(int awayLoop = 0; awayLoop < [customAways count]; awayLoop++)
289         {
290                 [self addStatusFromString:[customAways objectAtIndex:awayLoop] isAway:YES withGroup:awayGroup];
291         }
292                 
293         [importStatusDetails setStringValue:@"Status importing is now complete."];
294         [importStatusProgress stopAnimation:importStatusProgress];
295         [backButton setEnabled:YES];
298 // the only difference between imported statuses is their type and reply behavior (optionally can be added to a group)
299 -(void)addStatusFromString:(NSString *)statusString isAway:(BOOL)shouldBeAway withGroup:(AIStatusGroup *)parentGroup
301         AIStatus *newStatus = [AIStatus statusOfType:(shouldBeAway ? AIAwayStatusType : AIAvailableStatusType)];
302         [newStatus setTitle:statusString];
303         [newStatus setStatusMessage:[[[NSAttributedString alloc] initWithString:statusString] autorelease]];
304         [newStatus setAutoReplyIsStatusMessage:(shouldBeAway ? YES : NO)];
305         [newStatus setShouldForceInitialIdleTime:NO];
306         
307         // optionally add to a status group
308         if(parentGroup == nil) {
309                 [[adium statusController] addStatusState:newStatus];    
310         }
311         else {
312                 [parentGroup addStatusItem:newStatus atIndex:-1];
313         }
316 @end
318 @implementation BGICImportController
320 -(void)awakeFromNib {
321         currentStep = 0;
322         
323         //Configure our background view; it should display the image transparently where our tabView overlaps it
324         [backgroundView setBackgroundImage:[NSImage imageNamed:@"AdiumyButler"]];
325         NSRect tabViewFrame = [assistantPanes frame];
326         NSRect backgroundViewFrame = [backgroundView frame];
327         tabViewFrame.origin.x -= backgroundViewFrame.origin.x;
328         tabViewFrame.origin.y -= backgroundViewFrame.origin.y;
329         [backgroundView setTransparentRect:tabViewFrame];       
330         
331         [[self window] center];
332         
333         [assistantPanes selectTabViewItemWithIdentifier:@"start"];
334         [backButton setEnabled:NO];
337 -(IBAction)openHelp:(id)sender
339 #warning This help anchor is necessary and needs a corresponding page in the book + the index needs regenerated.
340         NSString *locBookName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleHelpBookName"];
341         [[NSHelpManager sharedHelpManager] openHelpAnchor:@"ichatImport"  inBook:locBookName];
344 // this action is currently defined as returning to the start of the assistant, unchecking all and noting completed actions
345 -(IBAction)goBack:(id)sender
347         currentStep = 0;
348         
349         [backButton setEnabled:NO];
350         [proceedButton setEnabled:YES];
351         [proceedButton setTitle:@"Continue"]; // in case we are on the last step
352         
353         [importAccountsButton setState:NSOffState];
354         [importStatusButton setState:NSOffState];
355         [importLogsButton setState:NSOffState];
356         [createStatusGroupsButton setState:NSOffState];
357         
358         [assistantPanes selectTabViewItemWithIdentifier:@"start"];
361 -(IBAction)proceed:(id)sender 
363         BOOL doneSomething = NO;
364         
365         // when first clicked we'll determine how the workflow proceeds
366         if([[[assistantPanes selectedTabViewItem] identifier] isEqual:@"start"])
367         {
368                 // we want to increase the number of steps for each option selected
369                 if([importAccountsButton state] == NSOnState)
370                         currentStep++;
371                 if([importStatusButton state] == NSOnState)
372                         currentStep++;
373                 if([importLogsButton state] == NSOnState)
374                         currentStep++;
375         }
376         
377         if(currentStep == -1)
378         {
379                 doneSomething = YES;
380                 currentStep++; // return to 0
381                 [self closeWindow:self];
382         }
384         if([importAccountsButton state] == NSOnState && currentStep > 0 && !doneSomething) {
385                 doneSomething = YES;
386                 [backButton setEnabled:NO];
387                 [importAccountsProgress startAnimation:importAccountsProgress];
388                 [importAccountsDetails setStringValue:@"Now importing all your accounts from iChat..."];
389                 [titleField setStringValue:@"Importing Accounts and Settings..."];
390                 [assistantPanes selectTabViewItemWithIdentifier:@"accounts"];
391                 [importAccountsButton setState:NSOffState]; // reset so we don't do this again
392                 currentStep--;
393                 // do what's necessary to import here
394                 [self importAccountsForService:@"AIM"];
395                 [self importAccountsForService:@"Jabber"];
396                 [self importAccountsForService:@"SubNet"]; // SubNet is where iChat stores Bonjour accounts
397                 if(!blockForBonjour) {
398                         [importAccountsDetails setStringValue:@"Your accounts have been successfully imported."];
399                         [importAccountsProgress stopAnimation:importAccountsProgress];
400                         [backButton setEnabled:YES];
401                 }
402         }       
403         if([importStatusButton state] == NSOnState && currentStep > 0 && !doneSomething) {
404                 doneSomething = YES;
405                 [backButton setEnabled:NO];
406                 [importStatusProgress startAnimation:importStatusProgress];
407                 [importStatusDetails setStringValue:@"Preparing to import your custom Available and Away messages..."];
408                 [titleField setStringValue:@"Importing Statuses..."];
409                 [assistantPanes selectTabViewItemWithIdentifier:@"statuses"];
410                 [importStatusButton setState:NSOffState]; // reset so we don't do this again
411                 currentStep--;
412                 [self performSelector:@selector(importStatuses) withObject:nil afterDelay:0.3];
413         }
414         if([importLogsButton state] == NSOnState && currentStep > 0  && !doneSomething) {
415                 doneSomething = YES;
416                 [proceedButton setEnabled:NO];
417                 [self populateAccountPicker];
418                 [titleField     setStringValue:@"Importing iChat Transcripts..."];
419                 [loggingPanes selectTabViewItemWithIdentifier:@"select"];
420                 [assistantPanes selectTabViewItemWithIdentifier:@"logs"];
421                 [importLogsButton setState:NSOffState]; // reset so we don't do this again
422         }       
423         else if(currentStep == 0  && !doneSomething) {
424                 doneSomething = YES;
425                 [backButton setEnabled:YES];
426                 [titleField     setStringValue:@"Import Finished"];
427                 [assistantPanes selectTabViewItemWithIdentifier:@"end"];
428                 [proceedButton setTitle:@"Done"];
429                 currentStep--;
430         }
433 -(IBAction)completeBonjourCreation:(id)sender
435         AIAccount *newAcct = [[adium accountController] createAccountWithService:bonjourService
436                                                                                                                                                  UID:[bonjourAccountNameField stringValue]];
437         if(newAcct != nil)
438         {                                                               
439                 [newAcct setPreference:[NSNumber numberWithBool:bonjourAutoLogin]
440                                                 forKey:@"Online"
441                                                  group:GROUP_ACCOUNT_STATUS];
442                 
443                 [[adium accountController] addAccount:newAcct];         
444         }
445                                 
446         [NSApp endSheet:bonjourNamePromptWindow];
447         [bonjourNamePromptWindow orderOut:bonjourNamePromptWindow];
448         [backButton setEnabled:YES];
449         [importAccountsDetails setStringValue:@"Your accounts have been successfully imported."];
450         [importAccountsProgress stopAnimation:importAccountsProgress];
451         blockForBonjour = NO;
454 -(IBAction)selectLogAccountDestination:(id)sender
456         destinationAccount = [accountsArray objectAtIndex:[sender indexOfSelectedItem]];
457         [self performSelector:@selector(startLogImport) withObject:nil afterDelay:0.7]; // immediate == scary :)
460 // we need only set the cancel flag appropriately and the recursive importLogs will handle on its next pass
461 -(IBAction)cancelLogImport:(id)sender
463         [importDetails setStringValue:@"Cancelling transcript import... this may take a moment."];
464         cancelImport = YES;
467 -(IBAction)deleteLogs:(id)sender
469         NSAlert *warningBeforehand = [NSAlert alertWithMessageText:@"Are you sure you want to delete all of your iChat Transcripts?"
470                                                                                                  defaultButton:@"Delete" 
471                                                                                            alternateButton:@"Cancel"
472                                                                                                    otherButton:nil 
473                                                                          informativeTextWithFormat:@"All of the iChat transcripts that were imported into Adium will be moved to the Trash."];
474         [warningBeforehand beginSheetModalForWindow:[self window] 
475                                                                   modalDelegate:self
476                                                                  didEndSelector:@selector(deleteAlertDidEnd:returnCode:contextInfo:) 
477                                                                         contextInfo:nil];
480 - (void)deleteAlertDidEnd:(NSAlert *)alert returnCode:(int)returnCode contextInfo:(void *)contextInfo
482         if(returnCode == NSAlertDefaultReturn)
483         {
484                 [importDetails setStringValue:@"Deleting iChat Transcripts, this may take a few moments."];
485                 [deleteLogsButton setHidden:YES];
486                 [proceedButton setEnabled:NO];
487                 [self performSelector:@selector(deleteAllFromiChat) withObject:nil afterDelay:0.3];
488         }
491 -(void)dealloc
493         if(fullDump)
494                 [fullDump release];
495         if(logImporter)
496                 [logImporter release];
497         [super dealloc];
500 @end