this merges the master head of https://github.com/helma-org/apps-modules-mirror into helma
705 lines
22 KiB
JavaScript
705 lines
22 KiB
JavaScript
/*
|
|
* Helma License Notice
|
|
*
|
|
* The contents of this file are subject to the Helma License
|
|
* Version 2.0 (the "License"). You may not use this file except in
|
|
* compliance with the License. A copy of the License is available at
|
|
* http://adele.helma.org/download/helma/license.txt
|
|
*
|
|
* Copyright 1998-2007 Helma Software. All Rights Reserved.
|
|
*
|
|
* $RCSfile: Mail.js,v $
|
|
* $Author$
|
|
* $Revision$
|
|
* $Date$
|
|
*/
|
|
|
|
/**
|
|
* @fileoverview Fields and methods of the helma.Mail class.
|
|
* <br /><br />
|
|
* To use this optional module, its repository needs to be added to the
|
|
* application, for example by calling app.addRepository('modules/helma/Mail.js')
|
|
*/
|
|
|
|
// take care of any dependencies
|
|
app.addRepository('modules/helma/File.js');
|
|
|
|
/**
|
|
* Define the global namespace if not existing
|
|
*/
|
|
if (!global.helma) {
|
|
global.helma = {};
|
|
}
|
|
|
|
/**
|
|
* Mail client enabling you to send e-mail via SMTP using Packages.javax.mail.
|
|
* <br /><br />
|
|
* @class This class provides functionality to sending
|
|
* Email messages.
|
|
* A mail client object is created by using the helma.Mail()
|
|
* constructor. The mail object then can be manipulated and sent
|
|
* using the methods listed below.
|
|
* <br /><br />
|
|
* You will either need to set your mail server via the smtp
|
|
* property in the app.properties or server.properties file
|
|
* or pass the hostname of the mail server you want to use as a
|
|
* parameter to the constructor.
|
|
* <br /><br />
|
|
* Note: Make sure that the SMTP server itself is well-configured,
|
|
* so that it accepts e-mails coming from your server and does
|
|
* not deny relaying. Best and fastest configuration is of course
|
|
* if you run your own SMTP server (e.g. postfix) which might be
|
|
* a bit tricky to set up, however.</p>
|
|
*
|
|
* @param {String} smtp as String, the hostname of the mail server
|
|
* @constructor
|
|
*/
|
|
helma.Mail = function(host, port) {
|
|
// Error code values for this.status
|
|
var OK = 0;
|
|
var SUBJECT = 10;
|
|
var TEXT = 11;
|
|
var MIMEPART = 12;
|
|
var TO = 20;
|
|
var CC = 21;
|
|
var BCC = 22;
|
|
var FROM = 23;
|
|
var REPLYTO = 24;
|
|
var SETHEADER = 25;
|
|
var ADDHEADER = 26;
|
|
var GETHEADER = 27;
|
|
var REMOVEHEADER = 28;
|
|
var SEND = 30;
|
|
var MAILPKG = Packages.javax.mail;
|
|
|
|
var self = this;
|
|
var errStr = "Error in helma.Mail";
|
|
|
|
var System = java.lang.System;
|
|
var Properties = java.util.Properties;
|
|
var IOException = java.io.IOException;
|
|
var Wrapper = Packages.org.mozilla.javascript.Wrapper;
|
|
var FileDataSource = Packages.javax.activation.FileDataSource;
|
|
var DataHandler = Packages.javax.activation.DataHandler;
|
|
|
|
var MimePart = Packages.helma.util.MimePart;
|
|
var MimePartDataSource = Packages.helma.util.MimePartDataSource;
|
|
|
|
var BodyPart = MAILPKG.BodyPart;
|
|
var Message = MAILPKG.Message;
|
|
var Session = MAILPKG.Session;
|
|
var InternetAddress = MAILPKG.internet.InternetAddress;
|
|
var AddressException = MAILPKG.internet.AddressException;
|
|
var MimeBodyPart = MAILPKG.internet.MimeBodyPart;
|
|
var MimeMessage = MAILPKG.internet.MimeMessage;
|
|
var MimeUtility = MAILPKG.internet.MimeUtility;
|
|
var MimeMultipart = MAILPKG.internet.MimeMultipart;
|
|
|
|
var buffer, multipart, multipartType = "mixed";
|
|
var username, password;
|
|
|
|
var setStatus = function(status) {
|
|
if (self.status === OK) {
|
|
self.status = status;
|
|
}
|
|
return;
|
|
};
|
|
|
|
var getStatus = function() {
|
|
return self.status;
|
|
};
|
|
|
|
var addRecipient = function(addstr, name, type) {
|
|
if (addstr.indexOf("@") < 0) {
|
|
throw new AddressException();
|
|
}
|
|
if (name != null) {
|
|
var address = new InternetAddress(addstr,
|
|
MimeUtility.encodeWord(name.toString()));
|
|
} else {
|
|
var address = new InternetAddress(addstr);
|
|
}
|
|
message.addRecipient(type, address);
|
|
return;
|
|
};
|
|
|
|
/**
|
|
* Adds the content stored in this helma.Mail instance
|
|
* to the wrapped message.
|
|
* @private
|
|
*/
|
|
var setContent = function() {
|
|
if (buffer != null) {
|
|
if (multipart != null) {
|
|
var part = new MimeBodyPart();
|
|
part.setContent(buffer.toString(), "text/plain");
|
|
multipart.addBodyPart(part, 0);
|
|
message.setContent(multipart);
|
|
} else {
|
|
message.setText(buffer.toString());
|
|
}
|
|
} else if (multipart != null) {
|
|
message.setContent(multipart);
|
|
} else {
|
|
message.setText("");
|
|
}
|
|
return;
|
|
};
|
|
|
|
/**
|
|
* Returns the text buffer of this mail message
|
|
* @returns The text buffer of this mail message
|
|
* @type java.lang.StringBuffer
|
|
* @private
|
|
*/
|
|
this.getBuffer = function() {
|
|
return buffer;
|
|
};
|
|
|
|
/**
|
|
* Returns the mime multipart object of this mail message
|
|
* @returns The mime multipart object of this mail message
|
|
* @type javax.mail.internet.MimeMultipart
|
|
* @private
|
|
*/
|
|
this.getMultipart = function() {
|
|
return multipart;
|
|
};
|
|
|
|
/**
|
|
* Sets username and password to use for SMTP authentication.
|
|
* @param {String} uname The username to use
|
|
* @param {String} pwd The password to use
|
|
*/
|
|
this.setAuthentication = function(uname, pwd) {
|
|
if (uname && pwd) {
|
|
username = uname;
|
|
password = pwd;
|
|
// enable smtp authentication
|
|
props.put("mail.smtp.auth", "true");
|
|
}
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* Returns the wrapped message
|
|
* @returns The wrapped message
|
|
* @type javax.mail.internet.MimeMessage
|
|
*/
|
|
this.getMessage = function() {
|
|
return message;
|
|
};
|
|
|
|
/**
|
|
* Switches debug mode on or off.
|
|
* @param {Boolean} debug If true debug mode is enabled
|
|
*/
|
|
this.setDebug = function(debug) {
|
|
session.setDebug(debug === true);
|
|
};
|
|
|
|
/**
|
|
* The status of this Mail object. This equals <code>0</code> unless
|
|
* an error occurred. See {@link helma.Mail Mail.js} source code for a list of
|
|
* possible error codes.
|
|
*/
|
|
this.status = OK;
|
|
|
|
/**
|
|
* Sets the sender of an e-mail message.
|
|
* <br /><br />
|
|
* The first argument specifies the receipient's
|
|
* e-mail address. The optional second argument
|
|
* specifies the name of the recipient.
|
|
*
|
|
* @param {String} addstr as String, sender email address
|
|
* @param {String} name as String, optional sender name
|
|
*/
|
|
this.setFrom = function(addstr, name) {
|
|
try {
|
|
if (addstr.indexOf("@") < 0) {
|
|
throw new AddressException();
|
|
}
|
|
if (name != null) {
|
|
var address = new InternetAddress(addstr,
|
|
MimeUtility.encodeWord(name.toString()));
|
|
} else {
|
|
var address = new InternetAddress(addstr);
|
|
}
|
|
message.setFrom(address);
|
|
} catch (mx) {
|
|
app.logger.error(errStr + ".setFrom(): " + mx);
|
|
setStatus(FROM);
|
|
}
|
|
return;
|
|
};
|
|
|
|
/**
|
|
* Set a header in the e-mail message. If the given header is already set the previous
|
|
* value is replaced with the new one.
|
|
* @param name a header name
|
|
* @param value the header value
|
|
*/
|
|
this.setHeader = function(name, value) {
|
|
try {
|
|
message.addHeader(name, MimeUtility.encodeText(value));
|
|
} catch (mx) {
|
|
app.logger.error(errStr + ".setHeader(): " + mx);
|
|
setStatus(SETHEADER);
|
|
}
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* Set a header in the e-mail message. If the given header is already set the previous
|
|
* value is replaced with the new one.
|
|
* @param name a header name
|
|
* @param value the header value
|
|
*/
|
|
this.addHeader = function(name, value) {
|
|
try {
|
|
message.addHeader(name, MimeUtility.encodeText(value));
|
|
} catch (mx) {
|
|
app.logger.error(errStr + ".addHeader(): " + mx);
|
|
setStatus(ADDHEADER);
|
|
}
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* Get all the headers for this header name.
|
|
* Returns null if no headers for this header name are available.
|
|
* @param name a header name
|
|
* @return {String[]} a string array of header values, or null
|
|
*/
|
|
this.getHeader = function(name) {
|
|
var value = null;
|
|
try {
|
|
value = message.getHeader(name);
|
|
if (value && value.length) {
|
|
for (var i = 0; i < value.length; i++) {
|
|
value[i] = MimeUtility.decodeText(value[i]);
|
|
}
|
|
}
|
|
} catch (mx) {
|
|
app.logger.error(errStr + ".getHeader(): " + mx);
|
|
setStatus(GETHEADER);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
/**
|
|
* Remove all headers with this name.
|
|
* @param name the header name
|
|
*/
|
|
this.removeHeader = function(name) {
|
|
try {
|
|
message.removeHeader(name);
|
|
} catch (mx) {
|
|
app.logger.error(errStr + ".removeHeader(): " + mx);
|
|
setStatus(REMOVEHEADER);
|
|
}
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* Sets the Reply-To address of an e-mail message.
|
|
*
|
|
* @param {String} addstr as String, the reply-to email address
|
|
*/
|
|
this.setReplyTo = function(addstr) {
|
|
try {
|
|
if (addstr.indexOf("@") < 0) {
|
|
throw new AddressException();
|
|
}
|
|
var address = [new InternetAddress(addstr)];
|
|
message.setReplyTo(address);
|
|
} catch (mx) {
|
|
app.logger.error(errStr + ".setReplyTo(): " + mx);
|
|
setStatus(REPLYTO);
|
|
}
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* Sets the recipient of an e-mail message.
|
|
*
|
|
* The first argument specifies the receipient's
|
|
* e-mail address. The optional second argument
|
|
* specifies the name of the recipient.
|
|
*
|
|
* @param {String} addstr as String, receipients email address
|
|
* @param {String} name as String, optional receipients name
|
|
* @see #addTo
|
|
*/
|
|
this.setTo = function(addstr, name) {
|
|
try {
|
|
addRecipient(addstr, name, Message.RecipientType.TO);
|
|
} catch (mx) {
|
|
app.logger.error(errStr + ".setTo(): " + mx);
|
|
setStatus(TO);
|
|
}
|
|
return;
|
|
};
|
|
|
|
/**
|
|
* Adds a recipient to the address list of an e-mail message.
|
|
* <br /><br />
|
|
* The first argument specifies the receipient's
|
|
* e-mail address. The optional second argument
|
|
* specifies the name of the recipient.
|
|
*
|
|
* @param {String} addstr as String, receipients email address
|
|
* @param {String} name as String, optional receipients name
|
|
* @see setTo
|
|
*/
|
|
this.addTo = function(addstr, name) {
|
|
try {
|
|
addRecipient(addstr, name, Message.RecipientType.TO);
|
|
} catch (mx) {
|
|
app.logger.error(errStr + ".addTo(): " + mx);
|
|
setStatus(TO);
|
|
}
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* Adds a recipient to the list of addresses to get a "carbon copy"
|
|
* of an e-mail message.
|
|
* <br /><br />
|
|
* The first argument specifies the receipient's
|
|
* e-mail address. The optional second argument
|
|
* specifies the name of the recipient.
|
|
*
|
|
* @param {String} addstr as String, receipients email address
|
|
* @param {String} name as String, optional receipients name
|
|
*/
|
|
this.addCC = function(addstr, name) {
|
|
try {
|
|
addRecipient(addstr, name, Message.RecipientType.CC);
|
|
} catch (mx) {
|
|
app.logger.error(errStr + ".addCC(): " + mx);
|
|
setStatus(CC);
|
|
}
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* Adds a recipient to the list of addresses to get a "blind carbon copy" of an e-mail message.
|
|
* <br /><br />
|
|
* The first argument specifies the receipient's
|
|
* e-mail address. The optional second argument
|
|
* specifies the name of the recipient.
|
|
*
|
|
* @param {String} addstr as String, receipients email address
|
|
* @param {String} name as String, optional receipients name
|
|
*/
|
|
this.addBCC = function(addstr, name) {
|
|
try {
|
|
addRecipient(addstr, name, Message.RecipientType.BCC);
|
|
} catch (mx) {
|
|
app.logger.error(errStr + ".addBCC(): " + mx);
|
|
setStatus(BCC);
|
|
}
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* Sets the subject of an e-mail message.
|
|
*
|
|
* @param {String} subject as String, the email subject
|
|
*/
|
|
this.setSubject = function(subject) {
|
|
if (!subject) {
|
|
return;
|
|
}
|
|
try {
|
|
message.setSubject(MimeUtility.encodeWord(subject.toString()));
|
|
} catch (mx) {
|
|
app.logger.error(errStr + ".setSubject(): " + mx);
|
|
setStatus(SUBJECT);
|
|
}
|
|
return;
|
|
};
|
|
|
|
/**
|
|
* Sets the body text of an e-mail message.
|
|
*
|
|
* @param {String} text as String, to be appended to the message body
|
|
* @see #addText
|
|
*/
|
|
this.setText = function(text) {
|
|
if (text) {
|
|
buffer = new java.lang.StringBuffer(text);
|
|
}
|
|
return;
|
|
};
|
|
|
|
/**
|
|
* Appends a string to the body text of an e-mail message.
|
|
*
|
|
* @param {String} text as String, to be appended to the message body
|
|
* @see #setText
|
|
*/
|
|
this.addText = function(text) {
|
|
if (buffer == null) {
|
|
buffer = new java.lang.StringBuffer(text);
|
|
} else {
|
|
buffer.append(text);
|
|
}
|
|
return;
|
|
};
|
|
|
|
/**
|
|
* Sets the MIME multiparte message subtype. The default value is
|
|
* "mixed" for messages of type multipart/mixed. A common value
|
|
* is "alternative" for the multipart/alternative MIME type.
|
|
* @param {String} messageType the MIME subtype such as "mixed" or "alternative".
|
|
* @see #getMultipartType
|
|
* @see #addPart
|
|
*/
|
|
this.setMultipartType = function(messageType) {
|
|
multipartType = messageType;
|
|
return;
|
|
};
|
|
|
|
/**
|
|
* Returns the MIME multiparte message subtype. The default value is
|
|
* "mixed" for messages of type multipart/mixed.
|
|
* @return the MIME subtype
|
|
* @type String
|
|
* @see #setMultipartType
|
|
* @see #addPart
|
|
*/
|
|
this.getMultipartType = function(messageType) {
|
|
return multipartType;
|
|
};
|
|
|
|
/**
|
|
* Adds an attachment to an e-mail message.
|
|
* <br /><br />
|
|
* The attachment needs to be either a helma.util.MimePart Object retrieved
|
|
* through the global getURL function, or a {@link helma.File} object, or a String.
|
|
* <br /><br />
|
|
* Use the getURL() function to retrieve a MIME object or wrap a
|
|
* helma.File object around a file of the local file system.
|
|
*
|
|
* @param {fileOrMimeObjectOrString} obj File, Mime object or String to attach to the email
|
|
* @param {String} filename optional name of the attachment
|
|
* @param {String} contentType optional content type (only if first argument is a string)
|
|
* @see global.getURL
|
|
* @see helma.util.MimePart
|
|
* @see helma.File
|
|
*/
|
|
this.addPart = function(obj, filename, contentType) {
|
|
try {
|
|
if (obj == null) {
|
|
throw new IOException(
|
|
errStr + ".addPart: method called with wrong number of arguments."
|
|
);
|
|
}
|
|
if (multipart == null) {
|
|
multipart = new MimeMultipart(multipartType);
|
|
}
|
|
if (obj instanceof Wrapper) {
|
|
obj = obj.unwrap();
|
|
}
|
|
|
|
var part;
|
|
if (obj instanceof BodyPart) {
|
|
// we already got a body part, no need to convert it
|
|
part = obj;
|
|
} else {
|
|
part = new MimeBodyPart();
|
|
if (typeof obj == "string") {
|
|
part.setContent(obj.toString(), contentType || "text/plain");
|
|
} else if (obj instanceof File || obj instanceof helma.File) {
|
|
var source = new FileDataSource(obj.getPath());
|
|
part.setDataHandler(new DataHandler(source));
|
|
} else if (obj instanceof MimePart) {
|
|
var source = new MimePartDataSource(obj);
|
|
part.setDataHandler(new DataHandler(source));
|
|
}
|
|
}
|
|
if (filename != null) {
|
|
try {
|
|
part.setFileName(filename.toString());
|
|
} catch (x) {}
|
|
} else if (obj instanceof File || obj instanceof helma.File) {
|
|
try {
|
|
part.setFileName(obj.getName());
|
|
} catch (x) {}
|
|
}
|
|
multipart.addBodyPart(part);
|
|
} catch (mx) {
|
|
app.logger.error(errStr + ".addPart(): " + mx);
|
|
setStatus(MIMEPART);
|
|
}
|
|
return;
|
|
};
|
|
|
|
/**
|
|
* Saves this mail RFC 822 formatted into a file. The name of the
|
|
* file is prefixed with "helma.Mail" followed by the current time
|
|
* in milliseconds and a random number.
|
|
* @param {helma.File} dir An optional directory where to save
|
|
* this mail to. If omitted the mail will be saved in the system's
|
|
* temp directory.
|
|
*/
|
|
this.writeToFile = function(dir) {
|
|
if (!dir || !dir.exists() || !dir.canWrite()) {
|
|
dir = new java.io.File(System.getProperty("java.io.tmpdir"));
|
|
}
|
|
var fileName = "helma.Mail." + (new Date()).getTime() +
|
|
"." + Math.round(Math.random() * 1000000);
|
|
var file = new java.io.File(dir, fileName);
|
|
if (file.exists()) {
|
|
file["delete"]();
|
|
}
|
|
try {
|
|
setContent();
|
|
var fos = new java.io.FileOutputStream(file);
|
|
var os = new java.io.BufferedOutputStream(fos);
|
|
message.writeTo(os);
|
|
os.close();
|
|
app.logger.info("helma.Mail.saveTo(): saved mail to " +
|
|
file.getAbsolutePath());
|
|
} catch (e) {
|
|
app.logger.error(errStr + ".saveTo(): " + e);
|
|
}
|
|
return;
|
|
};
|
|
|
|
/**
|
|
* Returns the source of this mail as RFC 822 formatted string.
|
|
* @returns The source of this mail as RFC 822 formatted string
|
|
* @type String
|
|
*/
|
|
this.getSource = function() {
|
|
try {
|
|
setContent();
|
|
var buf = new java.io.ByteArrayOutputStream();
|
|
var os = new java.io.BufferedOutputStream(buf);
|
|
message.writeTo(os);
|
|
os.close();
|
|
return buf.toString();
|
|
} catch (e) {
|
|
app.logger.error(errStr + ".getSource(): " + e);
|
|
}
|
|
return null;
|
|
};
|
|
|
|
/**
|
|
* Sends an e-mail message.
|
|
* <br /><br />
|
|
* This function sends the message using the SMTP
|
|
* server as specified when the Mail object was
|
|
* constructed using helma.Mail.
|
|
* <br /><br />
|
|
* If no smtp hostname was specified when the Mail
|
|
* object was constructed, the smtp property in either
|
|
* the app.properties or server.properties file needs
|
|
* to be set in order for this to work.
|
|
* <br /><br />
|
|
* As a fallback, the message will then be written to
|
|
* file using the {@link #writeToFile} method.
|
|
* Additionally, the location of the message files can
|
|
* be determined by setting smtp.dir in app.properties
|
|
* to the desired file path.
|
|
*/
|
|
this.send = function() {
|
|
if (this.status > OK) {
|
|
app.logger.error(errStr + ".send(): Status is " + this.status);
|
|
return;
|
|
}
|
|
if (host != null) {
|
|
try {
|
|
setContent();
|
|
message.setSentDate(new Date());
|
|
var transport = session.getTransport("smtp");
|
|
if (username && password) {
|
|
transport.connect(host, username, password);
|
|
} else {
|
|
transport.connect();
|
|
}
|
|
message.saveChanges();
|
|
transport.sendMessage(message, message.getAllRecipients());
|
|
} catch (mx) {
|
|
app.logger.error(errStr + ".send(): " + mx);
|
|
setStatus(SEND);
|
|
} finally {
|
|
if (transport != null && transport.isConnected()) {
|
|
transport.close();
|
|
}
|
|
}
|
|
} else {
|
|
// no smtp host is given, so write the mail to a file
|
|
this.writeToFile(getProperty("smtp.dir"));
|
|
}
|
|
return;
|
|
};
|
|
|
|
/**
|
|
* Main constructor body
|
|
*/
|
|
var props = new Properties();
|
|
if (host || (host = getProperty("smtp"))) {
|
|
props.put("mail.transport.protocol", "smtp");
|
|
props.put("mail.smtp.host", String(host));
|
|
props.put("mail.smtp.port", String(port || 25));
|
|
props.put("mail.smtp.starttls.enable",
|
|
getProperty("smtp.tls") || "false");
|
|
props.put("mail.mime.charset",
|
|
getProperty("smtp.charset") ||
|
|
System.getProperty("mail.charset") ||
|
|
"ISO-8859-15");
|
|
}
|
|
|
|
this.setAuthentication(getProperty("smtp.username"),
|
|
getProperty("smtp.password"));
|
|
var session = Session.getInstance(props);
|
|
var message = new MimeMessage(session);
|
|
|
|
for (var i in this)
|
|
this.dontEnum(i);
|
|
|
|
return this;
|
|
}
|
|
|
|
|
|
/** @ignore */
|
|
helma.Mail.toString = function() {
|
|
return "[helma.Mail]";
|
|
};
|
|
|
|
|
|
/** @ignore */
|
|
helma.Mail.prototype.toString = function() {
|
|
return "[helma.Mail Object]";
|
|
};
|
|
|
|
helma.Mail.example = function(host, sender, addr, subject, text) {
|
|
// var smtp = "smtp.host.dom";
|
|
// var sender = "sender@host.dom";
|
|
// var addr = "recipient@host.dom";
|
|
// var subject = "Hello, World!";
|
|
// var text = "This is a test.";
|
|
var port = 25;
|
|
var msg = new helma.Mail(host, port);
|
|
msg.setFrom(sender);
|
|
msg.addTo(addr);
|
|
msg.setSubject(subject);
|
|
msg.setText(text);
|
|
msg.send();
|
|
res.write(msg.status);
|
|
return;
|
|
};
|
|
|
|
|
|
helma.lib = "Mail";
|
|
helma.dontEnum(helma.lib);
|
|
for (var i in helma[helma.lib])
|
|
helma[helma.lib].dontEnum(i);
|
|
for (var i in helma[helma.lib].prototype)
|
|
helma[helma.lib].prototype.dontEnum(i);
|
|
delete helma.lib;
|