Fixed the accessibility hierarchy of the message view to allow the accessibility...
[adiumx.git] / Source / XtrasInstaller.m
blobd9a0b3b2b363f0a340329485cd945c2951bf5fcb
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 "XtrasInstaller.h"
18 #import <AIUtilities/AIApplicationAdditions.h>
19 #import <AIUtilities/AIBundleAdditions.h>
20 #import <AIUtilities/AIStringAdditions.h>
22 //Should only be YES for testing
23 #define ALLOW_UNTRUSTED_XTRAS   NO
25 @interface XtrasInstaller (PRIVATE)
26 - (void)closeInstaller;
27 - (void)updateInfoText;
28 @end
30 /*!
31  * @class XtrasInstaller
32  * @brief Class which displays a progress window and downloads an AdiumXtra, decompresses it, and installs it.
33  */
34 @implementation XtrasInstaller
36 //XtrasInstaller does not autorelease because it will release itself when closed
37 + (XtrasInstaller *)installer
39         return [[XtrasInstaller alloc] init];
42 - (id)init
44         if ((self = [super init])) {
45                 download = nil;
46                 window = nil;
47         }
49         return self;
52 - (void)dealloc
54         [download release];
56         [super dealloc];
59 - (IBAction)cancel:(id)sender;
61         if (download) [download cancel];
62         [self closeInstaller];
65 - (void)sheetDidDismiss:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
67         [self cancel:nil];
70 - (void)closeInstaller
72         if (window) [window close];
73         [self autorelease];     
76 - (void)installXtraAtURL:(NSURL *)url
78         if ([[url host] isEqualToString:@"www.adiumxtras.com"] || ALLOW_UNTRUSTED_XTRAS) {
79                 NSURL   *urlToDownload;
81                 [NSBundle loadNibNamed:@"XtraProgressWindow" owner:self];
82                 [progressBar setUsesThreadedAnimation:YES];
83                 
84                 xtraName = nil;
85                 amountDownloaded = 0;
86                 downloadSize = 0;
87                 
88                 [progressBar setDoubleValue:0];
89                 [cancelButton setLocalizedString:AILocalizedString(@"Cancel",nil)];
90                 [window setTitle:AILocalizedString(@"Xtra Download",nil)];
92                 [self updateInfoText];
94                 [window makeKeyAndOrderFront:self];
96                 urlToDownload = [[NSURL alloc] initWithString:[NSString stringWithFormat:@"%@://%@/%@?%@", @"http", [url host], [url path], [url query]]];
97 //              dest = [NSTemporaryDirectory() stringByAppendingPathComponent:[[urlToDownload path] lastPathComponent]];
99                 download = [[NSURLDownload alloc] initWithRequest:[NSURLRequest requestWithURL:urlToDownload] delegate:self];
100 //              [download setDestination:dest allowOverwrite:YES];
102                 [urlToDownload release];
104         } else {
105                 NSRunAlertPanel(AILocalizedString(@"Nontrusted Xtra", nil),
106                                                 AILocalizedString(@"This Xtra is not hosted by adiumxtras.com. Automatic installation is not allowed.", nil),
107                                                 AILocalizedString(@"Cancel", nil),
108                                                 nil, nil);
109                 [self closeInstaller];
110         }
113 - (void)updateInfoText
115         int                             percentComplete = (downloadSize > 0 ? (int)(((double)amountDownloaded / (double)downloadSize) * 100.0) : 0);
116         NSString                *installText = [NSString stringWithFormat:AILocalizedString(@"Downloading %@", @"Install an Xtra; %@ is the name of the Xtra."), (xtraName ? xtraName : @"")];
117         
118         [infoText setStringValue:[NSString stringWithFormat:@"%@ (%d%%)", installText, percentComplete]];
121 - (void)download:(NSURLDownload *)connection didReceiveResponse:(NSHTTPURLResponse *)response
122 {       
123         xtraName = [[response allHeaderFields] objectForKey:@"X-Xtraname"];
124         amountDownloaded = 0;
125         downloadSize = [response expectedContentLength];
126         [progressBar setMaxValue:(long long)downloadSize];
127         [progressBar setDoubleValue:0.0];
128         [self updateInfoText];
131 - (void)download:(NSURLDownload *)connection decideDestinationWithSuggestedFilename:(NSString *)filename
133         NSString * downloadDir = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString uuid]];
134         [[NSFileManager defaultManager] createDirectoryAtPath:downloadDir attributes:nil];
135         dest = [downloadDir stringByAppendingPathComponent:filename];
136         [download setDestination:dest allowOverwrite:YES];
139 - (void)download:(NSURLDownload *)download didReceiveDataOfLength:(unsigned)length
141         amountDownloaded += (long long)length;
142         if (downloadSize != NSURLResponseUnknownLength) {
143                 [progressBar setDoubleValue:(double)amountDownloaded];
144                 [self updateInfoText];
145         }
146         else
147                 [progressBar setIndeterminate:YES];
150 - (BOOL)download:(NSURLDownload *)download shouldDecodeSourceDataOfMIMEType:(NSString *)encodingType {
151     return NO;
154 - (void)download:(NSURLDownload *)inDownload didFailWithError:(NSError *)error {
155         NSString        *errorMsg;
157         errorMsg = [NSString stringWithFormat:AILocalizedString(@"An error occurred while downloading this Xtra: %@.",nil),[error localizedDescription]];
158         
159         NSBeginAlertSheet(AILocalizedString(@"Xtra Downloading Error",nil), AILocalizedString(@"Cancel",nil), nil, nil, window, self,
160                                          NULL, @selector(sheetDidDismiss:returnCode:contextInfo:), nil, errorMsg);
163 - (void)downloadDidFinish:(NSURLDownload *)download {
164         NSString                *lastPathComponent = [[dest lowercaseString] lastPathComponent];
165         NSString                *pathExtension = [lastPathComponent pathExtension];
166         BOOL                    decompressionSuccess = YES;
167         
168         if ([pathExtension isEqualToString:@"tgz"] || [lastPathComponent hasSuffix:@".tar.gz"]) {
169                 NSTask                  *uncompress, *untar;
171                 uncompress = [[NSTask alloc] init];
172                 [uncompress setLaunchPath:@"/usr/bin/gunzip"];
173                 [uncompress setArguments:[NSArray arrayWithObjects:@"-df" , [dest lastPathComponent] ,  nil]];
174                 [uncompress setCurrentDirectoryPath:[dest stringByDeletingLastPathComponent]];
175                 
176                 @try
177                 {
178                         [uncompress launch];
179                         [uncompress waitUntilExit];
180                 }
181                 @catch(id exc)
182                 {
183                         decompressionSuccess = NO;      
184                 }
185                         
186                 [uncompress release];
187                 
188                 if (decompressionSuccess) {
189                         if ([pathExtension isEqualToString:@"tgz"]) {
190                                 dest = [[dest stringByDeletingPathExtension] stringByAppendingPathExtension:@"tar"];
191                         } else {
192                                 //hasSuffix .tar.gz
193                                 dest = [dest substringToIndex:[dest length] - 3];//remove the .gz, leaving us with .tar
194                         }
195                         
196                         untar = [[NSTask alloc] init];
197                         [untar setLaunchPath:@"/usr/bin/tar"];
198                         [untar setArguments:[NSArray arrayWithObjects:@"-xvf", [dest lastPathComponent], nil]];
199                         [untar setCurrentDirectoryPath:[dest stringByDeletingLastPathComponent]];
200                         
201                         @try
202                         {
203                                 [untar launch];
204                                 [untar waitUntilExit];
205                         }
206                         @catch(id exc)
207                         {
208                                 decompressionSuccess = NO;
209                         }
210                         [untar release];
211                 }
212                 
213         } else if ([pathExtension isEqualToString:@"zip"]) {
214                 NSTask  *unzip;
215                 
216                 //First, perform the actual unzipping
217                 unzip = [[NSTask alloc] init];
218                 [unzip setLaunchPath:@"/usr/bin/unzip"];
219                 [unzip setArguments:[NSArray arrayWithObjects:
220                         @"-o",  /* overwrite */
221                         @"-q", /* quiet! */
222                         dest, /* source zip file */
223                         @"-d", [dest stringByDeletingLastPathComponent], /*destination folder*/
224                         nil]];
226                 [unzip setCurrentDirectoryPath:[dest stringByDeletingLastPathComponent]];
228                 @try
229                 {
230                         [unzip launch];
231                         [unzip waitUntilExit];
232                 }
233                 @catch(id exc)
234                 {
235                         decompressionSuccess = NO;                      
236                 }
237                 [unzip release];
239         } else {
240                 decompressionSuccess = NO;
241         }
242         
243         NSFileManager   *fileManager = [NSFileManager defaultManager];
244         NSEnumerator    *fileEnumerator;
246         //Delete the compressed xtra, now that we've decompressed it
247         [fileManager removeFileAtPath:dest handler:nil];
248         
249         dest = [dest stringByDeletingLastPathComponent];
250         
251         //the remaining files in the directory should be the contents of the xtra
252         fileEnumerator = [fileManager enumeratorAtPath:dest];
253         AILog(@"Downloaded to %@. fileEnumerator: %@",dest,fileEnumerator);
255         if (decompressionSuccess && fileEnumerator) {
256                 NSString                *xtraPath;
257                 NSString                *nextFile;
258                 NSSet                   *supportedDocumentExtensions = [[NSBundle mainBundle] supportedDocumentExtensions];
260                 while((nextFile = [fileEnumerator nextObject])) {
261                         /* Ignore hidden files and the __MACOSX folder which some compression engines stick into the archive but
262                          * /usr/bin/unzip doesn't handle properly.
263                          */
264                         if ((![[nextFile lastPathComponent] hasPrefix:@"."]) &&
265                                 (![[nextFile pathComponents] containsObject:@"__MACOSX"])) {
266                                 NSString                *fileExtension = [nextFile pathExtension];
267                                 NSEnumerator    *supportedDocumentExtensionsEnumerator;
268                                 NSString                *extension;
269                                 BOOL                    isSupported = NO;
271                                 //We want to do a case-insensitive path extension comparison
272                                 supportedDocumentExtensionsEnumerator = [supportedDocumentExtensions objectEnumerator];
273                                 while (!isSupported &&
274                                            (extension = [supportedDocumentExtensionsEnumerator nextObject])) {
275                                         isSupported = ([fileExtension caseInsensitiveCompare:extension] == NSOrderedSame);
276                                 }
278                                 if (isSupported) {
279                                         BOOL    success;
281                                         xtraPath = [dest stringByAppendingPathComponent:nextFile];
283                                         //Open the file directly
284                                         AILog(@"Installing %@",xtraPath);
285                                         success = [[NSApp delegate] application:NSApp
286                                                                                            openTempFile:xtraPath];
288                                         if (!success) {
289                                                 NSLog(@"Installation Error: %@",xtraPath);
290                                         }
291                                 }
292                         }
293                 }
294                 
295         } else {
296                 NSLog(@"Installation Error: %@ (%@)",dest, (decompressionSuccess ? @"Decompressed succesfully" : @"Failed to decompress"));
297         }
298         
299         //delete our temporary directory, and any files remaining in it
300         [fileManager removeFileAtPath:dest handler:nil];
301         
302         [self closeInstaller];
305 @end