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.
1243 lines
52 KiB
1243 lines
52 KiB
//
|
|
// MGMController.m
|
|
// CocoaShare
|
|
//
|
|
// Created by Mr. Gecko on 1/15/11.
|
|
// Copyright (c) 2015 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
|
//
|
|
|
|
#import "MGMController.h"
|
|
#import "MGMPathSubscriber.h"
|
|
#import "MGMLoginItems.h"
|
|
#import "MGMAddons.h"
|
|
#import "MGMMenuItem.h"
|
|
#import "RegexKitLite.h"
|
|
#import <MGMUsers/MGMUsers.h>
|
|
#import <GeckoReporter/GeckoReporter.h>
|
|
#import <Growl/GrowlApplicationBridge.h>
|
|
#import <Carbon/Carbon.h>
|
|
|
|
NSString * const MGMCopyright = @"Copyright (c) 2015 Mr. Gecko's Media (James Coleman). http://mrgeckosmedia.com/ All rights reserved.";
|
|
NSString * const MGMVersion = @"MGMVersion";
|
|
NSString * const MGMLaunchCount = @"MGMLaunchCount";
|
|
|
|
NSString * const MGMDisplay = @"MGMDisplay";
|
|
NSString * const MGMStartup = @"MGMStartup";
|
|
NSString * const MGMUploadName = @"MGMUploadName";
|
|
NSString * const MGMHistoryCount = @"MGMHistoryCount";
|
|
NSString * const MGMGrowlErrors = @"MGMGrowlErrors";
|
|
NSString * const MGMUploadLimit = @"MGMUploadLimit";
|
|
|
|
NSString * const MGMHistoryPlist = @"history.plist";
|
|
NSString * const MGMHURL = @"url";
|
|
NSString * const MGMHInfo = @"info";
|
|
NSString * const MGMHDate = @"date";
|
|
|
|
NSString * const MGMESound = @"MGME%dSound";
|
|
NSString * const MGMEPath = @"MGME%dPath";
|
|
NSString * const MGMEDelete = @"MGME%dDelete";
|
|
NSString * const MGMEGrowl = @"MGME%dGrowl";
|
|
const int MGMEUploadingAutomatic = 0;
|
|
const int MGMEUploadedAutomatic = 1;
|
|
const int MGMEUploading = 2;
|
|
const int MGMEUploaded = 3;
|
|
NSString * const MGMEventNotification = @"MGMEventNotification";
|
|
NSString * const MGMEvent = @"event";
|
|
NSString * const MGMEventPath = @"path";
|
|
NSString * const MGMEventURL = @"URL";
|
|
|
|
NSString * const MGMFiltersPlist = @"filters.plist";
|
|
NSString * const MGMFID = @"id";
|
|
NSString * const MGMFPath = @"path";
|
|
NSString * const MGMFFilter = @"filter";
|
|
|
|
NSString * const MGMResizePlist = @"resize.plist";
|
|
NSString * const MGMRID = @"id";
|
|
NSString * const MGMRWidth = @"width";
|
|
NSString * const MGMRHeight = @"height";
|
|
NSString * const MGMRScale = @"scale";
|
|
NSString * const MGMRFilters = @"filters";
|
|
NSString * const MGMRNetworks = @"networks";
|
|
NSString * const MGMRIPPrefix = @"IPPrefix";
|
|
|
|
NSString * const MGMPluginFolder = @"PlugIns";
|
|
NSString * const MGMCurrentPlugIn = @"MGMCurrentPlugIn";
|
|
|
|
NSString * const MGMMUThemesFolder = @"Multi Upload Themes";
|
|
NSString * const MGMCurrentMUTheme = @"MGMCurrentMUTheme";
|
|
|
|
NSString * const MGMKCType = @"application password";
|
|
NSString * const MGMKCName = @"CocoaShare";
|
|
|
|
NSString * const MGMUPath = @"path";
|
|
NSString * const MGMUAutomatic = @"automatic";
|
|
NSString * const MGMUMultiUpload = @"multiUpload";
|
|
NSString * const MGMNSStringPboardType = @"NSStringPboardType";
|
|
NSString * const MGMNSPasteboardTypeString = @"public.utf8-plain-text";
|
|
|
|
OSStatus frontAppChanged(EventHandlerCallRef nextHandler, EventRef theEvent, void *userData) {
|
|
ProcessSerialNumber thisProcess;
|
|
GetCurrentProcess(&thisProcess);
|
|
ProcessSerialNumber newProcess;
|
|
GetFrontProcess(&newProcess);
|
|
Boolean same;
|
|
SameProcess(&newProcess, &thisProcess, &same);
|
|
if (!same)
|
|
[(MGMController *)userData setFrontProcess:&newProcess];
|
|
return (CallNextEventHandler(nextHandler, theEvent));
|
|
}
|
|
|
|
static MGMController *MGMSharedController;
|
|
|
|
NSString * const MGMPrimaryInterface = @"PrimaryInterface";
|
|
NSString * const MGMAddresses = @"Addresses";
|
|
|
|
NSString * const MGMIPv4Info = @"State:/Network/Interface/%@/IPv4";
|
|
NSString * const MGMIPv6Info = @"State:/Network/Interface/%@/IPv6";
|
|
NSString * const MGMIPv4State = @"State:/Network/Global/IPv4";
|
|
NSString * const MGMIPv6State = @"State:/Network/Global/IPv6";
|
|
NSString * const MGMAirPortInfo = @"State:/Network/Interface/%@/AirPort";
|
|
|
|
static void systemNotification(SCDynamicStoreRef store, NSArray *changedKeys, void *info) {
|
|
for (int i=0; i<[changedKeys count]; ++i) {
|
|
NSString *key = [changedKeys objectAtIndex:i];
|
|
if ([key isEqual:MGMIPv4State]) {
|
|
NSDictionary *value = (NSDictionary *)SCDynamicStoreCopyValue(store, (CFStringRef)key);
|
|
[(MGMController *)info ipv4Changed:value];
|
|
[value release];
|
|
} else if ([key isEqual:MGMIPv6State]) {
|
|
NSDictionary *value = (NSDictionary *)SCDynamicStoreCopyValue(store, (CFStringRef)key);
|
|
[(MGMController *)info ipv6Changed:value];
|
|
[value release];
|
|
} else if ([key hasSuffix:@"AirPort"]) {
|
|
NSDictionary *value = (NSDictionary *)SCDynamicStoreCopyValue(store, (CFStringRef)key);
|
|
[(MGMController *)info airportChanged:value];
|
|
[value release];
|
|
}
|
|
}
|
|
}
|
|
|
|
@implementation MGMController
|
|
+ (id)sharedController {
|
|
if (MGMSharedController==nil) {
|
|
MGMSharedController = [MGMController new];
|
|
}
|
|
return MGMSharedController;
|
|
}
|
|
- (id)init {
|
|
if (MGMSharedController!=nil) {
|
|
if ((self = [super init]))
|
|
[self release];
|
|
self = MGMSharedController;
|
|
} else if ((self = [super init])) {
|
|
MGMSharedController = self;
|
|
}
|
|
return self;
|
|
}
|
|
- (void)awakeFromNib {
|
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(setup) name:MGMGRDoneNotification object:nil];
|
|
[MGMReporter sharedReporter];
|
|
}
|
|
- (void)setup {
|
|
autoreleaseDrain = [[NSTimer scheduledTimerWithTimeInterval:30.0 target:self selector:@selector(drainAutoreleasePool) userInfo:nil repeats:YES] retain];
|
|
|
|
[GrowlApplicationBridge setGrowlDelegate:nil];
|
|
|
|
NSString *AirPortBSDName = nil;
|
|
CFArrayRef interfaces = SCNetworkInterfaceCopyAll();
|
|
for (int i=0; i<CFArrayGetCount(interfaces); i++) {
|
|
SCNetworkInterfaceRef interface = CFArrayGetValueAtIndex(interfaces, i);
|
|
if ([(NSString *)SCNetworkInterfaceGetInterfaceType(interface) isEqual:@"IEEE80211"]) {
|
|
AirPortBSDName = (NSString *)SCNetworkInterfaceGetBSDName(interface);
|
|
}
|
|
}
|
|
CFRelease(interfaces);
|
|
|
|
SCDynamicStoreContext context = {0, self, NULL, NULL, NULL};
|
|
store = SCDynamicStoreCreate(kCFAllocatorDefault, CFBundleGetIdentifier(CFBundleGetMainBundle()), (SCDynamicStoreCallBack)systemNotification, &context);
|
|
if (!store) {
|
|
NSLog(@"Unable to create store for system configuration %s", SCErrorString(SCError()));
|
|
} else {
|
|
NSMutableArray *keys = [NSMutableArray arrayWithObjects:MGMIPv4State, MGMIPv6State, nil];
|
|
if (AirPortBSDName!=nil) {
|
|
[keys addObject:[NSString stringWithFormat:MGMAirPortInfo, AirPortBSDName]];
|
|
}
|
|
if (!SCDynamicStoreSetNotificationKeys(store, (CFArrayRef)keys, NULL)) {
|
|
NSLog(@"faild to set the store for notifications %s", SCErrorString(SCError()));
|
|
CFRelease(store);
|
|
store = NULL;
|
|
} else {
|
|
runLoop = SCDynamicStoreCreateRunLoopSource(kCFAllocatorDefault, store, 0);
|
|
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoop, kCFRunLoopDefaultMode);
|
|
|
|
|
|
NSDictionary *IPv4State = (NSDictionary *)SCDynamicStoreCopyValue(store, (CFStringRef)MGMIPv4State);
|
|
NSDictionary *IPv4Info = (NSDictionary *)SCDynamicStoreCopyValue(store, (CFStringRef)[NSString stringWithFormat:MGMIPv4Info, [IPv4State objectForKey:MGMPrimaryInterface]]);
|
|
IPv4Addresses = [[IPv4Info objectForKey:MGMAddresses] retain];
|
|
[IPv4Info release];
|
|
[IPv4State release];
|
|
|
|
NSDictionary *IPv6State = (NSDictionary *)SCDynamicStoreCopyValue(store, (CFStringRef)MGMIPv6State);
|
|
NSDictionary *IPv6Info = (NSDictionary *)SCDynamicStoreCopyValue(store, (CFStringRef)[NSString stringWithFormat:MGMIPv6Info, [IPv6State objectForKey:MGMPrimaryInterface]]);
|
|
IPv6Addresses = [[IPv6Info objectForKey:MGMAddresses] retain];
|
|
[IPv6Info release];
|
|
[IPv6State release];
|
|
|
|
if (AirPortBSDName!=nil) {
|
|
lastAirPortState = (NSDictionary *)SCDynamicStoreCopyValue(store, (CFStringRef)[NSString stringWithFormat:MGMAirPortInfo, AirPortBSDName]);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
connectionManager = [[MGMURLConnectionManager managerWithCookieStorage:[MGMUser cookieStorage]] retain];
|
|
|
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
|
[self registerDefaults];
|
|
if ([defaults integerForKey:MGMLaunchCount]!=5) {
|
|
[defaults setInteger:[defaults integerForKey:MGMLaunchCount]+1 forKey:MGMLaunchCount];
|
|
if ([defaults integerForKey:MGMLaunchCount]==5) {
|
|
NSAlert *alert = [[NSAlert new] autorelease];
|
|
[alert setMessageText:[@"Donations" localized]];
|
|
[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]];
|
|
[alert addButtonWithTitle:[@"Yes" localized]];
|
|
[alert addButtonWithTitle:[@"No" localized]];
|
|
int result = [alert runModal];
|
|
if (result==1000)
|
|
[self donate:self];
|
|
}
|
|
}
|
|
|
|
if ([defaults boolForKey:MGMStartup])
|
|
[[MGMLoginItems items] addThisApplication];
|
|
|
|
NSFileManager *manager = [NSFileManager defaultManager];
|
|
if ([manager fileExistsAtPath:[[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMHistoryPlist]]) {
|
|
history = [[NSMutableArray arrayWithContentsOfFile:[[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMHistoryPlist]] retain];
|
|
[self updateMenu];
|
|
} else {
|
|
history = [NSMutableArray new];
|
|
[history writeToFile:[[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMHistoryPlist] atomically:YES];
|
|
[self updateMenu];
|
|
}
|
|
|
|
saveLock = [NSLock new];
|
|
filterWatcher = [MGMPathSubscriber sharedPathSubscriber];
|
|
[filterWatcher setDelegate:self];
|
|
if ([manager fileExistsAtPath:[[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMFiltersPlist]]) {
|
|
filters = [[NSMutableArray arrayWithContentsOfFile:[[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMFiltersPlist]] retain];
|
|
[self updateFilterWatcher];
|
|
} else {
|
|
filters = [NSMutableArray new];
|
|
[self saveFilters];
|
|
}
|
|
filtersEnabled = YES;
|
|
|
|
if ([manager fileExistsAtPath:[[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMResizePlist]]) {
|
|
NSData *plistData = [NSData dataWithContentsOfFile:[[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMResizePlist]];
|
|
NSString *error = nil;
|
|
resizeLogic = [[NSPropertyListSerialization propertyListFromData:plistData mutabilityOption:NSPropertyListMutableContainersAndLeaves format:NULL errorDescription:&error] retain];
|
|
if (error!=nil) {
|
|
NSLog(@"Error processing resize.plist: %@", error);
|
|
}
|
|
} else {
|
|
resizeLogic = [NSMutableArray new];
|
|
[self saveResizeLogic];
|
|
}
|
|
|
|
if ([defaults integerForKey:MGMDisplay]>0)
|
|
[self addMenu];
|
|
|
|
preferences = [MGMPreferences new];
|
|
[preferences addPreferencesPaneClassName:@"MGMGeneralPane"];
|
|
[preferences addPreferencesPaneClassName:@"MGMAccountPane"];
|
|
[preferences addPreferencesPaneClassName:@"MGMAutoUploadPane"];
|
|
[preferences addPreferencesPaneClassName:@"MGMResizePane"];
|
|
[preferences addPreferencesPaneClassName:@"MGMEventsPane"];
|
|
|
|
EventTypeSpec eventType;
|
|
eventType.eventClass = kEventClassApplication;
|
|
eventType.eventKind = kEventAppFrontSwitched;
|
|
EventHandlerUPP handlerUPP = NewEventHandlerUPP(frontAppChanged);
|
|
InstallApplicationEventHandler(handlerUPP, 1, &eventType, self, NULL);
|
|
|
|
if ([defaults integerForKey:MGMLaunchCount]==2)
|
|
[preferences showPreferences];
|
|
|
|
about = [MGMAbout new];
|
|
|
|
uploads = [NSMutableArray new];
|
|
|
|
if ([defaults objectForKey:MGMVersion]==nil || [[defaults objectForKey:MGMVersion] doubleValue]<=0.3) {
|
|
for (int i=0; i<[filters count]; i++) {
|
|
if ([[filters objectAtIndex:i] objectForKey:MGMFID]==nil) {
|
|
CFUUIDRef uuid = CFUUIDCreate(NULL);
|
|
NSString *uuidString = [(NSString *)CFUUIDCreateString(NULL, uuid) autorelease];
|
|
CFRelease(uuid);
|
|
NSDictionary *filter = [[filters objectAtIndex:i] mutableCopy];
|
|
[filter setValue:uuidString forKey:MGMFID];
|
|
[filters replaceObjectAtIndex:i withObject:filter];
|
|
[filter release];
|
|
}
|
|
}
|
|
[self saveFilters];
|
|
}
|
|
[defaults setObject:[[MGMSystemInfo info] applicationVersion] forKey:MGMVersion];
|
|
|
|
[self loadMUThemes];
|
|
[self loadPlugIns];
|
|
}
|
|
- (void)dealloc {
|
|
[autoreleaseDrain invalidate];
|
|
[autoreleaseDrain release];
|
|
if (store!=NULL) {
|
|
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), runLoop, kCFRunLoopDefaultMode);
|
|
CFRelease(store);
|
|
}
|
|
[IPv4Addresses release];
|
|
[IPv6Addresses release];
|
|
[lastAirPortState release];
|
|
[connectionManager release];
|
|
[preferences release];
|
|
[[NSStatusBar systemStatusBar] removeStatusItem:statusItem];
|
|
[statusItem release];
|
|
[menuItem release];
|
|
[history release];
|
|
[filters release];
|
|
[saveLock release];
|
|
[filterWatcher release];
|
|
[accountPlugIns release];
|
|
[plugIns release];
|
|
[uploads release];
|
|
[super dealloc];
|
|
}
|
|
|
|
- (void)registerDefaults {
|
|
NSMutableDictionary *defaults = [NSMutableDictionary dictionary];
|
|
[defaults setObject:[NSNumber numberWithInt:1] forKey:MGMLaunchCount];
|
|
|
|
[defaults setObject:[NSNumber numberWithInt:([[MGMSystemInfo info] isUIElement] ? 2 : 0)] forKey:MGMDisplay];
|
|
[defaults setObject:[NSNumber numberWithBool:[[MGMLoginItems items] thisApplicationExists]] forKey:MGMStartup];
|
|
[defaults setObject:[NSNumber numberWithInt:0] forKey:MGMUploadName];
|
|
[defaults setObject:[NSNumber numberWithInt:5] forKey:MGMHistoryCount];
|
|
[defaults setObject:[NSNumber numberWithInt:5] forKey:MGMUploadLimit];
|
|
|
|
[defaults setObject:[NSNumber numberWithInt:2] forKey:[NSString stringWithFormat:MGMEDelete, MGMEUploadedAutomatic]];
|
|
|
|
[defaults setObject:[[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:MGMMUThemesFolder] stringByAppendingPathComponent:@"White Background"] forKey:MGMCurrentMUTheme];
|
|
[[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
|
|
}
|
|
|
|
- (void)drainAutoreleasePool {
|
|
NSEvent *event = [NSEvent otherEventWithType:NSApplicationDefined location:NSMakePoint(0, 0) modifierFlags:0 timestamp:CFAbsoluteTimeGetCurrent() windowNumber:0 context:nil subtype:0 data1:0 data2:0];
|
|
[[NSApplication sharedApplication] postEvent:event atStart:NO];
|
|
}
|
|
|
|
|
|
- (void)ipv4Changed:(NSDictionary *)theInfo {
|
|
NSDictionary *info = (NSDictionary *)SCDynamicStoreCopyValue(store, (CFStringRef)[NSString stringWithFormat:MGMIPv4Info, [theInfo objectForKey:MGMPrimaryInterface]]);
|
|
[IPv4Addresses autorelease];
|
|
IPv4Addresses = [[info objectForKey:MGMAddresses] retain];
|
|
[info release];
|
|
}
|
|
- (void)ipv6Changed:(NSDictionary *)theInfo {
|
|
NSDictionary *info = (NSDictionary *)SCDynamicStoreCopyValue(store, (CFStringRef)[NSString stringWithFormat:MGMIPv6Info, [theInfo objectForKey:MGMPrimaryInterface]]);
|
|
[IPv6Addresses autorelease];
|
|
IPv6Addresses = [[info objectForKey:MGMAddresses] retain];
|
|
[info release];
|
|
}
|
|
|
|
- (void)airportChanged:(NSDictionary *)theInfo {
|
|
[lastAirPortState autorelease];
|
|
lastAirPortState = [theInfo retain];
|
|
}
|
|
|
|
|
|
- (MGMURLConnectionManager *)connectionManager {
|
|
return connectionManager;
|
|
}
|
|
- (MGMPreferences *)preferences {
|
|
return preferences;
|
|
}
|
|
|
|
- (void)loadPlugIns {
|
|
NSFileManager *manager = [NSFileManager defaultManager];
|
|
[accountPlugIns release];
|
|
accountPlugIns = [NSMutableArray new];
|
|
[plugIns release];
|
|
plugIns = [NSMutableArray new];
|
|
|
|
NSArray *checkPaths = [NSArray arrayWithObjects:[[NSBundle mainBundle] builtInPlugInsPath], [[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMPluginFolder], nil];
|
|
for (int i=0; i<[checkPaths count]; i++) {
|
|
NSArray *plugInsFolder = [manager contentsOfDirectoryAtPath:[checkPaths objectAtIndex:i]];
|
|
for (int p=0; p<[plugInsFolder count]; p++) {
|
|
NSString *path = [[[checkPaths objectAtIndex:i] stringByAppendingPathComponent:[plugInsFolder objectAtIndex:p]] stringByResolvingSymlinksInPath];
|
|
NSBundle *bundle = [NSBundle bundleWithPath:path];
|
|
if (bundle!=nil) {
|
|
Class plugInClass = [bundle principalClass];
|
|
id<MGMPlugInProtocol> plugIn = [[[plugInClass alloc] init] autorelease];
|
|
if (plugIn!=nil && [plugIn respondsToSelector:@selector(isAccountPlugIn)] && [plugIn isAccountPlugIn])
|
|
[accountPlugIns addObject:plugIn];
|
|
else if (plugIn!=nil)
|
|
[plugIns addObject:plugIn];
|
|
}
|
|
}
|
|
}
|
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
|
NSString *currentPlugInName = [defaults objectForKey:MGMCurrentPlugIn];
|
|
BOOL foundCurrentPlugIn = NO;
|
|
for (int i=0; i<[accountPlugIns count]; i++) {
|
|
if ([NSStringFromClass([[accountPlugIns objectAtIndex:i] class]) isEqual:currentPlugInName]) {
|
|
currentPlugIn = [accountPlugIns objectAtIndex:i];
|
|
currentPlugInIndex = i;
|
|
if ([currentPlugIn respondsToSelector:@selector(setCurrentPlugIn:)]) [currentPlugIn setCurrentPlugIn:YES];
|
|
foundCurrentPlugIn = YES;
|
|
break;
|
|
}
|
|
}
|
|
if (!foundCurrentPlugIn && [accountPlugIns count]>0)
|
|
[self setCurrentPlugIn:[accountPlugIns objectAtIndex:0]];
|
|
}
|
|
- (NSArray *)accountPlugIns {
|
|
return accountPlugIns;
|
|
}
|
|
- (NSArray *)plugIns {
|
|
return plugIns;
|
|
}
|
|
- (void)setCurrentPlugIn:(id)thePlugIn {
|
|
int plugInIndex = [accountPlugIns indexOfObject:thePlugIn];
|
|
if (plugInIndex>=0) {
|
|
[self removePassword];
|
|
if ([currentPlugIn respondsToSelector:@selector(setCurrentPlugIn:)]) [currentPlugIn setCurrentPlugIn:NO];
|
|
currentPlugIn = thePlugIn;
|
|
currentPlugInIndex = plugInIndex;
|
|
[[NSUserDefaults standardUserDefaults] setObject:NSStringFromClass([currentPlugIn class]) forKey:MGMCurrentPlugIn];
|
|
if ([currentPlugIn respondsToSelector:@selector(setCurrentPlugIn:)]) [currentPlugIn setCurrentPlugIn:YES];
|
|
}
|
|
}
|
|
- (id<MGMPlugInProtocol>)currentPlugIn {
|
|
return currentPlugIn;
|
|
}
|
|
- (int)currentPlugInIndex {
|
|
return currentPlugInIndex;
|
|
}
|
|
|
|
|
|
- (void)loadMUThemes {
|
|
NSFileManager *manager = [NSFileManager defaultManager];
|
|
[MUThemes release];
|
|
MUThemes = [NSMutableArray new];
|
|
|
|
NSArray *checkPaths = [NSArray arrayWithObjects:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:MGMMUThemesFolder], [[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMMUThemesFolder], nil];
|
|
for (int i=0; i<[checkPaths count]; i++) {
|
|
NSArray *MUThemesFolder = [manager contentsOfDirectoryAtPath:[checkPaths objectAtIndex:i]];
|
|
for (int p=0; p<[MUThemesFolder count]; p++) {
|
|
NSString *path = [[[checkPaths objectAtIndex:i] stringByAppendingPathComponent:[MUThemesFolder objectAtIndex:p]] stringByResolvingSymlinksInPath];
|
|
[MUThemes addObject:path];
|
|
}
|
|
}
|
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
|
NSString *currentMUThemePath = [defaults objectForKey:MGMCurrentMUTheme];
|
|
BOOL foundCurrentMUTheme = NO;
|
|
for (int i=0; i<[MUThemes count]; i++) {
|
|
if ([[MUThemes objectAtIndex:i] isEqual:currentMUThemePath]) {
|
|
currentMUThemeIndex = i;
|
|
foundCurrentMUTheme = YES;
|
|
break;
|
|
}
|
|
}
|
|
if (!foundCurrentMUTheme && [MUThemes count]>0)
|
|
[self setCurrentMUTheme:[MUThemes objectAtIndex:0]];
|
|
}
|
|
- (NSArray *)MUThemes {
|
|
return MUThemes;
|
|
}
|
|
- (void)setCurrentMUTheme:(NSString *)theMUTheme {
|
|
int MUThemeIndex = [MUThemes indexOfObject:theMUTheme];
|
|
if (MUThemeIndex>=0) {
|
|
currentMUThemeIndex = MUThemeIndex;
|
|
[[NSUserDefaults standardUserDefaults] setObject:theMUTheme forKey:MGMCurrentMUTheme];
|
|
}
|
|
}
|
|
- (int)currentMUThemeIndex {
|
|
return currentMUThemeIndex;
|
|
}
|
|
- (NSString *)currentMUTheme {
|
|
return [MUThemes objectAtIndex:currentMUThemeIndex];
|
|
}
|
|
|
|
- (void)setFrontProcess:(ProcessSerialNumber *)theProcess {
|
|
frontProcess = *theProcess;
|
|
/*CFStringRef name;
|
|
CopyProcessName(theProcess, &name);
|
|
if (name!=NULL) {
|
|
NSLog(@"%@ became front", (NSString *)name);
|
|
CFRelease(name);
|
|
}*/
|
|
}
|
|
- (void)becomeFront:(NSWindow *)theWindow {
|
|
if (theWindow!=nil) {
|
|
windowCount++;
|
|
if ([[MGMSystemInfo info] isUIElement])
|
|
[theWindow setLevel:NSFloatingWindowLevel];
|
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(frontWindowClosed:) name:NSWindowWillCloseNotification object:theWindow];
|
|
}
|
|
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
|
|
}
|
|
- (void)resignFront {
|
|
SetFrontProcess(&frontProcess);
|
|
}
|
|
- (void)frontWindowClosed:(NSNotification *)theNotification {
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self name:[theNotification name] object:[theNotification object]];
|
|
windowCount--;
|
|
if (windowCount==0)
|
|
[self resignFront];
|
|
}
|
|
|
|
- (void)addMenu {
|
|
if (statusItem==nil) {
|
|
menuItem = [[MGMMenuItem alloc] initWithFrame:NSZeroRect];
|
|
[menuItem setDelegate:self];
|
|
NSString *osxMode = [[NSUserDefaults standardUserDefaults] stringForKey:@"AppleInterfaceStyle"];
|
|
if ([osxMode isEqualTo:@"Dark"]) {
|
|
[menuItem setImage:[NSImage imageNamed:@"menuiconselected"]];
|
|
[menuItem setAlternateImage:[NSImage imageNamed:@"menuicon"]];
|
|
} else {
|
|
[menuItem setImage:[NSImage imageNamed:@"menuicon"]];
|
|
[menuItem setAlternateImage:[NSImage imageNamed:@"menuiconselected"]];
|
|
}
|
|
[menuItem setToolTip:@"CocoaShare"];
|
|
statusItem = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength] retain];
|
|
[statusItem setView:menuItem];
|
|
}
|
|
}
|
|
- (void)removeMenu {
|
|
if (statusItem!=nil) {
|
|
[[NSStatusBar systemStatusBar] removeStatusItem:statusItem];
|
|
[statusItem release];
|
|
statusItem = nil;
|
|
[menuItem release];
|
|
menuItem = nil;
|
|
}
|
|
}
|
|
- (void)setDockHidden:(BOOL)isHidden {
|
|
NSFileManager *manager = [NSFileManager defaultManager];
|
|
NSBundle *bundle = [NSBundle mainBundle];
|
|
NSString *path = [[bundle bundlePath] stringByAppendingPathComponent:@"Contents/Info.plist"];
|
|
if ([manager isWritableFileAtPath:path]) {
|
|
NSMutableDictionary *infoDict = [NSMutableDictionary dictionaryWithContentsOfFile:path];
|
|
[infoDict setObject:[NSNumber numberWithBool:isHidden] forKey:@"LSUIElement"];
|
|
[infoDict writeToFile:path atomically:NO];
|
|
NSDictionary *attributes = [NSDictionary dictionaryWithObject:[NSDate date] forKey:NSFileModificationDate];
|
|
[manager setAttributes:attributes ofItemAtPath:[bundle bundlePath]];
|
|
|
|
if (isHidden) {
|
|
NSAlert *alert = [[NSAlert new] autorelease];
|
|
[alert setMessageText:[@"Restart Required" localized]];
|
|
[alert setInformativeText:[@"Inorder to hide the dock, you must restart CocoaShare. Do you want to restart CocoaShare now?" localized]];
|
|
[alert addButtonWithTitle:[@"Yes" localized]];
|
|
[alert addButtonWithTitle:[@"No" localized]];
|
|
int result = [alert runModal];
|
|
if (result==1000) {
|
|
//Took from Sparkle.
|
|
NSString *pathToRelaunch = [[NSBundle mainBundle] bundlePath];
|
|
NSString *relaunchPath = [[[NSBundle bundleWithIdentifier:@"org.andymatuschak.Sparkle"] resourcePath] stringByAppendingPathComponent:@"relaunch"];
|
|
[NSTask launchedTaskWithLaunchPath:relaunchPath arguments:[NSArray arrayWithObjects:pathToRelaunch, [NSString stringWithFormat:@"%d", [[NSProcessInfo processInfo] processIdentifier]], nil]];
|
|
[[NSApplication sharedApplication] terminate:self];
|
|
}
|
|
}
|
|
} else {
|
|
NSAlert *alert = [[NSAlert new] autorelease];
|
|
[alert setMessageText:[@"Unable to change dock" localized]];
|
|
[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])]];
|
|
[alert runModal];
|
|
}
|
|
if (!isHidden) {
|
|
ProcessSerialNumber psn = {0, kCurrentProcess};
|
|
TransformProcessType(&psn, kProcessTransformToForegroundApplication);
|
|
[self resignFront];
|
|
[self performSelector:@selector(becomeFront:) withObject:[preferences preferencesWindow] afterDelay:0.0];
|
|
}
|
|
}
|
|
|
|
- (void)menuClicked:(id)sender {
|
|
[statusItem popUpStatusItemMenu:mainMenu];
|
|
}
|
|
- (void)menuDraggingEntered:(id)sender {
|
|
[menuItem setImage:[NSImage imageNamed:@"menuicondrag"]];
|
|
}
|
|
- (void)menuDraggingExited:(id)sender {
|
|
NSString *osxMode = [[NSUserDefaults standardUserDefaults] stringForKey:@"AppleInterfaceStyle"];
|
|
if ([osxMode isEqualTo:@"Dark"]) {
|
|
[menuItem setImage:[NSImage imageNamed:@"menuiconselected"]];
|
|
} else {
|
|
[menuItem setImage:[NSImage imageNamed:@"menuicon"]];
|
|
}
|
|
}
|
|
- (void)menu:(id)sender droppedFiles:(NSArray *)files {
|
|
NSFileManager *manager = [NSFileManager defaultManager];
|
|
for (int i=0; i<[files count]; i++) {
|
|
BOOL directory = NO;
|
|
if ([manager fileExistsAtPath:[files objectAtIndex:i] isDirectory:&directory]) {
|
|
if (directory) {
|
|
NSAlert *alert = [[NSAlert new] autorelease];
|
|
[alert setMessageText:[@"Upload Error" localized]];
|
|
[alert setInformativeText:[@"Uploading of directories is impossible." localized]];
|
|
[alert runModal];
|
|
continue;
|
|
}
|
|
[self addPathToUploads:[files objectAtIndex:i] automaticFilter:nil multiUpload:([files count]==1 ? 0 : (i==0 ? 1 : (i==[files count]-1 ? 3 : 2)))];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (NSMutableArray *)history {
|
|
return history;
|
|
}
|
|
- (void)updateMenu {
|
|
int splitterIndex = 0;
|
|
for (int i=0; i<[mainMenu numberOfItems]; i++) {
|
|
if ([[mainMenu itemAtIndex:i] isSeparatorItem]) {
|
|
splitterIndex = i;
|
|
break;
|
|
}
|
|
[mainMenu removeItemAtIndex:i];
|
|
i--;
|
|
}
|
|
if ([history count]>0) {
|
|
for (int i=0; i<[history count]; i++) {
|
|
NSDictionary *historyItem = [history objectAtIndex:i];
|
|
NSMenuItem *item = [[NSMenuItem new] autorelease];
|
|
NSDateFormatter *formatter = [[NSDateFormatter new] autorelease];
|
|
[formatter setDateFormat:[@"MMMM d, yyyy h:mm:ss a" localized]];
|
|
NSString *date = [formatter stringFromDate:[historyItem objectForKey:MGMHDate]];
|
|
if (date!=nil)
|
|
[item setTitle:date];
|
|
else
|
|
[item setTitle:[NSString stringWithFormat:@"%@", [historyItem objectForKey:MGMHDate]]];
|
|
[item setRepresentedObject:[historyItem objectForKey:MGMHURL]];
|
|
[item setTarget:self];
|
|
[item setAction:@selector(copyHistoryItem:)];
|
|
[mainMenu insertItem:item atIndex:splitterIndex];
|
|
}
|
|
} else {
|
|
NSMenuItem *item = [[NSMenuItem new] autorelease];
|
|
[item setTitle:[@"No Upload History" localized]];
|
|
[item setEnabled:NO];
|
|
[mainMenu insertItem:item atIndex:splitterIndex];
|
|
}
|
|
}
|
|
- (IBAction)copyHistoryItem:(id)sender {
|
|
NSPasteboard *pboard = [NSPasteboard generalPasteboard];
|
|
[pboard declareTypes:[NSArray arrayWithObjects:MGMNSStringPboardType, MGMNSPasteboardTypeString, nil] owner:nil];
|
|
[pboard setString:[sender representedObject] forType:MGMNSStringPboardType];
|
|
[pboard setString:[sender representedObject] forType:MGMNSPasteboardTypeString];
|
|
}
|
|
- (void)addURLToHistory:(NSURL *)theURL {
|
|
[history addObject:[NSDictionary dictionaryWithObjectsAndKeys:[theURL absoluteString], MGMHURL, [NSDate date], MGMHDate, nil]];
|
|
int maxHistoryItems = [[NSUserDefaults standardUserDefaults] integerForKey:MGMHistoryCount];
|
|
int itemsToDelete = [history count]-maxHistoryItems;
|
|
if (itemsToDelete>0) {
|
|
for (int i=0; i<itemsToDelete; i++) {
|
|
[history removeObjectAtIndex:0];
|
|
}
|
|
}
|
|
[history writeToFile:[[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMHistoryPlist] atomically:YES];
|
|
[self updateMenu];
|
|
}
|
|
- (void)uploadFinished:(NSString *)thePath url:(NSURL *)theURL info:(id)theInfo {
|
|
[history addObject:[NSDictionary dictionaryWithObjectsAndKeys:[theURL absoluteString], MGMHURL, theInfo, MGMHInfo, [NSDate date], MGMHDate, nil]];
|
|
int maxHistoryItems = [[NSUserDefaults standardUserDefaults] integerForKey:MGMHistoryCount];
|
|
int itemsToDelete = [history count]-maxHistoryItems;
|
|
if (itemsToDelete>0) {
|
|
for (int i=0; i<itemsToDelete; i++) {
|
|
[history removeObjectAtIndex:0];
|
|
}
|
|
}
|
|
[history writeToFile:[[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMHistoryPlist] atomically:YES];
|
|
[self updateMenu];
|
|
}
|
|
|
|
- (IBAction)uploadFile:(id)sender {
|
|
NSOpenPanel *panel = [NSOpenPanel openPanel];
|
|
[panel setCanChooseFiles:YES];
|
|
[panel setCanChooseDirectories:NO];
|
|
[panel setResolvesAliases:YES];
|
|
[panel setAllowsMultipleSelection:YES];
|
|
[panel setTitle:[@"Choose File(s)" localized]];
|
|
[panel setPrompt:[@"Choose" localized]];
|
|
[self becomeFront:nil];
|
|
int returnCode = [panel runModal];
|
|
if (returnCode==NSOKButton) {
|
|
for (int i=0; i<[[panel URLs] count]; i++) {
|
|
[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)))];
|
|
}
|
|
}
|
|
[self resignFront];
|
|
}
|
|
|
|
- (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag {
|
|
if (!flag)
|
|
[self preferences:self];
|
|
return YES;
|
|
}
|
|
- (void)application:(NSApplication *)theApplication openFiles:(NSArray *)theFiles {
|
|
for (int i=0; i<[theFiles count]; i++) {
|
|
[self addPathToUploads:[theFiles objectAtIndex:i] automaticFilter:nil multiUpload:([theFiles count]==1 ? 0 : (i==0 ? 1 : (i==[theFiles count]-1 ? 3 : 2)))];
|
|
}
|
|
}
|
|
|
|
- (IBAction)disableFilters:(id)sender {
|
|
filtersEnabled = !filtersEnabled;
|
|
[disableFilters setTitle:(filtersEnabled ? [@"Disable Auto Upload" localized] : [@"Enable Auto Upload" localized])];
|
|
}
|
|
- (IBAction)about:(id)sender {
|
|
[about show];
|
|
[self becomeFront:[about window]];
|
|
}
|
|
- (IBAction)preferences:(id)sender {
|
|
[preferences showPreferences];
|
|
[self becomeFront:[preferences preferencesWindow]];
|
|
}
|
|
- (IBAction)donate:(id)sender {
|
|
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"https://mrgeckosmedia.com/donate?purpose=cocoashare"]];
|
|
}
|
|
- (IBAction)quit:(id)sender {
|
|
[[MGMLoginItems items] removeThisApplication];
|
|
[[NSApplication sharedApplication] terminate:self];
|
|
}
|
|
|
|
- (NSMutableArray *)filters {
|
|
return filters;
|
|
}
|
|
- (void)saveFilters {
|
|
if (saveCount==2)
|
|
return;
|
|
saveCount++;
|
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
|
[saveLock lock];
|
|
[filters writeToFile:[[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMFiltersPlist] atomically:YES];
|
|
[self updateFilterWatcher];
|
|
saveCount--;
|
|
[pool drain];
|
|
[saveLock unlock];
|
|
}
|
|
- (MGMPathSubscriber *)filterWatcher {
|
|
return filterWatcher;
|
|
}
|
|
- (NSArray *)filtersForPath:(NSString *)thePath {
|
|
NSMutableArray *filtersFound = [NSMutableArray array];
|
|
for (int i=0; i<[filters count]; i++) {
|
|
NSString *path = [[[filters objectAtIndex:i] objectForKey:MGMFPath] stringByExpandingTildeInPath];
|
|
if ([path isEqual:thePath])
|
|
[filtersFound addObject:[filters objectAtIndex:i]];
|
|
}
|
|
return filtersFound;
|
|
}
|
|
- (void)updateFilterWatcher {
|
|
[filterWatcher removeAllPaths];
|
|
for (int i=0; i<[filters count]; i++) {
|
|
NSDictionary *filter = [filters objectAtIndex:i];
|
|
if (![[filter objectForKey:MGMFFilter] isEqual:@""]) {
|
|
NSString *path = [[filter objectForKey:MGMFPath] stringByExpandingTildeInPath];
|
|
if (![path isEqual:@""])
|
|
[filterWatcher addPath:path];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)subscribedPathChanged:(NSString *)thePath {
|
|
NSLog(@"Changed: %@", thePath);
|
|
if (filtersEnabled) {
|
|
NSFileManager *manager = [NSFileManager defaultManager];
|
|
int uploadLimit = [[NSUserDefaults standardUserDefaults] integerForKey:MGMUploadLimit];
|
|
NSDate *dateLimit = [NSDate dateWithTimeIntervalSinceNow:-uploadLimit];
|
|
NSArray *filtersFound = [self filtersForPath:thePath];
|
|
NSArray *files = [manager contentsOfDirectoryAtPath:thePath];
|
|
for (int i=0; i<[files count]; i++) {
|
|
NSString *file = [files objectAtIndex:i];
|
|
NSString *fullPath = [thePath stringByAppendingPathComponent:file];
|
|
NSDictionary *attributes = [manager attributesOfItemAtPath:fullPath];
|
|
if (uploadLimit!=0 && [[attributes objectForKey:NSFileCreationDate] earlierDate:dateLimit]!=dateLimit)
|
|
continue;
|
|
BOOL directory = NO;
|
|
if ([manager fileExistsAtPath:fullPath isDirectory:&directory] && !directory) {
|
|
for (int f=0; f<[filtersFound count]; f++) {
|
|
NSString *filter = [[filtersFound objectAtIndex:f] objectForKey:MGMFFilter];
|
|
if ([filter hasPrefix:@"MD:"]) {
|
|
if ([filter hasPrefix:@"MD: "])
|
|
filter = [filter substringFromIndex:4];
|
|
else
|
|
filter = [filter substringFromIndex:3];
|
|
|
|
MDItemRef metadata = MDItemCreate(kCFAllocatorDefault, (CFStringRef)fullPath);
|
|
if (metadata!=NULL) {
|
|
NSArray *items = (NSArray *)MDItemCopyAttributeNames(metadata);
|
|
for (int m=0; m<[items count]; m++) {
|
|
id item = (id)MDItemCopyAttribute(metadata, (CFStringRef)[items objectAtIndex:m]);
|
|
if ([[items objectAtIndex:m] isMatchedByRegex:filter]) {
|
|
[self addPathToUploads:fullPath automaticFilter:[[filtersFound objectAtIndex:f] objectForKey:MGMFID]];
|
|
} else if ([item isKindOfClass:[NSString class]] && [item isMatchedByRegex:filter]) {
|
|
[self addPathToUploads:fullPath automaticFilter:[[filtersFound objectAtIndex:f] objectForKey:MGMFID]];
|
|
}
|
|
if (item!=nil)
|
|
CFRelease((CFTypeRef)item);
|
|
}
|
|
if (items!=nil)
|
|
CFRelease((CFArrayRef)items);
|
|
CFRelease(metadata);
|
|
} else {
|
|
NSLog(@"Unable to get metadata of %@", fullPath);
|
|
}
|
|
|
|
NSDictionary *extendedAttributes = nil;
|
|
if ([manager respondsToSelector:@selector(attributesOfItemAtPath:error:)]) {
|
|
extendedAttributes = [[manager attributesOfItemAtPath:fullPath error:nil] objectForKey:@"NSFileExtendedAttributes"];
|
|
} else {
|
|
extendedAttributes = [[manager fileSystemAttributesAtPath:fullPath] objectForKey:@"NSFileExtendedAttributes"];
|
|
}
|
|
for (int a=0; a<[[extendedAttributes allKeys] count]; a++) {
|
|
if ([[[extendedAttributes allKeys] objectAtIndex:a] isMatchedByRegex:filter]) {
|
|
[self addPathToUploads:fullPath automaticFilter:[[filtersFound objectAtIndex:f] objectForKey:MGMFID]];
|
|
} else if ([[extendedAttributes objectForKey:[[extendedAttributes allKeys] objectAtIndex:a]] isKindOfClass:[NSString class]] && [[extendedAttributes objectForKey:[[extendedAttributes allKeys] objectAtIndex:a]] isMatchedByRegex:filter]) {
|
|
[self addPathToUploads:fullPath automaticFilter:[[filtersFound objectAtIndex:f] objectForKey:MGMFID]];
|
|
}
|
|
}
|
|
} else {
|
|
if ([file isMatchedByRegex:filter]) {
|
|
[self addPathToUploads:fullPath automaticFilter:[[filtersFound objectAtIndex:f] objectForKey:MGMFID]];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
- (NSMutableArray *)resizeLogic {
|
|
return resizeLogic;
|
|
}
|
|
- (void)resizeIfNeeded:(NSString *)thePath {
|
|
[self resizeIfNeeded:thePath filterID:nil];
|
|
}
|
|
- (void)resizeIfNeeded:(NSString *)thePath filterID:(NSString *)theID {
|
|
NSArray *extensions = [NSArray arrayWithObjects:@"jpg", @"jpeg", @"png", @"tif", @"tiff", @"bmp", nil];
|
|
if (![extensions containsObject:[[thePath pathExtension] lowercaseString]])
|
|
return;
|
|
NSDictionary *lastMatch = nil;
|
|
BOOL matchedOnFilter = NO;
|
|
BOOL matchedOnNetwork = NO;
|
|
BOOL matchedOnPrefix = NO;
|
|
for (int i=0; i<[resizeLogic count]; i++) {
|
|
NSDictionary *logic = [resizeLogic objectAtIndex:i];
|
|
BOOL prefixMatch = NO;
|
|
if (![[logic objectForKey:MGMRIPPrefix] isEqual:@""]) {
|
|
NSString *prefix = [logic objectForKey:MGMRIPPrefix];
|
|
for (int ip=0; ip<[IPv4Addresses count]; ip++) {
|
|
if ([[IPv4Addresses objectAtIndex:ip] hasPrefix:prefix]) {
|
|
prefixMatch = YES;
|
|
}
|
|
}
|
|
for (int ip=0; ip<[IPv6Addresses count]; ip++) {
|
|
if ([[IPv6Addresses objectAtIndex:ip] hasPrefix:prefix]) {
|
|
prefixMatch = YES;
|
|
}
|
|
}
|
|
}
|
|
BOOL networkMatch = (lastAirPortState!=nil && [lastAirPortState objectForKey:@"SSID"]!=nil && [[logic objectForKey:MGMRNetworks] containsObject:[[[NSString alloc] initWithData:[lastAirPortState objectForKey:@"SSID"] encoding:NSUTF8StringEncoding] autorelease]]);
|
|
BOOL filterMatch = (theID!=nil && [[logic objectForKey:MGMRFilters] containsObject:theID]);
|
|
NSLog(@"%d %d %d", prefixMatch, networkMatch, filterMatch);
|
|
if ([[logic objectForKey:MGMRFilters] count]==0 && (networkMatch || prefixMatch)) {//No filters and network or prefix match.
|
|
if (lastMatch!=nil && matchedOnFilter) {//If this is a network match and previous was a filter match, do not match.
|
|
continue;
|
|
}
|
|
if (lastMatch!=nil && matchedOnNetwork && !networkMatch) {//If this isn't a network match, yet the previous was, do not match.
|
|
continue;
|
|
}
|
|
} else if ([[logic objectForKey:MGMRFilters] count]==0) {//No filters and not network or prefix.
|
|
if (lastMatch!=nil && (matchedOnNetwork || matchedOnPrefix || matchedOnFilter)) {//If previous matches on network, prefix, or filter, do not match.
|
|
continue;
|
|
}
|
|
} else if ([[logic objectForKey:MGMRFilters] count]!=0 && !filterMatch) {//Cannot match if filteres exist, but not matched.
|
|
continue;
|
|
} else if (filterMatch) {//If filtere match.
|
|
if (networkMatch || prefixMatch) {//Network or prefix match.
|
|
if (lastMatch!=nil && matchedOnFilter && matchedOnNetwork && !networkMatch) {//Previous matched on network and this isn't a network match, do not match.
|
|
continue;
|
|
}
|
|
} else {//Not network or prefix match.
|
|
if (lastMatch!=nil && matchedOnFilter && (matchedOnNetwork || matchedOnFilter)) {//If was a network match, do not match.
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
if (([[logic objectForKey:MGMRWidth] intValue]==0 || [[logic objectForKey:MGMRHeight] intValue]==0) && [[logic objectForKey:MGMRScale] intValue]==0) {//Incorrect resize logic.
|
|
continue;
|
|
}
|
|
lastMatch = logic;
|
|
matchedOnFilter = filterMatch;
|
|
matchedOnNetwork = networkMatch;
|
|
matchedOnPrefix = prefixMatch;
|
|
}
|
|
|
|
if (lastMatch!=nil) {
|
|
int scale = [[lastMatch objectForKey:MGMRScale] intValue];
|
|
if (scale!=0) {
|
|
[self resize:thePath toSize:NSZeroSize scale:1-(((float)scale)/100)];
|
|
} else {
|
|
[self resize:thePath toSize:NSMakeSize([[lastMatch objectForKey:MGMRWidth] floatValue], [[lastMatch objectForKey:MGMRHeight] floatValue]) scale:0.0];
|
|
}
|
|
}
|
|
}
|
|
- (void)resize:(NSString *)thePath toSize:(NSSize)theSize scale:(float)theScale {
|
|
NSString *extension = [[thePath pathExtension] lowercaseString];
|
|
CFStringRef type = kUTTypeImage;
|
|
if ([extension isEqual:@"jpg"] || [extension isEqual:@"jpeg"]) {
|
|
type = kUTTypeJPEG;
|
|
} else if ([extension isEqual:@"png"]) {
|
|
type = kUTTypePNG;
|
|
} else if ([extension isEqual:@"bmp"]) {
|
|
type = kUTTypeBMP;
|
|
} else if ([extension isEqual:@"tif"] || [extension isEqual:@"tiff"]) {
|
|
type = kUTTypeTIFF;
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
CFURLRef fileURL = (__bridge CFURLRef)[NSURL fileURLWithPath:[thePath stringByExpandingTildeInPath]];
|
|
CGImageSourceRef source = CGImageSourceCreateWithURL(fileURL, NULL);
|
|
if (source==NULL) {
|
|
NSLog(@"Unable to create image source: %@", thePath);
|
|
return;
|
|
}
|
|
CGImageRef imageRef = CGImageSourceCreateImageAtIndex(source, 0, NULL);
|
|
CFRelease(source);
|
|
if (imageRef==NULL) {
|
|
NSLog(@"Unable to create image: %@", thePath);
|
|
return;
|
|
}
|
|
NSSize size = NSMakeSize(CGImageGetWidth(imageRef), CGImageGetHeight(imageRef));
|
|
|
|
float scaleFactor = 0.0;
|
|
float scaledWidth = 0.0;
|
|
float scaledHeight = 0.0;
|
|
if (NSEqualSizes(theSize, NSZeroSize)) {
|
|
scaleFactor = theScale;
|
|
} else {
|
|
float widthFactor = theSize.width / size.width;
|
|
float heightFactor = theSize.height / size.height;
|
|
|
|
if (widthFactor < heightFactor)
|
|
scaleFactor = widthFactor;
|
|
else
|
|
scaleFactor = heightFactor;
|
|
}
|
|
scaledWidth = size.width * scaleFactor;
|
|
scaledHeight = size.height * scaleFactor;
|
|
if (size.width<=scaledWidth && size.height<=scaledHeight) {
|
|
CGImageRelease(imageRef);
|
|
return;//Output larger or equal to input.
|
|
}
|
|
NSLog(@"Resizing: %@", thePath);
|
|
NSLog(@"Width: %f Height: %f", size.width, size.height);
|
|
NSLog(@"Width: %f Height: %f", scaledWidth, scaledHeight);
|
|
|
|
NSSize newSize = NSMakeSize(scaledWidth, scaledHeight);
|
|
if (!NSEqualSizes(newSize, NSZeroSize)) {
|
|
CGContextRef bitmap = CGBitmapContextCreate(NULL, newSize.width, newSize.height, CGImageGetBitsPerComponent(imageRef), 0, CGImageGetColorSpace(imageRef), (CGBitmapInfo)((type==kUTTypePNG || type==kUTTypeTIFF) ? kCGImageAlphaPremultipliedLast : kCGImageAlphaNoneSkipLast));
|
|
CGContextSetInterpolationQuality(bitmap, kCGInterpolationHigh);
|
|
CGContextDrawImage(bitmap, NSMakeRect(0, 0, newSize.width, newSize.height), imageRef);
|
|
CGImageRef newImage = CGBitmapContextCreateImage(bitmap);
|
|
CGContextRelease(bitmap);
|
|
|
|
|
|
CGImageDestinationRef destination = CGImageDestinationCreateWithURL(fileURL, type, 1, NULL);
|
|
if (!destination) {
|
|
NSLog(@"Failed to create CGImageDestination for %@", thePath);
|
|
CGImageRelease(newImage);
|
|
CGImageRelease(imageRef);
|
|
return;
|
|
}
|
|
|
|
CGImageDestinationAddImage(destination, newImage, nil);
|
|
if (!CGImageDestinationFinalize(destination)) {
|
|
NSLog(@"Failed to write image to %@", thePath);
|
|
}
|
|
|
|
CFRelease(destination);
|
|
CGImageRelease(newImage);
|
|
}
|
|
CGImageRelease(imageRef);
|
|
}
|
|
- (void)saveResizeLogic {
|
|
if (saveCount==2)
|
|
return;
|
|
saveCount++;
|
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
|
[saveLock lock];
|
|
[resizeLogic writeToFile:[[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMResizePlist] atomically:YES];
|
|
saveCount--;
|
|
[pool drain];
|
|
[saveLock unlock];
|
|
}
|
|
|
|
- (void)removePassword {
|
|
NSArray *items = [MGMKeychain items:MGMKCType withName:MGMKCName service:MGMKCName account:MGMKCName];
|
|
if ([items count]>0)
|
|
[[items objectAtIndex:0] remove];
|
|
}
|
|
- (void)setPassword:(NSString *)thePassword {
|
|
NSArray *items = [MGMKeychain items:MGMKCType withName:MGMKCName service:MGMKCName account:MGMKCName];
|
|
if ([items count]>0) {
|
|
[[items objectAtIndex:0] setString:thePassword];
|
|
} else {
|
|
[MGMKeychain addItem:MGMKCType withName:MGMKCName service:MGMKCName account:MGMKCName password:thePassword];
|
|
}
|
|
}
|
|
- (NSString *)password {
|
|
NSArray *items = [MGMKeychain items:MGMKCType withName:MGMKCName service:MGMKCName account:MGMKCName];
|
|
if ([items count]>0)
|
|
return [[items objectAtIndex:0] string];
|
|
return nil;
|
|
}
|
|
|
|
- (void)processEvent:(int)theEvent path:(NSString *)thePath {
|
|
[self processEvent:theEvent path:thePath url:nil];
|
|
}
|
|
- (void)processEvent:(int)theEvent path:(NSString *)thePath url:(NSURL *)theURL {
|
|
NSMutableDictionary *eventInfo = [NSMutableDictionary dictionary];
|
|
[eventInfo setObject:[NSNumber numberWithInt:theEvent] forKey:MGMEvent];
|
|
[eventInfo setObject:thePath forKey:MGMEventPath];
|
|
if (theURL!=nil)
|
|
[eventInfo setObject:theURL forKey:MGMEventURL];
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:MGMEventNotification object:self userInfo:eventInfo];
|
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
|
NSFileManager *manager = [NSFileManager defaultManager];
|
|
|
|
NSString *soundPath = [defaults objectForKey:[NSString stringWithFormat:MGMESound, theEvent]];
|
|
if (soundPath!=nil && [manager fileExistsAtPath:soundPath]) {
|
|
NSSound *sound = [[NSSound alloc] initWithContentsOfFile:soundPath byReference:YES];
|
|
[sound setDelegate:self];
|
|
[sound play];
|
|
}
|
|
|
|
NSString *path = [[defaults objectForKey:[NSString stringWithFormat:MGMEPath, theEvent]] stringByExpandingTildeInPath];
|
|
if ([manager fileExistsAtPath:path])
|
|
[manager moveItemAtPath:thePath toPath:path];
|
|
|
|
int deleteFile = [[defaults objectForKey:[NSString stringWithFormat:MGMEDelete, theEvent]] intValue];
|
|
if (deleteFile!=0 && [manager fileExistsAtPath:thePath]) {
|
|
if (deleteFile==1) {
|
|
[manager removeItemAtPath:thePath];
|
|
} else if (deleteFile==2) {
|
|
NSString *trash = [@"~/.Trash" stringByExpandingTildeInPath];
|
|
NSInteger tag;
|
|
[[NSWorkspace sharedWorkspace] performFileOperation:NSWorkspaceRecycleOperation source:[thePath stringByDeletingLastPathComponent] destination:trash files:[NSArray arrayWithObject:[thePath lastPathComponent]] tag:&tag];
|
|
if (tag!=0)
|
|
NSLog(@"Error Deleting: %ld", (long)tag);
|
|
}
|
|
}
|
|
|
|
BOOL growl = [[defaults objectForKey:[NSString stringWithFormat:MGMEGrowl, theEvent]] boolValue];
|
|
if (growl) {
|
|
NSString *title = nil;
|
|
NSString *description = nil;
|
|
NSString *notificationName = nil;
|
|
if (theEvent==MGMEUploading) {
|
|
title = [@"Uploading File" localized];
|
|
description = [NSString stringWithFormat:[@"Uploading %@" localized], [[thePath lastPathComponent] stringByDeletingPathExtension]];
|
|
notificationName = @"UploadingFile";
|
|
} else if (theEvent==MGMEUploadingAutomatic) {
|
|
title = [@"Automatically Uploading File" localized];
|
|
description = [NSString stringWithFormat:[@"Uploading %@" localized], [[thePath lastPathComponent] stringByDeletingPathExtension]];
|
|
notificationName = @"UploadingFileAutomatically";
|
|
} else if (theEvent==MGMEUploaded) {
|
|
title = [@"Uploaded File" localized];
|
|
description = [NSString stringWithFormat:[@"Uploaded %@ to %@" localized], [[thePath lastPathComponent] stringByDeletingPathExtension], theURL];
|
|
notificationName = @"UploadedFile";
|
|
} else if (theEvent==MGMEUploadedAutomatic) {
|
|
title = [@"Automatically Uploaded File" localized];
|
|
description = [NSString stringWithFormat:[@"Uploaded %@ to %@" localized], [[thePath lastPathComponent] stringByDeletingPathExtension], theURL];
|
|
notificationName = @"UploadedFileAutomatically";
|
|
}
|
|
[GrowlApplicationBridge notifyWithTitle:title description:description notificationName:notificationName iconData:[[[NSApplication sharedApplication] applicationIconImage] TIFFRepresentation] priority:0 isSticky:NO clickContext:nil];
|
|
}
|
|
}
|
|
- (void)sound:(NSSound *)sound didFinishPlaying:(BOOL)finishedPlaying {
|
|
if (finishedPlaying)
|
|
[sound release];
|
|
}
|
|
|
|
- (NSMutableArray *)uploads {
|
|
return uploads;
|
|
}
|
|
- (NSDictionary *)uploadForPath:(NSString *)thePath {
|
|
for (int i=0; i<[uploads count]; i++) {
|
|
if ([[[uploads objectAtIndex:i] objectForKey:MGMUPath] isEqual:thePath])
|
|
return [uploads objectAtIndex:i];
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
- (void)addPathToUploads:(NSString *)thePath automaticFilter:(NSString *)theFilter {
|
|
[self addPathToUploads:thePath automaticFilter:theFilter multiUpload:0];
|
|
}
|
|
|
|
/*
|
|
0 - Not a upload queue with multiple uploads.
|
|
1 - First upload in the queue.
|
|
2 - An upload in the queue.
|
|
3 - Last upload in the queue.
|
|
4 - The multi upload page.
|
|
*/
|
|
- (void)addPathToUploads:(NSString *)thePath automaticFilter:(NSString *)theFilter multiUpload:(int)multiUploadState {
|
|
if ([self uploadForPath:thePath]==nil) {
|
|
if ([currentPlugIn respondsToSelector:@selector(allowedExtensions)]) {
|
|
if (![[currentPlugIn allowedExtensions] containsObject:[[thePath pathExtension] lowercaseString]]) {
|
|
NSAlert *alert = [[NSAlert new] autorelease];
|
|
[alert setMessageText:[@"Upload Error" localized]];
|
|
[alert setInformativeText:[@"The current PlugIn does not support this file format." localized]];
|
|
[alert runModal];
|
|
return;
|
|
}
|
|
}
|
|
[self resizeIfNeeded:thePath filterID:theFilter];
|
|
|
|
[uploads addObject:[NSDictionary dictionaryWithObjectsAndKeys:thePath, MGMUPath, [NSNumber numberWithBool:(theFilter!=nil)], MGMUAutomatic, [NSNumber numberWithInt:multiUploadState], MGMUMultiUpload, nil]];
|
|
if ([uploads count]==1)
|
|
[self processNextUpload];
|
|
}
|
|
}
|
|
- (void)processNextUpload {
|
|
if ([uploads count]>0) {
|
|
if (currentPlugIn==nil) {
|
|
NSAlert *alert = [[NSAlert new] autorelease];
|
|
[alert setMessageText:[@"Upload Error" localized]];
|
|
[alert setInformativeText:[@"No PlugIns found. You must have at least 1 PlugIn to upload a file." localized]];
|
|
[alert runModal];
|
|
[uploads removeAllObjects];
|
|
return;
|
|
} else if (![currentPlugIn respondsToSelector:@selector(sendFileAtPath:withName:)] && ![currentPlugIn respondsToSelector:@selector(sendFileAtPath:withName:multiUpload:)]) {
|
|
NSAlert *alert = [[NSAlert new] autorelease];
|
|
[alert setMessageText:[@"Upload Error" localized]];
|
|
[alert setInformativeText:[@"The current PlugIn doesn't support uploading." localized]];
|
|
[alert runModal];
|
|
[uploads removeAllObjects];
|
|
return;
|
|
}
|
|
NSFileManager *manager = [NSFileManager defaultManager];
|
|
NSDictionary *upload = [uploads objectAtIndex:0];
|
|
int multiUpload = [[upload objectForKey:MGMUMultiUpload] intValue];
|
|
if (multiUpload==1) {
|
|
[multiUploadLinks release];
|
|
multiUploadLinks = [NSMutableArray new];
|
|
}
|
|
|
|
if (![manager fileExistsAtPath:[upload objectForKey:MGMUPath]]) {
|
|
[uploads removeObject:upload];
|
|
[self processNextUpload];
|
|
return;
|
|
}
|
|
[menuItem setImage:[NSImage imageNamed:@"menuiconupload"]];
|
|
[self processEvent:([[upload objectForKey:MGMUAutomatic] boolValue] ? MGMEUploadingAutomatic : MGMEUploading) path:[upload objectForKey:MGMUPath]];
|
|
int uploadNameType = [[[NSUserDefaults standardUserDefaults] objectForKey:MGMUploadName] intValue];
|
|
NSString *randomizedName = [[NSString stringWithFormat:@"%f", [[NSDate date] timeIntervalSince1970]] MD5];
|
|
NSString *name = [[upload objectForKey:MGMUPath] lastPathComponent];
|
|
if ((uploadNameType==0 && [[upload objectForKey:MGMUAutomatic] boolValue]) || uploadNameType==1)
|
|
name = [randomizedName stringByAppendingPathExtension:[name pathExtension]];
|
|
if ([currentPlugIn respondsToSelector:@selector(sendFileAtPath:withName:multiUpload:)]) {
|
|
[currentPlugIn sendFileAtPath:[upload objectForKey:MGMUPath] withName:name multiUpload:multiUpload];
|
|
} else {
|
|
[currentPlugIn sendFileAtPath:[upload objectForKey:MGMUPath] withName:name];
|
|
}
|
|
} else {
|
|
NSString *osxMode = [[NSUserDefaults standardUserDefaults] stringForKey:@"AppleInterfaceStyle"];
|
|
if ([osxMode isEqualTo:@"Dark"]) {
|
|
[menuItem setImage:[NSImage imageNamed:@"menuiconselected"]];
|
|
} else {
|
|
[menuItem setImage:[NSImage imageNamed:@"menuicon"]];
|
|
}
|
|
}
|
|
}
|
|
- (void)upload:(NSString *)thePath receivedError:(NSError *)theError {
|
|
NSDictionary *upload = [self uploadForPath:thePath];
|
|
if (upload!=nil) {
|
|
NSLog(@"Error: %@", theError);
|
|
if ([[NSUserDefaults standardUserDefaults] boolForKey:MGMGrowlErrors]) {
|
|
[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];
|
|
} else {
|
|
NSAlert *alert = [[NSAlert new] autorelease];
|
|
[alert setMessageText:[@"Upload Error" localized]];
|
|
[alert setInformativeText:[NSString stringWithFormat:[@"Unable to upload %@: %@" localized], [[upload objectForKey:MGMUPath] lastPathComponent], [theError localizedDescription]]];
|
|
[alert runModal];
|
|
}
|
|
[uploads removeObject:upload];
|
|
[self processNextUpload];
|
|
}
|
|
}
|
|
- (void)uploadFinished:(NSString *)thePath url:(NSURL *)theURL {
|
|
NSDictionary *upload = [self uploadForPath:thePath];
|
|
if (upload!=nil) {
|
|
int multiUpload = [[upload objectForKey:MGMUMultiUpload] intValue];
|
|
[self processEvent:([[upload objectForKey:MGMUAutomatic] boolValue] ? MGMEUploadedAutomatic : MGMEUploaded) path:[upload objectForKey:MGMUPath] url:theURL];
|
|
//No need to bother the clip board when there will end up being a multi upload url.
|
|
if (multiUpload==0 || multiUpload==4) {
|
|
NSPasteboard *pboard = [NSPasteboard generalPasteboard];
|
|
[pboard declareTypes:[NSArray arrayWithObjects:MGMNSStringPboardType, MGMNSPasteboardTypeString, nil] owner:nil];
|
|
[pboard setString:[theURL absoluteString] forType:MGMNSStringPboardType];
|
|
[pboard setString:[theURL absoluteString] forType:MGMNSPasteboardTypeString];
|
|
}
|
|
[self addURLToHistory:theURL];
|
|
|
|
if (multiUpload>=1 && multiUpload!=4) {
|
|
[multiUploadLinks addObject:theURL];
|
|
}
|
|
if (multiUpload==3) {
|
|
if ([currentPlugIn respondsToSelector:@selector(createMultiUploadPage)]) {
|
|
[currentPlugIn createMultiUploadPage];
|
|
} else {
|
|
NSString *randomizedName = [[NSString stringWithFormat:@"%f", [[NSDate date] timeIntervalSince1970]] MD5];
|
|
NSString *htmlPath = [NSString stringWithFormat:@"/tmp/CocoaShare_%@.htm", randomizedName];
|
|
|
|
NSString *imageHTML = [NSString stringWithContentsOfFile:[[self currentMUTheme] stringByAppendingPathComponent:@"image.html"] encoding:NSUTF8StringEncoding error:nil];
|
|
if (imageHTML==nil) {
|
|
[uploads removeObject:upload];
|
|
[self processNextUpload];
|
|
return;
|
|
}
|
|
NSString *fileHTML = [NSString stringWithContentsOfFile:[[self currentMUTheme] stringByAppendingPathComponent:@"file.html"] encoding:NSUTF8StringEncoding error:nil];
|
|
|
|
[[NSFileManager defaultManager] createFileAtPath:htmlPath contents:nil attributes:nil];
|
|
NSFileHandle *multiUploadHtml = [NSFileHandle fileHandleForWritingAtPath:htmlPath];
|
|
[multiUploadHtml writeData:[NSData dataWithContentsOfFile:[[self currentMUTheme] stringByAppendingPathComponent:@"header.html"]]];
|
|
NSArray *imageExtensions = [NSArray arrayWithObjects:@"jpg", @"jpeg", @"png", @"bmp", @"gif", nil];
|
|
for (int i=0; i<[multiUploadLinks count]; i++) {
|
|
NSURL *link = [multiUploadLinks objectAtIndex:i];
|
|
NSString *linkString = [link absoluteString];
|
|
if ([imageExtensions containsObject:[[link pathExtension] lowercaseString]]) {
|
|
[multiUploadHtml writeData:[[imageHTML replace:@"{url}" with:linkString] dataUsingEncoding:NSUTF8StringEncoding]];
|
|
} else {
|
|
[multiUploadHtml writeData:[[fileHTML replace:@"{url}" with:linkString] dataUsingEncoding:NSUTF8StringEncoding]];
|
|
}
|
|
}
|
|
[multiUploadHtml writeData:[NSData dataWithContentsOfFile:[[self currentMUTheme] stringByAppendingPathComponent:@"footer.html"]]];
|
|
[multiUploadHtml closeFile];
|
|
[self addPathToUploads:htmlPath automaticFilter:nil multiUpload:4];
|
|
}
|
|
}
|
|
if (multiUpload==4) {
|
|
[[NSFileManager defaultManager] removeItemAtPath:[upload objectForKey:MGMUPath]];
|
|
}
|
|
|
|
[uploads removeObject:upload];
|
|
[self processNextUpload];
|
|
}
|
|
}
|
|
- (void)multiUploadPageCreated:(NSURL *)theURL {
|
|
NSPasteboard *pboard = [NSPasteboard generalPasteboard];
|
|
[pboard declareTypes:[NSArray arrayWithObjects:MGMNSStringPboardType, MGMNSPasteboardTypeString, nil] owner:nil];
|
|
[pboard setString:[theURL absoluteString] forType:MGMNSStringPboardType];
|
|
[pboard setString:[theURL absoluteString] forType:MGMNSPasteboardTypeString];
|
|
[self addURLToHistory:theURL];
|
|
}
|
|
@end
|