internationalized user error messages
[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.66 2003/03/09 05:52:13 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 ServletModuleExc("Lost password");
243             }
244             String passwd = req.getParameter("passwd");
245             if ( passwd == null || passwd.length()==0) {
246               throw new ServletModuleUserExc("comment.error.missingpassword", new String[] {});
247             }
248             if (!sessionPasswd.equals(passwd)) {
249               throw new ServletModuleUserExc("comment.error.invalidpassword", new String[] {});
250             }
251             session.invalidate();
252           }
253
254           // inserting into database
255           String id = mainModule.add(withValues);
256           logger.debug("id: "+id);
257           //insert was not successfull
258           if(id==null){
259             deliver(req, res, new SimpleHash(), commentFormDupeTemplate);
260           }
261           else {
262             DatabaseContent.getInstance().setUnproduced("id="+aid);
263
264             try {
265               EntityComment comment = (EntityComment) DatabaseComment.getInstance().selectById(id);
266               MirGlobal.localizer().openPostings().afterCommentPosting(comment);
267             }
268             catch (Throwable t) {
269               throw new ServletModuleExc(t.getMessage());
270             }
271           }
272
273           // redirecting to url
274           // should implement back to article
275           SimpleHash mergeData = new SimpleHash();
276           deliver(req, res, mergeData, commentFormDoneTemplate);
277         }
278         catch (Throwable e) {
279           throw new ServletModuleFailure(e);
280         }
281       }
282     else throw new ServletModuleExc("aid not set!");
283
284   }
285
286   /**
287    *  Method for delivering the form-Page for open posting
288    */
289
290   public void addposting(HttpServletRequest req, HttpServletResponse res)
291       throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure
292   {
293     SimpleHash mergeData = new SimpleHash();
294
295     // onetimepasswd
296     if(passwdProtection.equals("yes")){
297       String passwd = this.createOneTimePasswd();
298       HttpSession session = req.getSession(false);
299       session.setAttribute("passwd",passwd);
300       mergeData.put("passwd", passwd);
301     }
302
303     String maxMedia = configuration.getString("ServletModule.OpenIndy.MaxMediaUploadItems");
304     String defaultMedia = configuration.getString("ServletModule.OpenIndy.DefaultMediaUploadItems");
305     String numOfMedia = req.getParameter("medianum");
306
307     if(numOfMedia==null||numOfMedia.equals("")){
308       numOfMedia=defaultMedia;
309     }
310     else if(Integer.parseInt(numOfMedia) > Integer.parseInt(maxMedia)) {
311       numOfMedia = maxMedia;
312     }
313
314     int mediaNum = Integer.parseInt(numOfMedia);
315     SimpleList mediaFields = new SimpleList();
316     for(int i =0; i<mediaNum;i++){
317       Integer mNum = new Integer(i+1);
318       mediaFields.add(mNum.toString());
319     }
320     mergeData.put("medianum",numOfMedia);
321     mergeData.put("mediafields",mediaFields);
322
323
324     SimpleHash extraInfo = new SimpleHash();
325     try{
326       extraInfo.put("languagePopUpData", DatabaseLanguage.getInstance().getPopupData() );
327       extraInfo.put("themenPopupData", topicsModule.getTopicsAsSimpleList());
328
329       extraInfo.put("topics", topicsModule.getTopicsList());
330
331     }
332     catch (Exception e) {
333       logger.error("languagePopUpData or getTopicslist failed "+e.toString());
334
335       throw new ServletModuleFailure("OpenIndy -- failed getting language or topics: "+e.toString(), e);
336     }
337
338     deliver(req, res, mergeData, extraInfo, postingFormTemplate);
339   }
340
341   /**
342    *  Method for inserting an open posting into the Database and delivering
343    *  the postingDone Page
344    */
345
346   public void insposting(HttpServletRequest req, HttpServletResponse res) throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure
347   {
348     SimpleHash mergeData = new SimpleHash();
349     boolean setMedia=false;
350     boolean setTopic = false;
351
352     try {
353
354       WebdbMultipartRequest mp = null;
355       EntityList mediaList = null;
356       try {
357         // new MediaRequest, "1" is the id for the openPosting user
358         MediaRequest mediaReq = new MediaRequest("1", true);
359         mp = new WebdbMultipartRequest(req, (FileHandler)mediaReq);
360         mediaList = mediaReq.getEntityList();
361       }
362       catch (Throwable e) {
363         throw new ServletModuleFailure(e);
364       }
365
366       Map withValues = mp.getParameters();
367
368       //checking the onetimepasswd
369       if(passwdProtection.equals("yes")){
370         HttpSession session = req.getSession(false);
371         String sessionPasswd = (String)session.getAttribute("passwd");
372         if ( sessionPasswd == null){
373           throw new ServletModuleExc("Lost password");
374         }
375         String passwd = (String)withValues.get("passwd");
376         if ( passwd == null || passwd.length()==0) {
377           throw new ServletModuleUserExc("posting.error.missingpassword", new String[] {});
378         }
379         if (!sessionPasswd.equals(passwd)) {
380           throw new ServletModuleUserExc("posting.error.invalidpassword", new String[] {});
381         }
382         session.invalidate();
383       }
384
385       if ((((String)withValues.get("title")).length() == 0) ||
386           (((String)withValues.get("description")).length() == 0) ||
387           (((String)withValues.get("content_data")).length() == 0))
388         throw new ServletModuleUserExc("posting.error.missingfield", new String[] {});
389
390       // call the routines that escape html
391
392       for (Iterator i=withValues.keySet().iterator(); i.hasNext(); ){
393         String k=(String)i.next();
394         String v=(String)withValues.get(k);
395
396         if (k.equals("content_data")){
397           //this doesn't quite work yet, so for now, all html goes
398           //withValues.put(k,StringUtil.approveHTMLTags(v));
399           withValues.put(k,StringUtil.deleteForbiddenTags(v));
400         }
401         else if (k.equals("description")) {
402           String tmp = StringUtil.deleteForbiddenTags(v);
403           withValues.put(k,StringUtil.deleteHTMLTableTags(tmp));
404         }
405         else {
406           withValues.put(k,StringUtil.removeHTMLTags(v));
407         }
408
409       }
410
411       withValues.put("date", StringUtil.date2webdbDate(new GregorianCalendar()));
412       withValues.put("publish_path", StringUtil.webdbDate2path((String)withValues.get("date")));
413       withValues.put("is_produced", "0");
414       // by default stuff is published, they can be un-published through the
415       // admin interface.
416       withValues.put("is_published","1");
417       // if op direct article-type == newswire
418       if (directOp.equals("yes")) withValues.put("to_article_type","1");
419
420       withValues.put("to_publisher","1");
421
422       // owner is openposting user
423       //      ML: this is not multi-language friendly and this can be done in a template
424       //      if (withValues.get("creator").toString().equals(""))
425       //        withValues.put("creator","Anonym");
426
427       // inserting  content into database
428       String cid = contentModule.add(withValues);
429       logger.debug("id: "+cid);
430       //insert was not successfull
431       if(cid==null){
432         //How do we know that it was not succesful cause of a
433         //dupe, what if it failed cause of "No space left on device"?
434         //Or is there something I am missing? Wouldn't it be better
435         //to have an explicit dupe check and then insert? I have no
436         //idea what I am talking about. this comment is in case
437         //I forget to explicitely ask. -mh
438         deliver(req, res, mergeData, postingFormDupeTemplate);
439       }
440
441       String[] to_topicsArr = mp.getParameterValues("to_topic");
442
443       if (to_topicsArr != null && to_topicsArr.length > 0) {
444         try{
445           DatabaseContentToTopics.getInstance().setTopics(cid,to_topicsArr);
446           setTopic = true;
447         }
448         catch (Throwable e) {
449           logger.error("setting content_x_topic failed");
450           contentModule.deleteById(cid);
451           throw new ServletModuleFailure("smod - openindy :: insposting: setting content_x_topic failed: "+e.toString(), e);
452         } //end try
453       } //end if
454
455       //if we're here all is ok... associate the media to the article
456       for(int i=0;i<mediaList.size();i++) {
457         Entity mediaEnt = (Entity)mediaList.elementAt(i);
458         DatabaseContentToMedia.getInstance().addMedia(cid,mediaEnt.getId());
459       }
460
461       try {
462         MirGlobal.localizer().openPostings().afterContentPosting(
463                                                                  (EntityContent)contentModule.getById(cid));
464       }
465       catch (Throwable t) {
466         throw new ServletModuleFailure(t);
467       }
468     }
469     catch (Throwable e) {
470       Throwable cause = ExceptionFunctions.traceCauseException(e);
471
472       if (cause instanceof UnsupportedMediaFormatExc) {
473         throw new ServletModuleUserExc("media.unsupportedformat", new String[] {} );
474       }
475       throw new ServletModuleFailure(e);
476     }
477
478     deliver(req, res, mergeData, postingFormDoneTemplate);
479   }
480
481     /*
482    * Method for preparing and sending a content as an email message
483    */
484
485   public void mail(HttpServletRequest req, HttpServletResponse res)
486       throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure
487   {
488     String aid = req.getParameter("mail_aid");
489     if (aid == null){
490       throw new ServletModuleExc("An article id must be specified in requests to email an article.  Something therefore went badly wrong....");
491     }
492
493     String to = req.getParameter("mail_to");
494     String from = req.getParameter("mail_from");
495     String from_name = req.getParameter("mail_from_name");
496     String comment = req.getParameter("mail_comment");
497     String mail_language = req.getParameter("mail_language");
498
499     SimpleHash mergeData = new SimpleHash();
500
501     if (to == null || from == null || from_name == null|| to.equals("") || from.equals("") || from_name.equals("") || mail_language == null || mail_language.equals("")){
502
503       for (Enumeration theParams = req.getParameterNames(); theParams.hasMoreElements() ;) {
504         String pName=(String)theParams.nextElement();
505         if (pName.startsWith("mail_")){
506           mergeData.put(pName,new SimpleScalar(req.getParameter(pName)));
507         }
508       }
509       deliver(req,res,mergeData,prepareMailTemplate);
510     }
511     else {
512       //run checks on to and from and mail_language to make sure no monkey business occurring
513       if (mail_language.indexOf('.') != -1 || mail_language.indexOf('/') != -1 ) {
514         throw new ServletModuleExc("Invalid language");
515       }
516       if (to.indexOf('\n') != -1
517           || to.indexOf('\r') != -1
518           || to.indexOf(',') != -1) {
519         throw new ServletModuleUserExc("email.error.invalidtoaddress", new String[] {to});
520       }
521       if (from.indexOf('\n') != -1 || from.indexOf('\r') != -1 || from.indexOf(',') != -1 ) {
522         throw new ServletModuleUserExc("email.error.invalidfromaddress", new String[] {from});
523       }
524
525
526       EntityContent contentEnt;
527       try{
528         contentEnt = (EntityContent)contentModule.getById(aid);
529       }
530       catch (Throwable e){
531         throw new ServletModuleFailure("Couldn't get content for article "+aid + ": " + e.getMessage(), e);
532       }
533       String producerStorageRoot=configuration.getString("Producer.StorageRoot");
534       String producerDocRoot=configuration.getString("Producer.DocRoot");
535       String publishPath = contentEnt.getValue("publish_path");
536       String txtFilePath = producerStorageRoot + producerDocRoot + "/" + mail_language +
537                                                                                                          publishPath + "/" + aid + ".txt";
538
539
540       File inputFile = new File(txtFilePath);
541       String content;
542
543       try{
544         FileReader in = new FileReader(inputFile);
545         StringWriter out = new StringWriter();
546         int c;
547         while ((c = in.read()) != -1)
548           out.write(c);
549         in.close();
550         content= out.toString();
551       }
552       catch (FileNotFoundException e){
553         throw new ServletModuleFailure("No text file found in " + txtFilePath, e);
554       }
555       catch (IOException e){
556         throw new ServletModuleFailure("Problem reading file in " + txtFilePath, e);
557       }
558       // add some headers
559       content = "To: " + to + "\nReply-To: "+ from + "\n" + content;
560       // put in the comment where it should go
561       if (comment != null) {
562         String commentTextToInsert = "\n\nAttached comment from " + from_name + ":\n" + comment;
563         try {
564           content=StringRoutines.performRegularExpressionReplacement(content,"!COMMENT!",commentTextToInsert);
565         }
566         catch (Throwable e){
567           throw new ServletModuleFailure("Problem doing regular expression replacement " + e.toString(), e);
568         }
569       }
570       else{
571         try {
572           content=StringRoutines.performRegularExpressionReplacement(content,"!COMMENT!","");
573         }
574         catch (Throwable e){
575           throw new ServletModuleFailure("Problem doing regular expression replacement " + e.toString(), e);
576         }
577       }
578
579       SMTPClient client=new SMTPClient();
580       try {
581         int reply;
582         client.connect(configuration.getString("ServletModule.OpenIndy.SMTPServer"));
583
584         reply = client.getReplyCode();
585
586         if (!SMTPReply.isPositiveCompletion(reply)) {
587           client.disconnect();
588           throw new ServletModuleExc("SMTP server refused connection.");
589         }
590
591         client.sendSimpleMessage(configuration.getString("ServletModule.OpenIndy.EmailIsFrom"), to, content);
592
593         client.disconnect();
594         //mission accomplished
595         deliver(req, res, mergeData, sentMailTemplate);
596       }
597       catch(IOException e) {
598         if(client.isConnected()) {
599           try {
600             client.disconnect();
601           } catch(IOException f) {
602             // do nothing
603           }
604         }
605         throw new ServletModuleFailure(e);
606       }
607     }
608   }
609
610
611   /*
612    * Method for querying a lucene index
613    */
614   public void search(HttpServletRequest req, HttpServletResponse res)
615       throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure {
616     try {
617       int increment=10;
618
619       HttpSession session = req.getSession(false);
620
621       String queryString="";
622
623       SimpleHash mergeData = new SimpleHash();
624
625       KeywordSearchTerm dateTerm = new KeywordSearchTerm("date_formatted","search_date","webdb_create_formatted","webdb_create_formatted","webdb_create_formatted");
626       UnIndexedSearchTerm whereTerm = new UnIndexedSearchTerm("","","","where","where");
627       TextSearchTerm creatorTerm = new TextSearchTerm("creator","search_creator","creator","creator","creator");
628       TextSearchTerm titleTerm = new TextSearchTerm("title","search_content","title","title","title");
629       TextSearchTerm descriptionTerm =  new TextSearchTerm("description","search_content","description","description","description");
630       ContentSearchTerm contentTerm = new ContentSearchTerm("content_data","search_content","content","","");
631       TopicSearchTerm topicTerm = new TopicSearchTerm();
632       ImagesSearchTerm imagesTerm = new ImagesSearchTerm();
633       AudioSearchTerm audioTerm = new AudioSearchTerm();
634       VideoSearchTerm videoTerm = new VideoSearchTerm();
635
636       //make the query available to subsequent iterations
637
638       for (Enumeration theParams = req.getParameterNames(); theParams.hasMoreElements() ;) {
639         String pName=(String)theParams.nextElement();
640         if (pName.startsWith("search_")){
641           mergeData.put(pName,new SimpleScalar(req.getParameter(pName)));
642         }
643       }
644
645       try{
646         mergeData.put("topics", topicsModule.getTopicsAsSimpleList());
647       }
648       catch(Throwable e) {
649         logger.debug("Can't get topics: " + e.toString());
650       }
651
652       String searchBackValue = req.getParameter("search_back");
653       String searchForwardValue = req.getParameter("search_forward");
654
655       if (searchBackValue != null){
656         int totalHits = ((Integer) session.getAttribute("numberOfHits")).intValue();
657         int newPosition=((Integer)session.getAttribute("positionInResults")).intValue()-increment;
658         if (newPosition<0)
659           newPosition=0;
660         if (newPosition >= totalHits)
661           newPosition=totalHits-1;
662         session.setAttribute("positionInResults",new Integer(newPosition));
663       }
664       else {
665         if (searchForwardValue != null){
666           int totalHits = ((Integer) session.getAttribute("numberOfHits")).intValue();
667           int newPosition=((Integer)session.getAttribute("positionInResults")).intValue()+increment;
668           if (newPosition<0)
669             newPosition=0;
670           if (newPosition >= totalHits)
671             newPosition=totalHits-1;
672
673           session.setAttribute("positionInResults",new Integer(newPosition));
674         }
675         else {
676           String indexPath=configuration.getString("IndexPath");
677
678
679           String creatorFragment = creatorTerm.makeTerm(req);
680           if (creatorFragment != null){
681             queryString = queryString + " +" + creatorFragment;
682           }
683
684           // search title, description, and content for something
685           // the contentTerm uses param "search_boolean" to combine its terms
686           String contentFragment = contentTerm.makeTerm(req);
687           if (contentFragment != null){
688             logger.debug("contentFragment: " + contentFragment);
689             queryString = queryString + " +" + contentFragment;
690           }
691
692           String topicFragment = topicTerm.makeTerm(req);
693           if (topicFragment != null){
694             queryString = queryString + " +" + topicFragment;
695           }
696
697           String imagesFragment = imagesTerm.makeTerm(req);
698           if (imagesFragment != null){
699             queryString = queryString + " +" + imagesFragment;
700           }
701
702           String audioFragment = audioTerm.makeTerm(req);
703           if (audioFragment != null){
704             queryString = queryString + " +" + audioFragment;
705           }
706
707           String videoFragment = videoTerm.makeTerm(req);
708           if (videoFragment != null){
709             queryString = queryString + " +" + videoFragment;
710           }
711
712           if (queryString == null || queryString == ""){
713             queryString = "";
714           }
715           else{
716             try{
717               Searcher searcher = null;
718               try {
719                 searcher = new IndexSearcher(indexPath);
720               }
721               catch(IOException e) {
722                 logger.debug("Can't open indexPath: " + indexPath);
723                 throw new ServletModuleExc("Problem with Search Index! : "+ e.toString());
724               }
725
726               Query query = null;
727               try {
728                 query = QueryParser.parse(queryString, "content", new StandardAnalyzer());
729               }
730               catch(Exception e) {
731                 searcher.close();
732                 logger.debug("Query don't parse: " + queryString);
733                 throw new ServletModuleExc("Problem with Query String! (was '"+queryString+"')");
734               }
735
736               Hits hits = null;
737               try {
738                 hits = searcher.search(query);
739               }
740               catch(IOException e) {
741                 searcher.close();
742                 logger.debug("Can't get hits: " + e.toString());
743                 throw new ServletModuleExc("Problem getting hits!");
744               }
745
746               int start = 0;
747               int end = hits.length();
748
749               String sortBy=req.getParameter("search_sort");
750               if (sortBy == null || sortBy.equals("")){
751                 throw new ServletModuleExc("Please let me sort by something!(missing search_sort)");
752               }
753
754               // here is where the documents will go for storage across sessions
755               ArrayList theDocumentsSorted = new ArrayList();
756
757               if (sortBy.equals("score")){
758                 for(int i = start; i < end; i++) {
759                   theDocumentsSorted.add(hits.doc(i));
760                 }
761               }
762               else{
763                 // then we'll sort by date!
764                 Map dateToPosition = new HashMap(end,1.0F); //we know how big it will be
765                 for(int i = start; i < end; i++) {
766                   String creationDate=(hits.doc(i)).get("creationDate");
767                   // do a little dance in case two contents created at the same second!
768                   if (dateToPosition.containsKey(creationDate)){
769                     ((ArrayList) (dateToPosition.get(creationDate))).add(new Integer(i));
770                   }
771                   else{
772                     ArrayList thePositions = new ArrayList();
773                     thePositions.add(new Integer(i));
774                     dateToPosition.put(creationDate,thePositions);
775                   }
776                 }
777                 Set keys = dateToPosition.keySet();
778                 ArrayList keyList= new ArrayList(keys);
779                 Collections.sort(keyList);
780                 if (sortBy.equals("date_desc")){
781                   Collections.reverse(keyList);
782                 }
783                 else{
784                   if (!sortBy.equals("date_asc")){
785                     throw new ServletModuleExc("don't know how to sort by: "+ sortBy);
786                   }
787                 }
788                 ListIterator keyTraverser = keyList.listIterator();
789                 while (keyTraverser.hasNext()){
790                   ArrayList positions = (ArrayList)dateToPosition.get((keyTraverser.next()));
791                   ListIterator positionsTraverser=positions.listIterator();
792                   while (positionsTraverser.hasNext()){
793                     theDocumentsSorted.add(hits.doc(((Integer)(positionsTraverser.next())).intValue()));
794                   }
795                 }
796               }
797
798               try{
799                 searcher.close();
800               }
801               catch (IOException e){
802                 logger.debug("Can't close searcher: " + e.toString());
803                 throw new ServletModuleFailure("Problem closing searcher(normal):" + e.getMessage(), e);
804               }
805
806
807               session.removeAttribute("numberOfHits");
808               session.removeAttribute("theDocumentsSorted");
809               session.removeAttribute("positionInResults");
810
811               session.setAttribute("numberOfHits",new Integer(end));
812               session.setAttribute("theDocumentsSorted",theDocumentsSorted);
813               session.setAttribute("positionInResults",new Integer(0));
814
815             }
816             catch (IOException e){
817               logger.debug("Can't close searcher: " + e.toString());
818               throw new ServletModuleFailure("Problem closing searcher: " + e.getMessage(), e);
819             }
820           }
821         }
822       }
823
824       try {
825         ArrayList theDocs = (ArrayList)session.getAttribute("theDocumentsSorted");
826         if (theDocs != null){
827
828           mergeData.put("numberOfHits", ((Integer)session.getAttribute("numberOfHits")).toString());
829           SimpleList theHits = new SimpleList();
830           int pIR=((Integer)session.getAttribute("positionInResults")).intValue();
831           int terminus;
832           int numHits=((Integer)session.getAttribute("numberOfHits")).intValue();
833
834           if (!(pIR+increment>=numHits)){
835             mergeData.put("hasNext","y");
836           }
837           if (pIR>0){
838             mergeData.put("hasPrevious","y");
839           }
840
841           if ((pIR+increment)>numHits){
842             terminus=numHits;
843           }
844           else {
845             terminus=pIR+increment;
846           }
847           for(int i = pIR; i < terminus; i++) {
848             SimpleHash h = new SimpleHash();
849             Document theHit = (Document)theDocs.get(i);
850             whereTerm.returnMeta(h,theHit);
851             creatorTerm.returnMeta(h,theHit);
852             titleTerm.returnMeta(h,theHit);
853             descriptionTerm.returnMeta(h,theHit);
854             dateTerm.returnMeta(h,theHit);
855             imagesTerm.returnMeta(h,theHit);
856             audioTerm.returnMeta(h,theHit);
857             videoTerm.returnMeta(h,theHit);
858             theHits.add(h);
859           }
860           mergeData.put("hits",theHits);
861         }
862       }
863       catch (Throwable e) {
864         logger.error("Can't iterate over hits: " + e.toString());
865
866         throw new ServletModuleFailure("Problem getting hits: " + e.getMessage(), e);
867       }
868
869       mergeData.put("queryString",queryString);
870       deliver(req,res,mergeData,searchResultsTemplate);
871     }
872     catch (NullPointerException n){
873       throw new ServletModuleFailure("Null Pointer: "+n.toString(), n);
874     }
875   }
876
877   /*
878    * Method for dynamically generating a pdf from a fo file
879    */
880   public void getpdf(HttpServletRequest req, HttpServletResponse res)
881       throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure {
882     String ID_REQUEST_PARAM = "id";
883     String language = req.getParameter("language");
884     String generateFO=configuration.getString("GenerateFO");
885     String generatePDF=configuration.getString("GeneratePDF");
886
887
888     //don't do anything if we are not making FO files, or if we are
889     //pregenerating PDF's
890     if (generateFO.equals("yes") && generatePDF.equals("no")){
891       //fop complains unless you do the logging this way
892       org.apache.log.Logger log = null;
893       Hierarchy hierarchy = Hierarchy.getDefaultHierarchy();
894       log = hierarchy.getLoggerFor("fop");
895       log.setPriority(Priority.WARN);
896
897       String producerStorageRoot=configuration.getString("Producer.StorageRoot");
898       String producerDocRoot=configuration.getString("Producer.DocRoot");
899       //      String templateDir=MirConfig.getPropWithHome("HTMLTemplateProcessor.Dir");
900       String xslSheet=configuration.getString("Producer.HTML2FOStyleSheet");
901       try {
902         String idParam = req.getParameter(ID_REQUEST_PARAM);
903         if (idParam != null) {
904           EntityContent contentEnt =
905             (EntityContent)contentModule.getById(idParam);
906           String publishPath = StringUtil.webdbDate2path(contentEnt.getValue("date"));
907           String foFile;
908
909           if (language == null){
910             foFile = producerStorageRoot + producerDocRoot + "/"
911               + publishPath  + idParam + ".fo";
912           }
913           else{
914             foFile = producerStorageRoot + producerDocRoot + "/"
915               + language + publishPath  + idParam + ".fo";
916           }
917           logger.debug("USING FILES" + foFile + " and " + xslSheet);
918           XSLTInputHandler input = new XSLTInputHandler(new File(foFile),
919                                                         new File(xslSheet));
920
921           ByteArrayOutputStream out = new ByteArrayOutputStream();
922           res.setContentType("application/pdf");
923
924           Driver driver = new Driver();
925           driver.setLogger(log);
926           driver.setRenderer(Driver.RENDER_PDF);
927           driver.setOutputStream(out);
928           driver.render(input.getParser(), input.getInputSource());
929
930           byte[] content = out.toByteArray();
931           res.setContentLength(content.length);
932           res.getOutputStream().write(content);
933           res.getOutputStream().flush();
934         }
935         else {
936           throw new ServletModuleExc("Missing id.");
937         }
938       }
939       catch (Exception ex) {
940         logger.error(ex.toString());
941         throw new ServletModuleFailure(ex);
942       }
943     } else {
944       throw new ServletModuleExc("Can't generate a PDF because the config tells me not to.");
945     }
946   }
947
948   protected String createOneTimePasswd(){
949     Random r = new Random();
950     int random = r.nextInt();
951     long l = System.currentTimeMillis();
952     l = (l*l*l*l)/random;
953     if(l<0) l = l * -1;
954     String returnString = ""+l;
955     return returnString.substring(5);
956   }
957
958
959   /* this is an overwritten method of ServletModule in order
960      to use different bundles for open and admin */
961   public void deliver(HttpServletRequest req, HttpServletResponse res,
962                       TemplateModelRoot rtm, TemplateModelRoot popups,
963                       String templateFilename) throws ServletModuleFailure
964   {
965     if (rtm == null) rtm = new SimpleHash();
966     try {
967       PrintWriter out = res.getWriter();
968       HTMLTemplateProcessor.process(res, templateFilename, rtm, popups, out,
969                                     getLocale(req), "bundles.open");
970       out.close();
971     }
972     catch (Throwable e) {
973       throw new ServletModuleFailure(e);
974     }
975   }
976 }
977
978
979