001: package org.claros.intouch.webmail.services;
002:
003: import java.io.IOException;
004: import java.io.PrintWriter;
005: import java.net.URLDecoder;
006: import java.util.ArrayList;
007: import java.util.Collections;
008: import java.util.List;
009: import java.util.Locale;
010: import java.util.StringTokenizer;
011:
012: import javax.servlet.ServletException;
013: import javax.servlet.http.Cookie;
014: import javax.servlet.http.HttpServletRequest;
015: import javax.servlet.http.HttpServletResponse;
016:
017: import org.apache.commons.logging.Log;
018: import org.apache.commons.logging.LogFactory;
019: import org.claros.commons.auth.models.AuthProfile;
020: import org.claros.commons.configuration.PropertyFile;
021: import org.claros.commons.mail.comparator.ComparatorDate;
022: import org.claros.commons.mail.comparator.ComparatorFrom;
023: import org.claros.commons.mail.comparator.ComparatorSize;
024: import org.claros.commons.mail.comparator.ComparatorSubject;
025: import org.claros.commons.mail.comparator.ComparatorTo;
026: import org.claros.commons.mail.exception.ProtocolNotAvailableException;
027: import org.claros.commons.mail.models.ConnectionMetaHandler;
028: import org.claros.commons.mail.models.ConnectionProfile;
029: import org.claros.commons.mail.models.EmailHeader;
030: import org.claros.commons.mail.protocols.Protocol;
031: import org.claros.commons.mail.protocols.ProtocolFactory;
032: import org.claros.commons.mail.utility.Constants;
033: import org.claros.intouch.common.services.BaseService;
034: import org.claros.intouch.webmail.controllers.FolderController;
035: import org.claros.intouch.webmail.controllers.InboxController;
036: import org.claros.intouch.webmail.factory.FolderControllerFactory;
037: import org.claros.intouch.webmail.factory.InboxControllerFactory;
038: import org.claros.intouch.webmail.models.FolderDbObject;
039: import org.claros.intouch.common.utility.Utility;
040:
041: public class ListHeadersService extends BaseService {
042:
043: /**
044: *
045: */
046: private static final long serialVersionUID = -38711675148470029L;
047: private static Log log = LogFactory
048: .getLog(ListHeadersService.class);
049: private static Locale loc;
050:
051: static {
052: if (org.claros.intouch.common.utility.Constants.charset
053: .indexOf("_") < 0) {
054: loc = new Locale(
055: org.claros.intouch.common.utility.Constants.charset);
056: } else {
057: StringTokenizer token = new StringTokenizer(
058: org.claros.intouch.common.utility.Constants.charset,
059: "_");
060: loc = new Locale(token.nextToken(), token.nextToken());
061: }
062: }
063:
064: /**
065: * The doPost method of the servlet. <br>
066: *
067: * This method is called when a form has its tag value method equals to post.
068: *
069: * @param request the request send by the client to the server
070: * @param response the response send by the server to the client
071: * @throws ServletException if an error occurred
072: * @throws IOException if an error occurred
073: */
074: public void doPost(HttpServletRequest request,
075: HttpServletResponse response) throws ServletException,
076: IOException {
077: response.setHeader("Expires", "-1");
078: response.setHeader("Pragma", "no-cache");
079: response.setHeader("Cache-control", "no-cache");
080: response.setHeader("Content-Type", "text/html; charset=utf-8");
081:
082: PrintWriter out = response.getWriter();
083:
084: AuthProfile auth = getAuthProfile(request);
085: // get folder and set it into sesssion
086: String sFolder = URLDecoder.decode((String) getVariable(
087: request, "folder"), "UTF-8");
088:
089: // prepare variables
090: List headers = null;
091: ConnectionMetaHandler handler = getConnectionHandler(request);
092: ConnectionProfile profile = getConnectionProfile(request);
093:
094: FolderControllerFactory foldFact = null;
095: FolderController folderCont = null;
096: String currFolder = org.claros.commons.mail.utility.Constants
097: .FOLDER_INBOX(profile);
098:
099: try {
100: if (auth == null) {
101: throw new org.claros.commons.exception.NoPermissionException();
102: }
103: // if folder name is empty or it is inbox then do mail filtering. It is done by inbox controller
104: if (sFolder == null || sFolder.equals("")
105: || sFolder.equals(currFolder)) {
106: try {
107: InboxControllerFactory inFact = new InboxControllerFactory(
108: auth, profile, handler);
109: InboxController inCont = inFact
110: .getInboxController();
111: handler = inCont.checkEmail();
112: request.getSession().setAttribute("handler",
113: handler);
114: foldFact = new FolderControllerFactory(auth,
115: profile, handler);
116: folderCont = foldFact.getFolderController();
117: } catch (Exception e) {
118: log.debug("minor error while checking new mail", e);
119: }
120:
121: // get the id(pop3) or the mail folder name (imap)
122: if (profile.getProtocol().equals(
123: org.claros.commons.mail.utility.Constants.POP3)) {
124: currFolder = folderCont.getInboxFolder().getId()
125: .toString();
126: } else {
127: currFolder = folderCont.getInboxFolder()
128: .getFolderName();
129: }
130: } else {
131: currFolder = sFolder;
132: handler = (ConnectionMetaHandler) request.getSession()
133: .getAttribute("handler");
134: foldFact = new FolderControllerFactory(auth, profile,
135: handler);
136: folderCont = foldFact.getFolderController();
137: }
138: request.getSession().setAttribute("folder", currFolder);
139:
140: // get info about the current folder
141: FolderDbObject myFolder = folderCont.getFolder(currFolder);
142:
143: // time to fetch the headers
144: if (profile.getProtocol().equals(
145: org.claros.commons.mail.utility.Constants.POP3)
146: && myFolder
147: .getFolderType()
148: .equals(
149: org.claros.intouch.common.utility.Constants.FOLDER_TYPE_INBOX)) {
150: currFolder = org.claros.commons.mail.utility.Constants
151: .FOLDER_INBOX(null);
152: }
153:
154: // get and set sort parameters
155: String mailSort = (String) getVariable(request, "mailSort");
156: if (null == mailSort)
157: mailSort = "date";
158: String mailSortDirection = (String) getVariable(request,
159: "mailSortDirection");
160: if (null == mailSortDirection)
161: mailSortDirection = "desc";
162: request.getSession().setAttribute("mailSort", mailSort);
163: request.getSession().setAttribute("mailSortDirection",
164: mailSortDirection);
165:
166: // first check to see if the server supports server side sorting or not.
167: // if it supports server side sorting it is a big performance enhancement.
168: ArrayList sortedHeaders = null;
169: boolean supportsServerSorting = false;
170: try {
171: // if the user doesn't want server side sorting for any reason(????) do not to server
172: // side imap sorting.
173: String disableImapSort = PropertyFile.getConfiguration(
174: "/config/config.xml").getString(
175: "common-params.disable-imap-sort");
176: if (disableImapSort != null
177: && (disableImapSort.toLowerCase().equals("yes") || disableImapSort
178: .toLowerCase().equals("true"))) {
179: sortedHeaders = null;
180: supportsServerSorting = false;
181: } else {
182: // the user agrees on the performance enhancement imap sort offers. So go on.
183: // let's give a try if the user supports it or not.
184: ProtocolFactory pFact = new ProtocolFactory(
185: profile, auth, handler);
186: Protocol protocol = pFact.getProtocol(currFolder);
187:
188: sortedHeaders = protocol.getHeadersSortedList(
189: mailSort, mailSortDirection);
190:
191: // profile has the boolean variable of it supports server side sorting or not!!!
192: // so set it to the session for future references.
193: profile = protocol.getProfile();
194: request.getSession().setAttribute("profile",
195: profile);
196:
197: supportsServerSorting = true;
198: }
199: } catch (ProtocolNotAvailableException p) {
200: sortedHeaders = null;
201: supportsServerSorting = false;
202: }
203:
204: // it is pop3 mode or the imap server doesn't support server side sorting.
205: if (!supportsServerSorting) {
206: headers = folderCont.getHeadersByFolder(currFolder);
207: }
208: // if server side sorting is supported, do not fetch the messages yet. they will be fetched
209: // when paging variables are set below.
210:
211: // get and set pageNo
212: int pageNo = 1;
213: try {
214: pageNo = Integer
215: .parseInt(getVariable(request, "pageNo")
216: .toString());
217: } catch (Exception e) {
218: }
219: request.getSession().setAttribute("pageNo",
220: new Integer(pageNo));
221:
222: Cookie c1 = new Cookie("mailSort", mailSort);
223: c1.setMaxAge(Integer.MAX_VALUE);
224: Cookie c2 = new Cookie("mailSortDirection",
225: mailSortDirection);
226: c2.setMaxAge(Integer.MAX_VALUE);
227: Cookie c3 = new Cookie("pageNo", String.valueOf(pageNo));
228: c3.setMaxAge(Integer.MAX_VALUE);
229: response.addCookie(c1);
230: response.addCookie(c2);
231: response.addCookie(c3);
232:
233: boolean isAscending = false;
234: if (mailSortDirection != null
235: && mailSortDirection.equals("asc")) {
236: isAscending = true;
237: }
238:
239: // organize em
240: String fromSort = "";
241: String dateSort = "";
242: String sizeSort = "";
243: String subjectSort = "";
244:
245: if (mailSort == null || mailSort.equals("date")) {
246: if (isAscending)
247: dateSort = "asc";
248: else
249: dateSort = "desc";
250: } else if (mailSort.equals("from")) {
251: if (isAscending)
252: fromSort = "asc";
253: else
254: fromSort = "desc";
255: } else if (mailSort.equals("subject")) {
256: if (isAscending)
257: subjectSort = "asc";
258: else
259: subjectSort = "desc";
260: } else if (mailSort.equals("to")) {
261: if (isAscending)
262: fromSort = "asc";
263: else
264: fromSort = "desc";
265: } else if (mailSort.equals("size")) {
266: if (isAscending)
267: sizeSort = "asc";
268: else
269: sizeSort = "desc";
270: }
271:
272: out
273: .print("<div id=\"ieHolder\" class=\"ieHolder\"><div class=\"ie7Holder\" id=\"ie7Holder\">");
274:
275: // at least show the title bar also with sort arrows
276: if (profile.getProtocol().equals(Constants.IMAP)) {
277: out
278: .print("<p class='title' id='mailtitle' displayName='"
279: + myFolder.getFolderName()
280: + "' folderid='"
281: + myFolder.getId()
282: + "' foldername='mailFolder"
283: + myFolder.getFolderName()
284: + "' type='"
285: + myFolder.getFolderType()
286: + "'>"
287: + " <span class='flag' style='background-image:url(images/unchecked.gif);background-repeat:no-repeat;' onclick='clickAll();'><a href='javascript:;'> </a></span>");
288: } else {
289: out
290: .print("<p class='title' id='mailtitle' displayName='"
291: + myFolder.getFolderName()
292: + "' folderid='"
293: + myFolder.getId()
294: + "' foldername='mailFolder"
295: + myFolder.getId()
296: + "' type='"
297: + myFolder.getFolderType()
298: + "'>"
299: + " <span class='flag' style='background-image:url(images/unchecked.gif);background-repeat:no-repeat;' onclick='clickAll();'><a href='javascript:;'> </a></span>");
300: }
301: out
302: .print("<span class='attributes'><a href='javascript:;'><span style='cursor:hand'><img alt='' src='images/priority-title.gif' align='absmiddle'><img alt='' src='images/sensitivity-title.gif' align='absmiddle'></span></a></span>");
303:
304: if (myFolder
305: .getFolderType()
306: .equals(
307: org.claros.intouch.common.utility.Constants.FOLDER_TYPE_SENT)) {
308: out
309: .print(" <span class='from "
310: + fromSort
311: + "' onclick=\"sortColumn(this, 'to');\" sort='"
312: + fromSort
313: + "'><a href='javascript:;'><span style='cursor:hand'>"
314: + getText(request, "to")
315: + "</span></a></span>");
316: if (mailSort != null && mailSort.equals("from")) {
317: mailSort = "to";
318: }
319: } else {
320: out
321: .print(" <span class='from "
322: + fromSort
323: + "' onclick=\"sortColumn(this, 'from');\" sort='"
324: + fromSort
325: + "'><a href='javascript:;'><span style='cursor:hand'>"
326: + getText(request, "from")
327: + "</span></a></span>");
328: if (mailSort != null && mailSort.equals("to")) {
329: mailSort = "from";
330: }
331: }
332: out
333: .print(" <span class='subject "
334: + subjectSort
335: + "' onclick=\"sortColumn(this, 'subject');\" sort='"
336: + subjectSort
337: + "'><a href='javascript:;'><span style='cursor:hand'>"
338: + getText(request, "subject")
339: + "</span></a></span>"
340: + " <span class='date "
341: + dateSort
342: + "' onclick=\"sortColumn(this, 'date');\" sort='"
343: + dateSort
344: + "'><a href='javascript:;'><span style='cursor:hand'>"
345: + getText(request, "date")
346: + "</span></a></span>"
347: + " <span class='size "
348: + sizeSort
349: + "' onclick=\"sortColumn(this, 'size');\" sort='"
350: + sizeSort
351: + "'><a href='javascript:;'><span style='cursor:hand'>"
352: + getText(request, "size")
353: + "</span></a></span>"
354: + " <span class='attach'><a href='javascript:;'> </a></span>"
355: + "</p>");
356:
357: if (!supportsServerSorting) {
358: // sort the headers
359: if (mailSort == null || mailSort.equals("date")) {
360: Collections.sort(headers, new ComparatorDate(
361: isAscending));
362: } else if (mailSort.equals("from")) {
363: Collections.sort(headers, new ComparatorFrom(
364: isAscending, loc));
365: } else if (mailSort.equals("subject")) {
366: Collections.sort(headers, new ComparatorSubject(
367: isAscending, loc));
368: } else if (mailSort.equals("to")) {
369: Collections.sort(headers, new ComparatorTo(
370: isAscending, loc));
371: } else if (mailSort.equals("size")) {
372: Collections.sort(headers, new ComparatorSize(
373: isAscending));
374: }
375: }
376:
377: // organize and generate XML from the headers.
378: if (headers != null || supportsServerSorting) {
379: EmailHeader tmp = null;
380: int pageSize = 25;
381: String strPageSize = PropertyFile.getConfiguration(
382: "/config/config.xml").getString(
383: "common-params.mailbox-page-size");
384: if (strPageSize != null) {
385: try {
386: pageSize = Integer.parseInt(strPageSize);
387: } catch (Exception e) {
388: pageSize = 25;
389: }
390: }
391:
392: // determine the message count. the method varies if server side or client side
393: // sorting is used.
394: int messageCount = -1;
395: if (!supportsServerSorting) {
396: messageCount = headers.size();
397: } else {
398: messageCount = sortedHeaders.size();
399: }
400: int pageCount = messageCount / pageSize;
401: if ((messageCount % pageSize) > 0)
402: pageCount++;
403: if (pageNo > pageCount)
404: pageNo = pageCount;
405: int startIdx = (pageNo - 1) * pageSize;
406: if (startIdx < 0)
407: startIdx = 0;
408: int endIdx = startIdx + pageSize;
409: if (endIdx > messageCount)
410: endIdx = messageCount;
411:
412: out
413: .print("<span id=\"pagerParams\" style=\"display:none\">"
414: + pageNo
415: + ":"
416: + pageCount
417: + ":"
418: + messageCount
419: + ":"
420: + pageSize
421: + "</span>");
422:
423: // If server side sorting is supported, it is time to fetch the message headers.
424: // not all of the headers are fetched.
425: if (supportsServerSorting) {
426: int msgs[] = new int[endIdx - startIdx];
427: int counter = 0;
428: for (int y = startIdx; y < endIdx; y++) {
429: msgs[counter] = ((Integer) sortedHeaders.get(y))
430: .intValue();
431: counter++;
432: }
433: headers = folderCont.getHeadersByFolder(currFolder,
434: msgs);
435:
436: // we only have the headers to be displayed in the headers arraylist.
437: for (int i = 0; i < headers.size(); i++) {
438: tmp = (EmailHeader) headers.get(i);
439: writeHeaderInfoToOut(tmp, out, request,
440: myFolder);
441: }
442: } else {
443: // with the client side sorting method the headers array has all the message headers
444: // so with a for statement display them.
445: for (int i = startIdx; i < endIdx; i++) {
446: tmp = (EmailHeader) headers.get(i);
447: writeHeaderInfoToOut(tmp, out, request,
448: myFolder);
449: }
450: }
451: }
452: out.print("</div></div>");
453: } catch (Exception e) {
454: out
455: .print("<p class='title'>"
456: + "<span class='flag' style='background-image:url(images/unchecked.gif);background-repeat:no-repeat;' onclick='clickAll();'><a href='javascript:;'> </a></span>"
457: + "<span class='attributes'><a href='javascript:;'><span> </span></a></span>"
458: + "<span class='from asc'><a href='javascript:;'><span>"
459: + getText(request, "from")
460: + "</span></a></span>"
461: + "<span class='subject'><a href='javascript:;'><span>"
462: + getText(request, "subject")
463: + "</span></a></span>"
464: + "<span class='date'><a href='javascript:;'><span>"
465: + getText(request, "date")
466: + "</span></a></span>"
467: + "<span class='size'><a href='javascript:;'><span>"
468: + getText(request, "size")
469: + "</span></a></span>"
470: + "<span class='attach'><a href='javascript:;'> </a></span>"
471: + "</p>");
472:
473: }
474: }
475:
476: private void writeHeaderInfoToOut(EmailHeader tmp, PrintWriter out,
477: HttpServletRequest request, FolderDbObject myFolder) {
478: String subject = tmp.getSubject();
479: if (null == subject || 0 == subject.length())
480: subject = getText(request, "no.subject");
481: String from = tmp.getFromShown();
482: if (null == from || 0 == from.length())
483: from = getText(request, "unknown.sender");
484: String priority = org.claros.commons.mail.models.EmailPriority
485: .toStringValue(tmp.getPriority());
486: short sensitivity = tmp.getSensitivity();
487:
488: out
489: .print("<p "
490: + ((tmp.isMultipart()) ? " class='attach' "
491: : "")
492: + "id='mail"
493: + tmp.getMessageId()
494: + "' "
495: + ((tmp.getUnread().booleanValue()) ? "style='font-weight:bold;'"
496: : "")
497: + ">"
498: + "<span class='flag' onclick='mailListClick(event, this, false, true);'> </span>");
499: out
500: .print("<span class='attributes' onclick='mailListClick(event, this, true, false);'><img alt='' src='images/priority-"
501: + priority.toLowerCase()
502: + ".gif' align='absmiddle'><img alt='' src='images/sensitivity-"
503: + sensitivity
504: + ".gif' align='absmiddle'></span>");
505: if (myFolder
506: .getFolderType()
507: .equals(
508: org.claros.intouch.common.utility.Constants.FOLDER_TYPE_SENT)) {
509: out
510: .print("<span class='from' onclick='mailListClick(event, this, true, false);'>"
511: + org.claros.commons.utility.Utility
512: .convertTRCharsToHtmlSafe(Utility
513: .htmlCheck(sbjTrim(tmp
514: .getToShown())))
515: + "</span>");
516: } else {
517: out
518: .print("<span class='from' onclick='mailListClick(event, this, true, false);'>"
519: + org.claros.commons.utility.Utility
520: .convertTRCharsToHtmlSafe(Utility
521: .htmlCheck(sbjTrim(from)))
522: + "</span>");
523: }
524: out
525: .print("<span class='subject' onclick='mailListClick(event, this, true, false);' title=\""
526: + org.claros.commons.utility.Utility
527: .convertTRCharsToHtmlSafe(Utility
528: .htmlCheck(subject))
529: + "\">"
530: + org.claros.commons.utility.Utility
531: .convertTRCharsToHtmlSafe(Utility
532: .htmlCheck(sbjTrim(subject)))
533: + "</span>"
534: + "<span class='date' onclick='mailListClick(event, this, true, false);'>"
535: + Utility.htmlCheck(tmp.getDateShown())
536: + "</span>"
537: + "<span class='size' onclick='mailListClick(event, this, true, false);'>"
538: + Utility.htmlCheck(tmp.getSizeShown())
539: + "</span>"
540: + "<span class='attach' onclick='mailListClick(event, this, true, false);'> </span>"
541: + "</p>");
542: }
543:
544: public void doGet(HttpServletRequest request,
545: HttpServletResponse response) throws ServletException,
546: IOException {
547: doPost(request, response);
548: }
549:
550: private String sbjTrim(String str) {
551: if (str != null) {
552: if (str.length() > 40) {
553: str = str.substring(0, 40) + "...";
554: }
555: }
556: return str;
557: }
558: }
|