001: /*
002: * Copyright (c) JForum Team
003: * All rights reserved.
004: *
005: * Redistribution and use in source and binary forms,
006: * with or without modification, are permitted provided
007: * that the following conditions are met:
008: *
009: * 1) Redistributions of source code must retain the above
010: * copyright notice, this list of conditions and the
011: * following disclaimer.
012: * 2) Redistributions in binary form must reproduce the
013: * above copyright notice, this list of conditions and
014: * the following disclaimer in the documentation and/or
015: * other materials provided with the distribution.
016: * 3) Neither the name of "Rafael Steil" nor
017: * the names of its contributors may be used to endorse
018: * or promote products derived from this software without
019: * specific prior written permission.
020: *
021: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
022: * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
023: * EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
024: * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
025: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR
026: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
027: * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
028: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
029: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES
030: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
031: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
032: * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
033: * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
034: * IN CONTRACT, STRICT LIABILITY, OR TORT
035: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
036: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
037: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
038: *
039: * Created on Jan 18, 2005 3:08:48 PM
040: * The JForum Project
041: * http://www.jforum.net
042: */
043: package net.jforum.view.forum.common;
044:
045: import java.awt.image.BufferedImage;
046: import java.io.File;
047: import java.util.ArrayList;
048: import java.util.Arrays;
049: import java.util.Calendar;
050: import java.util.GregorianCalendar;
051: import java.util.HashMap;
052: import java.util.Iterator;
053: import java.util.List;
054: import java.util.Map;
055:
056: import net.jforum.SessionFacade;
057: import net.jforum.context.RequestContext;
058: import net.jforum.dao.AttachmentDAO;
059: import net.jforum.dao.DataAccessDriver;
060: import net.jforum.entities.Attachment;
061: import net.jforum.entities.AttachmentExtension;
062: import net.jforum.entities.AttachmentInfo;
063: import net.jforum.entities.Group;
064: import net.jforum.entities.Post;
065: import net.jforum.entities.QuotaLimit;
066: import net.jforum.entities.User;
067: import net.jforum.exceptions.AttachmentException;
068: import net.jforum.exceptions.AttachmentSizeTooBigException;
069: import net.jforum.exceptions.BadExtensionException;
070: import net.jforum.repository.SecurityRepository;
071: import net.jforum.security.SecurityConstants;
072: import net.jforum.util.I18n;
073: import net.jforum.util.MD5;
074: import net.jforum.util.image.ImageUtils;
075: import net.jforum.util.legacy.commons.fileupload.FileItem;
076: import net.jforum.util.preferences.ConfigKeys;
077: import net.jforum.util.preferences.SystemGlobals;
078:
079: import org.apache.log4j.Logger;
080:
081: /**
082: * @author Rafael Steil
083: * @version $Id: AttachmentCommon.java,v 1.36 2007/09/20 16:07:08 rafaelsteil Exp $
084: */
085: public class AttachmentCommon {
086: private static Logger logger = Logger
087: .getLogger(AttachmentCommon.class);
088: private static final String DENY_ALL = "*";
089:
090: private RequestContext request;
091: private AttachmentDAO am;
092: private boolean canProceed;
093: private Map filesToSave = new HashMap();
094:
095: public AttachmentCommon(RequestContext request, int forumId) {
096: this .request = request;
097: this .am = DataAccessDriver.getInstance().newAttachmentDAO();
098:
099: this .canProceed = SecurityRepository.canAccess(
100: SecurityConstants.PERM_ATTACHMENTS_ENABLED, Integer
101: .toString(forumId));
102: }
103:
104: public void preProcess() {
105: if (!this .canProceed) {
106: return;
107: }
108:
109: String t = this .request.getParameter("total_files");
110:
111: if (t == null || "".equals(t)) {
112: return;
113: }
114:
115: int total = Integer.parseInt(t);
116:
117: if (total < 1) {
118: return;
119: }
120:
121: if (total > SystemGlobals
122: .getIntValue(ConfigKeys.ATTACHMENTS_MAX_POST)) {
123: total = SystemGlobals
124: .getIntValue(ConfigKeys.ATTACHMENTS_MAX_POST);
125: }
126:
127: long totalSize = 0;
128: int userId = SessionFacade.getUserSession().getUserId();
129: Map extensions = this .am.extensionsForSecurity();
130:
131: for (int i = 0; i < total; i++) {
132: FileItem item = (FileItem) this .request
133: .getObjectParameter("file_" + i);
134:
135: if (item == null) {
136: continue;
137: }
138:
139: if (item.getName().indexOf('\000') > -1) {
140: logger.warn("Possible bad attachment (null char): "
141: + item.getName() + " - user_id: "
142: + SessionFacade.getUserSession().getUserId());
143: continue;
144: }
145:
146: UploadUtils uploadUtils = new UploadUtils(item);
147:
148: // Check if the extension is allowed
149: boolean containsExtension = extensions
150: .containsKey(uploadUtils.getExtension());
151: boolean denyAll = extensions.containsKey(DENY_ALL);
152:
153: boolean isAllowed = (!denyAll && !containsExtension)
154: || (containsExtension && extensions.get(
155: uploadUtils.getExtension()).equals(
156: Boolean.TRUE));
157:
158: if (!isAllowed) {
159: throw new BadExtensionException(I18n.getMessage(
160: "Attachments.badExtension",
161: new String[] { uploadUtils.getExtension() }));
162: }
163:
164: // Check comment length:
165: String comment = this .request.getParameter("comment_" + i);
166: if (comment.length() > 254) {
167: throw new AttachmentException("Comment too long.");
168: }
169:
170: Attachment a = new Attachment();
171: a.setUserId(userId);
172:
173: AttachmentInfo info = new AttachmentInfo();
174: info.setFilesize(item.getSize());
175: info.setComment(comment);
176: info.setMimetype(item.getContentType());
177:
178: // Get only the filename, without the path (IE does that)
179: String realName = this .stripPath(item.getName());
180:
181: info.setRealFilename(realName);
182: info.setUploadTimeInMillis(System.currentTimeMillis());
183:
184: AttachmentExtension ext = this .am
185: .selectExtension(uploadUtils.getExtension()
186: .toLowerCase());
187: if (ext.isUnknown()) {
188: ext.setExtension(uploadUtils.getExtension());
189: }
190:
191: info.setExtension(ext);
192: String savePath = this .makeStoreFilename(info);
193: info.setPhysicalFilename(savePath);
194:
195: a.setInfo(info);
196: filesToSave.put(uploadUtils, a);
197:
198: totalSize += item.getSize();
199: }
200:
201: // Check upload limits
202: QuotaLimit ql = this .getQuotaLimit(userId);
203: if (ql != null) {
204: if (ql.exceedsQuota(totalSize)) {
205: throw new AttachmentSizeTooBigException(
206: I18n
207: .getMessage(
208: "Attachments.tooBig",
209: new Integer[] {
210: new Integer(
211: ql
212: .getSizeInBytes() / 1024),
213: new Integer(
214: (int) totalSize / 1024) }));
215: }
216: }
217: }
218:
219: /**
220: * @param realName String
221: * @return String
222: */
223: public String stripPath(String realName) {
224: String separator = "/";
225: int index = realName.lastIndexOf(separator);
226:
227: if (index == -1) {
228: separator = "\\";
229: index = realName.lastIndexOf(separator);
230: }
231:
232: if (index > -1) {
233: realName = realName.substring(index + 1);
234: }
235:
236: return realName;
237: }
238:
239: public void insertAttachments(Post post) {
240: if (!this .canProceed) {
241: return;
242: }
243:
244: post.hasAttachments(this .filesToSave.size() > 0);
245:
246: for (Iterator iter = this .filesToSave.entrySet().iterator(); iter
247: .hasNext();) {
248: Map.Entry entry = (Map.Entry) iter.next();
249: Attachment a = (Attachment) entry.getValue();
250: a.setPostId(post.getId());
251:
252: String path = SystemGlobals
253: .getValue(ConfigKeys.ATTACHMENTS_STORE_DIR)
254: + "/" + a.getInfo().getPhysicalFilename();
255:
256: this .am.addAttachment(a);
257: ((UploadUtils) entry.getKey()).saveUploadedFile(path);
258:
259: if (this .shouldCreateThumb(a)) {
260: this .createSaveThumb(path);
261: }
262: }
263: }
264:
265: private boolean shouldCreateThumb(Attachment a) {
266: String extension = a.getInfo().getExtension().getExtension()
267: .toLowerCase();
268:
269: return SystemGlobals
270: .getBoolValue(ConfigKeys.ATTACHMENTS_IMAGES_CREATE_THUMB)
271: && ("jpg".equals(extension) || "jpeg".equals(extension)
272: || "gif".equals(extension) || "png"
273: .equals(extension));
274: }
275:
276: private void createSaveThumb(String path) {
277: try {
278: BufferedImage image = ImageUtils
279: .resizeImage(
280: path,
281: ImageUtils.IMAGE_JPEG,
282: SystemGlobals
283: .getIntValue(ConfigKeys.ATTACHMENTS_IMAGES_MAX_THUMB_W),
284: SystemGlobals
285: .getIntValue(ConfigKeys.ATTACHMENTS_IMAGES_MAX_THUMB_H));
286: ImageUtils.saveImage(image, path + "_thumb",
287: ImageUtils.IMAGE_JPEG);
288: } catch (Exception e) {
289: logger.error(e.toString(), e);
290: }
291: }
292:
293: public QuotaLimit getQuotaLimit(int userId) {
294: QuotaLimit ql = new QuotaLimit();
295: User u = DataAccessDriver.getInstance().newUserDAO()
296: .selectById(userId);
297:
298: for (Iterator iter = u.getGroupsList().iterator(); iter
299: .hasNext();) {
300: QuotaLimit l = this .am
301: .selectQuotaLimitByGroup(((Group) iter.next())
302: .getId());
303: if (l == null) {
304: continue;
305: }
306:
307: if (l.getSizeInBytes() > ql.getSizeInBytes()) {
308: ql = l;
309: }
310: }
311:
312: if (ql.getSize() == 0) {
313: return null;
314: }
315:
316: return ql;
317: }
318:
319: public void editAttachments(int postId, int forumId) {
320: // Allow removing the attachments at least
321: AttachmentDAO am = DataAccessDriver.getInstance()
322: .newAttachmentDAO();
323:
324: // Check for attachments to remove
325: List deleteList = new ArrayList();
326: String[] delete = null;
327: String s = this .request.getParameter("delete_attach");
328:
329: if (s != null) {
330: delete = s.split(",");
331: }
332:
333: if (delete != null) {
334: for (int i = 0; i < delete.length; i++) {
335: if (delete[i] != null && !delete[i].equals("")) {
336: int id = Integer.parseInt(delete[i]);
337: Attachment a = am.selectAttachmentById(id);
338:
339: am.removeAttachment(id, postId);
340:
341: String filename = SystemGlobals
342: .getValue(ConfigKeys.ATTACHMENTS_STORE_DIR)
343: + "/" + a.getInfo().getPhysicalFilename();
344:
345: File f = new File(filename);
346:
347: if (f.exists()) {
348: f.delete();
349: }
350:
351: // Check if we have a thumb to delete
352: f = new File(filename + "_thumb");
353:
354: if (f.exists()) {
355: f.delete();
356: }
357: }
358: }
359:
360: deleteList = Arrays.asList(delete);
361: }
362:
363: if (!SecurityRepository.canAccess(
364: SecurityConstants.PERM_ATTACHMENTS_ENABLED, Integer
365: .toString(forumId))
366: && !SecurityRepository
367: .canAccess(SecurityConstants.PERM_ATTACHMENTS_DOWNLOAD)) {
368: return;
369: }
370:
371: // Update
372: String[] attachIds = null;
373: s = this .request.getParameter("edit_attach_ids");
374: if (s != null) {
375: attachIds = s.split(",");
376: }
377:
378: if (attachIds != null) {
379: for (int i = 0; i < attachIds.length; i++) {
380: if (deleteList.contains(attachIds[i])
381: || attachIds[i] == null
382: || attachIds[i].equals("")) {
383: continue;
384: }
385:
386: int id = Integer.parseInt(attachIds[i]);
387: Attachment a = am.selectAttachmentById(id);
388: a.getInfo()
389: .setComment(
390: this .request
391: .getParameter("edit_comment_"
392: + id));
393:
394: am.updateAttachment(a);
395: }
396: }
397: }
398:
399: private String makeStoreFilename(AttachmentInfo a) {
400: Calendar c = new GregorianCalendar();
401: c.setTimeInMillis(System.currentTimeMillis());
402: c.get(Calendar.YEAR);
403:
404: int year = Calendar.getInstance().get(Calendar.YEAR);
405: int month = Calendar.getInstance().get(Calendar.MONTH) + 1;
406: int day = Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
407:
408: StringBuffer dir = new StringBuffer(256);
409: dir.append(year).append('/').append(month).append('/').append(
410: day).append('/');
411:
412: new File(SystemGlobals
413: .getValue(ConfigKeys.ATTACHMENTS_STORE_DIR)
414: + "/" + dir).mkdirs();
415:
416: return dir.append(
417: MD5.crypt(a.getRealFilename()
418: + System.currentTimeMillis())).append('_')
419: .append(SessionFacade.getUserSession().getUserId())
420: .append('.').append(a.getExtension().getExtension())
421: .append('_').toString();
422: }
423:
424: public List getAttachments(int postId, int forumId) {
425: if (!SecurityRepository
426: .canAccess(SecurityConstants.PERM_ATTACHMENTS_DOWNLOAD)
427: && !SecurityRepository.canAccess(
428: SecurityConstants.PERM_ATTACHMENTS_ENABLED,
429: Integer.toString(forumId))) {
430: return new ArrayList();
431: }
432:
433: return this .am.selectAttachments(postId);
434: }
435:
436: public boolean isPhysicalDownloadMode(int extensionGroupId) {
437: return this .am.isPhysicalDownloadMode(extensionGroupId);
438: }
439:
440: public void deleteAttachments(int postId, int forumId) {
441: // Attachments
442: List attachments = DataAccessDriver.getInstance()
443: .newAttachmentDAO().selectAttachments(postId);
444: StringBuffer attachIds = new StringBuffer();
445:
446: for (Iterator iter = attachments.iterator(); iter.hasNext();) {
447: Attachment a = (Attachment) iter.next();
448: attachIds.append(a.getId()).append(',');
449: }
450:
451: this .request.addOrReplaceParameter("delete_attach", attachIds
452: .toString());
453: this.editAttachments(postId, forumId);
454: }
455: }
|