Download attachments of a message as a zip archive
parent
2a2ebd553e
commit
011fae8a65
3
NEWS
3
NEWS
|
@ -1,6 +1,9 @@
|
|||
3.2.5 (2016-12-DD)
|
||||
------------------
|
||||
|
||||
New features
|
||||
- [web] download attachments of a message as a zip archive
|
||||
|
||||
Enhancements
|
||||
- [web] prevent using localhost on additional IMAP accounts
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
fromIndex: (int) start;
|
||||
- (int) indexOf: (unichar) _c;
|
||||
- (NSString *) decodedHeader;
|
||||
- (NSString *) asSafeFilename;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -688,4 +688,26 @@ convertChars (const char *oldString, unsigned int oldLength,
|
|||
return decodedHeader;
|
||||
}
|
||||
|
||||
- (NSString *) asSafeFilename
|
||||
{
|
||||
NSRange r;
|
||||
NSMutableString *safeName;
|
||||
|
||||
r = [self rangeOfString: @"\\"
|
||||
options: NSBackwardsSearch];
|
||||
if (r.length > 0)
|
||||
safeName = [NSMutableString stringWithString: [self substringFromIndex: r.location + 1]];
|
||||
else
|
||||
safeName = [NSMutableString stringWithString: self];
|
||||
[safeName replaceString: @"/" withString: @"_"];
|
||||
|
||||
if ([self isEqualToString: @"."])
|
||||
return @"_";
|
||||
|
||||
if ([self isEqualToString: @".."])
|
||||
return @"__";
|
||||
|
||||
return safeName;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -97,7 +97,6 @@
|
|||
/* attachments */
|
||||
|
||||
- (NSArray *) fetchAttachmentAttrs;
|
||||
- (BOOL) isValidAttachmentName: (NSString *) _name;
|
||||
- (NGMimeBodyPart *) bodyPartForAttachmentWithName: (NSString *) _name;
|
||||
- (NSString *) pathToAttachmentWithName: (NSString *) _name;
|
||||
- (NSException *) saveAttachment: (NSData *) _attach
|
||||
|
|
|
@ -845,59 +845,22 @@ static NSString *userAgent = nil;
|
|||
}
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
- (NSArray *) _attachmentBodiesFromPaths: (NSArray *) paths
|
||||
fromResponseFetch: (NSDictionary *) fetch;
|
||||
{
|
||||
NSEnumerator *attachmentKeys;
|
||||
NSMutableArray *bodies;
|
||||
NSString *currentKey;
|
||||
NSDictionary *body;
|
||||
|
||||
bodies = [NSMutableArray array];
|
||||
|
||||
attachmentKeys = [paths objectEnumerator];
|
||||
while ((currentKey = [attachmentKeys nextObject]))
|
||||
{
|
||||
body = [fetch objectForKey: [currentKey lowercaseString]];
|
||||
if (body)
|
||||
[bodies addObject: [body objectForKey: @"data"]];
|
||||
else
|
||||
[bodies addObject: [NSData data]];
|
||||
}
|
||||
|
||||
return bodies;
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
- (void) _fetchAttachmentsFromMail: (SOGoMailObject *) sourceMail
|
||||
{
|
||||
unsigned int count, max;
|
||||
NSArray *parts, *paths, *bodies;
|
||||
NSData *body;
|
||||
unsigned int max, count;
|
||||
NSArray *attachments;
|
||||
NSDictionary *currentInfo;
|
||||
NGHashMap *response;
|
||||
|
||||
parts = [sourceMail fetchFileAttachmentKeys];
|
||||
max = [parts count];
|
||||
if (max > 0)
|
||||
attachments = [sourceMail fetchFileAttachments];
|
||||
max = [attachments count];
|
||||
for (count = 0; count < max; count++)
|
||||
{
|
||||
paths = [parts keysWithFormat: @"BODY[%{path}]"];
|
||||
response = [[sourceMail fetchParts: paths] objectForKey: @"RawResponse"];
|
||||
bodies = [self _attachmentBodiesFromPaths: paths
|
||||
fromResponseFetch: [response objectForKey: @"fetch"]];
|
||||
for (count = 0; count < max; count++)
|
||||
{
|
||||
currentInfo = [parts objectAtIndex: count];
|
||||
body = [[bodies objectAtIndex: count]
|
||||
bodyDataFromEncoding: [currentInfo
|
||||
objectForKey: @"encoding"]];
|
||||
[self saveAttachment: body withMetadata: currentInfo];
|
||||
}
|
||||
currentInfo = [attachments objectAtIndex: count];
|
||||
[self saveAttachment: [currentInfo objectForKey: @"body"]
|
||||
withMetadata: currentInfo];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1098,12 +1061,6 @@ static NSString *userAgent = nil;
|
|||
return ma;
|
||||
}
|
||||
|
||||
- (BOOL) isValidAttachmentName: (NSString *) filename
|
||||
{
|
||||
return (!([filename rangeOfString: @"/"].length
|
||||
|| [filename isEqualToString: @"."]
|
||||
|| [filename isEqualToString: @".."]));
|
||||
}
|
||||
|
||||
- (NSString *) pathToAttachmentWithName: (NSString *) _name
|
||||
{
|
||||
|
@ -1113,17 +1070,15 @@ static NSString *userAgent = nil;
|
|||
return [[self draftFolderPath] stringByAppendingPathComponent:_name];
|
||||
}
|
||||
|
||||
- (NSException *) invalidAttachmentNameError: (NSString *) _name
|
||||
{
|
||||
return [NSException exceptionWithHTTPStatus:400 /* Bad Request */
|
||||
reason: @"Invalid attachment name!"];
|
||||
}
|
||||
|
||||
/**
|
||||
* Write attachment file to the spool directory of the draft and write a dot
|
||||
* file with its mime type.
|
||||
*/
|
||||
- (NSException *) saveAttachment: (NSData *) _attach
|
||||
withMetadata: (NSDictionary *) metadata
|
||||
{
|
||||
NSString *p, *pmime, *name, *mimeType;
|
||||
NSRange r;
|
||||
|
||||
if (![_attach isNotNull]) {
|
||||
return [NSException exceptionWithHTTPStatus:400 /* Bad Request */
|
||||
|
@ -1135,15 +1090,7 @@ static NSString *userAgent = nil;
|
|||
reason: @"Could not create folder for draft!"];
|
||||
}
|
||||
|
||||
name = [metadata objectForKey: @"filename"];
|
||||
r = [name rangeOfString: @"\\"
|
||||
options: NSBackwardsSearch];
|
||||
if (r.length > 0)
|
||||
name = [name substringFromIndex: r.location + 1];
|
||||
|
||||
if (![self isValidAttachmentName: name])
|
||||
return [self invalidAttachmentNameError: name];
|
||||
|
||||
name = [[metadata objectForKey: @"filename"] asSafeFilename];
|
||||
p = [self pathToAttachmentWithName: name];
|
||||
if (![_attach writeToFile: p atomically: YES])
|
||||
{
|
||||
|
@ -1173,19 +1120,12 @@ static NSString *userAgent = nil;
|
|||
NSException *error;
|
||||
|
||||
error = nil;
|
||||
|
||||
if ([self isValidAttachmentName:_name])
|
||||
{
|
||||
fm = [NSFileManager defaultManager];
|
||||
p = [self pathToAttachmentWithName:_name];
|
||||
if ([fm fileExistsAtPath: p])
|
||||
if (![fm removeFileAtPath: p handler: nil])
|
||||
error
|
||||
= [NSException exceptionWithHTTPStatus: 500 /* Server Error */
|
||||
reason: @"Could not delete attachment from draft!"];
|
||||
}
|
||||
else
|
||||
error = [self invalidAttachmentNameError:_name];
|
||||
fm = [NSFileManager defaultManager];
|
||||
p = [self pathToAttachmentWithName: [_name asSafeFilename]];
|
||||
if ([fm fileExistsAtPath: p])
|
||||
if (![fm removeFileAtPath: p handler: nil])
|
||||
error = [NSException exceptionWithHTTPStatus: 500 /* Server Error */
|
||||
reason: @"Could not delete attachment from draft!"];
|
||||
|
||||
return error;
|
||||
}
|
||||
|
@ -1288,8 +1228,7 @@ static NSString *userAgent = nil;
|
|||
NSString *s, *p;
|
||||
NSData *mimeData;
|
||||
|
||||
p = [self pathToAttachmentWithName:
|
||||
[NSString stringWithFormat: @".%@.mime", _name]];
|
||||
p = [self pathToAttachmentWithName: [NSString stringWithFormat: @".%@.mime", _name]];
|
||||
mimeData = [NSData dataWithContentsOfFile: p];
|
||||
if (mimeData)
|
||||
{
|
||||
|
@ -1308,20 +1247,18 @@ static NSString *userAgent = nil;
|
|||
}
|
||||
|
||||
- (NSString *) contentDispositionForAttachmentWithName: (NSString *) _name
|
||||
andContentType: (NSString *) _type
|
||||
{
|
||||
NSString *type;
|
||||
NSString *cdtype;
|
||||
NSString *cd;
|
||||
SOGoDomainDefaults *dd;
|
||||
|
||||
type = [self contentTypeForAttachmentWithName:_name];
|
||||
|
||||
if ([type hasPrefix: @"text/"])
|
||||
if ([_type hasPrefix: @"text/"])
|
||||
{
|
||||
dd = [[context activeUser] domainDefaults];
|
||||
cdtype = [dd mailAttachTextDocumentsInline] ? @"inline" : @"attachment";
|
||||
}
|
||||
else if ([type hasPrefix: @"image/"] || [type hasPrefix: @"message"])
|
||||
else if ([_type hasPrefix: @"image/"] || [_type hasPrefix: @"message"])
|
||||
cdtype = @"inline";
|
||||
else
|
||||
cdtype = @"attachment";
|
||||
|
@ -1369,7 +1306,7 @@ static NSString *userAgent = nil;
|
|||
else if ([s hasPrefix: @"message/rfc822"])
|
||||
attachAsRFC822 = YES;
|
||||
}
|
||||
if ((s = [self contentDispositionForAttachmentWithName: _name]))
|
||||
if ((s = [self contentDispositionForAttachmentWithName: _name andContentType: s]))
|
||||
{
|
||||
NGMimeContentDispositionHeaderField *o;
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/*
|
||||
Copyright (C) 2009-2016 Inverse inc.
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
@ -48,6 +49,8 @@
|
|||
@class NGImap4Envelope;
|
||||
@class NGImap4EnvelopeAddress;
|
||||
|
||||
@class WOResponse;
|
||||
|
||||
NSArray *SOGoMailCoreInfoKeys;
|
||||
|
||||
@interface SOGoMailObject : SOGoMailBaseObject
|
||||
|
@ -107,6 +110,8 @@ NSArray *SOGoMailCoreInfoKeys;
|
|||
- (BOOL) hasAttachment;
|
||||
- (NSDictionary *) fetchFileAttachmentIds;
|
||||
- (NSArray *) fetchFileAttachmentKeys;
|
||||
- (NSArray *) fetchFileAttachments;
|
||||
- (WOResponse *) archiveAllFilesinArchiveNamed: (NSString *) archiveName;
|
||||
|
||||
/* flags */
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright (C) 2007-2014 Inverse inc.
|
||||
Copyright (C) 2007-2016 Inverse inc.
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of SOGo.
|
||||
|
@ -20,6 +20,7 @@
|
|||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/NSTask.h>
|
||||
#import <Foundation/NSURL.h>
|
||||
#import <Foundation/NSValue.h>
|
||||
|
||||
|
@ -27,6 +28,7 @@
|
|||
#import <NGObjWeb/WORequest.h>
|
||||
#import <NGObjWeb/NSException+HTTP.h>
|
||||
#import <NGExtensions/NGHashMap.h>
|
||||
#import <NGExtensions/NSFileManager+Extensions.h>
|
||||
#import <NGExtensions/NSNull+misc.h>
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
#import <NGExtensions/NSString+Encoding.h>
|
||||
|
@ -38,7 +40,9 @@
|
|||
|
||||
#import <SOGo/NSArray+Utilities.h>
|
||||
#import <SOGo/NSDictionary+Utilities.h>
|
||||
#import <SOGo/NSString+Utilities.h>
|
||||
#import <SOGo/SOGoPermissions.h>
|
||||
#import <SOGo/SOGoSystemDefaults.h>
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import <SOGo/SOGoUserDefaults.h>
|
||||
#import <SOGo/NSCalendarDate+SOGo.h>
|
||||
|
@ -913,6 +917,160 @@ static BOOL debugSoParts = NO;
|
|||
return keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of dictionaries with the following keys:
|
||||
* - encoding
|
||||
* - filename
|
||||
* - mimetype
|
||||
* - path
|
||||
* - size
|
||||
* - url
|
||||
* - urlAsAttachment
|
||||
* - body (NSData)
|
||||
*/
|
||||
- (NSArray *) fetchFileAttachments
|
||||
{
|
||||
unsigned int count, max;
|
||||
NGHashMap *response;
|
||||
NSArray *parts, *paths; //, *bodies;
|
||||
NSData *body;
|
||||
NSDictionary *fetch, *currentInfo, *currentBody;
|
||||
NSMutableArray *attachments;
|
||||
NSMutableDictionary *currentAttachment;
|
||||
NSString *currentPath;
|
||||
|
||||
parts = [self fetchFileAttachmentKeys];
|
||||
max = [parts count];
|
||||
attachments = [NSMutableArray arrayWithCapacity: max];
|
||||
if (max > 0)
|
||||
{
|
||||
paths = [parts keysWithFormat: @"BODY[%{path}]"];
|
||||
response = [[self fetchParts: paths] objectForKey: @"RawResponse"];
|
||||
fetch = [response objectForKey: @"fetch"];
|
||||
for (count = 0; count < max; count++)
|
||||
{
|
||||
currentInfo = [parts objectAtIndex: count];
|
||||
currentPath = [[paths objectAtIndex: count] lowercaseString];
|
||||
currentBody = [fetch objectForKey: currentPath];
|
||||
|
||||
if (currentBody)
|
||||
{
|
||||
body = [currentBody objectForKey: @"data"];
|
||||
body = [body bodyDataFromEncoding: [currentInfo objectForKey: @"encoding"]];
|
||||
}
|
||||
else
|
||||
body = [NSData data];
|
||||
|
||||
currentAttachment = [NSMutableDictionary dictionaryWithDictionary: currentInfo];
|
||||
[currentAttachment setObject: body forKey: @"body"];
|
||||
[attachments addObject: currentAttachment];
|
||||
}
|
||||
}
|
||||
|
||||
return attachments;
|
||||
}
|
||||
|
||||
- (WOResponse *) archiveAllFilesinArchiveNamed: (NSString *) archiveName
|
||||
{
|
||||
NSArray *attachments;
|
||||
NSData *body, *zipContent;
|
||||
NSDictionary *currentAttachment;
|
||||
NSException *error;
|
||||
NSFileManager *fm;
|
||||
NSMutableArray *zipTaskArguments;
|
||||
NSString *spoolPath, *name, *fileName, *baseName, *extension, *zipPath, *qpFileName;
|
||||
NSTask *zipTask;
|
||||
SOGoMailFolder *folder;
|
||||
WOResponse *response;
|
||||
unsigned int max, count;
|
||||
|
||||
if (!archiveName)
|
||||
archiveName = @"attachments.zip";
|
||||
|
||||
folder = [self container];
|
||||
spoolPath = [folder userSpoolFolderPath];
|
||||
|
||||
if (![folder ensureSpoolFolderPath])
|
||||
{
|
||||
[self errorWithFormat: @"spool directory '%@' doesn't exist", spoolPath];
|
||||
error = [NSException exceptionWithHTTPStatus: 500
|
||||
reason: @"spool directory does not exist"];
|
||||
return (WOResponse *)error;
|
||||
}
|
||||
|
||||
// Prepare execution of zip
|
||||
zipPath = [[SOGoSystemDefaults sharedSystemDefaults] zipPath];
|
||||
fm = [NSFileManager defaultManager];
|
||||
if (![fm fileExistsAtPath: zipPath])
|
||||
{
|
||||
error = [NSException exceptionWithHTTPStatus: 500
|
||||
reason: @"zip not available"];
|
||||
return (WOResponse *)error;
|
||||
}
|
||||
|
||||
zipTask = [[NSTask alloc] init];
|
||||
[zipTask setCurrentDirectoryPath: spoolPath];
|
||||
[zipTask setLaunchPath: zipPath];
|
||||
|
||||
zipTaskArguments = [NSMutableArray arrayWithObjects: nil];
|
||||
[zipTaskArguments addObject: @"attachments.zip"];
|
||||
|
||||
// Fetch attachments and write them on disk
|
||||
attachments = [self fetchFileAttachments];
|
||||
max = [attachments count];
|
||||
for (count = 0; count < max; count++)
|
||||
{
|
||||
currentAttachment = [attachments objectAtIndex: count];
|
||||
body = [currentAttachment objectForKey: @"body"];
|
||||
name = [[currentAttachment objectForKey: @"filename"] asSafeFilename];
|
||||
|
||||
fileName = [NSString stringWithFormat:@"%@/%@", spoolPath, name];
|
||||
[body writeToFile: fileName atomically: YES];
|
||||
|
||||
[zipTaskArguments addObject: name];
|
||||
}
|
||||
|
||||
// Zip files
|
||||
[zipTask setArguments: zipTaskArguments];
|
||||
[zipTask launch];
|
||||
[zipTask waitUntilExit];
|
||||
[zipTask release];
|
||||
zipContent = [[NSData alloc] initWithContentsOfFile:
|
||||
[NSString stringWithFormat: @"%@/attachments.zip", spoolPath]];
|
||||
|
||||
// Delete attachments from disk
|
||||
max = [zipTaskArguments count];
|
||||
for (count = 0; count < max; count++)
|
||||
{
|
||||
fileName = [zipTaskArguments objectAtIndex: count];
|
||||
[fm removeFileAtPath:
|
||||
[NSString stringWithFormat: @"%@/%@", spoolPath, fileName] handler: nil];
|
||||
}
|
||||
|
||||
// Prepare response
|
||||
response = [context response];
|
||||
baseName = [archiveName stringByDeletingPathExtension];
|
||||
extension = [archiveName pathExtension];
|
||||
if ([extension length] > 0)
|
||||
extension = [@"." stringByAppendingString: extension];
|
||||
else
|
||||
extension = @"";
|
||||
|
||||
qpFileName = [NSString stringWithFormat: @"%@%@",
|
||||
[baseName asQPSubjectString: @"utf-8"], extension];
|
||||
[response setHeader: [NSString stringWithFormat: @"application/zip;"
|
||||
@" name=\"%@\"", qpFileName]
|
||||
forKey: @"content-type"];
|
||||
[response setHeader: [NSString stringWithFormat: @"attachment; filename=\"%@\"",
|
||||
qpFileName]
|
||||
forKey: @"Content-Disposition"];
|
||||
[response setContent: zipContent];
|
||||
|
||||
[zipContent release];
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/* convert parts to strings */
|
||||
- (NSString *) stringForData: (NSData *) _data
|
||||
partInfo: (NSDictionary *) _info
|
||||
|
|
|
@ -217,6 +217,12 @@
|
|||
/* Message view "more" menu: create a task from message */
|
||||
"Convert To Task" = "Convert To Task";
|
||||
|
||||
/* Message view "more" menu: download all attachments as a zip archive */
|
||||
"Download all attachments" = "Download all attachments";
|
||||
|
||||
/* Filename prefix when downloading all attachments as a zip archive */
|
||||
"attachments" = "attachments";
|
||||
|
||||
"Print..." = "Print...";
|
||||
"Delete Message" = "Delete Message";
|
||||
"Delete Selected Messages" = "Delete Selected Messages";
|
||||
|
|
|
@ -312,6 +312,18 @@ static NSString *mailETag = nil;
|
|||
return response;
|
||||
}
|
||||
|
||||
- (id <WOActionResults>) archiveAttachmentsAction
|
||||
{
|
||||
NSString *name;
|
||||
SOGoMailObject *co;
|
||||
|
||||
co = [self clientObject];
|
||||
name = [NSString stringWithFormat: @"%@-%@.zip",
|
||||
[self labelForKey: @"attachments"], [co nameInContainer]];
|
||||
|
||||
return [co archiveAllFilesinArchiveNamed: name];
|
||||
}
|
||||
|
||||
/* MDN */
|
||||
|
||||
- (BOOL) _userHasEMail: (NSString *) email
|
||||
|
|
|
@ -244,6 +244,11 @@
|
|||
pageName = "UIxMailView";
|
||||
actionName = "sendMDN";
|
||||
};
|
||||
archiveAttachments = {
|
||||
protectedBy = "View";
|
||||
pageName = "UIxMailView";
|
||||
actionName = "archiveAttachments";
|
||||
};
|
||||
viewsource = {
|
||||
protectedBy = "View";
|
||||
actionClass = "UIxMailSourceView";
|
||||
|
|
|
@ -84,10 +84,16 @@
|
|||
</md-menu-item>
|
||||
<md-menu-item>
|
||||
<md-button label:aria-label="Save As..."
|
||||
ng-click="viewer.message.saveMessage()">
|
||||
ng-click="viewer.message.download()">
|
||||
<var:string label:value="Save As..."/>
|
||||
</md-button>
|
||||
</md-menu-item>
|
||||
<md-menu-item ng-show="::viewer.message.attachmentAttrs.length">
|
||||
<md-button label:aria-label="Download all attachments"
|
||||
ng-click="viewer.message.downloadAttachments()">
|
||||
<var:string label:value="Download all attachments"/>
|
||||
</md-button>
|
||||
</md-menu-item>
|
||||
<md-menu-item>
|
||||
<md-button label:aria-label="View Message Source"
|
||||
ng-click="viewer.toggleRawSource($event)">
|
||||
|
|
|
@ -192,14 +192,21 @@
|
|||
},
|
||||
responseType: 'arraybuffer',
|
||||
cache: false,
|
||||
transformResponse: function (data, headers) {
|
||||
transformResponse: function (data, headers, status) {
|
||||
var fileName, result, blob = null;
|
||||
|
||||
if (status < 200 || status > 299) {
|
||||
throw new Error('Bad gateway');
|
||||
}
|
||||
if (data) {
|
||||
blob = new Blob([data], { type: type });
|
||||
}
|
||||
fileName = getFileNameFromHeader(headers('content-disposition'));
|
||||
|
||||
if (options && options.filename) {
|
||||
fileName = options.filename;
|
||||
}
|
||||
else {
|
||||
getFileNameFromHeader(headers('content-disposition'));
|
||||
}
|
||||
if (!saveAs) {
|
||||
throw new Error('To use Resource.download, FileSaver.js must be loaded.');
|
||||
}
|
||||
|
|
|
@ -713,14 +713,19 @@
|
|||
* @returns a promise of the HTTP operation
|
||||
*/
|
||||
AddressBook.prototype.exportCards = function(selectedOnly) {
|
||||
var selectedUIDs;
|
||||
var data = null, options, selectedCards;
|
||||
|
||||
options = {
|
||||
type: 'application/octet-stream',
|
||||
filename: this.name + '.ldif'
|
||||
};
|
||||
|
||||
if (selectedOnly) {
|
||||
var selectedCards = _.filter(this.$cards, function(card) { return card.selected; });
|
||||
selectedUIDs = _.map(selectedCards, 'id');
|
||||
selectedCards = _.filter(this.$cards, function(card) { return card.selected; });
|
||||
data = { uids: _.map(selectedCards, 'id') };
|
||||
}
|
||||
|
||||
return AddressBook.$$resource.download(this.id, 'export', (angular.isDefined(selectedUIDs) ? {uids: selectedUIDs} : null), {type: 'application/octet-stream'});
|
||||
return AddressBook.$$resource.download(this.id, 'export', data, options);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -269,11 +269,15 @@
|
|||
* @returns a promise of the HTTP operation
|
||||
*/
|
||||
Card.prototype.export = function() {
|
||||
var selectedIDs;
|
||||
var data, options;
|
||||
|
||||
selectedIDs = [ this.id ];
|
||||
data = { uids: [ this.id ] };
|
||||
options = {
|
||||
type: 'application/octet-stream',
|
||||
filename: this.$$fullname + '.ldif'
|
||||
};
|
||||
|
||||
return Card.$$resource.download(this.pid, 'export', {uids: selectedIDs}, {type: 'application/octet-stream'});
|
||||
return Card.$$resource.download(this.pid, 'export', data, options);
|
||||
};
|
||||
|
||||
Card.prototype.$fullname = function(options) {
|
||||
|
|
|
@ -598,10 +598,12 @@
|
|||
* @returns a promise of the HTTP operation
|
||||
*/
|
||||
Mailbox.prototype.saveSelectedMessages = function() {
|
||||
var selectedMessages, selectedUIDs;
|
||||
var data, options, selectedMessages, selectedUIDs;
|
||||
|
||||
selectedMessages = _.filter(this.$messages, function(message) { return message.selected; });
|
||||
selectedUIDs = _.map(selectedMessages, 'uid');
|
||||
data = { uids: selectedUIDs };
|
||||
options = { filename: l('Saved Messages.zip') };
|
||||
|
||||
return Mailbox.$$resource.download(this.id, 'saveMessages', {uids: selectedUIDs});
|
||||
};
|
||||
|
@ -613,7 +615,11 @@
|
|||
* @returns a promise of the HTTP operation
|
||||
*/
|
||||
Mailbox.prototype.exportFolder = function() {
|
||||
return Mailbox.$$resource.download(this.id, 'exportFolder');
|
||||
var options;
|
||||
|
||||
options = { filename: this.name + '.zip' };
|
||||
|
||||
return Mailbox.$$resource.download(this.id, 'exportFolder', null, options);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -708,17 +708,32 @@
|
|||
};
|
||||
|
||||
/**
|
||||
* @function saveMessage
|
||||
* @function download
|
||||
* @memberof Message.prototype
|
||||
* @desc Download the current message
|
||||
* @returns a promise of the HTTP operation
|
||||
*/
|
||||
Message.prototype.saveMessage = function() {
|
||||
var selectedUIDs;
|
||||
Message.prototype.download = function() {
|
||||
var data, options;
|
||||
|
||||
selectedUIDs = [ this.uid ];
|
||||
data = { uids: [this.uid] };
|
||||
options = { filename: this.subject + '.zip' };
|
||||
|
||||
return Message.$$resource.download(this.$mailbox.id, 'saveMessages', {uids: selectedUIDs});
|
||||
return Message.$$resource.download(this.$mailbox.id, 'saveMessages', data, options);
|
||||
};
|
||||
|
||||
/**
|
||||
* @function downloadAttachments
|
||||
* @memberof Message.prototype
|
||||
* @desc Download an archive of all attachments
|
||||
* @returns a promise of the HTTP operation
|
||||
*/
|
||||
Message.prototype.downloadAttachments = function() {
|
||||
var options;
|
||||
|
||||
options = { filename: l('attachments') + "-" + this.uid + ".zip" };
|
||||
|
||||
return Message.$$resource.download(this.$absolutePath(), 'archiveAttachments', null, options);
|
||||
};
|
||||
|
||||
})();
|
||||
|
|
|
@ -530,7 +530,14 @@
|
|||
* @returns a promise of the HTTP operation
|
||||
*/
|
||||
Calendar.prototype.export = function() {
|
||||
return Calendar.$$resource.download(this.id + '.ics', 'export', null, {type: 'application/octet-stream'});
|
||||
var options;
|
||||
|
||||
options = {
|
||||
type: 'application/octet-stream',
|
||||
filename: this.name + '.ics'
|
||||
};
|
||||
|
||||
return Calendar.$$resource.download(this.id + '.ics', 'export', null, options);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue