/**********************************************************************************
* $URL: https://source.sakaiproject.org/svn/mailarchive/trunk/mailarchive-tool/tool/src/java/org/sakaiproject/mailarchive/tool/MailboxAction.java $
* $Id: MailboxAction.java 131929 2013-11-25 17:56:30Z dsobiera@indiana.edu $
***********************************************************************************
*
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008 The Sakai Foundation
*
* Licensed under the Educational Community License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.opensource.org/licenses/ECL-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
**********************************************************************************/
package org.sakaiproject.mailarchive.tool;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import java.util.Map.Entry;
import org.sakaiproject.alias.api.Alias;
import org.sakaiproject.alias.cover.AliasService;
import org.sakaiproject.authz.api.PermissionsHelper;
import org.sakaiproject.cheftool.Context;
import org.sakaiproject.cheftool.JetspeedRunData;
import org.sakaiproject.cheftool.PagedResourceActionII;
import org.sakaiproject.cheftool.PortletConfig;
import org.sakaiproject.cheftool.RunData;
import org.sakaiproject.cheftool.VelocityPortlet;
import org.sakaiproject.cheftool.api.Menu;
import org.sakaiproject.cheftool.menu.MenuDivider;
import org.sakaiproject.cheftool.menu.MenuEntry;
import org.sakaiproject.cheftool.menu.MenuImpl;
import org.sakaiproject.component.cover.ServerConfigurationService;
import org.sakaiproject.content.cover.ContentTypeImageService;
import org.sakaiproject.entity.api.Reference;
import org.sakaiproject.entity.cover.EntityManager;
import org.sakaiproject.event.api.SessionState;
import org.sakaiproject.exception.IdUnusedException;
import org.sakaiproject.exception.InUseException;
import org.sakaiproject.exception.PermissionException;
import org.sakaiproject.exception.IdInvalidException;
import org.sakaiproject.javax.Filter;
import org.sakaiproject.javax.Order;
import org.sakaiproject.javax.PagingPosition;
import org.sakaiproject.javax.Search;
import org.sakaiproject.javax.SearchFilter;
import org.sakaiproject.mailarchive.api.MailArchiveChannel;
import org.sakaiproject.mailarchive.api.MailArchiveChannelEdit;
import org.sakaiproject.mailarchive.api.MailArchiveMessage;
import org.sakaiproject.mailarchive.cover.MailArchiveService;
import org.sakaiproject.message.api.Message;
import org.sakaiproject.site.cover.SiteService;
import org.sakaiproject.tool.cover.ToolManager;
import org.sakaiproject.user.api.User;
import org.sakaiproject.user.cover.UserDirectoryService;
import org.sakaiproject.util.FormattedText;
import org.sakaiproject.util.ResourceLoader;
import org.sakaiproject.util.StringUtil;
import org.apache.commons.lang.StringUtils;
import org.sakaiproject.util.Validator;
/**
* <p>
* MailboxAction is a the Sakai mailbox tool.
* </p>
*/
public class MailboxAction extends PagedResourceActionII
{
private static ResourceLoader rb = new ResourceLoader("email");
/** portlet configuration parameter names. */
private static final String PARAM_CHANNEL = "channel";
private static final String PARAM_SITE = "site";
private static final String PARAM_SHOW_NON_ALIAS = "showNonAlias";
/** Configure form field names. */
private static final String FORM_CHANNEL = "channel";
private static final String FORM_PAGESIZE = "pagesize";
private static final String FORM_OPEN = "open";
private static final String FORM_REPLY = "reply";
private static final String FORM_SENDTO = "sendto";
private static final String FORM_ALIAS = "alias";
private static final int FORM_ALIAS_MAX_LENGTH = 99;
private static final String FORM_ITEM_NUMBER = "item_number";
/** List request parameters. */
private static final String VIEW_ID = "view-id";
/** state attribute names. */
private static final String STATE_CHANNEL_REF = "channelId";
private static final String STATE_ASCENDING = "ascending";
private static final String STATE_SORT = "sort";
private static final String STATE_VIEW_HEADERS = "view-headers";
private static final String STATE_OPTION_PAGESIZE = "optSize";
private static final String STATE_OPTION_OPEN = "optOpen";
private static final String STATE_OPTION_REPLY = "optReply";
private static final String STATE_OPTION_SENDTO = "optSendTo";
private static final String STATE_OPTION_ALIAS = "optAlias";
private static final String STATE_SHOW_NON_ALIAS = "showNonAlias";
private static final String STATE_ALERT_MESSAGE = "alertMessage";
private static final String STATE_DELETE_CONFIRM_ID = "confirmDeleteId";
/** Sort codes. */
private static final int SORT_FROM = 0;
private static final int SORT_DATE = 1;
private static final int SORT_SUBJECT = 2;
/** paging */
private static final String STATE_MSG_VIEW_ID = "msg-id";
/** State to cache the count of messages */
private static final String STATE_COUNT = "state-cached-count";
private static final String STATE_COUNT_SEARCH = "state-cached-count-search";
/** Default for search suppression threshold */
private final int MESSAGE_THRESHOLD_DEFAULT = 2500;
/** paging */
/*
* (non-Javadoc)
*
* @see org.sakaiproject.cheftool.PagedResourceActionII#sizeResources(org.sakaiproject.service.framework.session.SessionState)
*/
protected int sizeResources(SessionState state)
{
String search = (String) state.getAttribute(STATE_SEARCH);
// We cache the count at the tool level because it is not done perfectly
// at the lower layer
Integer lastCount = (Integer) state.getAttribute(STATE_COUNT);
String countSearch = (String) state.getAttribute(STATE_COUNT_SEARCH);
if ( search == null && countSearch == null && lastCount != null )
{
return lastCount.intValue();
}
if ( countSearch != null && countSearch.equals(search))
{
return lastCount.intValue();
}
// We must talk to the Storage to count the messages
try
{
MailArchiveChannel channel = MailArchiveService.getMailArchiveChannel((String) state.getAttribute(STATE_CHANNEL_REF));
int cCount = 0;
if(search == null) {
cCount = channel.getCount();
} else {
cCount = channel.getCount((Filter) getSearchFilter(search, 0, 0));
}
lastCount = new Integer(cCount);
state.setAttribute(STATE_COUNT, lastCount);
state.setAttribute(STATE_COUNT_SEARCH, search);
return cCount;
}
catch (Exception e)
{
Log.warn("sakai", "sizeResources failed search="+search+" exeption="+e);
}
return 0;
}
/*
* (non-Javadoc)
*
* @see org.sakaiproject.cheftool.PagedResourceActionII#readResourcesPage(org.sakaiproject.service.framework.session.SessionState, int, int)
*/
protected List readResourcesPage(SessionState state, int first, int last)
{
// read all channel messages
List allMessages = null;
boolean ascending = ((Boolean) state.getAttribute(STATE_ASCENDING)).booleanValue();
int sort = ((Integer) state.getAttribute(STATE_SORT)).intValue();
String search = (String) state.getAttribute(STATE_SEARCH);
try
{
MailArchiveChannel channel = MailArchiveService.getMailArchiveChannel((String) state.getAttribute(STATE_CHANNEL_REF));
Search f = getSearchFilter(search, first, last);
if ( sort == SORT_FROM )
{
f.setOrders(new Order[] { new Order("OWNER",ascending) } );
}
else if ( sort == SORT_SUBJECT )
{
f.setOrders(new Order[] { new Order("SUBJECT",ascending) } );
}
allMessages = channel.getMessages((Filter) f, ascending, null);
}
catch (Exception e)
{
Log.warn("sakai", "readResourcesPage not able to retrieve messages sort ="+
sort+" search = "+search+" first="+first+" last="+last);
}
// deal with no messages
if (allMessages == null) return new Vector();
return allMessages;
} // readPagedResources
/**
* Populate the state object, if needed.
*/
protected void initState(SessionState state, VelocityPortlet portlet, JetspeedRunData rundata)
{
super.initState(state, portlet, rundata);
if (state.getAttribute(STATE_CHANNEL_REF) == null)
{
PortletConfig config = portlet.getPortletConfig();
// start in list mode
state.setAttribute(STATE_MODE, "list");
// read the channel from configuration, or, if not specified, use the default for the request
String channel = StringUtils.trimToNull(config.getInitParameter(PARAM_CHANNEL));
if (channel == null)
{
channel = MailArchiveService.channelReference(ToolManager.getCurrentPlacement().getContext(),
SiteService.MAIN_CONTAINER);
}
state.setAttribute(STATE_CHANNEL_REF, channel);
if (state.getAttribute(STATE_SHOW_NON_ALIAS) == null)
{
Boolean showNonAlias = Boolean.parseBoolean(config.getInitParameter(PARAM_SHOW_NON_ALIAS, "false"));
state.setAttribute(STATE_SHOW_NON_ALIAS, showNonAlias);
}
if (state.getAttribute(STATE_ASCENDING) == null)
{
state.setAttribute(STATE_ASCENDING, Boolean.valueOf(false));
}
if (state.getAttribute(STATE_SORT) == null)
{
state.setAttribute(STATE_SORT, Integer.valueOf(SORT_DATE));
}
if (state.getAttribute(STATE_VIEW_HEADERS) == null)
{
state.setAttribute(STATE_VIEW_HEADERS, Boolean.valueOf(false));
}
}
} // initState
/**
* build the context for the main panel
*
* @return (optional) template name for this panel
*/
public String buildMainPanelContext(VelocityPortlet portlet, Context context, RunData rundata, SessionState state)
{
String mode = (String) state.getAttribute(STATE_MODE);
context.put(Menu.CONTEXT_ACTION, state.getAttribute(STATE_ACTION));
String alertMessage = (String) state.getAttribute(STATE_ALERT_MESSAGE);
if ( alertMessage != null )
{
state.setAttribute(STATE_ALERT_MESSAGE, null);
context.put(STATE_ALERT_MESSAGE, alertMessage);
}
// Put this back only for Confirm
String deleteConfirm = (String) state.getAttribute(STATE_DELETE_CONFIRM_ID);
state.removeAttribute(STATE_DELETE_CONFIRM_ID);
if ("list".equals(mode))
{
return buildListModeContext(portlet, context, rundata, state);
}
else if ("confirm-remove".equals(mode))
{
if ( deleteConfirm != null && deleteConfirm.length() > 0 )
{
state.setAttribute(STATE_DELETE_CONFIRM_ID,deleteConfirm);
}
return buildConfirmModeContext(portlet, context, rundata, state);
}
else if ("view".equals(mode))
{
return buildViewModeContext(portlet, context, rundata, state);
}
else if (MODE_OPTIONS.equals(mode))
{
return buildOptionsPanelContext(portlet, context, rundata, state);
}
else
{
Log.warn("sakai", this + ".buildMainPanelContext: invalid mode: " + mode);
return null;
}
} // buildMainPanelContext
/**
* build the context for the View mode (in the Main panel)
*
* @return (optional) template name for this panel
*/
private String buildViewModeContext(VelocityPortlet portlet, Context context, RunData rundata, SessionState state)
{
boolean allowDelete = false;
int viewPos = ((Integer) state.getAttribute(FORM_ITEM_NUMBER)).intValue();
int numMessages = sizeResources(state);
int prevPos = viewPos - 1;
int nextPos = viewPos + 1;
state.setAttribute(STATE_PREV_EXISTS, "");
state.setAttribute(STATE_NEXT_EXISTS, "");
// Message numbers are one-based
boolean goPrev = (prevPos > 0);
boolean goNext = (nextPos <= numMessages);
context.put("viewPos",viewPos);
context.put("nextPos",nextPos);
context.put("goNPButton", Boolean.valueOf(goNext));
context.put("prevPos",prevPos);
context.put("goPPButton", Boolean.valueOf(goPrev));
// prepare the sort of messages
context.put("tlang", rb);
String channelRef = (String) state.getAttribute(STATE_CHANNEL_REF);
MailArchiveChannel channel = null;
try
{
channel = MailArchiveService.getMailArchiveChannel(channelRef);
}
catch (Exception e)
{
Log.warn("sakai", "Cannot find channel "+channelRef);
}
// Read a single message
List messagePage = readResourcesPage(state, viewPos, viewPos);
if ( messagePage != null ) {
Message msg = (Message) messagePage.get(0);
context.put("email",msg);
allowDelete = channel.allowRemoveMessage(msg);
// Sadly this is the only way to send this to a menu pick :(
state.setAttribute(STATE_DELETE_CONFIRM_ID, msg.getId());
} else {
Log.warn("sakai", "Could not retrieve message "+channelRef);
context.put("message", rb.getString("thiemames1"));
}
context.put("viewheaders", state.getAttribute(STATE_VIEW_HEADERS));
context.put("contentTypeImageService", ContentTypeImageService.getInstance());
// build the menu
Menu bar = new MenuImpl(portlet, rundata, (String) state.getAttribute(STATE_ACTION));
// bar.add( new MenuEntry(rb.getString("listall"), "doList"));
// addViewPagingMenus(bar, state);
if (((Boolean) state.getAttribute(STATE_VIEW_HEADERS)).booleanValue())
{
bar.add(new MenuEntry(rb.getString("hidehead"), "doHide_headers"));
}
else
{
bar.add(new MenuEntry(rb.getString("viehea"), "doView_headers"));
}
if (allowDelete) bar.add(new MenuEntry(rb.getString("del"), "doRemove"));
// make sure there's not leading or trailing dividers
bar.adjustDividers();
context.put(Menu.CONTEXT_MENU, bar);
return (String) getContext(rundata).get("template") + "-view";
} // buildViewModeContext
/**
* Build the context for the confirm remove mode (in the Main panel).
*/
private String buildConfirmModeContext(VelocityPortlet portlet, Context context, RunData rundata, SessionState state)
{
// get the message
context.put("tlang", rb);
String id = (String) state.getAttribute(STATE_DELETE_CONFIRM_ID);
MailArchiveMessage message = null;
try
{
MailArchiveChannel channel = MailArchiveService.getMailArchiveChannel((String) state.getAttribute(STATE_CHANNEL_REF));
message = channel.getMailArchiveMessage(id);
context.put("email", message);
context.put(STATE_DELETE_CONFIRM_ID, message.getId());
}
catch (IdUnusedException e)
{
}
catch (PermissionException e)
{
}
if (message == null)
{
context.put("message", rb.getString("thiemames1"));
}
context.put("viewheaders", state.getAttribute(STATE_VIEW_HEADERS));
return (String) getContext(rundata).get("template") + "-confirm_remove";
} // buildConfirmModeContext
/**
* build the context for the list mode (in the Main panel).
*/
private String buildListModeContext(VelocityPortlet portlet, Context context, RunData rundata, SessionState state)
{
// prepare the page of messages
context.put("tlang", rb);
List messages = prepPage(state);
context.put("messages", messages);
// build the menu
Menu bar = new MenuImpl(portlet, rundata, (String) state.getAttribute(STATE_ACTION));
if (SiteService.allowUpdateSite(ToolManager.getCurrentPlacement().getContext()))
{
bar.add(new MenuDivider());
// add options if allowed
addOptionsMenu(bar, (JetspeedRunData) rundata);
bar.add(new MenuEntry(rb.getString("perm"), "doPermissions"));
}
// make sure there's not leading or trailing dividers
bar.adjustDividers();
context.put(Menu.CONTEXT_MENU, bar);
// Decide if we are going to allow searching...
int numMessages = sizeResources(state);
int messageLimit = getMessageThreshold();
context.put("allow-search",Boolean.valueOf(numMessages <= messageLimit));
// output the search field
context.put(STATE_SEARCH, state.getAttribute(STATE_SEARCH));
// eventSubmit value and id field for drill down
context.put("view-id", VIEW_ID);
context.put(Menu.CONTEXT_ACTION, state.getAttribute(STATE_ACTION));
context.put("sort-by", state.getAttribute(STATE_SORT));
context.put("sort-order", state.getAttribute(STATE_ASCENDING));
pagingInfoToContext(state, context);
// the aliases for the channel
List all = AliasService.getAliases((String) state.getAttribute(STATE_CHANNEL_REF));
// and the aliases for the site (context)
Reference channelRef = EntityManager.newReference((String) state.getAttribute(STATE_CHANNEL_REF));
String siteRef = SiteService.siteReference(channelRef.getContext());
all.addAll(AliasService.getAliases(siteRef));
context.put("aliases", all);
if (all.size() == 0 || (Boolean)state.getAttribute(STATE_SHOW_NON_ALIAS))
{
context.put("nonAlias", channelRef.getContext());
}
context.put("serverName", ServerConfigurationService.getServerName());
// if the user has permission to send mail, drop in the email address
try
{
MailArchiveChannel channel = MailArchiveService.getMailArchiveChannel((String) state.getAttribute(STATE_CHANNEL_REF));
if (channel.getEnabled())
{
if (channel.getOpen())
{
// if open, mail from anywhere
context.put("validFrom", "*");
}
else if (channel.allowAddMessage())
{
User user = UserDirectoryService.getCurrentUser();
String email = user.getEmail();
context.put("validFrom", email);
}
context.put(STATE_OPTION_SENDTO, channel.getSendToList());
}
}
catch (IdUnusedException e)
{
addAlert(state, rb.getString("thismaiis"));
}
catch (PermissionException e)
{
addAlert(state, rb.getString("youdonot1"));
}
catch (Exception e)
{
}
// inform the observing courier that we just updated the page...
// if there are pending requests to do so they can be cleared
justDelivered(state);
return (String) getContext(rundata).get("template") + "-List";
} // buildListModeContext
/**
* Handle a user drill down request.
*/
public void doView(RunData runData, Context context)
{
// access the portlet element id to find our state
String peid = ((JetspeedRunData) runData).getJs_peid();
SessionState state = ((JetspeedRunData) runData).getPortletSessionState(peid);
// switch to view mode
state.setAttribute(STATE_MODE, "view");
String id = runData.getParameters().getString(VIEW_ID);
state.setAttribute(STATE_MSG_VIEW_ID, id);
String position = runData.getParameters().getString(FORM_ITEM_NUMBER);
state.setAttribute(FORM_ITEM_NUMBER, Integer.valueOf(position));
// disable auto-updates while in view mode
disableObservers(state);
} // doView
/**
* Handle a return-to-list-view request.
*/
public void doList(RunData runData, Context context)
{
// access the portlet element id to find our state
String peid = ((JetspeedRunData) runData).getJs_peid();
SessionState state = ((JetspeedRunData) runData).getPortletSessionState(peid);
// switch to view mode
state.setAttribute(STATE_MODE, "list");
// make sure auto-updates are enabled
enableObserver(state);
state.removeAttribute(STATE_MSG_VIEW_ID);
} // doList
/**
* Handle a view headers request.
*/
public void doView_headers(RunData runData, Context context)
{
// access the portlet element id to find our state
String peid = ((JetspeedRunData) runData).getJs_peid();
SessionState state = ((JetspeedRunData) runData).getPortletSessionState(peid);
// switch to view mode
state.setAttribute(STATE_VIEW_HEADERS, Boolean.valueOf(true));
} // doView_headers
/**
* Handle a hide headers request.
*/
public void doHide_headers(RunData runData, Context context)
{
// access the portlet element id to find our state
String peid = ((JetspeedRunData) runData).getJs_peid();
SessionState state = ((JetspeedRunData) runData).getPortletSessionState(peid);
// switch to view mode
state.setAttribute(STATE_VIEW_HEADERS, Boolean.valueOf(false));
} // doHide_headers
/**
* Handle a user request to change the sort to "from"
*/
public void doSort_from(RunData runData, Context context)
{
// access the portlet element id to find our state
String peid = ((JetspeedRunData) runData).getJs_peid();
SessionState state = ((JetspeedRunData) runData).getPortletSessionState(peid);
// we are changing the sort, so start from the first page again
resetPaging(state);
// if already from, swap the order
if (((Integer) state.getAttribute(STATE_SORT)).intValue() == SORT_FROM)
{
boolean order = !((Boolean) state.getAttribute(STATE_ASCENDING)).booleanValue();
state.setAttribute(STATE_ASCENDING, Boolean.valueOf(order));
}
// set state
else
{
state.setAttribute(STATE_SORT, Integer.valueOf(SORT_FROM));
}
} // doSort_from
/**
* Handle a user request to change the sort to "date"
*/
public void doSort_date(RunData runData, Context context)
{
// access the portlet element id to find our state
String peid = ((JetspeedRunData) runData).getJs_peid();
SessionState state = ((JetspeedRunData) runData).getPortletSessionState(peid);
// we are changing the sort, so start from the first page again
resetPaging(state);
// if already date, swap the order
if (((Integer) state.getAttribute(STATE_SORT)).intValue() == SORT_DATE)
{
boolean order = !((Boolean) state.getAttribute(STATE_ASCENDING)).booleanValue();
state.setAttribute(STATE_ASCENDING, Boolean.valueOf(order));
}
// set state
else
{
state.setAttribute(STATE_SORT, Integer.valueOf(SORT_DATE));
}
} // doSort_date
/**
* Handle a user request to change the sort to "subject"
*/
public void doSort_subject(RunData runData, Context context)
{
// access the portlet element id to find our state
String peid = ((JetspeedRunData) runData).getJs_peid();
SessionState state = ((JetspeedRunData) runData).getPortletSessionState(peid);
// we are changing the sort, so start from the first page again
resetPaging(state);
// if already subject, swap the order
if (((Integer) state.getAttribute(STATE_SORT)).intValue() == SORT_SUBJECT)
{
boolean order = !((Boolean) state.getAttribute(STATE_ASCENDING)).booleanValue();
state.setAttribute(STATE_ASCENDING, Boolean.valueOf(order));
}
// set state
else
{
state.setAttribute(STATE_SORT, Integer.valueOf(SORT_SUBJECT));
}
} // doSort_subject
/**
* doRemove called when "eventSubmit_doRemove" is in the request parameters to confirm removal of the group
*/
public void doRemove(RunData data, Context context)
{
// access the portlet element id to find our state
String peid = ((JetspeedRunData) data).getJs_peid();
SessionState state = ((JetspeedRunData) data).getPortletSessionState(peid);
// go to remove confirm mode
state.setAttribute(STATE_MODE, "confirm-remove");
// disable auto-updates while in confirm mode
disableObservers(state);
} // doRemove
/**
* doRemove_confirmed called when "eventSubmit_doRemove_confirmed" is in the request parameters to remove the group
*/
public void doRemove_confirmed(RunData data, Context context)
{
// access the portlet element id to find our state
String peid = ((JetspeedRunData) data).getJs_peid();
SessionState state = ((JetspeedRunData) data).getPortletSessionState(peid);
// Grab and remove immedaitely
String msgId = (String) state.getAttribute(STATE_DELETE_CONFIRM_ID);
state.removeAttribute(STATE_DELETE_CONFIRM_ID);
state.removeAttribute(STATE_COUNT);
state.removeAttribute(STATE_COUNT_SEARCH);
// remove
try
{
MailArchiveChannel channel = MailArchiveService.getMailArchiveChannel((String) state.getAttribute(STATE_CHANNEL_REF));
if (msgId != null)
channel.removeMessage(msgId);
else
addAlert(state, rb.getString("thimeshas"));
}
catch (PermissionException e)
{
addAlert(state, rb.getString("youdonot3"));
}
catch (IdUnusedException e)
{
addAlert(state, rb.getString("thimeshas"));
}
// go to list mode
doList(data, context);
} // doRemove_confirmed
/**
* doCancel_remove called when "eventSubmit_doCancel_remove" is in the request parameters to cancel group removal
*/
public void doRemove_cancel(RunData data, Context context)
{
// access the portlet element id to find our state
String peid = ((JetspeedRunData) data).getJs_peid();
SessionState state = ((JetspeedRunData) data).getPortletSessionState(peid);
// Clean up state
state.removeAttribute(STATE_MSG_VIEW_ID);
// return to view mode
state.setAttribute(STATE_MODE, "view");
// disable auto-updates while in view mode
disableObservers(state);
} // doRemove_cancel
/**
* Handle a request to set options.
*/
public void doOptions(RunData runData, Context context)
{
super.doOptions(runData, context);
// access the portlet element id to find our state
String peid = ((JetspeedRunData) runData).getJs_peid();
SessionState state = ((JetspeedRunData) runData).getPortletSessionState(peid);
// if we ended up in options mode, do whatever else ...
if (!MODE_OPTIONS.equals(state.getAttribute(STATE_MODE))) return;
} // doOptions
/**
* Setup for options.
*/
public String buildOptionsPanelContext(VelocityPortlet portlet, Context context, RunData rundata, SessionState state)
{
context.put("tlang", rb);
// provide "pagesize" with the current page size setting
context.put("pagesize", ((Integer) state.getAttribute(STATE_PAGESIZE)).toString());
// provide form names
context.put("form-pagesize", FORM_PAGESIZE);
context.put("form-open", FORM_OPEN);
context.put("form-reply", FORM_REPLY);
context.put("form-sendto", FORM_SENDTO);
context.put("form-alias", FORM_ALIAS);
context.put("form-alias-max-length",FORM_ALIAS_MAX_LENGTH);
context.put("form-submit", BUTTON + "doUpdate");
context.put("form-cancel", BUTTON + "doCancel");
// in progress values
if (state.getAttribute(STATE_OPTION_PAGESIZE) != null)
context.put(STATE_OPTION_PAGESIZE, state.getAttribute(STATE_OPTION_PAGESIZE));
if (state.getAttribute(STATE_OPTION_OPEN) != null)
context.put(STATE_OPTION_OPEN, state.getAttribute(STATE_OPTION_OPEN));
if (state.getAttribute(STATE_OPTION_REPLY) != null)
context.put(STATE_OPTION_REPLY, state.getAttribute(STATE_OPTION_REPLY));
if (state.getAttribute(STATE_OPTION_SENDTO) != null)
context.put(STATE_OPTION_SENDTO, state.getAttribute(STATE_OPTION_SENDTO));
if (state.getAttribute(STATE_OPTION_ALIAS) != null)
context.put(STATE_OPTION_ALIAS, state.getAttribute(STATE_OPTION_ALIAS));
// provide the channel
try
{
MailArchiveChannel channel = MailArchiveService.getMailArchiveChannel((String) state.getAttribute(STATE_CHANNEL_REF));
context.put("channel", channel);
}
catch (Exception ignore)
{
}
// place the current alias, if any, in to context
List all = AliasService.getAliases((String) state.getAttribute(STATE_CHANNEL_REF), 1, 1);
if (!all.isEmpty()) context.put("alias", ((Alias) all.get(0)).getId());
context.put("serverName", ServerConfigurationService.getServerName());
// pick the "-customize" template based on the standard template name
String template = (String) getContext(rundata).get("template");
return template + "-customize";
} // buildOptionsPanelContext
/**
* doUpdate called for form input tags type="submit" named="eventSubmit_doUpdate" update/save from the options process
*/
public void doUpdate(RunData data, Context context)
{
// access the portlet element id to find our state
String peid = ((JetspeedRunData) data).getJs_peid();
SessionState state = ((JetspeedRunData) data).getPortletSessionState(peid);
// collect & save in state (for possible form re-draw)
// String pagesize = StringUtil.trimToZero(data.getParameters().getString(FORM_PAGESIZE));
// state.setAttribute(STATE_OPTION_PAGESIZE, pagesize);
String open = data.getParameters().getString(FORM_OPEN);
state.setAttribute(STATE_OPTION_OPEN, open);
String replyToList = data.getParameters().getString(FORM_REPLY);
state.setAttribute(STATE_OPTION_REPLY, replyToList);
String sendToList = data.getParameters().getString(FORM_SENDTO);
state.setAttribute(STATE_OPTION_SENDTO, sendToList);
String alias = StringUtils.trimToNull(data.getParameters().getString(FORM_ALIAS));
state.setAttribute(STATE_OPTION_ALIAS, alias);
MailArchiveChannel channel = null;
try
{
channel = MailArchiveService.getMailArchiveChannel((String) state.getAttribute(STATE_CHANNEL_REF));
}
catch (Exception e)
{
addAlert(state, rb.getString("cannot1"));
channel = null;
}
if (channel == null)
{
addAlert(state, rb.getString("theemaarc"));
return;
}
// validate the email alias
if (alias != null)
{
if (!Validator.checkEmailLocal(alias))
{
addAlert(state, rb.getString("theemaali"));
}
}
// make sure we can get to the channel
MailArchiveChannelEdit edit = null;
try {
edit = (MailArchiveChannelEdit) MailArchiveService.editChannel(channel.getReference());
} catch (IdUnusedException e1) {
addAlert(state, rb.getString("theemaali"));
} catch (PermissionException e1) {
addAlert(state, rb.getString("theemaali"));
} catch (InUseException e1) {
addAlert(state, rb.getString("theemaali")); }
// if all is well, save
if (state.getAttribute(STATE_MESSAGE) == null)
{
// get any current alias for this channel
List all = AliasService.getAliases((String) state.getAttribute(STATE_CHANNEL_REF), 1, 1);
String curAlias = null;
if (!all.isEmpty()) curAlias = ((Alias) all.get(0)).getId();
// alias from the form
if (StringUtil.different(curAlias, alias))
{
boolean ok = false;
// see if this alias exists
if (alias != null)
{
try
{
String target = AliasService.getTarget(alias);
// if so, is it this channel?
ok = target.equals(channel.getReference());
}
catch (IdUnusedException e)
{
// not in use
ok = true;
}
}
else
{
// no alias is desired
ok = true;
}
if (ok)
{
try
{
if ( alias == null ) {
AliasService.removeTargetAliases(channel.getReference());
} else {
AliasService.setAlias(alias, channel.getReference());
}
}
catch (IdInvalidException iie) {
addAlert(state, rb.getString("theemaali4"));
}
catch (Exception any)
{
addAlert(state, rb.getString("theemaali2"));
}
}
else
{
addAlert(state, rb.getString("theemaali3"));
}
}
// if the alias saving went well, go on to the rest
if (state.getAttribute(STATE_MESSAGE) == null)
{
boolean modified = false;
// update the channel for open (if changed)
boolean ss = Boolean.valueOf(open).booleanValue();
if (channel.getOpen() != ss)
{
edit.setOpen(ss);
modified = true;
}
ss = Boolean.valueOf(replyToList).booleanValue();
if (channel.getReplyToList() != ss)
{
edit.setReplyToList(ss);
modified = true;
}
ss = Boolean.valueOf(sendToList).booleanValue();
if (channel.getSendToList() != ss)
{
edit.setSendToList(ss);
modified = true;
}
if (modified)
{
MailArchiveService.commitChannel(edit);
}
else
{
MailArchiveService.cancelChannel(edit);
}
edit = null;
// we are done with customization... back to the main (list) mode
state.setAttribute(STATE_MODE, "list");
// clear state temps.
state.removeAttribute(STATE_OPTION_PAGESIZE);
state.removeAttribute(STATE_OPTION_OPEN);
state.removeAttribute(STATE_OPTION_REPLY);
state.removeAttribute(STATE_OPTION_SENDTO);
state.removeAttribute(STATE_OPTION_ALIAS);
// re-enable auto-updates when going back to list mode
enableObserver(state);
}
}
// before leaving, make sure the edit was cleared
if (edit != null)
{
MailArchiveService.cancelChannel(edit);
edit = null;
}
} // doUpdate
/**
* doCancel called for form input tags type="submit" named="eventSubmit_doCancel" cancel the options process
*/
public void doCancel(RunData data, Context context)
{
// access the portlet element id to find our state
String peid = ((JetspeedRunData) data).getJs_peid();
SessionState state = ((JetspeedRunData) data).getPortletSessionState(peid);
// cancel the options
cancelOptions();
// we are done with customization... back to the main (list) mode
state.setAttribute(STATE_MODE, "list");
// clear state temps.
state.removeAttribute(STATE_OPTION_PAGESIZE);
state.removeAttribute(STATE_OPTION_OPEN);
state.removeAttribute(STATE_OPTION_REPLY);
state.removeAttribute(STATE_OPTION_SENDTO);
state.removeAttribute(STATE_OPTION_ALIAS);
// re-enable auto-updates when going back to list mode
enableObserver(state);
} // doCancel
/**
* Fire up the permissions editor
*/
public void doPermissions(RunData data, Context context)
{
// get into helper mode with this helper tool
startHelper(data.getRequest(), "sakai.permissions.helper");
SessionState state = ((JetspeedRunData) data).getPortletSessionState(((JetspeedRunData) data).getJs_peid());
String channelRefStr = (String) state.getAttribute(STATE_CHANNEL_REF);
Reference channelRef = EntityManager.newReference(channelRefStr);
String siteRef = SiteService.siteReference(channelRef.getContext());
// setup for editing the permissions of the site for this tool, using the roles of this site, too
state.setAttribute(PermissionsHelper.TARGET_REF, siteRef);
// ... with this description
state.setAttribute(PermissionsHelper.DESCRIPTION, rb.getString("setperm")
+ SiteService.getSiteDisplay(channelRef.getContext()));
// ... showing only locks that are prpefixed with this
state.setAttribute(PermissionsHelper.PREFIX, "mail.");
// ... pass the resource loader object
ResourceLoader pRb = new ResourceLoader("permissions");
HashMap<String, String> pRbValues = new HashMap<String, String>();
for (Iterator<Entry<String, String>> iKeys = pRb.entrySet().iterator();iKeys.hasNext();)
{
Entry<String, String> entry = iKeys.next();
String key = entry.getKey();
pRbValues.put(key, entry.getValue());
}
state.setAttribute("permissionDescriptions", pRbValues);
} // doPermissions
private Search getSearchFilter(String search, int first, int last)
{
return new MailMessageSearchFilter(search, first, last);
}
protected class MailMessageSearchFilter extends Search implements SearchFilter
{
public MailMessageSearchFilter(String searchString, int first, int last)
{
super(searchString);
this.setStart(first);
this.setLimit(last);
}
// Deal with the name mis-match
public String getSearchString()
{
return this.getQueryString();
}
/**
* Does this object satisfy the criteria of the filter?
*
* @param o
* The object to test.
* @return true if the object is accepted by the filter, false if not.
*/
public boolean accept(Object o)
{
// we want to test only messages
if (!(o instanceof MailArchiveMessage))
{
return false;
}
String searchStr = getSearchString();
if ( searchStr != null )
{
MailArchiveMessage msg = (MailArchiveMessage) o;
if (StringUtils.containsIgnoreCase(msg.getMailArchiveHeader().getSubject(), searchStr)
|| StringUtils.containsIgnoreCase(msg.getMailArchiveHeader().getFromAddress(), searchStr)
|| StringUtils.containsIgnoreCase(FormattedText.convertFormattedTextToPlaintext(msg.getBody()), searchStr))
{
return false;
}
}
return true;
}
}
/**
* get the Message Threshold - above which searching is disabled
*/
private int getMessageThreshold()
{
return ServerConfigurationService.getInt("sakai.mailbox.search-threshold",
MESSAGE_THRESHOLD_DEFAULT);
}
} // MailboxAction