1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-22 01:34:21 +00:00
JUCE/src/native/mac/juce_mac_Network.mm

429 lines
12 KiB
Text

/*
==============================================================================
This file is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-10 by Raw Material Software Ltd.
------------------------------------------------------------------------------
JUCE can be redistributed and/or modified under the terms of the GNU General
Public License (Version 2), as published by the Free Software Foundation.
A copy of the license is included in the JUCE distribution, or can be found
online at www.gnu.org/licenses.
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.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.rawmaterialsoftware.com/juce for more information.
==============================================================================
*/
// (This file gets included by juce_mac_NativeCode.mm, rather than being
// compiled on its own).
#if JUCE_INCLUDED_FILE
//==============================================================================
int SystemStats::getMACAddresses (int64* addresses, int maxNum, const bool littleEndian)
{
#ifndef IFT_ETHER
#define IFT_ETHER 6
#endif
ifaddrs* addrs = 0;
int numResults = 0;
if (getifaddrs (&addrs) == 0)
{
const ifaddrs* cursor = addrs;
while (cursor != 0 && numResults < maxNum)
{
sockaddr_storage* sto = (sockaddr_storage*) cursor->ifa_addr;
if (sto->ss_family == AF_LINK)
{
const sockaddr_dl* const sadd = (const sockaddr_dl*) cursor->ifa_addr;
if (sadd->sdl_type == IFT_ETHER)
{
const uint8* const addr = ((const uint8*) sadd->sdl_data) + sadd->sdl_nlen;
uint64 a = 0;
for (int i = 6; --i >= 0;)
a = (a << 8) | addr [littleEndian ? i : (5 - i)];
*addresses++ = (int64) a;
++numResults;
}
}
cursor = cursor->ifa_next;
}
freeifaddrs (addrs);
}
return numResults;
}
//==============================================================================
bool PlatformUtilities::launchEmailWithAttachments (const String& targetEmailAddress,
const String& emailSubject,
const String& bodyText,
const StringArray& filesToAttach)
{
#if JUCE_IPHONE
//xxx probably need to use MFMailComposeViewController
jassertfalse
return false;
#else
const ScopedAutoReleasePool pool;
String script;
script << "tell application \"Mail\"\r\n"
"set newMessage to make new outgoing message with properties {subject:\""
<< emailSubject.replace ("\"", "\\\"")
<< "\", content:\""
<< bodyText.replace ("\"", "\\\"")
<< "\" & 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 ("\"", "\\\"")
<< "\"} 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: juceStringToNS (script)];
NSDictionary* error = 0;
const bool ok = [s executeAndReturnError: &error] != nil;
[s release];
return ok;
#endif
}
//==============================================================================
END_JUCE_NAMESPACE
using namespace JUCE_NAMESPACE;
//==============================================================================
#define JuceURLConnection MakeObjCClassName(JuceURLConnection)
@interface JuceURLConnection : NSObject
{
@public
NSURLRequest* request;
NSURLConnection* connection;
NSMutableData* data;
Thread* runLoopThread;
bool initialised, hasFailed, hasFinished;
int position;
int64 contentLength;
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 ("http connection"),
owner (owner_)
{
}
~JuceURLConnectionMessageThread()
{
stopThread (10000);
}
void run()
{
[owner createConnection];
while (! threadShouldExit())
{
const ScopedAutoReleasePool 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;
contentLength = -1;
runLoopThread = new JuceURLConnectionMessageThread (self);
runLoopThread->startThread();
while (runLoopThread->isThreadRunning() && ! initialised)
{
if (callback != 0)
callback (context, -1, (int) [[request HTTPBody] length]);
Thread::sleep (1);
}
return self;
}
- (void) dealloc
{
[self stop];
deleteAndZero (runLoopThread);
[connection release];
[data release];
[dataLock release];
[request release];
[super dealloc];
}
- (void) createConnection
{
connection = [[NSURLConnection alloc] initWithRequest: request
delegate: [self retain]];
if (connection == nil)
runLoopThread->signalThreadShouldExit();
}
- (void) connection: (NSURLConnection*) conn didReceiveResponse: (NSURLResponse*) response
{
(void) conn;
[dataLock lock];
[data setLength: 0];
[dataLock unlock];
initialised = true;
contentLength = [response expectedContentLength];
}
- (void) connection: (NSURLConnection*) conn didFailWithError: (NSError*) error
{
(void) conn;
DBG (nsStringToJuce ([error description]));
hasFailed = true;
initialised = true;
if (runLoopThread != 0)
runLoopThread->signalThreadShouldExit();
}
- (void) connection: (NSURLConnection*) conn didReceiveData: (NSData*) newData
{
(void) conn;
[dataLock lock];
[data appendData: newData];
[dataLock unlock];
initialised = true;
}
- (void) connectionDidFinishLoading: (NSURLConnection*) conn
{
(void) conn;
hasFinished = true;
initialised = true;
if (runLoopThread != 0)
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, (int) [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];
if (runLoopThread != 0)
runLoopThread->stopThread (10000);
}
@end
BEGIN_JUCE_NAMESPACE
void* juce_openInternetFile (const String& url,
const String& headers,
const MemoryBlock& postData,
const bool isPost,
URL::OpenStreamProgressCallback* callback,
void* callbackContext,
int timeOutMs)
{
const ScopedAutoReleasePool 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 (":", false, false).trim());
const String value (headerLines[i].fromFirstOccurrenceOf (":", 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)
{
const ScopedAutoReleasePool pool;
[s stop];
[s release];
}
}
int juce_readFromInternetFile (void* handle, void* buffer, int bytesToRead)
{
JuceURLConnection* const s = (JuceURLConnection*) handle;
if (s != 0)
{
const ScopedAutoReleasePool pool;
return [s read: (char*) buffer numBytes: bytesToRead];
}
return 0;
}
int64 juce_getInternetFileContentLength (void* handle)
{
JuceURLConnection* const s = (JuceURLConnection*) handle;
if (s != 0)
return s->contentLength;
return -1;
}
int juce_seekInInternetFile (void* handle, int /*newPosition*/)
{
JuceURLConnection* const s = (JuceURLConnection*) handle;
if (s != 0)
return [s readPosition];
return 0;
}
#endif