0001: /**********************************************************************************
0002: * $URL: https://source.sakaiproject.org/svn/mailarchive/tags/sakai_2-4-1/mailarchive-tool/tool/src/java/org/sakaiproject/mailarchive/tool/MailboxAction.java $
0003: * $Id: MailboxAction.java 29104 2007-04-18 22:03:36Z ajpoland@iupui.edu $
0004: ***********************************************************************************
0005: *
0006: * Copyright (c) 2003, 2004, 2005, 2006 The Sakai Foundation.
0007: *
0008: * Licensed under the Educational Community License, Version 1.0 (the "License");
0009: * you may not use this file except in compliance with the License.
0010: * You may obtain a copy of the License at
0011: *
0012: * http://www.opensource.org/licenses/ecl1.php
0013: *
0014: * Unless required by applicable law or agreed to in writing, software
0015: * distributed under the License is distributed on an "AS IS" BASIS,
0016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0017: * See the License for the specific language governing permissions and
0018: * limitations under the License.
0019: *
0020: **********************************************************************************/package org.sakaiproject.mailarchive.tool;
0021:
0022: import java.util.Collections;
0023: import java.util.Comparator;
0024: import java.util.Iterator;
0025: import java.util.List;
0026: import java.util.Vector;
0027:
0028: import org.sakaiproject.alias.api.Alias;
0029: import org.sakaiproject.alias.cover.AliasService;
0030: import org.sakaiproject.authz.api.PermissionsHelper;
0031: import org.sakaiproject.cheftool.Context;
0032: import org.sakaiproject.cheftool.JetspeedRunData;
0033: import org.sakaiproject.cheftool.PagedResourceActionII;
0034: import org.sakaiproject.cheftool.PortletConfig;
0035: import org.sakaiproject.cheftool.RunData;
0036: import org.sakaiproject.cheftool.VelocityPortlet;
0037: import org.sakaiproject.cheftool.api.Menu;
0038: import org.sakaiproject.cheftool.menu.MenuDivider;
0039: import org.sakaiproject.cheftool.menu.MenuEntry;
0040: import org.sakaiproject.cheftool.menu.MenuImpl;
0041: import org.sakaiproject.component.cover.ServerConfigurationService;
0042: import org.sakaiproject.content.cover.ContentTypeImageService;
0043: import org.sakaiproject.entity.api.Reference;
0044: import org.sakaiproject.entity.cover.EntityManager;
0045: import org.sakaiproject.event.api.SessionState;
0046: import org.sakaiproject.exception.IdUnusedException;
0047: import org.sakaiproject.exception.PermissionException;
0048: import org.sakaiproject.javax.PagingPosition;
0049: import org.sakaiproject.mailarchive.api.MailArchiveChannel;
0050: import org.sakaiproject.mailarchive.api.MailArchiveChannelEdit;
0051: import org.sakaiproject.mailarchive.api.MailArchiveMessage;
0052: import org.sakaiproject.mailarchive.cover.MailArchiveService;
0053: import org.sakaiproject.site.cover.SiteService;
0054: import org.sakaiproject.tool.cover.ToolManager;
0055: import org.sakaiproject.user.api.User;
0056: import org.sakaiproject.user.cover.UserDirectoryService;
0057: import org.sakaiproject.util.FormattedText;
0058: import org.sakaiproject.util.ResourceLoader;
0059: import org.sakaiproject.util.StringUtil;
0060: import org.sakaiproject.util.Validator;
0061:
0062: /**
0063: * <p>
0064: * MailboxAction is a the Sakai mailbox tool.
0065: * </p>
0066: */
0067: public class MailboxAction extends PagedResourceActionII {
0068: private static ResourceLoader rb = new ResourceLoader("email");
0069:
0070: /** portlet configuration parameter names. */
0071: private static final String PARAM_CHANNEL = "channel";
0072:
0073: private static final String PARAM_SITE = "site";
0074:
0075: /** Configure form field names. */
0076: private static final String FORM_CHANNEL = "channel";
0077:
0078: private static final String FORM_PAGESIZE = "pagesize";
0079:
0080: private static final String FORM_OPEN = "open";
0081:
0082: private static final String FORM_ALIAS = "alias";
0083:
0084: /** List request parameters. */
0085: private static final String VIEW_ID = "view-id";
0086:
0087: /** state attribute names. */
0088: private static final String STATE_CHANNEL_REF = "channelId";
0089:
0090: private static final String STATE_ASCENDING = "ascending";
0091:
0092: private static final String STATE_SORT = "sort";
0093:
0094: private static final String STATE_VIEW_HEADERS = "view-headers";
0095:
0096: private static final String STATE_OPTION_PAGESIZE = "optSize";
0097:
0098: private static final String STATE_OPTION_OPEN = "optOpen";
0099:
0100: private static final String STATE_OPTION_ALIAS = "optAlias";
0101:
0102: /** Sort codes. */
0103: private static final int SORT_FROM = 0;
0104:
0105: private static final int SORT_DATE = 1;
0106:
0107: private static final int SORT_SUBJECT = 2;
0108:
0109: /** paging */
0110: private static final String STATE_ALL_MESSAGES = "allMessages";
0111:
0112: private static final String STATE_MSG_VIEW_ID = "msg-id";
0113:
0114: /** paging */
0115: /*
0116: * (non-Javadoc)
0117: *
0118: * @see org.sakaiproject.cheftool.PagedResourceActionII#readResourcesPage(org.sakaiproject.service.framework.session.SessionState, int, int)
0119: */
0120: protected List readResourcesPage(SessionState state, int first,
0121: int last) {
0122:
0123: List rv = new Vector();
0124: if (state.getAttribute(STATE_ALL_MESSAGES) != null) {
0125: rv = (List) state.getAttribute(STATE_ALL_MESSAGES);
0126: }
0127:
0128: PagingPosition page = new PagingPosition(first, last);
0129: page.validate(rv.size());
0130: rv = rv.subList(page.getFirst() - 1, page.getLast());
0131:
0132: return rv;
0133: }
0134:
0135: /*
0136: * (non-Javadoc)
0137: *
0138: * @see org.sakaiproject.cheftool.PagedResourceActionII#sizeResources(org.sakaiproject.service.framework.session.SessionState)
0139: */
0140: protected int sizeResources(SessionState state) {
0141: int size = 0;
0142: if (state.getAttribute(STATE_ALL_MESSAGES) != null) {
0143: size = ((List) state.getAttribute(STATE_ALL_MESSAGES))
0144: .size();
0145: }
0146: return size;
0147: }
0148:
0149: /**
0150: * Sort support for email messages.
0151: */
0152: private class MyComparator implements Comparator {
0153: /** the criteria - a sort code. */
0154: private int m_criteria = SORT_DATE;
0155:
0156: /** True for ascending sort, false for descending. */
0157: private boolean m_asc = true;
0158:
0159: /**
0160: * constructor
0161: *
0162: * @param criteria
0163: * The sort criteria string
0164: * @param asc
0165: * The sort order string. "true" if ascending; "false" otherwise.
0166: */
0167: public MyComparator(int criteria, boolean asc) {
0168: m_criteria = criteria;
0169: m_asc = asc;
0170:
0171: } // MyComparator
0172:
0173: /**
0174: * Compares its two arguments for order.
0175: *
0176: * @param o1
0177: * The first object.
0178: * @param o2
0179: * The second object.
0180: * @return a a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.
0181: */
0182: public int compare(Object o1, Object o2) {
0183: // make these MailArchiveMessages - let the class cast exception be thrown if not
0184: MailArchiveMessage m1 = (MailArchiveMessage) o1;
0185: MailArchiveMessage m2 = (MailArchiveMessage) o2;
0186:
0187: // if these are the same object (or equal - it may be cheaper to just let the comparison find the equality)
0188: if ((m1 == m2) /* || (m1.equals(m2)) */)
0189: return 0;
0190:
0191: // if it's ascending, use the compareTo value - if descending, reverse it
0192: int orderFactor = (m_asc ? 1 : -1);
0193:
0194: switch (m_criteria) {
0195: case SORT_FROM: {
0196: String addr1 = m1.getMailArchiveHeader()
0197: .getFromAddress();
0198: String addr2 = m2.getMailArchiveHeader()
0199: .getFromAddress();
0200: String rex = "^[^<>]*<[^<>@]*@[^<>@]*>[^<>@]*";
0201: if (addr1.matches(rex)) {
0202: addr1 = addr1.substring(addr1.indexOf('<') + 1,
0203: addr1.indexOf('>'));
0204: }
0205: if (addr2.matches(rex)) {
0206: addr2 = addr2.substring(addr2.indexOf('<') + 1,
0207: addr2.indexOf('>'));
0208: }
0209: return orderFactor * addr1.compareTo(addr2);
0210: }
0211:
0212: case SORT_DATE: {
0213: return orderFactor
0214: * m1.getMailArchiveHeader().getDateSent()
0215: .compareTo(
0216: m2.getMailArchiveHeader()
0217: .getDateSent());
0218: }
0219:
0220: case SORT_SUBJECT: {
0221: String subj1 = m1.getMailArchiveHeader().getSubject()
0222: .toUpperCase();
0223: String subj2 = m2.getMailArchiveHeader().getSubject()
0224: .toUpperCase();
0225: while (subj1.startsWith("RE:")) {
0226: subj1 = subj1.substring(subj1.indexOf(':') + 1)
0227: .trim();
0228: }
0229: while (subj2.startsWith("RE:")) {
0230: subj2 = subj2.substring(subj2.indexOf(':') + 1)
0231: .trim();
0232: }
0233: return orderFactor * subj1.compareTo(subj2);
0234: }
0235: }
0236:
0237: // trouble!
0238: Log.warn("chef",
0239: "MailboxAction.MyComparator - invalid sort: "
0240: + m_criteria);
0241: return 0;
0242:
0243: } // compare
0244:
0245: } // class MyComparator
0246:
0247: /**
0248: * Implement this to return alist of all the resources that there are to page. Sort them as appropriate.
0249: */
0250: protected List readAllResources(SessionState state) {
0251: // read all channel messages
0252: List allMessages = null;
0253: try {
0254: MailArchiveChannel channel = MailArchiveService
0255: .getMailArchiveChannel((String) state
0256: .getAttribute(STATE_CHANNEL_REF));
0257:
0258: allMessages = channel.getMessages(null, true);
0259: } catch (PermissionException e) {
0260: } catch (IdUnusedException e) {
0261: }
0262:
0263: // deal with no messages
0264: if (allMessages == null)
0265: return new Vector();
0266:
0267: String search = (String) state.getAttribute(STATE_SEARCH);
0268:
0269: // filter if searching
0270: if (search != null) {
0271: Vector filtered = new Vector();
0272: for (Iterator iMsgs = allMessages.iterator(); iMsgs
0273: .hasNext();) {
0274: MailArchiveMessage msg = (MailArchiveMessage) iMsgs
0275: .next();
0276:
0277: if (StringUtil.containsIgnoreCase(msg
0278: .getMailArchiveHeader().getSubject(), search)
0279: || StringUtil.containsIgnoreCase(msg
0280: .getMailArchiveHeader()
0281: .getFromAddress(), search)
0282: || StringUtil.containsIgnoreCase(FormattedText
0283: .convertFormattedTextToPlaintext(msg
0284: .getBody()), search)) {
0285: filtered.add(msg);
0286: }
0287: }
0288:
0289: allMessages = filtered;
0290: }
0291:
0292: // if other than ascending date, sort them all
0293: boolean ascending = ((Boolean) state
0294: .getAttribute(STATE_ASCENDING)).booleanValue();
0295: int sort = ((Integer) state.getAttribute(STATE_SORT))
0296: .intValue();
0297: if ((allMessages.size() > 1)
0298: && ((!ascending) || (sort != SORT_DATE))) {
0299: Collections.sort(allMessages, new MyComparator(sort,
0300: ascending));
0301: }
0302:
0303: return allMessages;
0304:
0305: } // readAllResources
0306:
0307: /**
0308: * Populate the state object, if needed.
0309: */
0310: protected void initState(SessionState state,
0311: VelocityPortlet portlet, JetspeedRunData rundata) {
0312: super .initState(state, portlet, rundata);
0313:
0314: if (state.getAttribute(STATE_CHANNEL_REF) == null) {
0315: PortletConfig config = portlet.getPortletConfig();
0316:
0317: // start in list mode
0318: state.setAttribute(STATE_MODE, "list");
0319:
0320: // read the channel from configuration, or, if not specified, use the default for the request
0321: String channel = StringUtil.trimToNull(config
0322: .getInitParameter(PARAM_CHANNEL));
0323: if (channel == null) {
0324: channel = MailArchiveService.channelReference(
0325: ToolManager.getCurrentPlacement().getContext(),
0326: SiteService.MAIN_CONTAINER);
0327: }
0328: state.setAttribute(STATE_CHANNEL_REF, channel);
0329:
0330: if (state.getAttribute(STATE_ASCENDING) == null) {
0331: state.setAttribute(STATE_ASCENDING, new Boolean(false));
0332: }
0333:
0334: if (state.getAttribute(STATE_SORT) == null) {
0335: state.setAttribute(STATE_SORT, new Integer(SORT_DATE));
0336: }
0337:
0338: if (state.getAttribute(STATE_VIEW_HEADERS) == null) {
0339: state.setAttribute(STATE_VIEW_HEADERS, new Boolean(
0340: false));
0341: }
0342:
0343: // // setup the observer to notify our main panel
0344: // if (state.getAttribute(STATE_OBSERVER) == null)
0345: // {
0346: // // the delivery location for this tool
0347: // String deliveryId = clientWindowId(state, portlet.getID());
0348: //
0349: // // the html element to update on delivery
0350: // String elementId = mainPanelUpdateId(portlet.getID());
0351: //
0352: // // the event resource reference pattern to watch for
0353: // Reference r = EntityManager.newReference(channel);
0354: // String pattern = MailArchiveService.messageReference(r.getContext(), r.getId(), "");
0355: //
0356: // state.setAttribute(STATE_OBSERVER, new EventObservingCourier(deliveryId, elementId, pattern));
0357: // }
0358: }
0359:
0360: } // initState
0361:
0362: /**
0363: * build the context for the main panel
0364: *
0365: * @return (optional) template name for this panel
0366: */
0367: public String buildMainPanelContext(VelocityPortlet portlet,
0368: Context context, RunData rundata, SessionState state) {
0369: String mode = (String) state.getAttribute(STATE_MODE);
0370:
0371: context.put(Menu.CONTEXT_ACTION, state
0372: .getAttribute(STATE_ACTION));
0373:
0374: if ("list".equals(mode)) {
0375: return buildListModeContext(portlet, context, rundata,
0376: state);
0377: }
0378:
0379: else if ("confirm-remove".equals(mode)) {
0380: return buildConfirmModeContext(portlet, context, rundata,
0381: state);
0382: }
0383:
0384: else if ("view".equals(mode)) {
0385: return buildViewModeContext(portlet, context, rundata,
0386: state);
0387: }
0388:
0389: else if (MODE_OPTIONS.equals(mode)) {
0390: return buildOptionsPanelContext(portlet, context, rundata,
0391: state);
0392: }
0393:
0394: else {
0395: Log.warn("chef", this
0396: + ".buildMainPanelContext: invalid mode: " + mode);
0397: return null;
0398: }
0399:
0400: } // buildMainPanelContext
0401:
0402: /**
0403: * build the context for the View mode (in the Main panel)
0404: *
0405: * @return (optional) template name for this panel
0406: */
0407: private String buildViewModeContext(VelocityPortlet portlet,
0408: Context context, RunData rundata, SessionState state) {
0409: boolean allowDelete = false;
0410:
0411: // get the message
0412: MailArchiveMessage message = null;
0413:
0414: // prepare the sort of messages
0415: context.put("tlang", rb);
0416: prepPage(state);
0417:
0418: List messages = (List) state.getAttribute(STATE_ALL_MESSAGES);
0419: int pos = ((Integer) state.getAttribute(STATE_VIEW_ID))
0420: .intValue();
0421: message = (MailArchiveMessage) messages.get(pos);
0422:
0423: // fix for SAK-5879
0424: // make sure STATE_MSG_VIEW_ID is updated so that Confirm mode will have access to the correct message id
0425: state.setAttribute(STATE_MSG_VIEW_ID, message.getId());
0426: //
0427:
0428: boolean goNext = state.getAttribute(STATE_NEXT_EXISTS) != null;
0429: boolean goPrev = state.getAttribute(STATE_PREV_EXISTS) != null;
0430: context.put("goPPButton", new Boolean(goPrev));
0431: context.put("goNPButton", new Boolean(goNext));
0432:
0433: try {
0434: MailArchiveChannel channel = MailArchiveService
0435: .getMailArchiveChannel((String) state
0436: .getAttribute(STATE_CHANNEL_REF));
0437: context.put("email", message);
0438:
0439: allowDelete = channel.allowRemoveMessage(message);
0440: } catch (IdUnusedException e) {
0441: } catch (PermissionException e) {
0442: }
0443: if (message == null) {
0444: context.put("message", rb.getString("thiemames1"));
0445: }
0446:
0447: context.put("viewheaders", state
0448: .getAttribute(STATE_VIEW_HEADERS));
0449:
0450: context.put("contentTypeImageService", ContentTypeImageService
0451: .getInstance());
0452:
0453: // build the menu
0454: Menu bar = new MenuImpl(portlet, rundata, (String) state
0455: .getAttribute(STATE_ACTION));
0456:
0457: // bar.add( new MenuEntry(rb.getString("listall"), "doList"));
0458: // addViewPagingMenus(bar, state);
0459:
0460: if (((Boolean) state.getAttribute(STATE_VIEW_HEADERS))
0461: .booleanValue()) {
0462: bar.add(new MenuEntry(rb.getString("hidehead"),
0463: "doHide_headers"));
0464: } else {
0465: bar.add(new MenuEntry(rb.getString("viehea"),
0466: "doView_headers"));
0467: }
0468: if (allowDelete)
0469: bar.add(new MenuEntry(rb.getString("del"), "doRemove"));
0470:
0471: // make sure there's not leading or trailing dividers
0472: bar.adjustDividers();
0473:
0474: context.put(Menu.CONTEXT_MENU, bar);
0475:
0476: return (String) getContext(rundata).get("template") + "-view";
0477:
0478: } // buildViewModeContext
0479:
0480: /*
0481: *
0482: */
0483: /*
0484: * private MailArchiveMessage adjustPaging(Context context, SessionState state) { MailArchiveMessage message = null; List messages = (List) state.getAttribute(STATE_ALL_MESSAGES); int pos = ((Integer) state.getAttribute(STATE_VIEW_ID)).intValue();
0485: * boolean goNext = state.getAttribute(STATE_GO_NEXT) != null; boolean goPrev = state.getAttribute(STATE_GO_PREV) != null; state.removeAttribute(STATE_GO_NEXT); state.removeAttribute(STATE_GO_PREV); if (goNext || goPrev) { if (goNext) { if (pos <
0486: * messages.size()-1) { pos++; } } if (goPrev) { if (pos > 0) { pos--; } } } if (pos == -1) { pos = 0; } if (pos >= messages.size()) { pos = messages.size() -1; } message = (MailArchiveMessage) messages.get(pos); //get the message id if (pos > 0) {
0487: * context.put("goPPButton", Boolean.TRUE); } else { context.put("goPPButton", Boolean.FALSE); } if (pos < sizeResources(state)-1) { context.put("goNPButton", Boolean.TRUE); } else { context.put("goNPButton", Boolean.FALSE); } return message; }
0488: */
0489:
0490: /**
0491: * Build the context for the confirm remove mode (in the Main panel).
0492: */
0493: private String buildConfirmModeContext(VelocityPortlet portlet,
0494: Context context, RunData rundata, SessionState state) {
0495: // get the message
0496: context.put("tlang", rb);
0497: MailArchiveMessage message = null;
0498: try {
0499: MailArchiveChannel channel = MailArchiveService
0500: .getMailArchiveChannel((String) state
0501: .getAttribute(STATE_CHANNEL_REF));
0502: message = channel.getMailArchiveMessage((String) state
0503: .getAttribute(STATE_MSG_VIEW_ID));
0504: context.put("email", message);
0505: } catch (IdUnusedException e) {
0506: } catch (PermissionException e) {
0507: }
0508:
0509: if (message == null) {
0510: context.put("message", rb.getString("thiemames1"));
0511: }
0512:
0513: context.put("viewheaders", state
0514: .getAttribute(STATE_VIEW_HEADERS));
0515:
0516: return (String) getContext(rundata).get("template")
0517: + "-confirm_remove";
0518:
0519: } // buildConfirmModeContext
0520:
0521: /**
0522: * build the context for the list mode (in the Main panel).
0523: */
0524: private String buildListModeContext(VelocityPortlet portlet,
0525: Context context, RunData rundata, SessionState state) {
0526: state.setAttribute(STATE_ALL_MESSAGES, readAllResources(state));
0527:
0528: // prepare the page of messages
0529: context.put("tlang", rb);
0530: List messages = prepPage(state);
0531: context.put("messages", messages);
0532:
0533: // build the menu
0534: Menu bar = new MenuImpl(portlet, rundata, (String) state
0535: .getAttribute(STATE_ACTION));
0536:
0537: // add paging commands
0538: // addListPagingMenus(bar, state);
0539:
0540: // add the search commands
0541: // addSearchMenus(bar, state);
0542:
0543: // add the refresh commands
0544: // addRefreshMenus(bar, state);
0545:
0546: if (SiteService.allowUpdateSite(ToolManager
0547: .getCurrentPlacement().getContext())) {
0548: bar.add(new MenuDivider());
0549:
0550: // add options if allowed
0551: addOptionsMenu(bar, (JetspeedRunData) rundata);
0552:
0553: bar
0554: .add(new MenuEntry(rb.getString("perm"),
0555: "doPermissions"));
0556: }
0557:
0558: // make sure there's not leading or trailing dividers
0559: bar.adjustDividers();
0560:
0561: context.put(Menu.CONTEXT_MENU, bar);
0562:
0563: // output the search field
0564: context.put(STATE_SEARCH, state.getAttribute(STATE_SEARCH));
0565:
0566: // if (state.getAttribute(STATE_NUM_MESSAGES) != null)
0567: // {
0568: // context.put("num-messages", state.getAttribute(STATE_NUM_MESSAGES));
0569: // }
0570:
0571: // eventSubmit value and id field for drill down
0572: context.put("view-id", VIEW_ID);
0573:
0574: context.put(Menu.CONTEXT_ACTION, state
0575: .getAttribute(STATE_ACTION));
0576:
0577: context.put("sort-by", state.getAttribute(STATE_SORT));
0578: context.put("sort-order", state.getAttribute(STATE_ASCENDING));
0579:
0580: pagingInfoToContext(state, context);
0581:
0582: // the aliases for the channel
0583: List all = AliasService.getAliases((String) state
0584: .getAttribute(STATE_CHANNEL_REF));
0585:
0586: // and the aliases for the site (context)
0587: Reference channelRef = EntityManager
0588: .newReference((String) state
0589: .getAttribute(STATE_CHANNEL_REF));
0590: String siteRef = SiteService.siteReference(channelRef
0591: .getContext());
0592: all.addAll(AliasService.getAliases(siteRef));
0593:
0594: context.put("aliases", all);
0595: context.put("nonAlias", channelRef.getContext());
0596: context.put("serverName", ServerConfigurationService
0597: .getServerName());
0598:
0599: // if the user has permission to send mail, drop in the email address
0600: try {
0601: MailArchiveChannel channel = MailArchiveService
0602: .getMailArchiveChannel((String) state
0603: .getAttribute(STATE_CHANNEL_REF));
0604: if (channel.getEnabled()) {
0605: if (channel.getOpen()) {
0606: // if open, mail from anywhere
0607: context.put("validFrom", "*");
0608: } else if (channel.allowAddMessage()) {
0609: User user = UserDirectoryService.getCurrentUser();
0610: String email = user.getEmail();
0611: context.put("validFrom", email);
0612: }
0613: }
0614: } catch (IdUnusedException e) {
0615: addAlert(state, rb.getString("thismaiis"));
0616: } catch (PermissionException e) {
0617: addAlert(state, rb.getString("youdonot1"));
0618: } catch (Exception e) {
0619: }
0620:
0621: // inform the observing courier that we just updated the page...
0622: // if there are pending requests to do so they can be cleared
0623: justDelivered(state);
0624:
0625: return (String) getContext(rundata).get("template") + "-List";
0626:
0627: } // buildListModeContext
0628:
0629: /**
0630: * Handle a user drill down request.
0631: */
0632: public void doView(RunData runData, Context context) {
0633: // access the portlet element id to find our state
0634: String peid = ((JetspeedRunData) runData).getJs_peid();
0635: SessionState state = ((JetspeedRunData) runData)
0636: .getPortletSessionState(peid);
0637:
0638: // switch to view mode
0639: state.setAttribute(STATE_MODE, "view");
0640:
0641: String id = runData.getParameters().getString(VIEW_ID);
0642: state.setAttribute(STATE_MSG_VIEW_ID, id);
0643:
0644: int pos = -1;
0645: List resources = (List) state.getAttribute(STATE_ALL_MESSAGES);
0646: if (resources != null) {
0647: for (int i = 0; i < resources.size(); i++) {
0648: // if this is the one, return this index
0649: if (((MailArchiveMessage) (resources.get(i))).getId()
0650: .equals(id))
0651: pos = i;
0652: }
0653: }
0654: state.setAttribute(STATE_VIEW_ID, new Integer(pos));
0655:
0656: // disable auto-updates while in view mode
0657: disableObservers(state);
0658:
0659: // set the message id
0660: // state.setAttribute(STATE_VIEW_ID, runData.getParameters().getString(VIEW_ID));
0661:
0662: } // doView
0663:
0664: /**
0665: * Handle a return-to-list-view request.
0666: */
0667: public void doList(RunData runData, Context context) {
0668: // access the portlet element id to find our state
0669: String peid = ((JetspeedRunData) runData).getJs_peid();
0670: SessionState state = ((JetspeedRunData) runData)
0671: .getPortletSessionState(peid);
0672:
0673: // switch to view mode
0674: state.setAttribute(STATE_MODE, "list");
0675:
0676: // make sure auto-updates are enabled
0677: enableObserver(state);
0678:
0679: // cleanup
0680: state.removeAttribute(STATE_VIEW_ID);
0681: state.removeAttribute(STATE_MSG_VIEW_ID);
0682:
0683: } // doList
0684:
0685: /**
0686: * Handle a view headers request.
0687: */
0688: public void doView_headers(RunData runData, Context context) {
0689: // access the portlet element id to find our state
0690: String peid = ((JetspeedRunData) runData).getJs_peid();
0691: SessionState state = ((JetspeedRunData) runData)
0692: .getPortletSessionState(peid);
0693:
0694: // switch to view mode
0695: state.setAttribute(STATE_VIEW_HEADERS, new Boolean(true));
0696:
0697: } // doView_headers
0698:
0699: /**
0700: * Handle a hide headers request.
0701: */
0702: public void doHide_headers(RunData runData, Context context) {
0703: // access the portlet element id to find our state
0704: String peid = ((JetspeedRunData) runData).getJs_peid();
0705: SessionState state = ((JetspeedRunData) runData)
0706: .getPortletSessionState(peid);
0707:
0708: // switch to view mode
0709: state.setAttribute(STATE_VIEW_HEADERS, new Boolean(false));
0710:
0711: } // doHide_headers
0712:
0713: /**
0714: * Handle a user request to change the sort to "from"
0715: */
0716: public void doSort_from(RunData runData, Context context) {
0717: // access the portlet element id to find our state
0718: String peid = ((JetspeedRunData) runData).getJs_peid();
0719: SessionState state = ((JetspeedRunData) runData)
0720: .getPortletSessionState(peid);
0721:
0722: // we are changing the sort, so start from the first page again
0723: resetPaging(state);
0724:
0725: // if already from, swap the order
0726: if (((Integer) state.getAttribute(STATE_SORT)).intValue() == SORT_FROM) {
0727: boolean order = !((Boolean) state
0728: .getAttribute(STATE_ASCENDING)).booleanValue();
0729: state.setAttribute(STATE_ASCENDING, new Boolean(order));
0730: }
0731:
0732: // set state
0733: else {
0734: state.setAttribute(STATE_SORT, new Integer(SORT_FROM));
0735: }
0736:
0737: } // doSort_from
0738:
0739: /**
0740: * Handle a user request to change the sort to "date"
0741: */
0742: public void doSort_date(RunData runData, Context context) {
0743: // access the portlet element id to find our state
0744: String peid = ((JetspeedRunData) runData).getJs_peid();
0745: SessionState state = ((JetspeedRunData) runData)
0746: .getPortletSessionState(peid);
0747:
0748: // we are changing the sort, so start from the first page again
0749: resetPaging(state);
0750:
0751: // if already date, swap the order
0752: if (((Integer) state.getAttribute(STATE_SORT)).intValue() == SORT_DATE) {
0753: boolean order = !((Boolean) state
0754: .getAttribute(STATE_ASCENDING)).booleanValue();
0755: state.setAttribute(STATE_ASCENDING, new Boolean(order));
0756: }
0757:
0758: // set state
0759: else {
0760: state.setAttribute(STATE_SORT, new Integer(SORT_DATE));
0761: }
0762:
0763: } // doSort_date
0764:
0765: /**
0766: * Handle a user request to change the sort to "subject"
0767: */
0768: public void doSort_subject(RunData runData, Context context) {
0769: // access the portlet element id to find our state
0770: String peid = ((JetspeedRunData) runData).getJs_peid();
0771: SessionState state = ((JetspeedRunData) runData)
0772: .getPortletSessionState(peid);
0773:
0774: // we are changing the sort, so start from the first page again
0775: resetPaging(state);
0776:
0777: // if already subject, swap the order
0778: if (((Integer) state.getAttribute(STATE_SORT)).intValue() == SORT_SUBJECT) {
0779: boolean order = !((Boolean) state
0780: .getAttribute(STATE_ASCENDING)).booleanValue();
0781: state.setAttribute(STATE_ASCENDING, new Boolean(order));
0782: }
0783:
0784: // set state
0785: else {
0786: state.setAttribute(STATE_SORT, new Integer(SORT_SUBJECT));
0787: }
0788:
0789: } // doSort_subject
0790:
0791: /**
0792: * doRemove called when "eventSubmit_doRemove" is in the request parameters to confirm removal of the group
0793: */
0794: public void doRemove(RunData data, Context context) {
0795: // access the portlet element id to find our state
0796: String peid = ((JetspeedRunData) data).getJs_peid();
0797: SessionState state = ((JetspeedRunData) data)
0798: .getPortletSessionState(peid);
0799:
0800: // go to remove confirm mode
0801: state.setAttribute(STATE_MODE, "confirm-remove");
0802:
0803: // disable auto-updates while in confirm mode
0804: disableObservers(state);
0805:
0806: } // doRemove
0807:
0808: /**
0809: * doRemove_confirmed called when "eventSubmit_doRemove_confirmed" is in the request parameters to remove the group
0810: */
0811: public void doRemove_confirmed(RunData data, Context context) {
0812: // access the portlet element id to find our state
0813: String peid = ((JetspeedRunData) data).getJs_peid();
0814: SessionState state = ((JetspeedRunData) data)
0815: .getPortletSessionState(peid);
0816:
0817: // remove
0818: try {
0819: MailArchiveChannel channel = MailArchiveService
0820: .getMailArchiveChannel((String) state
0821: .getAttribute(STATE_CHANNEL_REF));
0822:
0823: String msgId = (String) state
0824: .getAttribute(STATE_MSG_VIEW_ID);
0825:
0826: if (msgId != null)
0827: channel.removeMessage(msgId);
0828: else
0829: addAlert(state, rb.getString("thimeshas"));
0830: } catch (PermissionException e) {
0831: addAlert(state, rb.getString("youdonot3"));
0832: } catch (IdUnusedException e) {
0833: addAlert(state, rb.getString("thimeshas"));
0834: }
0835:
0836: // go to list mode
0837: doList(data, context);
0838:
0839: } // doRemove_confirmed
0840:
0841: /**
0842: * doCancel_remove called when "eventSubmit_doCancel_remove" is in the request parameters to cancel group removal
0843: */
0844: public void doRemove_cancel(RunData data, Context context) {
0845: // access the portlet element id to find our state
0846: String peid = ((JetspeedRunData) data).getJs_peid();
0847: SessionState state = ((JetspeedRunData) data)
0848: .getPortletSessionState(peid);
0849:
0850: // return to view mode
0851: state.setAttribute(STATE_MODE, "view");
0852:
0853: // disable auto-updates while in view mode
0854: disableObservers(state);
0855:
0856: } // doRemove_cancel
0857:
0858: /**
0859: * Handle a request to set options.
0860: */
0861: public void doOptions(RunData runData, Context context) {
0862: super .doOptions(runData, context);
0863:
0864: // access the portlet element id to find our state
0865: String peid = ((JetspeedRunData) runData).getJs_peid();
0866: SessionState state = ((JetspeedRunData) runData)
0867: .getPortletSessionState(peid);
0868:
0869: // if we ended up in options mode, do whatever else ...
0870: if (!MODE_OPTIONS.equals(state.getAttribute(STATE_MODE)))
0871: return;
0872:
0873: } // doOptions
0874:
0875: /**
0876: * Setup for options.
0877: */
0878: public String buildOptionsPanelContext(VelocityPortlet portlet,
0879: Context context, RunData rundata, SessionState state) {
0880:
0881: context.put("tlang", rb);
0882: // provide "pagesize" with the current page size setting
0883: context.put("pagesize", ((Integer) state
0884: .getAttribute(STATE_PAGESIZE)).toString());
0885:
0886: // provide form names
0887: context.put("form-pagesize", FORM_PAGESIZE);
0888: context.put("form-open", FORM_OPEN);
0889: context.put("form-alias", FORM_ALIAS);
0890: context.put("form-submit", BUTTON + "doUpdate");
0891: context.put("form-cancel", BUTTON + "doCancel");
0892:
0893: // in progress values
0894: if (state.getAttribute(STATE_OPTION_PAGESIZE) != null)
0895: context.put(STATE_OPTION_PAGESIZE, state
0896: .getAttribute(STATE_OPTION_PAGESIZE));
0897: if (state.getAttribute(STATE_OPTION_OPEN) != null)
0898: context.put(STATE_OPTION_OPEN, state
0899: .getAttribute(STATE_OPTION_OPEN));
0900: if (state.getAttribute(STATE_OPTION_ALIAS) != null)
0901: context.put(STATE_OPTION_ALIAS, state
0902: .getAttribute(STATE_OPTION_ALIAS));
0903:
0904: // provide the channel
0905: try {
0906: MailArchiveChannel channel = MailArchiveService
0907: .getMailArchiveChannel((String) state
0908: .getAttribute(STATE_CHANNEL_REF));
0909: context.put("channel", channel);
0910: } catch (Exception ignore) {
0911: }
0912:
0913: // place the current alias, if any, in to context
0914: List all = AliasService.getAliases((String) state
0915: .getAttribute(STATE_CHANNEL_REF), 1, 1);
0916: if (!all.isEmpty())
0917: context.put("alias", ((Alias) all.get(0)).getId());
0918:
0919: context.put("serverName", ServerConfigurationService
0920: .getServerName());
0921:
0922: // pick the "-customize" template based on the standard template name
0923: String template = (String) getContext(rundata).get("template");
0924: return template + "-customize";
0925:
0926: } // buildOptionsPanelContext
0927:
0928: /**
0929: * doUpdate called for form input tags type="submit" named="eventSubmit_doUpdate" update/save from the options process
0930: */
0931: public void doUpdate(RunData data, Context context) {
0932: // access the portlet element id to find our state
0933: String peid = ((JetspeedRunData) data).getJs_peid();
0934: SessionState state = ((JetspeedRunData) data)
0935: .getPortletSessionState(peid);
0936:
0937: // collect & save in state (for possible form re-draw)
0938: // String pagesize = StringUtil.trimToZero(data.getParameters().getString(FORM_PAGESIZE));
0939: // state.setAttribute(STATE_OPTION_PAGESIZE, pagesize);
0940: String open = data.getParameters().getString(FORM_OPEN);
0941: state.setAttribute(STATE_OPTION_OPEN, open);
0942: String alias = StringUtil.trimToNull(data.getParameters()
0943: .getString(FORM_ALIAS));
0944: state.setAttribute(STATE_OPTION_ALIAS, alias);
0945:
0946: MailArchiveChannel channel = null;
0947: try {
0948: channel = MailArchiveService
0949: .getMailArchiveChannel((String) state
0950: .getAttribute(STATE_CHANNEL_REF));
0951: } catch (Exception e) {
0952: addAlert(state, rb.getString("cannot1"));
0953: }
0954:
0955: // first validate - page size
0956: // int size = 0;
0957: // try
0958: // {
0959: // size = Integer.parseInt(pagesize);
0960: // if (size <= 0)
0961: // {
0962: // addAlert(state,rb.getString("pagsiz"));
0963: // }
0964: // }
0965: // catch (Exception any)
0966: // {
0967: // addAlert(state, rb.getString("pagsiz"));
0968: // }
0969:
0970: // validate the email alias
0971: if (alias != null) {
0972: if (!Validator.checkEmailLocal(alias)) {
0973: addAlert(state, rb.getString("theemaali"));
0974: }
0975: }
0976:
0977: // make sure we can get to the channel
0978: MailArchiveChannelEdit edit = null;
0979: try {
0980: edit = (MailArchiveChannelEdit) MailArchiveService
0981: .editChannel(channel.getReference());
0982: } catch (Exception any) {
0983: addAlert(state, rb.getString("theemaarc"));
0984: }
0985:
0986: // if all is well, save
0987: if (state.getAttribute(STATE_MESSAGE) == null) {
0988: // get any current alias for this channel
0989: List all = AliasService.getAliases((String) state
0990: .getAttribute(STATE_CHANNEL_REF), 1, 1);
0991: String curAlias = null;
0992: if (!all.isEmpty())
0993: curAlias = ((Alias) all.get(0)).getId();
0994:
0995: // alias from the form
0996: if (StringUtil.different(curAlias, alias)) {
0997: boolean ok = false;
0998:
0999: // see if this alias exists
1000: if (alias != null) {
1001: try {
1002: String target = AliasService.getTarget(alias);
1003:
1004: // if so, is it this channel?
1005: ok = target.equals(channel.getReference());
1006: } catch (IdUnusedException e) {
1007: // not in use
1008: ok = true;
1009: }
1010: } else {
1011: // no alias is desired
1012: ok = true;
1013: }
1014:
1015: if (ok) {
1016: try {
1017: // first, clear any alias set to this channel
1018: AliasService.removeTargetAliases(channel
1019: .getReference());
1020:
1021: // then add the desired alias
1022: if (alias != null) {
1023: AliasService.setAlias(alias, channel
1024: .getReference());
1025: }
1026: } catch (Exception any) {
1027: addAlert(state, rb.getString("theemaali2"));
1028: }
1029: } else {
1030: addAlert(state, rb.getString("theemaali3"));
1031: }
1032: }
1033:
1034: // if the alias saving went well, go on to the rest
1035: if (state.getAttribute(STATE_MESSAGE) == null) {
1036: // update the channel for open (if changed)
1037: boolean ss = new Boolean(open).booleanValue();
1038: if (channel.getOpen() != ss) {
1039: edit.setOpen(ss);
1040: MailArchiveService.commitChannel(edit);
1041: } else {
1042: MailArchiveService.cancelChannel(edit);
1043: }
1044: edit = null;
1045:
1046: // // update the tool config & state for page size (if different)
1047: // if (size != ((Integer) state.getAttribute(STATE_PAGESIZE)).intValue())
1048: // {
1049: // state.setAttribute(STATE_PAGESIZE, new Integer(size));
1050: // Placement placement = ToolManager.getCurrentPlacement();
1051: // placement.getPlacementConfig().setProperty(PARAM_PAGESIZE, Integer.toString(size));
1052: //
1053: // // commit the options change
1054: // saveOptions();
1055: // }
1056: // else
1057: // {
1058: // cancelOptions();
1059: // }
1060:
1061: // we are done with customization... back to the main (list) mode
1062: state.setAttribute(STATE_MODE, "list");
1063:
1064: // clear state temps.
1065: state.removeAttribute(STATE_OPTION_PAGESIZE);
1066: state.removeAttribute(STATE_OPTION_OPEN);
1067: state.removeAttribute(STATE_OPTION_ALIAS);
1068:
1069: // re-enable auto-updates when going back to list mode
1070: enableObserver(state);
1071: }
1072: }
1073:
1074: // before leaving, make sure the edit was cleared
1075: if (edit != null) {
1076: MailArchiveService.cancelChannel(edit);
1077: edit = null;
1078: }
1079:
1080: } // doUpdate
1081:
1082: /**
1083: * doCancel called for form input tags type="submit" named="eventSubmit_doCancel" cancel the options process
1084: */
1085: public void doCancel(RunData data, Context context) {
1086: // access the portlet element id to find our state
1087: String peid = ((JetspeedRunData) data).getJs_peid();
1088: SessionState state = ((JetspeedRunData) data)
1089: .getPortletSessionState(peid);
1090:
1091: // cancel the options
1092: cancelOptions();
1093:
1094: // we are done with customization... back to the main (list) mode
1095: state.setAttribute(STATE_MODE, "list");
1096:
1097: // clear state temps.
1098: state.removeAttribute(STATE_OPTION_PAGESIZE);
1099: state.removeAttribute(STATE_OPTION_OPEN);
1100: state.removeAttribute(STATE_OPTION_ALIAS);
1101:
1102: // re-enable auto-updates when going back to list mode
1103: enableObserver(state);
1104:
1105: } // doCancel
1106:
1107: /**
1108: * Fire up the permissions editor
1109: */
1110: public void doPermissions(RunData data, Context context) {
1111: // get into helper mode with this helper tool
1112: startHelper(data.getRequest(), "sakai.permissions.helper");
1113:
1114: SessionState state = ((JetspeedRunData) data)
1115: .getPortletSessionState(((JetspeedRunData) data)
1116: .getJs_peid());
1117:
1118: String channelRefStr = (String) state
1119: .getAttribute(STATE_CHANNEL_REF);
1120: Reference channelRef = EntityManager
1121: .newReference(channelRefStr);
1122: String siteRef = SiteService.siteReference(channelRef
1123: .getContext());
1124:
1125: // setup for editing the permissions of the site for this tool, using the roles of this site, too
1126: state.setAttribute(PermissionsHelper.TARGET_REF, siteRef);
1127:
1128: // ... with this description
1129: state.setAttribute(PermissionsHelper.DESCRIPTION, rb
1130: .getString("setperm")
1131: + SiteService.getSiteDisplay(channelRef.getContext()));
1132:
1133: // ... showing only locks that are prpefixed with this
1134: state.setAttribute(PermissionsHelper.PREFIX, "mail.");
1135:
1136: } // doPermissions
1137:
1138: } // MailboxAction
|