support for CAPTCHAs
[mir.git] / source / mircoders / servlet / ServletModuleOpenIndy.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.f
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
31 package mircoders.servlet;
32
33 import mir.bundle.Bundle;
34 import mir.generator.Generator;
35 import mir.misc.StringUtil;
36 import mir.module.ModuleExc;
37 import mir.servlet.ServletModule;
38 import mir.servlet.ServletModuleExc;
39 import mir.servlet.ServletModuleFailure;
40 import mir.servlet.ServletModuleUserExc;
41 import mir.session.*;
42 import mir.util.FileRoutines;
43 import mir.util.HTTPParsedRequest;
44 import mir.util.HTTPRequestParser;
45 import mir.util.StringRoutines;
46 import mircoders.entity.EntityContent;
47 import mircoders.global.CacheKey;
48 import mircoders.global.MirGlobal;
49 import mircoders.localizer.MirLocalizerExc;
50 import mircoders.localizer.MirOpenPostingLocalizer;
51 import mircoders.module.ModuleContent;
52 import mircoders.pdf.PDFGenerator;
53 import mircoders.search.*;
54 import mircoders.storage.DatabaseTopics;
55 import org.apache.commons.net.smtp.SMTPClient;
56 import org.apache.commons.net.smtp.SMTPReply;
57 import org.apache.lucene.analysis.standard.StandardAnalyzer;
58 import org.apache.lucene.document.Document;
59 import org.apache.lucene.queryParser.QueryParser;
60 import org.apache.lucene.search.Hits;
61 import org.apache.lucene.search.IndexSearcher;
62 import org.apache.lucene.search.Query;
63 import org.apache.lucene.search.Searcher;
64 import org.apache.lucene.store.FSDirectory;
65 import org.apache.oro.text.regex.*;
66
67 import javax.servlet.http.HttpServletRequest;
68 import javax.servlet.http.HttpServletResponse;
69 import javax.servlet.http.HttpSession;
70 import javax.servlet.ServletOutputStream;
71 import java.io.*;
72 import java.util.*;
73
74 import com.sun.image.codec.jpeg.JPEGCodec;
75 import com.sun.image.codec.jpeg.JPEGImageEncoder;
76
77 /*
78  */
79
80 public class ServletModuleOpenIndy extends ServletModule {
81   private String        searchResultsTemplate;
82   private String        prepareMailTemplate,sentMailTemplate,emailAnArticleTemplate;
83   private ModuleContent contentModule;
84
85   public ServletModuleOpenIndy() {
86     searchResultsTemplate = getConfiguration().getString("ServletModule.OpenIndy.SearchResultsTemplate");
87     prepareMailTemplate = getConfiguration().getString("ServletModule.OpenIndy.PrepareMailTemplate");
88     emailAnArticleTemplate = getConfiguration().getString("ServletModule.OpenIndy.MailableArticleTemplate");
89     sentMailTemplate = getConfiguration().getString("ServletModule.OpenIndy.SentMailTemplate");
90
91     contentModule = new ModuleContent();
92   }
93
94   /**
95    * Perform the default open posting action
96    */
97   public void defaultAction(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure {
98     opensession(aRequest, aResponse);
99   }
100
101   /**
102    * Method to return an out of service notice when open postings are disabled
103    */
104   public void openPostingDisabled(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure {
105     deliver(aRequest, aResponse, null, null, getConfiguration().getString("ServletModule.OpenIndy.PostingDisabledTemplate"));
106   }
107
108   /**
109    * Due to a serious shortcoming of Tomcat 3.3, an extra sessionid parameter is
110    *   generated into open session urls. Tomcat 3.3 makes it impossible to
111    *   distinguish between sessions that are identified using a url and those
112    *   that are identified using cookies: if both a sessionid cookie and a sessionid
113    *   url are available, tomcat 3.3 pretends the url wasn't there...
114    */
115   private static final String SESSION_REQUEST_KEY="sessionid";
116
117   /**
118    * Determines the Locale to be used for the current session
119    */
120   protected Locale getResponseLocale(HttpSession aSession, HttpServletRequest aRequest) {
121     String requestLanguage = aRequest.getParameter("language");
122     String sessionLanguage = (String) aSession.getAttribute("language");
123     String acceptLanguage = aRequest.getLocale().getLanguage();
124     String defaultLanguage = getConfiguration().getString("Mir.Login.DefaultLanguage", "en");
125
126     String language = requestLanguage;
127
128     if (language==null)
129       language = sessionLanguage;
130
131     if (language==null)
132       language = acceptLanguage;
133
134     if (language==null)
135       language = defaultLanguage;
136
137     aSession.setAttribute("language", language);
138
139     return new Locale(language, "");
140   }
141
142   /**
143    * Dispatch method for open sessions: a flexible extensible and customizable way
144    *   for open access. Can be used for postings, but also for lots of other stuff.
145    *
146    * @param aRequest
147    * @param aResponse
148    * @throws ServletModuleExc
149    * @throws ServletModuleUserExc
150    * @throws ServletModuleFailure
151    */
152   public void opensession(HttpServletRequest aRequest, HttpServletResponse aResponse)
153       throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure {
154
155     try {
156       Request request =
157           new HTTPAdapters.HTTPParsedRequestAdapter(new HTTPParsedRequest(aRequest,
158               getConfiguration().getString("Mir.DefaultEncoding"),
159               getConfiguration().getInt("MaxMediaUploadSize")*1024,
160               getConfiguration().getString("TempDir")));
161
162       if (aRequest.isRequestedSessionIdValid() && !aRequest.isRequestedSessionIdFromURL() &&
163           !aRequest.getRequestedSessionId().equals(aRequest.getParameter(SESSION_REQUEST_KEY))) {
164         aRequest.getSession().invalidate();
165       }
166
167       Session session = new HTTPAdapters.HTTPSessionAdapter(aRequest.getSession());
168
169       SimpleResponse response = new SimpleResponse(
170           ServletHelper.makeGenerationData(aRequest, aResponse,
171               new Locale[] {
172                   getResponseLocale(aRequest.getSession(), aRequest),
173                   getFallbackLocale(aRequest)
174               },
175              "etc/bundles/open"));
176
177       response.setResponseValue("actionURL", aResponse.encodeURL(MirGlobal.config().getString("RootUri") + "/servlet/OpenMir")+"?"+SESSION_REQUEST_KEY+"="+aRequest.getSession().getId());
178
179       SessionHandler handler = MirGlobal.localizer().openPostings().getOpenSessionHandler(request, session);
180
181       handler.processRequest(request, session, response);
182       ServletHelper.generateOpenPostingResponse(aResponse.getWriter(), response.getResponseValues(), response.getResponseGenerator());
183     }
184     catch (Throwable t) {
185       getLogger().error(t.toString(), t);
186
187       throw new ServletModuleFailure(t);
188     }
189   }
190
191   public void captcha(HttpServletRequest aRequest, HttpServletResponse aResponse)
192           throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure {
193     try {
194       MirOpenPostingLocalizer.Captcha captcha = MirGlobal.localizer().openPostings().generateCaptcha(aRequest.getSession().getId());
195       aRequest.getSession().setAttribute("captcha", captcha);
196
197        // the output stream to render the captcha image as jpeg into
198       ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
199       JPEGImageEncoder jpegEncoder = JPEGCodec.createJPEGEncoder(jpegOutputStream);
200       jpegEncoder.encode(captcha.getChallenge());
201
202       aResponse.setHeader("Cache-Control", "no-store");
203       aResponse.setHeader("Pragma", "no-cache");
204       aResponse.setDateHeader("Expires", 0);
205       aResponse.setContentType("image/jpeg");
206
207       ServletOutputStream responseOutputStream = aResponse.getOutputStream();
208
209       responseOutputStream.write(jpegOutputStream.toByteArray());
210       responseOutputStream.flush();
211       responseOutputStream.close();
212     }
213     catch (IOException e) {
214       throw new ServletModuleFailure(e);
215     }
216   }
217
218   /**
219    * Method for preparing and sending a content as an email message
220    */
221   public void mail(HttpServletRequest aRequest, HttpServletResponse aResponse)
222       throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure {
223     String aid = aRequest.getParameter("mail_aid");
224     if (aid == null){
225       throw new ServletModuleExc("An article id must be specified in requests " +
226           "to email an article.  Something therefore went badly wrong....");
227     }
228
229     String to = aRequest.getParameter("mail_to");
230     String from = aRequest.getParameter("mail_from");
231     String from_name = aRequest.getParameter("mail_from_name");
232     String from_ip = aRequest.getRemoteAddr();
233     String comment = aRequest.getParameter("mail_comment");
234     String mail_language = aRequest.getParameter("mail_language");
235
236     Map mergeData = new HashMap();
237     mergeData.put("mail_to",to);
238     mergeData.put("mail_from",from);
239     mergeData.put("mail_from_name",from_name);
240     mergeData.put("mail_comment",comment);
241     mergeData.put("mail_aid",aid);
242     mergeData.put("mail_language",mail_language);
243
244
245     if (to == null || from == null || from_name == null|| to.equals("") || from.equals("") || from_name.equals("") || mail_language == null || mail_language.equals("")){
246       deliver(aRequest, aResponse, mergeData, null, prepareMailTemplate);
247     }
248     else {
249       //run checks on to and from and mail_language to make sure no monkey business occurring
250       if (mail_language.indexOf('.') != -1 || mail_language.indexOf('/') != -1 ) {
251         throw new ServletModuleExc("Invalid language");
252       }
253       if (to.indexOf('\n') != -1
254           || to.indexOf('\r') != -1
255           || to.indexOf(',') != -1) {
256         throw new ServletModuleUserExc("email.error.invalidtoaddress", new String[] {to});
257       }
258       if (from.indexOf('\n') != -1 || from.indexOf('\r') != -1 || from.indexOf(',') != -1 ) {
259         throw new ServletModuleUserExc("email.error.invalidfromaddress", new String[] {from});
260       }
261
262       CacheKey theCacheKey=new CacheKey("email",aid+mail_language);
263       String theEmailText;
264
265       EntityContent article;
266       try {
267         article = (EntityContent) contentModule.getById(aid);
268       }
269       catch (ModuleExc e) {
270         throw new ServletModuleExc("Couldn't retrieve article " + aid);
271       }
272
273       if (!MirGlobal.localizer().openPostings().allowArticlePublication(article)) {
274         throw new ServletModuleExc("Illegal article");
275       }
276
277       if (MirGlobal.mruCache().hasObject(theCacheKey)){
278         getLogger().info("fetching email text for article "+aid+" from cache");
279         theEmailText = (String) MirGlobal.mruCache().getObject(theCacheKey);
280       }
281       else {
282         StringWriter theEMailTextWriter = new StringWriter();
283         PrintWriter dest = new PrintWriter(theEMailTextWriter);
284         try {
285           Map articleData = new HashMap();
286           try {
287             articleData.put("article",
288                 MirGlobal.localizer().dataModel().adapterModel().makeEntityAdapter("content", article));
289           }
290           catch (MirLocalizerExc e) {
291             throw new ServletModuleExc("Can't retrieve article " + aid, e);
292           }
293           articleData.put("languagecode", mail_language);
294           deliver(dest, aRequest, aResponse, articleData, null, emailAnArticleTemplate, mail_language);
295         }
296         finally {
297           dest.close();
298         }
299         theEmailText = theEMailTextWriter.toString();
300         MirGlobal.mruCache().storeObject(theCacheKey, theEmailText);
301       }
302
303       String content = theEmailText;
304
305       // add some headers
306       content = "To: " + to + "\nReply-To: "+ from + "\nX-Originating-IP: "+ from_ip + "\n" + content;
307       // put in the comment where it should go
308       if (comment != null) {
309         String commentTextToInsert = "\n\nAttached comment from " + from_name + ":\n" + comment;
310         try {
311           content=StringRoutines.performRegularExpressionReplacement(content,"!COMMENT!",commentTextToInsert);
312         }
313         catch (Throwable e){
314           throw new ServletModuleFailure("Problem doing regular expression replacement " + e.toString(), e);
315         }
316       }
317       else{
318         try {
319           content=StringRoutines.performRegularExpressionReplacement(content,"!COMMENT!","");
320         }
321         catch (Throwable e){
322           throw new ServletModuleFailure("Problem doing regular expression replacement " + e.toString(), e);
323         }
324       }
325
326       SMTPClient client=new SMTPClient();
327       try {
328         int reply;
329         client.connect(getConfiguration().getString("ServletModule.OpenIndy.SMTPServer"));
330
331         reply = client.getReplyCode();
332
333         if (!SMTPReply.isPositiveCompletion(reply)) {
334           client.disconnect();
335           throw new ServletModuleExc("SMTP server refused connection.");
336         }
337
338         client.sendSimpleMessage(getConfiguration().getString("ServletModule.OpenIndy.EmailIsFrom"), to, content);
339
340         client.disconnect();
341         //mission accomplished
342         deliver(aRequest, aResponse, mergeData, null, sentMailTemplate);
343       }
344       catch(IOException e) {
345         if(client.isConnected()) {
346           try {
347             client.disconnect();
348           } catch(IOException f) {
349             // do nothing
350           }
351         }
352         throw new ServletModuleFailure(e);
353       }
354     }
355   }
356
357
358
359   /**
360    * Method for querying a lucene index
361    *
362    * @param req
363    * @param res
364    * @throws ServletModuleExc
365    * @throws ServletModuleUserExc
366    * @throws ServletModuleFailure
367    */
368
369   public void search(HttpServletRequest req, HttpServletResponse res) throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure {
370     try {
371       final String[] search_variables = {
372           "search_content", "search_boolean", "search_creator",
373           "search_topic", "search_hasImages", "search_hasAudio", "search_hasVideo", "search_sort",
374           "search_submit", "search_back", "search_forward"};
375       HTTPRequestParser requestParser = new HTTPRequestParser(req);
376
377       int increment = 10;
378
379       HttpSession session = req.getSession(false);
380
381       String queryString = "";
382
383       Map mergeData = new HashMap();
384
385       KeywordSearchTerm dateTerm = new KeywordSearchTerm("date_formatted", "search_date", "webdb_create_formatted", "webdb_create_formatted", "webdb_create_formatted");
386       UnIndexedSearchTerm whereTerm = new UnIndexedSearchTerm("", "", "", "where", "where");
387       TextSearchTerm creatorTerm = new TextSearchTerm("creator", "search_creator", "creator", "creator", "creator");
388       TextSearchTerm titleTerm = new TextSearchTerm("title", "search_content", "title", "title", "title");
389       TextSearchTerm descriptionTerm = new TextSearchTerm("description", "search_content", "description", "description", "description");
390       ContentSearchTerm contentTerm = new ContentSearchTerm("content_data", "search_content", "content", "", "");
391       TopicSearchTerm topicTerm = new TopicSearchTerm();
392       TopicMatrixSearchTerm topicMatrixTerm = new TopicMatrixSearchTerm();
393       ImagesSearchTerm imagesTerm = new ImagesSearchTerm();
394       AudioSearchTerm audioTerm = new AudioSearchTerm();
395       VideoSearchTerm videoTerm = new VideoSearchTerm();
396
397       //make the query available to subsequent iterations
398
399       Iterator j = Arrays.asList(search_variables).iterator();
400       while (j.hasNext()) {
401         String variable = (String) j.next();
402
403         mergeData.put(variable, requestParser.getParameter(variable));
404       }
405
406       try {
407         mergeData.put("topics", DatabaseTopics.getInstance().getPopupData());
408       }
409       catch (Throwable e) {
410         getLogger().debug("Can't get topics: " + e.toString());
411       }
412
413       String searchBackValue = req.getParameter("search_back");
414       String searchForwardValue = req.getParameter("search_forward");
415
416       if (searchBackValue != null) {
417         int totalHits = ( (Integer) session.getAttribute("numberOfHits")).intValue();
418         int newPosition = ( (Integer) session.getAttribute("positionInResults")).intValue() - increment;
419         if (newPosition < 0)
420           newPosition = 0;
421         if (newPosition >= totalHits)
422           newPosition = totalHits - 1;
423         session.setAttribute("positionInResults", new Integer(newPosition));
424       }
425       else {
426         if (searchForwardValue != null) {
427           int totalHits = ( (Integer) session.getAttribute("numberOfHits")).intValue();
428           int newPosition = ( (Integer) session.getAttribute("positionInResults")).intValue() + increment;
429           if (newPosition < 0)
430             newPosition = 0;
431           if (newPosition >= totalHits)
432             newPosition = totalHits - 1;
433
434           session.setAttribute("positionInResults", new Integer(newPosition));
435         }
436         else {
437           File indexFile = FileRoutines.getAbsoluteOrRelativeFile(getConfiguration().getHome(), getConfiguration().getString("IndexPath"));
438
439           String creatorFragment = creatorTerm.makeTerm(req);
440           if (creatorFragment != null) {
441             queryString = queryString + " +" + creatorFragment;
442           }
443
444           // search title, description, and content for something
445           // the contentTerm uses param "search_boolean" to combine its terms
446           String contentFragment = contentTerm.makeTerm(req);
447           if (contentFragment != null) {
448             getLogger().debug("contentFragment: " + contentFragment);
449             queryString = queryString + " +" + contentFragment;
450           }
451
452           String topicFragment = topicTerm.makeTerm(req);
453           if (topicFragment != null) {
454             queryString = queryString + " +" + topicFragment;
455           }
456
457           String topicMatrixFragment = topicMatrixTerm.makeTerm(req);
458           if (topicMatrixFragment != null) {
459             queryString = queryString + " +" + topicMatrixFragment;
460           }
461
462           String imagesFragment = imagesTerm.makeTerm(req);
463           if (imagesFragment != null) {
464             queryString = queryString + " +" + imagesFragment;
465           }
466
467           String audioFragment = audioTerm.makeTerm(req);
468           if (audioFragment != null) {
469             queryString = queryString + " +" + audioFragment;
470           }
471
472           String videoFragment = videoTerm.makeTerm(req);
473           if (videoFragment != null) {
474             queryString = queryString + " +" + videoFragment;
475           }
476
477           if (queryString == null || queryString.length()==0) {
478             queryString = "";
479           }
480           else {
481             try {
482               Searcher searcher;
483
484               try {
485                 searcher = new IndexSearcher(FSDirectory.getDirectory(indexFile,false));
486               }
487               catch (IOException e) {
488                 getLogger().debug("Can't open indexPath: " + indexFile.getAbsolutePath());
489                 throw new ServletModuleExc("Problem with Search Index! : " + e.toString());
490               }
491
492               Query query;
493               try {
494                 query = QueryParser.parse(queryString, "content", new StandardAnalyzer());
495               }
496               catch (Exception e) {
497                 searcher.close();
498                 getLogger().debug("Query don't parse: " + queryString);
499                 throw new ServletModuleExc("Problem with Query String! (was '" + queryString + "')");
500               }
501
502               Hits hits = null;
503               try {
504                 hits = searcher.search(query);
505               }
506               catch (IOException e) {
507                 searcher.close();
508                 getLogger().debug("Can't get hits: " + e.toString());
509                 throw new ServletModuleExc("Problem getting hits!");
510               }
511
512               int start = 0;
513               int end = hits.length();
514
515               String sortBy = req.getParameter("search_sort");
516               if (sortBy == null || sortBy.equals("")) {
517                 throw new ServletModuleExc("Please let me sort by something!(missing search_sort)");
518               }
519
520               // here is where the documents will go for database across sessions
521               ArrayList theDocumentsSorted = new ArrayList();
522
523               if (sortBy.equals("score")) {
524                 for (int i = start; i < end; i++) {
525                   theDocumentsSorted.add(hits.doc(i));
526                 }
527               }
528               else {
529                 // then we'll sort by date!
530                 Map dateToPosition = new HashMap(end, 1.0F); //we know how big it will be
531                 for (int i = start; i < end; i++) {
532                   String creationDate = (hits.doc(i)).get("creationDate");
533                   // do a little dance in case two contents created at the same second!
534                   if (dateToPosition.containsKey(creationDate)) {
535                     ( (ArrayList) (dateToPosition.get(creationDate))).add(new Integer(i));
536                   }
537                   else {
538                     ArrayList thePositions = new ArrayList();
539                     thePositions.add(new Integer(i));
540                     dateToPosition.put(creationDate, thePositions);
541                   }
542                 }
543                 Set keys = dateToPosition.keySet();
544                 ArrayList keyList = new ArrayList(keys);
545                 Collections.sort(keyList);
546                 if (sortBy.equals("date_desc")) {
547                   Collections.reverse(keyList);
548                 }
549                 else {
550                   if (!sortBy.equals("date_asc")) {
551                     throw new ServletModuleExc("don't know how to sort by: " + sortBy);
552                   }
553                 }
554                 ListIterator keyTraverser = keyList.listIterator();
555                 while (keyTraverser.hasNext()) {
556                   ArrayList positions = (ArrayList) dateToPosition.get( (keyTraverser.next()));
557                   ListIterator positionsTraverser = positions.listIterator();
558                   while (positionsTraverser.hasNext()) {
559                     theDocumentsSorted.add(hits.doc( ( (Integer) (positionsTraverser.next())).intValue()));
560                   }
561                 }
562               }
563
564               try {
565                 searcher.close();
566               }
567               catch (IOException e) {
568                 getLogger().debug("Can't close searcher: " + e.toString());
569                 throw new ServletModuleFailure("Problem closing searcher(normal):" + e.getMessage(), e);
570               }
571
572               session.removeAttribute("numberOfHits");
573               session.removeAttribute("theDocumentsSorted");
574               session.removeAttribute("positionInResults");
575
576               session.setAttribute("numberOfHits", new Integer(end));
577               session.setAttribute("theDocumentsSorted", theDocumentsSorted);
578               session.setAttribute("positionInResults", new Integer(0));
579
580             }
581             catch (IOException e) {
582               getLogger().debug("Can't close searcher: " + e.toString());
583               throw new ServletModuleFailure("Problem closing searcher: " + e.getMessage(), e);
584             }
585           }
586         }
587       }
588
589       try {
590         ArrayList theDocs = (ArrayList) session.getAttribute("theDocumentsSorted");
591         if (theDocs != null) {
592
593           mergeData.put("numberOfHits", (session.getAttribute("numberOfHits")).toString());
594           List theHits = new ArrayList();
595           int pIR = ( (Integer) session.getAttribute("positionInResults")).intValue();
596           int terminus;
597           int numHits = ( (Integer) session.getAttribute("numberOfHits")).intValue();
598
599           if (! (pIR + increment >= numHits)) {
600             mergeData.put("hasNext", "y");
601           }
602           else {
603             mergeData.put("hasNext", null);
604           }
605           if (pIR > 0) {
606             mergeData.put("hasPrevious", "y");
607           }
608           else {
609             mergeData.put("hasPrevious", null);
610           }
611
612           if ( (pIR + increment) > numHits) {
613             terminus = numHits;
614           }
615           else {
616             terminus = pIR + increment;
617           }
618           for (int i = pIR; i < terminus; i++) {
619             Map h = new HashMap();
620             Document theHit = (Document) theDocs.get(i);
621             whereTerm.returnMeta(h, theHit);
622             creatorTerm.returnMeta(h, theHit);
623             titleTerm.returnMeta(h, theHit);
624             descriptionTerm.returnMeta(h, theHit);
625             dateTerm.returnMeta(h, theHit);
626             imagesTerm.returnMeta(h, theHit);
627             audioTerm.returnMeta(h, theHit);
628             videoTerm.returnMeta(h, theHit);
629             theHits.add(h);
630           }
631           mergeData.put("hits", theHits);
632         }
633       }
634       catch (Throwable e) {
635         getLogger().error("Can't iterate over hits: " + e.toString());
636
637         throw new ServletModuleFailure("Problem getting hits: " + e.getMessage(), e);
638       }
639
640       mergeData.put("queryString", queryString);
641
642       deliver(req, res, mergeData, null, searchResultsTemplate);
643     }
644     catch (NullPointerException n) {
645       throw new ServletModuleFailure("Null Pointer: " + n.toString(), n);
646     }
647   }
648
649   /*
650    * Method for dynamically generating a pdf using iText
651    */
652
653   public void getpdf(HttpServletRequest aRequest, HttpServletResponse aResponse)
654       throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure {
655
656     long starttime = System.currentTimeMillis();
657
658     String ID_REQUEST_PARAM = "id";
659     int maxArticlesInNewsleter = 15; // it is nice not to be dos'ed
660     try {
661       String idParameterValue = aRequest.getParameter(ID_REQUEST_PARAM);
662       if (idParameterValue != null) {
663         Pattern idPattern = new Perl5Compiler().compile("[0-9]+");
664         PatternMatcher matcher = new Perl5Matcher();
665         PatternMatcherInput input = new PatternMatcherInput(idParameterValue);
666         List ids = new ArrayList();
667         while (matcher.contains(input, idPattern)) {
668           ids.add(matcher.getMatch().toString());
669         }
670
671         String cacheType = "pdf";
672
673         CacheKey theCacheKey = new CacheKey(cacheType, idParameterValue);
674
675         byte[] thePDF;
676
677         if (MirGlobal.mruCache().hasObject(theCacheKey)) {
678           getLogger().debug("fetching pdf from cache");
679           thePDF = (byte[]) MirGlobal.mruCache().getObject(theCacheKey);
680         }
681         else {
682           getLogger().debug("generating pdf and caching it");
683           ByteArrayOutputStream out = new ByteArrayOutputStream();
684           PDFGenerator pdfMaker = new PDFGenerator(out);
685
686           if (ids.size() > 1) {
687             pdfMaker.addLine();
688             for (int i = 0; i < ids.size() && i < maxArticlesInNewsleter; i++) {
689               EntityContent contentEnt = (EntityContent) contentModule.getById((String) ids.get(i));
690
691               pdfMaker.addIndexItem(contentEnt);
692             }
693           }
694
695           for (int i = 0; i < ids.size(); i++) {
696             EntityContent article = (EntityContent) contentModule.getById((String) ids.get(i));
697
698             if (!MirGlobal.localizer().openPostings().allowArticlePublication(article)) {
699               throw new ServletModuleExc("Illegal article");
700             }
701
702             pdfMaker.add(article, getLocale(aRequest));
703           }
704
705           pdfMaker.stop();
706           thePDF = out.toByteArray();
707
708           //and save all our hard work!
709           MirGlobal.mruCache().storeObject(theCacheKey, thePDF);
710         }
711
712         aResponse.setContentType("application/pdf");
713         aResponse.setContentLength(thePDF.length);
714         aResponse.getOutputStream().write(thePDF);
715         aResponse.getOutputStream().flush();
716         String elapsedtime = (new Long(System.currentTimeMillis() - starttime)).toString();
717         getLogger().info("pdf retireval took " + elapsedtime + " milliseconds");
718
719       }
720       else {
721         throw new ServletModuleExc("Missing id.");
722       }
723     }
724     catch (Throwable t) {
725       getLogger().error(t.toString());
726
727       throw new ServletModuleFailure(t);
728     }
729   }
730
731
732   public String generateOnetimePassword() {
733     Random r = new Random();
734     int random = r.nextInt();
735
736     long l = System.currentTimeMillis();
737
738     l = (l * l * l * l) / random;
739     if (l < 0)
740       l = l * -1;
741
742     String returnString = "" + l;
743
744     return returnString.substring(5);
745   }
746
747   public void deliver(HttpServletRequest aRequest, HttpServletResponse aResponse, Map aData, Map anExtra, String aGenerator) throws ServletModuleFailure {
748     try {
749       deliver(aResponse.getWriter(), aRequest, aResponse, aData, anExtra, aGenerator);
750     }
751     catch (Throwable t) {
752       throw new ServletModuleFailure(t);
753     }
754   }
755
756   public void deliver(PrintWriter anOutputWriter, HttpServletRequest aRequest, HttpServletResponse aResponse, Map aData, Map anExtra, String aGenerator)
757       throws ServletModuleFailure {
758     try {
759       Map responseData = ServletHelper.makeGenerationData(aRequest, aResponse, new Locale[] { getLocale(aRequest), getFallbackLocale(aRequest)}, "etc/bundles/open");
760       responseData.put("data", aData);
761       responseData.put("extra", anExtra);
762
763
764       Generator generator =
765           MirGlobal.localizer().generators().makeOpenPostingGeneratorLibrary().makeGenerator(aGenerator, null);
766       generator.generate(anOutputWriter, responseData, getLogger());
767
768       anOutputWriter.close();
769     }
770     catch (Throwable e) {
771       getLogger().error("Error while generating " + aGenerator + ": " + e.getMessage());
772
773       throw new ServletModuleFailure(e);
774     }
775   }
776
777   public void deliver(PrintWriter anOutputWriter, HttpServletRequest aRequest, HttpServletResponse aResponse, Map aData, Map anExtra, String aGenerator,String aLocaleString)
778       throws ServletModuleFailure {
779     try {
780       Map responseData = ServletHelper.makeGenerationData(aRequest, aResponse, new Locale[] { new Locale(aLocaleString,""), getFallbackLocale(aRequest)}, "etc/bundles/open");
781       responseData.put("data", aData);
782       responseData.put("extra", anExtra);
783
784
785       Generator generator =
786           MirGlobal.localizer().generators().
787               makeOpenPostingGeneratorLibrary().makeGenerator(aGenerator, null);
788       generator.generate(anOutputWriter, responseData, getLogger());
789
790       anOutputWriter.close();
791     }
792     catch (Throwable e) {
793       getLogger().error("Error while generating " + aGenerator + ": " + e.getMessage());
794
795       throw new ServletModuleFailure(e);
796     }
797   }
798
799
800   public void handleError(HttpServletRequest aRequest, HttpServletResponse aResponse,PrintWriter out, Throwable anException) {
801     try {
802       getLogger().error("Error during open action", anException);
803       Map data = new HashMap();
804
805       data.put("errorstring", anException.getMessage());
806       data.put("date", StringUtil.date2readableDateTime(new GregorianCalendar()));
807
808       deliver(out, aRequest, aResponse, data, null, getConfiguration().getString("ServletModule.OpenIndy.ErrorTemplate"));
809     }
810     catch (Throwable e) {
811       throw new ServletModuleFailure(e);
812     }
813   }
814
815   public void handleUserError(HttpServletRequest aRequest, HttpServletResponse aResponse,
816                                PrintWriter out, ServletModuleUserExc anException) {
817     try {
818       getLogger().warn("user error: " + anException.getMessage());
819       Map data = new HashMap();
820
821       Bundle bundle =
822           MirGlobal.getBundleFactory().getBundle("etc/bundles/open", new
823               String[] { getLocale(aRequest).getLanguage() });
824       data.put("errorstring", bundle.getValue(anException.getMessage(), Arrays.asList(anException.getParameters())));
825       data.put("date", StringUtil.date2readableDateTime(new GregorianCalendar()));
826
827       deliver(out, aRequest, aResponse, data, null, getConfiguration().getString("ServletModule.OpenIndy.UserErrorTemplate"));
828     }
829     catch (Throwable e) {
830       throw new ServletModuleFailure(e);
831     }
832   }
833 }