001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.messageboards.util;
016    
017    import com.liferay.portal.kernel.dao.shard.ShardCallable;
018    import com.liferay.portal.kernel.exception.SystemException;
019    import com.liferay.portal.kernel.log.Log;
020    import com.liferay.portal.kernel.log.LogFactoryUtil;
021    import com.liferay.portal.kernel.portlet.LiferayWindowState;
022    import com.liferay.portal.kernel.sanitizer.Sanitizer;
023    import com.liferay.portal.kernel.sanitizer.SanitizerUtil;
024    import com.liferay.portal.kernel.transaction.TransactionCommitCallbackRegistryUtil;
025    import com.liferay.portal.kernel.util.CharPool;
026    import com.liferay.portal.kernel.util.ContentTypes;
027    import com.liferay.portal.kernel.util.GetterUtil;
028    import com.liferay.portal.kernel.util.Http;
029    import com.liferay.portal.kernel.util.LocaleUtil;
030    import com.liferay.portal.kernel.util.LocalizationUtil;
031    import com.liferay.portal.kernel.util.ParamUtil;
032    import com.liferay.portal.kernel.util.PropsUtil;
033    import com.liferay.portal.kernel.util.StringBundler;
034    import com.liferay.portal.kernel.util.StringPool;
035    import com.liferay.portal.kernel.util.StringUtil;
036    import com.liferay.portal.kernel.util.Validator;
037    import com.liferay.portal.kernel.workflow.WorkflowConstants;
038    import com.liferay.portal.model.Group;
039    import com.liferay.portal.model.Organization;
040    import com.liferay.portal.model.Role;
041    import com.liferay.portal.model.UserGroup;
042    import com.liferay.portal.security.permission.ActionKeys;
043    import com.liferay.portal.security.permission.PermissionChecker;
044    import com.liferay.portal.service.GroupLocalServiceUtil;
045    import com.liferay.portal.service.OrganizationLocalServiceUtil;
046    import com.liferay.portal.service.RoleLocalServiceUtil;
047    import com.liferay.portal.service.UserGroupLocalServiceUtil;
048    import com.liferay.portal.service.UserGroupRoleLocalServiceUtil;
049    import com.liferay.portal.service.UserLocalServiceUtil;
050    import com.liferay.portal.theme.ThemeDisplay;
051    import com.liferay.portal.util.PortalUtil;
052    import com.liferay.portal.util.PropsValues;
053    import com.liferay.portal.util.WebKeys;
054    import com.liferay.portlet.messageboards.model.MBBan;
055    import com.liferay.portlet.messageboards.model.MBCategory;
056    import com.liferay.portlet.messageboards.model.MBCategoryConstants;
057    import com.liferay.portlet.messageboards.model.MBMessage;
058    import com.liferay.portlet.messageboards.model.MBMessageConstants;
059    import com.liferay.portlet.messageboards.model.MBStatsUser;
060    import com.liferay.portlet.messageboards.model.MBThread;
061    import com.liferay.portlet.messageboards.service.MBCategoryLocalServiceUtil;
062    import com.liferay.portlet.messageboards.service.MBMessageLocalServiceUtil;
063    import com.liferay.portlet.messageboards.service.MBThreadLocalServiceUtil;
064    import com.liferay.portlet.messageboards.service.permission.MBMessagePermission;
065    import com.liferay.util.ContentUtil;
066    import com.liferay.util.mail.JavaMailUtil;
067    
068    import java.io.InputStream;
069    
070    import java.util.Calendar;
071    import java.util.Collections;
072    import java.util.Date;
073    import java.util.HashMap;
074    import java.util.List;
075    import java.util.Map;
076    import java.util.concurrent.Callable;
077    
078    import javax.mail.BodyPart;
079    import javax.mail.Message;
080    import javax.mail.Part;
081    import javax.mail.internet.MimeMessage;
082    import javax.mail.internet.MimeMultipart;
083    
084    import javax.portlet.PortletPreferences;
085    import javax.portlet.PortletURL;
086    import javax.portlet.RenderResponse;
087    
088    import javax.servlet.http.HttpServletRequest;
089    
090    /**
091     * @author Brian Wing Shun Chan
092     */
093    public class MBUtil {
094    
095            public static final String BB_CODE_EDITOR_WYSIWYG_IMPL_KEY =
096                    "editor.wysiwyg.portal-web.docroot.html.portlet.message_boards." +
097                            "edit_message.bb_code.jsp";
098    
099            public static final String MESSAGE_POP_PORTLET_PREFIX = "mb_message.";
100    
101            public static void addPortletBreadcrumbEntries(
102                            long categoryId, HttpServletRequest request,
103                            RenderResponse renderResponse)
104                    throws Exception {
105    
106                    if ((categoryId == MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) ||
107                            (categoryId == MBCategoryConstants.DISCUSSION_CATEGORY_ID)) {
108    
109                            return;
110                    }
111    
112                    MBCategory category = MBCategoryLocalServiceUtil.getCategory(
113                            categoryId);
114    
115                    addPortletBreadcrumbEntries(category, request, renderResponse);
116            }
117    
118            public static void addPortletBreadcrumbEntries(
119                            MBCategory category, HttpServletRequest request,
120                            RenderResponse renderResponse)
121                    throws Exception {
122    
123                    String strutsAction = ParamUtil.getString(request, "struts_action");
124    
125                    PortletURL portletURL = renderResponse.createRenderURL();
126    
127                    if (strutsAction.equals("/message_boards/select_category") ||
128                            strutsAction.equals("/message_boards_admin/select_category")) {
129    
130                            ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
131                                    WebKeys.THEME_DISPLAY);
132    
133                            portletURL.setParameter(
134                                    "struts_action", "/message_boards/select_category");
135                            portletURL.setWindowState(LiferayWindowState.POP_UP);
136    
137                            PortalUtil.addPortletBreadcrumbEntry(
138                                    request, themeDisplay.translate("categories"),
139                                    portletURL.toString());
140                    }
141                    else {
142                            portletURL.setParameter("struts_action", "/message_boards/view");
143                    }
144    
145                    List<MBCategory> ancestorCategories = category.getAncestors();
146    
147                    Collections.reverse(ancestorCategories);
148    
149                    for (MBCategory curCategory : ancestorCategories) {
150                            portletURL.setParameter(
151                                    "mbCategoryId", String.valueOf(curCategory.getCategoryId()));
152    
153                            PortalUtil.addPortletBreadcrumbEntry(
154                                    request, curCategory.getName(), portletURL.toString());
155                    }
156    
157                    portletURL.setParameter(
158                            "mbCategoryId", String.valueOf(category.getCategoryId()));
159    
160                    PortalUtil.addPortletBreadcrumbEntry(
161                            request, category.getName(), portletURL.toString());
162            }
163    
164            public static void addPortletBreadcrumbEntries(
165                            MBMessage message, HttpServletRequest request,
166                            RenderResponse renderResponse)
167                    throws Exception {
168    
169                    if (message.getCategoryId() ==
170                                    MBCategoryConstants.DISCUSSION_CATEGORY_ID) {
171    
172                            return;
173                    }
174    
175                    if (message.getCategoryId() !=
176                                    MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) {
177    
178                            addPortletBreadcrumbEntries(
179                                    message.getCategory(), request, renderResponse);
180                    }
181    
182                    PortletURL portletURL = renderResponse.createRenderURL();
183    
184                    portletURL.setParameter(
185                            "struts_action", "/message_boards/view_message");
186                    portletURL.setParameter(
187                            "messageId", String.valueOf(message.getMessageId()));
188    
189                    PortalUtil.addPortletBreadcrumbEntry(
190                            request, message.getSubject(), portletURL.toString());
191            }
192    
193            public static void collectMultipartContent(
194                            MimeMultipart multipart, MBMailMessage collector)
195                    throws Exception {
196    
197                    for (int i = 0; i < multipart.getCount(); i++) {
198                            BodyPart part = multipart.getBodyPart(i);
199    
200                            collectPartContent(part, collector);
201                    }
202            }
203    
204            public static void collectPartContent(
205                            Part part, MBMailMessage mbMailMessage)
206                    throws Exception {
207    
208                    Object partContent = part.getContent();
209    
210                    String contentType = part.getContentType().toLowerCase();
211    
212                    if ((part.getDisposition() != null) &&
213                            part.getDisposition().equalsIgnoreCase(MimeMessage.ATTACHMENT)) {
214    
215                            if (_log.isDebugEnabled()) {
216                                    _log.debug("Processing attachment");
217                            }
218    
219                            byte[] bytes = null;
220    
221                            if (partContent instanceof String) {
222                                    bytes = ((String)partContent).getBytes();
223                            }
224                            else if (partContent instanceof InputStream) {
225                                    bytes = JavaMailUtil.getBytes(part);
226                            }
227    
228                            mbMailMessage.addBytes(part.getFileName(), bytes);
229                    }
230                    else {
231                            if (partContent instanceof MimeMultipart) {
232                                    MimeMultipart mimeMultipart = (MimeMultipart)partContent;
233    
234                                    collectMultipartContent(mimeMultipart, mbMailMessage);
235                            }
236                            else if (partContent instanceof String) {
237                                    Map<String, Object> options = new HashMap<String, Object>();
238    
239                                    options.put("emailPartToMBMessageBody", Boolean.TRUE);
240    
241                                    String messageBody = SanitizerUtil.sanitize(
242                                            0, 0, 0, MBMessage.class.getName(), 0, contentType,
243                                            Sanitizer.MODE_ALL, (String)partContent, options);
244    
245                                    if (contentType.startsWith(ContentTypes.TEXT_HTML)) {
246                                            mbMailMessage.setHtmlBody(messageBody);
247                                    }
248                                    else {
249                                            mbMailMessage.setPlainBody(messageBody);
250                                    }
251                            }
252                    }
253            }
254    
255            public static long getCategoryId(
256                    HttpServletRequest request, MBCategory category) {
257    
258                    long categoryId = MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID;
259    
260                    if (category != null) {
261                            categoryId = category.getCategoryId();
262                    }
263    
264                    categoryId = ParamUtil.getLong(request, "mbCategoryId", categoryId);
265    
266                    return categoryId;
267            }
268    
269            public static long getCategoryId(
270                    HttpServletRequest request, MBMessage message) {
271    
272                    long categoryId = MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID;
273    
274                    if (message != null) {
275                            categoryId = message.getCategoryId();
276                    }
277    
278                    categoryId = ParamUtil.getLong(request, "mbCategoryId", categoryId);
279    
280                    return categoryId;
281            }
282    
283            public static String getEmailFromAddress(
284                            PortletPreferences preferences, long companyId)
285                    throws SystemException {
286    
287                    return PortalUtil.getEmailFromAddress(
288                            preferences, companyId,
289                            PropsValues.MESSAGE_BOARDS_EMAIL_FROM_ADDRESS);
290            }
291    
292            public static String getEmailFromName(
293                            PortletPreferences preferences, long companyId)
294                    throws SystemException {
295    
296                    return PortalUtil.getEmailFromName(
297                            preferences, companyId, PropsValues.MESSAGE_BOARDS_EMAIL_FROM_NAME);
298            }
299    
300            public static boolean getEmailHtmlFormat(PortletPreferences preferences) {
301                    String emailHtmlFormat = preferences.getValue(
302                            "emailHtmlFormat", StringPool.BLANK);
303    
304                    if (Validator.isNotNull(emailHtmlFormat)) {
305                            return GetterUtil.getBoolean(emailHtmlFormat);
306                    }
307                    else {
308                            return PropsValues.MESSAGE_BOARDS_EMAIL_HTML_FORMAT;
309                    }
310            }
311    
312            public static String getEmailMessageAddedBody(
313                    PortletPreferences preferences) {
314    
315                    String emailMessageAddedBody = preferences.getValue(
316                            "emailMessageAddedBody", StringPool.BLANK);
317    
318                    if (Validator.isNotNull(emailMessageAddedBody)) {
319                            return emailMessageAddedBody;
320                    }
321                    else {
322                            return ContentUtil.get(
323                                    PropsValues.MESSAGE_BOARDS_EMAIL_MESSAGE_ADDED_BODY);
324                    }
325            }
326    
327            public static boolean getEmailMessageAddedEnabled(
328                    PortletPreferences preferences) {
329    
330                    String emailMessageAddedEnabled = preferences.getValue(
331                            "emailMessageAddedEnabled", StringPool.BLANK);
332    
333                    if (Validator.isNotNull(emailMessageAddedEnabled)) {
334                            return GetterUtil.getBoolean(emailMessageAddedEnabled);
335                    }
336                    else {
337                            return PropsValues.MESSAGE_BOARDS_EMAIL_MESSAGE_ADDED_ENABLED;
338                    }
339            }
340    
341            public static String getEmailMessageAddedSignature(
342                    PortletPreferences preferences) {
343    
344                    String emailMessageAddedSignature = preferences.getValue(
345                            "emailMessageAddedSignature", StringPool.BLANK);
346    
347                    if (Validator.isNotNull(emailMessageAddedSignature)) {
348                            return emailMessageAddedSignature;
349                    }
350                    else {
351                            return ContentUtil.get(
352                                    PropsValues.MESSAGE_BOARDS_EMAIL_MESSAGE_ADDED_SIGNATURE);
353                    }
354            }
355    
356            public static String getEmailMessageAddedSubjectPrefix(
357                    PortletPreferences preferences) {
358    
359                    String emailMessageAddedSubjectPrefix = preferences.getValue(
360                            "emailMessageAddedSubjectPrefix", StringPool.BLANK);
361    
362                    if (Validator.isNotNull(emailMessageAddedSubjectPrefix)) {
363                            return emailMessageAddedSubjectPrefix;
364                    }
365                    else {
366                            return ContentUtil.get(
367                                    PropsValues.MESSAGE_BOARDS_EMAIL_MESSAGE_ADDED_SUBJECT_PREFIX);
368                    }
369            }
370    
371            public static String getEmailMessageUpdatedBody(
372                    PortletPreferences preferences) {
373    
374                    String emailMessageUpdatedBody = preferences.getValue(
375                            "emailMessageUpdatedBody", StringPool.BLANK);
376    
377                    if (Validator.isNotNull(emailMessageUpdatedBody)) {
378                            return emailMessageUpdatedBody;
379                    }
380                    else {
381                            return ContentUtil.get(
382                                    PropsValues.MESSAGE_BOARDS_EMAIL_MESSAGE_UPDATED_BODY);
383                    }
384            }
385    
386            public static boolean getEmailMessageUpdatedEnabled(
387                    PortletPreferences preferences) {
388    
389                    String emailMessageUpdatedEnabled = preferences.getValue(
390                            "emailMessageUpdatedEnabled", StringPool.BLANK);
391    
392                    if (Validator.isNotNull(emailMessageUpdatedEnabled)) {
393                            return GetterUtil.getBoolean(emailMessageUpdatedEnabled);
394                    }
395                    else {
396                            return PropsValues.MESSAGE_BOARDS_EMAIL_MESSAGE_UPDATED_ENABLED;
397                    }
398            }
399    
400            public static String getEmailMessageUpdatedSignature(
401                    PortletPreferences preferences) {
402    
403                    String emailMessageUpdatedSignature = preferences.getValue(
404                            "emailMessageUpdatedSignature", StringPool.BLANK);
405    
406                    if (Validator.isNotNull(emailMessageUpdatedSignature)) {
407                            return emailMessageUpdatedSignature;
408                    }
409                    else {
410                            return ContentUtil.get(
411                                    PropsValues.MESSAGE_BOARDS_EMAIL_MESSAGE_UPDATED_SIGNATURE);
412                    }
413            }
414    
415            public static String getEmailMessageUpdatedSubjectPrefix(
416                    PortletPreferences preferences) {
417    
418                    String emailMessageUpdatedSubject = preferences.getValue(
419                            "emailMessageUpdatedSubjectPrefix", StringPool.BLANK);
420    
421                    if (Validator.isNotNull(emailMessageUpdatedSubject)) {
422                            return emailMessageUpdatedSubject;
423                    }
424                    else {
425                            return ContentUtil.get(
426                                    PropsValues.
427                                            MESSAGE_BOARDS_EMAIL_MESSAGE_UPDATED_SUBJECT_PREFIX);
428                    }
429            }
430    
431            public static String getMessageFormat(PortletPreferences preferences) {
432                    String messageFormat = preferences.getValue(
433                            "messageFormat", MBMessageConstants.DEFAULT_FORMAT);
434    
435                    String editorImpl = PropsUtil.get(BB_CODE_EDITOR_WYSIWYG_IMPL_KEY);
436    
437                    if (messageFormat.equals("bbcode") &&
438                            !(editorImpl.equals("bbcode") ||
439                              editorImpl.equals("ckeditor_bbcode"))) {
440    
441                            messageFormat = "html";
442                    }
443    
444                    return messageFormat;
445            }
446    
447            public static long getMessageId(String mailId) {
448                    int x = mailId.indexOf(CharPool.LESS_THAN) + 1;
449                    int y = mailId.indexOf(CharPool.AT);
450    
451                    long messageId = 0;
452    
453                    if ((x > 0 ) && (y != -1)) {
454                            String temp = mailId.substring(x, y);
455    
456                            int z = temp.lastIndexOf(CharPool.PERIOD);
457    
458                            if (z != -1) {
459                                    messageId = GetterUtil.getLong(temp.substring(z + 1));
460                            }
461                    }
462    
463                    return messageId;
464            }
465    
466            public static long getParentMessageId(Message message) throws Exception {
467                    long parentMessageId = -1;
468    
469                    String parentHeader = getParentMessageIdString(message);
470    
471                    if (parentHeader != null) {
472                            if (_log.isDebugEnabled()) {
473                                    _log.debug("Parent header " + parentHeader);
474                            }
475    
476                            parentMessageId = getMessageId(parentHeader);
477    
478                            if (_log.isDebugEnabled()) {
479                                    _log.debug("Previous message id " + parentMessageId);
480                            }
481                    }
482    
483                    return parentMessageId;
484            }
485    
486            public static String getParentMessageIdString(Message message)
487                    throws Exception {
488    
489                    // If the previous block failed, try to get the parent message ID from
490                    // the "References" header as explained in
491                    // http://cr.yp.to/immhf/thread.html. Some mail clients such as Yahoo!
492                    // Mail use the "In-Reply-To" header, so we check that as well.
493    
494                    String parentHeader = null;
495    
496                    String[] references = message.getHeader("References");
497    
498                    if ((references != null) && (references.length > 0)) {
499                            String reference = references[0];
500    
501                            int x = reference.lastIndexOf("<mb.");
502    
503                            if (x > -1) {
504                                    int y = reference.indexOf(">", x);
505    
506                                    parentHeader = reference.substring(x, y);
507                            }
508                    }
509    
510                    if (parentHeader == null) {
511                            String[] inReplyToHeaders = message.getHeader("In-Reply-To");
512    
513                            if ((inReplyToHeaders != null) && (inReplyToHeaders.length > 0)) {
514                                    parentHeader = inReplyToHeaders[0];
515                            }
516                    }
517    
518                    if (Validator.isNull(parentHeader) ||
519                            !parentHeader.startsWith(MESSAGE_POP_PORTLET_PREFIX, 1)) {
520    
521                            parentHeader = _getParentMessageIdFromSubject(message);
522                    }
523    
524                    return parentHeader;
525            }
526    
527            public static String getReplyToAddress(
528                    long categoryId, long messageId, String mx,
529                    String defaultMailingListAddress) {
530    
531                    if (PropsValues.POP_SERVER_SUBDOMAIN.length() <= 0) {
532                            return defaultMailingListAddress;
533                    }
534    
535                    StringBundler sb = new StringBundler(8);
536    
537                    sb.append(MESSAGE_POP_PORTLET_PREFIX);
538                    sb.append(categoryId);
539                    sb.append(StringPool.PERIOD);
540                    sb.append(messageId);
541                    sb.append(StringPool.AT);
542                    sb.append(PropsValues.POP_SERVER_SUBDOMAIN);
543                    sb.append(StringPool.PERIOD);
544                    sb.append(mx);
545    
546                    return sb.toString();
547            }
548    
549            public static String getSubjectWithoutMessageId(Message message)
550                    throws Exception {
551    
552                    String subject = message.getSubject();
553    
554                    String parentMessageId = _getParentMessageIdFromSubject(message);
555    
556                    if (Validator.isNotNull(parentMessageId)) {
557                            int pos = subject.indexOf(parentMessageId);
558    
559                            if (pos != -1) {
560                                    subject = subject.substring(0, pos);
561                            }
562                    }
563    
564                    return subject;
565            }
566    
567            public static String[] getThreadPriority(
568                            PortletPreferences preferences, String languageId, double value,
569                            ThemeDisplay themeDisplay)
570                    throws Exception {
571    
572                    String[] priorities = LocalizationUtil.getPreferencesValues(
573                            preferences, "priorities", languageId);
574    
575                    String[] priorityPair = _findThreadPriority(
576                            value, themeDisplay, priorities);
577    
578                    if (priorityPair == null) {
579                            String defaultLanguageId = LocaleUtil.toLanguageId(
580                                    LocaleUtil.getDefault());
581    
582                            priorities = LocalizationUtil.getPreferencesValues(
583                                    preferences, "priorities", defaultLanguageId);
584    
585                            priorityPair = _findThreadPriority(value, themeDisplay, priorities);
586                    }
587    
588                    return priorityPair;
589            }
590    
591            public static Date getUnbanDate(MBBan ban, int expireInterval) {
592                    Date banDate = ban.getCreateDate();
593    
594                    Calendar cal = Calendar.getInstance();
595    
596                    cal.setTime(banDate);
597    
598                    cal.add(Calendar.DATE, expireInterval);
599    
600                    return cal.getTime();
601            }
602    
603            public static String getUserRank(
604                            PortletPreferences preferences, String languageId, int posts)
605                    throws Exception {
606    
607                    String rank = StringPool.BLANK;
608    
609                    String[] ranks = LocalizationUtil.getPreferencesValues(
610                            preferences, "ranks", languageId);
611    
612                    for (int i = 0; i < ranks.length; i++) {
613                            String[] kvp = StringUtil.split(ranks[i], CharPool.EQUAL);
614    
615                            String kvpName = kvp[0];
616                            int kvpPosts = GetterUtil.getInteger(kvp[1]);
617    
618                            if (posts >= kvpPosts) {
619                                    rank = kvpName;
620                            }
621                            else {
622                                    break;
623                            }
624                    }
625    
626                    return rank;
627            }
628    
629            public static String[] getUserRank(
630                            PortletPreferences preferences, String languageId,
631                            MBStatsUser statsUser)
632                    throws Exception {
633    
634                    String[] rank = {StringPool.BLANK, StringPool.BLANK};
635    
636                    int maxPosts = 0;
637    
638                    Group group = GroupLocalServiceUtil.getGroup(statsUser.getGroupId());
639    
640                    long companyId = group.getCompanyId();
641    
642                    String[] ranks = LocalizationUtil.getPreferencesValues(
643                            preferences, "ranks", languageId);
644    
645                    for (int i = 0; i < ranks.length; i++) {
646                            String[] kvp = StringUtil.split(ranks[i], CharPool.EQUAL);
647    
648                            String curRank = kvp[0];
649                            String curRankValue = kvp[1];
650    
651                            String[] curRankValueKvp = StringUtil.split(
652                                    curRankValue, CharPool.COLON);
653    
654                            if (curRankValueKvp.length <= 1) {
655                                    int posts = GetterUtil.getInteger(curRankValue);
656    
657                                    if ((posts <= statsUser.getMessageCount()) &&
658                                            (posts >= maxPosts)) {
659    
660                                            rank[0] = curRank;
661                                            maxPosts = posts;
662                                    }
663    
664                            }
665                            else {
666                                    String entityType = curRankValueKvp[0];
667                                    String entityValue = curRankValueKvp[1];
668    
669                                    try {
670                                            if (_isEntityRank(
671                                                            companyId, statsUser, entityType, entityValue)) {
672    
673                                                    rank[1] = curRank;
674    
675                                                    break;
676                                            }
677                                    }
678                                    catch (Exception e) {
679                                            if (_log.isWarnEnabled()) {
680                                                    _log.warn(e);
681                                            }
682                                    }
683                            }
684                    }
685    
686                    return rank;
687            }
688    
689            public static boolean hasMailIdHeader(Message message) throws Exception {
690                    String[] messageIds = message.getHeader("Message-ID");
691    
692                    if (messageIds == null) {
693                            return false;
694                    }
695    
696                    for (String messageId : messageIds) {
697                            if (Validator.isNotNull(PropsValues.POP_SERVER_SUBDOMAIN) &&
698                                    messageId.contains(PropsValues.POP_SERVER_SUBDOMAIN)) {
699    
700                                    return true;
701                            }
702                    }
703    
704                    return false;
705            }
706    
707            public static boolean isAllowAnonymousPosting(
708                    PortletPreferences preferences) {
709    
710                    return GetterUtil.getBoolean(
711                            preferences.getValue("allowAnonymousPosting", null),
712                            PropsValues.MESSAGE_BOARDS_ANONYMOUS_POSTING_ENABLED);
713            }
714    
715            public static boolean isViewableMessage(
716                            ThemeDisplay themeDisplay, MBMessage message)
717                    throws Exception {
718    
719                    return isViewableMessage(themeDisplay, message, message);
720            }
721    
722            public static boolean isViewableMessage(
723                            ThemeDisplay themeDisplay, MBMessage message,
724                            MBMessage parentMessage)
725                    throws Exception {
726    
727                    PermissionChecker permissionChecker =
728                            themeDisplay.getPermissionChecker();
729    
730                    if (!MBMessagePermission.contains(
731                                    permissionChecker, parentMessage, ActionKeys.VIEW)) {
732    
733                            return false;
734                    }
735    
736                    if ((message.getMessageId() != parentMessage.getMessageId()) &&
737                            !MBMessagePermission.contains(
738                                    permissionChecker, message, ActionKeys.VIEW)) {
739    
740                            return false;
741                    }
742    
743                    if (!message.isApproved() &&
744                            !Validator.equals(message.getUserId(), themeDisplay.getUserId()) &&
745                            !permissionChecker.isGroupAdmin(themeDisplay.getScopeGroupId())) {
746    
747                            return false;
748                    }
749    
750                    return true;
751            }
752    
753            public static String replaceMessageBodyPaths(
754                    ThemeDisplay themeDisplay, String messageBody) {
755    
756                    return StringUtil.replace(
757                            messageBody,
758                            new String[] {
759                                    "@theme_images_path@", "href=\"/", "src=\"/"
760                            },
761                            new String[] {
762                                    themeDisplay.getPathThemeImages(),
763                                    "href=\"" + themeDisplay.getURLPortal() + "/",
764                                    "src=\"" + themeDisplay.getURLPortal() + "/"
765                            });
766            }
767    
768            public static void updateCategoryMessageCount(
769                    long companyId, final long categoryId) {
770    
771                    Callable<Void> callable = new ShardCallable<Void>(companyId) {
772    
773                            @Override
774                            protected Void doCall() throws Exception {
775                                    MBCategory category =
776                                            MBCategoryLocalServiceUtil.fetchMBCategory(categoryId);
777    
778                                    if (category == null) {
779                                            return null;
780                                    }
781    
782                                    int messageCount =
783                                            MBMessageLocalServiceUtil.getCategoryMessagesCount(
784                                                    category.getGroupId(), category.getCategoryId(),
785                                                    WorkflowConstants.STATUS_APPROVED);
786    
787                                    category.setMessageCount(messageCount);
788    
789                                    MBCategoryLocalServiceUtil.updateMBCategory(category);
790    
791                                    return null;
792                            }
793    
794                    };
795    
796                    TransactionCommitCallbackRegistryUtil.registerCallback(callable);
797            }
798    
799            public static void updateCategoryStatistics(
800                    long companyId, final long categoryId) {
801    
802                    Callable<Void> callable = new ShardCallable<Void>(companyId) {
803    
804                            @Override
805                            protected Void doCall() throws Exception {
806                                    MBCategory category =
807                                            MBCategoryLocalServiceUtil.fetchMBCategory(categoryId);
808    
809                                    if (category == null) {
810                                            return null;
811                                    }
812    
813                                    int messageCount =
814                                            MBMessageLocalServiceUtil.getCategoryMessagesCount(
815                                                    category.getGroupId(), category.getCategoryId(),
816                                                    WorkflowConstants.STATUS_APPROVED);
817    
818                                    int threadCount =
819                                            MBThreadLocalServiceUtil.getCategoryThreadsCount(
820                                                    category.getGroupId(), category.getCategoryId(),
821                                                    WorkflowConstants.STATUS_APPROVED);
822    
823                                    category.setMessageCount(messageCount);
824                                    category.setThreadCount(threadCount);
825    
826                                    MBCategoryLocalServiceUtil.updateMBCategory(category);
827    
828                                    return null;
829                            }
830    
831                    };
832    
833                    TransactionCommitCallbackRegistryUtil.registerCallback(callable);
834            }
835    
836            public static void updateCategoryThreadCount(
837                    long companyId, final long categoryId) {
838    
839                    Callable<Void> callable = new ShardCallable<Void>(companyId) {
840    
841                            @Override
842                            protected Void doCall() throws Exception {
843                                    MBCategory category =
844                                            MBCategoryLocalServiceUtil.fetchMBCategory(categoryId);
845    
846                                    if (category == null) {
847                                            return null;
848                                    }
849    
850                                    int threadCount =
851                                            MBThreadLocalServiceUtil.getCategoryThreadsCount(
852                                                    category.getGroupId(), category.getCategoryId(),
853                                                    WorkflowConstants.STATUS_APPROVED);
854    
855                                    category.setThreadCount(threadCount);
856    
857                                    MBCategoryLocalServiceUtil.updateMBCategory(category);
858    
859                                    return null;
860                            }
861    
862                    };
863    
864                    TransactionCommitCallbackRegistryUtil.registerCallback(callable);
865            }
866    
867            public static void updateThreadMessageCount(
868                    long companyId, final long threadId) {
869    
870                    Callable<Void> callable = new ShardCallable<Void>(companyId) {
871    
872                            @Override
873                            protected Void doCall() throws Exception {
874                                    MBThread thread = MBThreadLocalServiceUtil.fetchThread(
875                                            threadId);
876    
877                                    if (thread == null) {
878                                            return null;
879                                    }
880    
881                                    int messageCount =
882                                            MBMessageLocalServiceUtil.getThreadMessagesCount(
883                                                    threadId, WorkflowConstants.STATUS_APPROVED);
884    
885                                    thread.setMessageCount(messageCount);
886    
887                                    MBThreadLocalServiceUtil.updateMBThread(thread);
888    
889                                    return null;
890                            }
891    
892                    };
893    
894                    TransactionCommitCallbackRegistryUtil.registerCallback(callable);
895            }
896    
897            private static String[] _findThreadPriority(
898                    double value, ThemeDisplay themeDisplay, String[] priorities) {
899    
900                    for (int i = 0; i < priorities.length; i++) {
901                            String[] priority = StringUtil.split(priorities[i]);
902    
903                            try {
904                                    String priorityName = priority[0];
905                                    String priorityImage = priority[1];
906                                    double priorityValue = GetterUtil.getDouble(priority[2]);
907    
908                                    if (value == priorityValue) {
909                                            if (!priorityImage.startsWith(Http.HTTP)) {
910                                                    priorityImage =
911                                                            themeDisplay.getPathThemeImages() + priorityImage;
912                                            }
913    
914                                            return new String[] {priorityName, priorityImage};
915                                    }
916                            }
917                            catch (Exception e) {
918                                    _log.error("Unable to determine thread priority", e);
919                            }
920                    }
921    
922                    return null;
923            }
924    
925            private static String _getParentMessageIdFromSubject(Message message)
926                    throws Exception {
927    
928                    if (message.getSubject() == null) {
929                            return null;
930                    }
931    
932                    String parentMessageId = null;
933    
934                    String subject = StringUtil.reverse(message.getSubject());
935    
936                    int pos = subject.indexOf(CharPool.LESS_THAN);
937    
938                    if (pos != -1) {
939                            parentMessageId = StringUtil.reverse(subject.substring(0, pos + 1));
940                    }
941    
942                    return parentMessageId;
943            }
944    
945            private static boolean _isEntityRank(
946                            long companyId, MBStatsUser statsUser, String entityType,
947                            String entityValue)
948                    throws Exception {
949    
950                    long groupId = statsUser.getGroupId();
951                    long userId = statsUser.getUserId();
952    
953                    if (entityType.equals("organization-role") ||
954                            entityType.equals("site-role")) {
955    
956                            Role role = RoleLocalServiceUtil.getRole(companyId, entityValue);
957    
958                            if (UserGroupRoleLocalServiceUtil.hasUserGroupRole(
959                                            userId, groupId, role.getRoleId(), true)) {
960    
961                                    return true;
962                            }
963                    }
964                    else if (entityType.equals("organization")) {
965                            Organization organization =
966                                    OrganizationLocalServiceUtil.getOrganization(
967                                            companyId, entityValue);
968    
969                            if (OrganizationLocalServiceUtil.hasUserOrganization(
970                                            userId, organization.getOrganizationId(), false, false)) {
971    
972                                    return true;
973                            }
974                    }
975                    else if (entityType.equals("regular-role")) {
976                            if (RoleLocalServiceUtil.hasUserRole(
977                                            userId, companyId, entityValue, true)) {
978    
979                                    return true;
980                            }
981                    }
982                    else if (entityType.equals("user-group")) {
983                            UserGroup userGroup = UserGroupLocalServiceUtil.getUserGroup(
984                                    companyId, entityValue);
985    
986                            if (UserLocalServiceUtil.hasUserGroupUser(
987                                            userGroup.getUserGroupId(), userId)) {
988    
989                                    return true;
990                            }
991                    }
992    
993                    return false;
994            }
995    
996            private static Log _log = LogFactoryUtil.getLog(MBUtil.class);
997    
998    }