/* * Copyright (c) JForum Team * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided * that the following conditions are met: * * 1) Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * 2) Redistributions in binary form must reproduce the * above copyright notice, this list of conditions and * the following disclaimer in the documentation and/or * other materials provided with the distribution. * 3) Neither the name of "Rafael Steil" nor * the names of its contributors may be used to endorse * or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE * * Created on Jan 18, 2005 3:08:48 PM * The JForum Project * http://www.jforum.net */ package net.jforum.view.forum.common; import java.awt.image.BufferedImage; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import net.jforum.SessionFacade; import net.jforum.context.RequestContext; import net.jforum.dao.AttachmentDAO; import net.jforum.dao.DataAccessDriver; import net.jforum.entities.Attachment; import net.jforum.entities.AttachmentExtension; import net.jforum.entities.AttachmentInfo; import net.jforum.entities.Group; import net.jforum.entities.Post; import net.jforum.entities.QuotaLimit; import net.jforum.entities.User; import net.jforum.exceptions.AttachmentException; import net.jforum.exceptions.AttachmentSizeTooBigException; import net.jforum.exceptions.BadExtensionException; import net.jforum.repository.SecurityRepository; import net.jforum.security.SecurityConstants; import net.jforum.util.I18n; import net.jforum.util.MD5; import net.jforum.util.image.ImageUtils; import net.jforum.util.legacy.commons.fileupload.FileItem; import net.jforum.util.preferences.ConfigKeys; import net.jforum.util.preferences.SystemGlobals; import org.apache.log4j.Logger; /** * @author Rafael Steil * @version $Id: AttachmentCommon.java,v 1.36 2007/09/20 16:07:08 rafaelsteil Exp $ */ public class AttachmentCommon { private static Logger logger = Logger.getLogger(AttachmentCommon.class); private static final String DENY_ALL = "*"; private RequestContext request; private AttachmentDAO am; private boolean canProceed; private Map filesToSave = new HashMap(); public AttachmentCommon(RequestContext request, int forumId) { this.request = request; this.am = DataAccessDriver.getInstance().newAttachmentDAO(); this.canProceed = SecurityRepository.canAccess(SecurityConstants.PERM_ATTACHMENTS_ENABLED, Integer.toString(forumId)); } public void preProcess() { if (!this.canProceed) { return; } String t = this.request.getParameter("total_files"); if (t == null || "".equals(t)) { return; } int total = Integer.parseInt(t); if (total < 1) { return; } if (total > SystemGlobals.getIntValue(ConfigKeys.ATTACHMENTS_MAX_POST)) { total = SystemGlobals.getIntValue(ConfigKeys.ATTACHMENTS_MAX_POST); } long totalSize = 0; int userId = SessionFacade.getUserSession().getUserId(); Map extensions = this.am.extensionsForSecurity(); for (int i = 0; i < total; i++) { FileItem item = (FileItem)this.request.getObjectParameter("file_" + i); if (item == null) { continue; } if (item.getName().indexOf('\000') > -1) { logger.warn("Possible bad attachment (null char): " + item.getName() + " - user_id: " + SessionFacade.getUserSession().getUserId()); continue; } UploadUtils uploadUtils = new UploadUtils(item); // Check if the extension is allowed boolean containsExtension = extensions.containsKey(uploadUtils.getExtension()); boolean denyAll = extensions.containsKey(DENY_ALL); boolean isAllowed = (!denyAll && !containsExtension) || (containsExtension && extensions.get(uploadUtils.getExtension()).equals(Boolean.TRUE)); if (!isAllowed) { throw new BadExtensionException(I18n.getMessage("Attachments.badExtension", new String[] { uploadUtils.getExtension() })); } // Check comment length: String comment = this.request.getParameter("comment_" + i); if (comment.length() > 254) { throw new AttachmentException("Comment too long."); } Attachment a = new Attachment(); a.setUserId(userId); AttachmentInfo info = new AttachmentInfo(); info.setFilesize(item.getSize()); info.setComment(comment); info.setMimetype(item.getContentType()); // Get only the filename, without the path (IE does that) String realName = this.stripPath(item.getName()); info.setRealFilename(realName); info.setUploadTimeInMillis(System.currentTimeMillis()); AttachmentExtension ext = this.am.selectExtension(uploadUtils.getExtension().toLowerCase()); if (ext.isUnknown()) { ext.setExtension(uploadUtils.getExtension()); } info.setExtension(ext); String savePath = this.makeStoreFilename(info); info.setPhysicalFilename(savePath); a.setInfo(info); filesToSave.put(uploadUtils, a); totalSize += item.getSize(); } // Check upload limits QuotaLimit ql = this.getQuotaLimit(userId); if (ql != null) { if (ql.exceedsQuota(totalSize)) { throw new AttachmentSizeTooBigException(I18n.getMessage("Attachments.tooBig", new Integer[] { new Integer(ql.getSizeInBytes() / 1024), new Integer((int)totalSize / 1024) })); } } } /** * @param realName String * @return String */ public String stripPath(String realName) { String separator = "/"; int index = realName.lastIndexOf(separator); if (index == -1) { separator = "\\"; index = realName.lastIndexOf(separator); } if (index > -1) { realName = realName.substring(index + 1); } return realName; } public void insertAttachments(Post post) { if (!this.canProceed) { return; } post.hasAttachments(this.filesToSave.size() > 0); for (Iterator iter = this.filesToSave.entrySet().iterator(); iter.hasNext(); ) { Map.Entry entry = (Map.Entry)iter.next(); Attachment a = (Attachment)entry.getValue(); a.setPostId(post.getId()); String path = SystemGlobals.getValue(ConfigKeys.ATTACHMENTS_STORE_DIR) + "/" + a.getInfo().getPhysicalFilename(); this.am.addAttachment(a); ((UploadUtils)entry.getKey()).saveUploadedFile(path); if (this.shouldCreateThumb(a)) { this.createSaveThumb(path); } } } private boolean shouldCreateThumb(Attachment a) { String extension = a.getInfo().getExtension().getExtension().toLowerCase(); return SystemGlobals.getBoolValue(ConfigKeys.ATTACHMENTS_IMAGES_CREATE_THUMB) && ("jpg".equals(extension) || "jpeg".equals(extension) || "gif".equals(extension) || "png".equals(extension)); } private void createSaveThumb(String path) { try { BufferedImage image = ImageUtils.resizeImage(path, ImageUtils.IMAGE_JPEG, SystemGlobals.getIntValue(ConfigKeys.ATTACHMENTS_IMAGES_MAX_THUMB_W), SystemGlobals.getIntValue(ConfigKeys.ATTACHMENTS_IMAGES_MAX_THUMB_H)); ImageUtils.saveImage(image, path + "_thumb", ImageUtils.IMAGE_JPEG); } catch (Exception e) { logger.error(e.toString(), e); } } public QuotaLimit getQuotaLimit(int userId) { QuotaLimit ql = new QuotaLimit(); User u = DataAccessDriver.getInstance().newUserDAO().selectById(userId); for (Iterator iter = u.getGroupsList().iterator(); iter.hasNext();) { QuotaLimit l = this.am.selectQuotaLimitByGroup(((Group)iter.next()).getId()); if (l == null) { continue; } if (l.getSizeInBytes() > ql.getSizeInBytes()) { ql = l; } } if (ql.getSize() == 0) { return null; } return ql; } public void editAttachments(int postId, int forumId) { // Allow removing the attachments at least AttachmentDAO am = DataAccessDriver.getInstance().newAttachmentDAO(); // Check for attachments to remove List deleteList = new ArrayList(); String[] delete = null; String s = this.request.getParameter("delete_attach"); if (s != null) { delete = s.split(","); } if (delete != null) { for (int i = 0; i < delete.length; i++) { if (delete[i] != null && !delete[i].equals("")) { int id = Integer.parseInt(delete[i]); Attachment a = am.selectAttachmentById(id); am.removeAttachment(id, postId); String filename = SystemGlobals.getValue(ConfigKeys.ATTACHMENTS_STORE_DIR) + "/" + a.getInfo().getPhysicalFilename(); File f = new File(filename); if (f.exists()) { f.delete(); } // Check if we have a thumb to delete f = new File(filename + "_thumb"); if (f.exists()) { f.delete(); } } } deleteList = Arrays.asList(delete); } if (!SecurityRepository.canAccess(SecurityConstants.PERM_ATTACHMENTS_ENABLED, Integer.toString(forumId)) && !SecurityRepository.canAccess(SecurityConstants.PERM_ATTACHMENTS_DOWNLOAD)) { return; } // Update String[] attachIds = null; s = this.request.getParameter("edit_attach_ids"); if (s != null) { attachIds = s.split(","); } if (attachIds != null) { for (int i = 0; i < attachIds.length; i++) { if (deleteList.contains(attachIds[i]) || attachIds[i] == null || attachIds[i].equals("")) { continue; } int id = Integer.parseInt(attachIds[i]); Attachment a = am.selectAttachmentById(id); a.getInfo().setComment(this.request.getParameter("edit_comment_" + id)); am.updateAttachment(a); } } } private String makeStoreFilename(AttachmentInfo a) { Calendar c = new GregorianCalendar(); c.setTimeInMillis(System.currentTimeMillis()); c.get(Calendar.YEAR); int year = Calendar.getInstance().get(Calendar.YEAR); int month = Calendar.getInstance().get(Calendar.MONTH) + 1; int day = Calendar.getInstance().get(Calendar.DAY_OF_MONTH); StringBuffer dir = new StringBuffer(256); dir.append(year).append('/').append(month).append('/').append(day).append('/'); new File(SystemGlobals.getValue(ConfigKeys.ATTACHMENTS_STORE_DIR) + "/" + dir).mkdirs(); return dir .append(MD5.crypt(a.getRealFilename() + System.currentTimeMillis())) .append('_') .append(SessionFacade.getUserSession().getUserId()) .append('.') .append(a.getExtension().getExtension()) .append('_') .toString(); } public List getAttachments(int postId, int forumId) { if (!SecurityRepository.canAccess(SecurityConstants.PERM_ATTACHMENTS_DOWNLOAD) && !SecurityRepository.canAccess(SecurityConstants.PERM_ATTACHMENTS_ENABLED, Integer.toString(forumId))) { return new ArrayList(); } return this.am.selectAttachments(postId); } public boolean isPhysicalDownloadMode(int extensionGroupId) { return this.am.isPhysicalDownloadMode(extensionGroupId); } public void deleteAttachments(int postId, int forumId) { // Attachments List attachments = DataAccessDriver.getInstance().newAttachmentDAO().selectAttachments(postId); StringBuffer attachIds = new StringBuffer(); for (Iterator iter = attachments.iterator(); iter.hasNext(); ) { Attachment a = (Attachment)iter.next(); attachIds.append(a.getId()).append(','); } this.request.addOrReplaceParameter("delete_attach", attachIds.toString()); this.editAttachments(postId, forumId); } }