001: /*
002: Copyright (C) 2004 Know Gate S.L. All rights reserved.
003: C/Oņa, 107 1š2 28050 Madrid (Spain)
004:
005: Redistribution and use in source and binary forms, with or without
006: modification, are permitted provided that the following conditions
007: are met:
008:
009: 1. Redistributions of source code must retain the above copyright
010: notice, this list of conditions and the following disclaimer.
011:
012: 2. The end-user documentation included with the redistribution,
013: if any, must include the following acknowledgment:
014: "This product includes software parts from hipergate
015: (http://www.hipergate.org/)."
016: Alternately, this acknowledgment may appear in the software itself,
017: if and wherever such third-party acknowledgments normally appear.
018:
019: 3. The name hipergate must not be used to endorse or promote products
020: derived from this software without prior written permission.
021: Products derived from this software may not be called hipergate,
022: nor may hipergate appear in their name, without prior written
023: permission.
024:
025: This library is distributed in the hope that it will be useful,
026: but WITHOUT ANY WARRANTY; without even the implied warranty of
027: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
028:
029: You should have received a copy of hipergate License with this code;
030: if not, visit http://www.hipergate.org or mail to info@hipergate.org
031: */
032:
033: package com.knowgate.scheduler.jobs;
034:
035: import java.io.IOException;
036:
037: import java.sql.SQLException;
038: import java.sql.PreparedStatement;
039: import java.sql.ResultSet;
040:
041: import java.util.Properties;
042:
043: import javax.mail.Message;
044: import javax.mail.URLName;
045: import javax.mail.Address;
046: import javax.mail.Folder;
047: import javax.mail.MessagingException;
048: import javax.mail.SendFailedException;
049: import javax.mail.internet.InternetAddress;
050:
051: import com.sun.mail.smtp.SMTPMessage;
052:
053: import com.knowgate.debug.DebugFile;
054: import com.knowgate.acl.ACLUser;
055: import com.knowgate.jdc.JDCConnection;
056: import com.knowgate.misc.Gadgets;
057: import com.knowgate.dataobjs.DB;
058: import com.knowgate.dataxslt.FastStreamReplacer;
059: import com.knowgate.hipermail.DBStore;
060: import com.knowgate.hipermail.DBFolder;
061: import com.knowgate.hipermail.DBInetAddr;
062: import com.knowgate.hipermail.DBMimeMessage;
063: import com.knowgate.hipermail.MailAccount;
064: import com.knowgate.hipermail.SessionHandler;
065: import com.knowgate.scheduler.Job;
066: import com.knowgate.scheduler.Atom;
067:
068: /**
069: * <p>Send mime mail message to a recipients list</p>
070: * @author Sergio Montoro Ten
071: * @version 3.0
072: */
073:
074: public class MimeSender extends Job {
075:
076: private SessionHandler oHndlr;
077: private DBStore oStor;
078: private DBFolder oOutBox;
079: private String sBody;
080: private boolean bPersonalized;
081: private DBMimeMessage oDraft;
082: private Properties oHeaders;
083: private InternetAddress[] aFrom;
084: private InternetAddress[] aReply;
085:
086: public MimeSender() {
087: sBody = null;
088: oHndlr = null;
089: oStor = null;
090: oOutBox = null;
091: }
092:
093: // ---------------------------------------------------------------------------
094:
095: private String personalizeBody(Atom oAtm)
096: throws NullPointerException {
097: JDCConnection oConn = null;
098: PreparedStatement oStmt = null;
099: ResultSet oRSet = null;
100: String sPersonalizedBody;
101: String sNm, sSn, sSl, sCo, sEm;
102:
103: if (DebugFile.trace) {
104: DebugFile
105: .writeln("Begin MimeSender.personalizeBody([Atom])");
106: DebugFile.incIdent();
107: DebugFile.writeln("gu_job="
108: + oAtm.getStringNull(DB.gu_job, "null"));
109: if (oAtm.isNull(DB.pg_atom)) {
110: DebugFile.decIdent();
111: throw new NullPointerException(
112: "MimeSender.personalizeBody() no Atom set");
113: } else {
114: DebugFile.writeln("pg_atom="
115: + String.valueOf(oAtm.getInt(DB.pg_atom)));
116: }
117: }
118:
119: sEm = oAtm.getString(DB.tx_email);
120:
121: try {
122: oConn = getDataBaseBind().getConnection("MimeSender");
123: if (DebugFile.trace) {
124: DebugFile.writeln("Connection.prepareStatement(SELECT "
125: + DB.tx_name + "," + DB.tx_surname + ","
126: + DB.tx_salutation + "," + DB.nm_commercial
127: + " FROM " + DB.k_member_address + " WHERE "
128: + DB.gu_workarea + "='"
129: + getStringNull(DB.gu_workarea, "null")
130: + "' AND " + DB.tx_email + "='" + sEm + "')");
131: }
132: oStmt = oConn.prepareStatement("SELECT " + DB.tx_name + ","
133: + DB.tx_surname + "," + DB.tx_salutation + ","
134: + DB.nm_commercial + " FROM " + DB.k_member_address
135: + " WHERE " + DB.gu_workarea + "='"
136: + getString(DB.gu_workarea) + "' AND "
137: + DB.tx_email + "=?", ResultSet.TYPE_FORWARD_ONLY,
138: ResultSet.CONCUR_READ_ONLY);
139: oStmt.setString(1, sEm);
140: oRSet = oStmt.executeQuery();
141: if (oRSet.next()) {
142: sNm = oRSet.getString(1);
143: if (oRSet.wasNull())
144: sNm = "";
145: sSn = oRSet.getString(2);
146: if (oRSet.wasNull())
147: sSn = "";
148: sSl = oRSet.getString(3);
149: if (oRSet.wasNull())
150: sSl = "";
151: sCo = oRSet.getString(4);
152: if (oRSet.wasNull())
153: sCo = "";
154: } else {
155: sNm = sSn = sSl = sCo = "";
156: }
157: oRSet.close();
158: oRSet = null;
159: oStmt.close();
160: oStmt = null;
161: FastStreamReplacer oRplcr = new FastStreamReplacer(sBody
162: .length() + 256);
163: try {
164: sPersonalizedBody = oRplcr.replace(sBody,
165: FastStreamReplacer.createMap(new String[] {
166: "Data.Name", "Data.Surname",
167: "Data.Salutation",
168: "Data.Legal_Name,Address.EMail",
169: "Datos.Nombre", "Datos.Apellidos",
170: "Datos.Saludo", "Datos.Razon_Social",
171: "Direccion.EMail" }, new String[] {
172: sNm, sSn, sSl, sCo, sEm, sNm, sSn, sSl,
173: sCo, sEm }));
174: } catch (IOException ioe) {
175: if (DebugFile.trace)
176: DebugFile.writeln("IOException " + ioe.getMessage()
177: + " sending message "
178: + getParameter("message") + " to " + sEm);
179: log("IOException " + ioe.getMessage()
180: + " sending message " + getParameter("message")
181: + " to " + sEm);
182: sPersonalizedBody = sBody;
183: }
184: oConn.close("MimeSender");
185: oConn = null;
186: } catch (SQLException sqle) {
187: if (oRSet != null) {
188: try {
189: oRSet.close();
190: } catch (Exception ignore) {
191: }
192: }
193: if (oStmt != null) {
194: try {
195: oStmt.close();
196: } catch (Exception ignore) {
197: }
198: }
199: if (oConn != null) {
200: try {
201: oConn.close();
202: } catch (Exception ignore) {
203: }
204: }
205: if (DebugFile.trace)
206: DebugFile.writeln("SQLException " + sqle.getMessage()
207: + " sending message " + getParameter("message")
208: + " to " + sEm);
209: log("SQLException " + sqle.getMessage()
210: + " sending message " + getParameter("message")
211: + " to " + sEm);
212: sPersonalizedBody = sBody;
213: }
214:
215: if (DebugFile.trace) {
216: DebugFile.decIdent();
217: DebugFile.writeln("End MimeSender.personalizeBody()");
218: }
219: return sPersonalizedBody;
220: } // personalizeBody
221:
222: // ---------------------------------------------------------------------------
223:
224: private static int getDomainForWorkArea(JDCConnection oConn,
225: String sWrkA) throws SQLException {
226: int iDomainId = -1;
227:
228: if (DebugFile.trace) {
229: DebugFile
230: .writeln("Begin MimeSender.getDomainForWorkArea([JDCConnection],"
231: + sWrkA + ")");
232: DebugFile.incIdent();
233: DebugFile.writeln("Connection.prepareStatement(SELECT "
234: + DB.id_domain + " FROM " + DB.k_workareas
235: + " WHERE " + DB.gu_workarea + "='" + sWrkA + "')");
236: }
237:
238: PreparedStatement oStmt = oConn.prepareStatement("SELECT "
239: + DB.id_domain + " FROM " + DB.k_workareas + " WHERE "
240: + DB.gu_workarea + "=?", ResultSet.TYPE_FORWARD_ONLY,
241: ResultSet.CONCUR_READ_ONLY);
242: oStmt.setString(1, sWrkA);
243: ResultSet oRSet = oStmt.executeQuery();
244: if (oRSet.next())
245: iDomainId = oRSet.getInt(1);
246: oRSet.close();
247: oStmt.close();
248:
249: if (DebugFile.trace) {
250: DebugFile.decIdent();
251: DebugFile
252: .writeln("End MimeSender.getDomainForWorkArea() : "
253: + String.valueOf(iDomainId));
254: }
255: return iDomainId;
256: } // getDomainForWorkArea
257:
258: // ---------------------------------------------------------------------------
259:
260: public void init(Atom oAtm) throws SQLException,
261: MessagingException, NullPointerException {
262: if (DebugFile.trace) {
263: DebugFile.writeln("Begin MimeSender.init()");
264: DebugFile.incIdent();
265: }
266: // If mail is personalized (contains {#...} tags) a special parameter must has been previously set
267: bPersonalized = Boolean
268: .getBoolean(getParameter("personalized"));
269: if (DebugFile.trace)
270: DebugFile.writeln("personalized="
271: + getParameter("personalized"));
272: JDCConnection oConn = null;
273: PreparedStatement oStmt = null;
274: PreparedStatement oUpdt = null;
275: ResultSet oRSet = null;
276: ACLUser oUser = new ACLUser();
277: MailAccount oMacc = new MailAccount();
278: if (DebugFile.trace)
279: DebugFile.writeln("workarea="
280: + getStringNull(DB.gu_workarea, "null"));
281: String sWrkA = getString(DB.gu_workarea);
282: int iDomainId = -1;
283: try {
284: if (DebugFile.trace)
285: DebugFile.writeln("DBBind=" + getDataBaseBind());
286: // Get User, Account and Domain objects
287: oConn = getDataBaseBind().getConnection("MimeSender");
288: iDomainId = getDomainForWorkArea(oConn, sWrkA);
289: if (!oUser.load(oConn, new Object[] { getStringNull(
290: DB.gu_writer, null) }))
291: oUser = null;
292: if (!oMacc.load(oConn,
293: new Object[] { getParameter("account") }))
294: oMacc = null;
295: // If message is personalized then fill data for each mail address
296: if (bPersonalized)
297: resolveAtomsEMails(oConn);
298: oConn.close("MimeSender");
299: oConn = null;
300: } catch (SQLException sqle) {
301: if (DebugFile.trace)
302: DebugFile.writeln("MimeSender.process("
303: + getStringNull(DB.gu_job, "null") + ") "
304: + sqle.getClass().getName() + " "
305: + sqle.getMessage());
306: if (oConn != null) {
307: try {
308: oConn.close();
309: } catch (Exception ignore) {
310: }
311: }
312: throw sqle;
313: } catch (NullPointerException npe) {
314: if (DebugFile.trace)
315: DebugFile.writeln("MimeSender.process("
316: + getStringNull(DB.gu_job, "null") + ") "
317: + npe.getClass().getName());
318: if (oConn != null) {
319: try {
320: oConn.close();
321: } catch (Exception ignore) {
322: }
323: }
324: throw npe;
325: }
326: if (null == oUser) {
327: if (DebugFile.trace) {
328: DebugFile.decIdent();
329: DebugFile.writeln("End MimeSender.init("
330: + oAtm.getString(DB.gu_job) + ":"
331: + String.valueOf(oAtm.getInt(DB.pg_atom))
332: + ") : abnormal process termination");
333: }
334: throw new NullPointerException("User "
335: + getStringNull(DB.gu_writer, "null")
336: + " not found");
337: }
338: if (null == oMacc) {
339: if (DebugFile.trace) {
340: DebugFile.decIdent();
341: DebugFile.writeln("End MimeSender.init("
342: + oAtm.getString(DB.gu_job) + ":"
343: + String.valueOf(oAtm.getInt(DB.pg_atom))
344: + ") : abnormal process termination");
345: }
346: throw new NullPointerException("Mail Account "
347: + getParameter("account") + " not found");
348: }
349: try {
350: // Create mail session
351: if (DebugFile.trace)
352: DebugFile.writeln("new SessionHandler("
353: + oMacc.getStringNull(DB.gu_account, "null")
354: + ")");
355: oHndlr = new SessionHandler(oMacc);
356: // Retrieve profile name to be used from a Job parameter
357: // Profile is needed because it contains the path to /storage directory
358: // which is used for composing the path to outbox mbox file containing
359: // source of message to be sent
360: String sProfile = getParameter("profile");
361: String sMBoxDir = DBStore.MBoxDirectory(sProfile,
362: iDomainId, sWrkA);
363: oStor = new DBStore(oHndlr.getSession(), new URLName(
364: "jdbc://", sProfile, -1, sMBoxDir, oUser
365: .getString(DB.gu_user), oUser
366: .getString(DB.tx_pwd)));
367: oStor.connect(sProfile, oUser.getString(DB.gu_user), oUser
368: .getString(DB.tx_pwd));
369: oOutBox = (DBFolder) oStor.getFolder("outbox");
370: oOutBox.open(Folder.READ_WRITE);
371: String sMsgId = getParameter("message");
372: oDraft = oOutBox.getMessageByGuid(sMsgId);
373: if (null == oDraft)
374: throw new MessagingException(
375: "DBFolder.getMessageByGuid() Message " + sMsgId
376: + " not found");
377: oHeaders = oOutBox.getMessageHeaders(sMsgId);
378: if (null == oHeaders)
379: throw new MessagingException(
380: "DBFolder.getMessageHeaders() Message "
381: + sMsgId + " not found");
382: if (null == oHeaders.get(DB.nm_from))
383: aFrom = new InternetAddress[] { new InternetAddress(
384: oHeaders.getProperty(DB.tx_email_from)) };
385: else
386: aFrom = new InternetAddress[] { new InternetAddress(
387: oHeaders.getProperty(DB.tx_email_from),
388: oHeaders.getProperty(DB.nm_from)) };
389: if (null == oHeaders.get(DB.tx_reply_email))
390: aReply = aFrom;
391: else
392: aReply = new InternetAddress[] { new InternetAddress(
393: oHeaders.getProperty(DB.tx_reply_email)) };
394: sBody = oDraft.getText();
395: if (DebugFile.trace) {
396: if (null == sBody)
397: DebugFile.writeln("Message body: null");
398: else
399: DebugFile.writeln("Message body: "
400: + Gadgets.left(sBody.replace('\n', ' '),
401: 100));
402: }
403: } catch (Exception e) {
404: if (DebugFile.trace) {
405: DebugFile.decIdent();
406: DebugFile.writeln("End MimeSender.init("
407: + oAtm.getString(DB.gu_job) + ":"
408: + String.valueOf(oAtm.getInt(DB.pg_atom))
409: + ") : abnormal process termination");
410: }
411: if (null != oOutBox) {
412: try {
413: oOutBox.close(false);
414: oOutBox = null;
415: } catch (Exception ignore) {
416: }
417: }
418: if (null != oStor) {
419: try {
420: oStor.close();
421: oStor = null;
422: } catch (Exception ignore) {
423: }
424: }
425: if (null != oHndlr) {
426: try {
427: oHndlr.close();
428: oHndlr = null;
429: } catch (Exception ignore) {
430: }
431: }
432: throw new MessagingException(e.getMessage(), e);
433: }
434: if (DebugFile.trace) {
435: DebugFile.decIdent();
436: DebugFile.writeln("End MimeSender.init()");
437: }
438: } // init
439:
440: // ---------------------------------------------------------------------------
441:
442: public void free() {
443: if (DebugFile.trace) {
444: DebugFile.writeln("Begin MimeSender.free()");
445: DebugFile.incIdent();
446: DebugFile.writeln("gu_job="
447: + getStringNull(DB.gu_job, "null"));
448: }
449: oDraft = null;
450: if (null != oOutBox) {
451: try {
452: oOutBox.close(false);
453: oOutBox = null;
454: } catch (Exception ignore) {
455: }
456: }
457: if (null != oStor) {
458: try {
459: oStor.close();
460: oStor = null;
461: } catch (Exception ignore) {
462: }
463: }
464: if (null != oHndlr) {
465: try {
466: oHndlr.close();
467: oHndlr = null;
468: } catch (Exception ignore) {
469: }
470: }
471: if (DebugFile.trace) {
472: DebugFile.decIdent();
473: DebugFile.writeln("End MimeSender.free()");
474: }
475: } // free
476:
477: // ---------------------------------------------------------------------------
478:
479: public Object process(Atom oAtm) throws SQLException,
480: MessagingException, NullPointerException {
481:
482: if (DebugFile.trace) {
483: DebugFile.writeln("Begin MimeSender.process("
484: + oAtm.getString(DB.gu_job) + ":"
485: + String.valueOf(oAtm.getInt(DB.pg_atom)) + ")");
486: DebugFile.incIdent();
487: }
488:
489: // ***************************************************
490: // Create mail session if it does not previously exist
491:
492: if (oHndlr == null && iPendingAtoms > 0) {
493: init(oAtm);
494: }
495:
496: if (null == oDraft) {
497: if (DebugFile.trace) {
498: DebugFile.decIdent();
499: DebugFile.writeln("End MimeSender.process("
500: + oAtm.getString(DB.gu_job) + ":"
501: + String.valueOf(oAtm.getInt(DB.pg_atom))
502: + ") : abnormal process termination");
503: }
504: throw new NullPointerException("Draft message "
505: + getParameter("message") + " not found");
506: }
507:
508: // ***********************************
509: // Once session is created set message
510:
511: SMTPMessage oSentMsg;
512:
513: try {
514: // Personalize mail if needed by replacing {#...} tags by values taken from Atom fields
515: if (bPersonalized)
516: oSentMsg = oDraft.composeFinalMessage(oHndlr
517: .getSession(), oDraft.getSubject(),
518: personalizeBody(oAtm), getParameter("id"), oAtm
519: .getStringNull(DB.id_format, "text"));
520: else
521: oSentMsg = oDraft.composeFinalMessage(oHndlr
522: .getSession(), oDraft.getSubject(), sBody,
523: getParameter("id"), oAtm.getStringNull(
524: DB.id_format, "text"));
525:
526: // If there is no mail address at the atom then send message to recipients
527: // that are already set into message object itself.
528: // If there is a mail address at the atom then send message to that recipient
529: if (!oAtm.isNull(DB.tx_email)) {
530: if (DebugFile.trace)
531: DebugFile.writeln("tx_email="
532: + oAtm.getString(DB.tx_email));
533: InternetAddress oRec = DBInetAddr.parseAddress(oAtm
534: .getString(DB.tx_email));
535: String sRecType = oAtm.getStringNull(DB.tp_recipient,
536: "to");
537: if (sRecType.equalsIgnoreCase("to"))
538: oSentMsg.setRecipient(Message.RecipientType.TO,
539: oRec);
540: else if (sRecType.equalsIgnoreCase("cc"))
541: oSentMsg.setRecipient(Message.RecipientType.CC,
542: oRec);
543: else
544: oSentMsg.setRecipient(Message.RecipientType.BCC,
545: oRec);
546: } else {
547: if (DebugFile.trace)
548: DebugFile.writeln("tx_email is null");
549: }
550:
551: // Set From and Reply-To addresses
552: oSentMsg.addFrom(aFrom);
553: oSentMsg.setReplyTo(aReply);
554:
555: // Send message here
556: oHndlr.sendMessage(oSentMsg);
557:
558: } catch (Exception e) {
559: if (DebugFile.trace) {
560: DebugFile.writeStackTrace(e);
561: DebugFile.write("\n");
562: DebugFile.decIdent();
563: DebugFile.writeln("End MimeSender.process("
564: + oAtm.getString(DB.gu_job) + ":"
565: + String.valueOf(oAtm.getInt(DB.pg_atom))
566: + ") : abnormal process termination");
567: }
568: throw new MessagingException(e.getMessage(), e);
569: } finally {
570: // Decrement de count of atoms pending of processing at this job
571: if (0 == --iPendingAtoms) {
572: free();
573: } // fi (iPendingAtoms==0)
574: }
575:
576: if (DebugFile.trace) {
577: DebugFile.writeln("End MimeSender.process("
578: + oAtm.getString(DB.gu_job) + ":"
579: + String.valueOf(oAtm.getInt(DB.pg_atom)) + ")");
580: DebugFile.decIdent();
581: }
582:
583: return null;
584: } // process
585:
586: // ----------------------------------------------------------------------------
587:
588: public static MimeSender newInstance(JDCConnection oConn,
589: String sProfile, String sIdWrkA, String sGuMsg,
590: String sIdMsg, String sGuUser, String sGuAccount,
591: boolean bIsPersonalizedMail, String sTxTitle)
592: throws SQLException {
593: MimeSender oJob = new MimeSender();
594:
595: if (DebugFile.trace) {
596: DebugFile
597: .writeln("Begin MimeSender.newInstance(JDCConnection, "
598: + sProfile
599: + ", "
600: + sIdWrkA
601: + ", "
602: + sGuMsg
603: + ", "
604: + sIdMsg
605: + ", "
606: + sGuUser
607: + ", "
608: + sGuAccount
609: + ", "
610: + String.valueOf(bIsPersonalizedMail)
611: + ", " + sTxTitle + ")");
612: DebugFile.incIdent();
613: }
614:
615: oJob.put(DB.gu_workarea, sIdWrkA);
616: oJob.put(DB.gu_writer, sGuUser);
617: oJob.put(DB.id_command, "SEND");
618: oJob.put(DB.tl_job, Gadgets.left(sTxTitle, 100));
619: oJob.put(DB.tx_parameters, "profile:" + sProfile + ",id:"
620: + sIdMsg + ",message:" + sGuMsg + ",account:"
621: + sGuAccount + ",personalized:"
622: + String.valueOf(bIsPersonalizedMail));
623: oJob.store(oConn);
624:
625: if (DebugFile.trace) {
626: DebugFile.writeln("End MimeSender.newInstance() "
627: + oJob.getStringNull(DB.gu_job, "null"));
628: DebugFile.decIdent();
629: }
630:
631: return oJob;
632: }
633:
634: } // MimeSender
|