|
adamiser@9164
|
1 |
/* |
|
adamiser@9164
|
2 |
* Adium is the legal property of its developers, whose names are listed in the copyright file included |
|
adamiser@9164
|
3 |
* with this source distribution. |
|
adamiser@9164
|
4 |
* |
|
adamiser@9164
|
5 |
* This program is free software; you can redistribute it and/or modify it under the terms of the GNU |
|
adamiser@9164
|
6 |
* General Public License as published by the Free Software Foundation; either version 2 of the License, |
|
adamiser@9164
|
7 |
* or (at your option) any later version. |
|
adamiser@9164
|
8 |
* |
|
adamiser@9164
|
9 |
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even |
|
adamiser@9164
|
10 |
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General |
|
adamiser@9164
|
11 |
* Public License for more details. |
|
adamiser@9164
|
12 |
* |
|
adamiser@9164
|
13 |
* You should have received a copy of the GNU General Public License along with this program; if not, |
|
adamiser@9164
|
14 |
* write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
|
adamiser@9164
|
15 |
*/ |
|
adamiser@3
|
16 |
|
|
Evan@16125
|
17 |
#import "AIAdium.h" |
|
Colin@12580
|
18 |
#import "AdiumURLHandling.h" |
|
adamiser@3
|
19 |
#import "AIAccountController.h" |
|
Evan@11773
|
20 |
#import "AIChatController.h" |
|
adamiser@3
|
21 |
#import "AIContactController.h" |
|
adamiser@3
|
22 |
#import "AIContentController.h" |
|
adamiser@8782
|
23 |
#import "AICoreComponentLoader.h" |
|
adamiser@8782
|
24 |
#import "AICorePluginLoader.h" |
|
adamiser@8782
|
25 |
#import "AIDockController.h" |
|
adamiser@9967
|
26 |
#import "AIEmoticonController.h" |
|
adamiser@8782
|
27 |
#import "AIInterfaceController.h" |
|
adamiser@8782
|
28 |
#import "AILoginController.h" |
|
adamiser@8782
|
29 |
#import "AIMenuController.h" |
|
adamiser@3
|
30 |
#import "AIPreferenceController.h" |
|
adamiser@8782
|
31 |
#import "AISoundController.h" |
|
adamiser@8782
|
32 |
#import "AIStatusController.h" |
|
adamiser@8782
|
33 |
#import "AIToolbarController.h" |
|
adamiser@9164
|
34 |
#import "ESApplescriptabilityController.h" |
|
adamiser@8782
|
35 |
#import "ESContactAlertsController.h" |
|
adamiser@9164
|
36 |
#import "ESDebugController.h" |
|
Evan@1280
|
37 |
#import "ESFileTransferController.h" |
|
psiona@926
|
38 |
#import "LNAboutBoxController.h" |
|
David@12648
|
39 |
#import "AIXtrasManager.h" |
|
Evan@13082
|
40 |
#import "AdiumSetupWizard.h" |
|
gbooker@14441
|
41 |
#import "ESTextAndButtonsWindowController.h" |
|
Evan@16125
|
42 |
#import "AIAppearancePreferences.h" |
|
Evan@16125
|
43 |
#import <Adium/AIAdiumProtocol.h> |
|
Evan@16125
|
44 |
#import <Adium/AIPathUtilities.h> |
|
adamiser@9164
|
45 |
#import <AIUtilities/AIFileManagerAdditions.h> |
|
Evan@12088
|
46 |
#import <AIUtilities/AIApplicationAdditions.h> |
|
David@16311
|
47 |
#import <AIUtilities/AICalendarDateAdditions.h> |
|
David@16291
|
48 |
#import <Sparkle/SUConstants.h> |
|
David@16630
|
49 |
#import <Sparkle/SUUtilities.h> |
|
Evan@1719
|
50 |
|
|
Evan@17170
|
51 |
//For Apple Help |
|
Evan@17170
|
52 |
#import <Carbon/Carbon.h> |
|
Evan@17170
|
53 |
|
|
David@12633
|
54 |
#define ADIUM_TRAC_PAGE @"http://trac.adiumx.com/" |
|
Evan@17180
|
55 |
#define ADIUM_REPORT_BUG_PAGE @"http://trac.adiumx.com/wiki/ReportingBugs" |
|
David@12633
|
56 |
#define ADIUM_FORUM_PAGE AILocalizedString(@"http://forum.adiumx.com/","Adium forums page. Localized only if a translated version exists.") |
|
David@12633
|
57 |
#define ADIUM_FEEDBACK_PAGE @"mailto:feedback@adiumx.com" |
|
David@12633
|
58 |
|
|
David@12633
|
59 |
//Portable Adium prefs key |
|
David@12633
|
60 |
#define PORTABLE_ADIUM_KEY @"Preference Folder Location" |
|
David@12633
|
61 |
|
|
Evan@13082
|
62 |
#define ALWAYS_RUN_SETUP_WIZARD FALSE |
|
Evan@13082
|
63 |
|
|
Evan@9306
|
64 |
static NSString *prefsCategory; |
|
adamiser@9164
|
65 |
|
|
David@17097
|
66 |
enum { |
|
David@17097
|
67 |
kNumberType, |
|
David@17097
|
68 |
kStringType, |
|
David@17097
|
69 |
kPeriodType |
|
David@17097
|
70 |
}; |
|
David@17097
|
71 |
|
|
David@17097
|
72 |
// The version comparison code here is courtesy of Kevin Ballard, adapted from MacPAD. Thanks, Kevin! |
|
David@17097
|
73 |
|
|
Evan@17137
|
74 |
int AIGetCharType(NSString *character) |
|
David@17097
|
75 |
{ |
|
David@17097
|
76 |
if ([character isEqualToString:@"."]) { |
|
David@17097
|
77 |
return kPeriodType; |
|
David@17097
|
78 |
} else if ([character isEqualToString:@"0"] || [character intValue] != 0) { |
|
David@17097
|
79 |
return kNumberType; |
|
David@17097
|
80 |
} else { |
|
David@17097
|
81 |
return kStringType; |
|
David@17097
|
82 |
} |
|
David@17097
|
83 |
} |
|
David@17097
|
84 |
|
|
Evan@17137
|
85 |
NSArray *AISplitVersionString(NSString *version) |
|
David@17097
|
86 |
{ |
|
David@17097
|
87 |
NSString *character; |
|
David@17097
|
88 |
NSMutableString *s; |
|
David@17097
|
89 |
int i, n, oldType, newType; |
|
David@17097
|
90 |
NSMutableArray *parts = [NSMutableArray array]; |
|
David@17097
|
91 |
if ([version length] == 0) { |
|
David@17097
|
92 |
// Nothing to do here |
|
David@17097
|
93 |
return parts; |
|
David@17097
|
94 |
} |
|
David@17097
|
95 |
s = [[[version substringToIndex:1] mutableCopy] autorelease]; |
|
Evan@17137
|
96 |
oldType = AIGetCharType(s); |
|
David@17097
|
97 |
n = [version length] - 1; |
|
David@17097
|
98 |
for (i = 1; i <= n; ++i) { |
|
David@17097
|
99 |
character = [version substringWithRange:NSMakeRange(i, 1)]; |
|
Evan@17137
|
100 |
newType = AIGetCharType(character); |
|
David@17097
|
101 |
if (oldType != newType || oldType == kPeriodType) { |
|
David@17097
|
102 |
// We've reached a new segment |
|
David@17097
|
103 |
NSString *aPart = [[NSString alloc] initWithString:s]; |
|
David@17097
|
104 |
[parts addObject:aPart]; |
|
David@17097
|
105 |
[aPart release]; |
|
David@17097
|
106 |
[s setString:character]; |
|
David@17097
|
107 |
} else { |
|
David@17097
|
108 |
// Add character to string and continue |
|
David@17097
|
109 |
[s appendString:character]; |
|
David@17097
|
110 |
} |
|
David@17097
|
111 |
oldType = newType; |
|
David@17097
|
112 |
} |
|
David@17097
|
113 |
|
|
David@17097
|
114 |
// Add the last part onto the array |
|
David@17097
|
115 |
[parts addObject:[NSString stringWithString:s]]; |
|
David@17097
|
116 |
return parts; |
|
David@17097
|
117 |
} |
|
David@17097
|
118 |
|
|
David@17313
|
119 |
//newVersion, currentVersion |
|
David@17097
|
120 |
NSComparisonResult AICustomVersionComparison(NSString *versionA, NSString *versionB) |
|
David@17097
|
121 |
{ |
|
Evan@17137
|
122 |
NSArray *partsA = AISplitVersionString(versionA); |
|
Evan@17137
|
123 |
NSArray *partsB = AISplitVersionString(versionB); |
|
David@17097
|
124 |
|
|
David@17097
|
125 |
NSString *partA, *partB; |
|
David@17097
|
126 |
int i, n, typeA, typeB, intA, intB; |
|
David@17097
|
127 |
|
|
David@17097
|
128 |
n = MIN([partsA count], [partsB count]); |
|
David@17097
|
129 |
for (i = 0; i < n; ++i) { |
|
David@17097
|
130 |
partA = [partsA objectAtIndex:i]; |
|
David@17097
|
131 |
partB = [partsB objectAtIndex:i]; |
|
David@17097
|
132 |
|
|
Evan@17137
|
133 |
typeA = AIGetCharType(partA); |
|
Evan@17137
|
134 |
typeB = AIGetCharType(partB); |
|
David@17097
|
135 |
|
|
David@17097
|
136 |
// Compare types |
|
David@17097
|
137 |
if (typeA == typeB) { |
|
David@17097
|
138 |
// Same type; we can compare |
|
David@17097
|
139 |
if (typeA == kNumberType) { |
|
David@17097
|
140 |
intA = [partA intValue]; |
|
David@17097
|
141 |
intB = [partB intValue]; |
|
David@17097
|
142 |
if (intA > intB) { |
|
David@17097
|
143 |
return NSOrderedAscending; |
|
David@17097
|
144 |
} else if (intA < intB) { |
|
David@17097
|
145 |
return NSOrderedDescending; |
|
David@17097
|
146 |
} |
|
David@17097
|
147 |
} else if (typeA == kStringType) { |
|
David@17097
|
148 |
NSComparisonResult result = [partA compare:partB]; |
|
David@17097
|
149 |
if (result != NSOrderedSame) { |
|
David@17313
|
150 |
if ([partB isEqualToString:@"rc"]) |
|
David@17313
|
151 |
return NSOrderedDescending; |
|
David@17097
|
152 |
if ([partA isEqualToString:@"rc"]) |
|
David@17097
|
153 |
return NSOrderedAscending; |
|
David@17313
|
154 |
if ([partB isEqualToString:@"b"]) |
|
David@17097
|
155 |
return NSOrderedDescending; |
|
David@17097
|
156 |
if ([partA isEqualToString:@"b"]) |
|
David@17097
|
157 |
return NSOrderedAscending; |
|
David@17313
|
158 |
if ([partB isEqualToString:@"a"]) |
|
David@17097
|
159 |
return NSOrderedDescending; |
|
David@17097
|
160 |
if ([partA isEqualToString:@"a"]) |
|
David@17097
|
161 |
return NSOrderedAscending; |
|
David@17097
|
162 |
} |
|
David@17097
|
163 |
} |
|
David@17097
|
164 |
} else { |
|
David@17097
|
165 |
// Not the same type? Now we have to do some validity checking |
|
David@17097
|
166 |
if (typeA != kStringType && typeB == kStringType) { |
|
David@17097
|
167 |
// typeA wins |
|
David@17097
|
168 |
return NSOrderedAscending; |
|
David@17097
|
169 |
} else if (typeA == kStringType && typeB != kStringType) { |
|
David@17097
|
170 |
// typeB wins |
|
David@17097
|
171 |
return NSOrderedDescending; |
|
David@17097
|
172 |
} else { |
|
David@17097
|
173 |
// One is a number and the other is a period. The period is invalid |
|
David@17097
|
174 |
if (typeA == kNumberType) { |
|
David@17097
|
175 |
return NSOrderedAscending; |
|
David@17097
|
176 |
} else { |
|
David@17097
|
177 |
return NSOrderedDescending; |
|
David@17097
|
178 |
} |
|
David@17097
|
179 |
} |
|
David@17097
|
180 |
} |
|
David@17097
|
181 |
} |
|
David@17097
|
182 |
// The versions are equal up to the point where they both still have parts |
|
David@17097
|
183 |
// Lets check to see if one is larger than the other |
|
David@17097
|
184 |
if ([partsA count] != [partsB count]) { |
|
David@17097
|
185 |
// Yep. Lets get the next part of the larger |
|
David@17097
|
186 |
// n holds the value we want |
|
David@17097
|
187 |
NSString *missingPart; |
|
David@17097
|
188 |
int missingType, shorterResult, largerResult; |
|
David@17097
|
189 |
|
|
David@17097
|
190 |
if ([partsA count] > [partsB count]) { |
|
David@17097
|
191 |
missingPart = [partsA objectAtIndex:n]; |
|
David@17097
|
192 |
shorterResult = NSOrderedDescending; |
|
David@17097
|
193 |
largerResult = NSOrderedAscending; |
|
David@17097
|
194 |
} else { |
|
David@17097
|
195 |
missingPart = [partsB objectAtIndex:n]; |
|
David@17097
|
196 |
shorterResult = NSOrderedAscending; |
|
David@17097
|
197 |
largerResult = NSOrderedDescending; |
|
David@17097
|
198 |
} |
|
David@17097
|
199 |
|
|
Evan@17137
|
200 |
missingType = AIGetCharType(missingPart); |
|
David@17097
|
201 |
// Check the type |
|
David@17097
|
202 |
if (missingType == kStringType) { |
|
David@17097
|
203 |
// It's a string. Shorter version wins |
|
David@17097
|
204 |
return shorterResult; |
|
David@17097
|
205 |
} else { |
|
David@17097
|
206 |
// It's a number/period. Larger version wins |
|
David@17097
|
207 |
return largerResult; |
|
David@17097
|
208 |
} |
|
David@17097
|
209 |
} |
|
David@17097
|
210 |
|
|
David@17097
|
211 |
// The 2 strings are identical |
|
David@17097
|
212 |
return NSOrderedSame; |
|
David@17097
|
213 |
} |
|
David@17097
|
214 |
|
|
adamiser@3
|
215 |
@interface AIAdium (PRIVATE) |
|
adamiser@3
|
216 |
- (void)completeLogin; |
|
Evan@5163
|
217 |
- (void)openAppropriatePreferencesIfNeeded; |
|
Evan@17170
|
218 |
- (void)configureHelp; |
|
Evan@6860
|
219 |
- (void)deleteTemporaryFiles; |
|
adamiser@3
|
220 |
@end |
|
adamiser@3
|
221 |
|
|
adamiser@3
|
222 |
@implementation AIAdium |
|
adamiser@3
|
223 |
|
|
adamiser@2892
|
224 |
//Init |
|
adamiser@7751
|
225 |
- (id)init |
|
adamiser@7751
|
226 |
{ |
|
Evan@11752
|
227 |
if ((self = [super init])) { |
|
Peter@9686
|
228 |
[AIObject _setSharedAdiumInstance:self]; |
|
Peter@9686
|
229 |
} |
|
Evan@9106
|
230 |
|
|
Peter@9686
|
231 |
return self; |
|
adamiser@1714
|
232 |
} |
|
adamiser@1714
|
233 |
|
|
adamiser@2892
|
234 |
//Core Controllers ----------------------------------------------------------------------------------------------------- |
|
adamiser@2892
|
235 |
#pragma mark Core Controllers |
|
Evan@15541
|
236 |
- (NSObject <AILoginController> *)loginController{ |
|
Catfish_Man@12140
|
237 |
return loginController; |
|
adamiser@3
|
238 |
} |
|
Evan@15541
|
239 |
- (NSObject <AIMenuController> *)menuController{ |
|
Catfish_Man@12140
|
240 |
return menuController; |
|
adamiser@3
|
241 |
} |
|
Evan@15541
|
242 |
- (NSObject <AIAccountController> *)accountController{ |
|
Catfish_Man@12140
|
243 |
return accountController; |
|
adamiser@3
|
244 |
} |
|
Evan@15541
|
245 |
- (NSObject <AIChatController> *)chatController{ |
|
Catfish_Man@12140
|
246 |
return chatController; |
|
Evan@11773
|
247 |
} |
|
Evan@15541
|
248 |
- (NSObject <AIContentController> *)contentController{ |
|
Catfish_Man@12140
|
249 |
return contentController; |
|
adamiser@3
|
250 |
} |
|
Evan@15541
|
251 |
- (NSObject <AIContactController> *)contactController{ |
|
Catfish_Man@12140
|
252 |
return contactController; |
|
adamiser@3
|
253 |
} |
|
Evan@15541
|
254 |
- (NSObject <AIEmoticonController> *)emoticonController{ |
|
Catfish_Man@12140
|
255 |
return emoticonController; |
|
adamiser@9967
|
256 |
} |
|
Evan@15541
|
257 |
- (NSObject <AISoundController> *)soundController{ |
|
Catfish_Man@12140
|
258 |
return soundController; |
|
adamiser@3
|
259 |
} |
|
Evan@15541
|
260 |
- (NSObject <AIInterfaceController> *)interfaceController{ |
|
Catfish_Man@12140
|
261 |
return interfaceController; |
|
adamiser@3
|
262 |
} |
|
Evan@15541
|
263 |
- (NSObject <AIPreferenceController> *)preferenceController{ |
|
Catfish_Man@12140
|
264 |
return preferenceController; |
|
adamiser@3
|
265 |
} |
|
Evan@15541
|
266 |
- (NSObject <AIToolbarController> *)toolbarController{ |
|
Catfish_Man@12140
|
267 |
return toolbarController; |
|
adamiser@3
|
268 |
} |
|
Evan@15541
|
269 |
- (NSObject <AIDockController> *)dockController{ |
|
Catfish_Man@12140
|
270 |
return dockController; |
|
ramoth4@167
|
271 |
} |
|
Evan@15541
|
272 |
- (NSObject <AIFileTransferController> *)fileTransferController{ |
|
Catfish_Man@12140
|
273 |
return fileTransferController; |
|
Evan@1280
|
274 |
} |
|
Evan@15541
|
275 |
- (NSObject <AIContactAlertsController> *)contactAlertsController{ |
|
Catfish_Man@12140
|
276 |
return contactAlertsController; |
|
Evan@1428
|
277 |
} |
|
Evan@15541
|
278 |
- (NSObject <AIApplescriptabilityController> *)applescriptabilityController{ |
|
Catfish_Man@12140
|
279 |
return applescriptabilityController; |
|
Evan@5707
|
280 |
} |
|
Evan@15541
|
281 |
- (NSObject <AIDebugController> *)debugController{ |
|
Catfish_Man@12140
|
282 |
return debugController; |
|
Evan@7094
|
283 |
} |
|
Evan@15541
|
284 |
- (NSObject <AIStatusController> *)statusController{ |
|
Catfish_Man@12140
|
285 |
return statusController; |
|
adamiser@8782
|
286 |
} |
|
adamiser@2892
|
287 |
|
|
Peter@10945
|
288 |
//Loaders -------------------------------------------------------------------------------------------------------- |
|
Peter@10945
|
289 |
#pragma mark Loaders |
|
Peter@10945
|
290 |
|
|
Peter@10945
|
291 |
- (AICoreComponentLoader *)componentLoader |
|
Peter@10945
|
292 |
{ |
|
Peter@10945
|
293 |
return componentLoader; |
|
Peter@10945
|
294 |
} |
|
Peter@10945
|
295 |
|
|
adamiser@2892
|
296 |
//Notifications -------------------------------------------------------------------------------------------------------- |
|
adamiser@2892
|
297 |
#pragma mark Notifications |
|
adamiser@2892
|
298 |
//Return the shared Adium notification center |
|
adamiser@239
|
299 |
- (NSNotificationCenter *)notificationCenter |
|
adamiser@239
|
300 |
{ |
|
Evan@11752
|
301 |
if (notificationCenter == nil) { |
|
adamiser@239
|
302 |
notificationCenter = [[NSNotificationCenter alloc] init]; |
|
adamiser@239
|
303 |
} |
|
adamiser@969
|
304 |
|
|
Catfish_Man@12140
|
305 |
return notificationCenter; |
|
adamiser@239
|
306 |
} |
|
adamiser@239
|
307 |
|
|
adamiser@7751
|
308 |
|
|
adamiser@2892
|
309 |
//Startup and Shutdown ------------------------------------------------------------------------------------------------- |
|
adamiser@2892
|
310 |
#pragma mark Startup and Shutdown |
|
adamiser@2892
|
311 |
//Adium is almost done launching, init |
|
adamiser@2892
|
312 |
- (void)applicationWillFinishLaunching:(NSNotification *)notification |
|
adamiser@2892
|
313 |
{ |
|
adamiser@2892
|
314 |
notificationCenter = nil; |
|
adamiser@2892
|
315 |
completedApplicationLoad = NO; |
|
Evan@5163
|
316 |
advancedPrefsName = nil; |
|
Evan@9306
|
317 |
prefsCategory = nil; |
|
Colin@12580
|
318 |
queuedURLEvents = nil; |
|
Colin@12580
|
319 |
|
|
Evan@3961
|
320 |
//Ignore SIGPIPE, which is a harmless error signal |
|
Evan@3961
|
321 |
//sent when write() or similar function calls fail due to a broken pipe in the network connection |
|
Evan@3961
|
322 |
signal(SIGPIPE, SIG_IGN); |
|
Colin@12580
|
323 |
|
|
Colin@12580
|
324 |
[[NSAppleEventManager sharedAppleEventManager] setEventHandler:self |
|
Colin@12580
|
325 |
andSelector:@selector(handleURLEvent:withReplyEvent:) |
|
Colin@12580
|
326 |
forEventClass:kInternetEventClass |
|
Colin@12580
|
327 |
andEventID:kAEGetURL]; |
|
Colin@12580
|
328 |
} |
|
Colin@12580
|
329 |
|
|
Colin@12580
|
330 |
- (void)handleURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent |
|
Colin@12580
|
331 |
{ |
|
Colin@12580
|
332 |
if (!completedApplicationLoad) { |
|
Colin@12580
|
333 |
if (!queuedURLEvents) { |
|
Colin@12580
|
334 |
queuedURLEvents = [[NSMutableArray alloc] init]; |
|
Colin@12580
|
335 |
} |
|
Colin@12583
|
336 |
[queuedURLEvents addObject:[[event descriptorAtIndex:1] stringValue]]; |
|
Colin@12580
|
337 |
} else { |
|
Colin@12583
|
338 |
[AdiumURLHandling handleURLEvent:[[event descriptorAtIndex:1] stringValue]]; |
|
Colin@12580
|
339 |
} |
|
Evan@5163
|
340 |
} |
|
Evan@5163
|
341 |
|
|
Evan@5163
|
342 |
//Adium has finished launching |
|
Evan@5163
|
343 |
- (void)applicationDidFinishLaunching:(NSNotification *)notification |
|
Evan@5163
|
344 |
{ |
|
Evan@5163
|
345 |
//Begin loading and initing the components |
|
Evan@11773
|
346 |
loginController = [[AILoginController alloc] init]; |
|
adamiser@2892
|
347 |
|
|
adamiser@2892
|
348 |
//Begin Login |
|
adamiser@2892
|
349 |
[loginController requestUserNotifyingTarget:self selector:@selector(completeLogin)]; |
|
adamiser@2892
|
350 |
} |
|
adamiser@2892
|
351 |
|
|
adamiser@2892
|
352 |
//Forward a re-open message to the interface controller |
|
Evan@1577
|
353 |
- (BOOL)applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)flag |
|
Evan@1577
|
354 |
{ |
|
Catfish_Man@12140
|
355 |
return [interfaceController handleReopenWithVisibleWindows:flag]; |
|
Evan@1577
|
356 |
} |
|
Evan@1577
|
357 |
|
|
adamiser@2892
|
358 |
//Called by the login controller when a user has been selected, continue logging in |
|
adamiser@3
|
359 |
- (void)completeLogin |
|
adamiser@3
|
360 |
{ |
|
Evan@14152
|
361 |
NSAutoreleasePool *pool; |
|
Evan@14152
|
362 |
|
|
Evan@14152
|
363 |
pool = [[NSAutoreleasePool alloc] init]; |
|
Evan@14152
|
364 |
|
|
Evan@11773
|
365 |
/* Init the controllers. |
|
Evan@11773
|
366 |
* Menu and interface controllers are created by MainMenu.nib when it loads. |
|
Evan@11773
|
367 |
*/ |
|
Evan@11773
|
368 |
preferenceController = [[AIPreferenceController alloc] init]; |
|
Evan@11773
|
369 |
toolbarController = [[AIToolbarController alloc] init]; |
|
Evan@11787
|
370 |
|
|
Evan@11787
|
371 |
#ifdef DEBUG_BUILD |
|
Evan@11773
|
372 |
debugController = [[ESDebugController alloc] init]; |
|
Evan@11787
|
373 |
#else |
|
Evan@11787
|
374 |
debugController = nil; |
|
Evan@11787
|
375 |
#endif |
|
Evan@11787
|
376 |
|
|
Evan@11773
|
377 |
contactAlertsController = [[ESContactAlertsController alloc] init]; |
|
Evan@11773
|
378 |
soundController = [[AISoundController alloc] init]; |
|
Evan@11773
|
379 |
emoticonController = [[AIEmoticonController alloc] init]; |
|
Evan@11773
|
380 |
accountController = [[AIAccountController alloc] init]; |
|
Evan@11773
|
381 |
contactController = [[AIContactController alloc] init]; |
|
Evan@11773
|
382 |
chatController = [[AIChatController alloc] init]; |
|
Evan@11773
|
383 |
contentController = [[AIContentController alloc] init]; |
|
Evan@11773
|
384 |
dockController = [[AIDockController alloc] init]; |
|
Evan@11773
|
385 |
fileTransferController = [[ESFileTransferController alloc] init]; |
|
Evan@11773
|
386 |
applescriptabilityController = [[ESApplescriptabilityController alloc] init]; |
|
Evan@11773
|
387 |
statusController = [[AIStatusController alloc] init]; |
|
Evan@11773
|
388 |
|
|
Evan@11773
|
389 |
//Finish setting up the preference controller before the components and plugins load so they can read prefs |
|
adamiser@11846
|
390 |
[preferenceController controllerDidLoad]; |
|
adamiser@11846
|
391 |
[debugController controllerDidLoad]; |
|
David@15999
|
392 |
//Safety for when we remove previously included list xtras |
|
David@15999
|
393 |
[AIAppearancePreferences migrateOldListSettingsIfNeeded]; |
|
Evan@14152
|
394 |
[pool release]; |
|
Peter@10535
|
395 |
|
|
adamiser@11846
|
396 |
//Plugins and components should always init last, since they rely on everything else. |
|
Evan@14152
|
397 |
pool = [[NSAutoreleasePool alloc] init]; |
|
Evan@11773
|
398 |
componentLoader = [[AICoreComponentLoader alloc] init]; |
|
Evan@11773
|
399 |
pluginLoader = [[AICorePluginLoader alloc] init]; |
|
Evan@14152
|
400 |
[pool release]; |
|
Evan@14152
|
401 |
|
|
adamiser@11846
|
402 |
//Finish initing |
|
Evan@14152
|
403 |
pool = [[NSAutoreleasePool alloc] init]; |
|
gbooker@14427
|
404 |
[AdiumURLHandling registerURLTypes]; //Asks the user questions so must load after components |
|
adamiser@11846
|
405 |
[menuController controllerDidLoad]; //Loaded by nib |
|
adamiser@11846
|
406 |
[accountController controllerDidLoad]; //** Before contactController so accounts and services are available for contact creation |
|
adamiser@11846
|
407 |
[contactController controllerDidLoad]; //** Before interfaceController so the contact list is available to the interface |
|
adamiser@11846
|
408 |
[interfaceController controllerDidLoad]; //Loaded by nib |
|
Evan@14152
|
409 |
[pool release]; |
|
Evan@14152
|
410 |
|
|
Evan@14152
|
411 |
pool = [[NSAutoreleasePool alloc] init]; |
|
adamiser@11846
|
412 |
[toolbarController controllerDidLoad]; |
|
adamiser@11846
|
413 |
[contactAlertsController controllerDidLoad]; |
|
adamiser@11846
|
414 |
[soundController controllerDidLoad]; |
|
adamiser@11846
|
415 |
[emoticonController controllerDidLoad]; |
|
adamiser@11846
|
416 |
[chatController controllerDidLoad]; |
|
adamiser@11846
|
417 |
[contentController controllerDidLoad]; |
|
adamiser@11846
|
418 |
[dockController controllerDidLoad]; |
|
adamiser@11846
|
419 |
[fileTransferController controllerDidLoad]; |
|
Evan@14152
|
420 |
[pool release]; |
|
Evan@14152
|
421 |
|
|
Evan@14152
|
422 |
pool = [[NSAutoreleasePool alloc] init]; |
|
adamiser@11846
|
423 |
[applescriptabilityController controllerDidLoad]; |
|
adamiser@11846
|
424 |
[statusController controllerDidLoad]; |
|
toby@10776
|
425 |
|
|
Evan@5163
|
426 |
//Open the preferences if we were unable to because application:openFile: was called before we got here |
|
Evan@5163
|
427 |
[self openAppropriatePreferencesIfNeeded]; |
|
toby@10776
|
428 |
|
|
Evan@13082
|
429 |
//If no accounts are setup, run the setup wizard |
|
Evan@13082
|
430 |
if (([[accountController accounts] count] == 0) || ALWAYS_RUN_SETUP_WIZARD) { |
|
Evan@13082
|
431 |
[AdiumSetupWizard runWizard]; |
|
adamiser@9819
|
432 |
} |
|
toby@10776
|
433 |
|
|
Colin@12580
|
434 |
//Process any delayed URL events |
|
Colin@12580
|
435 |
if (queuedURLEvents) { |
|
Colin@12583
|
436 |
NSString *eventString = nil; |
|
Colin@12580
|
437 |
NSEnumerator *e = [queuedURLEvents objectEnumerator]; |
|
Colin@12583
|
438 |
while ((eventString = [e nextObject])) { |
|
Colin@12583
|
439 |
[AdiumURLHandling handleURLEvent:eventString]; |
|
Colin@12580
|
440 |
} |
|
Evan@12900
|
441 |
[queuedURLEvents release]; queuedURLEvents = nil; |
|
Colin@12580
|
442 |
} |
|
Colin@12580
|
443 |
|
|
Evan@14046
|
444 |
//If we were asked to open a log at launch, do it now |
|
Evan@14046
|
445 |
if (queuedLogPathToShow) { |
|
Evan@17646
|
446 |
[[self notificationCenter] postNotificationName:AIShowLogAtPathNotification |
|
Evan@14046
|
447 |
object:queuedLogPathToShow]; |
|
Evan@14046
|
448 |
[queuedLogPathToShow release]; |
|
Evan@14046
|
449 |
} |
|
Evan@14046
|
450 |
|
|
toby@10776
|
451 |
completedApplicationLoad = YES; |
|
Evan@8200
|
452 |
|
|
Evan@17170
|
453 |
[self configureHelp]; |
|
Evan@17170
|
454 |
|
|
Evan@18014
|
455 |
[[NSDistributedNotificationCenter defaultCenter] addObserver:self |
|
Evan@18014
|
456 |
selector:@selector(systemTimeZoneDidChange:) |
|
Evan@18014
|
457 |
name:@"NSSystemTimeZoneDidChangeDistributedNotification" |
|
Evan@18014
|
458 |
object:nil]; |
|
Evan@18014
|
459 |
|
|
Evan@18014
|
460 |
//Broadcast our presence |
|
Evan@18014
|
461 |
NSConnection *connection = [NSConnection defaultConnection]; |
|
Evan@18014
|
462 |
[connection setRootObject:self]; |
|
Evan@18025
|
463 |
[connection registerName:@"com.adiumX.adiumX"]; |
|
Evan@18014
|
464 |
|
|
Evan@18016
|
465 |
[[self notificationCenter] postNotificationName:AIApplicationDidFinishLoadingNotification object:nil]; |
|
Evan@18016
|
466 |
[[NSDistributedNotificationCenter defaultCenter] postNotificationName:AIApplicationDidFinishLoadingNotification object:nil]; |
|
Evan@18016
|
467 |
|
|
Evan@14152
|
468 |
[pool release]; |
|
adamiser@3
|
469 |
} |
|
adamiser@3
|
470 |
|
|
adamiser@2892
|
471 |
//Give all the controllers a chance to close down |
|
adamiser@158
|
472 |
- (void)applicationWillTerminate:(NSNotification *)notification |
|
adamiser@158
|
473 |
{ |
|
Evan@13067
|
474 |
//Take no action if we didn't complete the application load |
|
Evan@13067
|
475 |
if (!completedApplicationLoad) return; |
|
Evan@13067
|
476 |
|
|
Evan@17646
|
477 |
[[self notificationCenter] postNotificationName:AIAppWillTerminateNotification object:nil]; |
|
Evan@13356
|
478 |
|
|
adamiser@11846
|
479 |
//Close the preference window before we shut down the plugins that compose it |
|
adamiser@11846
|
480 |
[preferenceController closePreferenceWindow:nil]; |
|
adamiser@2819
|
481 |
|
|
adamiser@158
|
482 |
//Close the controllers in reverse order |
|
adamiser@11846
|
483 |
[pluginLoader controllerWillClose]; //** First because plugins rely on all the controllers |
|
adamiser@11846
|
484 |
[componentLoader controllerWillClose]; //** First because components rely on all the controllers |
|
adamiser@11846
|
485 |
[statusController controllerWillClose]; //** Before accountController so account states are saved before being set to offline |
|
adamiser@11846
|
486 |
[chatController controllerWillClose]; //** Before interfaceController so chats can be correctly closed |
|
adamiser@11846
|
487 |
[contactAlertsController controllerWillClose]; |
|
adamiser@11846
|
488 |
[fileTransferController controllerWillClose]; |
|
adamiser@11846
|
489 |
[dockController controllerWillClose]; |
|
adamiser@11846
|
490 |
[interfaceController controllerWillClose]; |
|
adamiser@11846
|
491 |
[contentController controllerWillClose]; |
|
adamiser@11846
|
492 |
[contactController controllerWillClose]; |
|
adamiser@11846
|
493 |
[accountController controllerWillClose]; |
|
adamiser@11846
|
494 |
[emoticonController controllerWillClose]; |
|
adamiser@11846
|
495 |
[soundController controllerWillClose]; |
|
adamiser@11846
|
496 |
[menuController controllerWillClose]; |
|
adamiser@11846
|
497 |
[applescriptabilityController controllerWillClose]; |
|
adamiser@11846
|
498 |
[debugController controllerWillClose]; |
|
adamiser@11846
|
499 |
[toolbarController controllerWillClose]; |
|
adamiser@11846
|
500 |
[preferenceController controllerWillClose]; //** Last since other controllers may want to write preferences as they close |
|
Evan@6860
|
501 |
|
|
Evan@6860
|
502 |
[self deleteTemporaryFiles]; |
|
Evan@6860
|
503 |
} |
|
Evan@6860
|
504 |
|
|
Evan@6860
|
505 |
- (void)deleteTemporaryFiles |
|
Evan@6860
|
506 |
{ |
|
Evan@8541
|
507 |
[[NSFileManager defaultManager] removeFilesInDirectory:[self cachesPath] |
|
Evan@6913
|
508 |
withPrefix:@"TEMP" |
|
Evan@6913
|
509 |
movingToTrash:NO]; |
|
adamiser@158
|
510 |
} |
|
adamiser@158
|
511 |
|
|
adamiser@2892
|
512 |
|
|
adamiser@2892
|
513 |
//Menu Item Hooks ------------------------------------------------------------------------------------------------------ |
|
adamiser@2892
|
514 |
#pragma mark Menu Item Hooks |
|
adamiser@2892
|
515 |
//Show the about box |
|
ramoth4@834
|
516 |
- (IBAction)showAboutBox:(id)sender |
|
ramoth4@834
|
517 |
{ |
|
adamiser@1714
|
518 |
[[LNAboutBoxController aboutBoxController] showWindow:nil]; |
|
Evan@1981
|
519 |
} |
|
adamiser@2892
|
520 |
|
|
adamiser@3321
|
521 |
- (IBAction)reportABug:(id)sender{ |
|
Evan@17180
|
522 |
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:ADIUM_REPORT_BUG_PAGE]]; |
|
adamiser@3321
|
523 |
} |
|
adamiser@3321
|
524 |
- (IBAction)sendFeedback:(id)sender{ |
|
adamiser@3321
|
525 |
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:ADIUM_FEEDBACK_PAGE]]; |
|
adamiser@3321
|
526 |
} |
|
adamiser@3321
|
527 |
- (IBAction)showForums:(id)sender{ |
|
adamiser@3321
|
528 |
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:ADIUM_FORUM_PAGE]]; |
|
adamiser@3321
|
529 |
} |
|
Evan@5507
|
530 |
- (IBAction)showXtras:(id)sender{ |
|
David@12648
|
531 |
[[AIXtrasManager sharedManager] showXtras]; |
|
Evan@5507
|
532 |
} |
|
ramoth4@834
|
533 |
|
|
Evan@14835
|
534 |
- (IBAction)contibutingToAdium:(id)sender |
|
Evan@14835
|
535 |
{ |
|
Evan@14835
|
536 |
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://trac.adiumx.com/wiki/ContributingToAdium"]]; |
|
Evan@14835
|
537 |
} |
|
Evan@14835
|
538 |
- (IBAction)donate:(id)sender |
|
Evan@14835
|
539 |
{ |
|
Evan@14835
|
540 |
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&submit.x=57&submit.y=8&encrypted=-----BEGIN+PKCS7-----%0D%0AMIIHFgYJKoZIhvcNAQcEoIIHBzCCBwMCAQExggEwMIIBLAIBADCBlDCBjjELMAkG%0D%0AA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQw%0D%0AEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UE%0D%0AAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb20CAQAwDQYJ%0D%0AKoZIhvcNAQEBBQAEgYAFR5tF%2BRKUV3BS49vJraDG%2BIoWDoZMieUT%2FJJ1Fzjsr511%0D%0Au7hS1F2piJuHuqmm%2F0r8Kf8oaycOo74K3zLmUQ6T6hUS6%2Bh6lZAoIlhI3A1YmqIP%0D%0AdrdY%2FtfKRbWfolDumJ9Mdv%2FzJxPnpdQiTN5K1PMrPYE6GgPWE9WC4V9lqstSmTEL%0D%0AMAkGBSsOAwIaBQAwgZMGCSqGSIb3DQEHATAUBggqhkiG9w0DBwQIjtd%2BN9o4ZB6A%0D%0AcIbH8ZjOLmE35xBQ%2F93chtzIcRXHhIQJVpBRCkyJkdTD3libP3F7TgkrLij1DBxg%0D%0AfFlE0V%2FGTk29Ys%2FwsPO7hNs3YSNuSz0HT5F6sa8aXwFtMCE%2FgB1Ha4qdtYY%2BNETJ%0D%0AEETwNMLefjhaBfI%2BnRxl2K2gggOHMIIDgzCCAuygAwIBAgIBADANBgkqhkiG9w0B%0D%0AAQUFADCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3Vu%0D%0AdGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9j%0D%0AZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBh%0D%0AbC5jb20wHhcNMDQwMjEzMTAxMzE1WhcNMzUwMjEzMTAxMzE1WjCBjjELMAkGA1UE%0D%0ABhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYD%0D%0AVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQI%0D%0AbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb20wgZ8wDQYJKoZI%0D%0AhvcNAQEBBQADgY0AMIGJAoGBAMFHTt38RMxLXJyO2SmS%2BNdl72T7oKJ4u4uw%2B6aw%0D%0AntALWh03PewmIJuzbALScsTS4sZoS1fKciBGoh11gIfHzylvkdNe%2FhJl66%2FRGqrj%0D%0A5rFb08sAABNTzDTiqqNpJeBsYs%2Fc2aiGozptX2RlnBktH%2BSUNpAajW724Nv2Wvhi%0D%0Af6sFAgMBAAGjge4wgeswHQYDVR0OBBYEFJaffLvGbxe9WT9S1wob7BDWZJRrMIG7%0D%0ABgNVHSMEgbMwgbCAFJaffLvGbxe9WT9S1wob7BDWZJRroYGUpIGRMIGOMQswCQYD%0D%0AVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxFDAS%0D%0ABgNVBAoTC1BheVBhbCBJbmMuMRMwEQYDVQQLFApsaXZlX2NlcnRzMREwDwYDVQQD%0D%0AFAhsaXZlX2FwaTEcMBoGCSqGSIb3DQEJARYNcmVAcGF5cGFsLmNvbYIBADAMBgNV%0D%0AHRMEBTADAQH%2FMA0GCSqGSIb3DQEBBQUAA4GBAIFfOlaagFrl71%2Bjq6OKidbWFSE%2B%0D%0AQ4FqROvdgIONth%2B8kSK%2F%2FY%2F4ihuE4Ymvzn5ceE3S%2FiBSQQMjyvb%2Bs2TWbQYDwcp1%0D%0A29OPIbD9epdr4tJOUNiSojw7BHwYRiPh58S1xGlFgHFXwrEBb3dgNbMUa%2Bu4qect%0D%0AsMAXpVHnD9wIyfmHMYIBmjCCAZYCAQEwgZQwgY4xCzAJBgNVBAYTAlVTMQswCQYD%0D%0AVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLUGF5UGFs%0D%0AIEluYy4xEzARBgNVBAsUCmxpdmVfY2VydHMxETAPBgNVBAMUCGxpdmVfYXBpMRww%0D%0AGgYJKoZIhvcNAQkBFg1yZUBwYXlwYWwuY29tAgEAMAkGBSsOAwIaBQCgXTAYBgkq%0D%0AhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0wNDAzMjUwNDQ0%0D%0AMzRaMCMGCSqGSIb3DQEJBDEWBBRzTAS6zk5cmMeC49IorY8CM%2BkX0TANBgkqhkiG%0D%0A9w0BAQEFAASBgBsyRfMv9mSyoYq00wIB7BmUHFGq5x%2Ffnr8M24XbKjhkyeULk2NC%0D%0As4jbCgaWNg6grvccJtjbvmDskMKt%2BdS%2BEAkeWwm1Zf%2F%2B5u1fMyb5vo1NNcRIs5oq%0D%0A7SvXiLTPRzVqzQdhVs7PoZG0i0RRIb0tMeo1IssZeB2GE5Nsg0D8PwpB%0D%0A-----END+PKCS7-----"]]; |
|
Evan@14835
|
541 |
} |
|
Evan@14835
|
542 |
|
|
gbooker@14441
|
543 |
- (void)unreadQuitQuestion:(NSNumber *)number userInfo:(id)info |
|
gbooker@14441
|
544 |
{ |
|
gbooker@14441
|
545 |
AITextAndButtonsReturnCode result = [number intValue]; |
|
gbooker@14441
|
546 |
switch(result) |
|
gbooker@14441
|
547 |
{ |
|
gbooker@14441
|
548 |
case AITextAndButtonsDefaultReturn: |
|
gbooker@14441
|
549 |
//Quit |
|
gbooker@14441
|
550 |
//Should we ask about File Transfers here????? |
|
gbooker@14441
|
551 |
[NSApp terminate:nil]; |
|
gbooker@14441
|
552 |
break; |
|
gbooker@14441
|
553 |
case AITextAndButtonsOtherReturn: |
|
gbooker@14441
|
554 |
//Don't Ask Again |
|
gbooker@14441
|
555 |
[[self preferenceController] setPreference:[NSNumber numberWithBool:YES] |
|
gbooker@14441
|
556 |
forKey:@"Suppress Quit Confirmation for Unread Messages" |
|
gbooker@14441
|
557 |
group:@"Confirmations"]; |
|
gbooker@14441
|
558 |
[NSApp terminate:nil]; |
|
gbooker@14441
|
559 |
break; |
|
gbooker@14441
|
560 |
default: |
|
gbooker@14441
|
561 |
//Cancel |
|
gbooker@14441
|
562 |
break; |
|
gbooker@14441
|
563 |
} |
|
gbooker@14441
|
564 |
} |
|
gbooker@14441
|
565 |
|
|
gbooker@14441
|
566 |
- (void)fileTransferQuitQuestion:(NSNumber *)number userInfo:(id)info |
|
gbooker@14441
|
567 |
{ |
|
gbooker@14441
|
568 |
AITextAndButtonsReturnCode result = [number intValue]; |
|
gbooker@14441
|
569 |
switch(result) |
|
gbooker@14441
|
570 |
{ |
|
gbooker@14441
|
571 |
case AITextAndButtonsDefaultReturn: |
|
gbooker@14441
|
572 |
//Quit |
|
gbooker@14441
|
573 |
[NSApp terminate:nil]; |
|
gbooker@14441
|
574 |
break; |
|
gbooker@14441
|
575 |
case AITextAndButtonsOtherReturn: |
|
gbooker@14441
|
576 |
//Don't Ask Again |
|
gbooker@14441
|
577 |
[[self preferenceController] setPreference:[NSNumber numberWithBool:YES] |
|
gbooker@14441
|
578 |
forKey:@"Suppress Quit Confirmation for File Transfers" |
|
gbooker@14441
|
579 |
group:@"Confirmations"]; |
|
gbooker@14441
|
580 |
[NSApp terminate:nil]; |
|
gbooker@14441
|
581 |
break; |
|
gbooker@14441
|
582 |
default: |
|
gbooker@14441
|
583 |
//Cancel |
|
gbooker@14441
|
584 |
break; |
|
gbooker@14441
|
585 |
} |
|
gbooker@14441
|
586 |
} |
|
gbooker@14441
|
587 |
|
|
Evan@4931
|
588 |
//Last call to perform actions before the app shuffles off its mortal coil and joins the bleeding choir invisible |
|
ramoth4@892
|
589 |
- (IBAction)confirmQuit:(id)sender |
|
ramoth4@892
|
590 |
{ |
|
Evan@17202
|
591 |
/* We may have received a message or begun a file transfer while the menu was open, if this is reached via a menu item. |
|
Evan@17202
|
592 |
* Wait one last run loop before beginning to quit so that activity can be registered, since menus run in |
|
Evan@17202
|
593 |
* a different run loop mode, NSEventTrackingRunLoopMode. |
|
Evan@17202
|
594 |
*/ |
|
Evan@17202
|
595 |
[NSObject cancelPreviousPerformRequestsWithTarget:self |
|
Evan@17202
|
596 |
selector:@selector(reallyConfirmQuit) |
|
Evan@17202
|
597 |
object:nil]; |
|
Evan@17202
|
598 |
[self performSelector:@selector(reallyConfirmQuit) |
|
Evan@17202
|
599 |
withObject:nil |
|
Evan@17202
|
600 |
afterDelay:0]; |
|
Evan@17202
|
601 |
} |
|
Evan@17202
|
602 |
|
|
Evan@17202
|
603 |
- (void)reallyConfirmQuit |
|
Evan@17202
|
604 |
{ |
|
gbooker@14440
|
605 |
BOOL allowQuit = YES; |
|
Evan@13198
|
606 |
if (([chatController unviewedContentCount] > 0) && |
|
David@14068
|
607 |
(![[preferenceController preferenceForKey:@"Suppress Quit Confirmation for Unread Messages" |
|
Evan@13198
|
608 |
group:@"Confirmations"] boolValue])) { |
|
gbooker@14441
|
609 |
[[self interfaceController] displayQuestion:AILocalizedString(@"Confirm Quit", nil) |
|
gbooker@14441
|
610 |
withDescription:AILocalizedString(@"You have unread messages.\nAre you sure you want to quit?", nil) |
|
gbooker@14441
|
611 |
withWindowTitle:nil |
|
gbooker@14441
|
612 |
defaultButton:AILocalizedString(@"Quit", nil) |
|
gbooker@14441
|
613 |
alternateButton:AILocalizedString(@"Cancel", nil) |
|
gbooker@14441
|
614 |
otherButton:AILocalizedString(@"Don't ask again", nil) |
|
gbooker@14441
|
615 |
target:self |
|
gbooker@14441
|
616 |
selector:@selector(unreadQuitQuestion:userInfo:) |
|
gbooker@14441
|
617 |
userInfo:nil]; |
|
gbooker@14440
|
618 |
allowQuit = NO; |
|
David@14068
|
619 |
} |
|
David@14068
|
620 |
|
|
gbooker@14441
|
621 |
if (allowQuit && |
|
gbooker@14441
|
622 |
([fileTransferController activeTransferCount] > 0) && |
|
gbooker@14440
|
623 |
(![[preferenceController preferenceForKey:@"Suppress Quit Confirmation for File Transfers" |
|
gbooker@14440
|
624 |
group:@"Confirmations"] boolValue])) { |
|
gbooker@14441
|
625 |
[[self interfaceController] displayQuestion:AILocalizedString(@"Confirm Quit", nil) |
|
gbooker@14441
|
626 |
withDescription:AILocalizedString(@"You have file transfers in progress.\nAre you sure you want to quit?", nil) |
|
gbooker@14441
|
627 |
withWindowTitle:nil |
|
gbooker@14441
|
628 |
defaultButton:AILocalizedString(@"Quit", nil) |
|
gbooker@14441
|
629 |
alternateButton:AILocalizedString(@"Cancel", nil) |
|
gbooker@14441
|
630 |
otherButton:AILocalizedString(@"Don't ask again", nil) |
|
gbooker@14441
|
631 |
target:self |
|
gbooker@14441
|
632 |
selector:@selector(fileTransferQuitQuestion:userInfo:) |
|
gbooker@14441
|
633 |
userInfo:nil]; |
|
gbooker@14440
|
634 |
allowQuit = NO; |
|
David@14068
|
635 |
} |
|
David@14068
|
636 |
|
|
Evan@14816
|
637 |
if (allowQuit) { |
|
Evan@13198
|
638 |
[NSApp terminate:nil]; |
|
Evan@13198
|
639 |
} |
|
ramoth4@892
|
640 |
} |
|
ramoth4@892
|
641 |
|
|
Peter@3867
|
642 |
//Other ------------------------------------------------------------------------------------------------------- |
|
Peter@3867
|
643 |
#pragma mark Other |
|
adamiser@2892
|
644 |
//If Adium was launched by double-clicking an associated file, we get this call after willFinishLaunching but before |
|
adamiser@2892
|
645 |
//didFinishLaunching |
|
Evan@2022
|
646 |
- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename |
|
Evan@2022
|
647 |
{ |
|
Evan@4867
|
648 |
NSString *extension = [filename pathExtension]; |
|
Evan@4867
|
649 |
NSString *destination = nil; |
|
Evan@4867
|
650 |
NSString *errorMessage = nil; |
|
Evan@5163
|
651 |
NSString *fileDescription = nil, *prefsButton = nil; |
|
Evan@4867
|
652 |
BOOL success = NO, requiresRestart = NO; |
|
Evan@4867
|
653 |
int buttonPressed; |
|
Evan@5163
|
654 |
|
|
Evan@14046
|
655 |
if (([extension caseInsensitiveCompare:@"AdiumLog"] == NSOrderedSame) || |
|
David@16339
|
656 |
([extension caseInsensitiveCompare:@"AdiumHtmlLog"] == NSOrderedSame) || |
|
David@16339
|
657 |
([extension caseInsensitiveCompare:@"chatlog"] == NSOrderedSame)) { |
|
Evan@14046
|
658 |
if (completedApplicationLoad) { |
|
Evan@14046
|
659 |
//Request display of the log immediately if Adium is ready |
|
Evan@17646
|
660 |
[[self notificationCenter] postNotificationName:AIShowLogAtPathNotification |
|
Evan@14046
|
661 |
object:filename]; |
|
Evan@14046
|
662 |
} else { |
|
Evan@14046
|
663 |
//Queue the request until Adium is done launching if Adium is not ready |
|
Evan@14046
|
664 |
[queuedLogPathToShow release]; queuedLogPathToShow = [filename retain]; |
|
Evan@14046
|
665 |
} |
|
Evan@14046
|
666 |
|
|
Evan@14046
|
667 |
//Don't continue to the xtras installation code. Return YES because we handled the open. |
|
Evan@14046
|
668 |
return YES; |
|
Evan@14046
|
669 |
} |
|
Evan@14046
|
670 |
|
|
Evan@14046
|
671 |
/* Installation of Xtras below this point */ |
|
Evan@14046
|
672 |
|
|
Evan@9306
|
673 |
[prefsCategory release]; prefsCategory = nil; |
|
Evan@5163
|
674 |
[advancedPrefsName release]; advancedPrefsName = nil; |
|
Evan@14046
|
675 |
|
|
Evan@2022
|
676 |
//Specify a file extension and a human-readable description of what the files of this type do |
|
Evan@18185
|
677 |
if ([extension caseInsensitiveCompare:@"AdiumPlugin"] == NSOrderedSame) { |
|
Peter@13081
|
678 |
destination = [AISearchPathForDirectoriesInDomains(AIPluginsDirectory, NSUserDomainMask, /*expandTilde*/ YES) objectAtIndex:0]; |
|
Evan@2022
|
679 |
//Plugins haven't been loaded yet if the application isn't done loading, so only request a restart if it has finished loading already |
|
Evan@2022
|
680 |
requiresRestart = completedApplicationLoad; |
|
eevyl@6470
|
681 |
fileDescription = AILocalizedString(@"Adium plugin",nil); |
|
Evan@10297
|
682 |
|
|
Evan@18185
|
683 |
} else if ([extension caseInsensitiveCompare:@"AdiumLibpurplePlugin"] == NSOrderedSame) { |
|
Evan@18185
|
684 |
destination = [AISearchPathForDirectoriesInDomains(AIPluginsDirectory, NSUserDomainMask, /*expandTilde*/ YES) objectAtIndex:0]; |
|
Evan@18185
|
685 |
//Plugins haven't been loaded yet if the application isn't done loading, so only request a restart if it has finished loading already |
|
Evan@18185
|
686 |
requiresRestart = completedApplicationLoad; |
|
Evan@18185
|
687 |
fileDescription = AILocalizedString(@"Adium plugin",nil); |
|
Evan@18185
|
688 |
extension = @"AdiumLibpurplePlugin"; |
|
Evan@18185
|
689 |
|
|
Evan@18185
|
690 |
} else if ([extension caseInsensitiveCompare:@"AdiumIcon"] == NSOrderedSame) { |
|
Peter@13081
|
691 |
destination = [AISearchPathForDirectoriesInDomains(AIDockIconsDirectory, NSUserDomainMask, /*expandTilde*/ YES) objectAtIndex:0]; |
|
eevyl@6470
|
692 |
fileDescription = AILocalizedString(@"dock icon set",nil); |
|
adamiser@9964
|
693 |
prefsButton = AILocalizedString(@"Open Appearance Prefs",nil); |
|
adamiser@9964
|
694 |
prefsCategory = @"appearance"; |
|
dchoby98@4680
|
695 |
|
|
Evan@11752
|
696 |
} else if ([extension caseInsensitiveCompare:@"AdiumSoundset"] == NSOrderedSame) { |
|
Peter@13081
|
697 |
destination = [AISearchPathForDirectoriesInDomains(AISoundsDirectory, NSUserDomainMask, /*expandTilde*/ YES) objectAtIndex:0]; |
|
eevyl@6470
|
698 |
fileDescription = AILocalizedString(@"sound set",nil); |
|
adamiser@9964
|
699 |
prefsButton = AILocalizedString(@"Open Event Prefs",nil); |
|
Evan@9306
|
700 |
prefsCategory = @"events"; |
|
dchoby98@4680
|
701 |
|
|
Evan@11752
|
702 |
} else if ([extension caseInsensitiveCompare:@"AdiumEmoticonset"] == NSOrderedSame) { |
|
Peter@13081
|
703 |
destination = [AISearchPathForDirectoriesInDomains(AIEmoticonsDirectory, NSUserDomainMask, /*expandTilde*/ YES) objectAtIndex:0]; |
|
eevyl@6470
|
704 |
fileDescription = AILocalizedString(@"emoticon set",nil); |
|
adamiser@9964
|
705 |
prefsButton = AILocalizedString(@"Open Appearance Prefs",nil); |
|
adamiser@9964
|
706 |
prefsCategory = @"appearance"; |
|
Evan@5163
|
707 |
|
|
dchoby98@5117
|
708 |
} else if ([extension caseInsensitiveCompare:@"AdiumScripts"] == NSOrderedSame) { |
|
Peter@13081
|
709 |
destination = [AISearchPathForDirectoriesInDomains(AIScriptsDirectory, NSUserDomainMask, /*expandTilde*/ YES) objectAtIndex:0]; |
|
eevyl@6470
|
710 |
fileDescription = AILocalizedString(@"AppleScript set",nil); |
|
dchoby98@5117
|
711 |
|
|
Evan@11752
|
712 |
} else if ([extension caseInsensitiveCompare:@"AdiumMessageStyle"] == NSOrderedSame) { |
|
Peter@13081
|
713 |
destination = [AISearchPathForDirectoriesInDomains(AIMessageStylesDirectory, NSUserDomainMask, /*expandTilde*/ YES) objectAtIndex:0]; |
|
toby@11276
|
714 |
fileDescription = AILocalizedString(@"message style",nil); |
|
toby@11276
|
715 |
prefsButton = AILocalizedString(@"Open Message Prefs",nil); |
|
toby@11276
|
716 |
prefsCategory = @"messages"; |
|
Evan@11752
|
717 |
} else if ([extension caseInsensitiveCompare:@"ListLayout"] == NSOrderedSame) { |
|
Peter@13081
|
718 |
destination = [AISearchPathForDirectoriesInDomains(AIContactListDirectory, NSUserDomainMask, /*expandTilde*/ YES) objectAtIndex:0]; |
|
eevyl@6856
|
719 |
fileDescription = AILocalizedString(@"contact list layout",nil); |
|
adamiser@9964
|
720 |
prefsButton = AILocalizedString(@"Open Appearance Prefs",nil); |
|
adamiser@9964
|
721 |
prefsCategory = @"appearance"; |
|
Evan@10297
|
722 |
|
|
Evan@11752
|
723 |
} else if ([extension caseInsensitiveCompare:@"ListTheme"] == NSOrderedSame) { |
|
Peter@13081
|
724 |
destination = [AISearchPathForDirectoriesInDomains(AIContactListDirectory, NSUserDomainMask, /*expandTilde*/ YES) objectAtIndex:0]; |
|
eevyl@6856
|
725 |
fileDescription = AILocalizedString(@"contact list theme",nil); |
|
adamiser@9964
|
726 |
prefsButton = AILocalizedString(@"Open Appearance Prefs",nil); |
|
adamiser@9964
|
727 |
prefsCategory = @"appearance"; |
|
Evan@10297
|
728 |
|
|
Evan@11752
|
729 |
} else if ([extension caseInsensitiveCompare:@"AdiumServiceIcons"] == NSOrderedSame) { |
|
Peter@13081
|
730 |
destination = [AISearchPathForDirectoriesInDomains(AIServiceIconsDirectory, NSUserDomainMask, /*expandTilde*/ YES) objectAtIndex:0]; |
|
Evan@10297
|
731 |
fileDescription = AILocalizedString(@"service icons",nil); |
|
Evan@10297
|
732 |
prefsButton = AILocalizedString(@"Open Appearance Prefs",nil); |
|
Evan@10297
|
733 |
prefsCategory = @"appearance"; |
|
Evan@10297
|
734 |
|
|
Evan@11752
|
735 |
} else if ([extension caseInsensitiveCompare:@"AdiumStatusIcons"] == NSOrderedSame) { |
|
Evan@11978
|
736 |
NSString *packName = [[filename lastPathComponent] stringByDeletingPathExtension]; |
|
Evan@11979
|
737 |
/* |
|
Evan@11979
|
738 |
//Can't do this because the preferenceController isn't ready yet |
|
Evan@11979
|
739 |
NSString *defaultPackName = [[self preferenceController] defaultPreferenceForKey:@"Status Icon Pack" |
|
Evan@11979
|
740 |
group:@"Appearance" |
|
Evan@11979
|
741 |
object:nil]; |
|
Evan@11979
|
742 |
*/ |
|
David@16968
|
743 |
NSString *defaultPackName = @"iBubble Status"; |
|
Evan@11979
|
744 |
|
|
Evan@11978
|
745 |
if (![packName isEqualToString:defaultPackName]) { |
|
Peter@13081
|
746 |
destination = [AISearchPathForDirectoriesInDomains(AIStatusIconsDirectory, NSUserDomainMask, /*expandTilde*/ YES) objectAtIndex:0]; |
|
Evan@11978
|
747 |
fileDescription = AILocalizedString(@"status icons",nil); |
|
Evan@11978
|
748 |
prefsButton = AILocalizedString(@"Open Appearance Prefs",nil); |
|
Evan@11978
|
749 |
prefsCategory = @"appearance"; |
|
Evan@11978
|
750 |
} else { |
|
Evan@11978
|
751 |
errorMessage = [NSString stringWithFormat:AILocalizedString(@"%@ is the name of the default status icon pack; this pack therefore can not be installed.",nil), |
|
Evan@11978
|
752 |
packName]; |
|
Evan@11978
|
753 |
} |
|
Evan@2448
|
754 |
} |
|
Evan@2781
|
755 |
|
|
Evan@11752
|
756 |
if (destination) { |
|
Evan@2036
|
757 |
NSString *destinationFilePath = [destination stringByAppendingPathComponent:[filename lastPathComponent]]; |
|
Evan@2036
|
758 |
|
|
Evan@4867
|
759 |
NSString *alertTitle = nil; |
|
Evan@4867
|
760 |
NSString *alertMsg = nil; |
|
Evan@4867
|
761 |
NSString *format; |
|
dchoby98@4680
|
762 |
|
|
Evan@11752
|
763 |
if ([filename isEqualToString:destinationFilePath]) { |
|
dchoby98@2987
|
764 |
// Don't copy the file if it's already in the right place!! |
|
eevyl@6470
|
765 |
alertTitle= AILocalizedString(@"Installation Successful","Title of installation successful window"); |
|
Evan@4867
|
766 |
|
|
eevyl@6470
|
767 |
format = AILocalizedString(@"Installation of the %@ %@ was successful because the file was already in the correct location.", |
|
Evan@4867
|
768 |
"Installation introduction, like 'Installation of the message style Fiat was successful...'."); |
|
Evan@4867
|
769 |
|
|
Evan@4867
|
770 |
alertMsg = [NSString stringWithFormat:format, |
|
Evan@4867
|
771 |
fileDescription, |
|
Evan@4867
|
772 |
[[filename lastPathComponent] stringByDeletingPathExtension]]; |
|
Evan@4867
|
773 |
|
|
dchoby98@2987
|
774 |
} else { |
|
Evan@3858
|
775 |
//Trash the old file if one exists (since we know it isn't ourself) |
|
dchoby98@2987
|
776 |
[[NSFileManager defaultManager] trashFileAtPath:destinationFilePath]; |
|
dchoby98@2987
|
777 |
|
|
Evan@3858
|
778 |
//Ensure the directory exists |
|
Evan@3858
|
779 |
[[NSFileManager defaultManager] createDirectoryAtPath:destination attributes:nil]; |
|
Evan@3858
|
780 |
|
|
dchoby98@2987
|
781 |
//Perform the copy and display an alert informing the user of its success or failure |
|
dchoby98@2987
|
782 |
if ([[NSFileManager defaultManager] copyPath:filename |
|
dchoby98@2987
|
783 |
toPath:destinationFilePath |
|
Evan@11752
|
784 |
handler:nil]) { |
|
dchoby98@2987
|
785 |
|
|
eevyl@6470
|
786 |
alertTitle = AILocalizedString(@"Installation Successful","Title of installation successful window"); |
|
eevyl@6470
|
787 |
alertMsg = [NSString stringWithFormat:AILocalizedString(@"Installation of the %@ %@ was successful.", |
|
Evan@4867
|
788 |
"Installation sentence, like 'Installation of the message style Fiat was successful.'."), |
|
Evan@4867
|
789 |
fileDescription, |
|
Evan@4867
|
790 |
[[filename lastPathComponent] stringByDeletingPathExtension]]; |
|
Evan@4867
|
791 |
|
|
Evan@11752
|
792 |
if (requiresRestart) { |
|
eevyl@6470
|
793 |
alertMsg = [alertMsg stringByAppendingString:AILocalizedString(@" Please restart Adium.",nil)]; |
|
dchoby98@2987
|
794 |
} |
|
dchoby98@2987
|
795 |
|
|
dchoby98@2987
|
796 |
success = YES; |
|
Evan@11752
|
797 |
} else { |
|
eevyl@6470
|
798 |
alertTitle = AILocalizedString(@"Installation Failed","Title of installation failed window"); |
|
eevyl@6470
|
799 |
alertMsg = [NSString stringWithFormat:AILocalizedString(@"Installation of the %@ %@ was unsuccessful.", |
|
Evan@4867
|
800 |
"Installation failed sentence, like 'Installation of the message style Fiat was unsuccessful.'."), |
|
Evan@4867
|
801 |
fileDescription, |
|
Evan@4867
|
802 |
[[filename lastPathComponent] stringByDeletingPathExtension]]; |
|
dchoby98@2987
|
803 |
} |
|
dchoby98@2987
|
804 |
} |
|
Evan@4194
|
805 |
|
|
Evan@17646
|
806 |
[[self notificationCenter] postNotificationName:AIXtrasDidChangeNotification |
|
Evan@5186
|
807 |
object:[[filename lastPathComponent] pathExtension]]; |
|
Evan@4867
|
808 |
|
|
Evan@4867
|
809 |
buttonPressed = NSRunInformationalAlertPanel(alertTitle,alertMsg,nil,prefsButton,nil); |
|
dchoby98@4680
|
810 |
|
|
dchoby98@4680
|
811 |
// User clicked the "open prefs" button |
|
Evan@11752
|
812 |
if (buttonPressed == NSAlertAlternateReturn) { |
|
Evan@5780
|
813 |
//If we're done loading the app, open the prefs now; if not, it'll be done once the load is finished |
|
Evan@5780
|
814 |
//so the controllers and plugins have had a chance to initialize |
|
Evan@11752
|
815 |
if (completedApplicationLoad) { |
|
Evan@5163
|
816 |
[self openAppropriatePreferencesIfNeeded]; |
|
Evan@5780
|
817 |
} |
|
Evan@11752
|
818 |
} else { |
|
Evan@5780
|
819 |
//If the user didn't press the "open prefs" button, clear the pref opening information |
|
Evan@9306
|
820 |
[prefsCategory release]; prefsCategory = nil; |
|
Evan@5780
|
821 |
[advancedPrefsName release]; advancedPrefsName = nil; |
|
dchoby98@4680
|
822 |
} |
|
Evan@5780
|
823 |
|
|
Evan@11752
|
824 |
} else { |
|
Evan@11752
|
825 |
if (!errorMessage) { |
|
eevyl@6470
|
826 |
errorMessage = AILocalizedString(@"An error occurred while installing the X(tra).",nil); |
|
Evan@4867
|
827 |
} |
|
Evan@4867
|
828 |
|
|
eevyl@6470
|
829 |
NSRunAlertPanel(AILocalizedString(@"Installation Failed","Title of installation failed window"), |
|
Evan@4867
|
830 |
errorMessage, |
|
Evan@4867
|
831 |
nil,nil,nil); |
|
Evan@4867
|
832 |
} |
|
Evan@2022
|
833 |
|
|
Evan@2022
|
834 |
return success; |
|
Evan@1719
|
835 |
} |
|
Evan@1719
|
836 |
|
|
Evan@7571
|
837 |
- (BOOL)application:(NSApplication *)theApplication openTempFile:(NSString *)filename |
|
Evan@7571
|
838 |
{ |
|
Evan@7572
|
839 |
BOOL success; |
|
Evan@7572
|
840 |
|
|
Evan@7572
|
841 |
success = [self application:theApplication openFile:filename]; |
|
Evan@7572
|
842 |
[[NSFileManager defaultManager] removeFileAtPath:filename handler:nil]; |
|
Evan@7572
|
843 |
|
|
Catfish_Man@12140
|
844 |
return success; |
|
Evan@7571
|
845 |
} |
|
Evan@7571
|
846 |
|
|
Evan@5163
|
847 |
- (void)openAppropriatePreferencesIfNeeded |
|
Evan@5163
|
848 |
{ |
|
Evan@11752
|
849 |
if (prefsCategory) { |
|
Evan@11752
|
850 |
if ([prefsCategory isEqualToString:@"advanced"]) { |
|
Evan@9306
|
851 |
[preferenceController openPreferencesToAdvancedPane:advancedPrefsName]; |
|
Evan@11752
|
852 |
} else { |
|
Evan@9306
|
853 |
[preferenceController openPreferencesToCategoryWithIdentifier:prefsCategory]; |
|
Evan@5163
|
854 |
} |
|
Evan@5163
|
855 |
|
|
Evan@9306
|
856 |
[prefsCategory release]; prefsCategory = nil; |
|
Evan@5163
|
857 |
} |
|
Evan@5163
|
858 |
} |
|
Evan@5163
|
859 |
|
|
Evan@9366
|
860 |
/*! |
|
Evan@13647
|
861 |
* @brief Returns the location of Adium's preference folder |
|
Evan@13647
|
862 |
* |
|
Evan@13647
|
863 |
* This may be specified in our bundle's info dictionary keyed as PORTABLE_ADIUM_KEY |
|
Evan@13647
|
864 |
* or, by default, be within the system's 'application support' directory. |
|
Evan@13647
|
865 |
*/ |
|
Evan@13647
|
866 |
- (NSString *)applicationSupportDirectory |
|
Evan@13647
|
867 |
{ |
|
Evan@13647
|
868 |
//Path to the preferences folder |
|
Evan@13647
|
869 |
static NSString *_preferencesFolderPath = nil; |
|
Evan@13647
|
870 |
|
|
Evan@13647
|
871 |
//Determine the preferences path if neccessary |
|
Evan@13647
|
872 |
if (!_preferencesFolderPath) { |
|
Evan@13647
|
873 |
_preferencesFolderPath = [[[[[NSBundle mainBundle] infoDictionary] objectForKey:PORTABLE_ADIUM_KEY] stringByExpandingTildeInPath] retain]; |
|
Evan@13647
|
874 |
if (!_preferencesFolderPath) |
|
Evan@13647
|
875 |
_preferencesFolderPath = [[[[NSHomeDirectory() stringByAppendingPathComponent:@"Library"] stringByAppendingPathComponent:@"Application Support"] stringByAppendingPathComponent:@"Adium 2.0"] retain]; |
|
Evan@13647
|
876 |
} |
|
Evan@13647
|
877 |
|
|
Evan@13647
|
878 |
return _preferencesFolderPath; |
|
Evan@13647
|
879 |
} |
|
Evan@13647
|
880 |
|
|
Evan@13647
|
881 |
/*! |
|
Evan@9250
|
882 |
* @brief Create a resource folder in the Library/Application\ Support/Adium\ 2.0 folder. |
|
Evan@9250
|
883 |
* |
|
Evan@9250
|
884 |
* Pass it the name of the folder (e.g. @"Scripts"). |
|
Evan@9250
|
885 |
* If it is found to already in a library folder, return that pathname, using the same order of preference as |
|
Evan@9250
|
886 |
* -[AIAdium resourcePathsForName:]. Otherwise, create it in the user library and return the pathname to it. |
|
Evan@9250
|
887 |
*/ |
|
Peter@3954
|
888 |
- (NSString *)createResourcePathForName:(NSString *)name |
|
Peter@3954
|
889 |
{ |
|
Evan@7279
|
890 |
NSString *targetPath; //This is the subfolder for the user domain (i.e. ~/L/AS/Adium\ 2.0). |
|
Evan@7279
|
891 |
NSFileManager *defaultManager; |
|
Evan@7279
|
892 |
NSArray *existingResourcePaths; |
|
Peter@3954
|
893 |
|
|
Evan@7279
|
894 |
defaultManager = [NSFileManager defaultManager]; |
|
Evan@7279
|
895 |
existingResourcePaths = [self resourcePathsForName:name]; |
|
Evan@13647
|
896 |
targetPath = [[self applicationSupportDirectory] stringByAppendingPathComponent:name]; |
|
Evan@7279
|
897 |
|
|
Evan@7279
|
898 |
/* |
|
Evan@7279
|
899 |
If the targetPath doesn't exist, create it, as this method was called to ensure that it exists |
|
Evan@7279
|
900 |
for creating files in the user domain. |
|
Evan@7279
|
901 |
*/ |
|
Evan@11752
|
902 |
if ([existingResourcePaths indexOfObject:targetPath] == NSNotFound) { |
|
Evan@11752
|
903 |
if (![defaultManager createDirectoryAtPath:targetPath attributes:nil]) { |
|
Evan@7279
|
904 |
BOOL error; |
|
Evan@7279
|
905 |
|
|
Evan@7279
|
906 |
//If the directory could not be created, there may be a file in the way. Death to file. |
|
Evan@7279
|
907 |
error = ![defaultManager trashFileAtPath:targetPath]; |
|
Peter@3954
|
908 |
|
|
Evan@7279
|
909 |
if (!error) error = ![defaultManager createDirectoryAtPath:targetPath attributes:nil]; |
|
Evan@7279
|
910 |
|
|
Evan@11752
|
911 |
if (error) { |
|
Evan@7279
|
912 |
targetPath = nil; |
|
Evan@7279
|
913 |
|
|
Evan@7352
|
914 |
int result; |
|
Evan@7352
|
915 |
result = NSRunCriticalAlertPanel([NSString stringWithFormat:AILocalizedString(@"Could not create the %@ folder.",nil), name], |
|
Evan@7352
|
916 |
AILocalizedString(@"Try running Repair Permissions from Disk Utility.",nil), |
|
Evan@7352
|
917 |
AILocalizedString(@"OK",nil), |
|
Evan@7352
|
918 |
AILocalizedString(@"Launch Disk Utility",nil), |
|
Evan@7352
|
919 |
nil); |
|
Evan@11752
|
920 |
if (result == NSAlertAlternateReturn) { |
|
Evan@7352
|
921 |
[[NSWorkspace sharedWorkspace] launchApplication:@"Disk Utility"]; |
|
Evan@7352
|
922 |
} |
|
Evan@7279
|
923 |
} |
|
Peter@4107
|
924 |
} |
|
Peter@3954
|
925 |
} else { |
|
Evan@7279
|
926 |
targetPath = [existingResourcePaths objectAtIndex:0]; |
|
Peter@3954
|
927 |
} |
|
Peter@3954
|
928 |
|
|
Peter@3954
|
929 |
return targetPath; |
|
Peter@3954
|
930 |
} |
|
Peter@3954
|
931 |
|
|
Evan@9366
|
932 |
/*! |
|
Evan@9250
|
933 |
* @brief Return zero or more resource pathnames to an filename |
|
Evan@9250
|
934 |
* |
|
Evan@9250
|
935 |
* Searches in the Application Support folders and the Resources/ folder of the Adium.app bundle. |
|
Evan@9250
|
936 |
* Only those pathnames that exist are returned. The Adium bundle's resource path will be the last item in the array, |
|
Evan@9250
|
937 |
* so precedence is given to the user and system Application Support folders. |
|
Evan@9250
|
938 |
* |
|
Evan@9250
|
939 |
* Pass nil to receive an array of paths to existing Adium Application Support folders (plus the Resouces folder). |
|
Evan@9250
|
940 |
* |
|
Evan@9250
|
941 |
* Example: If you call[adium resourcePathsForName:@"Scripts"], and there's a |
|
Evan@9250
|
942 |
* Scripts folder in ~/Library/Application Support/Adium\ 2.0 and in /Library/Application Support/Adium\ 2.0, but not |
|
Evan@9250
|
943 |
* in /System/Library/ApplicationSupport/Adium\ 2.0 or /Network/Library/Application Support/Adium\ 2.0. |
|
Evan@9250
|
944 |
* The array you get back will be { @"/Users/username/Library/Application Support/Adium 2.0/Scripts", |
|
Evan@9250
|
945 |
* @"/Library/Application Support/Adium 2.0/Scripts" }. |
|
Evan@9250
|
946 |
* |
|
Evan@9250
|
947 |
* @param name The full name (including extension as appropriate) of the resource for which to search |
|
Evan@9250
|
948 |
*/ |
|
hanji@3518
|
949 |
- (NSArray *)resourcePathsForName:(NSString *)name |
|
Peter@3104
|
950 |
{ |
|
Evan@5128
|
951 |
NSArray *librarySearchPaths; |
|
Evan@5128
|
952 |
NSEnumerator *searchPathEnumerator; |
|
Evan@5128
|
953 |
NSString *adiumFolderName, *path; |
|
Evan@5128
|
954 |
NSMutableArray *pathArray = [NSMutableArray arrayWithCapacity:4]; |
|
Evan@7279
|
955 |
NSFileManager *defaultManager = [NSFileManager defaultManager]; |
|
Evan@7279
|
956 |
BOOL isDir; |
|
Evan@7279
|
957 |
|
|
Evan@13644
|
958 |
adiumFolderName = (name ? |
|
Evan@13644
|
959 |
[[@"Application Support" stringByAppendingPathComponent:@"Adium 2.0"] stringByAppendingPathComponent:name] : |
|
Evan@13644
|
960 |
[@"Application Support" stringByAppendingPathComponent:@"Adium 2.0"]); |
|
Evan@5128
|
961 |
|
|
Evan@5128
|
962 |
//Find Library directories in all domains except /System (as of Panther, that's ~/Library, /Library, and /Network/Library) |
|
Evan@5128
|
963 |
librarySearchPaths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSAllDomainsMask - NSSystemDomainMask, YES); |
|
Evan@5128
|
964 |
searchPathEnumerator = [librarySearchPaths objectEnumerator]; |
|
Evan@5128
|
965 |
|
|
Evan@5128
|
966 |
//Copy each discovered path into the pathArray after adding our subfolder path |
|
Evan@11752
|
967 |
while ((path = [searchPathEnumerator nextObject])) { |
|
Evan@7279
|
968 |
NSString *fullPath; |
|
Evan@7279
|
969 |
|
|
Evan@7279
|
970 |
fullPath = [path stringByAppendingPathComponent:adiumFolderName]; |
|
Evan@11752
|
971 |
if (([defaultManager fileExistsAtPath:fullPath isDirectory:&isDir]) && |
|
Evan@13644
|
972 |
(isDir)) { |
|
Evan@7279
|
973 |
|
|
adamiser@5942
|
974 |
[pathArray addObject:fullPath]; |
|
adamiser@5942
|
975 |
} |
|
Peter@3104
|
976 |
} |
|
hanji@3518
|
977 |
|
|
Evan@13644
|
978 |
/* Check our application support directory directly. It may have been covered by the NSSearchPathForDirectoriesInDomains() search, |
|
Evan@13644
|
979 |
* or it may be distinct via the Portable Adium preference. |
|
Evan@13644
|
980 |
*/ |
|
Evan@13644
|
981 |
path = (name ? |
|
Evan@13647
|
982 |
[[self applicationSupportDirectory] stringByAppendingPathComponent:name] : |
|
Evan@13647
|
983 |
[self applicationSupportDirectory]); |
|
Evan@13656
|
984 |
if (![pathArray containsObject:path] && |
|
Evan@13644
|
985 |
([defaultManager fileExistsAtPath:path isDirectory:&isDir]) && |
|
Evan@13644
|
986 |
(isDir)) { |
|
Evan@13647
|
987 |
//Our application support directory should always be first |
|
Evan@13646
|
988 |
if ([pathArray count]) { |
|
Evan@13646
|
989 |
[pathArray insertObject:path atIndex:0]; |
|
Evan@13646
|
990 |
} else { |
|
Evan@13646
|
991 |
[pathArray addObject:path]; |
|
Evan@13646
|
992 |
} |
|
Evan@13644
|
993 |
} |
|
Evan@13644
|
994 |
|
|
Evan@5128
|
995 |
//Add the path to the resource in Adium's bundle |
|
Evan@11752
|
996 |
if (name) { |
|
Peter@3871
|
997 |
path = [[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:name] stringByExpandingTildeInPath]; |
|
Evan@11752
|
998 |
if (([defaultManager fileExistsAtPath:path isDirectory:&isDir]) && |
|
Evan@11752
|
999 |
(isDir)) { |
|
Peter@3871
|
1000 |
[pathArray addObject:path]; |
|
Peter@3871
|
1001 |
} |
|
Peter@3871
|
1002 |
} |
|
Peter@3871
|
1003 |
|
|
Catfish_Man@12140
|
1004 |
return pathArray; |
|
Peter@3104
|
1005 |
} |
|
Peter@4653
|
1006 |
|
|
samsamoa@10651
|
1007 |
|
|
samsamoa@10651
|
1008 |
/*! |
|
samsamoa@10651
|
1009 |
* @brief Returns an array of the paths to all of the resources for a given name, filtering out those without a certain extension |
|
samsamoa@10651
|
1010 |
* @param name The full name (including extension as appropriate) of the resource for which to search |
|
samsamoa@10651
|
1011 |
* @param extensions The extension(s) of the resources for which to search, either an NSString or an NSArray |
|
samsamoa@10651
|
1012 |
*/ |
|
samsamoa@10651
|
1013 |
- (NSArray *)allResourcesForName:(NSString *)name withExtensions:(id)extensions { |
|
Peter@10864
|
1014 |
NSMutableArray *resources = [NSMutableArray array]; |
|
samsamoa@10651
|
1015 |
NSEnumerator *pathEnumerator; |
|
samsamoa@10651
|
1016 |
NSEnumerator *resourceEnumerator; |
|
samsamoa@10651
|
1017 |
NSString *resourceDir; |
|
samsamoa@10651
|
1018 |
NSString *resourcePath; |
|
samsamoa@10651
|
1019 |
BOOL extensionsArray = [extensions isKindOfClass:[NSArray class]]; |
|
samsamoa@10651
|
1020 |
NSEnumerator *extensionsEnumerator; |
|
samsamoa@10651
|
1021 |
NSString *extension; |
|
samsamoa@10651
|
1022 |
|
|
samsamoa@10651
|
1023 |
// Get every path that can contain these resources |
|
samsamoa@10651
|
1024 |
pathEnumerator = [[self resourcePathsForName:name] objectEnumerator]; |
|
samsamoa@10651
|
1025 |
|
|
samsamoa@11441
|
1026 |
while ((resourceDir = [pathEnumerator nextObject])) { |
|
samsamoa@10651
|
1027 |
resourceEnumerator = [[[NSFileManager defaultManager] directoryContentsAtPath:resourceDir] objectEnumerator]; |
|
samsamoa@10651
|
1028 |
|
|
samsamoa@11441
|
1029 |
while ((resourcePath = [resourceEnumerator nextObject])) { |
|
samsamoa@10651
|
1030 |
// Add each resource to the array |
|
samsamoa@10651
|
1031 |
if (extensionsArray) { |
|
samsamoa@10651
|
1032 |
extensionsEnumerator = [extensions objectEnumerator]; |
|
samsamoa@11441
|
1033 |
while ((extension = [extensionsEnumerator nextObject])) { |
|
samsamoa@10651
|
1034 |
if ([[resourcePath pathExtension] caseInsensitiveCompare:extension] == NSOrderedSame) |
|
samsamoa@10651
|
1035 |
[resources addObject:[resourceDir stringByAppendingPathComponent:resourcePath]]; |
|
samsamoa@10651
|
1036 |
} |
|
samsamoa@10651
|
1037 |
} |
|
samsamoa@10651
|
1038 |
else { |
|
samsamoa@10651
|
1039 |
if ([[resourcePath pathExtension] caseInsensitiveCompare:extensions] == NSOrderedSame) |
|
samsamoa@10651
|
1040 |
[resources addObject:[resourceDir stringByAppendingPathComponent:resourcePath]]; |
|
samsamoa@10651
|
1041 |
} |
|
samsamoa@10651
|
1042 |
} |
|
samsamoa@10651
|
1043 |
} |
|
samsamoa@10651
|
1044 |
|
|
samsamoa@10651
|
1045 |
return resources; |
|
samsamoa@10651
|
1046 |
} |
|
samsamoa@10651
|
1047 |
|
|
Evan@9366
|
1048 |
/*! |
|
Evan@9250
|
1049 |
* @brief Return the path to be used for caching files for this user. |
|
Evan@9250
|
1050 |
* |
|
Evan@9250
|
1051 |
* @result A cached, tilde-expanded full path. |
|
Evan@9250
|
1052 |
*/ |
|
Evan@8541
|
1053 |
- (NSString *)cachesPath |
|
Evan@8541
|
1054 |
{ |
|
Evan@8541
|
1055 |
static NSString *cachesPath = nil; |
|
Evan@8557
|
1056 |
|
|
Evan@11752
|
1057 |
if (!cachesPath) { |
|
Evan@8557
|
1058 |
NSString *generalAdiumCachesPath; |
|
Evan@8557
|
1059 |
NSFileManager *defaultManager = [NSFileManager defaultManager]; |
|
Evan@8557
|
1060 |
|
|
Peter@11624
|
1061 |
generalAdiumCachesPath = [[[NSHomeDirectory() stringByAppendingPathComponent:@"Library"] stringByAppendingPathComponent:@"Caches"] stringByAppendingPathComponent:@"Adium"]; |
|
Evan@8557
|
1062 |
cachesPath = [[generalAdiumCachesPath stringByAppendingPathComponent:[[self loginController] currentUser]] retain]; |
|
Evan@8541
|
1063 |
|
|
Evan@8541
|
1064 |
//Ensure our cache path exists |
|
Evan@11752
|
1065 |
if ([defaultManager createDirectoriesForPath:cachesPath]) { |
|
Evan@8557
|
1066 |
//If we have to make directories, try to move old cache files into the new directory |
|
Evan@8557
|
1067 |
NSEnumerator *enumerator; |
|
Evan@8557
|
1068 |
NSString *filename; |
|
Evan@8557
|
1069 |
BOOL isDir; |
|
Evan@8557
|
1070 |
|
|
Evan@8557
|
1071 |
enumerator = [[defaultManager directoryContentsAtPath:generalAdiumCachesPath] objectEnumerator]; |
|
Evan@11752
|
1072 |
while ((filename = [enumerator nextObject])) { |
|
Evan@8557
|
1073 |
NSString *fullPath = [generalAdiumCachesPath stringByAppendingPathComponent:filename]; |
|
Evan@8557
|
1074 |
|
|
Evan@11752
|
1075 |
if (([defaultManager fileExistsAtPath:fullPath isDirectory:&isDir]) && |
|
Evan@11752
|
1076 |
(!isDir)) { |
|
Evan@8557
|
1077 |
[defaultManager movePath:fullPath |
|
Evan@8557
|
1078 |
toPath:[cachesPath stringByAppendingPathComponent:filename] |
|
Evan@8557
|
1079 |
handler:nil]; |
|
Evan@8557
|
1080 |
} |
|
Evan@8557
|
1081 |
} |
|
Evan@8557
|
1082 |
} |
|
Evan@8541
|
1083 |
} |
|
Evan@8557
|
1084 |
|
|
Evan@8541
|
1085 |
return cachesPath; |
|
Evan@8541
|
1086 |
} |
|
Evan@8541
|
1087 |
|
|
Peter@8206
|
1088 |
- (NSString *)pathOfPackWithName:(NSString *)name extension:(NSString *)extension resourceFolderName:(NSString *)folderName |
|
Evan@8200
|
1089 |
{ |
|
Evan@8200
|
1090 |
NSFileManager *fileManager = [NSFileManager defaultManager]; |
|
Evan@8200
|
1091 |
NSString *packFileName = [name stringByAppendingPathExtension:extension]; |
|
Evan@8200
|
1092 |
NSEnumerator *enumerator = [[self resourcePathsForName:folderName] objectEnumerator]; |
|
Evan@8200
|
1093 |
NSString *resourcePath; |
|
Evan@8200
|
1094 |
|
|
Evan@8200
|
1095 |
//Search all our resource paths for the requested pack |
|
Evan@11752
|
1096 |
while ((resourcePath = [enumerator nextObject])) { |
|
Evan@8200
|
1097 |
NSString *packPath = [resourcePath stringByAppendingPathComponent:packFileName]; |
|
Catfish_Man@12140
|
1098 |
if ([fileManager fileExistsAtPath:packPath]) return [packPath stringByExpandingTildeInPath]; |
|
Evan@8200
|
1099 |
} |
|
Evan@8200
|
1100 |
|
|
Catfish_Man@12140
|
1101 |
return nil; |
|
Evan@8200
|
1102 |
} |
|
Evan@8200
|
1103 |
|
|
Evan@18014
|
1104 |
- (void)systemTimeZoneDidChange:(NSNotification *)inNotification |
|
Evan@18014
|
1105 |
{ |
|
Evan@18014
|
1106 |
[NSTimeZone resetSystemTimeZone]; |
|
Evan@18014
|
1107 |
} |
|
Evan@18014
|
1108 |
|
|
Evan@18014
|
1109 |
- (NSApplication *)application |
|
Evan@18014
|
1110 |
{ |
|
Evan@18014
|
1111 |
return [NSApplication sharedApplication]; |
|
Evan@18014
|
1112 |
} |
|
Evan@18014
|
1113 |
|
|
Evan@5707
|
1114 |
#pragma mark Scripting |
|
Evan@5707
|
1115 |
- (BOOL)application:(NSApplication *)sender delegateHandlesKey:(NSString *)key { |
|
Evan@5707
|
1116 |
BOOL handleKey = NO; |
|
Evan@5780
|
1117 |
|
|
Evan@11752
|
1118 |
if ([key isEqualToString:@"applescriptabilityController"] || |
|
Evan@11752
|
1119 |
[key isEqualToString:@"interfaceController"] ) { |
|
Evan@5707
|
1120 |
handleKey = YES; |
|
Evan@5707
|
1121 |
|
|
Evan@5707
|
1122 |
} |
|
Evan@5707
|
1123 |
|
|
Evan@5707
|
1124 |
return handleKey; |
|
Evan@5707
|
1125 |
} |
|
Evan@5707
|
1126 |
|
|
Evan@17170
|
1127 |
#pragma mark Help |
|
Evan@17170
|
1128 |
- (void)configureHelp |
|
Evan@17170
|
1129 |
{ |
|
Evan@17170
|
1130 |
CFBundleRef myApplicationBundle; |
|
Evan@17170
|
1131 |
CFURLRef myBundleURL; |
|
Evan@17170
|
1132 |
FSRef myBundleRef; |
|
Evan@17170
|
1133 |
|
|
Evan@17170
|
1134 |
if ((myApplicationBundle = CFBundleGetMainBundle())) { |
|
Evan@17170
|
1135 |
myBundleURL = CFBundleCopyBundleURL(myApplicationBundle); |
|
Evan@17170
|
1136 |
|
|
Evan@17170
|
1137 |
if (CFURLGetFSRef(myBundleURL, &myBundleRef)) { |
|
Evan@17170
|
1138 |
AHRegisterHelpBook(&myBundleRef); |
|
Evan@17170
|
1139 |
} |
|
Evan@17170
|
1140 |
} |
|
Evan@17170
|
1141 |
} |
|
Evan@17170
|
1142 |
|
|
David@14622
|
1143 |
#pragma mark Sparkle Delegate Methods |
|
David@14622
|
1144 |
|
|
David@17973
|
1145 |
#define BETA_UPDATE_DICT [NSDictionary dictionaryWithObjectsAndKeys:@"type", @"key", @"Update Type", @"visibleKey", @"beta", @"value", @"Beta or Release Versions", @"visibleValue", nil] |
|
David@17973
|
1146 |
#define RELEASE_UPDATE_DICT [NSDictionary dictionaryWithObjectsAndKeys:@"type", @"key", @"Update Type", @"visibleKey", @"release", @"value", @"Release Versions Only", @"visibleValue", nil] |
|
David@17973
|
1147 |
|
|
Evan@18281
|
1148 |
#ifdef BETA_RELEASE |
|
Evan@18232
|
1149 |
//For a beta release, always use the beta appcast |
|
Evan@18232
|
1150 |
#define UPDATE_TYPE_DICT BETA_UPDATE_DICT |
|
David@17308
|
1151 |
#else |
|
Evan@18232
|
1152 |
//For a release, use the beta appcast if AIAlwaysUpdateToBetas is enabled; otherwise, use the release appcast |
|
Evan@18232
|
1153 |
#define UPDATE_TYPE_DICT ([[NSUserDefaults standardUserDefaults] boolForKey:@"AIAlwaysUpdateToBetas"] ? BETA_UPDATE_DICT : RELEASE_UPDATE_DICT) |
|
David@17308
|
1154 |
#endif |
|
David@17308
|
1155 |
|
|
Peter@18554
|
1156 |
//The first generation ended with 1.0.5 and 1.1. Our Sparkle Plus up to that point had a bug that left it unable to properly handle the sparkle:minimumSystemVersion element. |
|
Peter@18554
|
1157 |
//The second generation began with 1.0.6 and 1.1.1, with a Sparkle Plus that can handle that element. |
|
Peter@18554
|
1158 |
#define UPDATE_GENERATION_DICT [NSDictionary dictionaryWithObjectsAndKeys:@"generation", @"key", @"Appcast generation number", @"visibleKey", @"2", @"value", @"2", @"visibleValue", nil] |
|
Peter@18554
|
1159 |
|
|
David@14698
|
1160 |
/* This method gives the delegate the opportunity to customize the information that will |
|
David@14698
|
1161 |
* be included with update checks. Add or remove items from the dictionary as desired. |
|
David@14698
|
1162 |
* Each entry in profileInfo is an NSDictionary with the following keys: |
|
Evan@16215
|
1163 |
* key: The key to be used when reporting data to the server |
|
Evan@16215
|
1164 |
* visibleKey: Alternate version of key to be used in UI displays of profile information |
|
Evan@16215
|
1165 |
* value: Value to be used when reporting data to the server |
|
Evan@16215
|
1166 |
* visibleValue: Alternate version of value to be used in UI displays of profile information. |
|
David@14698
|
1167 |
*/ |
|
David@15946
|
1168 |
- (NSMutableArray *)updaterCustomizeProfileInfo:(NSMutableArray *)profileInfo |
|
David@16296
|
1169 |
{ |
|
David@16296
|
1170 |
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; |
|
Evan@18232
|
1171 |
|
|
Evan@18232
|
1172 |
//If we're not sending profile information, return just the type of update we're looking for |
|
Peter@18554
|
1173 |
if ([[defaults objectForKey:SUSendProfileInfoKey] boolValue]) { |
|
Peter@18554
|
1174 |
int now = [[NSCalendarDate date] dayOfCommonEra]; |
|
Peter@18554
|
1175 |
|
|
Peter@18554
|
1176 |
if (abs([defaults integerForKey:@"AILastSubmittedProfileDate2"] - now) >= 7) { |
|
Peter@18554
|
1177 |
[defaults setInteger:now forKey:@"AILastSubmittedProfileDate2"]; |
|
Peter@18554
|
1178 |
|
|
Peter@18554
|
1179 |
NSString *value = ([defaults boolForKey:@"AIHasSentSparkleProfileInfo"]) ? @"no" : @"yes"; |
|
Peter@18554
|
1180 |
|
|
Peter@18554
|
1181 |
NSDictionary *entry = [NSDictionary dictionaryWithObjectsAndKeys: |
|
Peter@18554
|
1182 |
@"FirstSubmission", @"key", |
|
Peter@18554
|
1183 |
@"First Time Submitting Profile Information", @"visibleKey", |
|
Peter@18554
|
1184 |
value, @"value", |
|
Peter@18554
|
1185 |
value, @"visibleValue", |
|
Peter@18554
|
1186 |
nil]; |
|
Peter@18554
|
1187 |
|
|
Peter@18554
|
1188 |
[profileInfo addObject:entry]; |
|
Peter@18554
|
1189 |
|
|
Peter@18554
|
1190 |
[defaults setBool:YES forKey:@"AIHasSentSparkleProfileInfo"]; |
|
Peter@18554
|
1191 |
|
|
Peter@18554
|
1192 |
/*************** Include info about what IM services are used ************/ |
|
Peter@18554
|
1193 |
NSMutableString *accountInfo = [NSMutableString string]; |
|
Peter@18554
|
1194 |
NSCountedSet *condensedAccountInfo = [NSCountedSet set]; |
|
Peter@18554
|
1195 |
NSEnumerator *accountEnu = [[[self accountController] accounts] objectEnumerator]; |
|
Peter@18554
|
1196 |
AIAccount *account = nil; |
|
Peter@18554
|
1197 |
while ((account = [accountEnu nextObject])) { |
|
Peter@18554
|
1198 |
NSString *serviceID = [account serviceID]; |
|
Peter@18554
|
1199 |
[accountInfo appendFormat:@"%@, ", serviceID]; |
|
Peter@18554
|
1200 |
if([serviceID isEqualToString:@"Yahoo! Japan"]) serviceID = @"YJ"; |
|
Peter@18554
|
1201 |
[condensedAccountInfo addObject:[NSString stringWithFormat:@"%@", [serviceID substringToIndex:2]]]; |
|
Peter@18554
|
1202 |
} |
|
Peter@18554
|
1203 |
|
|
Peter@18554
|
1204 |
NSMutableString *accountInfoString = [NSMutableString string]; |
|
Peter@18554
|
1205 |
NSEnumerator *infoEnu = [[[condensedAccountInfo allObjects] sortedArrayUsingSelector:@selector(compare:)] objectEnumerator]; |
|
Peter@18554
|
1206 |
while ((value = [infoEnu nextObject])) |
|
Peter@18554
|
1207 |
[accountInfoString appendFormat:@"%@%d", value, [condensedAccountInfo countForObject:value]]; |
|
Peter@18554
|
1208 |
|
|
Peter@18554
|
1209 |
entry = [NSDictionary dictionaryWithObjectsAndKeys: |
|
Peter@18554
|
1210 |
@"IMServices", @"key", |
|
Peter@18554
|
1211 |
@"IM Services Used", @"visibleKey", |
|
Peter@18554
|
1212 |
accountInfoString, @"value", |
|
Peter@18554
|
1213 |
accountInfo, @"visibleValue", |
|
Peter@18554
|
1214 |
nil]; |
|
Peter@18554
|
1215 |
[profileInfo addObject:entry]; |
|
Peter@18554
|
1216 |
} |
|
Peter@18554
|
1217 |
} |
|
Peter@18554
|
1218 |
|
|
Peter@18554
|
1219 |
[profileInfo addObject:UPDATE_GENERATION_DICT]; |
|
Peter@18554
|
1220 |
[profileInfo addObject:UPDATE_TYPE_DICT]; |
|
Peter@18554
|
1221 |
return profileInfo; |
|
David@14622
|
1222 |
} |
|
David@14622
|
1223 |
|
|
David@16630
|
1224 |
- (NSComparisonResult) compareVersion:(NSString *)newVersion toVersion:(NSString *)currentVersion |
|
David@16630
|
1225 |
{ |
|
David@16630
|
1226 |
//Allow updating from betas to anything, and anything to non-betas |
|
David@16630
|
1227 |
//Careful! a15 is fine, but A15 is not, because it would hit the A in Adium. |
|
David@16630
|
1228 |
NSCharacterSet *guardCharacters = [NSCharacterSet characterSetWithCharactersInString:@"abBrcRC"]; |
|
David@16630
|
1229 |
if([currentVersion rangeOfCharacterFromSet:guardCharacters].location != NSNotFound || !([newVersion rangeOfCharacterFromSet:guardCharacters].location != NSNotFound)) |
|
David@17097
|
1230 |
return AICustomVersionComparison(newVersion, currentVersion); //handles rc > b > a properly |
|
David@16630
|
1231 |
else |
|
David@16630
|
1232 |
return NSOrderedSame; |
|
David@16630
|
1233 |
} |
|
David@16630
|
1234 |
|
|
adamiser@3
|
1235 |
@end |