Skip to content

Commit

Permalink
register web app as a handler for mailto scheme
Browse files Browse the repository at this point in the history
Fixes #1223
  • Loading branch information
cgx committed Aug 29, 2017
1 parent c277c39 commit 5e5e52e
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 52 deletions.
1 change: 1 addition & 0 deletions NEWS
Expand Up @@ -4,6 +4,7 @@
New features
- [core] can now invite attendees to exceptions only (#2561)
- [web] display freebusy information of owner in appointment editor
- [web] register SOGo as a handler for the mailto scheme (#1223)

Enhancements
-
Expand Down
3 changes: 1 addition & 2 deletions UI/Templates/MailerUI/UIxMailEditor.wox
Expand Up @@ -12,8 +12,7 @@
nv-file-drop="nv-file-drop"
nv-file-over="nv-file-over"
over-class="sg-over-dropzone"
uploader="editor.uploader"
ng-controller="navController">
uploader="editor.uploader">
<form name="messageForm">
<md-toolbar>
<div class="md-toolbar-tools">
Expand Down
4 changes: 3 additions & 1 deletion UI/WebServerResources/js/Mailer/Account.service.js
Expand Up @@ -300,7 +300,7 @@
* @desc Prepare a new Message object associated to the appropriate mailbox.
* @returns a promise of the HTTP operations
*/
Account.prototype.$newMessage = function() {
Account.prototype.$newMessage = function(options) {
var _this = this;

// Query account for draft folder and draft UID
Expand All @@ -314,6 +314,8 @@
Account.$log.debug('New message (edit): ' + JSON.stringify(data, undefined, 2));
angular.extend(message.editable, data);
message.isNew = true;
if (options && options.mailto)
message.$parseMailto(options.mailto);
return message;
});
});
Expand Down
10 changes: 8 additions & 2 deletions UI/WebServerResources/js/Mailer/Mailer.app.js
Expand Up @@ -141,6 +141,12 @@

// if none of the above states are matched, use this as the fallback
$urlRouterProvider.otherwise('/Mail/0/inbox');

// Try to register SOGo has an handler for mailto: links
if (navigator && navigator.registerProtocolHandler) {
var mailtoURL = window.location.origin + window.ApplicationBaseURL + 'UIxMailPopupView#!/Mail/0/INBOX/new?%s';
navigator.registerProtocolHandler('mailto', mailtoURL, 'SOGo');
}
}

/**
Expand Down Expand Up @@ -178,8 +184,8 @@
/**
* @ngInject
*/
stateMailbox.$inject = ['$q', '$state', '$stateParams', 'stateAccount', 'decodeUriFilter', 'Mailbox'];
function stateMailbox($q, $state, $stateParams, stateAccount, decodeUriFilter, Mailbox) {
stateMailbox.$inject = ['$q', '$stateParams', 'stateAccount', 'decodeUriFilter', 'Mailbox'];
function stateMailbox($q, $stateParams, stateAccount, decodeUriFilter, Mailbox) {
var mailbox,
mailboxId = decodeUriFilter($stateParams.mailboxId),
_find;
Expand Down
66 changes: 45 additions & 21 deletions UI/WebServerResources/js/Mailer/Mailer.popup.js
Expand Up @@ -99,27 +99,33 @@
/**
* @ngInject
*/
stateAccounts.$inject = ['$q', 'Account'];
function stateAccounts($q, Account) {
stateAccounts.$inject = ['$window', '$q', 'Account'];
function stateAccounts($window, $q, Account) {
var accounts, promises = [];

if (window &&
window.opener &&
window.opener.$mailboxController) {
if ($window &&
$window.opener &&
$window.opener.$mailboxController) {
// Mail accounts are available from the parent window
accounts = window.opener.$mailboxController.accounts;
accounts = $window.opener.$mailboxController.accounts;
return $q.when(accounts);
}
else {
accounts = Account.$findAll();
// Fetch list of mailboxes for each account
angular.forEach(accounts, function(account, i) {
var mailboxes = account.$getMailboxes();
promises.push(mailboxes.then(function(objects) {
return account;
}));
return Account.$findAll().then(function(accounts) {
// Fetch list of mailboxes for each account
angular.forEach(accounts, function(account, i) {
var mailboxes = account.$getMailboxes();
if (i === 0)
// Make sure we have the list of mailboxes of the first account
promises.push(mailboxes.then(function(objects) {
return account;
}));
else
// Don't wait for external accounts
promises.push(account);
});
return $q.all(promises);
});
return $q.all(promises);
}
}

Expand All @@ -136,10 +142,12 @@
/**
* @ngInject
*/
stateMailbox.$inject = ['$stateParams', 'stateAccount', 'decodeUriFilter'];
function stateMailbox($stateParams, stateAccount, decodeUriFilter) {
var mailboxId = decodeUriFilter($stateParams.mailboxId),
stateMailbox.$inject = ['$q', '$state', '$stateParams', 'stateAccount', 'decodeUriFilter', 'Mailbox'];
function stateMailbox($q, $state, $stateParams, stateAccount, decodeUriFilter, Mailbox) {
var mailbox,
mailboxId = decodeUriFilter($stateParams.mailboxId),
_find;

// Recursive find function
_find = function(mailboxes) {
var mailbox = _.find(mailboxes, function(o) {
Expand All @@ -154,15 +162,31 @@
}
return mailbox;
};
return _find(stateAccount.$mailboxes);

mailbox = _find(stateAccount.$mailboxes);

if (mailbox) {
mailbox.$topIndex = 0;
mailbox.selectFolder();
return mailbox;
}
else
// Mailbox not found
return $q.reject("Mailbox doesn't exist");
}

/**
* @ngInject
*/
stateNewMessage.$inject = ['stateAccount'];
function stateNewMessage(stateAccount) {
return stateAccount.$newMessage();
stateNewMessage.$inject = ['$urlService', 'stateAccount'];
function stateNewMessage($urlService, stateAccount) {
var mailto, params = $urlService.search();
if (params) {
mailto = _.find(_.keys(params), function(k) {
return /^mailto:/i.test(k);
});
}
return stateAccount.$newMessage({ mailto: mailto });
}

/**
Expand Down
35 changes: 35 additions & 0 deletions UI/WebServerResources/js/Mailer/Message.service.js
Expand Up @@ -544,6 +544,41 @@
return this.$unwrap(futureMessageData);
};

/**
* @function $parseMailto
* @memberof Message.prototype
* @desc Extend the editable content of the message with the
* information parsed from the specified "mailto:" link.
*/
Message.prototype.$parseMailto = function(mailto) {
var to, data, match = /^mailto:([^\?]+)/.exec(mailto);
if (match) {
// Recipients
to = _.map(decodeURIComponent(match[1]).split(','), function(email) {
return '<' + email.trim() + '>';
});
data = { to: to };
// Subject & body
_.forEach(['subject', 'body'], function(param) {
var re = new RegExp(param + '=([^&]+)');
param = (param == 'body')? 'text' : param;
match = re.exec(mailto);
if (match)
data[param] = decodeURIComponent(match[1]);
});
// Other Recipients
_.forEach(['cc', 'bcc'], function(param) {
var re = new RegExp(param + '=([^&]+)');
match = re.exec(mailto);
if (match)
data[param] = _.map(decodeURIComponent(match[1]).split(','), function(email) {
return '<' + email.trim() + '>';
});
});
angular.extend(this.editable, data);
}
};

/**
* @function $reply
* @memberof Message.prototype
Expand Down
32 changes: 6 additions & 26 deletions UI/WebServerResources/js/Mailer/MessageController.js
Expand Up @@ -193,27 +193,8 @@
href = $event.target.attributes.href.value;
match = /^mailto:([^\?]+)/.exec(href);
if (match) {
// Recipients
to = _.map(decodeURIComponent(match[1]).split(','), function(email) {
return '<' + email + '>';
});
data = { to: to };
// Subject & body
_.forEach(['subject', 'body'], function(param) {
var re = new RegExp(param + '=([^&]+)');
param = (param == 'body')? 'text' : param;
match = re.exec(href);
if (match)
data[param] = [decodeURIComponent(match[1])];
});
// Recipients
_.forEach(['cc', 'bcc'], function(param) {
var re = new RegExp(param + '=([^&]+)');
match = re.exec(href);
if (match)
data[param] = [decodeURIComponent(match[1])];
});
this.newMessage($event, data); // will stop event propagation
delete $event.target.attributes.target;
this.newMessage($event, href); // will stop event propagation
}
}
};
Expand Down Expand Up @@ -359,13 +340,12 @@
$window.close();
};

this.newMessage = function($event, editableContent) {
this.account.$newMessage().then(function(message) {
angular.extend(message.editable, editableContent);
_showMailEditor($event, message);
});
this.newMessage = function($event, mailto) {
$event.stopPropagation();
$event.preventDefault();
this.account.$newMessage({ mailto: mailto }).then(function(message) {
_showMailEditor($event, message);
});
};

this.toggleRawSource = function($event) {
Expand Down

1 comment on commit 5e5e52e

@atsawin
Copy link

@atsawin atsawin commented on 5e5e52e Oct 1, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How to disable this feature. It's bit annoyed when it ask again and again if I want to register.

Please sign in to comment.