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: * This file creation date: 21/05/2004 - 15:33:36
040: * The JForum Project
041: * http://www.jforum.net
042: */
043: package net.jforum.view.forum.common;
044:
045: import java.util.ArrayList;
046: import java.util.Collection;
047: import java.util.Date;
048: import java.util.Iterator;
049: import java.util.List;
050: import java.util.regex.Matcher;
051: import java.util.regex.Pattern;
052:
053: import net.jforum.JForumExecutionContext;
054: import net.jforum.SessionFacade;
055: import net.jforum.context.RequestContext;
056: import net.jforum.dao.PostDAO;
057: import net.jforum.entities.Post;
058: import net.jforum.entities.Smilie;
059: import net.jforum.repository.BBCodeRepository;
060: import net.jforum.repository.PostRepository;
061: import net.jforum.repository.SecurityRepository;
062: import net.jforum.repository.SmiliesRepository;
063: import net.jforum.security.SecurityConstants;
064: import net.jforum.util.SafeHtml;
065: import net.jforum.util.bbcode.BBCode;
066: import net.jforum.util.preferences.ConfigKeys;
067: import net.jforum.util.preferences.SystemGlobals;
068:
069: /**
070: * @author Rafael Steil
071: * @version $Id: PostCommon.java,v 1.59 2007/09/24 03:29:17 rafaelsteil Exp $
072: */
073: public class PostCommon {
074: public static Post preparePostForDisplay(Post post) {
075: if (post.getText() == null) {
076: return post;
077: }
078:
079: StringBuffer text = new StringBuffer(post.getText());
080:
081: if (!post.isHtmlEnabled()) {
082: ViewCommon.replaceAll(text, "<", "<");
083: ViewCommon.replaceAll(text, ">", ">");
084: }
085:
086: // Do not remove the trailing blank space, as it would
087: // cause some regular expressions to fail
088: ViewCommon.replaceAll(text, "\n", "<br /> ");
089:
090: SafeHtml safeHtml = new SafeHtml();
091:
092: post.setText(text.toString());
093: post.setText(safeHtml.makeSafe(post.getText()));
094:
095: processText(post);
096:
097: post.setText(safeHtml
098: .ensureAllAttributesAreSafe(post.getText()));
099:
100: return post;
101: }
102:
103: private static void processText(Post post) {
104: int codeIndex = post.getText().indexOf("[code");
105: int codeEndIndex = codeIndex > -1 ? post.getText().indexOf(
106: "[/code]") : -1;
107:
108: boolean hasCodeBlock = false;
109:
110: if (codeIndex == -1 || codeEndIndex == -1
111: || codeEndIndex < codeIndex) {
112: post.setText(prepareTextForDisplayExceptCodeTag(post
113: .getText().toString(), post.isBbCodeEnabled(), post
114: .isSmiliesEnabled()));
115: } else if (post.isBbCodeEnabled()) {
116: hasCodeBlock = true;
117:
118: int nextStartPos = 0;
119: StringBuffer result = new StringBuffer(post.getText()
120: .length());
121:
122: while (codeIndex > -1 && codeEndIndex > -1
123: && codeEndIndex > codeIndex) {
124: codeEndIndex += "[/code]".length();
125:
126: String nonCodeResult = prepareTextForDisplayExceptCodeTag(
127: post.getText().substring(nextStartPos,
128: codeIndex), post.isBbCodeEnabled(),
129: post.isSmiliesEnabled());
130:
131: String codeResult = parseCode(post.getText().substring(
132: codeIndex, codeEndIndex));
133:
134: result.append(nonCodeResult).append(codeResult);
135:
136: nextStartPos = codeEndIndex;
137: codeIndex = post.getText().indexOf("[code",
138: codeEndIndex);
139: codeEndIndex = codeIndex > -1 ? post.getText().indexOf(
140: "[/code]", codeIndex) : -1;
141: }
142:
143: if (nextStartPos > -1) {
144: String nonCodeResult = prepareTextForDisplayExceptCodeTag(
145: post.getText().substring(nextStartPos), post
146: .isBbCodeEnabled(), post
147: .isSmiliesEnabled());
148:
149: result.append(nonCodeResult);
150: }
151:
152: post.setText(result.toString());
153: }
154:
155: if (hasCodeBlock) {
156: JForumExecutionContext.getTemplateContext().put(
157: "hasCodeBlock", hasCodeBlock);
158: }
159: }
160:
161: private static String parseCode(String text) {
162: for (Iterator iter = BBCodeRepository.getBBCollection()
163: .getBbList().iterator(); iter.hasNext();) {
164: BBCode bb = (BBCode) iter.next();
165:
166: if (bb.getTagName().startsWith("code")) {
167: Matcher matcher = Pattern.compile(bb.getRegex())
168: .matcher(text);
169: StringBuffer sb = new StringBuffer(text);
170:
171: while (matcher.find()) {
172: StringBuffer lang = null;
173: StringBuffer contents = null;
174:
175: if ("code".equals(bb.getTagName())) {
176: contents = new StringBuffer(matcher.group(1));
177: } else {
178: lang = new StringBuffer(matcher.group(1));
179: contents = new StringBuffer(matcher.group(2));
180: }
181:
182: ViewCommon.replaceAll(contents, "<br /> ", "\n");
183:
184: // XML-like tags
185: ViewCommon.replaceAll(contents, "<", "<");
186: ViewCommon.replaceAll(contents, ">", ">");
187:
188: // Note: there is no replacing for spaces and tabs as
189: // we are relying on the Javascript SyntaxHighlighter library
190: // to do it for us
191:
192: StringBuffer replace = new StringBuffer(bb
193: .getReplace());
194: int index = replace.indexOf("$1");
195:
196: if ("code".equals(bb.getTagName())) {
197: if (index > -1) {
198: replace.replace(index, index + 2, contents
199: .toString());
200: }
201:
202: index = sb.indexOf("[code]");
203: } else {
204: if (index > -1) {
205: replace.replace(index, index + 2, lang
206: .toString());
207: }
208:
209: index = replace.indexOf("$2");
210:
211: if (index > -1) {
212: replace.replace(index, index + 2, contents
213: .toString());
214: }
215:
216: index = sb.indexOf("[code=");
217: }
218: int lastIndex = sb.indexOf("[/code]", index)
219: + "[/code]".length();
220:
221: if (lastIndex > index) {
222: sb
223: .replace(index, lastIndex, replace
224: .toString());
225: }
226: }
227:
228: text = sb.toString();
229: }
230: }
231:
232: return text;
233: }
234:
235: public static String prepareTextForDisplayExceptCodeTag(
236: String text, boolean isBBCodeEnabled,
237: boolean isSmilesEnabled) {
238: if (text == null) {
239: return text;
240: }
241:
242: if (isSmilesEnabled) {
243: text = processSmilies(new StringBuffer(text));
244: }
245:
246: if (isBBCodeEnabled && text.indexOf('[') > -1
247: && text.indexOf(']') > -1) {
248: for (Iterator iter = BBCodeRepository.getBBCollection()
249: .getBbList().iterator(); iter.hasNext();) {
250: BBCode bb = (BBCode) iter.next();
251:
252: if (!bb.getTagName().startsWith("code")) {
253: text = text.replaceAll(bb.getRegex(), bb
254: .getReplace());
255: }
256: }
257: }
258:
259: text = parseDefaultRequiredBBCode(text);
260:
261: return text;
262: }
263:
264: public static String parseDefaultRequiredBBCode(String text) {
265: Collection list = BBCodeRepository.getBBCollection()
266: .getAlwaysProcessList();
267:
268: for (Iterator iter = list.iterator(); iter.hasNext();) {
269: BBCode bb = (BBCode) iter.next();
270: text = text.replaceAll(bb.getRegex(), bb.getReplace());
271: }
272:
273: return text;
274: }
275:
276: /**
277: * Replace the smlies code by the respective URL.
278: * @param text The text to process
279: * @return the parsed text. Note that the StringBuffer you pass as parameter
280: * will already have the right contents, as the replaces are done on the instance
281: */
282: public static String processSmilies(StringBuffer text) {
283: List smilies = SmiliesRepository.getSmilies();
284:
285: for (Iterator iter = smilies.iterator(); iter.hasNext();) {
286: Smilie s = (Smilie) iter.next();
287: int pos = text.indexOf(s.getCode());
288:
289: // The counter is used as prevention, in case
290: // the while loop turns into an always true
291: // expression, for any reason
292: int counter = 0;
293:
294: while (pos > -1 && counter++ < 300) {
295: text.replace(pos, pos + s.getCode().length(), s
296: .getUrl());
297: pos = text.indexOf(s.getCode());
298: }
299: }
300:
301: return text.toString();
302: }
303:
304: public static Post fillPostFromRequest() {
305: Post p = new Post();
306: p.setTime(new Date());
307:
308: return fillPostFromRequest(p, false);
309: }
310:
311: public static Post fillPostFromRequest(Post p, boolean isEdit) {
312: RequestContext request = JForumExecutionContext.getRequest();
313:
314: p.setSubject(request.getParameter("subject"));
315: p
316: .setBbCodeEnabled(request
317: .getParameter("disable_bbcode") == null);
318: p
319: .setSmiliesEnabled(request
320: .getParameter("disable_smilies") == null);
321: p
322: .setSignatureEnabled(request.getParameter("attach_sig") != null);
323:
324: if (!isEdit) {
325: p.setUserIp(request.getRemoteAddr());
326: p.setUserId(SessionFacade.getUserSession().getUserId());
327: }
328:
329: boolean htmlEnabled = SecurityRepository.canAccess(
330: SecurityConstants.PERM_HTML_DISABLED, request
331: .getParameter("forum_id"));
332: p.setHtmlEnabled(htmlEnabled
333: && request.getParameter("disable_html") == null);
334:
335: if (p.isHtmlEnabled()) {
336: p.setText(new SafeHtml().makeSafe(request
337: .getParameter("message")));
338: } else {
339: p.setText(request.getParameter("message"));
340: }
341:
342: return p;
343: }
344:
345: public static boolean canEditPost(Post post) {
346: return SessionFacade.isLogged()
347: && (post.getUserId() == SessionFacade.getUserSession()
348: .getUserId() || SecurityRepository
349: .canAccess(SecurityConstants.PERM_MODERATION_POST_EDIT));
350: }
351:
352: public static List topicPosts(PostDAO dao, boolean canEdit,
353: int userId, int topicId, int start, int count) {
354: boolean needPrepare = true;
355: List posts;
356:
357: if (SystemGlobals.getBoolValue(ConfigKeys.POSTS_CACHE_ENABLED)) {
358: posts = PostRepository.selectAllByTopicByLimit(topicId,
359: start, count);
360: needPrepare = false;
361: } else {
362: posts = dao.selectAllByTopicByLimit(topicId, start, count);
363: }
364:
365: List helperList = new ArrayList();
366:
367: int anonymousUser = SystemGlobals
368: .getIntValue(ConfigKeys.ANONYMOUS_USER_ID);
369:
370: for (Iterator iter = posts.iterator(); iter.hasNext();) {
371: Post p;
372:
373: if (needPrepare) {
374: p = (Post) iter.next();
375: } else {
376: p = new Post((Post) iter.next());
377: }
378:
379: if (canEdit
380: || (p.getUserId() != anonymousUser && p.getUserId() == userId)) {
381: p.setCanEdit(true);
382: }
383:
384: helperList.add(needPrepare ? PostCommon
385: .preparePostForDisplay(p) : p);
386: }
387:
388: return helperList;
389: }
390: }
|