KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mmbase > applications > email > EmailHandler


1 /*
2
3 This software is OSI Certified Open Source Software.
4 OSI Certified is a certification mark of the Open Source Initiative.
5
6 The license (Mozilla version 1.0) can be read at the MMBase site.
7 See http://www.MMBase.org/license
8
9 */

10 package org.mmbase.applications.email;
11
12 import java.io.*;
13 import java.net.*;
14 import java.util.*;
15 import javax.mail.internet.MimeMultipart JavaDoc;
16
17 import org.mmbase.util.StringObject;
18 import org.mmbase.module.core.*;
19
20
21 import org.mmbase.util.logging.Logger;
22 import org.mmbase.util.logging.Logging;
23
24 /**
25  * This is a helper class for EmailBuilder. It contains a lot of methods which deal with
26  * MMObjectNodes of type 'email' (So actually one would expect those functions to be member of
27  * EmailBuilder itself).
28  *
29  * @author Daniel Ockeloen
30  * @author Michiel Meeuwissen
31  * @author Simon Groenewolt
32  * @version $Id: EmailHandler.java,v 1.18 2006/07/06 11:50:26 michiel Exp $
33  * @since MMBase-1.7
34  */

35 public class EmailHandler {
36
37
38     private static final Logger log = Logging.getLoggerInstance(EmailHandler.class);
39
40
41     /**
42      * Send the email node.
43      * firsts finds all out all the related users and groups (or not)
44      * then parse the content for subject and body
45      * lastly mail it using the sendmail module
46      */

47     public static MMObjectNode sendMailNode(MMObjectNode node) {
48         // get the sendmail module
49
SendMailInterface sendmail = EmailBuilder.getSendMail();
50         if (sendmail == null) {
51             log.error("sendmail module not active, cannot send email");
52
53             //node.commit(); // why is the node committed here?
54

55             return node; // STATE_FAILED ?
56
}
57
58
59
60         String JavaDoc from = node.getStringValue("from");
61         Set toGroup = getAttachedGroups(node);
62
63         // get Body of the mail (including url based)
64
String JavaDoc body = node.getStringValue("body");
65
66         Map headers = getHeaders(node);
67
68         if (toGroup.size() > 0) {
69             // bulk-mailing
70
Set toUsers = new LinkedHashSet(getTo(node));
71             toUsers.addAll(toGroup);
72
73             // loop all the users we need to mail
74
Iterator i = toUsers.iterator();
75             while (i.hasNext()) {
76                 // get the next user we need to email
77
NodeRecipient to = (NodeRecipient) i.next();
78                 sendMail(node, from, to, body, headers);
79
80                 // make sure that CC and BCC are only on first mail, otherwise those poor people get a lot of mail.
81
headers.put("CC", null);
82                 headers.put("BCC", null);
83
84             }
85         } else {
86             // one simple mail
87
NodeRecipient to = new NodeRecipient(-1, node.getStringValue("to"));
88             sendMail(node, from, to, body, headers);
89         }
90         // set the new mailedtime, that can be used by admins
91
// to see when it was mailed vs the requested mail
92
// time
93
node.setValue("mailedtime", (int)(System.currentTimeMillis()/1000));
94
95         // commit the changes to the cloud
96
if (node.getNumber() > 0) {
97             node.commit();
98         }
99         return node;
100     }
101
102     /**
103      * Reads some fields from the given node and returns it as a Map with mail-headers.
104      * The considered fields are replyto, cc, bcc and subject.
105      */

106     private static Map getHeaders(MMObjectNode node) {
107         Map headers = new HashMap();
108
109         MMObjectBuilder email = node.getBuilder();
110         // headers.put("From", node.getStringValue("from"));
111
if (email.hasField("replyto")) {
112             headers.put("Reply-To", unemptyString(node.getStringValue("replyto")));
113         }
114         if (email.hasField("cc")) {
115             headers.put("CC", unemptyString(node.getStringValue("cc")));
116         }
117         if (email.hasField("bcc")) {
118             headers.put("BCC", unemptyString(node.getStringValue("bcc")));
119         }
120         headers.put("Subject", unemptyString(node.getStringValue("subject"))); // subject field is obligory
121
return headers;
122     }
123
124     /**
125      * Utility function.
126      * @return null if empty string, string otherwise
127      */

128
129     private static String JavaDoc unemptyString(String JavaDoc string) {
130         return "".equals(string) ? null : string;
131     }
132
133
134     /**
135      * get the To header if its not set directly
136      * try to obtain it from related objects.
137      */

138     private static Set getTo(MMObjectNode node) {
139         Set toUsers = new LinkedHashSet();
140         String JavaDoc to = node.getStringValue("to");
141         if (to != null && !to.equals("")) {
142             toUsers.add(new NodeRecipient(-1, to));
143         }
144         return toUsers;
145     }
146
147
148
149     /**
150      * Get the email addresses of related users, which are related to related groups.
151      */

152     private static Set getAttachedGroups(MMObjectNode node) {
153         Set toUsers = new LinkedHashSet();
154         if (MMBase.getMMBase().getBuilder(EmailBuilder.groupsBuilder) != null) { // never mind if groups builders does not exist
155
List rels = node.getRelatedNodes(EmailBuilder.groupsBuilder);
156             if (rels != null) {
157                 Iterator i = rels.iterator();
158                 while (i.hasNext()) {
159                     MMObjectNode pnode = (MMObjectNode) i.next();
160                     toUsers.addAll(getAttachedUsers(pnode));
161                 }
162             }
163         }
164
165         return toUsers;
166
167     }
168
169     /**
170      * Get the email addresses of related users;
171      */

172     private static Set getAttachedUsers(MMObjectNode node) {
173         Set toUsers = new LinkedHashSet();
174         // try and find related users
175
if (MMBase.getMMBase().getBuilder(EmailBuilder.usersBuilder) != null) { // never mind if users builders does not exist
176
List rels = node.getRelatedNodes(EmailBuilder.usersBuilder);
177             if (rels != null) {
178                 Iterator i = rels.iterator();
179                 while (i.hasNext()) {
180                     MMObjectNode pnode = (MMObjectNode) i.next();
181                     toUsers.add(new NodeRecipient(pnode.getNumber(), pnode.getStringValue(EmailBuilder.usersEmailField)));
182                 }
183             }
184         }
185         return toUsers;
186     }
187
188
189
190     private static String JavaDoc getUrlExtern(String JavaDoc absoluteUrl,String JavaDoc params,String JavaDoc usernumber) {
191         try {
192             if (usernumber != null) {
193                 params += "&usernumber=" + usernumber;
194             }
195             String JavaDoc prefix = "?";
196             if (absoluteUrl.indexOf("?") != -1) {
197                 prefix = "&";
198             }
199             URL includeURL = new URL(absoluteUrl + prefix + params);
200             HttpURLConnection connection = (HttpURLConnection) includeURL.openConnection();
201             String JavaDoc contentType = connection.getContentType();
202
203             // Default encoding for http transport is iso-8859-1
204
String JavaDoc encoding = "ISO-8859-1";
205
206             // If a Content-Type header is present: get the encoding from there
207
if (contentType != null) {
208
209                StringTokenizer tokenizer = new StringTokenizer(contentType, "; ");
210                while (tokenizer.hasMoreTokens()) {
211                    String JavaDoc value = tokenizer.nextToken();
212                    if (value.startsWith("charset=")) {
213                        // charset overrides the defaults for the mimetypes
214
encoding = value.substring(8);
215                    } else if (value.equals("text/xml")) {
216                        // default encoding for text/xml
217
encoding = "utf-8";
218                    }
219                    // default encoding for text/html en text/plain is ISO-8859-1
220

221                }
222             }
223             BufferedReader in = new BufferedReader(new InputStreamReader (connection.getInputStream(), encoding));
224             int buffersize = 10240;
225             char[] buffer = new char[buffersize];
226             StringBuffer JavaDoc string = new StringBuffer JavaDoc();
227             int len;
228             while ((len = in.read(buffer, 0, buffersize)) != -1) {
229                 string.append(buffer, 0, len);
230             }
231             String JavaDoc result = string.toString();
232             return result;
233
234         } catch(Exception JavaDoc e) {
235             // this is weird needs to be checked
236
//e.printStackTrace();
237
}
238         return "";
239     }
240
241     private static String JavaDoc stripToOneLine(String JavaDoc input) {
242         StringBuffer JavaDoc result = new StringBuffer JavaDoc();
243         StringTokenizer tok = new StringTokenizer(input,",\n\r");
244         while (tok.hasMoreTokens()) {
245             result.append(tok.nextToken());
246         }
247         return result.toString();
248     }
249
250
251     /**
252     * convert 'html' to 'plain' text
253     * this removes the br and p tags and converts them
254     * to returns and dubble returns for email use.
255     */

256     private static String JavaDoc html2plain(String JavaDoc input) {
257         // define the result string
258
StringBuffer JavaDoc result = new StringBuffer JavaDoc();
259
260         // setup a tokenizer on all returns and linefeeds so
261
// we can remove them
262
StringTokenizer tok = new StringTokenizer(input,"\n\r");
263         while (tok.hasMoreTokens()) {
264             // add the content part stripped of its return/linefeed
265
result.append(tok.nextToken());
266         }
267
268         // now use the html br and p tags to insert
269
// the wanted returns
270
StringObject obj = new StringObject(result.toString());
271         obj.replace("<br/>","\n");
272         obj.replace("<br />","\n");
273         obj.replace("<BR/>","\n");
274         obj.replace("<BR />","\n");
275         obj.replace("<br>","\n");
276         obj.replace("<BR>","\n");
277         obj.replace("<p>","\n\n");
278         obj.replace("<p/>","\n\n");
279         obj.replace("<p />","\n\n");
280         obj.replace("<P>","\n\n");
281
282
283         // return the coverted body
284
return obj.toString();
285     }
286
287     /**
288      * Sends one email. The body is a bit parsed. It can be an URL, in which case the result will be
289      * fetched, and the body replaced. It can also contain with &lt;DONTMAIL&gt; (why not at least
290      * start??) in which case nothing happens. It can contain &lt;multipart (why not at least
291      * starts) in which case the body will be considered a representation of a 'multipart' message
292      * (in a kind of XML format).
293      *
294      * @return whether successful
295      */

296
297     private static boolean sendMail(MMObjectNode node, String JavaDoc from, NodeRecipient to, String JavaDoc body, Map headers) {
298         String JavaDoc obody = body;
299
300         // if the body starts with a url call that url
301
if (obody.indexOf("http://") == 0) {
302             body = getUrlExtern(obody, "", "" + to.nodeNumber);
303
304                 // convert html to plain text unless a the html tag is found
305
if (body.indexOf("<html>")==-1 && body.indexOf("<HTML>")==-1) {
306                 //body=html2plain(body);
307
}
308         }
309
310         String JavaDoc osubject = (String JavaDoc) headers.get("Subject");
311
312         // if the subject starts with a url call that url
313
if (osubject != null && osubject.indexOf("http://") == 0) {
314             String JavaDoc subject = getUrlExtern(osubject, "" , "" + to.nodeNumber);
315             subject = stripToOneLine(subject);
316             headers.put("Subject", subject);
317         }
318
319
320         // little trick if it seems valid html page set
321
// the headers for html mail
322
if (body.indexOf("<HTML>") != -1 && body.indexOf("</HTML>")!=-1) {
323             headers.put("Mime-Version", "1.0");
324             headers.put("Content-Type", "text/html; charset=\"ISO-8859-1\"");
325         }
326
327         // is the don't mail tag set ? this allows
328
// a generated body to signal it doesn't
329
// want to be mailed since for some reason
330
// invalid (for example there is no news for
331
// you
332
if (body.indexOf("<DONTMAIL>") == -1) {
333             // if the subject contains 'fakemail'
334
// perform all actions butt don't really
335
// mail. This is done for testing
336
String JavaDoc subject = (String JavaDoc) headers.get("Subject");
337             if (subject != null && subject.indexOf("fakemail")!=-1) {
338                 // add one to the sendmail counter
339
// refix numberofmailsend++;
340
log.info("Email -> fake send to " + to);
341                 return true;
342             } else {
343
344                 boolean mailResult;
345                 // get mail text to see if we have a mime msg
346
if (body.indexOf("<multipart") == -1) {
347                     mailResult = EmailBuilder.getSendMail().sendMail(from, to.email, body, headers);
348                 } else {
349                     MimeMultipart JavaDoc mmpart = MimeMessageGenerator.getMimeMultipart(body);
350                     mailResult = EmailBuilder.getSendMail().sendMultiPartMail(from, to.email, headers, mmpart);
351                 }
352
353
354                 if (! mailResult) {
355                     log.debug("Email -> mail failed");
356                     node.setValue("mailstatus", EmailBuilder.STATE_FAILED);
357                     // add one to the sendmail counter
358
// refix numberofmailsend++;
359
} else {
360                     // add one to the sendmail counter
361
// refix numberofmailsend++;
362
log.debug("Email -> mail send");
363                     node.setValue("mailstatus", EmailBuilder.STATE_DELIVERED);
364                 }
365                 return true;
366             }
367         } else {
368             log.debug("Don't mail tag found");
369             return true;
370         }
371     }
372     /**
373      * Simple structure representing an email-adres which is associated with a node-number.
374      */

375
376     static class NodeRecipient {
377         int nodeNumber;
378         String JavaDoc email;
379         NodeRecipient(int i, String JavaDoc s) {
380             nodeNumber = i;
381             email = s;
382         }
383         public boolean equals(Object JavaDoc o) {
384             if (o instanceof NodeRecipient) {
385                 NodeRecipient other = (NodeRecipient) o;
386                 return other.nodeNumber == nodeNumber && other.email.equals(email);
387             } else {
388                 return false;
389             }
390         }
391         public int hashCode() {
392             return email.hashCode() + nodeNumber;
393         }
394         public String JavaDoc toString() {
395             return email;
396         }
397     }
398
399 }
400
401
Popular Tags