exception + misc. cleanup
[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.
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 the com.oreilly.servlet library, any library
22  * licensed under the Apache Software License, The Sun (tm) Java Advanced
23  * Imaging library (JAI), The Sun JIMI library (or with modified versions of
24  * the above that use the same license as the above), and distribute linked
25  * combinations including the two.  You must obey the GNU General Public
26  * License in all respects for all of the code used other than the above
27  * mentioned libraries.  If you modify this file, you may extend this exception
28  * to your version of the file, but you are not obligated to do so.  If you do
29  * not wish to do so, delete this exception statement from your version.
30  */
31
32 package mircoders.servlet;
33
34 import java.io.ByteArrayOutputStream;
35 import java.io.File;
36 import java.io.FileNotFoundException;
37 import java.io.FileReader;
38 import java.io.IOException;
39 import java.io.PrintWriter;
40 import java.io.StringWriter;
41 import java.util.ArrayList;
42 import java.util.Collections;
43 import java.util.Enumeration;
44 import java.util.GregorianCalendar;
45 import java.util.HashMap;
46 import java.util.Iterator;
47 import java.util.ListIterator;
48 import java.util.Locale;
49 import java.util.Map;
50 import java.util.Random;
51 import java.util.Set;
52
53 import javax.servlet.http.HttpServletRequest;
54 import javax.servlet.http.HttpServletResponse;
55 import javax.servlet.http.HttpSession;
56
57 import org.apache.commons.net.smtp.SMTPClient;
58 import org.apache.commons.net.smtp.SMTPReply;
59 import org.apache.fop.apps.Driver;
60 import org.apache.fop.apps.XSLTInputHandler;
61 import org.apache.log.Hierarchy;
62 import org.apache.log.Priority;
63 import org.apache.lucene.analysis.standard.StandardAnalyzer;
64 import org.apache.lucene.document.Document;
65 import org.apache.lucene.queryParser.QueryParser;
66 import org.apache.lucene.search.Hits;
67 import org.apache.lucene.search.IndexSearcher;
68 import org.apache.lucene.search.Query;
69 import org.apache.lucene.search.Searcher;
70
71 import freemarker.template.SimpleHash;
72 import freemarker.template.SimpleList;
73 import freemarker.template.SimpleScalar;
74 import freemarker.template.TemplateModelRoot;
75
76 import mir.entity.Entity;
77 import mir.entity.EntityList;
78 import mir.log.LoggerWrapper;
79 import mir.misc.FileHandler;
80 import mir.misc.HTMLTemplateProcessor;
81 import mir.misc.StringUtil;
82 import mir.misc.WebdbMultipartRequest;
83 import mir.servlet.ServletModule;
84 import mir.servlet.ServletModuleExc;
85 import mir.servlet.ServletModuleFailure;
86 import mir.servlet.ServletModuleUserExc;
87 import mir.storage.StorageObjectFailure;
88 import mir.util.StringRoutines;
89 import mir.util.ExceptionFunctions;
90 import mircoders.entity.EntityComment;
91 import mircoders.entity.EntityContent;
92 import mircoders.global.MirGlobal;
93 import mircoders.media.MediaRequest;
94 import mircoders.media.UnsupportedMediaFormatExc;
95 import mircoders.module.ModuleComment;
96 import mircoders.module.ModuleContent;
97 import mircoders.module.ModuleImages;
98 import mircoders.module.ModuleTopics;
99 import mircoders.search.AudioSearchTerm;
100 import mircoders.search.ContentSearchTerm;
101 import mircoders.search.ImagesSearchTerm;
102 import mircoders.search.KeywordSearchTerm;
103 import mircoders.search.TextSearchTerm;
104 import mircoders.search.TopicSearchTerm;
105 import mircoders.search.UnIndexedSearchTerm;
106 import mircoders.search.VideoSearchTerm;
107 import mircoders.storage.DatabaseComment;
108 import mircoders.storage.DatabaseContent;
109 import mircoders.storage.DatabaseContentToMedia;
110 import mircoders.storage.DatabaseContentToTopics;
111 import mircoders.storage.DatabaseImages;
112 import mircoders.storage.DatabaseLanguage;
113 import mircoders.storage.DatabaseTopics;
114
115 /*
116  *  ServletModuleOpenIndy -
117  *   is the open-access-servlet, which is responsible for
118  *    adding comments to articles &
119  *    open-postings to the newswire
120  *
121  * @author mir-coders group
122  * @version $Id: ServletModuleOpenIndy.java,v 1.65 2003/03/09 03:53:12 zapata Exp $
123  *
124  */
125
126 public class ServletModuleOpenIndy extends ServletModule
127 {
128
129   private String        commentFormTemplate, commentFormDoneTemplate, commentFormDupeTemplate;
130   private String        postingFormTemplate, postingFormDoneTemplate, postingFormDupeTemplate;
131   private String        searchResultsTemplate;
132   private String        prepareMailTemplate,sentMailTemplate;
133   private ModuleContent contentModule;
134   private ModuleComment commentModule;
135   private ModuleImages  imageModule;
136   private ModuleTopics  topicsModule;
137   private String        directOp ="yes";
138   private String        passwdProtection ="yes";
139   // Singelton / Kontruktor
140   private static ServletModuleOpenIndy instance = new ServletModuleOpenIndy();
141   public static ServletModule getInstance() { return instance; }
142
143   private ServletModuleOpenIndy() {
144     super();
145     try {
146       logger = new LoggerWrapper("ServletModule.OpenIndy");
147
148       commentFormTemplate = configuration.getString("ServletModule.OpenIndy.CommentTemplate");
149       commentFormDoneTemplate = configuration.getString("ServletModule.OpenIndy.CommentDoneTemplate");
150       commentFormDupeTemplate = configuration.getString("ServletModule.OpenIndy.CommentDupeTemplate");
151       postingFormTemplate = configuration.getString("ServletModule.OpenIndy.PostingTemplate");
152       postingFormDoneTemplate = configuration.getString("ServletModule.OpenIndy.PostingDoneTemplate");
153       postingFormDupeTemplate = configuration.getString("ServletModule.OpenIndy.PostingDupeTemplate");
154       searchResultsTemplate = configuration.getString("ServletModule.OpenIndy.SearchResultsTemplate");
155       prepareMailTemplate = configuration.getString("ServletModule.OpenIndy.PrepareMailTemplate");
156       sentMailTemplate = configuration.getString("ServletModule.OpenIndy.SentMailTemplate");
157       directOp = configuration.getString("DirectOpenposting").toLowerCase();
158       passwdProtection = configuration.getString("PasswdProtection").toLowerCase();
159       mainModule = new ModuleComment(DatabaseComment.getInstance());
160       contentModule = new ModuleContent(DatabaseContent.getInstance());
161       topicsModule = new ModuleTopics(DatabaseTopics.getInstance());
162       imageModule = new ModuleImages(DatabaseImages.getInstance());
163       defaultAction="addposting";
164     }
165     catch (StorageObjectFailure e) {
166       logger.error("servletmoduleopenindy could not be initialized: " + e.getMessage());
167     }
168   }
169
170
171   /**
172    *  Method for making a comment
173    */
174
175   public void addcomment(HttpServletRequest req, HttpServletResponse res) throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure
176   {
177     String aid = req.getParameter("aid"); // the article id the comment will belong to
178     String language = req.getParameter("language");
179
180     if (aid!=null && !aid.equals("")) {
181       try {
182         SimpleHash mergeData = new SimpleHash();
183
184         // onetimepasswd
185         if (passwdProtection.equals("yes")) {
186           String passwd = this.createOneTimePasswd();
187           HttpSession session = req.getSession(false);
188           session.setAttribute("passwd", passwd);
189           mergeData.put("passwd", passwd);
190         }
191
192         if (language != null) {
193           HttpSession session = req.getSession(false);
194           session.setAttribute("Locale", new Locale(language, ""));
195           session.setAttribute("passwd", language);
196         }
197
198         mergeData.put("aid", aid);
199
200         SimpleHash extraInfo = new SimpleHash();
201         extraInfo.put("languagePopUpData", DatabaseLanguage.getInstance().getPopupData());
202
203         deliver(req, res, mergeData, extraInfo, commentFormTemplate);
204       }
205       catch (Throwable t) {
206         throw new ServletModuleFailure("ServletModuleOpenIndy.addcomment: " + t.getMessage(), t);
207       }
208     }
209     else throw new ServletModuleExc("aid not set!");
210   }
211
212   /**
213    *  Method for inserting a comment into the Database and delivering
214    *  the commentDone Page
215    */
216
217   public void inscomment(HttpServletRequest req, HttpServletResponse res)
218     throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure
219   {
220     String aid = req.getParameter("to_media"); // the article id the comment will belong to
221     if (aid!=null && !aid.equals(""))
222       {
223         // ok, collecting data from form
224         try {
225           Map withValues = getIntersectingValues(req, DatabaseComment.getInstance());
226
227           //no html in comments(for now)
228           for (Iterator i=withValues.keySet().iterator(); i.hasNext(); ){
229             String k=(String)i.next();
230             String v=(String)withValues.get(k);
231
232             withValues.put(k,StringUtil.removeHTMLTags(v));
233           }
234           withValues.put("is_published","1");
235           withValues.put("to_comment_status","1");
236
237           //checking the onetimepasswd
238           if(passwdProtection.equals("yes")){
239             HttpSession session = req.getSession(false);
240             String sessionPasswd = (String)session.getAttribute("passwd");
241             if ( sessionPasswd == null){
242               throw new ServletModuleUserExc("Lost password");
243             }
244             String passwd = req.getParameter("passwd");
245             if ( passwd == null || (!sessionPasswd.equals(passwd))) {
246               throw new ServletModuleUserExc("Missing password");
247             }
248             session.invalidate();
249           }
250
251           // inserting into database
252           String id = mainModule.add(withValues);
253           logger.debug("id: "+id);
254           //insert was not successfull
255           if(id==null){
256             deliver(req, res, new SimpleHash(), commentFormDupeTemplate);
257           } else {
258             DatabaseContent.getInstance().setUnproduced("id="+aid);
259
260             try {
261               EntityComment comment = (EntityComment) DatabaseComment.getInstance().selectById(id);
262               MirGlobal.localizer().openPostings().afterCommentPosting(comment);
263             }
264             catch (Throwable t) {
265               throw new ServletModuleExc(t.getMessage());
266             }
267           }
268
269           // redirecting to url
270           // should implement back to article
271           SimpleHash mergeData = new SimpleHash();
272           deliver(req, res, mergeData, commentFormDoneTemplate);
273         }
274         catch (Throwable e) {
275           throw new ServletModuleFailure(e);
276         }
277       }
278     else throw new ServletModuleExc("aid not set!");
279
280   }
281
282   /**
283    *  Method for delivering the form-Page for open posting
284    */
285
286   public void addposting(HttpServletRequest req, HttpServletResponse res)
287       throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure
288   {
289     SimpleHash mergeData = new SimpleHash();
290
291     // onetimepasswd
292     if(passwdProtection.equals("yes")){
293       String passwd = this.createOneTimePasswd();
294       HttpSession session = req.getSession(false);
295       session.setAttribute("passwd",passwd);
296       mergeData.put("passwd", passwd);
297     }
298
299     String maxMedia = configuration.getString("ServletModule.OpenIndy.MaxMediaUploadItems");
300     String defaultMedia = configuration.getString("ServletModule.OpenIndy.DefaultMediaUploadItems");
301     String numOfMedia = req.getParameter("medianum");
302
303     if(numOfMedia==null||numOfMedia.equals("")){
304       numOfMedia=defaultMedia;
305     }
306     else if(Integer.parseInt(numOfMedia) > Integer.parseInt(maxMedia)) {
307       numOfMedia = maxMedia;
308     }
309
310     int mediaNum = Integer.parseInt(numOfMedia);
311     SimpleList mediaFields = new SimpleList();
312     for(int i =0; i<mediaNum;i++){
313       Integer mNum = new Integer(i+1);
314       mediaFields.add(mNum.toString());
315     }
316     mergeData.put("medianum",numOfMedia);
317     mergeData.put("mediafields",mediaFields);
318
319
320     SimpleHash extraInfo = new SimpleHash();
321     try{
322       extraInfo.put("languagePopUpData", DatabaseLanguage.getInstance().getPopupData() );
323       extraInfo.put("themenPopupData", topicsModule.getTopicsAsSimpleList());
324
325       extraInfo.put("topics", topicsModule.getTopicsList());
326
327     }
328     catch (Exception e) {
329       logger.error("languagePopUpData or getTopicslist failed "+e.toString());
330
331       throw new ServletModuleFailure("OpenIndy -- failed getting language or topics: "+e.toString(), e);
332     }
333
334     deliver(req, res, mergeData, extraInfo, postingFormTemplate);
335   }
336
337   /**
338    *  Method for inserting an open posting into the Database and delivering
339    *  the postingDone Page
340    */
341
342   public void insposting(HttpServletRequest req, HttpServletResponse res)
343       throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure
344   {
345     SimpleHash mergeData = new SimpleHash();
346     boolean setMedia=false;
347     boolean setTopic = false;
348
349     try {
350
351       WebdbMultipartRequest mp = null;
352       EntityList mediaList = null;
353       try {
354         // new MediaRequest, "1" is the id for the openPosting user
355         MediaRequest mediaReq = new MediaRequest("1", true);
356         mp = new WebdbMultipartRequest(req, (FileHandler)mediaReq);
357         mediaList = mediaReq.getEntityList();
358       }
359       catch (Throwable e) {
360         throw new ServletModuleFailure(e);
361       }
362
363       Map withValues = mp.getParameters();
364
365       //checking the onetimepasswd
366       if(passwdProtection.equals("yes")){
367         HttpSession session = req.getSession(false);
368         String sessionPasswd = (String)session.getAttribute("passwd");
369         if ( sessionPasswd == null){
370           throw new ServletModuleUserExc("Lost password");
371         }
372         String passwd = (String)withValues.get("passwd");
373         if ( passwd == null || (!sessionPasswd.equals(passwd))) {
374           throw new ServletModuleUserExc("Missing password");
375         }
376         session.invalidate();
377       }
378
379       if ((((String)withValues.get("title")).length() == 0) ||
380           (((String)withValues.get("description")).length() == 0) ||
381           (((String)withValues.get("content_data")).length() == 0))
382         throw new ServletModuleUserExc("Missing field");
383
384       // call the routines that escape html
385
386       for (Iterator i=withValues.keySet().iterator(); i.hasNext(); ){
387         String k=(String)i.next();
388         String v=(String)withValues.get(k);
389
390         if (k.equals("content_data")){
391           //this doesn't quite work yet, so for now, all html goes
392           //withValues.put(k,StringUtil.approveHTMLTags(v));
393           withValues.put(k,StringUtil.deleteForbiddenTags(v));
394         }
395         else if (k.equals("description")) {
396           String tmp = StringUtil.deleteForbiddenTags(v);
397           withValues.put(k,StringUtil.deleteHTMLTableTags(tmp));
398         }
399         else {
400           withValues.put(k,StringUtil.removeHTMLTags(v));
401         }
402
403       }
404
405       withValues.put("date", StringUtil.date2webdbDate(new GregorianCalendar()));
406       withValues.put("publish_path", StringUtil.webdbDate2path((String)withValues.get("date")));
407       withValues.put("is_produced", "0");
408       // by default stuff is published, they can be un-published through the
409       // admin interface.
410       withValues.put("is_published","1");
411       // if op direct article-type == newswire
412       if (directOp.equals("yes")) withValues.put("to_article_type","1");
413
414       withValues.put("to_publisher","1");
415
416       // owner is openposting user
417       //      ML: this is not multi-language friendly and this can be done in a template
418       //      if (withValues.get("creator").toString().equals(""))
419       //        withValues.put("creator","Anonym");
420
421       // inserting  content into database
422       String cid = contentModule.add(withValues);
423       logger.debug("id: "+cid);
424       //insert was not successfull
425       if(cid==null){
426         //How do we know that it was not succesful cause of a
427         //dupe, what if it failed cause of "No space left on device"?
428         //Or is there something I am missing? Wouldn't it be better
429         //to have an explicit dupe check and then insert? I have no
430         //idea what I am talking about. this comment is in case
431         //I forget to explicitely ask. -mh
432         deliver(req, res, mergeData, postingFormDupeTemplate);
433       }
434
435       String[] to_topicsArr = mp.getParameterValues("to_topic");
436
437       if (to_topicsArr != null && to_topicsArr.length > 0) {
438         try{
439           DatabaseContentToTopics.getInstance().setTopics(cid,to_topicsArr);
440           setTopic = true;
441         }
442         catch (Throwable e) {
443           logger.error("setting content_x_topic failed");
444           contentModule.deleteById(cid);
445           throw new ServletModuleFailure("smod - openindy :: insposting: setting content_x_topic failed: "+e.toString(), e);
446         } //end try
447       } //end if
448
449       //if we're here all is ok... associate the media to the article
450       for(int i=0;i<mediaList.size();i++) {
451         Entity mediaEnt = (Entity)mediaList.elementAt(i);
452         DatabaseContentToMedia.getInstance().addMedia(cid,mediaEnt.getId());
453       }
454
455       try {
456         MirGlobal.localizer().openPostings().afterContentPosting(
457                                                                  (EntityContent)contentModule.getById(cid));
458       }
459       catch (Throwable t) {
460         throw new ServletModuleFailure(t);
461       }
462     }
463     catch (Throwable e) {
464       Throwable cause = ExceptionFunctions.traceCauseException(e);
465
466       if (cause instanceof UnsupportedMediaFormatExc) {
467         throw new ServletModuleUserExc("Unsupported media format");
468       }
469       throw new ServletModuleFailure(e);
470     }
471
472     deliver(req, res, mergeData, postingFormDoneTemplate);
473   }
474
475     /*
476    * Method for preparing and sending a content as an email message
477    */
478
479   public void mail(HttpServletRequest req, HttpServletResponse res)
480       throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure
481   {
482     String aid = req.getParameter("mail_aid");
483     if (aid == null){
484       throw new ServletModuleUserExc("An article id must be specified in requests to email an article.  Something therefore went badly wrong....");
485     }
486
487     String to = req.getParameter("mail_to");
488     String from = req.getParameter("mail_from");
489     String from_name = req.getParameter("mail_from_name");
490     String comment = req.getParameter("mail_comment");
491     String mail_language = req.getParameter("mail_language");
492
493     SimpleHash mergeData = new SimpleHash();
494
495     if (to == null || from == null || from_name == null|| to.equals("") || from.equals("") || from_name.equals("") || mail_language == null || mail_language.equals("")){
496
497       for (Enumeration theParams = req.getParameterNames(); theParams.hasMoreElements() ;) {
498         String pName=(String)theParams.nextElement();
499         if (pName.startsWith("mail_")){
500           mergeData.put(pName,new SimpleScalar(req.getParameter(pName)));
501         }
502       }
503       deliver(req,res,mergeData,prepareMailTemplate);
504     }
505     else {
506       //run checks on to and from and mail_language to make sure no monkey business occurring
507       if (mail_language.indexOf('.') != -1 || mail_language.indexOf('/') != -1 ){
508         throw new ServletModuleUserExc("Sorry, you've entered an illegal character into the language field.  Go back and try again, asshole.");
509       }
510       if (to.indexOf('\n') != -1
511           || to.indexOf('\r') != -1
512           || to.indexOf(',') != -1
513           || from.indexOf('\n') != -1
514           || from.indexOf('\r') != -1
515           || from.indexOf(',') != -1 ){
516         throw new ServletModuleUserExc("Sorry, you've entered an illegal character into the from or to field.  Go back and try again.");
517       }
518       EntityContent contentEnt;
519       try{
520         contentEnt = (EntityContent)contentModule.getById(aid);
521       }
522       catch (Throwable e){
523         throw new ServletModuleFailure("Couldn't get content for article "+aid + ": " + e.getMessage(), e);
524       }
525       String producerStorageRoot=configuration.getString("Producer.StorageRoot");
526       String producerDocRoot=configuration.getString("Producer.DocRoot");
527       String publishPath = contentEnt.getValue("publish_path");
528       String txtFilePath = producerStorageRoot + producerDocRoot + "/" + mail_language +
529                                                                                                          publishPath + "/" + aid + ".txt";
530
531
532       File inputFile = new File(txtFilePath);
533       String content;
534
535       try{
536         FileReader in = new FileReader(inputFile);
537         StringWriter out = new StringWriter();
538         int c;
539         while ((c = in.read()) != -1)
540           out.write(c);
541         in.close();
542         content= out.toString();
543       }
544       catch (FileNotFoundException e){
545         throw new ServletModuleFailure("No text file found in " + txtFilePath, e);
546       }
547       catch (IOException e){
548         throw new ServletModuleFailure("Problem reading file in " + txtFilePath, e);
549       }
550       // add some headers
551       content = "To: " + to + "\nReply-To: "+ from + "\n" + content;
552       // put in the comment where it should go
553       if (comment != null) {
554         String commentTextToInsert = "\n\nAttached comment from " + from_name + ":\n" + comment;
555         try {
556           content=StringRoutines.performRegularExpressionReplacement(content,"!COMMENT!",commentTextToInsert);
557         }
558         catch (Throwable e){
559           throw new ServletModuleFailure("Problem doing regular expression replacement " + e.toString(), e);
560         }
561       }
562       else{
563         try {
564           content=StringRoutines.performRegularExpressionReplacement(content,"!COMMENT!","");
565         }
566         catch (Throwable e){
567           throw new ServletModuleFailure("Problem doing regular expression replacement " + e.toString(), e);
568         }
569       }
570
571       SMTPClient client=new SMTPClient();
572       try {
573         int reply;
574         client.connect(configuration.getString("ServletModule.OpenIndy.SMTPServer"));
575
576         reply = client.getReplyCode();
577
578         if (!SMTPReply.isPositiveCompletion(reply)) {
579           client.disconnect();
580           throw new ServletModuleExc("SMTP server refused connection.");
581         }
582
583         client.sendSimpleMessage(configuration.getString("ServletModule.OpenIndy.EmailIsFrom"), to, content);
584
585         client.disconnect();
586         //mission accomplished
587         deliver(req, res, mergeData, sentMailTemplate);
588       }
589       catch(IOException e) {
590         if(client.isConnected()) {
591           try {
592             client.disconnect();
593           } catch(IOException f) {
594             // do nothing
595           }
596         }
597         throw new ServletModuleFailure(e);
598       }
599     }
600   }
601
602
603   /*
604    * Method for querying a lucene index
605    */
606   public void search(HttpServletRequest req, HttpServletResponse res)
607       throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure {
608     try {
609       int increment=10;
610
611       HttpSession session = req.getSession(false);
612
613       String queryString="";
614
615       SimpleHash mergeData = new SimpleHash();
616
617       KeywordSearchTerm dateTerm = new KeywordSearchTerm("date_formatted","search_date","webdb_create_formatted","webdb_create_formatted","webdb_create_formatted");
618       UnIndexedSearchTerm whereTerm = new UnIndexedSearchTerm("","","","where","where");
619       TextSearchTerm creatorTerm = new TextSearchTerm("creator","search_creator","creator","creator","creator");
620       TextSearchTerm titleTerm = new TextSearchTerm("title","search_content","title","title","title");
621       TextSearchTerm descriptionTerm =  new TextSearchTerm("description","search_content","description","description","description");
622       ContentSearchTerm contentTerm = new ContentSearchTerm("content_data","search_content","content","","");
623       TopicSearchTerm topicTerm = new TopicSearchTerm();
624       ImagesSearchTerm imagesTerm = new ImagesSearchTerm();
625       AudioSearchTerm audioTerm = new AudioSearchTerm();
626       VideoSearchTerm videoTerm = new VideoSearchTerm();
627
628       //make the query available to subsequent iterations
629
630       for (Enumeration theParams = req.getParameterNames(); theParams.hasMoreElements() ;) {
631         String pName=(String)theParams.nextElement();
632         if (pName.startsWith("search_")){
633           mergeData.put(pName,new SimpleScalar(req.getParameter(pName)));
634         }
635       }
636
637       try{
638         mergeData.put("topics", topicsModule.getTopicsAsSimpleList());
639       }
640       catch(Throwable e) {
641         logger.debug("Can't get topics: " + e.toString());
642       }
643
644       String searchBackValue = req.getParameter("search_back");
645       String searchForwardValue = req.getParameter("search_forward");
646
647       if (searchBackValue != null){
648         int totalHits = ((Integer) session.getAttribute("numberOfHits")).intValue();
649         int newPosition=((Integer)session.getAttribute("positionInResults")).intValue()-increment;
650         if (newPosition<0)
651           newPosition=0;
652         if (newPosition >= totalHits)
653           newPosition=totalHits-1;
654         session.setAttribute("positionInResults",new Integer(newPosition));
655       }
656       else {
657         if (searchForwardValue != null){
658           int totalHits = ((Integer) session.getAttribute("numberOfHits")).intValue();
659           int newPosition=((Integer)session.getAttribute("positionInResults")).intValue()+increment;
660           if (newPosition<0)
661             newPosition=0;
662           if (newPosition >= totalHits)
663             newPosition=totalHits-1;
664
665           session.setAttribute("positionInResults",new Integer(newPosition));
666         }
667         else {
668           String indexPath=configuration.getString("IndexPath");
669
670
671           String creatorFragment = creatorTerm.makeTerm(req);
672           if (creatorFragment != null){
673             queryString = queryString + " +" + creatorFragment;
674           }
675
676           // search title, description, and content for something
677           // the contentTerm uses param "search_boolean" to combine its terms
678           String contentFragment = contentTerm.makeTerm(req);
679           if (contentFragment != null){
680             logger.debug("contentFragment: " + contentFragment);
681             queryString = queryString + " +" + contentFragment;
682           }
683
684           String topicFragment = topicTerm.makeTerm(req);
685           if (topicFragment != null){
686             queryString = queryString + " +" + topicFragment;
687           }
688
689           String imagesFragment = imagesTerm.makeTerm(req);
690           if (imagesFragment != null){
691             queryString = queryString + " +" + imagesFragment;
692           }
693
694           String audioFragment = audioTerm.makeTerm(req);
695           if (audioFragment != null){
696             queryString = queryString + " +" + audioFragment;
697           }
698
699           String videoFragment = videoTerm.makeTerm(req);
700           if (videoFragment != null){
701             queryString = queryString + " +" + videoFragment;
702           }
703
704           if (queryString == null || queryString == ""){
705             queryString = "";
706           }
707           else{
708             try{
709               Searcher searcher = null;
710               try {
711                 searcher = new IndexSearcher(indexPath);
712               }
713               catch(IOException e) {
714                 logger.debug("Can't open indexPath: " + indexPath);
715                 throw new ServletModuleExc("Problem with Search Index! : "+ e.toString());
716               }
717
718               Query query = null;
719               try {
720                 query = QueryParser.parse(queryString, "content", new StandardAnalyzer());
721               }
722               catch(Exception e) {
723                 searcher.close();
724                 logger.debug("Query don't parse: " + queryString);
725                 throw new ServletModuleExc("Problem with Query String! (was '"+queryString+"')");
726               }
727
728               Hits hits = null;
729               try {
730                 hits = searcher.search(query);
731               }
732               catch(IOException e) {
733                 searcher.close();
734                 logger.debug("Can't get hits: " + e.toString());
735                 throw new ServletModuleExc("Problem getting hits!");
736               }
737
738               int start = 0;
739               int end = hits.length();
740
741               String sortBy=req.getParameter("search_sort");
742               if (sortBy == null || sortBy.equals("")){
743                 throw new ServletModuleExc("Please let me sort by something!(missing search_sort)");
744               }
745
746               // here is where the documents will go for storage across sessions
747               ArrayList theDocumentsSorted = new ArrayList();
748
749               if (sortBy.equals("score")){
750                 for(int i = start; i < end; i++) {
751                   theDocumentsSorted.add(hits.doc(i));
752                 }
753               }
754               else{
755                 // then we'll sort by date!
756                 Map dateToPosition = new HashMap(end,1.0F); //we know how big it will be
757                 for(int i = start; i < end; i++) {
758                   String creationDate=(hits.doc(i)).get("creationDate");
759                   // do a little dance in case two contents created at the same second!
760                   if (dateToPosition.containsKey(creationDate)){
761                     ((ArrayList) (dateToPosition.get(creationDate))).add(new Integer(i));
762                   }
763                   else{
764                     ArrayList thePositions = new ArrayList();
765                     thePositions.add(new Integer(i));
766                     dateToPosition.put(creationDate,thePositions);
767                   }
768                 }
769                 Set keys = dateToPosition.keySet();
770                 ArrayList keyList= new ArrayList(keys);
771                 Collections.sort(keyList);
772                 if (sortBy.equals("date_desc")){
773                   Collections.reverse(keyList);
774                 }
775                 else{
776                   if (!sortBy.equals("date_asc")){
777                     throw new ServletModuleExc("don't know how to sort by: "+ sortBy);
778                   }
779                 }
780                 ListIterator keyTraverser = keyList.listIterator();
781                 while (keyTraverser.hasNext()){
782                   ArrayList positions = (ArrayList)dateToPosition.get((keyTraverser.next()));
783                   ListIterator positionsTraverser=positions.listIterator();
784                   while (positionsTraverser.hasNext()){
785                     theDocumentsSorted.add(hits.doc(((Integer)(positionsTraverser.next())).intValue()));
786                   }
787                 }
788               }
789
790               try{
791                 searcher.close();
792               }
793               catch (IOException e){
794                 logger.debug("Can't close searcher: " + e.toString());
795                 throw new ServletModuleFailure("Problem closing searcher(normal):" + e.getMessage(), e);
796               }
797
798
799               session.removeAttribute("numberOfHits");
800               session.removeAttribute("theDocumentsSorted");
801               session.removeAttribute("positionInResults");
802
803               session.setAttribute("numberOfHits",new Integer(end));
804               session.setAttribute("theDocumentsSorted",theDocumentsSorted);
805               session.setAttribute("positionInResults",new Integer(0));
806
807             }
808             catch (IOException e){
809               logger.debug("Can't close searcher: " + e.toString());
810               throw new ServletModuleFailure("Problem closing searcher: " + e.getMessage(), e);
811             }
812           }
813         }
814       }
815
816       try {
817         ArrayList theDocs = (ArrayList)session.getAttribute("theDocumentsSorted");
818         if (theDocs != null){
819
820           mergeData.put("numberOfHits", ((Integer)session.getAttribute("numberOfHits")).toString());
821           SimpleList theHits = new SimpleList();
822           int pIR=((Integer)session.getAttribute("positionInResults")).intValue();
823           int terminus;
824           int numHits=((Integer)session.getAttribute("numberOfHits")).intValue();
825
826           if (!(pIR+increment>=numHits)){
827             mergeData.put("hasNext","y");
828           }
829           if (pIR>0){
830             mergeData.put("hasPrevious","y");
831           }
832
833           if ((pIR+increment)>numHits){
834             terminus=numHits;
835           }
836           else {
837             terminus=pIR+increment;
838           }
839           for(int i = pIR; i < terminus; i++) {
840             SimpleHash h = new SimpleHash();
841             Document theHit = (Document)theDocs.get(i);
842             whereTerm.returnMeta(h,theHit);
843             creatorTerm.returnMeta(h,theHit);
844             titleTerm.returnMeta(h,theHit);
845             descriptionTerm.returnMeta(h,theHit);
846             dateTerm.returnMeta(h,theHit);
847             imagesTerm.returnMeta(h,theHit);
848             audioTerm.returnMeta(h,theHit);
849             videoTerm.returnMeta(h,theHit);
850             theHits.add(h);
851           }
852           mergeData.put("hits",theHits);
853         }
854       }
855       catch (Throwable e) {
856         logger.error("Can't iterate over hits: " + e.toString());
857
858         throw new ServletModuleFailure("Problem getting hits: " + e.getMessage(), e);
859       }
860
861       mergeData.put("queryString",queryString);
862       deliver(req,res,mergeData,searchResultsTemplate);
863     }
864     catch (NullPointerException n){
865       throw new ServletModuleFailure("Null Pointer: "+n.toString(), n);
866     }
867   }
868
869   /*
870    * Method for dynamically generating a pdf from a fo file
871    */
872   public void getpdf(HttpServletRequest req, HttpServletResponse res)
873       throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure {
874     String ID_REQUEST_PARAM = "id";
875     String language = req.getParameter("language");
876     String generateFO=configuration.getString("GenerateFO");
877     String generatePDF=configuration.getString("GeneratePDF");
878
879
880     //don't do anything if we are not making FO files, or if we are
881     //pregenerating PDF's
882     if (generateFO.equals("yes") && generatePDF.equals("no")){
883       //fop complains unless you do the logging this way
884       org.apache.log.Logger log = null;
885       Hierarchy hierarchy = Hierarchy.getDefaultHierarchy();
886       log = hierarchy.getLoggerFor("fop");
887       log.setPriority(Priority.WARN);
888
889       String producerStorageRoot=configuration.getString("Producer.StorageRoot");
890       String producerDocRoot=configuration.getString("Producer.DocRoot");
891       //      String templateDir=MirConfig.getPropWithHome("HTMLTemplateProcessor.Dir");
892       String xslSheet=configuration.getString("Producer.HTML2FOStyleSheet");
893       try {
894         String idParam = req.getParameter(ID_REQUEST_PARAM);
895         if (idParam != null) {
896           EntityContent contentEnt =
897             (EntityContent)contentModule.getById(idParam);
898           String publishPath = StringUtil.webdbDate2path(contentEnt.getValue("date"));
899           String foFile;
900
901           if (language == null){
902             foFile = producerStorageRoot + producerDocRoot + "/"
903               + publishPath  + idParam + ".fo";
904           }
905           else{
906             foFile = producerStorageRoot + producerDocRoot + "/"
907               + language + publishPath  + idParam + ".fo";
908           }
909           logger.debug("USING FILES" + foFile + " and " + xslSheet);
910           XSLTInputHandler input = new XSLTInputHandler(new File(foFile),
911                                                         new File(xslSheet));
912
913           ByteArrayOutputStream out = new ByteArrayOutputStream();
914           res.setContentType("application/pdf");
915
916           Driver driver = new Driver();
917           driver.setLogger(log);
918           driver.setRenderer(Driver.RENDER_PDF);
919           driver.setOutputStream(out);
920           driver.render(input.getParser(), input.getInputSource());
921
922           byte[] content = out.toByteArray();
923           res.setContentLength(content.length);
924           res.getOutputStream().write(content);
925           res.getOutputStream().flush();
926         }
927         else {
928           throw new ServletModuleUserExc("Missing id parameter.");
929         }
930       }
931       catch (Exception ex) {
932         logger.error(ex.toString());
933         throw new ServletModuleFailure(ex);
934       }
935     } else {
936       throw new ServletModuleExc("Can't generate a PDF because the config tells me not to.");
937     }
938   }
939
940   protected String createOneTimePasswd(){
941     Random r = new Random();
942     int random = r.nextInt();
943     long l = System.currentTimeMillis();
944     l = (l*l*l*l)/random;
945     if(l<0) l = l * -1;
946     String returnString = ""+l;
947     return returnString.substring(5);
948   }
949
950
951   /* this is an overwritten method of ServletModule in order
952      to use different bundles for open and admin */
953   public void deliver(HttpServletRequest req, HttpServletResponse res,
954                       TemplateModelRoot rtm, TemplateModelRoot popups,
955                       String templateFilename) throws ServletModuleFailure
956   {
957     if (rtm == null) rtm = new SimpleHash();
958     try {
959       PrintWriter out = res.getWriter();
960       HTMLTemplateProcessor.process(res, templateFilename, rtm, popups, out,
961                                     getLocale(req), "bundles.open");
962       out.close();
963     }
964     catch (Throwable e) {
965       throw new ServletModuleFailure(e);
966     }
967   }
968 }
969
970
971