001: /* ====================================================================
002: * The Jcorporate Apache Style Software License, Version 1.2 05-07-2002
003: *
004: * Copyright (c) 1995-2002 Jcorporate Ltd. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * 3. The end-user documentation included with the redistribution,
019: * if any, must include the following acknowledgment:
020: * "This product includes software developed by Jcorporate Ltd.
021: * (http://www.jcorporate.com/)."
022: * Alternately, this acknowledgment may appear in the software itself,
023: * if and wherever such third-party acknowledgments normally appear.
024: *
025: * 4. "Jcorporate" and product names such as "Expresso" must
026: * not be used to endorse or promote products derived from this
027: * software without prior written permission. For written permission,
028: * please contact info@jcorporate.com.
029: *
030: * 5. Products derived from this software may not be called "Expresso",
031: * or other Jcorporate product names; nor may "Expresso" or other
032: * Jcorporate product names appear in their name, without prior
033: * written permission of Jcorporate Ltd.
034: *
035: * 6. No product derived from this software may compete in the same
036: * market space, i.e. framework, without prior written permission
037: * of Jcorporate Ltd. For written permission, please contact
038: * partners@jcorporate.com.
039: *
040: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
041: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
042: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
043: * DISCLAIMED. IN NO EVENT SHALL JCORPORATE LTD OR ITS CONTRIBUTORS
044: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
045: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
046: * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
047: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
048: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
049: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
050: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
051: * SUCH DAMAGE.
052: * ====================================================================
053: *
054: * This software consists of voluntary contributions made by many
055: * individuals on behalf of the Jcorporate Ltd. Contributions back
056: * to the project(s) are encouraged when you make modifications.
057: * Please send them to support@jcorporate.com. For more information
058: * on Jcorporate Ltd. and its products, please see
059: * <http://www.jcorporate.com/>.
060: *
061: * Portions of this software are based upon other open source
062: * products and are subject to their respective licenses.
063: */
064:
065: package com.jcorporate.expresso.ext.controller;
066:
067: import com.jcorporate.expresso.core.controller.Block;
068: import com.jcorporate.expresso.core.controller.ControllerException;
069: import com.jcorporate.expresso.core.controller.ControllerRequest;
070: import com.jcorporate.expresso.core.controller.ControllerResponse;
071: import com.jcorporate.expresso.core.controller.DBController;
072: import com.jcorporate.expresso.core.controller.Output;
073: import com.jcorporate.expresso.core.controller.ServletControllerRequest;
074: import com.jcorporate.expresso.core.controller.State;
075: import com.jcorporate.expresso.core.controller.Transition;
076: import com.jcorporate.expresso.core.db.DBException;
077: import com.jcorporate.expresso.core.dbobj.SecuredDBObject;
078: import com.jcorporate.expresso.core.misc.DateTime;
079: import com.jcorporate.expresso.core.misc.EventHandler;
080: import com.jcorporate.expresso.core.misc.FileUtil;
081: import com.jcorporate.expresso.core.misc.RecordPaginator;
082: import com.jcorporate.expresso.core.misc.StringUtil;
083: import com.jcorporate.expresso.core.security.User;
084: import com.jcorporate.expresso.ext.dbobj.DownloadFiles;
085: import com.jcorporate.expresso.ext.dbobj.DownloadLog;
086: import com.jcorporate.expresso.ext.dbobj.RestrictedCountries;
087: import com.jcorporate.expresso.ext.dbobj.RestrictedOverrides;
088: import com.jcorporate.expresso.services.dbobj.MimeTypes;
089: import org.apache.log4j.Logger;
090:
091: import javax.servlet.http.HttpServletRequest;
092: import javax.servlet.http.HttpServletResponse;
093: import java.io.File;
094: import java.io.FileInputStream;
095: import java.io.FileNotFoundException;
096: import java.io.IOException;
097: import java.io.OutputStream;
098: import java.util.ArrayList;
099: import java.util.Enumeration;
100: import java.util.Iterator;
101: import java.util.StringTokenizer;
102: import java.util.Vector;
103:
104: /**
105: * The download controller provides a ready-to-use component for people to download
106: * files through. See DBObject for the data definition
107: * objects that support this controller
108: * <p/>
109: * Features supported include:
110: * <ul>
111: * <li>Filter by a workspace view with the "project" parameters</li>
112: * <li>Automatic Permission settings for which groups can download which files</li>
113: * <li><b>new</b> Automatic download restrictions for cryptographic exports</li>
114: * <li>Automatic Redirection to other higher-speed servers such as an http or ftp
115: * server for freely available downloads</li>
116: * </ul>
117: *
118: * @author Michael Rimov
119: * @see com.jcorporate.expresso.ext.dbobj.DownloadFiles
120: * @see com.jcorporate.expresso.services.dbobj.MimeTypes
121: * @see com.jcorporate.expresso.ext.dbobj.DownloadLog
122: */
123: public class Download extends DBController {
124: private static Logger log = Logger.getLogger(Download.class);
125:
126: public Download() {
127: super ();
128:
129: State prompt = new State("list", this
130: .getString("List_Downloadable"));
131: prompt.addOptionalParameter("project");
132: prompt.addOptionalParameter("file"); //Convenience parameter
133: //allows a straight file name download
134: addState(prompt);
135:
136: State begin = new State("begin", this
137: .getString("Begin_Downloading_A"));
138: begin.addRequiredParameter("file");
139: addState(begin);
140:
141: State download = new State("download", this
142: .getString("Download_A_File"));
143: download.addRequiredParameter("file");
144: addState(download);
145: setInitialState("list");
146:
147: State s = new State("viewNotes", "View_Notes");
148: s.addRequiredParameter("file");
149: this .addState(s);
150:
151: this
152: .setSchema(com.jcorporate.expresso.core.ExpressoSchema.class);
153: }
154:
155: /**
156: * Convenience method to retrieve the download file based upon the file
157: * parameter
158: *
159: * @param request The <code>ControllerRequest</code> object
160: * @param u the User requesting
161: * @return the DownloadFile DataObject representing the file parameter
162: * requested.
163: * @throws ControllerException upon illegal inputs
164: */
165: protected DownloadFiles getThisDownloadFile(
166: ControllerRequest request, User u)
167: throws ControllerException {
168: try {
169: DownloadFiles this File = new DownloadFiles(
170: SecuredDBObject.SYSTEM_ACCOUNT);
171: this File.setDataContext(request.getDataContext());
172: this File.setField("FileNumber", request
173: .getParameter("file"));
174:
175: if (!this File.find()) {
176: logInvalidFileRequest(request, u);
177: throw new ControllerException(
178: "Invalid File Number Request");
179: }
180:
181: return this File;
182: } catch (DBException ex) {
183: throw new ControllerException(
184: "Database communication error", ex);
185: }
186: }
187:
188: /**
189: * Starts a download for a file. Will provide the capability for client
190: * side redirects to download the file from a public server
191: *
192: * @param request The controller request object handed to us by
193: * the framework
194: * @param response The controller Response that this class fills out.
195: * @return The generated ControllerResponse.
196: * @throws ControllerException if there's an error with the processing of the
197: * request.
198: */
199: protected ControllerResponse runBeginState(
200: ControllerRequest request, ControllerResponse response)
201: throws ControllerException {
202: try {
203: User myUser = User.getUserFromId(request.getUid(), request
204: .getDataContext());
205: DownloadFiles this File = getThisDownloadFile(request,
206: myUser);
207: String fileName = this File.getField("FilePathName");
208:
209: //
210: //Check if allowed
211: //
212: checkIsAllowed(request, myUser, this File);
213:
214: File checkFile = new File(fileName);
215: if (checkFile == null || !checkFile.exists()) {
216: logInvalidFileRequest(request, myUser);
217: } /* if the file did not exist */
218:
219: long fileLength = checkFile.length();
220:
221: if (fileLength > 0) {
222: response.addOutput(new Output("fileLength", Long
223: .toString(fileLength)
224: + " bytes"));
225: response.addOutput(new Output("downloadTime",
226: getDownloadTime(response, fileLength)));
227: } else {
228: response.addOutput(new Output("fileLength", "unknown"));
229: response
230: .addOutput(new Output("downloadTime", "unknown"));
231: }
232:
233: response.addOutput(new Output("fileName",
234: getFriendlyName(this File)));
235:
236: //
237: // If a download URL exists, then we provide an output transition
238: // to that state. Otherwise, we provide a transition to the
239: // download state
240: //
241: String downloadURL = StringUtil.notNull(this File
242: .getField("FileURL"));
243:
244: if (downloadURL.length() > 0) {
245: response.addOutput(new Output("downloadURL",
246: downloadURL));
247: response.addOutput(new Output("downloadLabel", response
248: .getString("Click_Here_If")));
249:
250: if (!(request instanceof ServletControllerRequest)) {
251: throw new ControllerException(
252: "runDownloadState(): Request must be"
253: + " of class ServletControllerRequest");
254: }
255:
256: ServletControllerRequest req = (ServletControllerRequest) request;
257: HttpServletRequest hreq = (HttpServletRequest) req
258: .getServletRequest();
259: String eventString = ("User '" + request.getUser()
260: + "' (" + myUser.getDisplayName() + "), at "
261: + myUser.getEmail()
262: + " has just downloaded file '" + fileName
263: + "' (" + this File.getField("Descrip") + ")");
264:
265: EventHandler.Event(request.getDataContext(),
266: "DOWNLOAD", eventString, true);
267:
268: DownloadLog dll = new DownloadLog(
269: SecuredDBObject.SYSTEM_ACCOUNT);
270: dll.setDataContext(request.getDataContext());
271: dll.setField("ExpUid", request.getUid());
272: dll.setField("FileNumber", this File
273: .getField("FileNumber"));
274: dll.setField("FilePathName", this File
275: .getField("FilePathName"));
276: dll.setField("Downloaded", DateTime
277: .getDateTimeForDB(request.getDataContext()));
278: dll.setField("IPNumber", hreq.getRemoteAddr());
279: dll.add();
280: } else {
281: Transition t = new Transition("download", this );
282: t.addParam("file", request.getParameter("file"));
283: t.setLabel(response.getString("Click_Here_If"));
284: response.addTransition(t);
285: }
286: } catch (DBException dbe) {
287: log.error("DBException in runBeginState", dbe);
288: throw new ControllerException(dbe);
289: }
290:
291: return response;
292: }
293:
294: /**
295: * Lists the files available for download. Source code originally grabbed
296: * from the DownloadServlet and converted for controller use. Also
297: *
298: * @param request The controller request object handed to us by
299: * the framework
300: * @param response The controller Response that this class fills out.
301: * @return The generated ControllerResponse.
302: * @throws ControllerException if there's an error with the processing of the
303: * request.
304: * @see com.jcorporate.expresso.ext.dbobj.DownloadFiles
305: * for more information
306: */
307: protected ControllerResponse runListState(
308: ControllerRequest request, ControllerResponse response)
309: throws ControllerException {
310: //
311: //If a file has already been requested, simply start download so you can
312: //have URLs like so:
313: //http://localhost/expresso/Download.do?file=30
314: //
315: String fileNumParam = StringUtil.notNull(request
316: .getParameter("file"));
317:
318: if (fileNumParam.length() > 0) {
319: return runBeginState(request, response);
320: }
321: try {
322: response.addOutput(new Output("Heading", response
323: .getString("Files_Available_For")));
324:
325: DownloadFiles dl = new DownloadFiles(request);
326: dl.setField("IsActive", "Y");
327:
328: DownloadFiles oneDownloadFile = null;
329: String project = StringUtil.notNull(request
330: .getParameter("project"));
331:
332: if (!project.equals("")) {
333: dl.setField("Project", project);
334: }
335:
336: User myUser = User.getUserFromId(request.getUid(), request
337: .getDataContext());
338:
339: RecordPaginator paginator = new RecordPaginator();
340: paginator.setCountRecords(true);
341: paginator.setPageNumber(request);
342:
343: ArrayList retrieveList = paginator.searchAndRetrieve(dl,
344: DownloadFiles.FLD_LAST_UPDATED + " desc");
345:
346: if (retrieveList.size() == 0) {
347: response.addOutput(new Output("NoFiles", response
348: .getString("No_Files_Are")));
349:
350: return response;
351: }
352:
353: /* get each of the database objects for this schema */
354: Block matrix = new Block("downloadMatrix");
355: matrix.setAttribute("table", "Y");
356: matrix.setAttribute("header-row", response
357: .getString("FileNumber_File"));
358: response.addBlock(matrix);
359:
360: //Add Next Icon
361: if (paginator.isMoreRecords()) {
362: Transition t = new Transition("list", this );
363: t.setName("nextBtn");
364: t.setOwnerController(this .getClass().getName());
365:
366: if (project != null && project.length() > 0) {
367: t.addParam("project", project);
368: }
369:
370: t.setLabel(response.getString("List_Next_Page_Of"));
371: t.addParam("page", Integer.toString((paginator
372: .getPageNumber() + 1)));
373: response.add(t);
374: }
375: //Add Previous Icon
376: if (paginator.isPreviousRecords()) {
377: Transition t = new Transition("list", this );
378: t.setOwnerController(this .getClass().getName());
379: t.setName("prevBtn");
380:
381: if (project != null && project.length() > 0) {
382: t.addParam("project", project);
383: }
384:
385: t.addParam("page", Integer.toString((paginator
386: .getPageNumber() - 1)));
387: t.setLabel(response.getString("List_Previous_Page_Of"));
388: response.add(t);
389: }
390:
391: for (Iterator i = retrieveList.iterator(); i.hasNext();) {
392: oneDownloadFile = (DownloadFiles) i.next();
393:
394: if (isAllowed(request, oneDownloadFile, myUser)) {
395: Block oneRow = new Block("oneRow");
396: String value = null;
397: oneRow.setAttribute("row", "Y");
398:
399: String fileNumber = StringUtil
400: .notNull(oneDownloadFile
401: .getField("FileNumber"));
402:
403: if (fileNumber.length() == 0) {
404: throw new ControllerException(response
405: .getString("Retrieved_an_invalid"));
406: }
407:
408: String label = getFriendlyName(oneDownloadFile);
409: String pathName = StringUtil
410: .notNull(oneDownloadFile
411: .getField("FilePathName"));
412: String urlName = StringUtil.notNull(oneDownloadFile
413: .getField("FileURL"));
414:
415: if (label.length() == 0) {
416: if (pathName.length() > 0) {
417: label = FileUtil.getBase(pathName);
418: } else if (urlName.length() > 0) {
419: label = FileUtil.getBase(urlName);
420: } else {
421: throw new ControllerException(
422: "Error, must have either a "
423: + "file path or a file URL in the database");
424: }
425: }
426:
427: Transition t = new Transition("begin", this );
428: t.addParam("file", fileNumber);
429: t.setLabel(label);
430: t.setName("downloadLink");
431: t.setOwnerController(this .getClass().getName());
432: oneRow.add(t);
433: value = oneDownloadFile.getField("Descrip");
434:
435: if (value != null && value.length() > 0) {
436: oneRow.add(new Output("Descrip", value));
437: }
438:
439: value = oneDownloadFile
440: .getField(DownloadFiles.FLD_DL_NOTES);
441:
442: if (value != null && value.length() > 0) {
443: Transition viewNotes = new Transition(
444: "viewNotes", this );
445: viewNotes.addParam("file", fileNumber);
446: oneRow.add(viewNotes);
447: }
448:
449: value = oneDownloadFile
450: .getField(DownloadFiles.FLD_DL_NOTES);
451:
452: if (value != null && value.length() > 0) {
453: oneRow.add(new Output("Notes", value));
454: }
455:
456: oneRow.add(new Output("LastUpdated",
457: oneDownloadFile.getField("LastUpdated")));
458:
459: File checkFile = new File(oneDownloadFile
460: .getField("FilePathName"));
461: int tempLength = (int) checkFile.length();
462:
463: //Set the content length if we can cope with it. This will have
464: //a max length of 2 Gb.
465: if (tempLength > 0) {
466: oneRow.add(new Output("FileLength", Integer
467: .toString(tempLength)
468: + " bytes"));
469: } else {
470: oneRow.add(new Output("FileLength", "unknown"));
471: }
472:
473: MimeTypes mimeType = new MimeTypes(request);
474: mimeType.setField("MimeNumber", oneDownloadFile
475: .getField("MimeNumber"));
476:
477: if (mimeType.find()) {
478: oneRow.add(new Output("IconURL", mimeType
479: .getIconURL()));
480: }
481:
482: matrix.add(oneRow);
483: } /* if allowed */
484:
485: } /* for each file listed */
486:
487: } catch (DBException de) {
488: throw new ControllerException("Download.runListState()", de);
489: }
490:
491: return response;
492: }
493:
494: /**
495: * Returns the file actually requested by the user. Records the download
496: * as well
497: *
498: * @param controllerRequest The controller request object handed to us by
499: * the framework
500: * @param controllerResponse The controller Response that this class fills out.
501: * @return The generated ControllerResponse.
502: * @throws ControllerException if there's an error with the processing of the
503: * request.
504: */
505: protected ControllerResponse runDownloadState(
506: ControllerRequest controllerRequest,
507: ControllerResponse controllerResponse)
508: throws ControllerException {
509: String fileName = ("no name");
510: controllerResponse.setCustomResponse(true);
511:
512: if (!(controllerRequest instanceof ServletControllerRequest)) {
513: throw new ControllerException(
514: "runDownloadState(): Request must be"
515: + " of class ServletControllerRequest");
516: }
517:
518: ServletControllerRequest req = (ServletControllerRequest) controllerRequest;
519: HttpServletRequest request = (HttpServletRequest) req
520: .getServletRequest();
521: HttpServletResponse response = (HttpServletResponse) req
522: .getServletResponse();
523:
524: response.reset();
525: OutputStream toClient = null;
526:
527: try {
528: String fileNumber = StringUtil.notNull(controllerRequest
529: .getParameter("file"));
530: User myUser = User.getUserFromId(
531: controllerRequest.getUid(), controllerRequest
532: .getDataContext());
533:
534: if (log.isInfoEnabled()) {
535: log.info("User '" + controllerRequest.getUser() + "' ("
536: + myUser.getLoginName()
537: + ") requesting download of file number '"
538: + fileNumber + "'");
539: }
540:
541: DownloadFiles this File = this .getThisDownloadFile(
542: controllerRequest, myUser);
543:
544: fileName = this File
545: .getField(DownloadFiles.FLD_FILE_PATH_NAME);
546:
547: checkIsAllowed(controllerRequest, myUser, this File);
548:
549: File checkFile = new File(fileName);
550:
551: if (!checkFile.exists()) {
552: logInvalidFileRequest(controllerRequest, myUser);
553: } /* if the file did not exist */
554:
555: StringTokenizer stfn = new StringTokenizer(fileName, "/");
556: String baseName = null;
557:
558: while (stfn.hasMoreTokens()) {
559: baseName = stfn.nextToken();
560: }
561:
562: response.setHeader("Content-Disposition",
563: "inline;filename=" + baseName);
564:
565: String eventString = ("User '"
566: + controllerRequest.getUser() + "' ("
567: + myUser.getDisplayName() + "), at "
568: + myUser.getEmail() + " has just downloaded file '"
569: + fileName + "' (" + this File.getField("Descrip") + ")");
570:
571: EventHandler.Event(controllerRequest.getDataContext(),
572: "DOWNLOAD", eventString, true);
573:
574: DownloadLog dll = new DownloadLog(
575: SecuredDBObject.SYSTEM_ACCOUNT);
576: dll.setDataContext(controllerRequest.getDataContext());
577: dll.setField("ExpUid", controllerRequest.getUid());
578: dll.setField("FileNumber", fileNumber);
579: dll.setField("FilePathName", fileName);
580: dll.setField("Downloaded", DateTime
581: .getDateTimeForDB(controllerRequest
582: .getDataContext()));
583: dll.setField("IPNumber", request.getRemoteAddr());
584: dll.add();
585:
586: String mimeNumber = this File.getField("MimeNumber");
587:
588: if (mimeNumber == null) {
589: response.setHeader("Content-Type",
590: "application/x-unknown");
591: } else {
592: try {
593: MimeTypes contentType = new MimeTypes(
594: SecuredDBObject.SYSTEM_ACCOUNT);
595: contentType.setField("MimeNumber", mimeNumber);
596: contentType.retrieve();
597: // response.setContentType(contentType.getField("MimeType"));
598: response.setHeader("Content-Type", contentType
599: .getField("MimeType"));
600: } catch (DBException ex) {
601: response.setHeader("Content-Type",
602: "application/x-unknown");
603: // response.setContentType("application/x-unknown");
604: }
605: }
606:
607: int tempLength = (int) checkFile.length();
608:
609: //Set the content length if we can cope with it. This will have
610: //a max length of 2 Gb.
611: if (tempLength > 0) {
612: response.setContentLength(tempLength);
613: }
614:
615: toClient = response.getOutputStream();
616: returnFile(fileName, toClient);
617: // toClient.close();
618: } catch (DBException dbe) {
619: throw new ControllerException(
620: "DownloadController.runDownloadState", dbe);
621: } catch (Exception de) {
622: if (de instanceof IOException) {
623: log.error("Download IO Exception:", de);
624: } else {
625: throw new ControllerException(
626: "DownloadController.runDownloadState", de);
627: }
628: } finally {
629:
630: /* unload this servlet completely */
631: if (toClient != null) {
632: try {
633: toClient.flush();
634: } catch (java.io.IOException ioe) {
635: log.debug("Error flushing client stream", ioe);
636: }
637: }
638: }
639:
640: return controllerResponse;
641: }
642:
643: /**
644: * Sends the contents of the specified file to the output stream
645: *
646: * @param filename the file to send
647: * @param out the output stream to write the file
648: * @throws FileNotFoundException if the file does not exist
649: * @throws IOException if an I/O error occurs
650: */
651: protected void returnFile(String filename, OutputStream out)
652: throws FileNotFoundException, IOException {
653:
654: // A FileInputStream is for bytes
655: FileInputStream fis = null;
656:
657: try {
658: fis = new FileInputStream(filename);
659: FileUtil.copyStream(fis, out);
660:
661: // byte[] buf = new byte[4 * 1024]; // 4K buffer
662: // int bytesRead;
663: //
664: // while ((bytesRead = fis.read(buf)) != -1) {
665: // out.write(buf, 0, bytesRead);
666: // }
667: } finally {
668: if (fis != null) {
669: fis.close();
670: }
671: }
672:
673: } /* returnFile(String, OutputStream) */
674:
675: /**
676: * Is it allowed for this user to download this particular file?
677: *
678: * @param request The Controller Request object passed to the controller state handler
679: * @param oneFile The download file definition
680: * @param myUser The user making the controller request.
681: * @return true if the file is allowed
682: * @throws DBException upon database access error
683: */
684: protected boolean isAllowed(ControllerRequest request,
685: DownloadFiles oneFile, User myUser) throws DBException {
686: boolean foundGroupName = false;
687: Vector groupList = myUser.getGroups();
688: String allowedGroup = oneFile.getField("GroupName");
689:
690: if (allowedGroup == null || allowedGroup.length() == 0) {
691: throw new DBException(
692: "No allowed download groups for this file");
693: }
694: /* now see if the user is allowed to get to that file */
695: for (Enumeration e = groupList.elements(); e.hasMoreElements();) {
696: String oneGroup = (String) e.nextElement();
697:
698: if (oneGroup
699: .equalsIgnoreCase(oneFile.getField("GroupName"))) {
700: foundGroupName = true;
701: }
702: } /* for each group this user belongs to */
703:
704: if (foundGroupName == true) {
705:
706: //
707: //Check if this is a restricted download and if it is, check to make
708: //sure the client can download the files.
709: //
710: boolean isRestricted = oneFile
711: .getFieldBoolean("IsRestricted");
712: if (isRestricted) {
713: String remoteIP = ((ServletControllerRequest) request)
714: .getServletRequest().getRemoteAddr();
715:
716: if (remoteIP.equals("127.0.0.1")) {
717: log
718: .warn("Got a restricted download request from localhost."
719: + " Please make sure that remote connection ip addresses"
720: + " are getting through the servlet connector properly");
721:
722: return true;
723: } else {
724:
725: //
726: //First check the override system for this
727: //
728: RestrictedOverrides overRides = new RestrictedOverrides(
729: request);
730: int overRideValue = overRides.isAllowed(myUser);
731:
732: switch (overRideValue) {
733: case RestrictedOverrides.OVERRIDE_ALLOWED:
734: return true;
735:
736: case RestrictedOverrides.OVERRIDE_DENIED:
737: return false;
738:
739: case RestrictedOverrides.OVERRIDE_NOT_FOUND:
740:
741: //Continue checking against override country
742: break;
743:
744: default:
745: throw new DBException(
746: "RestrictedOverrides."
747: + "isAllowed() returned unknown integer value: "
748: + overRideValue);
749: }
750:
751: RestrictedCountries rc = new RestrictedCountries(
752: request);
753:
754: if (!rc
755: .isRestricted(((ServletControllerRequest) request)
756: .getServletRequest()
757: .getRemoteAddr())) {
758: return true;
759: }
760: }
761: } else {
762: return true;
763: }
764: }
765:
766: return false;
767: }
768:
769: /**
770: * Sets off the system event for an invalid file number requested.
771: *
772: * @param request The Controller Request object sent to this controller for
773: * the state handler.
774: * @param myUser The logged-in definition of the user currently logged in.
775: * @throws ControllerException if the download file number was invalid.
776: */
777: protected void logInvalidFileRequest(ControllerRequest request,
778: User myUser) throws ControllerException {
779: String eventString = null;
780:
781: try {
782: eventString = ("User '" + request.getUser() + "' ("
783: + myUser.getDisplayName()
784: + ") attempted to downloaded file number'"
785: + request.getParameter("file") + "', but " + "the record did not exist.");
786: EventHandler.Event(request.getDataContext(), "DOWNLOAD",
787: eventString, false);
788: throw new ControllerException(
789: "There is no download file number '"
790: + request.getParameter("file") + "'");
791: } catch (DBException de) {
792: log.error("Could not trigger event:"
793: + StringUtil.notNull(eventString) + ":", de);
794: }
795: }
796:
797: /**
798: * Returns the friendly download name
799: *
800: * @param oneDownloadFile The download file definition object
801: * @return java.lang.String A friendly name for display on the Download listing
802: * page.
803: * @throws ControllerException if the record is mal-formed
804: * @throws DBException if there's an error accessing the database.
805: * @see com.jcorporate.expresso.ext.dbobj.DownloadFiles
806: */
807: protected String getFriendlyName(DownloadFiles oneDownloadFile)
808: throws ControllerException, DBException {
809: String label = StringUtil.notNull(oneDownloadFile
810: .getField("DisplayName"));
811: String pathName = StringUtil.notNull(oneDownloadFile
812: .getField("FilePathName"));
813: String urlName = StringUtil.notNull(oneDownloadFile
814: .getField("FileURL"));
815:
816: if (label.length() == 0) {
817: if (pathName.length() > 0) {
818: label = FileUtil.getBase(pathName);
819: } else if (urlName.length() > 0) {
820: label = FileUtil.getBase(urlName);
821: } else {
822: throw new ControllerException(
823: "Error, must have either a "
824: + "file path or a file URL in the database");
825: }
826: }
827:
828: return label;
829: }
830:
831: /**
832: * Returns a string estimating download time at 28.8k
833: * This function assumes a download rate of 5 Mb / minute
834: *
835: * @param response The controller response object to get the requesting
836: * user's Locale.
837: * @param fileLength The length of the file to calculate.
838: * @return java.lang.String estimating the download time at 28.8k
839: * @throws ControllerException if the download time is unable to get the
840: * internationalized strings for Minutes and Seconds.
841: */
842: protected String getDownloadTime(ControllerResponse response,
843: long fileLength) throws ControllerException {
844: long downloadSeconds = fileLength / 3333;
845:
846: if (downloadSeconds >= 120) {
847: return (Long.toString(downloadSeconds / 60) + response
848: .getString("Minutes"));
849: } else {
850: return (Long.toString(downloadSeconds) + response
851: .getString("Seconds"));
852: }
853: }
854:
855: /**
856: * Checks file permissions and throws an Exception, and logs an event
857: * if the user does not have permission to run.
858: *
859: * @param request the ControllerRequest object
860: * @param u the user requesting the file
861: * @param file the file to download
862: * @throws ControllerException if the file is not allowed for the given
863: * user.
864: */
865: protected void checkIsAllowed(ControllerRequest request, User u,
866: DownloadFiles file) throws ControllerException {
867: try {
868: //
869: //Check if allowed
870: //
871: if (!isAllowed(request, file, u)) {
872: String fileName = file
873: .getField(DownloadFiles.FLD_DISPLAY_NAME);
874: String eventString = ("User '" + request.getUser()
875: + "' (" + u.getDisplayName()
876: + ") attempted to downloaded file '" + fileName
877: + "' (" + file.getField("Descrip") + "), but " + "did not have permission to do so.");
878:
879: EventHandler.Event(request.getDataContext(),
880: "DOWNLOAD", eventString, false);
881: throw new ControllerException("You do not have "
882: + " permission to download '" + fileName + "'");
883: } /* if file not allowed */
884: } catch (DBException ex) {
885: throw new ControllerException(
886: "Database communication error.", ex);
887: }
888:
889: }
890:
891: /**
892: * Returns title of this controller
893: *
894: * @return java.lang.String The Title of the controller
895: */
896: public String getTitle() {
897: return "Download Controller";
898: }
899:
900: /**
901: * View the notes associated with the download.
902: *
903: * @param request The controller request object handed to us by
904: * the framework
905: * @param response The controller Response that this class fills out.
906: * @throws ControllerException upon error [data access or otherwise]
907: */
908: protected void runViewNotesState(ControllerRequest request,
909: ControllerResponse response) throws ControllerException {
910:
911: try {
912: User u = User.getUserFromId(request.getUid(), request
913: .getDataContext());
914: DownloadFiles df = getThisDownloadFile(request, u);
915: checkIsAllowed(request, u, df);
916:
917: response.addOutput(new Output("notes", df
918: .getField(DownloadFiles.FLD_DL_NOTES)));
919: } catch (DBException ex) {
920: throw new ControllerException("Database Access Error", ex);
921: }
922: }
923: }
|