interceptor concept introduced: entity adapter fields referenced in a
[mir.git] / source / mircoders / localizer / basic / MirBasicEmailArticleHandler.java
1 /*
2  * Copyright (C) 2001, 2002 The Mir-coders group
3  *
4  * This file is part of Mir.
5  *
6  * Mir is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Mir is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Mir; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * In addition, as a special exception, The Mir-coders gives permission to link
21  * the code of this program with  any library licensed under the Apache Software License,
22  * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
23  * (or with modified versions of the above that use the same license as the above),
24  * and distribute linked combinations including the two.  You must obey the
25  * GNU General Public License in all respects for all of the code used other than
26  * the above mentioned libraries.  If you modify this file, you may extend this
27  * exception to your version of the file, but you are not obligated to do so.
28  * If you do not wish to do so, delete this exception statement from your version.
29  */
30 package mircoders.localizer.basic;
31
32 import java.io.IOException;
33 import java.io.PrintWriter;
34 import java.io.StringWriter;
35 import java.util.ArrayList;
36 import java.util.Collections;
37 import java.util.HashMap;
38 import java.util.List;
39 import java.util.Locale;
40 import java.util.Map;
41
42 import mir.config.MirPropertiesConfiguration;
43 import mir.generator.Generator;
44 import mir.generator.GeneratorHelper;
45 import mir.log.LoggerWrapper;
46 import mir.session.Request;
47 import mir.session.Response;
48 import mir.session.Session;
49 import mir.session.SessionExc;
50 import mir.session.SessionFailure;
51 import mir.session.SessionHandler;
52 import mir.session.ValidationHelper;
53 import mir.session.HTTPAdapters.HTTPRequestAdapter;
54 import mir.util.StringRoutines;
55 import mircoders.entity.EntityContent;
56 import mircoders.global.CacheKey;
57 import mircoders.global.MirGlobal;
58 import mircoders.module.ModuleContent;
59
60 import org.apache.commons.net.smtp.SMTPClient;
61 import org.apache.commons.net.smtp.SMTPReply;
62
63
64 /**
65  *
66  * <p>Title: Tenative session handler for emailing postings </p>
67  * <p>Description: </p>
68  * <p>Copyright: Copyright (c) 2003</p>
69  * <p>Company: </p>
70  * @author john
71  * @version 1.0
72  */
73
74
75 public class MirBasicEmailArticleHandler implements SessionHandler {
76   protected LoggerWrapper logger;
77   protected MirPropertiesConfiguration configuration;
78
79   public MirBasicEmailArticleHandler() {
80     logger = new LoggerWrapper("Localizer.EmailArticle");
81     try {
82       configuration = MirPropertiesConfiguration.instance();
83     }
84     catch (Throwable t) {
85       logger.fatal("Cannot load configuration: " + t.toString());
86
87       throw new RuntimeException("Cannot load configuration: " + t.toString());
88     }
89   }
90
91   public void processRequest(Request aRequest, Session aSession, Response aResponse) throws SessionExc, SessionFailure {
92     if (aSession.getAttribute("initialRequest") == null) {
93       aSession.setAttribute("initialRequest", "no");
94       initialRequest(aRequest, aSession, aResponse);
95     }
96     else {
97       subsequentRequest(aRequest, aSession, aResponse);
98     }
99   }
100
101   protected void initialRequest(Request aRequest, Session aSession, Response aResponse) throws SessionExc, SessionFailure {
102     initializeSession(aRequest, aSession);
103     makeInitialResponse(aRequest, aSession, aResponse);
104   }
105
106   protected void initializeSession(Request aRequest, Session aSession) throws SessionExc, SessionFailure {
107     /* do nothing for now */
108
109   }
110
111   protected void makeInitialResponse(Request aRequest, Session aSession, Response aResponse) throws SessionExc, SessionFailure {
112     /* if you do not supply an aid to this handler, it should return an error page */
113     /* if you supply a non-functioning/non-published  aid to this handler, it should return an error page, but at a
114        later stage, because we don't check the db until we are potentially populating the cache*/
115     /* otherwise you get to address an article and add some comments */
116     String articleID = aRequest.getParameter("mail_aid");
117     if (articleID == null){
118       throw new SessionExc("makeInitialResponse: article id not set!");
119     }
120
121     EntityContent article;
122     try {
123       article = (EntityContent) (new ModuleContent()).getById(articleID);
124     }
125     catch (Throwable t) {
126       throw new SessionExc("Unknown article: " + articleID);
127     }
128
129     if (!MirGlobal.localizer().openPostings().allowArticlePublication(article)) {
130
131     }
132
133
134
135     aSession.setAttribute("email.aid",articleID);
136     aResponse.setResponseValue("errors", null);
137
138     String mail_language = configuration.getString("Mir.Login.DefaultLanguage", "en");
139     aResponse.setResponseValue("mail_language",mail_language);
140     aResponse.setResponseValue("mail_to","");
141     aResponse.setResponseValue("mail_from","");
142     aResponse.setResponseValue("mail_from_name","");
143     aResponse.setResponseValue("mail_comment","");
144
145     aResponse.setResponseGenerator(configuration.getString("Localizer.OpenSession.email.PrepareTemplate"));
146   }
147
148   protected boolean shouldSendMail(Request aRequest, Session aSession, Response aResponse,List aValidationErrors) throws SessionExc, SessionFailure{
149     if (validate(aRequest,aSession,aResponse,aValidationErrors)){
150       String to=aRequest.getParameter("mail_to");
151       if (to.indexOf('@') == -1
152           || to.indexOf('\n') != -1
153           || to.indexOf('\r') != -1
154           || to.indexOf(',') != -1) {
155         throw new SessionExc("Invalid to address"); // we might want to see this in a log, so it is not a validation error
156       }
157                         return true; // go for it
158     }
159                 return false; //validation failed, but not in a potentially abusive way
160
161   }
162
163
164
165
166
167   protected boolean validate(Request aRequest, Session aSession, Response aResponse,List aValidationErrors) throws SessionExc, SessionFailure{
168
169     if (ValidationHelper.testFieldEntered(aRequest, "mail_to", "validationerror.missing", aValidationErrors))
170       aResponse.setResponseValue("mail_to",aRequest.getParameter("mail_to"));
171     if (ValidationHelper.testFieldEntered(aRequest, "mail_from", "validationerror.missing", aValidationErrors))
172       aResponse.setResponseValue("mail_from",aRequest.getParameter("mail_from"));
173     if (ValidationHelper.testFieldEntered(aRequest, "mail_from_name", "validationerror.missing", aValidationErrors))
174       aResponse.setResponseValue("mail_from_name",aRequest.getParameter("mail_from_name"));
175     if (ValidationHelper.testFieldEntered(aRequest, "mail_language", "validationerror.missing", aValidationErrors))
176       aResponse.setResponseValue("mail_language",aRequest.getParameter("mail_language"));
177
178     return (aValidationErrors==null || aValidationErrors.size() == 0);
179   }
180
181   protected String getEmailText(String aid,String language) throws SessionExc{
182     String theText;
183     CacheKey theCacheKey=new CacheKey("email",aid+language);
184
185     if (MirGlobal.mruCache().hasObject(theCacheKey)){
186       logger.info("fetching email text for article "+aid+" from cache");
187       theText = (String) MirGlobal.mruCache().getObject(theCacheKey);
188     }
189     else {
190       try {
191         ModuleContent contentModule = new ModuleContent();
192         EntityContent contentEnt = (EntityContent) contentModule.getById(aid);
193
194         Map articleData = new HashMap();
195         articleData.put("article", MirGlobal.localizer().dataModel().adapterModel().makeEntityAdapter("content", contentEnt));
196         articleData.put("languagecode", language);
197         Map responseData = GeneratorHelper.makeBasicGenerationData(new Locale[] {new Locale(language,""),new Locale(configuration.getString("Mir.Admin.FallbackLanguage", "en"), "")},"bundles.open","bundles.open");
198         responseData.put("data",articleData);
199
200         String emailAnArticleTemplate = configuration.getString("Localizer.OpenSession.email.MailTemplate");
201
202         Generator generator =
203       MirGlobal.localizer().generators().makeOpenPostingGeneratorLibrary().
204           makeGenerator(emailAnArticleTemplate, null);
205
206         StringWriter theEmailStringWriter = new StringWriter();
207         PrintWriter theEmailPrintWriter = new PrintWriter(theEmailStringWriter);
208         generator.generate(theEmailPrintWriter, responseData, logger);
209
210         theEmailStringWriter.close();
211
212         theText = theEmailStringWriter.toString();
213         MirGlobal.mruCache().storeObject(theCacheKey, theText);
214       }
215       catch (Throwable e) {
216         throw new SessionExc("Couldn't get content for article " + aid + language + ": " + e.getMessage());
217       }
218     }
219
220     return theText;
221   }
222
223   protected String getExtraEmailHeaders(Request aRequest,String to,String from) throws SessionExc {
224
225     String headers = "To: " + to + "\nReply-To: "+ from+"\n";
226     if (configuration.getString("Localizer.OpenSession.email.includeSenderIP","no").equals("yes"))
227       headers= headers+"X-Originating-IP: "+ ((HTTPRequestAdapter)aRequest).getRequest().getRemoteAddr() + "\n";
228
229     return headers;
230   }
231
232   protected String interpolateComment(String emailText,String comment,String from_name,String language) throws SessionExc{
233     if (comment != null) {
234       String commentTextToInsert =
235           MirGlobal.getBundleFactory().getBundle("etc/bundles/open", new String[] { language }).
236             getValue("email.comment.intro" , Collections.singletonList(from_name)) + "\n";
237
238       try {
239         emailText = StringRoutines.performRegularExpressionReplacement(emailText, "!COMMENT!", commentTextToInsert);
240       }
241       catch (Throwable e) {
242         throw new SessionExc("Problem doing regular expression replacement :" + e.toString());
243       }
244     }
245     else {
246       try {
247         emailText = StringRoutines.performRegularExpressionReplacement(emailText, "!COMMENT!", "");
248       }
249       catch (Throwable e) {
250         throw new SessionExc("Problem doing regular expression replacement " + e.toString());
251       }
252     }
253     return emailText;
254   }
255
256   protected boolean doTheSMTP(String aMessage,String aTo,String aFrom) throws SessionExc{
257    SMTPClient client=new SMTPClient();
258    try {
259      int reply;
260      client.connect(configuration.getString("ServletModule.OpenIndy.SMTPServer"));
261      reply = client.getReplyCode();
262
263      if (!SMTPReply.isPositiveCompletion(reply)) {
264        client.disconnect();
265         throw new SessionExc("SMTP server refused connection.");
266      }
267      boolean trueIfItWorked = client.sendSimpleMessage(configuration.getString("ServletModule.OpenIndy.EmailIsFrom"), aTo, aMessage);
268      client.disconnect();
269      // mission accomplished??
270      if (! trueIfItWorked)
271        throw new SessionExc(client.getReplyString());
272                 return trueIfItWorked;
273    }
274    catch(IOException e) {
275       if(client.isConnected()) {
276         try {
277           client.disconnect();
278         } catch(IOException f) {
279           // do nothing
280         }
281       }
282       throw new SessionExc(e.getMessage());
283    }
284   }
285
286   protected boolean sendMail(Request aRequest,Session aSession,Response aResponse) throws SessionExc,SessionFailure {
287     String to=aRequest.getParameter("mail_to");
288     String from=aRequest.getParameter("mail_from");
289     String from_name=aRequest.getParameter("mail_from_name");
290     String language=aRequest.getParameter("mail_language");
291     String comment=aRequest.getParameter("mail_comment");
292
293     String theEmailText=getEmailText((String) aSession.getAttribute("email.aid"),language);
294     String headers=getExtraEmailHeaders(aRequest,to,from);
295     theEmailText=interpolateComment(theEmailText,comment,from_name,language);
296     String message=headers+theEmailText;  // the space between headers and content is in the template
297
298     return doTheSMTP(message,to,from);
299
300   }
301
302
303   protected void subsequentRequest(Request aRequest, Session aSession, Response aResponse) throws SessionExc, SessionFailure {
304     List validationErrors = new ArrayList();
305     if (shouldSendMail(aRequest,aSession,aResponse,validationErrors)){
306
307       sendMail(aRequest,aSession,aResponse);
308       aResponse.setResponseGenerator(configuration.getString("Localizer.OpenSession.email.DoneTemplate"));
309     }
310     else {
311       aResponse.setResponseValue("mail_comment",aRequest.getParameter("mail_comment"));  //everything else is required
312       aResponse.setResponseValue("errors",validationErrors);
313       aResponse.setResponseGenerator(configuration.getString("Localizer.OpenSession.email.PrepareTemplate"));
314     }
315
316   }
317
318       /*
319       String mail_language = aRequest.getParameter("mail_language");
320       if (mail_language == null)
321         mail_language = configuration.getString("Mir.Login.DefaultLanguage", "en");
322
323       aResponse.setResponseValue("mail_language",mail_language);
324       */
325
326
327
328
329 }