/*
*
* * Copyright 2014 Orient Technologies LTD (info(at)orientechnologies.com)
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * http://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
* *
* * For more information: http://www.orientechnologies.com
*
*/
package com.orientechnologies.orient.server.plugin.mail;
import com.orientechnologies.common.exception.OException;
import com.orientechnologies.common.io.OIOUtils;
import com.orientechnologies.common.log.OLogManager;
import com.orientechnologies.common.parser.OSystemVariableResolver;
import com.orientechnologies.orient.core.Orient;
import com.orientechnologies.orient.core.command.script.OScriptInjection;
import com.orientechnologies.orient.core.exception.OConfigurationException;
import com.orientechnologies.orient.core.record.impl.ODocument;
import com.orientechnologies.orient.server.OServer;
import com.orientechnologies.orient.server.config.OServerParameterConfiguration;
import com.orientechnologies.orient.server.plugin.OServerPluginAbstract;
import com.orientechnologies.orient.server.plugin.OServerPluginConfigurable;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.*;
import javax.mail.internet.*;
import javax.script.Bindings;
import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
public class OMailPlugin extends OServerPluginAbstract implements OScriptInjection, OServerPluginConfigurable {
private static final String CONFIG_PROFILE_PREFIX = "profile.";
private static final String CONFIG_MAIL_PREFIX = "mail.";
private ODocument configuration;
private Map<String, OMailProfile> profiles = new HashMap<String, OMailProfile>();
private String configFile = "${ORIENTDB_HOME}/config/mail.json";
public OMailPlugin() {
Orient.instance().getScriptManager().registerInjection(this);
}
@Override
public void config(final OServer oServer, final OServerParameterConfiguration[] iParams) {
configuration = new ODocument();
for (OServerParameterConfiguration param : iParams) {
if (param.name.equalsIgnoreCase("enabled")) {
configuration.field("enabled", Boolean.parseBoolean(param.value));
} else if (param.name.startsWith(CONFIG_PROFILE_PREFIX)) {
final String parts = param.name.substring(CONFIG_PROFILE_PREFIX.length());
int pos = parts.indexOf('.');
if (pos == -1)
continue;
final String profileName = parts.substring(0, pos);
final String profileParam = parts.substring(pos + 1);
OMailProfile profile = profiles.get(profileName);
if (profile == null) {
profile = new OMailProfile();
profiles.put(profileName, profile);
}
if (profileParam.startsWith(CONFIG_MAIL_PREFIX)) {
profile.put(profileParam, param.value);
}
}
}
List<Map<String, String>> profilesDocuments = new ArrayList<Map<String, String>>();
for (String p : profiles.keySet()) {
OMailProfile oMailProfile = profiles.get(p);
Map<String, String> properties = new HashMap<String, String>();
Set<String> strings = oMailProfile.stringPropertyNames();
for (String string : strings) {
properties.put(string, oMailProfile.getProperty(string));
}
properties.put("name", p);
profilesDocuments.add(properties);
}
configuration.field("profiles", profilesDocuments);
configure();
OLogManager.instance().info(this, "Installing Mail plugin, loaded %d profile(s): %s", profiles.size(), profiles.keySet());
}
private void configure() {
final File f = new File(OSystemVariableResolver.resolveSystemVariables(configFile));
if (f.exists()) {
// READ THE FILE
try {
final String configurationContent = OIOUtils.readFileAsString(f);
configuration = new ODocument().fromJSON(configurationContent);
} catch (IOException e) {
throw OException.wrapException(new OConfigurationException("Cannot load Mail configuration file '" + configFile
+ "'. Mail Plugin will be disabled"), e);
}
} else {
try {
f.getParentFile().mkdirs();
f.createNewFile();
OIOUtils.writeFile(f, configuration.toJSON("prettyPrint"));
OLogManager.instance().info(this, "Mail plugin: migrated configuration to file '%s'", f);
} catch (IOException e) {
throw OException.wrapException(new OConfigurationException("Cannot create Mail plugin configuration file '" + configFile
+ "'. Mail Plugin will be disabled"), e);
}
}
profiles.clear();
Collection<Map<String, Object>> profilesInDocs = configuration.field("profiles");
for (Map<String, Object> profile : profilesInDocs) {
String name = (String) profile.get("name");
OMailProfile p = profiles.get(name);
if (p == null) {
p = new OMailProfile();
profiles.put(name, p);
}
for (String s : profile.keySet()) {
if (!s.equalsIgnoreCase("name")) {
p.put(s, profile.get(s).toString());
}
}
}
}
public void writeConfiguration() throws IOException {
final File f = new File(OSystemVariableResolver.resolveSystemVariables(configFile));
OIOUtils.writeFile(f, configuration.toJSON("prettyPrint"));
}
/**
* Sends an email. Supports the following configuration: subject, message, to, cc, bcc, date, attachments
*
* @param iMessage
* Configuration as Map<String,Object>
* @throws AddressException
* @throws MessagingException
* @throws ParseException
*/
public void send(final Map<String, Object> iMessage) throws AddressException, MessagingException, ParseException {
if (iMessage == null)
throw new IllegalArgumentException("Configuration is null");
final String profileName = (String) iMessage.get("profile");
final OMailProfile profile = profiles.get(profileName);
if (profile == null)
throw new IllegalArgumentException("Mail profile '" + profileName + "' is not configured on server");
// creates a new session with an authenticator
Authenticator auth = new OSMTPAuthenticator((String) profile.getProperty("mail.smtp.user"),
(String) profile.getProperty("mail.smtp.password"));
final Session session = Session.getInstance(profile, auth);
// creates a new e-mail message
MimeMessage msg = new MimeMessage(session);
final String from;
if (iMessage.containsKey("from"))
// GET THE 'FROM' FROM THE MESSAGE
from = (String) iMessage.get("from");
else
// GET THE 'FROM' FROM PROFILE
from = (String) profile.getProperty("mail.from");
if (from != null)
msg.setFrom(new InternetAddress(from));
final String to = (String) iMessage.get("to");
if (to != null && !to.isEmpty())
msg.setRecipients(Message.RecipientType.TO, getEmails(to));
final String cc = (String) iMessage.get("cc");
if (cc != null && !cc.isEmpty())
msg.setRecipients(Message.RecipientType.CC, getEmails(cc));
final String bcc = (String) iMessage.get("bcc");
if (bcc != null && !bcc.isEmpty())
msg.setRecipients(Message.RecipientType.BCC, getEmails(bcc));
msg.setSubject((String) iMessage.get("subject"));
// DATE
Object date = iMessage.get("date");
final Date sendDate;
if (date == null)
// NOT SPECIFIED = NOW
sendDate = new Date();
else if (date instanceof Date)
// PASSED
sendDate = (Date) date;
else {
// FORMAT IT
String dateFormat = (String) profile.getProperty("mail.date.format");
if (dateFormat == null)
dateFormat = "yyyy-MM-dd HH:mm:ss";
sendDate = new SimpleDateFormat(dateFormat).parse(date.toString());
}
msg.setSentDate(sendDate);
// creates message part
MimeBodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setContent(iMessage.get("message"), "text/html");
// creates multi-part
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(messageBodyPart);
final String[] attachments = (String[]) iMessage.get("attachments");
// adds attachments
if (attachments != null && attachments.length > 0) {
for (String filePath : attachments) {
addAttachment(multipart, filePath);
}
}
// sets the multi-part as e-mail's content
msg.setContent(multipart);
// sends the e-mail
Transport.send(msg);
}
@Override
public void bind(final Bindings binding) {
binding.put("mail", this);
}
@Override
public void unbind(final Bindings binding) {
binding.put("mail", null);
}
@Override
public String getName() {
return "mail";
}
public Set<String> getProfileNames() {
return profiles.keySet();
}
public OMailProfile getProfile(final String iName) {
return profiles.get(iName);
}
public OMailPlugin registerProfile(final String iName, final OMailProfile iProfile) {
profiles.put(iName, iProfile);
return this;
}
protected InternetAddress[] getEmails(final String iText) throws AddressException {
if (iText == null)
return null;
final String[] items = iText.split(",");
final InternetAddress[] addresses = new InternetAddress[items.length];
for (int i = 0; i < items.length; ++i)
addresses[i] = new InternetAddress(items[i]);
return addresses;
}
/**
* Adds a file as an attachment to the email's content
*
* @param multipart
* @param filePath
* @throws MessagingException
*/
private void addAttachment(final Multipart multipart, final String filePath) throws MessagingException {
MimeBodyPart attachPart = new MimeBodyPart();
DataSource source = new FileDataSource(filePath);
attachPart.setDataHandler(new DataHandler(source));
attachPart.setFileName(new File(filePath).getName());
multipart.addBodyPart(attachPart);
}
@Override
public ODocument getConfig() {
return configuration;
}
@Override
public void changeConfig(ODocument document) {
ODocument oldConfig = configuration;
configuration = document;
try {
writeConfiguration();
} catch (IOException e) {
configuration = oldConfig;
throw OException.wrapException(new OConfigurationException("Cannot Write Mail configuration file '" + configFile
+ "'. Restoring old configuration."), e);
}
configure();
}
}