├── 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 | });
--------------------------------------------------------------------------------