├── README.md ├── plugin.xml ├── src ├── android │ ├── EmailAttachmentProvider.java │ └── EmailComposer.java └── ios │ ├── EmailComposer.h │ ├── EmailComposer.m │ ├── NSData+Base64.h │ └── NSData+Base64.m └── www └── EmailComposer.js /README.md: -------------------------------------------------------------------------------- 1 | # Email Composer with Attachments Plugin # 2 | 3 | Email Composer with Attachments allows for sending of emails with attachments. Modified from the original Phonegap plugin to accept attachment data directly from JavaScript, encoded in Base64. 4 | 5 | The original source + commit history is no longer maintained. 6 | You can find it here: 7 | 8 | https://github.com/phonegap/phonegap-plugins/tree/DEPRECATED/iPhone/EmailComposer 9 | 10 | and here : 11 | 12 | https://github.com/phonegap/phonegap-plugins/tree/DEPRECATED/iOS/EmailComposer 13 | 14 | and here : 15 | 16 | https://github.com/phonegap/phonegap-plugins/tree/DEPRECATED/iOS/EmailComposerWithAttachments 17 | 18 | 19 | **Callable interface:** 20 | ``` 21 | window.plugins.emailComposer.showEmailComposerWithCallback(callback,subject,body,toRecipients,ccRecipients,bccRecipients,isHtml,attachments,attachmentsData); 22 | ``` 23 | 24 | **Parameters:** 25 | - callback: a js function that will receive return parameter from the plugin 26 | - subject: a string representing the subject of the email; can be null 27 | - body: a string representing the email body (could be HTML code, in this case set **isHtml** to **true**); can be null 28 | - toRecipients: a js array containing all the email addresses for TO field; can be null/empty 29 | - ccRecipients: a js array containing all the email addresses for CC field; can be null/empty 30 | - bccRecipients: a js array containing all the email addresses for BCC field; can be null/empty 31 | - isHtml: a bool value indicating if the body is HTML or plain text 32 | - attachments: a js array containing all full paths to the files you want to attach; can be null/empty 33 | - attachmentsData: a js array of fileName-fileData array pairs, e.g. [['filename1','base64data1'],['filename2','base64data2']] 34 | 35 | ## Special thanks ## 36 | 37 | I would like to say thanks to Guido Sabatini (https://github.com/phonegap/phonegap-plugins/blob/master/iOS/EmailComposerWithAttachments/) for the code we have (re)used and added extra functionalities to. 38 | 39 | ## License ## 40 | 41 | [The MIT License (MIT)](http://www.opensource.org/licenses/mit-license.html) 42 | 43 | Permission is hereby granted, free of charge, to any person obtaining a copy 44 | of this software and associated documentation files (the "Software"), to deal 45 | in the Software without restriction, including without limitation the rights 46 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 47 | copies of the Software, and to permit persons to whom the Software is 48 | furnished to do so, subject to the following conditions: 49 | 50 | The above copyright notice and this permission notice shall be included in 51 | all copies or substantial portions of the Software. 52 | 53 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 54 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 55 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 56 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 57 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 58 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 59 | THE SOFTWARE. 60 | -------------------------------------------------------------------------------- /plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | Email Composer with Attachments 8 | 9 | 10 | <p>Email Composer with Attachments</p> 11 | 12 | <p>Email Composer with Attachments. Modified from the original Phonegap plugin 13 | to accept multiple attachments</p> 14 | 15 | 16 | MIT 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /src/android/EmailAttachmentProvider.java: -------------------------------------------------------------------------------- 1 | package com.jcjee.plugins; 2 | 3 | import java.io.File; 4 | import java.io.FileNotFoundException; 5 | 6 | import android.content.ContentProvider; 7 | import android.content.ContentValues; 8 | import android.content.UriMatcher; 9 | import android.database.Cursor; 10 | import android.database.MatrixCursor; 11 | import android.net.Uri; 12 | import android.os.ParcelFileDescriptor; 13 | import android.provider.MediaStore; 14 | import android.webkit.MimeTypeMap; 15 | 16 | public class EmailAttachmentProvider extends ContentProvider { 17 | 18 | public static final String AUTHORITY = "com.jcjee.plugins.emailcomposer.provider"; 19 | 20 | private UriMatcher uriMatcher; 21 | 22 | @Override 23 | public boolean onCreate() { 24 | uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); 25 | 26 | uriMatcher.addURI(AUTHORITY, "*", 1); 27 | 28 | return true; 29 | } 30 | 31 | @Override 32 | public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { 33 | switch(uriMatcher.match(uri)) { 34 | case 1: 35 | String fileLocation = getContext().getCacheDir() + File.separator + uri.getLastPathSegment(); 36 | ParcelFileDescriptor pfd = ParcelFileDescriptor.open(new File(fileLocation), ParcelFileDescriptor.MODE_READ_ONLY); 37 | return pfd; 38 | default: 39 | throw new FileNotFoundException("Unsupported uri: " + uri.toString()); 40 | } 41 | } 42 | 43 | @Override 44 | public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3) { 45 | return 0; 46 | } 47 | 48 | @Override 49 | public int delete(Uri arg0, String arg1, String[] arg2) { 50 | return 0; 51 | } 52 | 53 | @Override 54 | public Uri insert(Uri arg0, ContentValues arg1) { 55 | return null; 56 | } 57 | 58 | @Override 59 | public String getType(Uri arg0) { 60 | String fileExtension = MimeTypeMap.getFileExtensionFromUrl(arg0.getPath()); 61 | String type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(fileExtension); 62 | 63 | return type; 64 | } 65 | 66 | @Override 67 | public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { 68 | MatrixCursor result = new MatrixCursor(projection); 69 | Object[] row = new Object[projection.length]; 70 | long fileSize = 0; 71 | 72 | String fileLocation = getContext().getCacheDir() + File.separator + uri.getLastPathSegment(); 73 | File tempFile = new File(fileLocation); 74 | fileSize = tempFile.length(); 75 | 76 | for (int i=0; i 0) { 77 | emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, subject); 78 | } 79 | } catch (Exception e) { 80 | LOG.e("EmailComposer", "Error handling subject param: " + e.toString()); 81 | } 82 | 83 | // setting body 84 | try { 85 | String body = parameters.getString("body"); 86 | if (body != null && body.length() > 0) { 87 | if (isHTML) { 88 | emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, Html.fromHtml(body)); 89 | } else { 90 | emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, body); 91 | } 92 | } 93 | } catch (Exception e) { 94 | LOG.e("EmailComposer", "Error handling body param: " + e.toString()); 95 | } 96 | 97 | // setting TO recipients 98 | try { 99 | JSONArray toRecipients = parameters.getJSONArray("toRecipients"); 100 | if (toRecipients != null && toRecipients.length() > 0) { 101 | String[] to = new String[toRecipients.length()]; 102 | for (int i=0; i 0) { 115 | String[] cc = new String[ccRecipients.length()]; 116 | for (int i=0; i 0) { 129 | String[] bcc = new String[bccRecipients.length()]; 130 | for (int i=0; i 0) { 143 | ArrayList uris = new ArrayList(); 144 | //convert from paths to Android friendly Parcelable Uri's 145 | for (int i=0; i 0) { 157 | emailIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris); 158 | } 159 | } 160 | } catch (Exception e) { 161 | LOG.e("EmailComposer", "Error handling attachments param: " + e.toString()); 162 | } 163 | 164 | // setting attachments data 165 | try { 166 | JSONArray attachmentsData = parameters.getJSONArray("attachmentsData"); 167 | if (attachmentsData != null && attachmentsData.length() > 0) { 168 | ArrayList uris = new ArrayList(); 169 | for (int i=0; i 0) { 187 | emailIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris); 188 | } 189 | } 190 | } catch (Exception e) { 191 | LOG.e("EmailComposer", "Error handling attachmentsData param: " + e.toString()); 192 | } 193 | 194 | this.cordova.startActivityForResult(this, emailIntent, 0); 195 | } 196 | 197 | @Override 198 | public void onActivityResult(int requestCode, int resultCode, Intent intent) { 199 | // TODO handle callback 200 | super.onActivityResult(requestCode, resultCode, intent); 201 | LOG.e("EmailComposer", "ResultCode: " + resultCode); 202 | // IT DOESN'T SEEM TO HANDLE RESULT CODES 203 | } 204 | 205 | } 206 | -------------------------------------------------------------------------------- /src/ios/EmailComposer.h: -------------------------------------------------------------------------------- 1 | // 2 | // EmailComposer.h 3 | // 4 | // Version 1.1 5 | // 6 | // Created by Guido Sabatini in 2012. 7 | // 8 | 9 | #import 10 | #import 11 | #import 12 | 13 | 14 | @interface EmailComposer : CDVPlugin { 15 | 16 | 17 | } 18 | 19 | // UNCOMMENT THIS METHOD if you want to use the plugin with versions of cordova < 2.2.0 20 | //- (void) showEmailComposer:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; 21 | 22 | // COMMENT THIS METHOD if you want to use the plugin with versions of cordova < 2.2.0 23 | - (void) showEmailComposer:(CDVInvokedUrlCommand*)command; 24 | 25 | @end -------------------------------------------------------------------------------- /src/ios/EmailComposer.m: -------------------------------------------------------------------------------- 1 | // 2 | // EmailComposer.m 3 | // 4 | // Version 1.1 5 | // 6 | // Created by Guido Sabatini in 2012. 7 | // 8 | // Version 1.2 9 | // 10 | // Modified by Jia Chang Jee in 2013. 11 | // 12 | 13 | #define RETURN_CODE_EMAIL_CANCELLED 0 14 | #define RETURN_CODE_EMAIL_SAVED 1 15 | #define RETURN_CODE_EMAIL_SENT 2 16 | #define RETURN_CODE_EMAIL_FAILED 3 17 | #define RETURN_CODE_EMAIL_NOTSENT 4 18 | 19 | #import "EmailComposer.h" 20 | #import "NSData+Base64.h" 21 | #import 22 | 23 | @interface EmailComposer () 24 | 25 | -(void) showEmailComposerWithParameters:(NSDictionary*)parameters; 26 | -(void) returnWithCode:(int)code; 27 | -(NSString *) getMimeTypeFromFileExtension:(NSString *)extension; 28 | 29 | @end 30 | 31 | @implementation EmailComposer 32 | 33 | // UNCOMMENT THIS METHOD if you want to use the plugin with versions of cordova < 2.2.0 34 | //- (void) showEmailComposer:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options { 35 | // NSDictionary *parameters = [NSDictionary dictionaryWithObjectsAndKeys: 36 | // [options valueForKey:@"toRecipients"], @"toRecipients", 37 | // [options valueForKey:@"ccRecipients"], @"ccRecipients", 38 | // [options valueForKey:@"bccRecipients"], @"bccRecipients", 39 | // [options valueForKey:@"subject"], @"subject", 40 | // [options valueForKey:@"body"], @"body", 41 | // [options valueForKey:@"bIsHTML"], @"bIsHTML", 42 | // [options valueForKey:@"attachments"], @"attachments", 43 | // nil]; 44 | // [self showEmailComposerWithParameters:parameters]; 45 | //} 46 | 47 | // COMMENT THIS METHOD if you want to use the plugin with versions of cordova < 2.2.0 48 | - (void) showEmailComposer:(CDVInvokedUrlCommand*)command { 49 | NSDictionary *parameters = [command.arguments objectAtIndex:0]; 50 | [self showEmailComposerWithParameters:parameters]; 51 | } 52 | 53 | -(void) showEmailComposerWithParameters:(NSDictionary*)parameters { 54 | 55 | MFMailComposeViewController *mailComposer = [[MFMailComposeViewController alloc] init]; 56 | mailComposer.mailComposeDelegate = self; 57 | 58 | // set subject 59 | @try { 60 | NSString* subject = [parameters objectForKey:@"subject"]; 61 | if (subject) { 62 | [mailComposer setSubject:subject]; 63 | } 64 | } 65 | @catch (NSException *exception) { 66 | NSLog(@"EmailComposer - Cannot set subject; error: %@", exception); 67 | } 68 | 69 | // set body 70 | @try { 71 | NSString* body = [parameters objectForKey:@"body"]; 72 | BOOL isHTML = [[parameters objectForKey:@"bIsHTML"] boolValue]; 73 | if(body) { 74 | [mailComposer setMessageBody:body isHTML:isHTML]; 75 | } 76 | } 77 | @catch (NSException *exception) { 78 | NSLog(@"EmailComposer - Cannot set body; error: %@", exception); 79 | } 80 | 81 | // Set recipients 82 | @try { 83 | NSArray* toRecipientsArray = [parameters objectForKey:@"toRecipients"]; 84 | if(toRecipientsArray) { 85 | [mailComposer setToRecipients:toRecipientsArray]; 86 | } 87 | } 88 | @catch (NSException *exception) { 89 | NSLog(@"EmailComposer - Cannot set TO recipients; error: %@", exception); 90 | } 91 | 92 | @try { 93 | NSArray* ccRecipientsArray = [parameters objectForKey:@"ccRecipients"]; 94 | if(ccRecipientsArray) { 95 | [mailComposer setCcRecipients:ccRecipientsArray]; 96 | } 97 | } 98 | @catch (NSException *exception) { 99 | NSLog(@"EmailComposer - Cannot set CC recipients; error: %@", exception); 100 | } 101 | 102 | @try { 103 | NSArray* bccRecipientsArray = [parameters objectForKey:@"bccRecipients"]; 104 | if(bccRecipientsArray) { 105 | [mailComposer setBccRecipients:bccRecipientsArray]; 106 | } 107 | } 108 | @catch (NSException *exception) { 109 | NSLog(@"EmailComposer - Cannot set BCC recipients; error: %@", exception); 110 | } 111 | 112 | @try { 113 | int counter = 1; 114 | NSArray *attachmentPaths = [parameters objectForKey:@"attachments"]; 115 | if (attachmentPaths) { 116 | for (NSString* path in attachmentPaths) { 117 | @try { 118 | NSRange range = [path rangeOfString:@"/" options:NSBackwardsSearch]; 119 | NSString *fileName = [path substringFromIndex:range.location + 1]; 120 | NSData *data = [[NSFileManager defaultManager] contentsAtPath:path]; 121 | //NSLog(@"HELLO %@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]); 122 | // [mailComposer addAttachmentData:data mimeType:[self getMimeTypeFromFileExtension:[path pathExtension]] fileName:[NSString stringWithFormat:@"attachment%d.%@", counter, [path pathExtension]]]; 123 | [mailComposer addAttachmentData:data mimeType:[self getMimeTypeFromFileExtension:[path pathExtension]] fileName:fileName]; 124 | counter++; 125 | } 126 | @catch (NSException *exception) { 127 | NSLog(@"Cannot attach file at path %@; error: %@", path, exception); 128 | } 129 | } 130 | } 131 | } 132 | @catch (NSException *exception) { 133 | NSLog(@"EmailComposer - Cannot set attachments; error: %@", exception); 134 | } 135 | 136 | @try { 137 | int counter = 1; 138 | NSArray *attachmentsData = [parameters objectForKey:@"attachmentsData"]; 139 | if (attachmentsData) { 140 | for (NSArray *dataArr in attachmentsData) { 141 | NSString *fileName = [dataArr objectAtIndex:0]; 142 | NSString *dataString = [dataArr objectAtIndex:1]; 143 | NSData *data = [NSData dataFromBase64String:dataString]; 144 | 145 | /* 146 | NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 147 | NSString *documentsDirectory = [paths objectAtIndex:0]; 148 | NSString *fullName = [NSString stringWithFormat:@"%@/%@", documentsDirectory, fileName]; 149 | 150 | [data writeToFile:fullName atomically:YES]; 151 | */ 152 | 153 | [mailComposer addAttachmentData:data mimeType:[self getMimeTypeFromFileExtension:[fileName pathExtension]] fileName:fileName]; 154 | counter++; 155 | } 156 | } 157 | } 158 | @catch (NSException *exception) { 159 | NSLog(@"EmailComposer - Cannot set attachments data; error: %@", exception); 160 | } 161 | 162 | if (mailComposer != nil) { 163 | [self.viewController presentViewController:mailComposer animated:YES completion:nil]; 164 | } else { 165 | [self returnWithCode:RETURN_CODE_EMAIL_NOTSENT]; 166 | } 167 | //[mailComposer release]; 168 | } 169 | 170 | 171 | // Dismisses the email composition interface when users tap Cancel or Send. 172 | // Proceeds to update the message field with the result of the operation. 173 | - (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error { 174 | // Notifies users about errors associated with the interface 175 | int webviewResult = 0; 176 | 177 | switch (result) { 178 | case MFMailComposeResultCancelled: 179 | webviewResult = RETURN_CODE_EMAIL_CANCELLED; 180 | break; 181 | case MFMailComposeResultSaved: 182 | webviewResult = RETURN_CODE_EMAIL_SAVED; 183 | break; 184 | case MFMailComposeResultSent: 185 | webviewResult =RETURN_CODE_EMAIL_SENT; 186 | break; 187 | case MFMailComposeResultFailed: 188 | webviewResult = RETURN_CODE_EMAIL_FAILED; 189 | break; 190 | default: 191 | webviewResult = RETURN_CODE_EMAIL_NOTSENT; 192 | break; 193 | } 194 | 195 | [controller dismissViewControllerAnimated:YES completion:nil]; 196 | [self returnWithCode:webviewResult]; 197 | } 198 | 199 | // Call the callback with the specified code 200 | -(void) returnWithCode:(int)code { 201 | [self.commandDelegate evalJs:[NSString stringWithFormat:@"window.plugins.emailComposer._didFinishWithResult(%d);", code]]; 202 | } 203 | 204 | // Retrieve the mime type from the file extension 205 | -(NSString *) getMimeTypeFromFileExtension:(NSString *)extension { 206 | if (!extension) 207 | return nil; 208 | CFStringRef pathExtension, type; 209 | // Get the UTI from the file's extension 210 | pathExtension = (__bridge_retained CFStringRef)extension; 211 | type = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension, NULL); 212 | CFRelease(pathExtension); 213 | 214 | // Converting UTI to a mime type 215 | NSString *mimeType = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass(type, kUTTagClassMIMEType); 216 | if (type != NULL) 217 | CFRelease(type); 218 | 219 | return mimeType; 220 | } 221 | 222 | @end 223 | -------------------------------------------------------------------------------- /src/ios/NSData+Base64.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSData+Base64.h 3 | // base64 4 | // 5 | // Created by Matt Gallagher on 2009/06/03. 6 | // Copyright 2009 Matt Gallagher. All rights reserved. 7 | // 8 | // This software is provided 'as-is', without any express or implied 9 | // warranty. In no event will the authors be held liable for any damages 10 | // arising from the use of this software. Permission is granted to anyone to 11 | // use this software for any purpose, including commercial applications, and to 12 | // alter it and redistribute it freely, subject to the following restrictions: 13 | // 14 | // 1. The origin of this software must not be misrepresented; you must not 15 | // claim that you wrote the original software. If you use this software 16 | // in a product, an acknowledgment in the product documentation would be 17 | // appreciated but is not required. 18 | // 2. Altered source versions must be plainly marked as such, and must not be 19 | // misrepresented as being the original software. 20 | // 3. This notice may not be removed or altered from any source 21 | // distribution. 22 | // 23 | 24 | #import 25 | 26 | void *NewBase64Decode( 27 | const char *inputBuffer, 28 | size_t length, 29 | size_t *outputLength); 30 | 31 | char *NewBase64Encode( 32 | const void *inputBuffer, 33 | size_t length, 34 | bool separateLines, 35 | size_t *outputLength); 36 | 37 | @interface NSData (Base64) 38 | 39 | + (NSData *)dataFromBase64String:(NSString *)aString; 40 | - (NSString *)base64EncodedString; 41 | 42 | @end -------------------------------------------------------------------------------- /src/ios/NSData+Base64.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSData+Base64.m 3 | // base64 4 | // 5 | // Created by Matt Gallagher on 2009/06/03. 6 | // Copyright 2009 Matt Gallagher. All rights reserved. 7 | // 8 | // This software is provided 'as-is', without any express or implied 9 | // warranty. In no event will the authors be held liable for any damages 10 | // arising from the use of this software. Permission is granted to anyone to 11 | // use this software for any purpose, including commercial applications, and to 12 | // alter it and redistribute it freely, subject to the following restrictions: 13 | // 14 | // 1. The origin of this software must not be misrepresented; you must not 15 | // claim that you wrote the original software. If you use this software 16 | // in a product, an acknowledgment in the product documentation would be 17 | // appreciated but is not required. 18 | // 2. Altered source versions must be plainly marked as such, and must not be 19 | // misrepresented as being the original software. 20 | // 3. This notice may not be removed or altered from any source 21 | // distribution. 22 | // 23 | // Comments converted to be ARC compatible 24 | 25 | #import "NSData+Base64.h" 26 | 27 | // 28 | // Mapping from 6 bit pattern to ASCII character. 29 | // 30 | static unsigned char base64EncodeLookup[65] = 31 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 32 | 33 | // 34 | // Definition for "masked-out" areas of the base64DecodeLookup mapping 35 | // 36 | #define xx 65 37 | 38 | // 39 | // Mapping from ASCII character to 6 bit pattern. 40 | // 41 | static unsigned char base64DecodeLookup[256] = 42 | { 43 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 44 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 45 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 62, xx, xx, xx, 63, 46 | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, xx, xx, xx, xx, xx, xx, 47 | xx, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 48 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, xx, xx, xx, xx, xx, 49 | xx, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 50 | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, xx, xx, xx, xx, xx, 51 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 52 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 53 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 54 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 55 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 56 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 57 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 58 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 59 | }; 60 | 61 | // 62 | // Fundamental sizes of the binary and base64 encode/decode units in bytes 63 | // 64 | #define BINARY_UNIT_SIZE 3 65 | #define BASE64_UNIT_SIZE 4 66 | 67 | // 68 | // NewBase64Decode 69 | // 70 | // Decodes the base64 ASCII string in the inputBuffer to a newly malloced 71 | // output buffer. 72 | // 73 | // inputBuffer - the source ASCII string for the decode 74 | // length - the length of the string or -1 (to specify strlen should be used) 75 | // outputLength - if not-NULL, on output will contain the decoded length 76 | // 77 | // returns the decoded buffer. Must be free'd by caller. Length is given by 78 | // outputLength. 79 | // 80 | void *NewBase64Decode( 81 | const char *inputBuffer, 82 | size_t length, 83 | size_t *outputLength) 84 | { 85 | if (length == -1) 86 | { 87 | length = strlen(inputBuffer); 88 | } 89 | 90 | size_t outputBufferSize = 91 | ((length+BASE64_UNIT_SIZE-1) / BASE64_UNIT_SIZE) * BINARY_UNIT_SIZE; 92 | unsigned char *outputBuffer = (unsigned char *)malloc(outputBufferSize); 93 | 94 | size_t i = 0; 95 | size_t j = 0; 96 | while (i < length) 97 | { 98 | // 99 | // Accumulate 4 valid characters (ignore everything else) 100 | // 101 | unsigned char accumulated[BASE64_UNIT_SIZE]; 102 | size_t accumulateIndex = 0; 103 | while (i < length) 104 | { 105 | unsigned char decode = base64DecodeLookup[inputBuffer[i++]]; 106 | if (decode != xx) 107 | { 108 | accumulated[accumulateIndex] = decode; 109 | accumulateIndex++; 110 | 111 | if (accumulateIndex == BASE64_UNIT_SIZE) 112 | { 113 | break; 114 | } 115 | } 116 | } 117 | 118 | // 119 | // Store the 6 bits from each of the 4 characters as 3 bytes 120 | // 121 | // (Uses improved bounds checking suggested by Alexandre Colucci) 122 | // 123 | if(accumulateIndex >= 2) 124 | outputBuffer[j] = (accumulated[0] << 2) | (accumulated[1] >> 4); 125 | if(accumulateIndex >= 3) 126 | outputBuffer[j + 1] = (accumulated[1] << 4) | (accumulated[2] >> 2); 127 | if(accumulateIndex >= 4) 128 | outputBuffer[j + 2] = (accumulated[2] << 6) | accumulated[3]; 129 | j += accumulateIndex - 1; 130 | } 131 | 132 | if (outputLength) 133 | { 134 | *outputLength = j; 135 | } 136 | return outputBuffer; 137 | } 138 | 139 | // 140 | // NewBase64Encode 141 | // 142 | // Encodes the arbitrary data in the inputBuffer as base64 into a newly malloced 143 | // output buffer. 144 | // 145 | // inputBuffer - the source data for the encode 146 | // length - the length of the input in bytes 147 | // separateLines - if zero, no CR/LF characters will be added. Otherwise 148 | // a CR/LF pair will be added every 64 encoded chars. 149 | // outputLength - if not-NULL, on output will contain the encoded length 150 | // (not including terminating 0 char) 151 | // 152 | // returns the encoded buffer. Must be free'd by caller. Length is given by 153 | // outputLength. 154 | // 155 | char *NewBase64Encode( 156 | const void *buffer, 157 | size_t length, 158 | bool separateLines, 159 | size_t *outputLength) 160 | { 161 | const unsigned char *inputBuffer = (const unsigned char *)buffer; 162 | 163 | #define MAX_NUM_PADDING_CHARS 2 164 | #define OUTPUT_LINE_LENGTH 64 165 | #define INPUT_LINE_LENGTH ((OUTPUT_LINE_LENGTH / BASE64_UNIT_SIZE) * BINARY_UNIT_SIZE) 166 | #define CR_LF_SIZE 2 167 | 168 | // 169 | // Byte accurate calculation of final buffer size 170 | // 171 | size_t outputBufferSize = 172 | ((length / BINARY_UNIT_SIZE) 173 | + ((length % BINARY_UNIT_SIZE) ? 1 : 0)) 174 | * BASE64_UNIT_SIZE; 175 | if (separateLines) 176 | { 177 | outputBufferSize += 178 | (outputBufferSize / OUTPUT_LINE_LENGTH) * CR_LF_SIZE; 179 | } 180 | 181 | // 182 | // Include space for a terminating zero 183 | // 184 | outputBufferSize += 1; 185 | 186 | // 187 | // Allocate the output buffer 188 | // 189 | char *outputBuffer = (char *)malloc(outputBufferSize); 190 | if (!outputBuffer) 191 | { 192 | return NULL; 193 | } 194 | 195 | size_t i = 0; 196 | size_t j = 0; 197 | const size_t lineLength = separateLines ? INPUT_LINE_LENGTH : length; 198 | size_t lineEnd = lineLength; 199 | 200 | while (true) 201 | { 202 | if (lineEnd > length) 203 | { 204 | lineEnd = length; 205 | } 206 | 207 | for (; i + BINARY_UNIT_SIZE - 1 < lineEnd; i += BINARY_UNIT_SIZE) 208 | { 209 | // 210 | // Inner loop: turn 48 bytes into 64 base64 characters 211 | // 212 | outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i] & 0xFC) >> 2]; 213 | outputBuffer[j++] = base64EncodeLookup[((inputBuffer[i] & 0x03) << 4) 214 | | ((inputBuffer[i + 1] & 0xF0) >> 4)]; 215 | outputBuffer[j++] = base64EncodeLookup[((inputBuffer[i + 1] & 0x0F) << 2) 216 | | ((inputBuffer[i + 2] & 0xC0) >> 6)]; 217 | outputBuffer[j++] = base64EncodeLookup[inputBuffer[i + 2] & 0x3F]; 218 | } 219 | 220 | if (lineEnd == length) 221 | { 222 | break; 223 | } 224 | 225 | // 226 | // Add the newline 227 | // 228 | outputBuffer[j++] = '\r'; 229 | outputBuffer[j++] = '\n'; 230 | lineEnd += lineLength; 231 | } 232 | 233 | if (i + 1 < length) 234 | { 235 | // 236 | // Handle the single '=' case 237 | // 238 | outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i] & 0xFC) >> 2]; 239 | outputBuffer[j++] = base64EncodeLookup[((inputBuffer[i] & 0x03) << 4) 240 | | ((inputBuffer[i + 1] & 0xF0) >> 4)]; 241 | outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i + 1] & 0x0F) << 2]; 242 | outputBuffer[j++] = '='; 243 | } 244 | else if (i < length) 245 | { 246 | // 247 | // Handle the double '=' case 248 | // 249 | outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i] & 0xFC) >> 2]; 250 | outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i] & 0x03) << 4]; 251 | outputBuffer[j++] = '='; 252 | outputBuffer[j++] = '='; 253 | } 254 | outputBuffer[j] = 0; 255 | 256 | // 257 | // Set the output length and return the buffer 258 | // 259 | if (outputLength) 260 | { 261 | *outputLength = j; 262 | } 263 | return outputBuffer; 264 | } 265 | 266 | @implementation NSData (Base64) 267 | 268 | // 269 | // dataFromBase64String: 270 | // 271 | // Creates an NSData object containing the base64 decoded representation of 272 | // the base64 string 'aString' 273 | // 274 | // Parameters: 275 | // aString - the base64 string to decode 276 | // 277 | // returns the NSData representation of the base64 string 278 | // 279 | + (NSData *)dataFromBase64String:(NSString *)aString 280 | { 281 | NSData *data = [aString dataUsingEncoding:NSASCIIStringEncoding]; 282 | size_t outputLength; 283 | void *outputBuffer = NewBase64Decode([data bytes], [data length], &outputLength); 284 | NSData *result = [NSData dataWithBytes:outputBuffer length:outputLength]; 285 | free(outputBuffer); 286 | return result; 287 | } 288 | 289 | // 290 | // base64EncodedString 291 | // 292 | // Creates an NSString object that contains the base 64 encoding of the 293 | // receiver's data. Lines are broken at 64 characters long. 294 | // 295 | // returns an NSString being the base 64 representation of the 296 | // receiver. 297 | // 298 | - (NSString *)base64EncodedString 299 | { 300 | size_t outputLength; 301 | char *outputBuffer = 302 | NewBase64Encode([self bytes], [self length], true, &outputLength); 303 | 304 | NSString *result = 305 | [[NSString alloc] initWithBytes:outputBuffer length:outputLength encoding:NSASCIIStringEncoding]; 306 | free(outputBuffer); 307 | return result; 308 | } 309 | 310 | @end -------------------------------------------------------------------------------- /www/EmailComposer.js: -------------------------------------------------------------------------------- 1 | function EmailComposer() { 2 | this.resultCallback = null; // Function 3 | } 4 | 5 | EmailComposer.ComposeResultType = { 6 | Cancelled : 0, 7 | Saved : 1, 8 | Sent : 2, 9 | Failed : 3, 10 | NotSent : 4 11 | } 12 | 13 | // showEmailComposer : all args optional 14 | 15 | EmailComposer.prototype.showEmailComposer = function(subject, body, 16 | toRecipients, ccRecipients, bccRecipients, bIsHTML, attachments, attachmentsData) { 17 | console.log("****************************AVVIATO"); 18 | var args = {}; 19 | if (toRecipients) 20 | args.toRecipients = toRecipients; 21 | if (ccRecipients) 22 | args.ccRecipients = ccRecipients; 23 | if (bccRecipients) 24 | args.bccRecipients = bccRecipients; 25 | if (subject) 26 | args.subject = subject; 27 | if (body) 28 | args.body = body; 29 | if (bIsHTML) 30 | args.bIsHTML = bIsHTML; 31 | if (attachments) 32 | args.attachments = attachments; 33 | if (attachmentsData) 34 | args.attachmentsData = attachmentsData; 35 | 36 | cordova.exec(null, null, "EmailComposer", "showEmailComposer", [ args ]); 37 | } 38 | 39 | EmailComposer.prototype.showEmailComposerWithCallback = function(callback, 40 | subject, body, toRecipients, ccRecipients, bccRecipients, isHTML, 41 | attachments, attachmentsData) { 42 | this.resultCallback = callback; 43 | this.showEmailComposer.apply(this, [ subject, body, toRecipients, 44 | ccRecipients, bccRecipients, isHTML, attachments, attachmentsData]); 45 | } 46 | 47 | EmailComposer.prototype._didFinishWithResult = function(res) { 48 | this.resultCallback(res); 49 | } 50 | 51 | cordova.addConstructor(function() { 52 | console.log("****************************"); 53 | if (!window.plugins) { 54 | window.plugins = {}; 55 | } 56 | 57 | // shim to work in 1.5 and 1.6 58 | if (!window.Cordova) { 59 | window.Cordova = cordova; 60 | } 61 | ; 62 | 63 | window.plugins.emailComposer = new EmailComposer(); 64 | }); --------------------------------------------------------------------------------