File sharing made easy.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1242 lines
52 KiB

13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
  1. //
  2. // MGMController.m
  3. // CocoaShare
  4. //
  5. // Created by Mr. Gecko on 1/15/11.
  6. // Copyright (c) 2015 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
  7. //
  8. #import "MGMController.h"
  9. #import "MGMPathSubscriber.h"
  10. #import "MGMLoginItems.h"
  11. #import "MGMAddons.h"
  12. #import "MGMMenuItem.h"
  13. #import "RegexKitLite.h"
  14. #import <MGMUsers/MGMUsers.h>
  15. #import <GeckoReporter/GeckoReporter.h>
  16. #import <Growl/GrowlApplicationBridge.h>
  17. #import <Carbon/Carbon.h>
  18. NSString * const MGMCopyright = @"Copyright (c) 2015 Mr. Gecko's Media (James Coleman). http://mrgeckosmedia.com/ All rights reserved.";
  19. NSString * const MGMVersion = @"MGMVersion";
  20. NSString * const MGMLaunchCount = @"MGMLaunchCount";
  21. NSString * const MGMDisplay = @"MGMDisplay";
  22. NSString * const MGMStartup = @"MGMStartup";
  23. NSString * const MGMUploadName = @"MGMUploadName";
  24. NSString * const MGMHistoryCount = @"MGMHistoryCount";
  25. NSString * const MGMGrowlErrors = @"MGMGrowlErrors";
  26. NSString * const MGMUploadLimit = @"MGMUploadLimit";
  27. NSString * const MGMHistoryPlist = @"history.plist";
  28. NSString * const MGMHURL = @"url";
  29. NSString * const MGMHInfo = @"info";
  30. NSString * const MGMHDate = @"date";
  31. NSString * const MGMESound = @"MGME%dSound";
  32. NSString * const MGMEPath = @"MGME%dPath";
  33. NSString * const MGMEDelete = @"MGME%dDelete";
  34. NSString * const MGMEGrowl = @"MGME%dGrowl";
  35. const int MGMEUploadingAutomatic = 0;
  36. const int MGMEUploadedAutomatic = 1;
  37. const int MGMEUploading = 2;
  38. const int MGMEUploaded = 3;
  39. NSString * const MGMEventNotification = @"MGMEventNotification";
  40. NSString * const MGMEvent = @"event";
  41. NSString * const MGMEventPath = @"path";
  42. NSString * const MGMEventURL = @"URL";
  43. NSString * const MGMFiltersPlist = @"filters.plist";
  44. NSString * const MGMFID = @"id";
  45. NSString * const MGMFPath = @"path";
  46. NSString * const MGMFFilter = @"filter";
  47. NSString * const MGMResizePlist = @"resize.plist";
  48. NSString * const MGMRID = @"id";
  49. NSString * const MGMRWidth = @"width";
  50. NSString * const MGMRHeight = @"height";
  51. NSString * const MGMRScale = @"scale";
  52. NSString * const MGMRFilters = @"filters";
  53. NSString * const MGMRNetworks = @"networks";
  54. NSString * const MGMRIPPrefix = @"IPPrefix";
  55. NSString * const MGMPluginFolder = @"PlugIns";
  56. NSString * const MGMCurrentPlugIn = @"MGMCurrentPlugIn";
  57. NSString * const MGMMUThemesFolder = @"Multi Upload Themes";
  58. NSString * const MGMCurrentMUTheme = @"MGMCurrentMUTheme";
  59. NSString * const MGMKCType = @"application password";
  60. NSString * const MGMKCName = @"CocoaShare";
  61. NSString * const MGMUPath = @"path";
  62. NSString * const MGMUAutomatic = @"automatic";
  63. NSString * const MGMUMultiUpload = @"multiUpload";
  64. NSString * const MGMNSStringPboardType = @"NSStringPboardType";
  65. NSString * const MGMNSPasteboardTypeString = @"public.utf8-plain-text";
  66. OSStatus frontAppChanged(EventHandlerCallRef nextHandler, EventRef theEvent, void *userData) {
  67. ProcessSerialNumber thisProcess;
  68. GetCurrentProcess(&thisProcess);
  69. ProcessSerialNumber newProcess;
  70. GetFrontProcess(&newProcess);
  71. Boolean same;
  72. SameProcess(&newProcess, &thisProcess, &same);
  73. if (!same)
  74. [(MGMController *)userData setFrontProcess:&newProcess];
  75. return (CallNextEventHandler(nextHandler, theEvent));
  76. }
  77. static MGMController *MGMSharedController;
  78. NSString * const MGMPrimaryInterface = @"PrimaryInterface";
  79. NSString * const MGMAddresses = @"Addresses";
  80. NSString * const MGMIPv4Info = @"State:/Network/Interface/%@/IPv4";
  81. NSString * const MGMIPv6Info = @"State:/Network/Interface/%@/IPv6";
  82. NSString * const MGMIPv4State = @"State:/Network/Global/IPv4";
  83. NSString * const MGMIPv6State = @"State:/Network/Global/IPv6";
  84. NSString * const MGMAirPortInfo = @"State:/Network/Interface/%@/AirPort";
  85. static void systemNotification(SCDynamicStoreRef store, NSArray *changedKeys, void *info) {
  86. for (int i=0; i<[changedKeys count]; ++i) {
  87. NSString *key = [changedKeys objectAtIndex:i];
  88. if ([key isEqual:MGMIPv4State]) {
  89. NSDictionary *value = (NSDictionary *)SCDynamicStoreCopyValue(store, (CFStringRef)key);
  90. [(MGMController *)info ipv4Changed:value];
  91. [value release];
  92. } else if ([key isEqual:MGMIPv6State]) {
  93. NSDictionary *value = (NSDictionary *)SCDynamicStoreCopyValue(store, (CFStringRef)key);
  94. [(MGMController *)info ipv6Changed:value];
  95. [value release];
  96. } else if ([key hasSuffix:@"AirPort"]) {
  97. NSDictionary *value = (NSDictionary *)SCDynamicStoreCopyValue(store, (CFStringRef)key);
  98. [(MGMController *)info airportChanged:value];
  99. [value release];
  100. }
  101. }
  102. }
  103. @implementation MGMController
  104. + (id)sharedController {
  105. if (MGMSharedController==nil) {
  106. MGMSharedController = [MGMController new];
  107. }
  108. return MGMSharedController;
  109. }
  110. - (id)init {
  111. if (MGMSharedController!=nil) {
  112. if ((self = [super init]))
  113. [self release];
  114. self = MGMSharedController;
  115. } else if ((self = [super init])) {
  116. MGMSharedController = self;
  117. }
  118. return self;
  119. }
  120. - (void)awakeFromNib {
  121. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(setup) name:MGMGRDoneNotification object:nil];
  122. [MGMReporter sharedReporter];
  123. }
  124. - (void)setup {
  125. autoreleaseDrain = [[NSTimer scheduledTimerWithTimeInterval:30.0 target:self selector:@selector(drainAutoreleasePool) userInfo:nil repeats:YES] retain];
  126. [GrowlApplicationBridge setGrowlDelegate:nil];
  127. NSString *AirPortBSDName = nil;
  128. CFArrayRef interfaces = SCNetworkInterfaceCopyAll();
  129. for (int i=0; i<CFArrayGetCount(interfaces); i++) {
  130. SCNetworkInterfaceRef interface = CFArrayGetValueAtIndex(interfaces, i);
  131. if ([(NSString *)SCNetworkInterfaceGetInterfaceType(interface) isEqual:@"IEEE80211"]) {
  132. AirPortBSDName = (NSString *)SCNetworkInterfaceGetBSDName(interface);
  133. }
  134. }
  135. CFRelease(interfaces);
  136. SCDynamicStoreContext context = {0, self, NULL, NULL, NULL};
  137. store = SCDynamicStoreCreate(kCFAllocatorDefault, CFBundleGetIdentifier(CFBundleGetMainBundle()), (SCDynamicStoreCallBack)systemNotification, &context);
  138. if (!store) {
  139. NSLog(@"Unable to create store for system configuration %s", SCErrorString(SCError()));
  140. } else {
  141. NSMutableArray *keys = [NSMutableArray arrayWithObjects:MGMIPv4State, MGMIPv6State, nil];
  142. if (AirPortBSDName!=nil) {
  143. [keys addObject:[NSString stringWithFormat:MGMAirPortInfo, AirPortBSDName]];
  144. }
  145. if (!SCDynamicStoreSetNotificationKeys(store, (CFArrayRef)keys, NULL)) {
  146. NSLog(@"faild to set the store for notifications %s", SCErrorString(SCError()));
  147. CFRelease(store);
  148. store = NULL;
  149. } else {
  150. runLoop = SCDynamicStoreCreateRunLoopSource(kCFAllocatorDefault, store, 0);
  151. CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoop, kCFRunLoopDefaultMode);
  152. NSDictionary *IPv4State = (NSDictionary *)SCDynamicStoreCopyValue(store, (CFStringRef)MGMIPv4State);
  153. NSDictionary *IPv4Info = (NSDictionary *)SCDynamicStoreCopyValue(store, (CFStringRef)[NSString stringWithFormat:MGMIPv4Info, [IPv4State objectForKey:MGMPrimaryInterface]]);
  154. IPv4Addresses = [[IPv4Info objectForKey:MGMAddresses] retain];
  155. [IPv4Info release];
  156. [IPv4State release];
  157. NSDictionary *IPv6State = (NSDictionary *)SCDynamicStoreCopyValue(store, (CFStringRef)MGMIPv6State);
  158. NSDictionary *IPv6Info = (NSDictionary *)SCDynamicStoreCopyValue(store, (CFStringRef)[NSString stringWithFormat:MGMIPv6Info, [IPv6State objectForKey:MGMPrimaryInterface]]);
  159. IPv6Addresses = [[IPv6Info objectForKey:MGMAddresses] retain];
  160. [IPv6Info release];
  161. [IPv6State release];
  162. if (AirPortBSDName!=nil) {
  163. lastAirPortState = (NSDictionary *)SCDynamicStoreCopyValue(store, (CFStringRef)[NSString stringWithFormat:MGMAirPortInfo, AirPortBSDName]);
  164. }
  165. }
  166. }
  167. connectionManager = [[MGMURLConnectionManager managerWithCookieStorage:[MGMUser cookieStorage]] retain];
  168. NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
  169. [self registerDefaults];
  170. if ([defaults integerForKey:MGMLaunchCount]!=5) {
  171. [defaults setInteger:[defaults integerForKey:MGMLaunchCount]+1 forKey:MGMLaunchCount];
  172. if ([defaults integerForKey:MGMLaunchCount]==5) {
  173. NSAlert *alert = [[NSAlert new] autorelease];
  174. [alert setMessageText:[@"Donations" localized]];
  175. [alert setInformativeText:[@"Thank you for using CocoaShare. CocoaShare is donation supported software. If you like using it, please consider giving a donation to help with development." localized]];
  176. [alert addButtonWithTitle:[@"Yes" localized]];
  177. [alert addButtonWithTitle:[@"No" localized]];
  178. int result = [alert runModal];
  179. if (result==1000)
  180. [self donate:self];
  181. }
  182. }
  183. if ([defaults boolForKey:MGMStartup])
  184. [[MGMLoginItems items] addThisApplication];
  185. NSFileManager *manager = [NSFileManager defaultManager];
  186. if ([manager fileExistsAtPath:[[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMHistoryPlist]]) {
  187. history = [[NSMutableArray arrayWithContentsOfFile:[[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMHistoryPlist]] retain];
  188. [self updateMenu];
  189. } else {
  190. history = [NSMutableArray new];
  191. [history writeToFile:[[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMHistoryPlist] atomically:YES];
  192. [self updateMenu];
  193. }
  194. saveLock = [NSLock new];
  195. filterWatcher = [MGMPathSubscriber sharedPathSubscriber];
  196. [filterWatcher setDelegate:self];
  197. if ([manager fileExistsAtPath:[[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMFiltersPlist]]) {
  198. filters = [[NSMutableArray arrayWithContentsOfFile:[[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMFiltersPlist]] retain];
  199. [self updateFilterWatcher];
  200. } else {
  201. filters = [NSMutableArray new];
  202. [self saveFilters];
  203. }
  204. filtersEnabled = YES;
  205. if ([manager fileExistsAtPath:[[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMResizePlist]]) {
  206. NSData *plistData = [NSData dataWithContentsOfFile:[[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMResizePlist]];
  207. NSString *error = nil;
  208. resizeLogic = [[NSPropertyListSerialization propertyListFromData:plistData mutabilityOption:NSPropertyListMutableContainersAndLeaves format:NULL errorDescription:&error] retain];
  209. if (error!=nil) {
  210. NSLog(@"Error processing resize.plist: %@", error);
  211. }
  212. } else {
  213. resizeLogic = [NSMutableArray new];
  214. [self saveResizeLogic];
  215. }
  216. if ([defaults integerForKey:MGMDisplay]>0)
  217. [self addMenu];
  218. preferences = [MGMPreferences new];
  219. [preferences addPreferencesPaneClassName:@"MGMGeneralPane"];
  220. [preferences addPreferencesPaneClassName:@"MGMAccountPane"];
  221. [preferences addPreferencesPaneClassName:@"MGMAutoUploadPane"];
  222. [preferences addPreferencesPaneClassName:@"MGMResizePane"];
  223. [preferences addPreferencesPaneClassName:@"MGMEventsPane"];
  224. EventTypeSpec eventType;
  225. eventType.eventClass = kEventClassApplication;
  226. eventType.eventKind = kEventAppFrontSwitched;
  227. EventHandlerUPP handlerUPP = NewEventHandlerUPP(frontAppChanged);
  228. InstallApplicationEventHandler(handlerUPP, 1, &eventType, self, NULL);
  229. if ([defaults integerForKey:MGMLaunchCount]==2)
  230. [preferences showPreferences];
  231. about = [MGMAbout new];
  232. uploads = [NSMutableArray new];
  233. if ([defaults objectForKey:MGMVersion]==nil || [[defaults objectForKey:MGMVersion] doubleValue]<=0.3) {
  234. for (int i=0; i<[filters count]; i++) {
  235. if ([[filters objectAtIndex:i] objectForKey:MGMFID]==nil) {
  236. CFUUIDRef uuid = CFUUIDCreate(NULL);
  237. NSString *uuidString = [(NSString *)CFUUIDCreateString(NULL, uuid) autorelease];
  238. CFRelease(uuid);
  239. NSDictionary *filter = [[filters objectAtIndex:i] mutableCopy];
  240. [filter setValue:uuidString forKey:MGMFID];
  241. [filters replaceObjectAtIndex:i withObject:filter];
  242. [filter release];
  243. }
  244. }
  245. [self saveFilters];
  246. }
  247. [defaults setObject:[[MGMSystemInfo info] applicationVersion] forKey:MGMVersion];
  248. [self loadMUThemes];
  249. [self loadPlugIns];
  250. }
  251. - (void)dealloc {
  252. [autoreleaseDrain invalidate];
  253. [autoreleaseDrain release];
  254. if (store!=NULL) {
  255. CFRunLoopRemoveSource(CFRunLoopGetCurrent(), runLoop, kCFRunLoopDefaultMode);
  256. CFRelease(store);
  257. }
  258. [IPv4Addresses release];
  259. [IPv6Addresses release];
  260. [lastAirPortState release];
  261. [connectionManager release];
  262. [preferences release];
  263. [[NSStatusBar systemStatusBar] removeStatusItem:statusItem];
  264. [statusItem release];
  265. [menuItem release];
  266. [history release];
  267. [filters release];
  268. [saveLock release];
  269. [filterWatcher release];
  270. [accountPlugIns release];
  271. [plugIns release];
  272. [uploads release];
  273. [super dealloc];
  274. }
  275. - (void)registerDefaults {
  276. NSMutableDictionary *defaults = [NSMutableDictionary dictionary];
  277. [defaults setObject:[NSNumber numberWithInt:1] forKey:MGMLaunchCount];
  278. [defaults setObject:[NSNumber numberWithInt:([[MGMSystemInfo info] isUIElement] ? 2 : 0)] forKey:MGMDisplay];
  279. [defaults setObject:[NSNumber numberWithBool:[[MGMLoginItems items] thisApplicationExists]] forKey:MGMStartup];
  280. [defaults setObject:[NSNumber numberWithInt:0] forKey:MGMUploadName];
  281. [defaults setObject:[NSNumber numberWithInt:5] forKey:MGMHistoryCount];
  282. [defaults setObject:[NSNumber numberWithInt:5] forKey:MGMUploadLimit];
  283. [defaults setObject:[NSNumber numberWithInt:2] forKey:[NSString stringWithFormat:MGMEDelete, MGMEUploadedAutomatic]];
  284. [defaults setObject:[[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:MGMMUThemesFolder] stringByAppendingPathComponent:@"White Background"] forKey:MGMCurrentMUTheme];
  285. [[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
  286. }
  287. - (void)drainAutoreleasePool {
  288. NSEvent *event = [NSEvent otherEventWithType:NSApplicationDefined location:NSMakePoint(0, 0) modifierFlags:0 timestamp:CFAbsoluteTimeGetCurrent() windowNumber:0 context:nil subtype:0 data1:0 data2:0];
  289. [[NSApplication sharedApplication] postEvent:event atStart:NO];
  290. }
  291. - (void)ipv4Changed:(NSDictionary *)theInfo {
  292. NSDictionary *info = (NSDictionary *)SCDynamicStoreCopyValue(store, (CFStringRef)[NSString stringWithFormat:MGMIPv4Info, [theInfo objectForKey:MGMPrimaryInterface]]);
  293. [IPv4Addresses autorelease];
  294. IPv4Addresses = [[info objectForKey:MGMAddresses] retain];
  295. [info release];
  296. }
  297. - (void)ipv6Changed:(NSDictionary *)theInfo {
  298. NSDictionary *info = (NSDictionary *)SCDynamicStoreCopyValue(store, (CFStringRef)[NSString stringWithFormat:MGMIPv6Info, [theInfo objectForKey:MGMPrimaryInterface]]);
  299. [IPv6Addresses autorelease];
  300. IPv6Addresses = [[info objectForKey:MGMAddresses] retain];
  301. [info release];
  302. }
  303. - (void)airportChanged:(NSDictionary *)theInfo {
  304. [lastAirPortState autorelease];
  305. lastAirPortState = [theInfo retain];
  306. }
  307. - (MGMURLConnectionManager *)connectionManager {
  308. return connectionManager;
  309. }
  310. - (MGMPreferences *)preferences {
  311. return preferences;
  312. }
  313. - (void)loadPlugIns {
  314. NSFileManager *manager = [NSFileManager defaultManager];
  315. [accountPlugIns release];
  316. accountPlugIns = [NSMutableArray new];
  317. [plugIns release];
  318. plugIns = [NSMutableArray new];
  319. NSArray *checkPaths = [NSArray arrayWithObjects:[[NSBundle mainBundle] builtInPlugInsPath], [[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMPluginFolder], nil];
  320. for (int i=0; i<[checkPaths count]; i++) {
  321. NSArray *plugInsFolder = [manager contentsOfDirectoryAtPath:[checkPaths objectAtIndex:i]];
  322. for (int p=0; p<[plugInsFolder count]; p++) {
  323. NSString *path = [[[checkPaths objectAtIndex:i] stringByAppendingPathComponent:[plugInsFolder objectAtIndex:p]] stringByResolvingSymlinksInPath];
  324. NSBundle *bundle = [NSBundle bundleWithPath:path];
  325. if (bundle!=nil) {
  326. Class plugInClass = [bundle principalClass];
  327. id<MGMPlugInProtocol> plugIn = [[[plugInClass alloc] init] autorelease];
  328. if (plugIn!=nil && [plugIn respondsToSelector:@selector(isAccountPlugIn)] && [plugIn isAccountPlugIn])
  329. [accountPlugIns addObject:plugIn];
  330. else if (plugIn!=nil)
  331. [plugIns addObject:plugIn];
  332. }
  333. }
  334. }
  335. NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
  336. NSString *currentPlugInName = [defaults objectForKey:MGMCurrentPlugIn];
  337. BOOL foundCurrentPlugIn = NO;
  338. for (int i=0; i<[accountPlugIns count]; i++) {
  339. if ([NSStringFromClass([[accountPlugIns objectAtIndex:i] class]) isEqual:currentPlugInName]) {
  340. currentPlugIn = [accountPlugIns objectAtIndex:i];
  341. currentPlugInIndex = i;
  342. if ([currentPlugIn respondsToSelector:@selector(setCurrentPlugIn:)]) [currentPlugIn setCurrentPlugIn:YES];
  343. foundCurrentPlugIn = YES;
  344. break;
  345. }
  346. }
  347. if (!foundCurrentPlugIn && [accountPlugIns count]>0)
  348. [self setCurrentPlugIn:[accountPlugIns objectAtIndex:0]];
  349. }
  350. - (NSArray *)accountPlugIns {
  351. return accountPlugIns;
  352. }
  353. - (NSArray *)plugIns {
  354. return plugIns;
  355. }
  356. - (void)setCurrentPlugIn:(id)thePlugIn {
  357. int plugInIndex = [accountPlugIns indexOfObject:thePlugIn];
  358. if (plugInIndex>=0) {
  359. [self removePassword];
  360. if ([currentPlugIn respondsToSelector:@selector(setCurrentPlugIn:)]) [currentPlugIn setCurrentPlugIn:NO];
  361. currentPlugIn = thePlugIn;
  362. currentPlugInIndex = plugInIndex;
  363. [[NSUserDefaults standardUserDefaults] setObject:NSStringFromClass([currentPlugIn class]) forKey:MGMCurrentPlugIn];
  364. if ([currentPlugIn respondsToSelector:@selector(setCurrentPlugIn:)]) [currentPlugIn setCurrentPlugIn:YES];
  365. }
  366. }
  367. - (id<MGMPlugInProtocol>)currentPlugIn {
  368. return currentPlugIn;
  369. }
  370. - (int)currentPlugInIndex {
  371. return currentPlugInIndex;
  372. }
  373. - (void)loadMUThemes {
  374. NSFileManager *manager = [NSFileManager defaultManager];
  375. [MUThemes release];
  376. MUThemes = [NSMutableArray new];
  377. NSArray *checkPaths = [NSArray arrayWithObjects:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:MGMMUThemesFolder], [[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMMUThemesFolder], nil];
  378. for (int i=0; i<[checkPaths count]; i++) {
  379. NSArray *MUThemesFolder = [manager contentsOfDirectoryAtPath:[checkPaths objectAtIndex:i]];
  380. for (int p=0; p<[MUThemesFolder count]; p++) {
  381. NSString *path = [[[checkPaths objectAtIndex:i] stringByAppendingPathComponent:[MUThemesFolder objectAtIndex:p]] stringByResolvingSymlinksInPath];
  382. [MUThemes addObject:path];
  383. }
  384. }
  385. NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
  386. NSString *currentMUThemePath = [defaults objectForKey:MGMCurrentMUTheme];
  387. BOOL foundCurrentMUTheme = NO;
  388. for (int i=0; i<[MUThemes count]; i++) {
  389. if ([[MUThemes objectAtIndex:i] isEqual:currentMUThemePath]) {
  390. currentMUThemeIndex = i;
  391. foundCurrentMUTheme = YES;
  392. break;
  393. }
  394. }
  395. if (!foundCurrentMUTheme && [MUThemes count]>0)
  396. [self setCurrentMUTheme:[MUThemes objectAtIndex:0]];
  397. }
  398. - (NSArray *)MUThemes {
  399. return MUThemes;
  400. }
  401. - (void)setCurrentMUTheme:(NSString *)theMUTheme {
  402. int MUThemeIndex = [MUThemes indexOfObject:theMUTheme];
  403. if (MUThemeIndex>=0) {
  404. currentMUThemeIndex = MUThemeIndex;
  405. [[NSUserDefaults standardUserDefaults] setObject:theMUTheme forKey:MGMCurrentMUTheme];
  406. }
  407. }
  408. - (int)currentMUThemeIndex {
  409. return currentMUThemeIndex;
  410. }
  411. - (NSString *)currentMUTheme {
  412. return [MUThemes objectAtIndex:currentMUThemeIndex];
  413. }
  414. - (void)setFrontProcess:(ProcessSerialNumber *)theProcess {
  415. frontProcess = *theProcess;
  416. /*CFStringRef name;
  417. CopyProcessName(theProcess, &name);
  418. if (name!=NULL) {
  419. NSLog(@"%@ became front", (NSString *)name);
  420. CFRelease(name);
  421. }*/
  422. }
  423. - (void)becomeFront:(NSWindow *)theWindow {
  424. if (theWindow!=nil) {
  425. windowCount++;
  426. if ([[MGMSystemInfo info] isUIElement])
  427. [theWindow setLevel:NSFloatingWindowLevel];
  428. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(frontWindowClosed:) name:NSWindowWillCloseNotification object:theWindow];
  429. }
  430. [[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
  431. }
  432. - (void)resignFront {
  433. SetFrontProcess(&frontProcess);
  434. }
  435. - (void)frontWindowClosed:(NSNotification *)theNotification {
  436. [[NSNotificationCenter defaultCenter] removeObserver:self name:[theNotification name] object:[theNotification object]];
  437. windowCount--;
  438. if (windowCount==0)
  439. [self resignFront];
  440. }
  441. - (void)addMenu {
  442. if (statusItem==nil) {
  443. menuItem = [[MGMMenuItem alloc] initWithFrame:NSZeroRect];
  444. [menuItem setDelegate:self];
  445. NSString *osxMode = [[NSUserDefaults standardUserDefaults] stringForKey:@"AppleInterfaceStyle"];
  446. if ([osxMode isEqualTo:@"Dark"]) {
  447. [menuItem setImage:[NSImage imageNamed:@"menuiconselected"]];
  448. [menuItem setAlternateImage:[NSImage imageNamed:@"menuicon"]];
  449. } else {
  450. [menuItem setImage:[NSImage imageNamed:@"menuicon"]];
  451. [menuItem setAlternateImage:[NSImage imageNamed:@"menuiconselected"]];
  452. }
  453. [menuItem setToolTip:@"CocoaShare"];
  454. statusItem = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength] retain];
  455. [statusItem setView:menuItem];
  456. }
  457. }
  458. - (void)removeMenu {
  459. if (statusItem!=nil) {
  460. [[NSStatusBar systemStatusBar] removeStatusItem:statusItem];
  461. [statusItem release];
  462. statusItem = nil;
  463. [menuItem release];
  464. menuItem = nil;
  465. }
  466. }
  467. - (void)setDockHidden:(BOOL)isHidden {
  468. NSFileManager *manager = [NSFileManager defaultManager];
  469. NSBundle *bundle = [NSBundle mainBundle];
  470. NSString *path = [[bundle bundlePath] stringByAppendingPathComponent:@"Contents/Info.plist"];
  471. if ([manager isWritableFileAtPath:path]) {
  472. NSMutableDictionary *infoDict = [NSMutableDictionary dictionaryWithContentsOfFile:path];
  473. [infoDict setObject:[NSNumber numberWithBool:isHidden] forKey:@"LSUIElement"];
  474. [infoDict writeToFile:path atomically:NO];
  475. NSDictionary *attributes = [NSDictionary dictionaryWithObject:[NSDate date] forKey:NSFileModificationDate];
  476. [manager setAttributes:attributes ofItemAtPath:[bundle bundlePath]];
  477. if (isHidden) {
  478. NSAlert *alert = [[NSAlert new] autorelease];
  479. [alert setMessageText:[@"Restart Required" localized]];
  480. [alert setInformativeText:[@"Inorder to hide the dock, you must restart CocoaShare. Do you want to restart CocoaShare now?" localized]];
  481. [alert addButtonWithTitle:[@"Yes" localized]];
  482. [alert addButtonWithTitle:[@"No" localized]];
  483. int result = [alert runModal];
  484. if (result==1000) {
  485. //Took from Sparkle.
  486. NSString *pathToRelaunch = [[NSBundle mainBundle] bundlePath];
  487. NSString *relaunchPath = [[[NSBundle bundleWithIdentifier:@"org.andymatuschak.Sparkle"] resourcePath] stringByAppendingPathComponent:@"relaunch"];
  488. [NSTask launchedTaskWithLaunchPath:relaunchPath arguments:[NSArray arrayWithObjects:pathToRelaunch, [NSString stringWithFormat:@"%d", [[NSProcessInfo processInfo] processIdentifier]], nil]];
  489. [[NSApplication sharedApplication] terminate:self];
  490. }
  491. }
  492. } else {
  493. NSAlert *alert = [[NSAlert new] autorelease];
  494. [alert setMessageText:[@"Unable to change dock" localized]];
  495. [alert setInformativeText:[NSString stringWithFormat:[@"CocoaShare is unable to %@ the dock due to permissions. To fix this issue, right click on CocoaShare and choose Get Info to make CocoaShare writable." localized], (isHidden ? [@"hide" localized] : [@"unhide" localized])]];
  496. [alert runModal];
  497. }
  498. if (!isHidden) {
  499. ProcessSerialNumber psn = {0, kCurrentProcess};
  500. TransformProcessType(&psn, kProcessTransformToForegroundApplication);
  501. [self resignFront];
  502. [self performSelector:@selector(becomeFront:) withObject:[preferences preferencesWindow] afterDelay:0.0];
  503. }
  504. }
  505. - (void)menuClicked:(id)sender {
  506. [statusItem popUpStatusItemMenu:mainMenu];
  507. }
  508. - (void)menuDraggingEntered:(id)sender {
  509. [menuItem setImage:[NSImage imageNamed:@"menuicondrag"]];
  510. }
  511. - (void)menuDraggingExited:(id)sender {
  512. NSString *osxMode = [[NSUserDefaults standardUserDefaults] stringForKey:@"AppleInterfaceStyle"];
  513. if ([osxMode isEqualTo:@"Dark"]) {
  514. [menuItem setImage:[NSImage imageNamed:@"menuiconselected"]];
  515. } else {
  516. [menuItem setImage:[NSImage imageNamed:@"menuicon"]];
  517. }
  518. }
  519. - (void)menu:(id)sender droppedFiles:(NSArray *)files {
  520. NSFileManager *manager = [NSFileManager defaultManager];
  521. for (int i=0; i<[files count]; i++) {
  522. BOOL directory = NO;
  523. if ([manager fileExistsAtPath:[files objectAtIndex:i] isDirectory:&directory]) {
  524. if (directory) {
  525. NSAlert *alert = [[NSAlert new] autorelease];
  526. [alert setMessageText:[@"Upload Error" localized]];
  527. [alert setInformativeText:[@"Uploading of directories is impossible." localized]];
  528. [alert runModal];
  529. continue;
  530. }
  531. [self addPathToUploads:[files objectAtIndex:i] automaticFilter:nil multiUpload:([files count]==1 ? 0 : (i==0 ? 1 : (i==[files count]-1 ? 3 : 2)))];
  532. }
  533. }
  534. }
  535. - (NSMutableArray *)history {
  536. return history;
  537. }
  538. - (void)updateMenu {
  539. int splitterIndex = 0;
  540. for (int i=0; i<[mainMenu numberOfItems]; i++) {
  541. if ([[mainMenu itemAtIndex:i] isSeparatorItem]) {
  542. splitterIndex = i;
  543. break;
  544. }
  545. [mainMenu removeItemAtIndex:i];
  546. i--;
  547. }
  548. if ([history count]>0) {
  549. for (int i=0; i<[history count]; i++) {
  550. NSDictionary *historyItem = [history objectAtIndex:i];
  551. NSMenuItem *item = [[NSMenuItem new] autorelease];
  552. NSDateFormatter *formatter = [[NSDateFormatter new] autorelease];
  553. [formatter setDateFormat:[@"MMMM d, yyyy h:mm:ss a" localized]];
  554. NSString *date = [formatter stringFromDate:[historyItem objectForKey:MGMHDate]];
  555. if (date!=nil)
  556. [item setTitle:date];
  557. else
  558. [item setTitle:[NSString stringWithFormat:@"%@", [historyItem objectForKey:MGMHDate]]];
  559. [item setRepresentedObject:[historyItem objectForKey:MGMHURL]];
  560. [item setTarget:self];
  561. [item setAction:@selector(copyHistoryItem:)];
  562. [mainMenu insertItem:item atIndex:splitterIndex];
  563. }
  564. } else {
  565. NSMenuItem *item = [[NSMenuItem new] autorelease];
  566. [item setTitle:[@"No Upload History" localized]];
  567. [item setEnabled:NO];
  568. [mainMenu insertItem:item atIndex:splitterIndex];
  569. }
  570. }
  571. - (IBAction)copyHistoryItem:(id)sender {
  572. NSPasteboard *pboard = [NSPasteboard generalPasteboard];
  573. [pboard declareTypes:[NSArray arrayWithObjects:MGMNSStringPboardType, MGMNSPasteboardTypeString, nil] owner:nil];
  574. [pboard setString:[sender representedObject] forType:MGMNSStringPboardType];
  575. [pboard setString:[sender representedObject] forType:MGMNSPasteboardTypeString];
  576. }
  577. - (void)addURLToHistory:(NSURL *)theURL {
  578. [history addObject:[NSDictionary dictionaryWithObjectsAndKeys:[theURL absoluteString], MGMHURL, [NSDate date], MGMHDate, nil]];
  579. int maxHistoryItems = [[NSUserDefaults standardUserDefaults] integerForKey:MGMHistoryCount];
  580. int itemsToDelete = [history count]-maxHistoryItems;
  581. if (itemsToDelete>0) {
  582. for (int i=0; i<itemsToDelete; i++) {
  583. [history removeObjectAtIndex:0];
  584. }
  585. }
  586. [history writeToFile:[[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMHistoryPlist] atomically:YES];
  587. [self updateMenu];
  588. }
  589. - (void)uploadFinished:(NSString *)thePath url:(NSURL *)theURL info:(id)theInfo {
  590. [history addObject:[NSDictionary dictionaryWithObjectsAndKeys:[theURL absoluteString], MGMHURL, theInfo, MGMHInfo, [NSDate date], MGMHDate, nil]];
  591. int maxHistoryItems = [[NSUserDefaults standardUserDefaults] integerForKey:MGMHistoryCount];
  592. int itemsToDelete = [history count]-maxHistoryItems;
  593. if (itemsToDelete>0) {
  594. for (int i=0; i<itemsToDelete; i++) {
  595. [history removeObjectAtIndex:0];
  596. }
  597. }
  598. [history writeToFile:[[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMHistoryPlist] atomically:YES];
  599. [self updateMenu];
  600. }
  601. - (IBAction)uploadFile:(id)sender {
  602. NSOpenPanel *panel = [NSOpenPanel openPanel];
  603. [panel setCanChooseFiles:YES];
  604. [panel setCanChooseDirectories:NO];
  605. [panel setResolvesAliases:YES];
  606. [panel setAllowsMultipleSelection:YES];
  607. [panel setTitle:[@"Choose File(s)" localized]];
  608. [panel setPrompt:[@"Choose" localized]];
  609. [self becomeFront:nil];
  610. int returnCode = [panel runModal];
  611. if (returnCode==NSOKButton) {
  612. for (int i=0; i<[[panel URLs] count]; i++) {
  613. [self addPathToUploads:[[[panel URLs] objectAtIndex:i] path] automaticFilter:nil multiUpload:([[panel URLs] count]==1 ? 0 : (i==0 ? 1 : (i==[[panel URLs] count]-1 ? 3 : 2)))];
  614. }
  615. }
  616. [self resignFront];
  617. }
  618. - (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag {
  619. if (!flag)
  620. [self preferences:self];
  621. return YES;
  622. }
  623. - (void)application:(NSApplication *)theApplication openFiles:(NSArray *)theFiles {
  624. for (int i=0; i<[theFiles count]; i++) {
  625. [self addPathToUploads:[theFiles objectAtIndex:i] automaticFilter:nil multiUpload:([theFiles count]==1 ? 0 : (i==0 ? 1 : (i==[theFiles count]-1 ? 3 : 2)))];
  626. }
  627. }
  628. - (IBAction)disableFilters:(id)sender {
  629. filtersEnabled = !filtersEnabled;
  630. [disableFilters setTitle:(filtersEnabled ? [@"Disable Auto Upload" localized] : [@"Enable Auto Upload" localized])];
  631. }
  632. - (IBAction)about:(id)sender {
  633. [about show];
  634. [self becomeFront:[about window]];
  635. }
  636. - (IBAction)preferences:(id)sender {
  637. [preferences showPreferences];
  638. [self becomeFront:[preferences preferencesWindow]];
  639. }
  640. - (IBAction)donate:(id)sender {
  641. [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"https://mrgeckosmedia.com/donate?purpose=cocoashare"]];
  642. }
  643. - (IBAction)quit:(id)sender {
  644. [[MGMLoginItems items] removeThisApplication];
  645. [[NSApplication sharedApplication] terminate:self];
  646. }
  647. - (NSMutableArray *)filters {
  648. return filters;
  649. }
  650. - (void)saveFilters {
  651. if (saveCount==2)
  652. return;
  653. saveCount++;
  654. NSAutoreleasePool *pool = [NSAutoreleasePool new];
  655. [saveLock lock];
  656. [filters writeToFile:[[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMFiltersPlist] atomically:YES];
  657. [self updateFilterWatcher];
  658. saveCount--;
  659. [pool drain];
  660. [saveLock unlock];
  661. }
  662. - (MGMPathSubscriber *)filterWatcher {
  663. return filterWatcher;
  664. }
  665. - (NSArray *)filtersForPath:(NSString *)thePath {
  666. NSMutableArray *filtersFound = [NSMutableArray array];
  667. for (int i=0; i<[filters count]; i++) {
  668. NSString *path = [[[filters objectAtIndex:i] objectForKey:MGMFPath] stringByExpandingTildeInPath];
  669. if ([path isEqual:thePath])
  670. [filtersFound addObject:[filters objectAtIndex:i]];
  671. }
  672. return filtersFound;
  673. }
  674. - (void)updateFilterWatcher {
  675. [filterWatcher removeAllPaths];
  676. for (int i=0; i<[filters count]; i++) {
  677. NSDictionary *filter = [filters objectAtIndex:i];
  678. if (![[filter objectForKey:MGMFFilter] isEqual:@""]) {
  679. NSString *path = [[filter objectForKey:MGMFPath] stringByExpandingTildeInPath];
  680. if (![path isEqual:@""])
  681. [filterWatcher addPath:path];
  682. }
  683. }
  684. }
  685. - (void)subscribedPathChanged:(NSString *)thePath {
  686. NSLog(@"Changed: %@", thePath);
  687. if (filtersEnabled) {
  688. NSFileManager *manager = [NSFileManager defaultManager];
  689. int uploadLimit = [[NSUserDefaults standardUserDefaults] integerForKey:MGMUploadLimit];
  690. NSDate *dateLimit = [NSDate dateWithTimeIntervalSinceNow:-uploadLimit];
  691. NSArray *filtersFound = [self filtersForPath:thePath];
  692. NSArray *files = [manager contentsOfDirectoryAtPath:thePath];
  693. for (int i=0; i<[files count]; i++) {
  694. NSString *file = [files objectAtIndex:i];
  695. NSString *fullPath = [thePath stringByAppendingPathComponent:file];
  696. NSDictionary *attributes = [manager attributesOfItemAtPath:fullPath];
  697. if (uploadLimit!=0 && [[attributes objectForKey:NSFileCreationDate] earlierDate:dateLimit]!=dateLimit)
  698. continue;
  699. BOOL directory = NO;
  700. if ([manager fileExistsAtPath:fullPath isDirectory:&directory] && !directory) {
  701. for (int f=0; f<[filtersFound count]; f++) {
  702. NSString *filter = [[filtersFound objectAtIndex:f] objectForKey:MGMFFilter];
  703. if ([filter hasPrefix:@"MD:"]) {
  704. if ([filter hasPrefix:@"MD: "])
  705. filter = [filter substringFromIndex:4];
  706. else
  707. filter = [filter substringFromIndex:3];
  708. MDItemRef metadata = MDItemCreate(kCFAllocatorDefault, (CFStringRef)fullPath);
  709. if (metadata!=NULL) {
  710. NSArray *items = (NSArray *)MDItemCopyAttributeNames(metadata);
  711. for (int m=0; m<[items count]; m++) {
  712. id item = (id)MDItemCopyAttribute(metadata, (CFStringRef)[items objectAtIndex:m]);
  713. if ([[items objectAtIndex:m] isMatchedByRegex:filter]) {
  714. [self addPathToUploads:fullPath automaticFilter:[[filtersFound objectAtIndex:f] objectForKey:MGMFID]];
  715. } else if ([item isKindOfClass:[NSString class]] && [item isMatchedByRegex:filter]) {
  716. [self addPathToUploads:fullPath automaticFilter:[[filtersFound objectAtIndex:f] objectForKey:MGMFID]];
  717. }
  718. if (item!=nil)
  719. CFRelease((CFTypeRef)item);
  720. }
  721. if (items!=nil)
  722. CFRelease((CFArrayRef)items);
  723. CFRelease(metadata);
  724. } else {
  725. NSLog(@"Unable to get metadata of %@", fullPath);
  726. }
  727. NSDictionary *extendedAttributes = nil;
  728. if ([manager respondsToSelector:@selector(attributesOfItemAtPath:error:)]) {
  729. extendedAttributes = [[manager attributesOfItemAtPath:fullPath error:nil] objectForKey:@"NSFileExtendedAttributes"];
  730. } else {
  731. extendedAttributes = [[manager fileSystemAttributesAtPath:fullPath] objectForKey:@"NSFileExtendedAttributes"];
  732. }
  733. for (int a=0; a<[[extendedAttributes allKeys] count]; a++) {
  734. if ([[[extendedAttributes allKeys] objectAtIndex:a] isMatchedByRegex:filter]) {
  735. [self addPathToUploads:fullPath automaticFilter:[[filtersFound objectAtIndex:f] objectForKey:MGMFID]];
  736. } else if ([[extendedAttributes objectForKey:[[extendedAttributes allKeys] objectAtIndex:a]] isKindOfClass:[NSString class]] && [[extendedAttributes objectForKey:[[extendedAttributes allKeys] objectAtIndex:a]] isMatchedByRegex:filter]) {
  737. [self addPathToUploads:fullPath automaticFilter:[[filtersFound objectAtIndex:f] objectForKey:MGMFID]];
  738. }
  739. }
  740. } else {
  741. if ([file isMatchedByRegex:filter]) {
  742. [self addPathToUploads:fullPath automaticFilter:[[filtersFound objectAtIndex:f] objectForKey:MGMFID]];
  743. }
  744. }
  745. }
  746. }
  747. }
  748. }
  749. }
  750. - (NSMutableArray *)resizeLogic {
  751. return resizeLogic;
  752. }
  753. - (void)resizeIfNeeded:(NSString *)thePath {
  754. [self resizeIfNeeded:thePath filterID:nil];
  755. }
  756. - (void)resizeIfNeeded:(NSString *)thePath filterID:(NSString *)theID {
  757. NSArray *extensions = [NSArray arrayWithObjects:@"jpg", @"jpeg", @"png", @"tif", @"tiff", @"bmp", nil];
  758. if (![extensions containsObject:[[thePath pathExtension] lowercaseString]])
  759. return;
  760. NSDictionary *lastMatch = nil;
  761. BOOL matchedOnFilter = NO;
  762. BOOL matchedOnNetwork = NO;
  763. BOOL matchedOnPrefix = NO;
  764. for (int i=0; i<[resizeLogic count]; i++) {
  765. NSDictionary *logic = [resizeLogic objectAtIndex:i];
  766. BOOL prefixMatch = NO;
  767. if (![[logic objectForKey:MGMRIPPrefix] isEqual:@""]) {
  768. NSString *prefix = [logic objectForKey:MGMRIPPrefix];
  769. for (int ip=0; ip<[IPv4Addresses count]; ip++) {
  770. if ([[IPv4Addresses objectAtIndex:ip] hasPrefix:prefix]) {
  771. prefixMatch = YES;
  772. }
  773. }
  774. for (int ip=0; ip<[IPv6Addresses count]; ip++) {
  775. if ([[IPv6Addresses objectAtIndex:ip] hasPrefix:prefix]) {
  776. prefixMatch = YES;
  777. }
  778. }
  779. }
  780. BOOL networkMatch = (lastAirPortState!=nil && [lastAirPortState objectForKey:@"SSID"]!=nil && [[logic objectForKey:MGMRNetworks] containsObject:[[[NSString alloc] initWithData:[lastAirPortState objectForKey:@"SSID"] encoding:NSUTF8StringEncoding] autorelease]]);
  781. BOOL filterMatch = (theID!=nil && [[logic objectForKey:MGMRFilters] containsObject:theID]);
  782. NSLog(@"%d %d %d", prefixMatch, networkMatch, filterMatch);
  783. if ([[logic objectForKey:MGMRFilters] count]==0 && (networkMatch || prefixMatch)) {//No filters and network or prefix match.
  784. if (lastMatch!=nil && matchedOnFilter) {//If this is a network match and previous was a filter match, do not match.
  785. continue;
  786. }
  787. if (lastMatch!=nil && matchedOnNetwork && !networkMatch) {//If this isn't a network match, yet the previous was, do not match.
  788. continue;
  789. }
  790. } else if ([[logic objectForKey:MGMRFilters] count]==0) {//No filters and not network or prefix.
  791. if (lastMatch!=nil && (matchedOnNetwork || matchedOnPrefix || matchedOnFilter)) {//If previous matches on network, prefix, or filter, do not match.
  792. continue;
  793. }
  794. } else if ([[logic objectForKey:MGMRFilters] count]!=0 && !filterMatch) {//Cannot match if filteres exist, but not matched.
  795. continue;
  796. } else if (filterMatch) {//If filtere match.
  797. if (networkMatch || prefixMatch) {//Network or prefix match.
  798. if (lastMatch!=nil && matchedOnFilter && matchedOnNetwork && !networkMatch) {//Previous matched on network and this isn't a network match, do not match.
  799. continue;
  800. }
  801. } else {//Not network or prefix match.
  802. if (lastMatch!=nil && matchedOnFilter && (matchedOnNetwork || matchedOnFilter)) {//If was a network match, do not match.
  803. continue;
  804. }
  805. }
  806. }
  807. if (([[logic objectForKey:MGMRWidth] intValue]==0 || [[logic objectForKey:MGMRHeight] intValue]==0) && [[logic objectForKey:MGMRScale] intValue]==0) {//Incorrect resize logic.
  808. continue;
  809. }
  810. lastMatch = logic;
  811. matchedOnFilter = filterMatch;
  812. matchedOnNetwork = networkMatch;
  813. matchedOnPrefix = prefixMatch;
  814. }
  815. if (lastMatch!=nil) {
  816. int scale = [[lastMatch objectForKey:MGMRScale] intValue];
  817. if (scale!=0) {
  818. [self resize:thePath toSize:NSZeroSize scale:1-(((float)scale)/100)];
  819. } else {
  820. [self resize:thePath toSize:NSMakeSize([[lastMatch objectForKey:MGMRWidth] floatValue], [[lastMatch objectForKey:MGMRHeight] floatValue]) scale:0.0];
  821. }
  822. }
  823. }
  824. - (void)resize:(NSString *)thePath toSize:(NSSize)theSize scale:(float)theScale {
  825. NSString *extension = [[thePath pathExtension] lowercaseString];
  826. CFStringRef type = kUTTypeImage;
  827. if ([extension isEqual:@"jpg"] || [extension isEqual:@"jpeg"]) {
  828. type = kUTTypeJPEG;
  829. } else if ([extension isEqual:@"png"]) {
  830. type = kUTTypePNG;
  831. } else if ([extension isEqual:@"bmp"]) {
  832. type = kUTTypeBMP;
  833. } else if ([extension isEqual:@"tif"] || [extension isEqual:@"tiff"]) {
  834. type = kUTTypeTIFF;
  835. } else {
  836. return;
  837. }
  838. CFURLRef fileURL = (__bridge CFURLRef)[NSURL fileURLWithPath:[thePath stringByExpandingTildeInPath]];
  839. CGImageSourceRef source = CGImageSourceCreateWithURL(fileURL, NULL);
  840. if (source==NULL) {
  841. NSLog(@"Unable to create image source: %@", thePath);
  842. return;
  843. }
  844. CGImageRef imageRef = CGImageSourceCreateImageAtIndex(source, 0, NULL);
  845. CFRelease(source);
  846. if (imageRef==NULL) {
  847. NSLog(@"Unable to create image: %@", thePath);
  848. return;
  849. }
  850. NSSize size = NSMakeSize(CGImageGetWidth(imageRef), CGImageGetHeight(imageRef));
  851. float scaleFactor = 0.0;
  852. float scaledWidth = 0.0;
  853. float scaledHeight = 0.0;
  854. if (NSEqualSizes(theSize, NSZeroSize)) {
  855. scaleFactor = theScale;
  856. } else {
  857. float widthFactor = theSize.width / size.width;
  858. float heightFactor = theSize.height / size.height;
  859. if (widthFactor < heightFactor)
  860. scaleFactor = widthFactor;
  861. else
  862. scaleFactor = heightFactor;
  863. }
  864. scaledWidth = size.width * scaleFactor;
  865. scaledHeight = size.height * scaleFactor;
  866. if (size.width<=scaledWidth && size.height<=scaledHeight) {
  867. CGImageRelease(imageRef);
  868. return;//Output larger or equal to input.
  869. }
  870. NSLog(@"Resizing: %@", thePath);
  871. NSLog(@"Width: %f Height: %f", size.width, size.height);
  872. NSLog(@"Width: %f Height: %f", scaledWidth, scaledHeight);
  873. NSSize newSize = NSMakeSize(scaledWidth, scaledHeight);
  874. if (!NSEqualSizes(newSize, NSZeroSize)) {
  875. CGContextRef bitmap = CGBitmapContextCreate(NULL, newSize.width, newSize.height, CGImageGetBitsPerComponent(imageRef), 0, CGImageGetColorSpace(imageRef), (CGBitmapInfo)((type==kUTTypePNG || type==kUTTypeTIFF) ? kCGImageAlphaPremultipliedLast : kCGImageAlphaNoneSkipLast));
  876. CGContextSetInterpolationQuality(bitmap, kCGInterpolationHigh);
  877. CGContextDrawImage(bitmap, NSMakeRect(0, 0, newSize.width, newSize.height), imageRef);
  878. CGImageRef newImage = CGBitmapContextCreateImage(bitmap);
  879. CGContextRelease(bitmap);
  880. CGImageDestinationRef destination = CGImageDestinationCreateWithURL(fileURL, type, 1, NULL);
  881. if (!destination) {
  882. NSLog(@"Failed to create CGImageDestination for %@", thePath);
  883. CGImageRelease(newImage);
  884. CGImageRelease(imageRef);
  885. return;
  886. }
  887. CGImageDestinationAddImage(destination, newImage, nil);
  888. if (!CGImageDestinationFinalize(destination)) {
  889. NSLog(@"Failed to write image to %@", thePath);
  890. }
  891. CFRelease(destination);
  892. CGImageRelease(newImage);
  893. }
  894. CGImageRelease(imageRef);
  895. }
  896. - (void)saveResizeLogic {
  897. if (saveCount==2)
  898. return;
  899. saveCount++;
  900. NSAutoreleasePool *pool = [NSAutoreleasePool new];
  901. [saveLock lock];
  902. [resizeLogic writeToFile:[[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMResizePlist] atomically:YES];
  903. saveCount--;
  904. [pool drain];
  905. [saveLock unlock];
  906. }
  907. - (void)removePassword {
  908. NSArray *items = [MGMKeychain items:MGMKCType withName:MGMKCName service:MGMKCName account:MGMKCName];
  909. if ([items count]>0)
  910. [[items objectAtIndex:0] remove];
  911. }
  912. - (void)setPassword:(NSString *)thePassword {
  913. NSArray *items = [MGMKeychain items:MGMKCType withName:MGMKCName service:MGMKCName account:MGMKCName];
  914. if ([items count]>0) {
  915. [[items objectAtIndex:0] setString:thePassword];
  916. } else {
  917. [MGMKeychain addItem:MGMKCType withName:MGMKCName service:MGMKCName account:MGMKCName password:thePassword];
  918. }
  919. }
  920. - (NSString *)password {
  921. NSArray *items = [MGMKeychain items:MGMKCType withName:MGMKCName service:MGMKCName account:MGMKCName];
  922. if ([items count]>0)
  923. return [[items objectAtIndex:0] string];
  924. return nil;
  925. }
  926. - (void)processEvent:(int)theEvent path:(NSString *)thePath {
  927. [self processEvent:theEvent path:thePath url:nil];
  928. }
  929. - (void)processEvent:(int)theEvent path:(NSString *)thePath url:(NSURL *)theURL {
  930. NSMutableDictionary *eventInfo = [NSMutableDictionary dictionary];
  931. [eventInfo setObject:[NSNumber numberWithInt:theEvent] forKey:MGMEvent];
  932. [eventInfo setObject:thePath forKey:MGMEventPath];
  933. if (theURL!=nil)
  934. [eventInfo setObject:theURL forKey:MGMEventURL];
  935. [[NSNotificationCenter defaultCenter] postNotificationName:MGMEventNotification object:self userInfo:eventInfo];
  936. NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
  937. NSFileManager *manager = [NSFileManager defaultManager];
  938. NSString *soundPath = [defaults objectForKey:[NSString stringWithFormat:MGMESound, theEvent]];
  939. if (soundPath!=nil && [manager fileExistsAtPath:soundPath]) {
  940. NSSound *sound = [[NSSound alloc] initWithContentsOfFile:soundPath byReference:YES];
  941. [sound setDelegate:self];
  942. [sound play];
  943. }
  944. NSString *path = [[defaults objectForKey:[NSString stringWithFormat:MGMEPath, theEvent]] stringByExpandingTildeInPath];
  945. if ([manager fileExistsAtPath:path])
  946. [manager moveItemAtPath:thePath toPath:path];
  947. int deleteFile = [[defaults objectForKey:[NSString stringWithFormat:MGMEDelete, theEvent]] intValue];
  948. if (deleteFile!=0 && [manager fileExistsAtPath:thePath]) {
  949. if (deleteFile==1) {
  950. [manager removeItemAtPath:thePath];
  951. } else if (deleteFile==2) {
  952. NSString *trash = [@"~/.Trash" stringByExpandingTildeInPath];
  953. NSInteger tag;
  954. [[NSWorkspace sharedWorkspace] performFileOperation:NSWorkspaceRecycleOperation source:[thePath stringByDeletingLastPathComponent] destination:trash files:[NSArray arrayWithObject:[thePath lastPathComponent]] tag:&tag];
  955. if (tag!=0)
  956. NSLog(@"Error Deleting: %ld", (long)tag);
  957. }
  958. }
  959. BOOL growl = [[defaults objectForKey:[NSString stringWithFormat:MGMEGrowl, theEvent]] boolValue];
  960. if (growl) {
  961. NSString *title = nil;
  962. NSString *description = nil;
  963. NSString *notificationName = nil;
  964. if (theEvent==MGMEUploading) {
  965. title = [@"Uploading File" localized];
  966. description = [NSString stringWithFormat:[@"Uploading %@" localized], [[thePath lastPathComponent] stringByDeletingPathExtension]];
  967. notificationName = @"UploadingFile";
  968. } else if (theEvent==MGMEUploadingAutomatic) {
  969. title = [@"Automatically Uploading File" localized];
  970. description = [NSString stringWithFormat:[@"Uploading %@" localized], [[thePath lastPathComponent] stringByDeletingPathExtension]];
  971. notificationName = @"UploadingFileAutomatically";
  972. } else if (theEvent==MGMEUploaded) {
  973. title = [@"Uploaded File" localized];
  974. description = [NSString stringWithFormat:[@"Uploaded %@ to %@" localized], [[thePath lastPathComponent] stringByDeletingPathExtension], theURL];
  975. notificationName = @"UploadedFile";
  976. } else if (theEvent==MGMEUploadedAutomatic) {
  977. title = [@"Automatically Uploaded File" localized];
  978. description = [NSString stringWithFormat:[@"Uploaded %@ to %@" localized], [[thePath lastPathComponent] stringByDeletingPathExtension], theURL];
  979. notificationName = @"UploadedFileAutomatically";
  980. }
  981. [GrowlApplicationBridge notifyWithTitle:title description:description notificationName:notificationName iconData:[[[NSApplication sharedApplication] applicationIconImage] TIFFRepresentation] priority:0 isSticky:NO clickContext:nil];
  982. }
  983. }
  984. - (void)sound:(NSSound *)sound didFinishPlaying:(BOOL)finishedPlaying {
  985. if (finishedPlaying)
  986. [sound release];
  987. }
  988. - (NSMutableArray *)uploads {
  989. return uploads;
  990. }
  991. - (NSDictionary *)uploadForPath:(NSString *)thePath {
  992. for (int i=0; i<[uploads count]; i++) {
  993. if ([[[uploads objectAtIndex:i] objectForKey:MGMUPath] isEqual:thePath])
  994. return [uploads objectAtIndex:i];
  995. }
  996. return nil;
  997. }
  998. - (void)addPathToUploads:(NSString *)thePath automaticFilter:(NSString *)theFilter {
  999. [self addPathToUploads:thePath automaticFilter:theFilter multiUpload:0];
  1000. }
  1001. /*
  1002. 0 - Not a upload queue with multiple uploads.
  1003. 1 - First upload in the queue.
  1004. 2 - An upload in the queue.
  1005. 3 - Last upload in the queue.
  1006. 4 - The multi upload page.
  1007. */
  1008. - (void)addPathToUploads:(NSString *)thePath automaticFilter:(NSString *)theFilter multiUpload:(int)multiUploadState {
  1009. if ([self uploadForPath:thePath]==nil) {
  1010. if ([currentPlugIn respondsToSelector:@selector(allowedExtensions)]) {
  1011. if (![[currentPlugIn allowedExtensions] containsObject:[[thePath pathExtension] lowercaseString]]) {
  1012. NSAlert *alert = [[NSAlert new] autorelease];
  1013. [alert setMessageText:[@"Upload Error" localized]];
  1014. [alert setInformativeText:[@"The current PlugIn does not support this file format." localized]];
  1015. [alert runModal];
  1016. return;
  1017. }
  1018. }
  1019. [self resizeIfNeeded:thePath filterID:theFilter];
  1020. [uploads addObject:[NSDictionary dictionaryWithObjectsAndKeys:thePath, MGMUPath, [NSNumber numberWithBool:(theFilter!=nil)], MGMUAutomatic, [NSNumber numberWithInt:multiUploadState], MGMUMultiUpload, nil]];
  1021. if ([uploads count]==1)
  1022. [self processNextUpload];
  1023. }
  1024. }
  1025. - (void)processNextUpload {
  1026. if ([uploads count]>0) {
  1027. if (currentPlugIn==nil) {
  1028. NSAlert *alert = [[NSAlert new] autorelease];
  1029. [alert setMessageText:[@"Upload Error" localized]];
  1030. [alert setInformativeText:[@"No PlugIns found. You must have at least 1 PlugIn to upload a file." localized]];
  1031. [alert runModal];
  1032. [uploads removeAllObjects];
  1033. return;
  1034. } else if (![currentPlugIn respondsToSelector:@selector(sendFileAtPath:withName:)] && ![currentPlugIn respondsToSelector:@selector(sendFileAtPath:withName:multiUpload:)]) {
  1035. NSAlert *alert = [[NSAlert new] autorelease];
  1036. [alert setMessageText:[@"Upload Error" localized]];
  1037. [alert setInformativeText:[@"The current PlugIn doesn't support uploading." localized]];
  1038. [alert runModal];
  1039. [uploads removeAllObjects];
  1040. return;
  1041. }
  1042. NSFileManager *manager = [NSFileManager defaultManager];
  1043. NSDictionary *upload = [uploads objectAtIndex:0];
  1044. int multiUpload = [[upload objectForKey:MGMUMultiUpload] intValue];
  1045. if (multiUpload==1) {
  1046. [multiUploadLinks release];
  1047. multiUploadLinks = [NSMutableArray new];
  1048. }
  1049. if (![manager fileExistsAtPath:[upload objectForKey:MGMUPath]]) {
  1050. [uploads removeObject:upload];
  1051. [self processNextUpload];
  1052. return;
  1053. }
  1054. [menuItem setImage:[NSImage imageNamed:@"menuiconupload"]];
  1055. [self processEvent:([[upload objectForKey:MGMUAutomatic] boolValue] ? MGMEUploadingAutomatic : MGMEUploading) path:[upload objectForKey:MGMUPath]];
  1056. int uploadNameType = [[[NSUserDefaults standardUserDefaults] objectForKey:MGMUploadName] intValue];
  1057. NSString *randomizedName = [[NSString stringWithFormat:@"%f", [[NSDate date] timeIntervalSince1970]] MD5];
  1058. NSString *name = [[upload objectForKey:MGMUPath] lastPathComponent];
  1059. if ((uploadNameType==0 && [[upload objectForKey:MGMUAutomatic] boolValue]) || uploadNameType==1)
  1060. name = [randomizedName stringByAppendingPathExtension:[name pathExtension]];
  1061. if ([currentPlugIn respondsToSelector:@selector(sendFileAtPath:withName:multiUpload:)]) {
  1062. [currentPlugIn sendFileAtPath:[upload objectForKey:MGMUPath] withName:name multiUpload:multiUpload];
  1063. } else {
  1064. [currentPlugIn sendFileAtPath:[upload objectForKey:MGMUPath] withName:name];
  1065. }
  1066. } else {
  1067. NSString *osxMode = [[NSUserDefaults standardUserDefaults] stringForKey:@"AppleInterfaceStyle"];
  1068. if ([osxMode isEqualTo:@"Dark"]) {
  1069. [menuItem setImage:[NSImage imageNamed:@"menuiconselected"]];
  1070. } else {
  1071. [menuItem setImage:[NSImage imageNamed:@"menuicon"]];
  1072. }
  1073. }
  1074. }
  1075. - (void)upload:(NSString *)thePath receivedError:(NSError *)theError {
  1076. NSDictionary *upload = [self uploadForPath:thePath];
  1077. if (upload!=nil) {
  1078. NSLog(@"Error: %@", theError);
  1079. if ([[NSUserDefaults standardUserDefaults] boolForKey:MGMGrowlErrors]) {
  1080. [GrowlApplicationBridge notifyWithTitle:[@"Unable to upload" localized] description:[NSString stringWithFormat:@"%@: %@", [[upload objectForKey:MGMUPath] lastPathComponent], [theError localizedDescription]] notificationName:@"UploadError" iconData:[[[NSApplication sharedApplication] applicationIconImage] TIFFRepresentation] priority:1 isSticky:NO clickContext:nil];
  1081. } else {
  1082. NSAlert *alert = [[NSAlert new] autorelease];
  1083. [alert setMessageText:[@"Upload Error" localized]];
  1084. [alert setInformativeText:[NSString stringWithFormat:[@"Unable to upload %@: %@" localized], [[upload objectForKey:MGMUPath] lastPathComponent], [theError localizedDescription]]];
  1085. [alert runModal];
  1086. }
  1087. [uploads removeObject:upload];
  1088. [self processNextUpload];
  1089. }
  1090. }
  1091. - (void)uploadFinished:(NSString *)thePath url:(NSURL *)theURL {
  1092. NSDictionary *upload = [self uploadForPath:thePath];
  1093. if (upload!=nil) {
  1094. int multiUpload = [[upload objectForKey:MGMUMultiUpload] intValue];
  1095. [self processEvent:([[upload objectForKey:MGMUAutomatic] boolValue] ? MGMEUploadedAutomatic : MGMEUploaded) path:[upload objectForKey:MGMUPath] url:theURL];
  1096. //No need to bother the clip board when there will end up being a multi upload url.
  1097. if (multiUpload==0 || multiUpload==4) {
  1098. NSPasteboard *pboard = [NSPasteboard generalPasteboard];
  1099. [pboard declareTypes:[NSArray arrayWithObjects:MGMNSStringPboardType, MGMNSPasteboardTypeString, nil] owner:nil];
  1100. [pboard setString:[theURL absoluteString] forType:MGMNSStringPboardType];
  1101. [pboard setString:[theURL absoluteString] forType:MGMNSPasteboardTypeString];
  1102. }
  1103. [self addURLToHistory:theURL];
  1104. if (multiUpload>=1 && multiUpload!=4) {
  1105. [multiUploadLinks addObject:theURL];
  1106. }
  1107. if (multiUpload==3) {
  1108. if ([currentPlugIn respondsToSelector:@selector(createMultiUploadPage)]) {
  1109. [currentPlugIn createMultiUploadPage];
  1110. } else {
  1111. NSString *randomizedName = [[NSString stringWithFormat:@"%f", [[NSDate date] timeIntervalSince1970]] MD5];
  1112. NSString *htmlPath = [NSString stringWithFormat:@"/tmp/CocoaShare_%@.htm", randomizedName];
  1113. NSString *imageHTML = [NSString stringWithContentsOfFile:[[self currentMUTheme] stringByAppendingPathComponent:@"image.html"] encoding:NSUTF8StringEncoding error:nil];
  1114. if (imageHTML==nil) {
  1115. [uploads removeObject:upload];
  1116. [self processNextUpload];
  1117. return;
  1118. }
  1119. NSString *fileHTML = [NSString stringWithContentsOfFile:[[self currentMUTheme] stringByAppendingPathComponent:@"file.html"] encoding:NSUTF8StringEncoding error:nil];
  1120. [[NSFileManager defaultManager] createFileAtPath:htmlPath contents:nil attributes:nil];
  1121. NSFileHandle *multiUploadHtml = [NSFileHandle fileHandleForWritingAtPath:htmlPath];
  1122. [multiUploadHtml writeData:[NSData dataWithContentsOfFile:[[self currentMUTheme] stringByAppendingPathComponent:@"header.html"]]];
  1123. NSArray *imageExtensions = [NSArray arrayWithObjects:@"jpg", @"jpeg", @"png", @"bmp", @"gif", nil];
  1124. for (int i=0; i<[multiUploadLinks count]; i++) {
  1125. NSURL *link = [multiUploadLinks objectAtIndex:i];
  1126. NSString *linkString = [link absoluteString];
  1127. if ([imageExtensions containsObject:[[link pathExtension] lowercaseString]]) {
  1128. [multiUploadHtml writeData:[[imageHTML replace:@"{url}" with:linkString] dataUsingEncoding:NSUTF8StringEncoding]];
  1129. } else {
  1130. [multiUploadHtml writeData:[[fileHTML replace:@"{url}" with:linkString] dataUsingEncoding:NSUTF8StringEncoding]];
  1131. }
  1132. }
  1133. [multiUploadHtml writeData:[NSData dataWithContentsOfFile:[[self currentMUTheme] stringByAppendingPathComponent:@"footer.html"]]];
  1134. [multiUploadHtml closeFile];
  1135. [self addPathToUploads:htmlPath automaticFilter:nil multiUpload:4];
  1136. }
  1137. }
  1138. if (multiUpload==4) {
  1139. [[NSFileManager defaultManager] removeItemAtPath:[upload objectForKey:MGMUPath]];
  1140. }
  1141. [uploads removeObject:upload];
  1142. [self processNextUpload];
  1143. }
  1144. }
  1145. - (void)multiUploadPageCreated:(NSURL *)theURL {
  1146. NSPasteboard *pboard = [NSPasteboard generalPasteboard];
  1147. [pboard declareTypes:[NSArray arrayWithObjects:MGMNSStringPboardType, MGMNSPasteboardTypeString, nil] owner:nil];
  1148. [pboard setString:[theURL absoluteString] forType:MGMNSStringPboardType];
  1149. [pboard setString:[theURL absoluteString] forType:MGMNSPasteboardTypeString];
  1150. [self addURLToHistory:theURL];
  1151. }
  1152. @end