diff --git a/build/macosx/platform_specific_code/juce_mac_Network.mm b/build/macosx/platform_specific_code/juce_mac_Network.mm index 0d87242aa2..15eefcda5e 100644 --- a/build/macosx/platform_specific_code/juce_mac_Network.mm +++ b/build/macosx/platform_specific_code/juce_mac_Network.mm @@ -1,439 +1,469 @@ -/* - ============================================================================== - - This file is part of the JUCE library - "Jules' Utility Class Extensions" - Copyright 2004-7 by Raw Material Software ltd. - - ------------------------------------------------------------------------------ - - JUCE can be redistributed and/or modified 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. - - JUCE 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 JUCE; if not, visit www.gnu.org/licenses or write to the - Free Software Foundation, Inc., 59 Temple Place, Suite 330, - Boston, MA 02111-1307 USA - - ------------------------------------------------------------------------------ - - If you'd like to release a closed-source product which uses JUCE, commercial - licenses are also available: visit www.rawmaterialsoftware.com/juce for - more information. - - ============================================================================== -*/ - -#include "juce_mac_NativeHeaders.h" - -#include -#include -#include -#include - -BEGIN_JUCE_NAMESPACE - -#include "../../../src/juce_core/text/juce_String.h" -#include "../../../src/juce_core/basics/juce_Time.h" -#include "../../../src/juce_core/basics/juce_SystemStats.h" -#include "../../../src/juce_core/basics/juce_Logger.h" -#include "../../../src/juce_core/threads/juce_ScopedLock.h" -#include "../../../src/juce_core/threads/juce_WaitableEvent.h" -#include "../../../src/juce_core/threads/juce_Thread.h" -#include "../../../src/juce_core/containers/juce_MemoryBlock.h" -#include "../../../src/juce_core/text/juce_StringArray.h" -#include "../../../src/juce_core/misc/juce_PlatformUtilities.h" -#include "../../../src/juce_core/io/network/juce_URL.h" - -//#include "juce_mac_HTTPStream.h" - -//============================================================================== -static bool GetEthernetIterator (io_iterator_t* matchingServices) throw() -{ - mach_port_t masterPort; - - if (IOMasterPort (MACH_PORT_NULL, &masterPort) == KERN_SUCCESS) - { - CFMutableDictionaryRef dict = IOServiceMatching (kIOEthernetInterfaceClass); - - if (dict != 0) - { - CFMutableDictionaryRef propDict = CFDictionaryCreateMutable (kCFAllocatorDefault, - 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - - if (propDict != 0) - { - CFDictionarySetValue (propDict, CFSTR (kIOPrimaryInterface), kCFBooleanTrue); - - CFDictionarySetValue (dict, CFSTR (kIOPropertyMatchKey), propDict); - CFRelease (propDict); - } - } - - return IOServiceGetMatchingServices (masterPort, dict, matchingServices) == KERN_SUCCESS; - } - - return false; -} - -int SystemStats::getMACAddresses (int64* addresses, int maxNum, const bool littleEndian) throw() -{ - int numResults = 0; - io_iterator_t it; - - if (GetEthernetIterator (&it)) - { - io_object_t i; - - while ((i = IOIteratorNext (it)) != 0) - { - io_object_t controller; - - if (IORegistryEntryGetParentEntry (i, kIOServicePlane, &controller) == KERN_SUCCESS) - { - CFTypeRef data = IORegistryEntryCreateCFProperty (controller, - CFSTR (kIOMACAddress), - kCFAllocatorDefault, - 0); - if (data != 0) - { - UInt8 addr [kIOEthernetAddressSize]; - zeromem (addr, sizeof (addr)); - - CFDataGetBytes ((CFDataRef) data, CFRangeMake (0, sizeof (addr)), addr); - CFRelease (data); - - int64 a = 0; - for (int i = 6; --i >= 0;) - a = (a << 8) | addr[i]; - - if (! littleEndian) - a = (int64) swapByteOrder ((uint64) a); - - if (numResults < maxNum) - { - *addresses++ = a; - ++numResults; - } - } - - IOObjectRelease (controller); - } - - IOObjectRelease (i); - } - - IOObjectRelease (it); - } - - return numResults; -} - -//============================================================================== -bool PlatformUtilities::launchEmailWithAttachments (const String& targetEmailAddress, - const String& emailSubject, - const String& bodyText, - const StringArray& filesToAttach) -{ - const AutoPool pool; - - String script; - script << "tell application \"Mail\"\r\n" - "set newMessage to make new outgoing message with properties {subject:\"" - << emailSubject.replace (T("\""), T("\\\"")) - << "\", content:\"" - << bodyText.replace (T("\""), T("\\\"")) - << "\" & return & return}\r\n" - "tell newMessage\r\n" - "set visible to true\r\n" - "set sender to \"sdfsdfsdfewf\"\r\n" - "make new to recipient at end of to recipients with properties {address:\"" - << targetEmailAddress - << "\"}\r\n"; - - for (int i = 0; i < filesToAttach.size(); ++i) - { - script << "tell content\r\n" - "make new attachment with properties {file name:\"" - << filesToAttach[i].replace (T("\""), T("\\\"")) - << "\"} at after the last paragraph\r\n" - "end tell\r\n"; - } - - script << "end tell\r\n" - "end tell\r\n"; - - NSAppleScript* s = [[NSAppleScript alloc] - initWithSource: [NSString stringWithUTF8String: (const char*) script.toUTF8()]]; - NSDictionary* error = 0; - const bool ok = [s executeAndReturnError: &error] != nil; - [s release]; - - return ok; -} - -//============================================================================== -END_JUCE_NAMESPACE - -using namespace JUCE_NAMESPACE; - -@interface JuceURLConnection : NSInputStream -{ - NSURLConnection* connection; - NSMutableData* data; - NSThread* runLoopThread; - NSRunLoop* runLoop; - bool initialised, hasFailed, hasFinished; - int position; - NSLock* dataLock; -} - -- (JuceURLConnection*) initWithRequest: (NSURLRequest*) req; -- (void) dealloc; -- (void) connection: (NSURLConnection*) connection didReceiveResponse: (NSURLResponse*) response; -- (void) connection: (NSURLConnection*) connection didFailWithError: (NSError*) error; -- (void) connection: (NSURLConnection*) connection didReceiveData: (NSData*) data; -- (void) connectionDidFinishLoading: (NSURLConnection*) connection; - -- (BOOL) isOpen; -- (int) read: (char*) dest numBytes: (int) num; -- (int) readPosition; - -- (void) runThread: (id) dummyParam; - -@end - -@implementation JuceURLConnection - -- (JuceURLConnection*) initWithRequest: (NSURLRequest*) req -{ - [super init]; - data = [[NSMutableData data] retain]; - dataLock = [[NSLock alloc] init]; - connection = 0; - initialised = false; - hasFailed = false; - hasFinished = false; - - runLoopThread = [[NSThread alloc] initWithTarget: self - selector: @selector (runThread:) - object: req]; - - [runLoopThread start]; - - while (! [runLoopThread isExecuting]) - Thread::sleep (1); - - while ([runLoopThread isExecuting] && ! initialised) - Thread::sleep (1); - - return self; -} - -- (void) dealloc -{ - [connection cancel]; - [runLoopThread cancel]; - - while ([runLoopThread isExecuting]) - [NSThread sleepForTimeInterval: 0.001]; - - [runLoopThread release]; - [connection release]; - [data release]; - [dataLock release]; - [super dealloc]; -} - -- (void) runThread: (id) request -{ - AutoPool pool; - - runLoop = [NSRunLoop currentRunLoop]; - - connection = [[NSURLConnection alloc] initWithRequest: request - delegate: self - startImmediately: YES]; - - if (connection == nil) - { - hasFailed = true; - return; - } - - initialised = true; - - while (! ([[NSThread currentThread] isCancelled] || hasFailed || hasFinished)) - { - [[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]]; - } -} - -- (void) connection: (NSURLConnection*) connection didReceiveResponse: (NSURLResponse*) response -{ - [dataLock lock]; - [data setLength: 0]; - [dataLock unlock]; -} - -- (void) connection: (NSURLConnection*) connection didFailWithError: (NSError*) error -{ - NSLog ([error description]); - hasFailed = true; -} - -- (void) connection: (NSURLConnection*) connection didReceiveData: (NSData*) newData -{ - [dataLock lock]; - [data appendData: newData]; - [dataLock unlock]; -} - -- (void) connectionDidFinishLoading: (NSURLConnection*) connection -{ - hasFinished = true; -} - -- (BOOL) isOpen -{ - return connection != 0 && ! hasFailed; -} - -- (int) readPosition -{ - return position; -} - -- (int) read: (char*) dest numBytes: (int) numNeeded -{ - int numDone = 0; - - while (numNeeded > 0) - { - int available = jmin (numNeeded, [data length]); - - if (available > 0) - { - [dataLock lock]; - [data getBytes: dest length: available]; - [data replaceBytesInRange: NSMakeRange (0, available) withBytes: nil length: 0]; - [dataLock unlock]; - - numDone += available; - numNeeded -= available; - dest += available; - } - else - { - if (hasFailed || hasFinished) - break; - - Thread::sleep (1); - } - } - - position += numDone; - return numDone; -} - -@end -BEGIN_JUCE_NAMESPACE - - -bool juce_isOnLine() -{ - return true; -} - -void* juce_openInternetFile (const String& url, - const String& headers, - const MemoryBlock& postData, - const bool isPost, - URL::OpenStreamProgressCallback* callback, - void* callbackContext, - int timeOutMs) -{ - AutoPool pool; - - NSMutableURLRequest* req = [NSMutableURLRequest - requestWithURL: [NSURL URLWithString: juceStringToNS (url)] - cachePolicy: NSURLRequestUseProtocolCachePolicy - timeoutInterval: timeOutMs <= 0 ? 60.0 : (timeOutMs / 1000.0)]; - - if (req == nil) - return 0; - - [req setHTTPMethod: isPost ? @"POST" : @"GET"]; - //[req setCachePolicy: NSURLRequestReloadIgnoringLocalAndRemoteCacheData]; - - StringArray headerLines; - headerLines.addLines (headers); - headerLines.removeEmptyStrings (true); - - for (int i = 0; i < headerLines.size(); ++i) - { - const String key (headerLines[i].upToFirstOccurrenceOf (T(":"), false, false).trim()); - const String value (headerLines[i].fromFirstOccurrenceOf (T(":"), false, false).trim()); - - if (key.isNotEmpty() && value.isNotEmpty()) - [req addValue: juceStringToNS (value) forHTTPHeaderField: juceStringToNS (key)]; - } - - if (isPost && postData.getSize() > 0) - { - [req setHTTPBody: [NSData dataWithBytes: postData.getData() - length: postData.getSize()]]; - } - - JuceURLConnection* const s = [[JuceURLConnection alloc] initWithRequest: req]; - - if ([s isOpen]) - return s; - - delete s; - return 0; -} - -void juce_closeInternetFile (void* handle) -{ - JuceURLConnection* const s = (JuceURLConnection*) handle; - - if (s != 0) - { - AutoPool pool; - [s release]; - } -} - -int juce_readFromInternetFile (void* handle, void* buffer, int bytesToRead) -{ - JuceURLConnection* const s = (JuceURLConnection*) handle; - - if (s != 0) - { - AutoPool pool; - return [s read: (char*) buffer numBytes: bytesToRead]; - } - - return 0; -} - -int juce_seekInInternetFile (void* handle, int newPosition) -{ - JuceURLConnection* const s = (JuceURLConnection*) handle; - - if (s != 0) - return [s readPosition]; - - return 0; -} - - -END_JUCE_NAMESPACE +/* + ============================================================================== + + This file is part of the JUCE library - "Jules' Utility Class Extensions" + Copyright 2004-7 by Raw Material Software ltd. + + ------------------------------------------------------------------------------ + + JUCE can be redistributed and/or modified 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. + + JUCE 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 JUCE; if not, visit www.gnu.org/licenses or write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------------ + + If you'd like to release a closed-source product which uses JUCE, commercial + licenses are also available: visit www.rawmaterialsoftware.com/juce for + more information. + + ============================================================================== +*/ + +#include "juce_mac_NativeHeaders.h" + +#include +#include +#include +#include + +BEGIN_JUCE_NAMESPACE + +#include "../../../src/juce_core/text/juce_String.h" +#include "../../../src/juce_core/basics/juce_Time.h" +#include "../../../src/juce_core/basics/juce_SystemStats.h" +#include "../../../src/juce_core/basics/juce_Logger.h" +#include "../../../src/juce_core/threads/juce_ScopedLock.h" +#include "../../../src/juce_core/threads/juce_WaitableEvent.h" +#include "../../../src/juce_core/threads/juce_Thread.h" +#include "../../../src/juce_core/containers/juce_MemoryBlock.h" +#include "../../../src/juce_core/text/juce_StringArray.h" +#include "../../../src/juce_core/misc/juce_PlatformUtilities.h" +#include "../../../src/juce_core/io/network/juce_URL.h" + +//#include "juce_mac_HTTPStream.h" + +//============================================================================== +static bool GetEthernetIterator (io_iterator_t* matchingServices) throw() +{ + mach_port_t masterPort; + + if (IOMasterPort (MACH_PORT_NULL, &masterPort) == KERN_SUCCESS) + { + CFMutableDictionaryRef dict = IOServiceMatching (kIOEthernetInterfaceClass); + + if (dict != 0) + { + CFMutableDictionaryRef propDict = CFDictionaryCreateMutable (kCFAllocatorDefault, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + if (propDict != 0) + { + CFDictionarySetValue (propDict, CFSTR (kIOPrimaryInterface), kCFBooleanTrue); + + CFDictionarySetValue (dict, CFSTR (kIOPropertyMatchKey), propDict); + CFRelease (propDict); + } + } + + return IOServiceGetMatchingServices (masterPort, dict, matchingServices) == KERN_SUCCESS; + } + + return false; +} + +int SystemStats::getMACAddresses (int64* addresses, int maxNum, const bool littleEndian) throw() +{ + int numResults = 0; + io_iterator_t it; + + if (GetEthernetIterator (&it)) + { + io_object_t i; + + while ((i = IOIteratorNext (it)) != 0) + { + io_object_t controller; + + if (IORegistryEntryGetParentEntry (i, kIOServicePlane, &controller) == KERN_SUCCESS) + { + CFTypeRef data = IORegistryEntryCreateCFProperty (controller, + CFSTR (kIOMACAddress), + kCFAllocatorDefault, + 0); + if (data != 0) + { + UInt8 addr [kIOEthernetAddressSize]; + zeromem (addr, sizeof (addr)); + + CFDataGetBytes ((CFDataRef) data, CFRangeMake (0, sizeof (addr)), addr); + CFRelease (data); + + int64 a = 0; + for (int i = 6; --i >= 0;) + a = (a << 8) | addr[i]; + + if (! littleEndian) + a = (int64) swapByteOrder ((uint64) a); + + if (numResults < maxNum) + { + *addresses++ = a; + ++numResults; + } + } + + IOObjectRelease (controller); + } + + IOObjectRelease (i); + } + + IOObjectRelease (it); + } + + return numResults; +} + +//============================================================================== +bool PlatformUtilities::launchEmailWithAttachments (const String& targetEmailAddress, + const String& emailSubject, + const String& bodyText, + const StringArray& filesToAttach) +{ + const AutoPool pool; + + String script; + script << "tell application \"Mail\"\r\n" + "set newMessage to make new outgoing message with properties {subject:\"" + << emailSubject.replace (T("\""), T("\\\"")) + << "\", content:\"" + << bodyText.replace (T("\""), T("\\\"")) + << "\" & return & return}\r\n" + "tell newMessage\r\n" + "set visible to true\r\n" + "set sender to \"sdfsdfsdfewf\"\r\n" + "make new to recipient at end of to recipients with properties {address:\"" + << targetEmailAddress + << "\"}\r\n"; + + for (int i = 0; i < filesToAttach.size(); ++i) + { + script << "tell content\r\n" + "make new attachment with properties {file name:\"" + << filesToAttach[i].replace (T("\""), T("\\\"")) + << "\"} at after the last paragraph\r\n" + "end tell\r\n"; + } + + script << "end tell\r\n" + "end tell\r\n"; + + NSAppleScript* s = [[NSAppleScript alloc] + initWithSource: [NSString stringWithUTF8String: (const char*) script.toUTF8()]]; + NSDictionary* error = 0; + const bool ok = [s executeAndReturnError: &error] != nil; + [s release]; + + return ok; +} + +//============================================================================== +END_JUCE_NAMESPACE + +using namespace JUCE_NAMESPACE; + +//============================================================================== +@interface JuceURLConnection : NSObject +{ + NSURLRequest* request; + NSURLConnection* connection; + NSMutableData* data; + Thread* runLoopThread; + bool initialised, hasFailed, hasFinished; + int position; + NSLock* dataLock; +} + +- (JuceURLConnection*) initWithRequest: (NSURLRequest*) req withCallback: (URL::OpenStreamProgressCallback*) callback withContext: (void*) context; +- (void) dealloc; +- (void) connection: (NSURLConnection*) connection didReceiveResponse: (NSURLResponse*) response; +- (void) connection: (NSURLConnection*) connection didFailWithError: (NSError*) error; +- (void) connection: (NSURLConnection*) connection didReceiveData: (NSData*) data; +- (void) connectionDidFinishLoading: (NSURLConnection*) connection; + +- (BOOL) isOpen; +- (int) read: (char*) dest numBytes: (int) num; +- (int) readPosition; +- (void) stop; +- (void) createConnection; + +@end + +class JuceURLConnectionMessageThread : public Thread +{ + JuceURLConnection* owner; + +public: + JuceURLConnectionMessageThread (JuceURLConnection* owner_) + : Thread (T("http connection")), + owner (owner_) + { + startThread(); + } + + ~JuceURLConnectionMessageThread() + { + stopThread (5000); + } + + void run() + { + AutoPool pool; + [owner createConnection]; + + while (! threadShouldExit()) + { + AutoPool pool; + [[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]]; + } + } +}; + +@implementation JuceURLConnection + +- (JuceURLConnection*) initWithRequest: (NSURLRequest*) req + withCallback: (URL::OpenStreamProgressCallback*) callback + withContext: (void*) context; +{ + [super init]; + request = req; + [request retain]; + data = [[NSMutableData data] retain]; + dataLock = [[NSLock alloc] init]; + connection = 0; + initialised = false; + hasFailed = false; + hasFinished = false; + + runLoopThread = new JuceURLConnectionMessageThread (self); + + while (runLoopThread->isThreadRunning() && ! initialised) + { + if (callback != 0) + callback (context, -1, [[request HTTPBody] length]); + + Thread::sleep (1); + } + + return self; +} + +- (void) dealloc +{ + [self stop]; + + delete runLoopThread; + [connection release]; + [data release]; + [dataLock release]; + [request release]; + [super dealloc]; +} + +- (void) createConnection +{ + connection = [[NSURLConnection alloc] initWithRequest: request + delegate: self]; + + if (connection == nil) + runLoopThread->signalThreadShouldExit(); +} + +- (void) connection: (NSURLConnection*) connection didReceiveResponse: (NSURLResponse*) response +{ + [dataLock lock]; + [data setLength: 0]; + [dataLock unlock]; + initialised = true; +} + +- (void) connection: (NSURLConnection*) connection didFailWithError: (NSError*) error +{ + NSLog ([error description]); + hasFailed = true; + initialised = true; + runLoopThread->signalThreadShouldExit(); +} + +- (void) connection: (NSURLConnection*) connection didReceiveData: (NSData*) newData +{ + [dataLock lock]; + [data appendData: newData]; + [dataLock unlock]; + initialised = true; +} + +- (void) connectionDidFinishLoading: (NSURLConnection*) connection +{ + hasFinished = true; + initialised = true; + runLoopThread->signalThreadShouldExit(); +} + +- (BOOL) isOpen +{ + return connection != 0 && ! hasFailed; +} + +- (int) readPosition +{ + return position; +} + +- (int) read: (char*) dest numBytes: (int) numNeeded +{ + int numDone = 0; + + while (numNeeded > 0) + { + int available = jmin (numNeeded, [data length]); + + if (available > 0) + { + [dataLock lock]; + [data getBytes: dest length: available]; + [data replaceBytesInRange: NSMakeRange (0, available) withBytes: nil length: 0]; + [dataLock unlock]; + + numDone += available; + numNeeded -= available; + dest += available; + } + else + { + if (hasFailed || hasFinished) + break; + + Thread::sleep (1); + } + } + + position += numDone; + return numDone; +} + +- (void) stop +{ + [connection cancel]; + runLoopThread->stopThread (5000); +} + +@end +BEGIN_JUCE_NAMESPACE + + +bool juce_isOnLine() +{ + return true; +} + +void* juce_openInternetFile (const String& url, + const String& headers, + const MemoryBlock& postData, + const bool isPost, + URL::OpenStreamProgressCallback* callback, + void* callbackContext, + int timeOutMs) +{ + AutoPool pool; + + NSMutableURLRequest* req = [NSMutableURLRequest + requestWithURL: [NSURL URLWithString: juceStringToNS (url)] + cachePolicy: NSURLRequestUseProtocolCachePolicy + timeoutInterval: timeOutMs <= 0 ? 60.0 : (timeOutMs / 1000.0)]; + + if (req == nil) + return 0; + + [req setHTTPMethod: isPost ? @"POST" : @"GET"]; + //[req setCachePolicy: NSURLRequestReloadIgnoringLocalAndRemoteCacheData]; + + StringArray headerLines; + headerLines.addLines (headers); + headerLines.removeEmptyStrings (true); + + for (int i = 0; i < headerLines.size(); ++i) + { + const String key (headerLines[i].upToFirstOccurrenceOf (T(":"), false, false).trim()); + const String value (headerLines[i].fromFirstOccurrenceOf (T(":"), false, false).trim()); + + if (key.isNotEmpty() && value.isNotEmpty()) + [req addValue: juceStringToNS (value) forHTTPHeaderField: juceStringToNS (key)]; + } + + if (isPost && postData.getSize() > 0) + { + [req setHTTPBody: [NSData dataWithBytes: postData.getData() + length: postData.getSize()]]; + } + + JuceURLConnection* const s = [[JuceURLConnection alloc] initWithRequest: req + withCallback: callback + withContext: callbackContext]; + + if ([s isOpen]) + return s; + + [s release]; + return 0; +} + +void juce_closeInternetFile (void* handle) +{ + JuceURLConnection* const s = (JuceURLConnection*) handle; + + if (s != 0) + { + AutoPool pool; + [s stop]; + [s release]; + } +} + +int juce_readFromInternetFile (void* handle, void* buffer, int bytesToRead) +{ + JuceURLConnection* const s = (JuceURLConnection*) handle; + + if (s != 0) + { + AutoPool pool; + return [s read: (char*) buffer numBytes: bytesToRead]; + } + + return 0; +} + +int juce_seekInInternetFile (void* handle, int newPosition) +{ + JuceURLConnection* const s = (JuceURLConnection*) handle; + + if (s != 0) + return [s readPosition]; + + return 0; +} + + +END_JUCE_NAMESPACE