Patch from Jesse Rusak which prevents the message window and contact list from steali...
[adiumx.git] / Source / XtrasInstaller.m
blob9537a826219919db6d76d08606f7ae2e12aee7a6
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/AIExceptionHandlingUtilities.h>
21 #import <AIUtilities/AIStringAdditions.h>
23 //Should only be YES for testing
24 #define ALLOW_UNTRUSTED_XTRAS   NO
26 @interface XtrasInstaller (PRIVATE)
27 - (void)closeInstaller;
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                 [progressBar setDoubleValue:0];
85                 [percentText setStringValue:@"0%"];
86                 [cancelButton setLocalizedString:AILocalizedString(@"Cancel",nil)];
87                 [window setTitle:AILocalizedString(@"Xtra Download",nil)];
88                 [window makeKeyAndOrderFront:self];
90                 urlToDownload = [[NSURL alloc] initWithString:[NSString stringWithFormat:@"%@://%@/%@?%@", @"http", [url host], [url path], [url query]]];
91 //              dest = [NSTemporaryDirectory() stringByAppendingPathComponent:[[urlToDownload path] lastPathComponent]];
93                 download = [[NSURLDownload alloc] initWithRequest:[NSURLRequest requestWithURL:urlToDownload] delegate:self];
94 //              [download setDestination:dest allowOverwrite:YES];
96                 [urlToDownload release];
98         } else {
99                 NSRunAlertPanel(AILocalizedString(@"Nontrusted Xtra", nil),
100                                                 AILocalizedString(@"This Xtra is not hosted by adiumxtras.com. Automatic installation is not allowed.", nil),
101                                                 AILocalizedString(@"Cancel", nil),
102                                                 nil, nil);
103                 [self closeInstaller];
104         }
107 - (void)download:(NSURLDownload *)connection didReceiveResponse:(NSURLResponse *)response
109         amountDownloaded = 0;
110         downloadSize = [response expectedContentLength];
111         [progressBar setMaxValue:(long long)downloadSize];
112         [progressBar setDoubleValue:0.0];
115 - (void)download:(NSURLDownload *)connection decideDestinationWithSuggestedFilename:(NSString *)filename
117         NSString * downloadDir = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString uuid]];
118         [[NSFileManager defaultManager] createDirectoryAtPath:downloadDir attributes:nil];
119         dest = [downloadDir stringByAppendingPathComponent:filename];
120         [download setDestination:dest allowOverwrite:YES];
123 - (void)download:(NSURLDownload *)download didReceiveDataOfLength:(unsigned)length
125         amountDownloaded += (long long)length;
126         if (downloadSize != NSURLResponseUnknownLength) {
127                 [progressBar setDoubleValue:(double)amountDownloaded];
128                 [percentText setStringValue:[NSString stringWithFormat:@"%f%",(double)((amountDownloaded / (double)downloadSize) * 100)]];
129         }
130         else
131                 [progressBar setIndeterminate:YES];
134 - (BOOL)download:(NSURLDownload *)download shouldDecodeSourceDataOfMIMEType:(NSString *)encodingType {
135     return NO;
138 - (void)download:(NSURLDownload *)inDownload didFailWithError:(NSError *)error {
139         NSString        *errorMsg;
141         errorMsg = [NSString stringWithFormat:AILocalizedString(@"An error occurred while downloading this Xtra: %@.",nil),[error localizedDescription]];
142         
143         NSBeginAlertSheet(AILocalizedString(@"Xtra Downloading Error",nil), AILocalizedString(@"Cancel",nil), nil, nil, window, self,
144                                          NULL, @selector(sheetDidDismiss:returnCode:contextInfo:), nil, errorMsg);
147 - (void)downloadDidFinish:(NSURLDownload *)download {
148         NSString                *lastPathComponent = [[dest lowercaseString] lastPathComponent];
149         NSString                *pathExtension = [lastPathComponent pathExtension];
150         BOOL                    decompressionSuccess = YES;
151         
152         if ([pathExtension isEqualToString:@"tgz"] || [lastPathComponent hasSuffix:@".tar.gz"]) {
153                 NSTask                  *uncompress, *untar;
155                 uncompress = [[NSTask alloc] init];
156                 [uncompress setLaunchPath:@"/usr/bin/gunzip"];
157                 [uncompress setArguments:[NSArray arrayWithObjects:@"-df" , [dest lastPathComponent] ,  nil]];
158                 [uncompress setCurrentDirectoryPath:[dest stringByDeletingLastPathComponent]];
159                 
160                 AI_DURING
161                 {
162                         [uncompress launch];
163                         [uncompress waitUntilExit];
164                 }
165                 AI_HANDLER
166                 {
167                         decompressionSuccess = NO;      
168                 }
169                 AI_ENDHANDLER
170                         
171                 [uncompress release];
172                 
173                 if (decompressionSuccess) {
174                         if ([pathExtension isEqualToString:@"tgz"]) {
175                                 dest = [[dest stringByDeletingPathExtension] stringByAppendingPathExtension:@"tar"];
176                         } else {
177                                 //hasSuffix .tar.gz
178                                 dest = [dest substringToIndex:[dest length] - 3];//remove the .gz, leaving us with .tar
179                         }
180                         
181                         untar = [[NSTask alloc] init];
182                         [untar setLaunchPath:@"/usr/bin/tar"];
183                         [untar setArguments:[NSArray arrayWithObjects:@"-xvf", [dest lastPathComponent], nil]];
184                         [untar setCurrentDirectoryPath:[dest stringByDeletingLastPathComponent]];
185                         
186                         AI_DURING
187                         {
188                                 [untar launch];
189                                 [untar waitUntilExit];
190                         }
191                         AI_HANDLER
192                         {
193                                 decompressionSuccess = NO;
194                         }
195                         AI_ENDHANDLER
196                         [untar release];
197                 }
198                 
199         } else if ([pathExtension isEqualToString:@"zip"]) {
200                 NSTask  *unzip;
201                 
202                 //First, perform the actual unzipping
203                 unzip = [[NSTask alloc] init];
204                 [unzip setLaunchPath:@"/usr/bin/unzip"];
205                 [unzip setArguments:[NSArray arrayWithObjects:
206                         @"-o",  /* overwrite */
207                         @"-q", /* quiet! */
208                         dest, /* source zip file */
209                         @"-d", [dest stringByDeletingLastPathComponent], /*destination folder*/
210                         nil]];
212                 [unzip setCurrentDirectoryPath:[dest stringByDeletingLastPathComponent]];
214                 AI_DURING
215                 {
216                         [unzip launch];
217                         [unzip waitUntilExit];
218                 }
219                 AI_HANDLER
220                 {
221                         decompressionSuccess = NO;                      
222                 }
223                 AI_ENDHANDLER
224                 [unzip release];
226         } else {
227                 decompressionSuccess = NO;
228         }
229         
230         NSFileManager   *fileManager = [NSFileManager defaultManager];
231         NSEnumerator    *fileEnumerator;
233         //Delete the compressed xtra, now that we've decompressed it
234         [fileManager removeFileAtPath:dest handler:nil];
235         
236         dest = [dest stringByDeletingLastPathComponent];
237         
238         //the remaining files in the directory should be the contents of the xtra
239         fileEnumerator = [fileManager enumeratorAtPath:dest];
240         AILog(@"Downloaded to %@. fileEnumerator: %@",dest,fileEnumerator);
242         if (decompressionSuccess && fileEnumerator) {
243                 NSString                *xtraPath;
244                 NSString                *nextFile;
245                 NSSet                   *supportedDocumentExtensions = [[NSBundle mainBundle] supportedDocumentExtensions];
247                 while((nextFile = [fileEnumerator nextObject])) {
248                         /* Ignore hidden files and the __MACOSX folder which some compression engines stick into the archive but
249                          * /usr/bin/unzip doesn't handle properly.
250                          */
251                         if ((![[nextFile lastPathComponent] hasPrefix:@"."]) &&
252                                 (![[nextFile pathComponents] containsObject:@"__MACOSX"])) {
253                                 NSString                *fileExtension = [nextFile pathExtension];
254                                 NSEnumerator    *supportedDocumentExtensionsEnumerator;
255                                 NSString                *extension;
256                                 BOOL                    isSupported = NO;
258                                 //We want to do a case-insensitive path extension comparison
259                                 supportedDocumentExtensionsEnumerator = [supportedDocumentExtensions objectEnumerator];
260                                 while (!isSupported &&
261                                            (extension = [supportedDocumentExtensionsEnumerator nextObject])) {
262                                         isSupported = ([fileExtension caseInsensitiveCompare:extension] == NSOrderedSame);
263                                 }
265                                 if (isSupported) {
266                                         BOOL    success;
268                                         xtraPath = [dest stringByAppendingPathComponent:nextFile];
270                                         //Open the file directly
271                                         AILog(@"Installing %@",xtraPath);
272                                         success = [[NSApp delegate] application:NSApp
273                                                                                            openTempFile:xtraPath];
275                                         if (!success) {
276                                                 NSLog(@"Installation Error: %@",xtraPath);
277                                         }
278                                 }
279                         }
280                 }
281                 
282         } else {
283                 NSLog(@"Installation Error: %@ (%@)",dest, (decompressionSuccess ? @"Decompressed succesfully" : @"Failed to decompress"));
284         }
285         
286         //delete our temporary directory, and any files remaining in it
287         [fileManager removeFileAtPath:dest handler:nil];
288         
289         [self closeInstaller];
292 @end