KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > james > imapserver > commands > FetchCommand


1 /***********************************************************************
2  * Copyright (c) 2000-2004 The Apache Software Foundation. *
3  * All rights reserved. *
4  * ------------------------------------------------------------------- *
5  * Licensed under the Apache License, Version 2.0 (the "License"); you *
6  * may not use this file except in compliance with the License. You *
7  * may obtain a copy of the License at: *
8  * *
9  * http://www.apache.org/licenses/LICENSE-2.0 *
10  * *
11  * Unless required by applicable law or agreed to in writing, software *
12  * distributed under the License is distributed on an "AS IS" BASIS, *
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or *
14  * implied. See the License for the specific language governing *
15  * permissions and limitations under the License. *
16  ***********************************************************************/

17
18 package org.apache.james.imapserver.commands;
19
20 import org.apache.excalibur.util.StringUtil;
21 import org.apache.james.core.MimeMessageWrapper;
22 import org.apache.james.imapserver.ImapRequestLineReader;
23 import org.apache.james.imapserver.ImapResponse;
24 import org.apache.james.imapserver.ImapSession;
25 import org.apache.james.imapserver.ProtocolException;
26 import org.apache.james.imapserver.store.MailboxException;
27 import org.apache.james.imapserver.store.MessageFlags;
28 import org.apache.james.imapserver.store.SimpleImapMessage;
29 import org.apache.james.imapserver.store.ImapMailbox;
30
31 import javax.mail.MessagingException;
32 import javax.mail.internet.MimeMessage;
33 import java.io.ByteArrayOutputStream;
34 import java.io.IOException;
35 import java.util.ArrayList;
36 import java.util.Collections;
37 import java.util.Enumeration;
38 import java.util.Iterator;
39 import java.util.List;
40 import java.util.Collection;
41
42 /**
43  * Handles processeing for the FETCH imap command.
44  *
45  *
46  * @version $Revision: 1.1.2.3 $
47  */

48 class FetchCommand extends SelectedStateCommand implements UidEnabledCommand
49 {
50     public static final String NAME = "FETCH";
51     public static final String ARGS = "<message-set> <fetch-profile>";
52
53     private FetchCommandParser parser = new FetchCommandParser();
54
55     /** @see CommandTemplate#doProcess */
56     protected void doProcess( ImapRequestLineReader request,
57                               ImapResponse response,
58                               ImapSession session )
59             throws ProtocolException, MailboxException
60     {
61         doProcess( request, response, session, false );
62     }
63
64     public void doProcess( ImapRequestLineReader request,
65                               ImapResponse response,
66                               ImapSession session,
67                               boolean useUids )
68             throws ProtocolException, MailboxException
69     {
70         IdSet idSet = parser.set( request );
71         FetchRequest fetch = parser.fetchRequest( request );
72         parser.endLine( request );
73
74         ImapMailbox mailbox = session.getSelected();
75         long[] uids = mailbox.getMessageUids();
76         for ( int i = 0; i < uids.length; i++ ) {
77             long uid = uids[i];
78             int msn = mailbox.getMsn( uid );
79
80             if ( ( useUids && idSet.includes( uid ) ) ||
81                  ( !useUids && idSet.includes( msn ) ) )
82             {
83                 SimpleImapMessage imapMessage = mailbox.getMessage( uid );
84                 String msgData = outputMessage( fetch, imapMessage );
85                 response.fetchResponse( msn, msgData );
86             }
87         }
88
89         session.unsolicitedResponses( response );
90         response.commandComplete( this );
91     }
92
93     private String outputMessage( FetchRequest fetch, SimpleImapMessage message )
94             throws MailboxException, ProtocolException
95     {
96
97         StringBuffer response = new StringBuffer();
98
99         List elements = fetch.getElements();
100         for ( int i = 0; i < elements.size(); i++ ) {
101             FetchElement fetchElement = ( FetchElement ) elements.get( i );
102             if ( i > 0 ) {
103                 response.append( SP );
104             }
105             response.append( fetchElement.getResponseName() );
106             response.append( SP );
107
108             if ( fetchElement == FetchElement.FLAGS ) {
109                 MessageFlags flags = message.getFlags();
110                 response.append( flags.format() );
111             }
112             else if ( fetchElement == FetchElement.INTERNALDATE ) {
113                 // TODO format properly
114
String internalDate = message.getAttributes().getInternalDateAsString();
115                 response.append( "\"" );
116                 response.append( internalDate );
117                 response.append ( "\"" );
118             }
119             else if ( fetchElement == FetchElement.RFC822_SIZE ) {
120                 response.append( message.getAttributes().getSize() );
121             }
122             else if ( fetchElement == FetchElement.ENVELOPE ) {
123                 response.append( message.getAttributes().getEnvelope() );
124             }
125             else if ( fetchElement == FetchElement.BODY ) {
126                 response.append( message.getAttributes().getBodyStructure( false ) );
127             }
128             else if ( fetchElement == FetchElement.BODYSTRUCTURE ) {
129                 response.append( message.getAttributes().getBodyStructure( true ) );
130             }
131             else if ( fetchElement == FetchElement.UID ) {
132                 response.append( message.getUid() );
133             }
134             // Various mechanisms for returning message body.
135
else if ( fetchElement instanceof BodyFetchElement ) {
136                 BodyFetchElement bodyFetchElement = (BodyFetchElement)fetchElement;
137                 String sectionSpecifier = bodyFetchElement.getParameters();
138                 boolean peek = bodyFetchElement.isPeek();
139
140                 MimeMessage mimeMessage = message.getMimeMessage();
141                 try {
142                     handleBodyFetch( mimeMessage, sectionSpecifier, response );
143                 }
144                 catch ( MessagingException e ) {
145                     // TODO chain exceptions
146
throw new MailboxException( e.getMessage() );
147                 }
148
149                 if ( ! peek ) {
150                     message.getFlags().setSeen( true );
151                     // TODO need to store this change.
152
}
153             }
154             else {
155                 throw new ProtocolException( "Invalid fetch attribute" );
156             }
157         }
158
159         return response.toString();
160     }
161
162
163     private void handleBodyFetch( MimeMessage mimeMessage,
164                                   String sectionSpecifier,
165                                   StringBuffer response )
166             throws ProtocolException, MessagingException
167     {
168         if ( sectionSpecifier.length() == 0 ) {
169             // TODO - need to use an InputStream from the response here.
170
ByteArrayOutputStream bout = new ByteArrayOutputStream();
171             try {
172                 mimeMessage.writeTo(bout);
173             }
174             catch ( IOException e ) {
175                 throw new ProtocolException( "Error reading message source" );
176             }
177             byte[] bytes = bout.toByteArray();
178             addLiteral( bytes, response );
179         }
180         else if ( sectionSpecifier.equalsIgnoreCase( "HEADER" ) ) {
181             Enumeration enum = mimeMessage.getAllHeaderLines();
182             addHeaders( enum, response );
183         }
184         else if ( sectionSpecifier.startsWith( "HEADER.FIELDS.NOT " ) ) {
185             String[] excludeNames = extractHeaderList( sectionSpecifier, "HEADER.FIELDS.NOT ".length() );
186             Enumeration enum = mimeMessage.getNonMatchingHeaderLines( excludeNames );
187             addHeaders( enum, response );
188         }
189         else if ( sectionSpecifier.startsWith( "HEADER.FIELDS " ) ) {
190             String[] includeNames = extractHeaderList( sectionSpecifier, "HEADER.FIELDS ".length() );
191             Enumeration enum = mimeMessage.getMatchingHeaderLines( includeNames );
192             addHeaders( enum, response );
193         }
194         else if ( sectionSpecifier.equalsIgnoreCase( "MIME" ) ) {
195             // TODO implement
196
throw new ProtocolException( "MIME not yet implemented." );
197         }
198         else if ( sectionSpecifier.equalsIgnoreCase( "TEXT" ) ) {
199             // TODO - need to use an InputStream from the response here.
200
// TODO - this is a hack. To get just the body content, I'm using a null
201
// input stream to take the headers. Need to have a way of ignoring headers.
202
ByteArrayOutputStream headerOut = new ByteArrayOutputStream();
203             ByteArrayOutputStream bodyOut = new ByteArrayOutputStream();
204             try {
205                 MimeMessageWrapper.writeTo( mimeMessage, headerOut, bodyOut );
206                 byte[] bytes = bodyOut.toByteArray();
207
208                 addLiteral( bytes, response );
209
210             }
211             catch ( IOException e ) {
212                 throw new ProtocolException( "Error reading message source" );
213             }
214         }
215         else {
216             // Should be a part specifier followed by a section specifier.
217
// See if there's a leading part specifier.
218
// If so, get the number, get the part, and call this recursively.
219
int dotPos = sectionSpecifier.indexOf( '.' );
220             if ( dotPos == -1 ) {
221                 throw new ProtocolException( "Malformed fetch attribute: " + sectionSpecifier );
222             }
223             int partNumber = Integer.parseInt( sectionSpecifier.substring( 0, dotPos ) );
224             String partSectionSpecifier = sectionSpecifier.substring( dotPos + 1 );
225
226             // TODO - get the MimePart of the mimeMessage, and call this method
227
// with the new partSectionSpecifier.
228
// MimeMessage part;
229
// handleBodyFetch( part, partSectionSpecifier, response );
230
throw new ProtocolException( "Mime parts not yet implemented for fetch." );
231         }
232
233     }
234
235     private void addLiteral( byte[] bytes, StringBuffer response )
236     {
237         response.append('{' );
238         response.append( bytes.length + 1 );
239         response.append( '}' );
240         response.append( "\r\n" );
241
242         for ( int i = 0; i < bytes.length; i++ ) {
243             byte b = bytes[i];
244             response.append((char)b);
245         }
246     }
247
248     // TODO should do this at parse time.
249
private String[] extractHeaderList( String headerList, int prefixLen )
250     {
251         // Remove the trailing and leading ')('
252
String tmp = headerList.substring( prefixLen + 1, headerList.length() - 1 );
253         String[] headerNames = StringUtil.split( tmp, " " );
254         return headerNames;
255     }
256
257     private void addHeaders( Enumeration enum, StringBuffer response )
258     {
259         List lines = new ArrayList();
260         int count = 0;
261         while (enum.hasMoreElements()) {
262             String line = (String)enum.nextElement();
263             count += line.length() + 2;
264             lines.add(line);
265         }
266         response.append( '{' );
267         response.append( count + 2 );
268         response.append( '}' );
269         response.append("\r\n");
270
271         Iterator lit = lines.iterator();
272         while (lit.hasNext()) {
273             String line = (String)lit.next();
274             response.append( line );
275             response.append( "\r\n" );
276         }
277         response.append("\r\n");
278     }
279
280     /** @see ImapCommand#getName */
281     public String getName()
282     {
283         return NAME;
284     }
285
286     /** @see CommandTemplate#getArgSyntax */
287     public String getArgSyntax()
288     {
289         return ARGS;
290     }
291
292     private class FetchCommandParser extends CommandParser
293     {
294
295
296         public FetchRequest fetchRequest( ImapRequestLineReader request )
297                 throws ProtocolException
298         {
299             FetchRequest fetch = new FetchRequest();
300             CharacterValidator validator = new NoopCharValidator();
301
302             char next = nextNonSpaceChar( request );
303             consumeChar( request, '(' );
304
305             next = nextNonSpaceChar( request );
306             while ( next != ')' ) {
307                 fetch.addElement( getNextElement( request ) );
308                 next = nextNonSpaceChar( request );
309             }
310
311             consumeChar(request, ')');
312
313             return fetch;
314         }
315
316         private FetchElement getNextElement( ImapRequestLineReader request)
317                 throws ProtocolException
318         {
319             char next = nextCharInLine( request );
320                 StringBuffer element = new StringBuffer();
321                 while ( next != ' ' && next != '[' && next != ')' ) {
322                     element.append(next);
323                     request.consume();
324                     next = nextCharInLine( request );
325                 }
326                 String name = element.toString();
327                 // Simple elements with no '[]' parameters.
328
if ( next == ' ' || next == ')' ) {
329                     if ( "FAST".equalsIgnoreCase( name ) ) {
330                         return FetchElement.FAST;
331                     }
332                     if ( "FULL".equalsIgnoreCase( name ) ) {
333                         return FetchElement.FULL;
334                     }
335                     if ( "ALL".equalsIgnoreCase( name ) ) {
336                         return FetchElement.ALL;
337                     }
338                     if ( "FLAGS".equalsIgnoreCase( name ) ) {
339                         return FetchElement.FLAGS;
340                     }
341                     if ( "RFC822.SIZE".equalsIgnoreCase( name ) ) {
342                         return FetchElement.RFC822_SIZE;
343                     }
344                     if ( "ENVELOPE".equalsIgnoreCase( name ) ) {
345                         return FetchElement.ENVELOPE;
346                     }
347                     if ( "INTERNALDATE".equalsIgnoreCase( name ) ) {
348                         return FetchElement.INTERNALDATE;
349                     }
350                     if ( "BODY".equalsIgnoreCase( name ) ) {
351                         return FetchElement.BODY;
352                     }
353                     if ( "BODYSTRUCTURE".equalsIgnoreCase( name ) ) {
354                         return FetchElement.BODYSTRUCTURE;
355                     }
356                     if ( "UID".equalsIgnoreCase( name ) ) {
357                         return FetchElement.UID;
358                     }
359                     if ( "RFC822".equalsIgnoreCase( name ) ) {
360                         return new BodyFetchElement( "RFC822", "", false );
361                     }
362                     if ( "RFC822.HEADER".equalsIgnoreCase( name ) ) {
363                         return new BodyFetchElement( "RFC822.HEADER", "HEADER", true );
364                     }
365                     if ( "RFC822.TEXT".equalsIgnoreCase( name ) ) {
366                         return new BodyFetchElement( "RFC822.TEXT", "TEXT", false );
367                     }
368                     else {
369                         throw new ProtocolException( "Invalid fetch attribute: " + name );
370                     }
371                 }
372                 else {
373                     consumeChar( request, '[' );
374
375                     StringBuffer sectionIdentifier = new StringBuffer();
376                     next = nextCharInLine( request );
377                     while ( next != ']' ) {
378                         sectionIdentifier.append( next );
379                         request.consume();
380                         next = nextCharInLine(request);
381                     }
382                     consumeChar( request, ']' );
383
384                     String parameter = sectionIdentifier.toString();
385
386                     if ( "BODY".equalsIgnoreCase( name ) ) {
387                         return new BodyFetchElement( "BODY[" + parameter + "]", parameter, false );
388                     }
389                     if ( "BODY.PEEK".equalsIgnoreCase( name ) ) {
390                         return new BodyFetchElement( "BODY[" + parameter + "]", parameter, true );
391                     }
392                     else {
393                         throw new ProtocolException( "Invalid fetch attibute: " + name + "[]" );
394                     }
395                 }
396             }
397
398         private char nextCharInLine( ImapRequestLineReader request )
399                 throws ProtocolException
400         {
401             char next = request.nextChar();
402             if ( next == '\r' || next == '\n' ) {
403                 throw new ProtocolException( "Unexpected end of line." );
404             }
405             return next;
406         }
407
408         private char nextNonSpaceChar( ImapRequestLineReader request )
409                 throws ProtocolException
410         {
411             char next = request.nextChar();
412             while ( next == ' ' ) {
413                 request.consume();
414                 next = request.nextChar();
415             }
416             return next;
417         }
418
419     }
420
421
422     private static class FetchRequest
423     {
424         private ArrayList elements = new ArrayList();
425         List getElements() {
426             return Collections.unmodifiableList( elements );
427         }
428         void addElement( FetchElement element )
429         {
430             if ( element == FetchElement.ALL ) {
431                 elements.add( FetchElement.FLAGS );
432                 elements.add( FetchElement.INTERNALDATE );
433                 elements.add( FetchElement.RFC822_SIZE );
434                 elements.add( FetchElement.ENVELOPE );
435             }
436             else if ( element == FetchElement.FAST ) {
437                 elements.add( FetchElement.FLAGS );
438                 elements.add( FetchElement.INTERNALDATE );
439                 elements.add( FetchElement.RFC822_SIZE );
440            }
441             else if ( element == FetchElement.FULL ) {
442                 elements.add( FetchElement.FLAGS );
443                 elements.add( FetchElement.INTERNALDATE );
444                 elements.add( FetchElement.RFC822_SIZE );
445                 elements.add( FetchElement.ENVELOPE );
446                 elements.add( FetchElement.BODY );
447             }
448             else {
449                 elements.add( element );
450             }
451         }
452     }
453
454     private static class FetchElement
455     {
456         public static final FetchElement FLAGS = new FetchElement( "FLAGS" );
457         public static final FetchElement INTERNALDATE = new FetchElement( "INTERNALDATE" );
458         public static final FetchElement RFC822_SIZE= new FetchElement( "RFC822.SIZE" );
459         public static final FetchElement ENVELOPE = new FetchElement( "ENVELOPE" );
460         public static final FetchElement BODY = new FetchElement( "BODY" );
461         public static final FetchElement BODYSTRUCTURE = new FetchElement( "BODYSTRUCTURE" );
462         public static final FetchElement UID = new FetchElement( "UID" );
463
464         public static final FetchElement FAST = new FetchElement( "FAST" );
465         public static final FetchElement FULL = new FetchElement( "FULL" );
466         public static final FetchElement ALL = new FetchElement( "ALL" );
467
468         String name;
469
470         protected FetchElement( String name )
471         {
472             this.name = name;
473         }
474
475         public String getResponseName() {
476             return this.name;
477         }
478     }
479
480     private class BodyFetchElement extends FetchElement
481     {
482         private boolean peek;
483         private String sectionIdentifier;
484
485         public BodyFetchElement( String name, String sectionIdentifier, boolean peek )
486         {
487             super( name );
488             this.sectionIdentifier = sectionIdentifier;
489             this.peek = peek;
490         }
491
492         public String getParameters()
493         {
494             return this.sectionIdentifier;
495         }
496
497         public boolean isPeek()
498         {
499             return this.peek;
500         }
501     }
502
503 }
504 /*
505 6.4.5. FETCH Command
506
507    Arguments: message set
508                message data item names
509
510    Responses: untagged responses: FETCH
511
512    Result: OK - fetch completed
513                NO - fetch error: can't fetch that data
514                BAD - command unknown or arguments invalid
515
516       The FETCH command retrieves data associated with a message in the
517       mailbox. The data items to be fetched can be either a single atom
518       or a parenthesized list.
519
520       The currently defined data items that can be fetched are:
521
522       ALL Macro equivalent to: (FLAGS INTERNALDATE
523                      RFC822.SIZE ENVELOPE)
524
525       BODY Non-extensible form of BODYSTRUCTURE.
526
527       BODY[<section>]<<partial>>
528                      The text of a particular body section. The section
529                      specification is a set of zero or more part
530                      specifiers delimited by periods. A part specifier
531                      is either a part number or one of the following:
532                      HEADER, HEADER.FIELDS, HEADER.FIELDS.NOT, MIME, and
533                      TEXT. An empty section specification refers to the
534                      entire message, including the header.
535
536                      Every message has at least one part number.
537                      Non-[MIME-IMB] messages, and non-multipart
538                      [MIME-IMB] messages with no encapsulated message,
539                      only have a part 1.
540
541                      Multipart messages are assigned consecutive part
542                      numbers, as they occur in the message. If a
543                      particular part is of type message or multipart,
544                      its parts MUST be indicated by a period followed by
545                      the part number within that nested multipart part.
546
547                      A part of type MESSAGE/RFC822 also has nested part
548                      numbers, referring to parts of the MESSAGE part's
549                      body.
550
551                      The HEADER, HEADER.FIELDS, HEADER.FIELDS.NOT, and
552                      TEXT part specifiers can be the sole part specifier
553                      or can be prefixed by one or more numeric part
554                      specifiers, provided that the numeric part
555                      specifier refers to a part of type MESSAGE/RFC822.
556                      The MIME part specifier MUST be prefixed by one or
557                      more numeric part specifiers.
558
559                      The HEADER, HEADER.FIELDS, and HEADER.FIELDS.NOT
560                      part specifiers refer to the [RFC-822] header of
561                      the message or of an encapsulated [MIME-IMT]
562                      MESSAGE/RFC822 message. HEADER.FIELDS and
563                      HEADER.FIELDS.NOT are followed by a list of
564                      field-name (as defined in [RFC-822]) names, and
565                      return a subset of the header. The subset returned
566                      by HEADER.FIELDS contains only those header fields
567                      with a field-name that matches one of the names in
568                      the list; similarly, the subset returned by
569                      HEADER.FIELDS.NOT contains only the header fields
570                      with a non-matching field-name. The field-matching
571                      is case-insensitive but otherwise exact. In all
572                      cases, the delimiting blank line between the header
573                      and the body is always included.
574
575                      The MIME part specifier refers to the [MIME-IMB]
576                      header for this part.
577
578                      The TEXT part specifier refers to the text body of
579                      the message, omitting the [RFC-822] header.
580
581
582                        Here is an example of a complex message
583                        with some of its part specifiers:
584
585                         HEADER ([RFC-822] header of the message)
586                         TEXT MULTIPART/MIXED
587                         1 TEXT/PLAIN
588                         2 APPLICATION/OCTET-STREAM
589                         3 MESSAGE/RFC822
590                         3.HEADER ([RFC-822] header of the message)
591                         3.TEXT ([RFC-822] text body of the message)
592                         3.1 TEXT/PLAIN
593                         3.2 APPLICATION/OCTET-STREAM
594                         4 MULTIPART/MIXED
595                         4.1 IMAGE/GIF
596                         4.1.MIME ([MIME-IMB] header for the IMAGE/GIF)
597                         4.2 MESSAGE/RFC822
598                         4.2.HEADER ([RFC-822] header of the message)
599                         4.2.TEXT ([RFC-822] text body of the message)
600                         4.2.1 TEXT/PLAIN
601                         4.2.2 MULTIPART/ALTERNATIVE
602                         4.2.2.1 TEXT/PLAIN
603                         4.2.2.2 TEXT/RICHTEXT
604
605
606                      It is possible to fetch a substring of the
607                      designated text. This is done by appending an open
608                      angle bracket ("<"), the octet position of the
609                      first desired octet, a period, the maximum number
610                      of octets desired, and a close angle bracket (">")
611                      to the part specifier. If the starting octet is
612                      beyond the end of the text, an empty string is
613                      returned.
614
615                      Any partial fetch that attempts to read beyond the
616                      end of the text is truncated as appropriate. A
617                      partial fetch that starts at octet 0 is returned as
618                      a partial fetch, even if this truncation happened.
619
620                           Note: this means that BODY[]<0.2048> of a
621                           1500-octet message will return BODY[]<0>
622                           with a literal of size 1500, not BODY[].
623
624                           Note: a substring fetch of a
625                           HEADER.FIELDS or HEADER.FIELDS.NOT part
626                           specifier is calculated after subsetting
627                           the header.
628
629
630                      The \Seen flag is implicitly set; if this causes
631                      the flags to change they SHOULD be included as part
632                      of the FETCH responses.
633
634       BODY.PEEK[<section>]<<partial>>
635                      An alternate form of BODY[<section>] that does not
636                      implicitly set the \Seen flag.
637
638       BODYSTRUCTURE The [MIME-IMB] body structure of the message. This
639                      is computed by the server by parsing the [MIME-IMB]
640                      header fields in the [RFC-822] header and
641                      [MIME-IMB] headers.
642
643       ENVELOPE The envelope structure of the message. This is
644                      computed by the server by parsing the [RFC-822]
645                      header into the component parts, defaulting various
646                      fields as necessary.
647
648       FAST Macro equivalent to: (FLAGS INTERNALDATE
649                      RFC822.SIZE)
650
651       FLAGS The flags that are set for this message.
652
653       FULL Macro equivalent to: (FLAGS INTERNALDATE
654                      RFC822.SIZE ENVELOPE BODY)
655
656       INTERNALDATE The internal date of the message.
657
658       RFC822 Functionally equivalent to BODY[], differing in the
659                      syntax of the resulting untagged FETCH data (RFC822
660                      is returned).
661
662       RFC822.HEADER Functionally equivalent to BODY.PEEK[HEADER],
663                      differing in the syntax of the resulting untagged
664                      FETCH data (RFC822.HEADER is returned).
665
666       RFC822.SIZE The [RFC-822] size of the message.
667
668       RFC822.TEXT Functionally equivalent to BODY[TEXT], differing in
669                      the syntax of the resulting untagged FETCH data
670                      (RFC822.TEXT is returned).
671
672       UID The unique identifier for the message.
673
674    Example: C: A654 FETCH 2:4 (FLAGS BODY[HEADER.FIELDS (DATE FROM)])
675                S: * 2 FETCH ....
676                S: * 3 FETCH ....
677                S: * 4 FETCH ....
678                S: A654 OK FETCH completed
679
680
681 7.4.2. FETCH Response
682
683    Contents: message data
684
685       The FETCH response returns data about a message to the client.
686       The data are pairs of data item names and their values in
687       parentheses. This response occurs as the result of a FETCH or
688       STORE command, as well as by unilateral server decision (e.g. flag
689       updates).
690
691       The current data items are:
692
693       BODY A form of BODYSTRUCTURE without extension data.
694
695       BODY[<section>]<<origin_octet>>
696                      A string expressing the body contents of the
697                      specified section. The string SHOULD be
698                      interpreted by the client according to the content
699                      transfer encoding, body type, and subtype.
700
701                      If the origin octet is specified, this string is a
702                      substring of the entire body contents, starting at
703                      that origin octet. This means that BODY[]<0> MAY
704                      be truncated, but BODY[] is NEVER truncated.
705
706                      8-bit textual data is permitted if a [CHARSET]
707                      identifier is part of the body parameter
708                      parenthesized list for this section. Note that
709                      headers (part specifiers HEADER or MIME, or the
710                      header portion of a MESSAGE/RFC822 part), MUST be
711                      7-bit; 8-bit characters are not permitted in
712                      headers. Note also that the blank line at the end
713                      of the header is always included in header data.
714
715                      Non-textual data such as binary data MUST be
716                      transfer encoded into a textual form such as BASE64
717                      prior to being sent to the client. To derive the
718                      original binary data, the client MUST decode the
719                      transfer encoded string.
720
721       BODYSTRUCTURE A parenthesized list that describes the [MIME-IMB]
722                      body structure of a message. This is computed by
723                      the server by parsing the [MIME-IMB] header fields,
724                      defaulting various fields as necessary.
725
726                      For example, a simple text message of 48 lines and
727                      2279 octets can have a body structure of: ("TEXT"
728                      "PLAIN" ("CHARSET" "US-ASCII") NIL NIL "7BIT" 2279
729                      48)
730
731                      Multiple parts are indicated by parenthesis
732                      nesting. Instead of a body type as the first
733                      element of the parenthesized list there is a nested
734                      body. The second element of the parenthesized list
735                      is the multipart subtype (mixed, digest, parallel,
736                      alternative, etc.).
737
738                      For example, a two part message consisting of a
739                      text and a BASE645-encoded text attachment can have
740                      a body structure of: (("TEXT" "PLAIN" ("CHARSET"
741                      "US-ASCII") NIL NIL "7BIT" 1152 23)("TEXT" "PLAIN"
742                      ("CHARSET" "US-ASCII" "NAME" "cc.diff")
743                      "<960723163407.20117h@cac.washington.edu>"
744                      "Compiler diff" "BASE64" 4554 73) "MIXED"))
745
746                      Extension data follows the multipart subtype.
747                      Extension data is never returned with the BODY
748                      fetch, but can be returned with a BODYSTRUCTURE
749                      fetch. Extension data, if present, MUST be in the
750                      defined order.
751
752                      The extension data of a multipart body part are in
753                      the following order:
754
755                      body parameter parenthesized list
756                         A parenthesized list of attribute/value pairs
757                         [e.g. ("foo" "bar" "baz" "rag") where "bar" is
758                         the value of "foo" and "rag" is the value of
759                         "baz"] as defined in [MIME-IMB].
760
761                      body disposition
762                         A parenthesized list, consisting of a
763                         disposition type string followed by a
764                         parenthesized list of disposition
765                         attribute/value pairs. The disposition type and
766                         attribute names will be defined in a future
767                         standards-track revision to [DISPOSITION].
768
769                      body language
770                         A string or parenthesized list giving the body
771                         language value as defined in [LANGUAGE-TAGS].
772
773                      Any following extension data are not yet defined in
774                      this version of the protocol. Such extension data
775                      can consist of zero or more NILs, strings, numbers,
776                      or potentially nested parenthesized lists of such
777                      data. Client implementations that do a
778                      BODYSTRUCTURE fetch MUST be prepared to accept such
779                      extension data. Server implementations MUST NOT
780                      send such extension data until it has been defined
781                      by a revision of this protocol.
782
783                      The basic fields of a non-multipart body part are
784                      in the following order:
785
786                      body type
787                         A string giving the content media type name as
788                         defined in [MIME-IMB].
789
790                      body subtype
791                         A string giving the content subtype name as
792                         defined in [MIME-IMB].
793
794                      body parameter parenthesized list
795                         A parenthesized list of attribute/value pairs
796                         [e.g. ("foo" "bar" "baz" "rag") where "bar" is
797                         the value of "foo" and "rag" is the value of
798                         "baz"] as defined in [MIME-IMB].
799
800                      body id
801                         A string giving the content id as defined in
802                         [MIME-IMB].
803
804                      body description
805                         A string giving the content description as
806                         defined in [MIME-IMB].
807
808                      body encoding
809                         A string giving the content transfer encoding as
810                         defined in [MIME-IMB].
811
812                      body size
813                         A number giving the size of the body in octets.
814                         Note that this size is the size in its transfer
815                         encoding and not the resulting size after any
816                         decoding.
817
818                      A body type of type MESSAGE and subtype RFC822
819                      contains, immediately after the basic fields, the
820                      envelope structure, body structure, and size in
821                      text lines of the encapsulated message.
822
823                      A body type of type TEXT contains, immediately
824                      after the basic fields, the size of the body in
825                      text lines. Note that this size is the size in its
826                      content transfer encoding and not the resulting
827                      size after any decoding.
828
829                      Extension data follows the basic fields and the
830                      type-specific fields listed above. Extension data
831                      is never returned with the BODY fetch, but can be
832                      returned with a BODYSTRUCTURE fetch. Extension
833                      data, if present, MUST be in the defined order.
834
835                      The extension data of a non-multipart body part are
836                      in the following order:
837
838                      body MD5
839                         A string giving the body MD5 value as defined in
840                         [MD5].
841
842                      body disposition
843                         A parenthesized list with the same content and
844                         function as the body disposition for a multipart
845                         body part.
846
847                      body language
848                         A string or parenthesized list giving the body
849                         language value as defined in [LANGUAGE-TAGS].
850
851                      Any following extension data are not yet defined in
852                      this version of the protocol, and would be as
853                      described above under multipart extension data.
854
855       ENVELOPE A parenthesized list that describes the envelope
856                      structure of a message. This is computed by the
857                      server by parsing the [RFC-822] header into the
858                      component parts, defaulting various fields as
859                      necessary.
860
861                      The fields of the envelope structure are in the
862                      following order: date, subject, from, sender,
863                      reply-to, to, cc, bcc, in-reply-to, and message-id.
864                      The date, subject, in-reply-to, and message-id
865                      fields are strings. The from, sender, reply-to,
866                      to, cc, and bcc fields are parenthesized lists of
867                      address structures.
868
869                      An address structure is a parenthesized list that
870                      describes an electronic mail address. The fields
871                      of an address structure are in the following order:
872                      personal name, [SMTP] at-domain-list (source
873                      route), mailbox name, and host name.
874
875                      [RFC-822] group syntax is indicated by a special
876                      form of address structure in which the host name
877                      field is NIL. If the mailbox name field is also
878                      NIL, this is an end of group marker (semi-colon in
879                      RFC 822 syntax). If the mailbox name field is
880                      non-NIL, this is a start of group marker, and the
881                      mailbox name field holds the group name phrase.
882
883                      Any field of an envelope or address structure that
884                      is not applicable is presented as NIL. Note that
885                      the server MUST default the reply-to and sender
886                      fields from the from field; a client is not
887                      expected to know to do this.
888
889       FLAGS A parenthesized list of flags that are set for this
890                      message.
891
892       INTERNALDATE A string representing the internal date of the
893                      message.
894
895       RFC822 Equivalent to BODY[].
896
897       RFC822.HEADER Equivalent to BODY.PEEK[HEADER].
898
899       RFC822.SIZE A number expressing the [RFC-822] size of the
900                      message.
901
902       RFC822.TEXT Equivalent to BODY[TEXT].
903
904       UID A number expressing the unique identifier of the
905                      message.
906
907
908    Example: S: * 23 FETCH (FLAGS (\Seen) RFC822.SIZE 44827)
909
910 */

911
Popular Tags