diff --git a/UI/MailerUI/UIxMailFolderActions.m b/UI/MailerUI/UIxMailFolderActions.m index b95ed67df0..fd4dfccaee 100644 --- a/UI/MailerUI/UIxMailFolderActions.m +++ b/UI/MailerUI/UIxMailFolderActions.m @@ -1,6 +1,6 @@ /* UIxMailFolderActions.m - this file is part of SOGo * - * Copyright (C) 2007-2021 Inverse inc. + * Copyright (C) 2007-2022 Inverse inc. * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,11 +30,15 @@ #import +#import +#import #import #import +#import #import #import +#import #import #import #import @@ -704,6 +708,99 @@ - (WOResponse *) moveMessagesAction return response; } +- (WOResponse *) forwardMessagesAction +{ + BOOL htmlComposition; + NSArray *uids; + NSDictionary *data, *identity, *headers; + NSMutableDictionary *attachment; + NSString *accountName, *mailboxName, *messageName, *fullName, *format, *signature, *nl, *space; + SOGoDraftObject *newMail; + SOGoDraftsFolder *drafts; + SOGoMailAccount *account; + SOGoMailFolder *co; + SOGoMailObject *currentMail; + SOGoUserDefaults *ud; + WOResponse *response; + unsigned int i; + + co = [self clientObject]; + data = [[[context request] contentAsString] objectFromJSONString]; + uids = [data objectForKey: @"uids"]; + response = nil; + + if ([uids count] > 0) + { + account = [co mailAccountFolder]; + identity = [account defaultIdentity]; + drafts = [account draftsFolderInContext: context]; + newMail = [drafts newDraft]; + ud = [[context activeUser] userDefaults]; + htmlComposition = [[ud mailComposeMessageType] isEqualToString: @"html"]; + + [newMail setIsHTML: htmlComposition]; + if (identity) + { + // Set From header + fullName = [identity objectForKey: @"fullName"]; + if ([fullName length]) + format = @"%{fullName} <%{email}>"; + else + format = @"%{email}"; + headers = [NSDictionary dictionaryWithObject: [identity keysWithFormat: format] + forKey: @"from"]; + [newMail setHeaders: headers]; + + // Add signature + signature = [identity objectForKey: @"signature"]; + if ([signature length]) + { + nl = (htmlComposition? @"
" : @"\n"); + space = (htmlComposition ? @" " : @" "); + [newMail setText: [NSString stringWithFormat: @"%@%@--%@%@%@", nl, nl, space, nl, signature]]; + } + } + + for (i = 0; i < [uids count]; i++) + { + currentMail = [co lookupName: [NSString stringWithFormat: @"%@", [uids objectAtIndex: i]] + inContext: context + acquire: NO]; + attachment = [NSMutableDictionary dictionaryWithObjectsAndKeys: + [currentMail filenameForForward], @"filename", + @"message/rfc822", @"mimetype", + nil]; + [newMail saveAttachment: [currentMail content] + withMetadata: attachment]; + } + + [newMail save]; // store on IMAP server + [newMail storeInfo]; + + accountName = [account nameInContainer]; + mailboxName = [drafts absoluteImap4Name]; + mailboxName = [mailboxName substringWithRange: NSMakeRange(1, [mailboxName length] - 2)]; + messageName = [newMail nameInContainer]; + + data = [NSDictionary dictionaryWithObjectsAndKeys: + accountName, @"accountId", + mailboxName, @"mailboxPath", + messageName, @"draftId", + [NSNumber numberWithInt: [newMail IMAP4ID]], @"uid", nil]; + + return [self responseWithStatus: 201 + andString: [data jsonRepresentation]]; + } + else + { + data = [NSDictionary dictionaryWithObject: [self labelForKey: @"Error forwarding messages." inContext: context] + forKey: @"message"]; + response = [self responseWithStatus: 500 andJSONRepresentation: data]; + } + + return response; +} + - (void) _setFolderPurposeOnMainAccount: (NSString *) purpose inUserDefaults: (SOGoUserDefaults *) ud to: (NSString *) value diff --git a/UI/MailerUI/product.plist b/UI/MailerUI/product.plist index 5f55a4f590..0f9b4ae452 100644 --- a/UI/MailerUI/product.plist +++ b/UI/MailerUI/product.plist @@ -99,6 +99,11 @@ actionClass = "UIxMailFolderActions"; actionName = "moveMessages"; }; + forwardMessages = { + protectedBy = "View"; + actionClass = "UIxMailFolderActions"; + actionName = "forwardMessages"; + }; setAsDraftsFolder = { protectedBy = "View"; actionClass = "UIxMailFolderActions"; diff --git a/UI/Templates/MailerUI/UIxMailFolderTemplate.wox b/UI/Templates/MailerUI/UIxMailFolderTemplate.wox index 1dd9841133..a621e6562b 100644 --- a/UI/Templates/MailerUI/UIxMailFolderTemplate.wox +++ b/UI/Templates/MailerUI/UIxMailFolderTemplate.wox @@ -227,6 +227,11 @@ + + + + + diff --git a/UI/WebServerResources/js/Mailer/Mailbox.service.js b/UI/WebServerResources/js/Mailer/Mailbox.service.js index 5dc38f86a5..60063d6582 100644 --- a/UI/WebServerResources/js/Mailer/Mailbox.service.js +++ b/UI/WebServerResources/js/Mailer/Mailbox.service.js @@ -746,6 +746,23 @@ }); }; + /** + * @function forwardMessages + * @memberof Mailbox.prototype + * @desc Attach multiple messages to a new draft + * @returns a promise of the HTTP operation with the draft coordinates + */ + Mailbox.prototype.forwardMessages = function(messages) { + var _this = this, + uids = _.map(messages, 'uid'); + + return Mailbox.$$resource.post(this.id, 'forwardMessages', { uids: uids }).then(function(data) { + Mailbox.$log.debug('Forward selected messages: ' + JSON.stringify(data, undefined, 2)); + var message = new Mailbox.$Message(data.accountId, _this.$account.$getMailboxByPath(data.mailboxPath), data); + return message; + }); + }; + /** * @function saveSelectedMessages * @memberof Mailbox.prototype diff --git a/UI/WebServerResources/js/Mailer/MailboxController.js b/UI/WebServerResources/js/Mailer/MailboxController.js index 528149b7a6..807572ba91 100644 --- a/UI/WebServerResources/js/Mailer/MailboxController.js +++ b/UI/WebServerResources/js/Mailer/MailboxController.js @@ -11,7 +11,8 @@ var vm = this, defaultWindowTitle = angular.element($window.document).find('title').attr('sg-default') || "SOGo", hotkeys = [], - sortLabels; + sortLabels, + popupWindow = null; sortLabels = { subject: 'Subject', @@ -184,15 +185,58 @@ return Preferences.defaults.SOGoMailComposeWindowEnabled; }; - this.newMessage = function($event, inPopup) { - var message, onCompleteDeferred = $q.defer(); + this.openInPopup = function(message, action) { + var url = [sgSettings.baseURL(), + 'UIxMailPopupView#!/Mail', + this.account.id], + wId = this.account.id + '/' + Math.random(0, 1000); + if (message) { + // The double-encoding is necessary + url.push(encodeUriFilter(encodeUriFilter(message.$mailbox.path))); + url.push(message.uid); + wId = message.$absolutePath(); + } + if (action) { + wId += '/' + action; + url.push(action); + } + url = url.join('/'); + popupWindow = $window.open(url, wId, + ["width=680", + "height=520", + "resizable=1", + "scrollbars=1", + "toolbar=0", + "location=0", + "directories=0", + "status=0", + "menubar=0", + "copyhistory=0"] + .join(',')); + }; - if (vm.messageDialog === null) { - if (inPopup || Preferences.defaults.SOGoMailComposeWindow == 'popup') - _newMessageInPopup(); - else { - message = vm.account.$newMessage(); - vm.messageDialog = $mdDialog + this.closePopup = function() { + if ($window.document.body.classList.contains('popup')) + $window.close(); + }; + + /** + * To keep track of the currently active dialog, we share a common variable with the parent controller. + */ + function _messageDialog() { + if ($scope.mailbox) { + if (arguments.length > 0) + $scope.mailbox.messageDialog = arguments[0]; + return $scope.mailbox.messageDialog; + } + return null; + } + + function _showMailEditor($event, message) { + if (_messageDialog() === null) { + var onCompleteDeferred = $q.defer(); + _messageDialog( + $mdDialog .show({ parent: angular.element(document.body), targetEvent: $event, @@ -215,34 +259,29 @@ }) .catch(_.noop) // Cancel .finally(function() { - vm.messageDialog = null; - }); - } + _messageDialog(null); + vm.closePopup(); + }) + ); } + } + + this._showMailEditorInPopup = function(message, action, inPopup) { + if (!sgSettings.isPopup && + (Preferences.defaults.SOGoMailComposeWindow == 'popup' || inPopup)) { + this.openInPopup(message, action); + return true; + } + return false; }; - function _newMessageInPopup() { - var url = [sgSettings.baseURL(), - 'UIxMailPopupView#!/Mail', - vm.account.id, - // The double-encoding is necessary - encodeUriFilter(encodeUriFilter(vm.selectedFolder.path)), - 'new'] - .join('/'), - wId = vm.selectedFolder.$id() + '/' + Math.random(0, 1000); - $window.open(url, wId, - ["width=680", - "height=520", - "resizable=1", - "scrollbars=1", - "toolbar=0", - "location=0", - "directories=0", - "status=0", - "menubar=0", - "copyhistory=0"] - .join(',')); - } + this.newMessage = function($event, inPopup) { + if (!this._showMailEditorInPopup(null, 'new', inPopup)) { + this.account.$newMessage().then(function(message) { + _showMailEditor($event, message); + }); + } + }; /** * User has pressed up arrow key @@ -579,6 +618,20 @@ } }; + this.forwardSelectedMessages = function($event) { + var _this = this, + selectedMessages = vm.selectedFolder.selectedMessages(); + if (_.size(selectedMessages) > 0) { + vm.selectedFolder.forwardMessages(selectedMessages).then(function(message) { + if (!_this._showMailEditorInPopup(message, 'edit')) { + message.$editableContent().then(function() { + _showMailEditor($event, message); + }); + } + }); + } + }; + } angular diff --git a/UI/WebServerResources/js/Mailer/Mailer.popup.js b/UI/WebServerResources/js/Mailer/Mailer.popup.js index b3e67bd711..8a16a377fc 100644 --- a/UI/WebServerResources/js/Mailer/Mailer.popup.js +++ b/UI/WebServerResources/js/Mailer/Mailer.popup.js @@ -43,7 +43,7 @@ stateMailbox: stateMailbox } }) - .state('mail.account.mailbox.newMessage', { + .state('mail.account.newMessage', { url: '/new', views: { 'message@': { @@ -91,7 +91,7 @@ }); // if none of the above states are matched, use this as the fallback - $urlRouterProvider.otherwise('/Mail/0/folderINBOX/new'); + $urlRouterProvider.otherwise('/Mail/0/new'); } /** @@ -199,7 +199,9 @@ } else { futureMailbox = stateAccount.$getMailboxes().then(function(mailboxes) { - return _find(mailboxes); + var data = _find(mailboxes), + mailbox = new Mailbox(stateAccount, data); + return mailbox; }); }