1 /**************************************************************** 2 * Licensed to the Apache Software Foundation (ASF) under one * 3 * or more contributor license agreements. See the NOTICE file * 4 * distributed with this work for additional information * 5 * regarding copyright ownership. The ASF licenses this file * 6 * to you under the Apache License, Version 2.0 (the * 7 * "License"); you may not use this file except in compliance * 8 * with the License. You may obtain a copy of the License at * 9 * * 10 * http://www.apache.org/licenses/LICENSE-2.0 * 11 * * 12 * Unless required by applicable law or agreed to in writing, * 13 * software distributed under the License is distributed on an * 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * 15 * KIND, either express or implied. See the License for the * 16 * specific language governing permissions and limitations * 17 * under the License. * 18 ****************************************************************/ 19 20 package org.apache.james.mailboxmanager; 21 22 import java.io.IOException; 23 import java.nio.channels.WritableByteChannel; 24 import java.util.Date; 25 import java.util.Iterator; 26 import java.util.List; 27 import java.util.Map; 28 import java.util.Set; 29 30 import javax.mail.Flags; 31 import javax.mail.MessagingException; 32 33 import org.apache.james.mailboxmanager.util.MessageResultUtils; 34 35 /** 36 * <p> 37 * Used to get specific informations about a Message without dealing with a 38 * MimeMessage instance. Demanded information can be requested by binary 39 * combining the constants. 40 * </p> 41 * 42 * <p> 43 * I came to the Idea of the MessageResult because there are many possible 44 * combinations of different requests (uid, msn, MimeMessage, Flags). 45 * </p> 46 * <p> 47 * e.g. I want to have all uids, msns and flags of all messages. (a common IMAP 48 * operation) Javamail would do it that way: 49 * <ol> 50 * <li>get all Message objects (Message[])</li> 51 * <li>call Message.getMessageNumber() </li> 52 * <li>call Message.getFlags() </li> 53 * <li>call Folder.getUid(Message)</li> 54 * </ol> 55 * <p> 56 * This means creating a lazy-loading MimeMessage instance. </br> So why don't 57 * call getMessages(MessageResult.UID | MessageResult.MSN | 58 * MessageResult.FLAGS)? This would leave a lot of room for the implementation 59 * to optimize 60 * </p> 61 * 62 * 63 */ 64 65 public interface MessageResult extends Comparable, Headers { 66 67 /** 68 * Indicates the results fetched. 69 */ 70 public interface FetchGroup { 71 72 /** 73 * For example: could have best performance when doing store and then 74 * forget. UIDs are always returned 75 */ 76 public static final int MINIMAL = 0x00; 77 78 /** 79 * 80 */ 81 public static final int MIME_DESCRIPTOR = 0x01; 82 83 public static final int SIZE = 0x20; 84 85 public static final int INTERNAL_DATE = 0x40; 86 87 public static final int FLAGS = 0x80; 88 89 public static final int HEADERS = 0x100; 90 91 public static final int FULL_CONTENT = 0x200; 92 93 public static final int BODY_CONTENT = 0x400; 94 95 public static final int MIME_HEADERS = 0x800; 96 97 public static final int MIME_CONTENT = 0x1000; 98 99 /** 100 * Contents to be fetched. Composed bitwise. 101 * 102 * @return bitwise descripion 103 * @see #MINIMAL 104 * @see #MIME_MESSAGE 105 * @see #KEY 106 * @see #SIZE 107 * @see #INTERNAL_DATE 108 * @see #FLAGS 109 * @see #HEADERS 110 * @see #FULL_CONTENT 111 * @see #BODY_CONTENT 112 * @see #MIME_CONTENT 113 */ 114 public int content(); 115 116 /** 117 * Gets contents to be fetched for contained parts. For each part to be 118 * contained, only one descriptor should be contained. 119 * 120 * @return <code>Set</code> of {@link PartContentDescriptor}, or null 121 * if there is no part content to be fetched 122 */ 123 public Set getPartContentDescriptors(); 124 125 /** 126 * Describes the contents to be fetched for a mail part. All 127 * implementations MUST implement equals. Two implementations are equal 128 * if and only if their paths are equal. 129 */ 130 public interface PartContentDescriptor { 131 /** 132 * Contents to be fetched. Composed bitwise. 133 * 134 * @return bitwise descripion 135 * @see #MINIMAL 136 * @see #MIME_MESSAGE 137 * @see #KEY 138 * @see #SIZE 139 * @see #INTERNAL_DATE 140 * @see #FLAGS 141 * @see #HEADERS 142 * @see #FULL_CONTENT 143 * @see #BODY_CONTENT 144 */ 145 public int content(); 146 147 /** 148 * Path describing the part to be fetched. 149 * 150 * @return path describing the part, not null 151 */ 152 public MimePath path(); 153 } 154 } 155 156 /** 157 * Gets the results set. 158 * 159 * @return bitwise indication of result set 160 * @see MessageResultUtils#isIncluded(MessageResult, int) 161 */ 162 FetchGroup getIncludedResults(); 163 164 MimeDescriptor getMimeDescriptor() throws MailboxManagerException; 165 166 long getUid(); 167 168 long getUidValidity(); 169 170 /** 171 * 172 * <p> 173 * IMAP defines this as the time when the message has arrived to the server 174 * (by smtp). Clients are also allowed to set the internalDate on apppend. 175 * </p> 176 * <p> 177 * Is this Mail.getLastUpdates() for James delivery? Should we use 178 * MimeMessage.getReceivedDate()? 179 * </p> 180 * 181 */ 182 183 Date getInternalDate(); 184 185 /** 186 * TODO optional, to be decided <br /> 187 * maybe this is a good thing because IMAP often requests only the Flags and 188 * this way we don't need to create a lazy-loading MimeMessage instance just 189 * for the Flags. 190 * 191 */ 192 Flags getFlags() throws MailboxManagerException; 193 194 int getSize(); 195 196 /** 197 * Gets headers for the message. 198 * 199 * @return <code>Header</code> <code>Iterator</code>, or null if 200 * {@link FetchGroup#HEADERS} was not fetched 201 */ 202 Iterator headers() throws MailboxManagerException; 203 204 /** 205 * Iterates the message headers for the given part in a multipart message. 206 * 207 * @param path 208 * describing the part's position within a multipart message 209 * @return <code>Header</code> <code>Iterator</code>, or null when 210 * {@link FetchGroup#mimeHeaders()} does not include the index and 211 * when the mime part cannot be found 212 * @throws MailboxManagerException 213 */ 214 Iterator iterateHeaders(MimePath path) throws MailboxManagerException; 215 216 /** 217 * Iterates the MIME headers for the given part in a multipart message. 218 * 219 * @param path 220 * describing the part's position within a multipart message 221 * @return <code>Header</code> <code>Iterator</code>, or null when 222 * {@link FetchGroup#mimeHeaders()} does not include the index and 223 * when the mime part cannot be found 224 * @throws MailboxManagerException 225 */ 226 Iterator iterateMimeHeaders(MimePath path) throws MailboxManagerException; 227 228 /** 229 * A header. 230 */ 231 public interface Header extends Content { 232 233 /** 234 * Gets the name of this header. 235 * 236 * @return name of this header 237 * @throws MessagingException 238 */ 239 public String getName() throws MailboxManagerException; 240 241 /** 242 * Gets the (unparsed) value of this header. 243 * 244 * @return value of this header 245 * @throws MessagingException 246 */ 247 public String getValue() throws MailboxManagerException; 248 } 249 250 /** 251 * Gets the full message including headers and body. The message data should 252 * have normalised line endings (CRLF). 253 * 254 * @return <code>Content</code>, or or null if 255 * {@link FetchGroup#FULL_CONTENT} has not been included in the 256 * results 257 */ 258 Content getFullContent() throws MailboxManagerException; 259 260 /** 261 * Gets the full content of the given mime part. 262 * 263 * @param path 264 * describes the part 265 * @return <code>Content</code>, or null when 266 * {@link FetchGroup#mimeBodies()} did not been include the given 267 * index and when the mime part cannot be found 268 * @throws MailboxManagerException 269 */ 270 Content getFullContent(MimePath path) throws MailboxManagerException; 271 272 /** 273 * Gets the body of the message excluding headers. The message data should 274 * have normalised line endings (CRLF). 275 * 276 * @return <code>Content</code>, or or null if 277 * {@link FetchGroup#FULL_CONTENT} has not been included in the 278 * results 279 */ 280 Content getBody() throws MailboxManagerException; 281 282 /** 283 * Gets the body of the given mime part. 284 * 285 * @param path 286 * describes the part 287 * @return <code>Content</code>, or null when 288 * {@link FetchGroup#mimeBodies()} did not been include the given 289 * index and when the mime part cannot be found 290 * @throws MailboxManagerException 291 */ 292 Content getBody(MimePath path) throws MailboxManagerException; 293 294 /** 295 * Gets the body of the given mime part. 296 * 297 * @param path 298 * describes the part 299 * @return <code>Content</code>, or null when 300 * {@link FetchGroup#mimeBodies()} did not been include the given 301 * index and when the mime part cannot be found 302 * @throws MailboxManagerException 303 */ 304 Content getMimeBody(MimePath path) throws MailboxManagerException; 305 306 /** 307 * IMAP needs to know the size of the content before it starts to write it 308 * out. This interface allows direct writing whilst exposing total size. 309 */ 310 public interface Content { 311 /** 312 * Writes content into the given buffer. 313 * 314 * @param buffer 315 * <code>StringBuffer</code>, not null 316 * @throws MessagingException 317 */ 318 public void writeTo(StringBuffer buffer); 319 320 /** 321 * Writes content to the given channel. 322 * 323 * @param channel 324 * <code>Channel</code> open, not null 325 * @throws MailboxManagerException 326 * @throws IOException 327 * when channel IO fails 328 */ 329 public void writeTo(WritableByteChannel channel) throws IOException; 330 331 /** 332 * Size (in octets) of the content. 333 * 334 * @return number of octets to be written 335 * @throws MessagingException 336 */ 337 public long size(); 338 } 339 340 /** 341 * Describes a path within a multipart MIME message. All implementations 342 * must implement equals. Two paths are equal if and only if each position 343 * is identical. 344 */ 345 public interface MimePath { 346 347 /** 348 * Gets the positions of each part in the path. 349 * 350 * @return part positions describing the path 351 */ 352 public int[] getPositions(); 353 } 354 355 public interface MimeDescriptor extends Headers { 356 357 /** 358 * Gets the top level MIME content media type. 359 * 360 * @return top level MIME content media type, or null if default 361 */ 362 public String getMimeType(); 363 364 /** 365 * Gets the MIME content subtype. 366 * 367 * @return the MIME content subtype, or null if default 368 */ 369 public String getMimeSubType(); 370 371 /** 372 * Gets the MIME <code>Content-ID</code> header value. 373 * 374 * @return MIME <code>Content-ID</code>, possibly null 375 */ 376 public String getContentID(); 377 378 /** 379 * Gets MIME <code>Content-Description</code> header value. 380 * 381 * @return MIME <code>Content-Description</code>, possibly null 382 */ 383 public String getContentDescription(); 384 385 /** 386 * Gets MIME <code>Content-Location</code> header value. 387 * 388 * @return parsed MIME <code>Content-Location</code>, possibly null 389 */ 390 public String getContentLocation(); 391 392 /** 393 * Gets MIME <code>Content-MD5</code> header value. 394 * 395 * @return parsed MIME <code>Content-MD5</code>, possibly null 396 */ 397 public String getContentMD5(); 398 399 /** 400 * Gets the MIME content transfer encoding. 401 * 402 * @return MIME <code>Content-Transfer-Encoding</code>, possibly null 403 */ 404 public String getTransferContentEncoding(); 405 406 /** 407 * Gets the languages, From the MIME <code>Content-Language</code> 408 * header value. 409 * 410 * @return <code>List</code> of <code>String</code> names 411 */ 412 public List getLanguages(); 413 414 /** 415 * Gets MIME <code>Content-Disposition</code>. 416 * 417 * @return <code>Content-Disposition</code>, or null if no 418 * disposition header exists 419 */ 420 public String getDisposition(); 421 422 /** 423 * Gets MIME <code>Content-Disposition</code> parameters. 424 * 425 * @return <code>Content-Disposition</code> values indexed by names 426 */ 427 public Map getDispositionParams(); 428 429 /** 430 * Gets the number of lines of text in a part of type <code>TEXT</code> 431 * when transfer encoded. 432 * 433 * @return <code>CRLF</code> count when a <code>TEXT</code> type, 434 * otherwise -1 435 */ 436 public long getLines(); 437 438 /** 439 * The number of octets contained in the body of this part. 440 * 441 * @return number of octets 442 */ 443 public long getBodyOctets(); 444 445 /** 446 * Gets parts. 447 * 448 * @return <code>MimeDescriptor</code> <code>Iterator</code> when a 449 * composite top level MIME media type, null otherwise 450 */ 451 public Iterator parts(); 452 453 /** 454 * Gets embedded message. 455 * 456 * @return <code>MimeDescriptor</code> when top level MIME type is 457 * <code>message</code>, null otherwise 458 */ 459 public MimeDescriptor embeddedMessage(); 460 461 /** 462 * Gets headers. 463 * 464 * @return <code>Header</code> <code>Iterator</code>, not null 465 */ 466 public Iterator headers(); 467 468 /** 469 * Gets MIME body parameters parsed from <code>Content-Type</code>. 470 * 471 * @return <code>Header</code> <code>Iterator</code>, not null 472 */ 473 public Iterator contentTypeParameters(); 474 } 475 }