Reintroducing App Sandbox, and more

- Implemented App Sandboxing in a more friendly manner.
- All sandboxed paths will need to be set in Preferences. Set as loose
  a path as you want. The shortest path will be preferred.
- Removed Last.fm client support, as it was non-functional by now,
  unfortunately. Maybe something better can come in the future.
- Added support for insecure SSL to the HTTP/S reader, in case anyone
  needs streams which are "protected" by self-signed or expired
  certificates, without having to futz around by adding certificates to
  the system settings, especially for expired certificates that can't
  otherwise be dodged this way.

If you want to import your old playlists to the new version, copy the
contents of `~/Library/Application Support/Cog` to the alternate sandbox
path: `~/Library/Containers/org.cogx.cog/Data/Library/Application `...
...continued...`Support/Cog`. The preferences file will migrate to the
new version automatically.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
swiftingly
Christopher Snowhill 2022-06-20 03:35:29 -07:00
parent 8009d911c2
commit c23bece62c
55 changed files with 767 additions and 676 deletions

View File

@ -12,6 +12,7 @@
#import "PlaylistLoader.h"
#import "PlaylistView.h"
#import "SQLiteStore.h"
#import "SandboxBroker.h"
#import "SpotlightWindowController.h"
#import "StringToURLTransformer.h"
#import <CogAudio/Status.h>
@ -189,6 +190,11 @@ BOOL kAppControllerShuttingDown = NO;
}
}
SandboxBroker *sandboxBroker = [SandboxBroker sharedSandboxBroker];
if(!sandboxBroker) {
ALog(@"Sandbox broker init failed.");
}
[[playlistController undoManager] enableUndoRegistration];
int lastStatus = (int)[[NSUserDefaults standardUserDefaults] integerForKey:@"lastPlaybackStatus"];
@ -434,6 +440,9 @@ BOOL kAppControllerShuttingDown = NO;
[[NSFileManager defaultManager] removeItemAtPath:[folder stringByAppendingPathComponent:fileName] error:&error];
DLog(@"Shutting down sandbox broker");
[[SandboxBroker sharedSandboxBroker] shutdown];
DLog(@"Saving expanded nodes: %@", [expandedNodes description]);
[[NSUserDefaults standardUserDefaults] setValue:[expandedNodes allObjects] forKey:@"fileTreeViewExpandedNodes"];

View File

@ -3,7 +3,6 @@
#import <Cocoa/Cocoa.h>
#import "AppController.h"
#import "AudioScrobbler.h"
#import "CogAudio/AudioPlayer.h"
#import "CogAudio/Status.h"
#import "TrackingSlider.h"
@ -15,6 +14,8 @@
#import "EqualizerWindowController.h"
#import "PlaylistEntry.h"
#define DEFAULT_VOLUME_DOWN 5
#define DEFAULT_VOLUME_UP DEFAULT_VOLUME_DOWN

View File

@ -11,8 +11,6 @@
#import "PlaybackController.h"
@class AudioScrobbler;
@interface PlaybackEventController
: NSObject <NSUserNotificationCenterDelegate, UNUserNotificationCenterDelegate> {
IBOutlet PlaybackController *playbackController;

View File

@ -7,8 +7,6 @@
#import "PlaybackEventController.h"
#import "AudioScrobbler.h"
#import "PlaylistEntry.h"
NSString *TrackNotification = @"com.apple.iTunes.playerInfo";
@ -27,8 +25,6 @@ typedef NS_ENUM(NSInteger, TrackStatus) { TrackPlaying,
TrackStopped };
@implementation PlaybackEventController {
AudioScrobbler *scrobbler;
NSOperationQueue *queue;
PlaylistEntry *entry;
@ -38,8 +34,6 @@ typedef NS_ENUM(NSInteger, TrackStatus) { TrackPlaying,
- (void)initDefaults {
NSDictionary *defaultsDictionary = @{
@"enableAudioScrobbler": @YES,
@"automaticallyLaunchLastFM": @NO,
@"notifications.enable": @YES,
@"notifications.itunes-style": @YES,
@"notifications.show-album-art": @YES
@ -85,7 +79,6 @@ typedef NS_ENUM(NSInteger, TrackStatus) { TrackPlaying,
queue = [[NSOperationQueue alloc] init];
[queue setMaxConcurrentOperationCount:1];
scrobbler = [[AudioScrobbler alloc] init];
[[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:self];
entry = nil;
@ -161,11 +154,6 @@ didReceiveNotificationResponse:(UNNotificationResponse *)response
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if([defaults boolForKey:@"notifications.enable"]) {
if([defaults boolForKey:@"enableAudioScrobbler"]) {
[scrobbler start:pe];
if([AudioScrobbler isRunning]) return;
}
if(@available(macOS 10.14, *)) {
if(didGainUN) {
UNUserNotificationCenter *center =
@ -300,9 +288,6 @@ didReceiveNotificationResponse:(UNNotificationResponse *)response
object:nil
userInfo:[self fillNotificationDictionary:entry status:TrackPaused]
deliverImmediately:YES];
if([[NSUserDefaults standardUserDefaults] boolForKey:@"enableAudioScrobbler"]) {
[scrobbler pause];
}
}
- (void)performPlaybackDidResumeActions {
@ -311,9 +296,6 @@ didReceiveNotificationResponse:(UNNotificationResponse *)response
object:nil
userInfo:[self fillNotificationDictionary:entry status:TrackPlaying]
deliverImmediately:YES];
if([[NSUserDefaults standardUserDefaults] boolForKey:@"enableAudioScrobbler"]) {
[scrobbler resume];
}
}
- (void)performPlaybackDidStopActions {
@ -323,9 +305,6 @@ didReceiveNotificationResponse:(UNNotificationResponse *)response
userInfo:[self fillNotificationDictionary:entry status:TrackStopped]
deliverImmediately:YES];
entry = nil;
if([[NSUserDefaults standardUserDefaults] boolForKey:@"enableAudioScrobbler"]) {
[scrobbler stop];
}
}
- (void)awakeFromNib {

View File

@ -1,45 +0,0 @@
/*
* $Id: AudioScrobbler.h 238 2007-01-26 22:55:20Z stephen_booth $
*
* Copyright (C) 2006 - 2007 Stephen F. Booth <me@sbooth.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#import <Cocoa/Cocoa.h>
#import <mach/mach.h>
@class PlaylistEntry;
@interface AudioScrobbler : NSObject {
NSString *_pluginID;
NSMutableArray *_queue;
BOOL _audioScrobblerThreadCompleted;
BOOL _keepProcessingAudioScrobblerCommands;
semaphore_t _semaphore;
}
+ (BOOL)isRunning;
- (void)start:(PlaylistEntry *)pe;
- (void)stop;
- (void)pause;
- (void)resume;
- (void)shutdown;
@end

View File

@ -1,259 +0,0 @@
/*
* $Id: AudioScrobbler.m 238 2007-01-26 22:55:20Z stephen_booth $
*
* Copyright (C) 2006 - 2007 Stephen F. Booth <me@sbooth.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#import "AudioScrobbler.h"
#import "AudioScrobblerClient.h"
#import "PlaylistEntry.h"
#import "Logging.h"
// ========================================
// Symbolic Constants
// ========================================
NSString *const AudioScrobblerRunLoopMode = @"org.cogx.Cog.AudioScrobbler.RunLoopMode";
// ========================================
// Helpers
// ========================================
static NSString *
escapeForLastFM(NSString *string) {
NSMutableString *result = [string mutableCopy];
[result replaceOccurrencesOfString:@"&"
withString:@"&&"
options:NSLiteralSearch
range:NSMakeRange(0, [result length])];
return (nil == result ? @"" : result);
}
@interface AudioScrobbler (Private)
- (NSMutableArray *)queue;
- (NSString *)pluginID;
- (void)sendCommand:(NSString *)command;
- (BOOL)keepProcessingAudioScrobblerCommands;
- (void)setKeepProcessingAudioScrobblerCommands:(BOOL)keepProcessingAudioScrobblerCommands;
- (BOOL)audioScrobblerThreadCompleted;
- (void)setAudioScrobblerThreadCompleted:(BOOL)audioScrobblerThreadCompleted;
- (semaphore_t)semaphore;
- (void)processAudioScrobblerCommands:(id)unused;
@end
@implementation AudioScrobbler
+ (BOOL)isRunning {
NSArray *launchedApps = [[NSWorkspace sharedWorkspace] runningApplications];
BOOL running = NO;
for(NSRunningApplication *app in launchedApps) {
if([[app bundleIdentifier] isEqualToString:@"fm.last.Last.fm"] ||
[[app bundleIdentifier] isEqualToString:@"fm.last.Scrobbler"]) {
running = YES;
break;
}
}
return running;
}
- (id)init {
if((self = [super init])) {
_pluginID = @"cog";
if([[NSUserDefaults standardUserDefaults] boolForKey:@"automaticallyLaunchLastFM"]) {
if(![AudioScrobbler isRunning]) {
[[NSWorkspace sharedWorkspace] launchApplication:@"Last.fm.app"];
}
}
_keepProcessingAudioScrobblerCommands = YES;
kern_return_t result = semaphore_create(mach_task_self(), &_semaphore, SYNC_POLICY_FIFO, 0);
if(KERN_SUCCESS != result) {
ALog(@"Couldn't create semaphore (%s).", mach_error_type(result));
self = nil;
return nil;
}
[NSThread detachNewThreadSelector:@selector(processAudioScrobblerCommands:) toTarget:self withObject:nil];
}
return self;
}
- (void)dealloc {
if([self keepProcessingAudioScrobblerCommands] || NO == [self audioScrobblerThreadCompleted])
[self shutdown];
_queue = nil;
semaphore_destroy(mach_task_self(), _semaphore);
_semaphore = 0;
}
- (void)start:(PlaylistEntry *)pe {
[self sendCommand:[NSString stringWithFormat:@"START c=%@&a=%@&t=%@&b=%@&m=%@&l=%i&p=%@\n",
[self pluginID],
escapeForLastFM([pe artist]),
escapeForLastFM([pe title]),
escapeForLastFM([pe album]),
@"", // TODO: MusicBrainz support
[[pe length] intValue],
escapeForLastFM([pe.url path])]];
}
- (void)stop {
[self sendCommand:[NSString stringWithFormat:@"STOP c=%@\n", [self pluginID]]];
}
- (void)pause {
[self sendCommand:[NSString stringWithFormat:@"PAUSE c=%@\n", [self pluginID]]];
}
- (void)resume {
[self sendCommand:[NSString stringWithFormat:@"RESUME c=%@\n", [self pluginID]]];
}
- (void)shutdown {
[self setKeepProcessingAudioScrobblerCommands:NO];
semaphore_signal([self semaphore]);
// Wait for the thread to terminate
while(NO == [self audioScrobblerThreadCompleted])
[[NSRunLoop currentRunLoop] runMode:AudioScrobblerRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.2]];
}
@end
@implementation AudioScrobbler (Private)
- (NSMutableArray *)queue {
if(nil == _queue)
_queue = [[NSMutableArray alloc] init];
return _queue;
}
- (NSString *)pluginID {
return _pluginID;
}
- (void)sendCommand:(NSString *)command {
@synchronized([self queue]) {
[[self queue] addObject:command];
}
semaphore_signal([self semaphore]);
}
- (BOOL)keepProcessingAudioScrobblerCommands {
return _keepProcessingAudioScrobblerCommands;
}
- (void)setKeepProcessingAudioScrobblerCommands:(BOOL)keepProcessingAudioScrobblerCommands {
_keepProcessingAudioScrobblerCommands = keepProcessingAudioScrobblerCommands;
}
- (BOOL)audioScrobblerThreadCompleted {
return _audioScrobblerThreadCompleted;
}
- (void)setAudioScrobblerThreadCompleted:(BOOL)audioScrobblerThreadCompleted {
_audioScrobblerThreadCompleted = audioScrobblerThreadCompleted;
}
- (semaphore_t)semaphore {
return _semaphore;
}
- (void)processAudioScrobblerCommands:(id)unused {
@autoreleasepool {
AudioScrobblerClient *client = [[AudioScrobblerClient alloc] init];
mach_timespec_t timeout = { 5, 0 };
NSString *command = nil;
NSString *response = nil;
in_port_t port = 33367;
while([self keepProcessingAudioScrobblerCommands]) {
@autoreleasepool {
// Get the first command to be sent
@synchronized([self queue]) {
if([[self queue] count]) {
command = [[self queue] objectAtIndex:0];
[[self queue] removeObjectAtIndex:0];
}
}
if(nil != command) {
@try {
if([client connectToHost:@"localhost" port:port]) {
port = [client connectedPort];
[client send:command];
command = nil;
response = [client receive];
if(2 > [response length] || NSOrderedSame != [response compare:@"OK" options:NSLiteralSearch range:NSMakeRange(0, 2)])
ALog(@"AudioScrobbler error: %@", response);
[client shutdown];
}
}
@catch(NSException *exception) {
command = nil;
[client shutdown];
// ALog(@"Exception: %@",exception);
continue;
}
}
semaphore_timedwait([self semaphore], timeout);
}
}
// Send a final stop command to cleanup
@try {
if([client connectToHost:@"localhost" port:port]) {
[client send:[NSString stringWithFormat:@"STOP c=%@\n", [self pluginID]]];
response = [client receive];
if(2 > [response length] || NSOrderedSame != [response compare:@"OK" options:NSLiteralSearch range:NSMakeRange(0, 2)])
ALog(@"AudioScrobbler error: %@", response);
[client shutdown];
}
}
@catch(NSException *exception) {
[client shutdown];
}
[self setAudioScrobblerThreadCompleted:YES];
}
}
@end

View File

@ -1,41 +0,0 @@
/*
* $Id: AudioScrobblerClient.h 666 2007-04-26 16:35:18Z stephen_booth $
*
* Copyright (C) 2006 - 2007 Stephen F. Booth <me@sbooth.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#import <Cocoa/Cocoa.h>
#include <netdb.h>
@interface AudioScrobblerClient : NSObject {
int _socket;
BOOL _doPortStepping;
in_port_t _port;
}
- (BOOL)connectToHost:(NSString *)hostname port:(in_port_t)port;
- (BOOL)isConnected;
- (in_port_t)connectedPort;
- (void)send:(NSString *)data;
- (NSString *)receive;
- (void)shutdown;
@end

View File

@ -1,212 +0,0 @@
/*
* $Id: AudioScrobblerClient.m 869 2007-06-18 15:51:33Z stephen_booth $
*
* Copyright (C) 2006 - 2007 Stephen F. Booth <me@sbooth.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* This is a port of the BlockingClient client class from
* the Last.fm ScrobSub library by sharevari
*/
#import "AudioScrobblerClient.h"
#include <arpa/inet.h>
#import "Logging.h"
#define kBufferSize 1024
#define kPortsToStep 5
static in_addr_t
addressForHost(NSString *hostname) {
NSCParameterAssert(nil != hostname);
in_addr_t address;
struct hostent *hostinfo;
address = inet_addr([hostname cStringUsingEncoding:NSASCIIStringEncoding]);
if(INADDR_NONE == address) {
hostinfo = gethostbyname([hostname cStringUsingEncoding:NSASCIIStringEncoding]);
if(NULL == hostinfo) {
ALog(@"AudioScrobblerClient error: Unable to resolve address for \"%@\".", hostname);
return INADDR_NONE;
}
address = *((in_addr_t *)hostinfo->h_addr_list[0]);
}
return address;
}
@interface AudioScrobblerClient (Private)
- (BOOL)connectToSocket:(in_addr_t)remoteAddress port:(in_port_t)port;
@end
@implementation AudioScrobblerClient
- (id)init {
if((self = [super init])) {
_socket = -1;
_doPortStepping = YES;
}
return self;
}
- (BOOL)connectToHost:(NSString *)hostname port:(in_port_t)port {
NSParameterAssert(nil != hostname);
in_addr_t remoteAddress = addressForHost(hostname);
if(INADDR_NONE != remoteAddress)
return [self connectToSocket:remoteAddress port:port];
return NO;
}
- (BOOL)isConnected {
return (-1 != _socket);
}
- (in_port_t)connectedPort {
return _port;
}
- (void)send:(NSString *)data {
const char *utf8data = [data UTF8String];
unsigned len = (unsigned int)strlen(utf8data);
unsigned bytesToSend = len;
unsigned totalBytesSent = 0;
ssize_t bytesSent = 0;
if(NO == [self isConnected]) {
ALog(@"AudioScrobblerClient error: Can't send data, client not connected");
return;
}
while(totalBytesSent < bytesToSend && -1 != bytesSent) {
bytesSent = send(_socket, utf8data + totalBytesSent, bytesToSend - totalBytesSent, 0);
if(-1 == bytesSent || 0 == bytesSent)
ALog(@"AudioScrobblerClient error: Unable to send data through socket: %s", strerror(errno));
totalBytesSent += bytesSent;
}
}
- (NSString *)receive {
char buffer[kBufferSize];
int readSize = kBufferSize - 1;
ssize_t bytesRead = 0;
BOOL keepGoing = YES;
NSString *result = nil;
if(NO == [self isConnected]) {
ALog(@"AudioScrobblerClient error: Can't receive data, client not connected");
return nil;
}
do {
bytesRead = recv(_socket, buffer, readSize, 0);
if(-1 == bytesRead || 0 == bytesRead) {
ALog(@"AudioScrobblerClient error: Unable to receive data through socket: %s", strerror(errno));
break;
}
if('\n' == buffer[bytesRead - 1]) {
--bytesRead;
keepGoing = NO;
}
buffer[bytesRead] = '\0';
result = [[NSString alloc] initWithUTF8String:buffer];
} while(keepGoing);
return result;
}
- (void)shutdown {
int result;
char buffer[kBufferSize];
ssize_t bytesRead;
if(NO == [self isConnected]) {
return;
}
result = shutdown(_socket, SHUT_WR);
if(-1 == result)
ALog(@"AudioScrobblerClient error: Socket shutdown failed: %s", strerror(errno));
for(;;) {
bytesRead = recv(_socket, buffer, kBufferSize, 0);
if(-1 == bytesRead)
ALog(@"AudioScrobblerClient error: Waiting for shutdown confirmation failed: %s", strerror(errno));
if(0 != bytesRead) {
NSString *received = [[NSString alloc] initWithBytes:buffer length:bytesRead encoding:NSUTF8StringEncoding];
ALog(@"Received unexpected bytes during shutdown: %@", received);
} else
break;
}
result = close(_socket);
if(-1 == result)
ALog(@"Couldn't close socket (%s)", strerror(errno));
_socket = -1;
_port = 0;
}
@end
@implementation AudioScrobblerClient (Private)
- (BOOL)connectToSocket:(in_addr_t)remoteAddress port:(in_port_t)port {
NSParameterAssert(INADDR_NONE != remoteAddress);
_port = port;
int result;
do {
struct sockaddr_in socketAddress;
_socket = socket(AF_INET, SOCK_STREAM, 0);
if(-1 == _socket) {
ALog(@"Unable to create socket (%s)", strerror(errno));
return NO;
}
socketAddress.sin_family = AF_INET;
socketAddress.sin_addr.s_addr = remoteAddress;
socketAddress.sin_port = htons(_port);
result = connect(_socket, (const struct sockaddr *)&socketAddress, sizeof(struct sockaddr_in));
if(-1 == result) {
close(_socket);
_socket = -1;
_port++;
}
} while(YES == _doPortStepping && -1 == result && _port < (port + kPortsToStep));
return (-1 != result);
}
@end

View File

@ -25,17 +25,17 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<splitView dividerStyle="thin" vertical="YES" translatesAutoresizingMaskIntoConstraints="NO" id="2123">
<rect key="frame" x="0.0" y="226" width="1000" height="174"/>
<rect key="frame" x="0.0" y="277" width="1000" height="123"/>
<subviews>
<scrollView fixedFrame="YES" borderType="none" autohidesScrollers="YES" horizontalLineScroll="24" horizontalPageScroll="0.0" verticalLineScroll="24" verticalPageScroll="0.0" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" id="206" userLabel="Scroll View - Playlist View">
<rect key="frame" x="0.0" y="0.0" width="1000" height="174"/>
<rect key="frame" x="0.0" y="0.0" width="1000" height="123"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<clipView key="contentView" drawsBackground="NO" copiesOnScroll="NO" id="KWC-Ti-8KY">
<rect key="frame" x="0.0" y="0.0" width="1000" height="174"/>
<rect key="frame" x="0.0" y="0.0" width="1000" height="123"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView focusRingType="none" verticalHuggingPriority="750" allowsExpansionToolTips="YES" alternatingRowBackgroundColors="YES" autosaveName="Playlist" rowHeight="18" headerView="1517" viewBased="YES" id="207" customClass="PlaylistView">
<rect key="frame" x="0.0" y="0.0" width="1000" height="157"/>
<rect key="frame" x="0.0" y="0.0" width="1000" height="106"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<size key="intercellSpacing" width="3" height="6"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>

View File

@ -2,7 +2,19 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.assets.movies.read-only</key>
<true/>
<key>com.apple.security.assets.music.read-only</key>
<true/>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.files.downloads.read-only</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
</dict>
</plist>

View File

@ -23,8 +23,6 @@
173855FF0E0CC81F00488CD4 /* FileTreeOutlineView.m in Sources */ = {isa = PBXBuildFile; fileRef = 173855FE0E0CC81F00488CD4 /* FileTreeOutlineView.m */; };
1752C36C0F59E00100F85F28 /* PlaybackButtons.m in Sources */ = {isa = PBXBuildFile; fileRef = 1752C36B0F59E00100F85F28 /* PlaybackButtons.m */; };
1755E1F90BA0D2B600CA3560 /* PlaylistLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 1755E1F70BA0D2B600CA3560 /* PlaylistLoader.m */; };
1766C6930B911DF1004A7AE4 /* AudioScrobbler.m in Sources */ = {isa = PBXBuildFile; fileRef = 1766C68F0B911DF1004A7AE4 /* AudioScrobbler.m */; };
1766C6950B911DF1004A7AE4 /* AudioScrobblerClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 1766C6910B911DF1004A7AE4 /* AudioScrobblerClient.m */; };
1770429C0B8BC53600B86321 /* AppController.m in Sources */ = {isa = PBXBuildFile; fileRef = 177042980B8BC53600B86321 /* AppController.m */; };
1770429E0B8BC53600B86321 /* PlaybackController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1770429A0B8BC53600B86321 /* PlaybackController.m */; };
1778D3B00F645A190037E7A0 /* missingArt.png in Resources */ = {isa = PBXBuildFile; fileRef = 1778D3AF0F645A190037E7A0 /* missingArt.png */; };
@ -93,6 +91,7 @@
56DB084C0D6717DC00453B6A /* NSNumber+CogSort.m in Sources */ = {isa = PBXBuildFile; fileRef = 56DB084B0D6717DC00453B6A /* NSNumber+CogSort.m */; };
56DB08550D67185300453B6A /* NSArray+CogSort.m in Sources */ = {isa = PBXBuildFile; fileRef = 56DB08540D67185300453B6A /* NSArray+CogSort.m */; };
8305963C277F013200EBFAAE /* File_Extractor.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 83059639277F011100EBFAAE /* File_Extractor.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
8307D30E28606148000FF8EB /* SandboxBroker.m in Sources */ = {isa = PBXBuildFile; fileRef = 8307D30D28606148000FF8EB /* SandboxBroker.m */; };
830C37A127B95E3000E02BB0 /* Equalizer.xib in Resources */ = {isa = PBXBuildFile; fileRef = 830C379F27B95E3000E02BB0 /* Equalizer.xib */; };
830C37A527B95EB300E02BB0 /* EqualizerWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 830C37A427B95EB300E02BB0 /* EqualizerWindowController.m */; };
830C37FC27B9956C00E02BB0 /* analyzer.c in Sources */ = {isa = PBXBuildFile; fileRef = 830C37F227B9956C00E02BB0 /* analyzer.c */; };
@ -784,10 +783,6 @@
1752C36B0F59E00100F85F28 /* PlaybackButtons.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PlaybackButtons.m; path = Window/PlaybackButtons.m; sourceTree = "<group>"; };
1755E1F60BA0D2B600CA3560 /* PlaylistLoader.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PlaylistLoader.h; sourceTree = "<group>"; };
1755E1F70BA0D2B600CA3560 /* PlaylistLoader.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = PlaylistLoader.m; sourceTree = "<group>"; };
1766C68E0B911DF1004A7AE4 /* AudioScrobbler.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = AudioScrobbler.h; sourceTree = "<group>"; };
1766C68F0B911DF1004A7AE4 /* AudioScrobbler.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = AudioScrobbler.m; sourceTree = "<group>"; };
1766C6900B911DF1004A7AE4 /* AudioScrobblerClient.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = AudioScrobblerClient.h; sourceTree = "<group>"; };
1766C6910B911DF1004A7AE4 /* AudioScrobblerClient.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = AudioScrobblerClient.m; sourceTree = "<group>"; };
1770424E0B8BC41800B86321 /* Cog.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Cog.app; sourceTree = BUILT_PRODUCTS_DIR; };
177042970B8BC53600B86321 /* AppController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = AppController.h; sourceTree = "<group>"; };
177042980B8BC53600B86321 /* AppController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = AppController.m; sourceTree = "<group>"; };
@ -909,6 +904,8 @@
56DB08530D67185300453B6A /* NSArray+CogSort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSArray+CogSort.h"; path = "Spotlight/NSArray+CogSort.h"; sourceTree = "<group>"; };
56DB08540D67185300453B6A /* NSArray+CogSort.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSArray+CogSort.m"; path = "Spotlight/NSArray+CogSort.m"; sourceTree = "<group>"; };
83059634277F011100EBFAAE /* File_Extractor.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = File_Extractor.xcodeproj; path = Frameworks/File_Extractor/File_Extractor.xcodeproj; sourceTree = "<group>"; };
8307D30C28606148000FF8EB /* SandboxBroker.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SandboxBroker.h; sourceTree = "<group>"; };
8307D30D28606148000FF8EB /* SandboxBroker.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SandboxBroker.m; sourceTree = "<group>"; };
830C37A027B95E3000E02BB0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/Equalizer.xib; sourceTree = "<group>"; };
830C37A327B95EB300E02BB0 /* EqualizerWindowController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = EqualizerWindowController.h; path = Equalizer/EqualizerWindowController.h; sourceTree = "<group>"; };
830C37A427B95EB300E02BB0 /* EqualizerWindowController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = EqualizerWindowController.m; path = Equalizer/EqualizerWindowController.m; sourceTree = "<group>"; };
@ -1136,7 +1133,6 @@
830C37A227B95E6000E02BB0 /* Equalizer */,
17D1B0FE0F63252900694C57 /* InfoInspector */,
569C52C50D5F2BD500BDBDC9 /* Spotlight */,
1766C68D0B911DF1004A7AE4 /* AudioScrobbler */,
17E0D5F60F520F42005B6FED /* Transformers */,
177EC0110B8BC2CF0000BC8C /* Utils */,
177EBF770B8BC2A70000BC8C /* ThirdParty */,
@ -1184,17 +1180,6 @@
name = "Other Frameworks";
sourceTree = "<group>";
};
1766C68D0B911DF1004A7AE4 /* AudioScrobbler */ = {
isa = PBXGroup;
children = (
1766C68E0B911DF1004A7AE4 /* AudioScrobbler.h */,
1766C68F0B911DF1004A7AE4 /* AudioScrobbler.m */,
1766C6900B911DF1004A7AE4 /* AudioScrobblerClient.h */,
1766C6910B911DF1004A7AE4 /* AudioScrobblerClient.m */,
);
path = AudioScrobbler;
sourceTree = "<group>";
};
177042960B8BC53600B86321 /* Application */ = {
isa = PBXGroup;
children = (
@ -1266,6 +1251,8 @@
177EC01B0B8BC2CF0000BC8C /* TrackingCell.m */,
177EC01C0B8BC2CF0000BC8C /* TrackingSlider.h */,
177EC01D0B8BC2CF0000BC8C /* TrackingSlider.m */,
8307D30C28606148000FF8EB /* SandboxBroker.h */,
8307D30D28606148000FF8EB /* SandboxBroker.m */,
);
path = Utils;
sourceTree = "<group>";
@ -2610,10 +2597,8 @@
177EC0290B8BC2CF0000BC8C /* TrackingSlider.m in Sources */,
1770429C0B8BC53600B86321 /* AppController.m in Sources */,
1770429E0B8BC53600B86321 /* PlaybackController.m in Sources */,
1766C6930B911DF1004A7AE4 /* AudioScrobbler.m in Sources */,
8355D6B6180612F300D05687 /* NSData+MD5.m in Sources */,
8377C66327B8CF6300E8BC0F /* SpectrumViewSK.m in Sources */,
1766C6950B911DF1004A7AE4 /* AudioScrobblerClient.m in Sources */,
1755E1F90BA0D2B600CA3560 /* PlaylistLoader.m in Sources */,
8E9A30160BA792DC0091081B /* NSFileHandle+CreateFile.m in Sources */,
179790E10C087AB7001D6996 /* OpenURLPanel.m in Sources */,
@ -2668,6 +2653,7 @@
171EFE8C0F59FEAE000ADC42 /* DockIconController.m in Sources */,
17F6C8070F603701000D9DA9 /* PlaybackEventController.m in Sources */,
83BC5AB220E4C87100631CD4 /* DualWindow.m in Sources */,
8307D30E28606148000FF8EB /* SandboxBroker.m in Sources */,
83229C9F283B0095004626A8 /* SpectrumWindowController.m in Sources */,
835F00BB279BD1CD00055FCF /* SecondsFormatter.m in Sources */,
1784560F0F631E24007E8021 /* FileTreeViewController.m in Sources */,

View File

@ -60,9 +60,14 @@
<attribute name="volume" optional="YES" attributeType="Float" defaultValueString="1" usesScalarValueType="YES"/>
<attribute name="year" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
</entity>
<entity name="SandboxToken" representedClassName="SandboxToken" syncable="YES" codeGenerationType="class">
<attribute name="bookmark" optional="YES" attributeType="Binary"/>
<attribute name="path" optional="YES" attributeType="String"/>
</entity>
<elements>
<element name="AlbumArtwork" positionX="0" positionY="207" width="128" height="59"/>
<element name="PlaylistEntry" positionX="-36" positionY="9" width="128" height="704"/>
<element name="PlayCount" positionX="-18" positionY="171" width="128" height="134"/>
<element name="PlaylistEntry" positionX="-36" positionY="9" width="128" height="704"/>
<element name="SandboxToken" positionX="-18" positionY="171" width="128" height="59"/>
</elements>
</model>

View File

@ -19,6 +19,10 @@
@class SpotlightWindowController;
@class PlaybackController;
@interface NSApplication (CoreDataStorageExtension)
- (NSPersistentContainer *_Nonnull)sharedPersistentContainer;
@end
typedef NS_ENUM(NSInteger, RepeatMode) {
RepeatModeNoRepeat = 0,
RepeatModeRepeatOne,
@ -139,7 +143,7 @@ typedef NS_ENUM(NSInteger, URLOrigin) {
- (IBAction)reloadTags:(id _Nullable)sender;
// Play statistics
- (void)updatePlayCountForTrack:(PlaylistEntry *)pe;
- (void)updatePlayCountForTrack:(PlaylistEntry *_Nonnull)pe;
- (void)moveObjectsInArrangedObjectsFromIndexes:(NSIndexSet *_Nullable)indexSet
toIndex:(NSUInteger)insertIndex;

View File

@ -27,6 +27,14 @@
extern BOOL kAppControllerShuttingDown;
NSPersistentContainer *__persistentContainer = nil;
@implementation NSApplication (CoreDataStorageExtension)
- (NSPersistentContainer *_Nonnull)sharedPersistentContainer {
return __persistentContainer;
}
@end
@implementation PlaylistController
@synthesize currentEntry;
@ -35,7 +43,6 @@ extern BOOL kAppControllerShuttingDown;
static NSArray *cellIdentifiers = nil;
NSPersistentContainer *__persistentContainer = nil;
NSMutableDictionary<NSString *, AlbumArtwork *> *__artworkDictionary = nil;
static void *playlistControllerContext = &playlistControllerContext;

View File

@ -32,6 +32,7 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
8307D31A286070EA000FF8EB /* SandboxBroker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SandboxBroker.h; path = ../../../Utils/SandboxBroker.h; sourceTree = "<group>"; };
8359009717FEF6490060F3ED /* ArchiveSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArchiveSource.h; sourceTree = "<group>"; };
8359009817FEF6490060F3ED /* ArchiveSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ArchiveSource.m; sourceTree = "<group>"; };
8359009A17FEFDA80060F3ED /* ArchiveContainer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArchiveContainer.h; sourceTree = "<group>"; };
@ -102,6 +103,7 @@
8359FF2017FEF35C0060F3ED /* ArchiveSource */ = {
isa = PBXGroup;
children = (
8307D31A286070EA000FF8EB /* SandboxBroker.h */,
8384913518081BA000E7332D /* Logging.h */,
835900A017FF079C0060F3ED /* Plugin.h */,
8359009A17FEFDA80060F3ED /* ArchiveContainer.h */,

View File

@ -12,6 +12,8 @@
#import "Logging.h"
#import "SandboxBroker.h"
static NSString *path_pack_string(NSString *src) {
return [NSString stringWithFormat:@"|%lu|%@|", [src length], src];
}
@ -43,6 +45,11 @@ static NSString *g_make_unpack_path(NSString *archive, NSString *file, NSString
return @[];
}
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
[sandboxBroker beginFolderAccess:url];
fex_t *fex;
fex_err_t error = fex_open(&fex, [[url path] UTF8String]);
if(error) {
@ -61,6 +68,8 @@ static NSString *g_make_unpack_path(NSString *archive, NSString *file, NSString
fex_close(fex);
[sandboxBroker endFolderAccess:url];
return files;
}

View File

@ -20,6 +20,7 @@
NSUInteger size;
NSURL *_url;
NSURL *fileURL;
}
@end

View File

@ -8,6 +8,8 @@
#import "ArchiveSource.h"
#import "SandboxBroker.h"
#import "Logging.h"
static NSString *path_unpack_string(NSString *src, NSRange *remainder) {
@ -83,6 +85,13 @@ static BOOL g_parse_unpack_path(NSString *src, NSString **archive, NSString **fi
if(![type isEqualToString:@"fex"])
return NO;
fileURL = [NSURL fileURLWithPath:archive];
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
[sandboxBroker beginFolderAccess:fileURL];
fex_err_t error;
error = fex_open(&fex, [archive UTF8String]);
@ -151,6 +160,13 @@ static BOOL g_parse_unpack_path(NSString *src, NSString **archive, NSString **fi
fex_close(fex);
fex = NULL;
}
if(fileURL) {
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
[sandboxBroker endFolderAccess:fileURL];
}
}
- (NSURL *)url {

View File

@ -8,6 +8,8 @@
#import "FileSource.h"
#import "SandboxBroker.h"
@implementation FileSource
+ (void)initialize {
@ -26,6 +28,11 @@
- (BOOL)open:(NSURL *)url {
[self setURL:url];
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
[sandboxBroker beginFolderAccess:url];
NSString *path = [url path];
fex_type_t type;
@ -123,6 +130,11 @@
fex_close(fex);
fex = NULL;
}
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
[sandboxBroker endFolderAccess:_url];
}
- (NSURL *)url {

View File

@ -37,6 +37,7 @@
17ADB4180B979AEB00257CA2 /* FileSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileSource.h; sourceTree = "<group>"; };
17ADB4190B979AEB00257CA2 /* FileSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FileSource.m; sourceTree = "<group>"; };
32DBCF630370AF2F00C91783 /* FileSource_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileSource_Prefix.pch; sourceTree = "<group>"; };
8307D31B2860722C000FF8EB /* SandboxBroker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SandboxBroker.h; path = ../../Utils/SandboxBroker.h; sourceTree = "<group>"; };
8335FF6817FF765A002D8DD2 /* File_Extractor.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = File_Extractor.xcodeproj; path = ../../Frameworks/File_Extractor/File_Extractor.xcodeproj; sourceTree = "<group>"; };
8D5B49B6048680CD000E48DA /* FileSource.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FileSource.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
8D5B49B7048680CD000E48DA /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@ -88,6 +89,7 @@
08FB77AFFE84173DC02AAC07 /* Classes */ = {
isa = PBXGroup;
children = (
8307D31B2860722C000FF8EB /* SandboxBroker.h */,
17ADB4080B979A8A00257CA2 /* Plugin.h */,
17ADB4180B979AEB00257CA2 /* FileSource.h */,
17ADB4190B979AEB00257CA2 /* FileSource.m */,

View File

@ -463,6 +463,8 @@ static void http_stream_reset(HTTPSource *fp) {
struct curl_slist *headers = NULL;
struct curl_slist *ok_aliases = curl_slist_append(NULL, "ICY 200 OK");
BOOL sslVerify = ![[[NSUserDefaultsController sharedUserDefaultsController] defaults] boolForKey:@"allowInsecureSSL"];
curl_easy_reset(curl);
curl_easy_setopt(curl, CURLOPT_URL, [[URL absoluteString] UTF8String]);
NSString *ua = [NSString stringWithFormat:@"Cog/%@", [[[NSBundle mainBundle] infoDictionary] valueForKey:(__bridge NSString *)kCFBundleVersionKey]];
@ -491,6 +493,7 @@ static void http_stream_reset(HTTPSource *fp) {
if(pos > 0 && length >= 0) {
curl_easy_setopt(curl, CURLOPT_RESUME_FROM, (long)pos);
}
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, (long)sslVerify);
// fp->status = STATUS_INITIAL;
DLog(@"curl: calling curl_easy_perform (status=%d)...\n", self->status);
gettimeofday(&last_read_time, NULL);

View File

@ -88,6 +88,7 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
8307D31E28607377000FF8EB /* SandboxBroker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SandboxBroker.h; path = ../../../Utils/SandboxBroker.h; sourceTree = "<group>"; };
831E2A7F27B4B2B2006F1C86 /* bassmidi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bassmidi.h; sourceTree = "<group>"; };
831E2A8027B4B2B2006F1C86 /* sflist.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sflist.c; sourceTree = "<group>"; };
831E2A8227B4B2B2006F1C86 /* sflist_rewrite.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sflist_rewrite.c; sourceTree = "<group>"; };
@ -295,6 +296,7 @@
83B06690180D5668008E3612 /* MIDI */ = {
isa = PBXGroup;
children = (
8307D31E28607377000FF8EB /* SandboxBroker.h */,
831E2A9127B4B2FA006F1C86 /* json */,
831E2A7D27B4B2B2006F1C86 /* BASS */,
8356BCC427B352620074E50C /* BMPlayer.cpp */,

View File

@ -24,6 +24,8 @@ class BMPlayer;
MIDIPlayer* player;
midi_container midi_file;
NSURL* sandboxURL;
NSString* globalSoundFontPath;
BOOL soundFontsAssigned;
BOOL isLooped;

View File

@ -18,6 +18,8 @@
#import "PlaylistController.h"
#import "SandboxBroker.h"
#import <dlfcn.h>
static OSType getOSType(const char *in_) {
@ -165,6 +167,15 @@ static OSType getOSType(const char *in_) {
globalSoundFontPath = [[NSUserDefaults standardUserDefaults] stringForKey:@"soundFontPath"];
if(globalSoundFontPath && [globalSoundFontPath length] > 0) {
sandboxURL = [NSURL fileURLWithPath:[globalSoundFontPath stringByDeletingLastPathComponent]];
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
[sandboxBroker beginFolderAccess:sandboxURL];
}
// First detect if soundfont has gone AWOL
if(![[NSFileManager defaultManager] fileExistsAtPath:globalSoundFontPath]) {
globalSoundFontPath = nil;
@ -333,6 +344,15 @@ static OSType getOSType(const char *in_) {
- (void)close {
delete player;
player = NULL;
if(sandboxURL) {
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
[sandboxBroker endFolderAccess:sandboxURL];
sandboxURL = nil;
}
}
- (void)dealloc {

View File

@ -11,6 +11,7 @@
17C93FC30B90056C008627D6 /* TagLibMetadataReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 17C93FC20B90056C008627D6 /* TagLibMetadataReader.m */; };
17F563B40C3BDBB30019975C /* TagLib.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 17F563A60C3BDB8F0019975C /* TagLib.framework */; };
17F563B60C3BDBB50019975C /* TagLib.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 17F563A60C3BDB8F0019975C /* TagLib.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
8307D31D286072BF000FF8EB /* SandboxBroker.h in Headers */ = {isa = PBXBuildFile; fileRef = 8307D31C286072BF000FF8EB /* SandboxBroker.h */; };
8356BCE527B377C20074E50C /* TagLibID3v2Reader.h in Headers */ = {isa = PBXBuildFile; fileRef = 8356BCE327B377C20074E50C /* TagLibID3v2Reader.h */; };
8356BCE627B377C20074E50C /* TagLibID3v2Reader.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8356BCE427B377C20074E50C /* TagLibID3v2Reader.mm */; };
8384913A18081FFC00E7332D /* Logging.h in Headers */ = {isa = PBXBuildFile; fileRef = 8384913918081FFC00E7332D /* Logging.h */; };
@ -58,6 +59,7 @@
17C93FC20B90056C008627D6 /* TagLibMetadataReader.m */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = TagLibMetadataReader.m; sourceTree = "<group>"; };
17F563A00C3BDB8F0019975C /* TagLib.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = TagLib.xcodeproj; path = ../../Frameworks/TagLib/TagLib.xcodeproj; sourceTree = SOURCE_ROOT; };
32DBCF630370AF2F00C91783 /* TagLib_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TagLib_Prefix.pch; sourceTree = "<group>"; };
8307D31C286072BF000FF8EB /* SandboxBroker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SandboxBroker.h; path = ../../Utils/SandboxBroker.h; sourceTree = "<group>"; };
8356BCE327B377C20074E50C /* TagLibID3v2Reader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TagLibID3v2Reader.h; sourceTree = "<group>"; };
8356BCE427B377C20074E50C /* TagLibID3v2Reader.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = TagLibID3v2Reader.mm; sourceTree = "<group>"; };
8384913918081FFC00E7332D /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../Utils/Logging.h; sourceTree = "<group>"; };
@ -111,6 +113,7 @@
08FB77AFFE84173DC02AAC07 /* Classes */ = {
isa = PBXGroup;
children = (
8307D31C286072BF000FF8EB /* SandboxBroker.h */,
8384913918081FFC00E7332D /* Logging.h */,
07CACE890ED1AD1000C0F1E8 /* TagLibMetadataWriter.h */,
07CACE8A0ED1AD1000C0F1E8 /* TagLibMetadataWriter.m */,
@ -174,6 +177,7 @@
buildActionMask = 2147483647;
files = (
8384913A18081FFC00E7332D /* Logging.h in Headers */,
8307D31D286072BF000FF8EB /* SandboxBroker.h in Headers */,
8356BCE527B377C20074E50C /* TagLibID3v2Reader.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;

View File

@ -19,6 +19,8 @@
#import <taglib/ogg/vorbis/vorbisfile.h>
#import <taglib/ogg/xiphcomment.h>
#import "SandboxBroker.h"
@implementation TagLibMetadataReader
+ (NSDictionary *)metadataForURL:(NSURL *)url {
@ -26,6 +28,11 @@
return [NSDictionary dictionary];
}
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
[sandboxBroker beginFolderAccess:url];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
// if ( !*TagLib::ascii_encoding ) {
@ -230,6 +237,8 @@
}
}
[sandboxBroker endFolderAccess:url];
return dict;
}

View File

@ -9,13 +9,13 @@
<customObject id="-2" userLabel="File's Owner" customClass="GeneralPreferencesPlugin">
<connections>
<outlet property="appearanceView" destination="CgN-sy-RmM" id="wvB-aW-Gfx"/>
<outlet property="generalPane" destination="tm7-TU-wbV" id="jTO-w4-xwD"/>
<outlet property="hotKeyPane" destination="6" id="14"/>
<outlet property="iTunesStyleCheck" destination="AIz-WH-Wqk" id="2n1-pY-cZR"/>
<outlet property="midiPane" destination="i5B-ga-Atm" id="rbe-uK-5n2"/>
<outlet property="notificationsView" destination="U4w-jw-ca5" id="wVJ-GH-A21"/>
<outlet property="outputPane" destination="57" id="75"/>
<outlet property="playlistView" destination="231" id="244"/>
<outlet property="scrobblerView" destination="0nK-XQ-5MY" id="dFj-Pk-FCG"/>
<outlet property="updatesView" destination="50" id="99"/>
</connections>
</customObject>
@ -368,6 +368,12 @@
<outlet property="view" destination="JXu-ar-J3Y" id="uI3-0O-h4x"/>
</connections>
</customObject>
<customObject id="tm7-TU-wbV" customClass="GeneralPane">
<connections>
<outlet property="sandboxBehaviorController" destination="9mC-3k-IQG" id="QzA-u4-vH7"/>
<outlet property="view" destination="0nK-XQ-5MY" id="TDK-Vn-N5G"/>
</connections>
</customObject>
<arrayController id="59" userLabel="OutputDevices" customClass="OutputsArrayController">
<declaredKeys>
<string>name</string>
@ -389,45 +395,96 @@
</declaredKeys>
<classReference key="objectClass" className="NSDictionary"/>
</arrayController>
<customView id="0nK-XQ-5MY" userLabel="ScrobblerView">
<rect key="frame" x="0.0" y="0.0" width="530" height="99"/>
<customView id="0nK-XQ-5MY" userLabel="GeneralView">
<rect key="frame" x="0.0" y="0.0" width="530" height="202"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<button fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="3gi-0d-78Z">
<rect key="frame" x="18" y="41" width="396" height="18"/>
<autoresizingMask key="autoresizingMask"/>
<buttonCell key="cell" type="check" title="Automatically launch Last.fm client" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="ze8-9p-SeX">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="52" name="value" keyPath="values.automaticallyLaunchLastFM" id="Ere-1R-mgh"/>
</connections>
</button>
<button fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ABj-cO-MaV">
<rect key="frame" x="18" y="69" width="396" height="18"/>
<autoresizingMask key="autoresizingMask"/>
<buttonCell key="cell" type="check" title="Enable Last.fm support (Last.fm client must be installed)" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="2N5-DH-IO6">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="52" name="value" keyPath="values.enableAudioScrobbler" id="R2p-gP-5oR"/>
</connections>
</button>
<button fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Hi4-pa-uDu">
<rect key="frame" x="18" y="13" width="389" height="18"/>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="dIu-uT-8YW">
<rect key="frame" x="18" y="165" width="226" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="Allow Last.fm client to control media keys" bezelStyle="regularSquare" imagePosition="left" inset="2" id="4Yi-67-ivc">
<buttonCell key="cell" type="check" title="Allow insecure SSL connections" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="sva-DV-ina">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="52" name="value" keyPath="values.allowLastfmMediaKeys" id="OZH-0Q-thF"/>
<binding destination="52" name="value" keyPath="values.allowInsecureSSL" id="78K-25-qki"/>
</connections>
</button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="crf-C9-9YF">
<rect key="frame" x="20" y="142" width="170" height="16"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Sandbox allow paths:" id="wWm-AD-cD4">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<scrollView fixedFrame="YES" autohidesScrollers="YES" horizontalLineScroll="24" horizontalPageScroll="10" verticalLineScroll="24" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6b3-9W-Flc">
<rect key="frame" x="20" y="20" width="490" height="115"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>