1 /*
2 * Copyright (c) 2004-2007 Creative Sphere Limited.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 *
10 * Creative Sphere - initial API and implementation
11 *
12 */
13 package org.abstracthorizon.mercury.imap.util;
14
15 import java.io.IOException;
16 import java.text.SimpleDateFormat;
17 import java.util.Date;
18 import java.util.Enumeration;
19 import java.util.Iterator;
20 import java.util.List;
21 import javax.mail.Folder;
22 import javax.mail.Message;
23 import javax.mail.MessagingException;
24 import javax.mail.UIDFolder;
25 import javax.mail.internet.MimeMessage;
26 import javax.mail.internet.MimePart;
27
28 import org.abstracthorizon.mercury.common.util.RFCDate;
29 import org.abstracthorizon.mercury.imap.IMAPSession;
30
31 /**
32 * Utility methods for working with messages
33 *
34 * @author Daniel Sendula
35 */
36 public class MessageUtilities {
37
38 /** Date format */
39 public static SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z");
40
41 /** CR/LF */
42 public static final String CRLF = "\r\n";
43
44 /**
45 * Find message by UID
46 * @param f folder
47 * @param uid uid
48 * @return message
49 * @throws MessagingException if folder is not of {@link UIDFolder} type
50 */
51 public static Message findMessageByUID(Folder f, long uid) throws MessagingException {
52 if (f instanceof UIDFolder) {
53 return ((UIDFolder) f).getMessageByUID(uid);
54 } else {
55 throw new MessagingException("Not Implemented");
56 }
57 }
58
59 /**
60 * Returns messages's UID
61 * @param m message
62 * @return UID
63 * @throws MessagingException if folder is not of {@link UIDFolder} type
64 */
65 public static long findUID(Message m) throws MessagingException {
66 Folder f = m.getFolder();
67 if (f instanceof UIDFolder) {
68 return ((UIDFolder) f).getUID(m);
69 } else {
70 throw new MessagingException("Not Implemented");
71 }
72 }
73
74 /**
75 * Creates string representation of headers for mime part
76 * @param m mime part
77 * @return string representation of headers
78 * @throws MessagingException
79 */
80 public static String createHeaders(MimePart m) throws MessagingException {
81 Enumeration<?> en = m.getAllHeaderLines();
82 // StringBuffer buf = new StringBuffer(512);
83 return createHeaders(m, en);
84 // while (en.hasMoreElements()) {
85 // buf.append(en.nextElement().toString()).append(MessageUtilities.CRLF);
86 // }
87 // if (m.getSize() > 0) {
88 // buf.append(MessageUtilities.CRLF);
89 // }
90 // return buf.toString();
91 }
92
93 /**
94 * Creates string representation of headers for mime part
95 * @param m mime part
96 * @param headers headers
97 * @param not should headers form the list be included or excluded
98 * @return string representation of headers
99 * @throws MessagingException
100 */
101 public static String createHeaders(MimePart m, List<String> headers, boolean not)
102 throws MessagingException {
103 String[] list = new String[headers.size()];
104 list = headers.toArray(list);
105 Enumeration<?> en = null;
106 if (not) {
107 en = m.getNonMatchingHeaderLines(list);
108 } else {
109 en = m.getMatchingHeaderLines(list);
110 }
111 return createHeaders(m, en);
112 }
113
114 /**
115 * Creates string representation of headers for mime part
116 * @param m mime part
117 * @param headers headers
118 * @return stirng representation of headers
119 * @throws MessagingException
120 */
121 public static String createHeaders(MimePart m, Enumeration<?> headers)
122 throws MessagingException {
123 StringBuffer buf = new StringBuffer(512);
124 while (headers.hasMoreElements()) {
125 String headerLine = headers.nextElement().toString();
126 if (headerLine.startsWith("Date: ")) {
127 String date = headerLine.substring(6).trim();
128 if (RFCDate.validate(date)) {
129 buf.append(headerLine).append(CRLF);
130 } else {
131 Date d;
132 if (m instanceof MimeMessage) {
133 d = ((MimeMessage) m).getReceivedDate();
134 } else {
135 d = new Date(); // !!!
136 }
137 String newHeaderLine = "Date: "
138 + RFCDate.DATE_FORMAT.format(d);
139 buf.append(newHeaderLine).append(CRLF);
140 }
141 } else {
142 buf.append(headerLine).append(CRLF);
143 }
144 }
145 if (m.getSize() > 0) {
146 buf.append(CRLF);
147 }
148 return buf.toString();
149 }
150
151 /**
152 * Iterates over sequence for given folder's messages
153 * @param session imap session
154 * @param processor message processor
155 * @param f folder
156 * @param sequenceSet sequence
157 * @param asuid does sequence represent UIDs or positions of messages
158 * @throws IOException
159 * @throws MessagingException
160 */
161 public static void sequenceIterator(IMAPSession session, MessageProcessor processor, Folder f,
162 Sequence sequenceSet, boolean asuid) throws IOException,
163 MessagingException {
164 if (!asuid) {
165 int msgCount = f.getMessageCount();
166 sequenceSet.setLowerLimit(1);
167 sequenceSet.setUpperLimit(msgCount);
168 }
169 if (sequenceSet instanceof ComposedSequence) {
170 composedSequenceIterator(session, processor, f,
171 (ComposedSequence) sequenceSet, asuid);
172 } else if (sequenceSet instanceof SimpleSequence) {
173 simpleSequenceIterator(session, processor, f, (SimpleSequence) sequenceSet,
174 asuid);
175 }
176 }
177
178 /**
179 * Iterates over sequence for given folder's messages
180 * @param session imap session
181 * @param processor message processor
182 * @param f folder
183 * @param sequenceSet sequence
184 * @param asuid does sequence represent UIDs or positions of messages
185 * @throws IOException
186 * @throws MessagingException
187 */
188 public static void composedSequenceIterator(IMAPSession session, MessageProcessor processor,
189 Folder f, ComposedSequence sequenceSet, boolean asuid)
190 throws IOException, MessagingException {
191 Iterator<Sequence> iterator = sequenceSet.getSequencesAsIterator();
192 while (iterator.hasNext()) {
193 Sequence set = (Sequence) iterator.next();
194 if (set instanceof ComposedSequence) {
195 composedSequenceIterator(session, processor, f, (ComposedSequence) set,
196 asuid);
197 } else if (set instanceof SimpleSequence) {
198 simpleSequenceIterator(session, processor, f, (SimpleSequence) set,
199 asuid);
200 }
201 }
202 }
203
204 /**
205 * Iterates over sequence for given folder's messages
206 * @param session imap session
207 * @param processor message processor
208 * @param f folder
209 * @param sequenceSet sequence
210 * @param asuid does sequence represent UIDs or positions of messages
211 * @throws IOException
212 * @throws MessagingException
213 */
214 public static void simpleSequenceIterator(IMAPSession session, MessageProcessor processor,
215 Folder f, SimpleSequence sequenceSet, boolean asuid)
216 throws IOException, MessagingException {
217 int min = sequenceSet.getMin();
218 int max = sequenceSet.getMax();
219 if (min < 1) {
220 min = 1;
221 }
222
223 if (min == max) {
224 MimeMessage msg;
225 if (asuid) {
226 msg = (MimeMessage) ((UIDFolder) f).getMessageByUID(min);
227 } else {
228 msg = (MimeMessage) f.getMessage(min);
229 }
230 if (msg != null) {
231 processor.process(session, msg);
232 }
233 } else {
234 Message[] msgs;
235 if (asuid) {
236 msgs = ((UIDFolder) f).getMessagesByUID(min, max);
237 } else {
238 int msgCount = f.getMessageCount();
239 if (max > msgCount) {
240 max = msgCount;
241 }
242 msgs = f.getMessages(min, max);
243 }
244 for (int i = 0; i < msgs.length; i++) {
245 MimeMessage msg = (MimeMessage) msgs[i];
246 if (msg != null) {
247 processor.process(session, msg);
248 }
249 }
250 }
251 }
252
253 /**
254 * Iterates over sequence for given folder's messages
255 * @param session imap session
256 * @param processor message processor
257 * @param f folder
258 * @param sequenceSet sequence
259 * @param asuid does sequence represent UIDs or positions of messages
260 * @throws IOException
261 * @throws MessagingException
262 */
263 public static void sequenceIteratorOld(IMAPSession session, MessageProcessor processor,
264 Folder f, Sequence sequenceSet, boolean asuid) throws IOException,
265 MessagingException {
266 int msgs = f.getMessageCount();
267 // logger.debug("1) min="+sequenceSet.getMin()+"
268 // max="+sequenceSet.getMax());
269 sequenceSet.setLowerLimit(1);
270 // logger.debug("2) min="+sequenceSet.getMin()+"
271 // max="+sequenceSet.getMax());
272 if (asuid) {
273 int max = (int) MessageUtilities.maxUID(f);
274 // logger.debug("max="+max);
275 sequenceSet.setUpperLimit(max);
276 } else {
277 // logger.debug("max="+msgs);
278 sequenceSet.setUpperLimit(msgs);
279 }
280 // logger.debug("3) min="+sequenceSet.getMin()+"
281 // max="+sequenceSet.getMax());
282
283 sequenceSet.first();
284 // logger.debug("4) min="+sequenceSet.getMin()+"
285 // max="+sequenceSet.getMax());
286 if (asuid) {
287 // logger.debug("as uid!");
288 int msgNo = -1;
289 while (sequenceSet.more()) {
290 int uid = sequenceSet.next();
291 // if (uid > 573) {
292 // logger.debug(": "+uid);
293 // }
294 MimeMessage m = null;
295 if (msgNo < 0) {
296 if (uid == 2764) {
297 uid = uid * 2 / 2;
298 }
299 m = (MimeMessage) MessageUtilities.findMessageByUID(f, uid);
300 if (m != null) {
301 msgNo = m.getMessageNumber();
302 // logger.debug(":(1) #="+msgNo);
303 } else {
304 // logger.debug(":(1) = null!");
305 msgNo = -1;
306 }
307 } else {
308 m = (MimeMessage) f.getMessage(msgNo + 1);
309 if (m != null) {
310 // logger.debug(":(2) #="+m.getMessageNumber());
311 int u = (int) MessageUtilities.findUID(m);
312 if (u > uid) {
313 // logger.debug(":(3) = u="+u);
314 sequenceSet.setLowerLimit(u);
315 sequenceSet.first();
316 m = null;
317 } else if (u < uid) {
318 // logger.debug(":(4) = u="+u);
319 m = (MimeMessage) MessageUtilities
320 .findMessageByUID(f, uid);
321 if (m != null) {
322 msgNo = m.getMessageNumber();
323 // logger.debug(":(4) = #="+msgNo);
324 } else {
325 // logger.debug(":(4) = null");
326 msgNo = -1;
327 }
328 } else {
329 msgNo = msgNo + 1;
330 // logger.debug(":(4) = msgNo = msgNo+1 u="+u+"
331 // uid="+uid);
332 }
333 } else {
334 // logger.debug(":(2) = null!");
335 sequenceSet.setLowerLimit(sequenceSet.getMax() + 1);
336 }
337 }
338
339 if (m != null) {
340 processor.process(session, m);
341 }
342 }
343 } else {
344 while (sequenceSet.more()) {
345 int msgNo = sequenceSet.next();
346 MimeMessage m = (MimeMessage) f.getMessage(msgNo);
347 if (m != null) {
348 processor.process(session, m);
349 }
350
351 } // while
352 }
353 }
354
355 /**
356 * Returns maximum UID form the folder
357 * @param f folder
358 * @return maxumum UID
359 * @throws MessagingException if folder is not of {@link UIDFolder} type
360 */
361 public static long maxUID(Folder f) throws MessagingException {
362 // logger.debug("count="+f.getMessageCount()+"
363 // #="+f.getMessage(f.getMessageCount()).getMessageNumber());
364 return findUID(f.getMessage(f.getMessageCount()));
365 }
366 }