Saving an Apple Mail Message using ScriptBridge - cocoa

I am trying to save a selected email from Apple Mail using ScriptBridge.
I have already created the Mail.h file and in my program I have successfully done other things with the Apple Mail ScriptBridge (like forwarding messages etc.)
Here is my current code. I get no error messages and the code is running fine; only the file never gets created.
I am using Xcode 4.6. on Mountain Lion 10.8.2. The deployment target of my app is 10.8.
- (void)saveEmail {
MailApplication *mailApp = [SBApplication applicationWithBundleIdentifier:#"com.apple.Mail"];
SBElementArray *viewers = [mailApp messageViewers];
for (MailMessageViewer *viewer in viewers) {
NSArray *selectedMessages = [viewer selectedMessages];
#try {
for (MailMessage *selectedMessage in selectedMessages) {
NSString *filePath = [NSString stringWithFormat:#"%#%#",#"/Users/patrick/Documents/",#"tmp.rtf"];
NSURL *fileUrl = [NSURL fileURLWithPath:filePath];
[selectedMessage saveIn:fileUrl as:MailSaveableFileFormatNativeFormat];
}
}
#catch (NSException *exception) {
NSLog(#"Exception:%#", exception);
}
}
}

Have exactly the same problem. Seems saveIn isn't implemented in Mail.
I have a workaround with this code:
[message.source writeToURL:mailUrl
atomically:YES
encoding:NSUTF8StringEncoding
error:nil];
Where message is an instance of MailMessage
This seems to work correctly most of the time. But sometimes the attachments are empty in the saved mail. So if anyone has a better solution...

Related

Launch OS X Application Programmatically

How do I programmatically open an OS X app (.app) that is contained within the app I am building?
The preferred way of doing this on OS X is through the NSWorkspace class, which provides a couple of methods to launch applications. One of them, launchApplicationAtURL:options:configuration:error: allows you to specify a file URL to the application to launch. In addition of not having sandbox problems like the system() and Apple Event solution, it also gives you an easy way to manipulate how the application should be launched, eg. you can specify environment variables to be passed to the application.
Following Code snippet is used to launch an app programmatically:
NSString *path = [[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent];
path = [path stringByAppendingString:#"/MyApp.app"]; // App Path
NSWorkspace *ws=[NSWorkspace sharedWorkspace];
NSURL* url = [NSURL fileURLWithPath:path isDirectory:NO];
[ws launchApplicationAtURL:url
options:NSWorkspaceLaunchWithoutActivation
configuration:nil
error:nil];
You could use an Apple Script.
NSDictionary* errorDict;
NSAppleEventDescriptor* returnDescriptor = NULL;
NSAppleScript* scriptObject;
scriptObject = [[NSAppleScript alloc] initWithSource:#"try\n
run application \"Macintosh HD:Applications:_Sandbox-AppleScript0.app\"\n
on error number -609 # 'Connection is invalid' error that is spuriously reported # simply ignore\n
end try"];
if (returnDescriptor != NULL) {
// successful execution
if (kAENullEvent != [returnDescriptor descriptorType]) {
// script returned an AppleScript result
if (cAEList == [returnDescriptor descriptorType]) {
// result is a list of other descriptors
}
else {
// coerce the result to the appropriate ObjC type
}
}
}

Best location to store config, plugins for my OS X application

I'm programming an OS X application and would like to know what is considered to be the best location to store application data like config-files and plugins for my program into.
The configs aren't in defaults format since I also deploy this application on Windows.
Usually in your app's subfolder within the Application Support directory is where stuff like is expected to be stored. Apple provides a nice function in their documentation for getting a standardized NSURL for your Application Support directory.
Extracted from their documentation:
- (NSURL*)applicationDirectory
{
NSString* bundleID = [[NSBundle mainBundle] bundleIdentifier];
NSFileManager*fm = [NSFileManager defaultManager];
NSURL* dirPath = nil;
// Find the application support directory in the home directory.
NSArray* appSupportDir = [fm URLsForDirectory:NSApplicationSupportDirectory
inDomains:NSUserDomainMask];
if ([appSupportDir count] > 0)
{
// Append the bundle ID to the URL for the
// Application Support directory
dirPath = [[appSupportDir objectAtIndex:0] URLByAppendingPathComponent:bundleID];
// If the directory does not exist, this method creates it.
// This method is only available in OS X v10.7 and iOS 5.0 or later.
NSError* theError = nil;
if (![fm createDirectoryAtURL:dirPath withIntermediateDirectories:YES
attributes:nil error:&theError])
{
// Handle the error.
return nil;
}
}
return dirPath;
}
You can call the subpath within NSApplicationDirectory anything you want, but they recommend using your bundle identifier, as seen in the example above.

dictionaryWithContentsOfFile and Sandbox

I've created a mac app that load a xml file from an user selected folder, and after using the app, the user saves a customized file (.adgf)
When i try to load the .adgf file (that is a plist file) that has the xml path within one record i call
dictionaryWithContentsOfFile but it return me a "nil". I think the problem is the sandbox (sometime it works sometime not). The string path is correct.
Maybe when the user load the xml file should i save within of particular app "Document folder"?
Edit:
I'm trying right now the Bookmark Data solution and I retraive a NSURL but it doen't work. The code I'm using is this:
- (NSData *)bookmarkFromURL:(NSURL *)url {
NSError *error = nil;
NSData *bookmark = [url bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope
includingResourceValuesForKeys:NULL
relativeToURL:NULL
error:&error];
if (error) {
NSLog(#"Error creating bookmark for URL (%#): %#", url, error);
[NSApp presentError:error];
}
return bookmark;
}
- (NSURL *)urlFromBookmark:(NSData *)bookmark {
NSURL *url = [NSURL URLByResolvingBookmarkData:bookmark
options:NSURLBookmarkResolutionWithSecurityScope
relativeToURL:NULL
bookmarkDataIsStale:NO
error:NULL];
return url;
}
After the user stores the file you should take the bookmark data from the URL using
-[NSURL bookmarkDataWithOptions: includingResourceValuesForKeys: relativeToURL: error:]
Use NSURLBookmarkCreationWithSecurityScope for the options.
This NSData object should be stored somewhere (plist?) and when you want to read the file again in a later session you can create a sandbox compliant NSURL from the bookmark data using +[NSURL
URLByResolvingBookmarkData:options:relativeToURL:bookmarkDataIsStale:error:]

Call a web service with MKNetworkoperation

In our development team we have implemented a WEB Service which will authenticate a client.
From the iPhone application we need to send the client's information to the web service and in order to do so, I have written the following function.
-(void)authenticateClient:(NSString*)theContractNumber
ClientCode:(NSString*)theClientCode
CellPhone:(NSString*)theCellPhone
appleID:(NSString*)theAppleID
{
NSLog(#"Begin Send the information to the Web Service",nil);
NSString *uid = [UIDevice currentDevice].uniqueIdentifier;
NSDictionary *formParams = [NSDictionary dictionaryWithObjectsAndKeys:
theClientCode, #"ClientCode",
theContractNumber, #"ContractCode",
theAppleID, #"AppleID",
#" ", #"AndroidID",
#" ", #"WindowsID",
uid, #"AppleDeviceID",
#" ", #"AndroidDeviceID",
#" ", #"WindowsDeviceID",
theCellPhone, #"TelephoneNumber"
, nil];
MKNetworkOperation *operation = [self.engine operationWithPath:#"/services/Authentication.ashx"
params: formParams
httpMethod:#"POST"];
[operation addCompletionHandler:
^(MKNetworkOperation *operation) {
NSLog(#"%#", [operation responseString]);
}
errorHandler:^(MKNetworkOperation *errorOperation, NSError *error) {
NSLog(#"%#", error);
}];
[self.engine enqueueOperation:operation] ;
}
the function works (or seems to works with no errors) but in fact it does not do anything. It passes from the [operation addCompletionHandler: block but it does not do anything. I have also executed it step by step and again I saw that the application reaches this line and then it executes it and directly goes to the [self.engine enqueueOperation:operation] line without going inside the code block.
Does anyone can help on this?
Thank you.

Uploading a file with POST using AFNetworking

So I'm trying to upload an XML file to a server with POST using AFNetworking.
So using example code from their site I have this set up. When it runs, something is uploaded to the server (or at least it leaves my computer). I can monitor the upload, when the upload is finished, the server recognizes that it completed and goes to load the file, but it loads an old XML. So its connecting properly to the server, but I'm not sure why the file upload isn’t working correctly. Also I just want to send the file, the server doesn’t need any headers or parameters etc.
So I'm wondering if I’ve stored the data correctly? Or if I'm not sending it the server properly or what? Any suggestions would be helpful
NSData *iTunesXMLData = [NSData dataWithContentsOfFile:filePath];
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
/* NSMutableURLRequest *request =[httpClientmultipartFormRequestWithMethod:#"POST"
path:#"/upload.php?id=5" parameters:nil constructingBodyWithBlock: ^(id <AFMultipartFormData>formData) {
[formData appendPartWithFileData:iTunesXMLData name:#"iTunes Music Library" fileName:#"iTunes Music Library.xml" mimeType:#"application/xml"];
}];*/
//I tried this way also, both did the same thing
NSMutableURLRequest *request = [httpClient multipartFormRequestWithMethod:#"POST" path:#"/upload.php?id=5" parameters:nil constructingBodyWithBlock: ^(id <AFMultipartFormData>formData) {
[formData appendPartWithFormData:iTunesXMLData name:#"iTunes Music Library"];
}];`
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];`
NSLog(#"Operation: %#", operation);
[operation setUploadProgressBlock:^(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite) {
NSLog(#"Sent %lld of %lld bytes", totalBytesWritten, totalBytesExpectedToWrite);
}];
[operation start];
Have you tried to catch the success/failure of the operation? Try this after setUploadProgressBlock:
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
// Operation ended successfully
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
// Something happened!
NSLog(#"ERROR: %#, %#", operation, error);
// Here you can catch operation.responseString to see the response of your server
}];
This is an easy way to know what your server returned. If something uploads to your server, double check that you're getting the right file. AFAIK, your AFNetwork seems ok.

Resources