See 4d-utility-sign-app on how to enable the plugin in 4D.
Accept drag and drop of messages from Apple Mail and Microsoft Outlook
A similar solution for Windows is available: message-file-drop
The plugin is compatible with the new security rules of macOS Mojave, but it is your responsibility to add the "Privacy - AppleEvents Sending Usage Description" (NSAppleEventsUsageDescription
) key to the main app's Info.plist
.
See 4d-plugin-notes for more information.
ACCEPT FILE PROMISES (accept;method{;context})
Parameter | Type | Description |
---|---|---|
accept | LONGINT | 1 or 0 |
method | TEXT | callback method($1:text;$2:text ) |
context | TEXT | any string ($2 passed to method ) |
In method
pass the callback project method name. It will be called with 2 parameters, where $1
is the system full path of the file dropped to 4D, and $2
is a copy of the context
you passed earlier. You can use context
to let the callback notify and update your UI worker/process, for example.
Note: You can disable the folder monitoring process by passing 0
to the command.
Do not abort the callback method. If you abort the execution context, the process will keep running but the method will not longer be called from the plugin until you reopen the structure file.
This plugin is designed to add the following functionalities to 4D:
- Drag and drop emails from typical clients (Mail, Outlook) directly to 4D.
To customise drag and drop event handling, the plugin uses a technique known as method swizzling. For that reason, it is only compatible with the 64-bit Cocoa version of 4D.
When swizzling is activated, the plugin adds some extra code to the following drag and drop obj-c methods from the NSDraggingDestination
protocol: draggingEntered:
draggingUpdated:
prepareForDragOperation:
performDragOperation:
concludeDragOperation:
.
This allows the plugin to perform some extra work when 4D processes drag and drop events (On Drag Over
, On Drop
) on its form objects.
draggingEntered:
nothing special
draggingUpdated:
nothing special
prepareForDragOperation:
nothing special
performDragOperation:
Inspect [[sender draggingPasteboard]types]
.
- Mail (Apple)
If com.apple.mail.PasteboardTypeAutomator
is found, the plugin runs code to get eml
files out of Mail.
Note: Evidently, Mail uses file promises to export a single message (short operation) and Automator to export multiple messages. com.apple.mail.PasteboardTypeAutomator
is a property list, an NSArray
of NSDictionary
, which maps to objects with the structure [{account:string, id:integer, mailbox:string, subject:string}]
. Given the 3 identifiers (account
, mailbox
, id
) it is possible to use AppleScript like this:
on run argv
set param_mailbox to item 1 of argv
set param_account to item 2 of argv
set param_id to item 3 of argv
set param_path to item 4 of argv
tell application "Mail"
set mm to (messages of mailbox param_mailbox of account param_account) whose id is param_id
if (count mm) is 1 then
set m to item 1 of mm
set p to param_path
set s to (source of m) as «class utf8»
try
set f to open for access p with write permission
write s to f
close access f
end try
end if
end tell
end run
For optimisation, the plugin uses ScriptingBridge
to create the eml
file by itself, rather than launching osascript
or NSAppleScript
to run the AppleScript shown above.
MailApplication *application = [SBApplication applicationWithBundleIdentifier:@"com.apple.mail"];
NSArray *mails = [application selection];
NSArray *sources = [mails arrayByApplyingSelector:@selector(source)];
NSUInteger i = 0;
NSString *path = (NSString *)CFURLCopyFileSystemPath((CFURLRef)url, kCFURLPOSIXPathStyle);
for (id source in sources) {
i++;
NSString *dst = [path stringByAppendingFormat:@"/%d.%@", i, @"eml"];
[(NSString *)source writeToFile:dst
atomically:NO
encoding:NSUTF8StringEncoding
error:nil];
}
- Outlook (Microsoft)
Likewise, if dyn.ah62d4rv4gu8ynywrqz31g2phqzkgc65yqzvg82pwqvnhw6df
is found, the plugin runs code to get eml
files out of Outlook.
Note: The above dynamic UTI resolves as ?0=6:4=ERMessagePasteboardType
using the method published here. Outlook used to deliver a type named ERMessagePasteboardType
in version 14 but evidently removed it in version 15.
There is no list of selected messages (as was the case with Mail) but we could assume in AppleScript that the current selection should be exported like this:
on run argv
set param_path to item 1 of argv
tell application "Microsoft Outlook"
set p to param_path
set mm to selection as list
repeat with m in mm
set s to (source of m) as «class utf8»
try
set f to open for access (p & (id of m) & ".eml") with write permission
write s to f
close access f
end try
end repeat
end tell
end run
For optimisation, the plugin uses ScriptingBridge
to create the eml
file by itself, rather than launching osascript
or NSAppleScript
to run the AppleScript shown above. Notice the property is selectedObjects
, not selection
as in Mail.
MailApplication *application = [SBApplication applicationWithBundleIdentifier:@"com.apple.mail"];
NSArray *mails = [application selection];
NSArray *sources = [mails arrayByApplyingSelector:@selector(source)];
NSUInteger i = 0;
NSString *path = (NSString *)CFURLCopyFileSystemPath((CFURLRef)url, kCFURLPOSIXPathStyle);
for (id source in sources) {
i++;
NSString *dst = [path stringByAppendingFormat:@"/%d.%@", i, @"eml"];
[(NSString *)source writeToFile:dst
atomically:NO
encoding:NSUTF8StringEncoding
error:nil];
}
- Fallback
When neither of the app specific types are found, but either kPasteboardTypeFileURLPromise
or NSPromiseContentsPboardType
is found, the plugin falls back to generic file promise handling. In particular, it calls namesOfPromisedFilesDroppedAtDestination:
to request the source to created the promised files. However, this does not seem to work on High Sierra (no issues on El Capitan).
Maybe it is because namesOfPromisedFilesDroppedAtDestination:
has been deprecated in 10.13.
- Folder Watching
Whether the designated apps (Mail, Outlook) are invoked by scripting, or file promises are used, the plugin starts monitoring the destination folder (which is created in the temporary folder, NSItemReplacementDirectory
in NSUserDomainMask
appropriate for NSDesktopDirectory
) using FSEventStream
.
The callback 4D method is executed every time a file is added to the destination folder. Meanwhile, for optimisation, the code to extract and export eml
files from Mail or Outlook are executed in a background thread, with performSelectorInBackground:
.
- Simple API
If neither the app specific types or the file promise types are found, but NSFilenamesPboardType
is found, in other words, a file (not a promise) has been dropped, the same callback 4D method is invoked instantly. 4D does not have to know if the file existed already or was created via scripting or via promises being kept. It just receives a path.