1 /* 2 Copyright (C) 2000-2007 SKYRIX Software AG 3 Copyright (C) 2007 Helge Hess 4 5 This file is part of SOPE. 6 7 SOPE is free software; you can redistribute it and/or modify it under 8 the terms of the GNU Lesser General Public License as published by the 9 Free Software Foundation; either version 2, or (at your option) any 10 later version. 11 12 SOPE is distributed in the hope that it will be useful, but WITHOUT ANY 13 WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 License for more details. 16 17 You should have received a copy of the GNU Lesser General Public 18 License along with SOPE; see the file COPYING. If not, write to the 19 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 20 02111-1307, USA. 21 */ 22 23 #ifndef __NGMime_NGMimePartParser_H__ 24 #define __NGMime_NGMimePartParser_H__ 25 26 #import <Foundation/NSObject.h> 27 #import <Foundation/NSString.h> 28 #import <Foundation/NSData.h> 29 #import <NGStreams/NGStreamProtocols.h> 30 #include <NGMime/NGPart.h> 31 #include <NGMime/NGMimeHeaderFieldParser.h> 32 #include <NGMime/NGMimeBodyParser.h> 33 34 /* 35 NGMimePartParser 36 37 This is an abstract class for parsing MIME parts. 38 39 Known Subclasses: 40 NGMimeMessageParser (parses RFC 822 MIME messages) 41 NGMimeBodyPartParser (parses the parts contained in a multipart structure) 42 NGHttpMessageParser (parses HTTP messages) 43 */ 44 45 @class NSString, NSData; 46 @class NGMutableHashMap, NGHashMap; 47 @class NGByteBuffer; 48 49 typedef struct _NGMimeHeaderNames { 50 NSString *accept; 51 NSString *acceptLanguage; 52 NSString *acceptEncoding; 53 NSString *acceptCharset; 54 NSString *cacheControl; 55 NSString *cc; 56 NSString *connection; 57 NSString *contentDisposition; 58 NSString *contentLength; 59 NSString *contentTransferEncoding; 60 NSString *contentType; 61 NSString *cookie; 62 NSString *date; 63 NSString *from; 64 NSString *host; 65 NSString *keepAlive; 66 NSString *messageID; 67 NSString *mimeVersion; 68 NSString *organization; 69 NSString *received; 70 NSString *returnPath; 71 NSString *referer; 72 NSString *replyTo; 73 NSString *subject; 74 NSString *to; 75 NSString *userAgent; 76 NSString *xMailer; 77 } NGMimeHeaderNames; 78 79 @interface NGMimePartParser : NSObject /* abstract */ 80 { 81 @protected 82 NSData *sourceData; /* for parsing with imutable data */ 83 const char *sourceBytes; 84 int dataIdx; /* data parsing index */ 85 int byteLen; 86 87 NGByteBuffer *source; // for parsing with LA 88 89 /* cached selectors */ 90 int (*readByte)(id, SEL); 91 int (*la)(id, SEL, unsigned); 92 void (*consume)(id, SEL); 93 void (*consumeCnt)(id, SEL, unsigned); 94 95 /* buffer-capacity and LA (has to be at least 4) */ 96 int bufLen; 97 98 /* 99 is set to the value of content-length header field 100 if contentLength == -1 -> read until EOF 101 */ 102 int contentLength; 103 BOOL useContentLength; // should be set in subclasses 104 NSString *contentTransferEncoding; 105 106 id delegate; // not retained to avoid retain cycles 107 108 struct { 109 BOOL parserWillParseHeader:1; 110 BOOL parserDidParseHeader:1; 111 BOOL parserKeepHeaderFieldData:1; 112 BOOL parserKeepHeaderFieldValue:1; 113 BOOL parserParseHeaderFieldData:1; 114 BOOL parserFoundCommentInHeaderField:1; 115 BOOL parserWillParseBodyOfPart:1; 116 BOOL parserDidParseBodyOfPart:1; 117 BOOL parserParseRawBodyDataOfPart:1; 118 BOOL parserBodyParserForPart:1; 119 BOOL parserDecodeBodyOfPart:1; 120 BOOL parserContentTypeOfPart:1; 121 } delegateRespondsTo; 122 123 124 } 125 126 + (NSStringEncoding)defaultHeaderFieldEncoding; 127 + (NGMimeHeaderNames *)headerFieldNames; 128 129 /* setting the delegate */ 130 131 - (void)setDelegate:(id)_delegate; 132 - (id)delegate; 133 134 /* parsing the whole part */ 135 136 - (id<NGMimePart>)parsePartFromStream:(id<NGStream>)_stream; 137 - (id<NGMimePart>)parsePartFromData:(NSData *)_data; 138 139 /* header field parsing */ 140 141 - (id<NGMimeHeaderFieldParser>)parserForHeaderField:(NSString *)_name; 142 143 /* perform further parsing of the header value */ 144 145 - (id)valueOfHeaderField:(NSString *)_name data:(id)_data; 146 147 // Parse headers until an empty line is seen, the delegate 148 // can reject header fields from being included in the HashMap 149 // This method can return <nil> to abort the parsing process. 150 - (NGHashMap *)parseHeader; 151 152 /* body parsing */ 153 154 - (id<NGMimePart>)producePartWithHeader:(NGHashMap *)_header; 155 156 - (NSData *)decodeBody:(NSData *)_data ofPart:(id<NGMimePart>)_part; 157 158 - (id<NGMimeBodyParser>) 159 parserForBodyOfPart:(id<NGMimePart>)_part data:(NSData *)_dt; 160 161 - (NGMimeType *)defaultContentTypeForPart:(id<NGMimePart>)_part; 162 163 - (void)parseBodyOfPart:(id<NGMimePart>)_part; 164 165 /* hooks for subclasses */ 166 167 - (BOOL)parsePrefix; // returns NO to abort parsing 168 - (void)parseSuffix; 169 - (BOOL)prepareForParsingFromStream:(id<NGStream>)_stream; 170 - (void)finishParsingOfPart:(id<NGMimePart>)_part; 171 172 /* accessors */ 173 174 - (void)setUseContentLength:(BOOL)_use; 175 - (BOOL)doesUseContentLength; 176 177 - (NSData *)applyTransferEncoding:(NSString *)_encoding onData:(NSData *)_data; 178 179 @end /* NGMimePartParser */ 180 181 @interface NSObject(NGMimePartParserDelegate) 182 183 /* 184 Called before the parsing of the headers begins. The delegate can return NO to 185 stop parsing or YES to continue parsing. 186 */ 187 - (BOOL)parserWillParseHeader:(NGMimePartParser *)_parser; 188 189 /* 190 This method is invoked when the parser finished parsing the complete header. 191 Those headers are available in the HashMap which is given to the delegate. 192 */ 193 - (void)parser:(NGMimePartParser *)_parser didParseHeader:(NGHashMap *)_headers; 194 195 /* 196 This method is invoked when a header field was read in. The field value is 197 as raw data which may be further processed by a field-value-parser. With 198 this method the delegate becomes to opportunity to parse the value itself. 199 When implementing this method the delegate takes over full responsibility 200 for parsing the field-value, no header-parser is invoked by the MIME parser 201 automatically. 202 */ 203 - (id)parser:(NGMimePartParser *)_parser 204 parseHeaderField:(NSString *)_name 205 data:(NSData *)_data; 206 207 /* 208 The delegate is asked whether the parser should proceed processing the header 209 field or whether the header field should be thrown away. Throwing away a header 210 field does not stop the parsing, it just ignores this field. 211 */ 212 - (BOOL)parser:(NGMimePartParser *)_parser 213 keepHeaderField:(NSString *)_name 214 data:(NSData *)_value; 215 216 /* 217 The delegate is asked whether the parser should proceed processing the header 218 field or whether the header field should be thrown away. Throwing away a header 219 field does not stop the parsing, it just ignores this field. 220 The value of the header is already parsed (this means in effect that the delegate 221 either didn't implement parser:keepHeader:data: or that it returned YES in this 222 method). 223 */ 224 - (BOOL)parser:(NGMimePartParser *)_parser 225 keepHeaderField:(NSString *)_name 226 value:(id)_value; 227 228 /* 229 The parser found a comment in a header field. This comment could be stored for 230 further processing by the delegate. Comment are usually ignored. 231 */ 232 - (void)parser:(NGMimePartParser *)_parser 233 foundComment:(NSString *)_comment // can be nil, if keepComments==NO 234 inHeaderField:(NSString *)_name; 235 236 /* 237 When the body of a part is read in appropriate content or content-transfer 238 encodings may need to be applied. Use this method to perform this operation. 239 */ 240 - (NSData *)parser:(NGMimePartParser *)_parser 241 decodeBody:(NSData *)_body 242 ofPart:(id<NGMimePart>)_part; 243 244 /* 245 After the headers were parsed the parser creates an NGMimePart object which 246 containes the headers. It will then begin to read in the body of the MIME 247 message, usually first as an NSData object. 248 You can return NO if you want to stop parsing (eg based on some values in the 249 headers or YES if you want to have the parser read in the data of the body. 250 */ 251 - (BOOL)parser:(NGMimePartParser *)_parser 252 willParseBodyOfPart:(id<NGMimePart>)_part; 253 254 /* 255 The parser successfully read in the body of the part. 256 */ 257 - (void)parser:(NGMimePartParser *)_parser 258 didParseBodyOfPart:(id<NGMimePart>)_part; 259 260 /* 261 After the MIME parser read in the body as an NSData object the delegate can 262 parse the body data and assign the result to the _part. 263 The delegate can return NO if it decides not to parse the body. The builtin 264 parser sequence is applied in this case. 265 Instead of parsing the body itself the delegate can select an appropriate 266 parser for the body using the -parser:bodyParserForPart: delegate method. 267 */ 268 - (BOOL)parser:(NGMimePartParser *)_parser 269 parseRawBodyData:(NSData *)_data 270 ofPart:(id<NGMimePart>)_part; 271 272 /* 273 If the delegate does not parse the body itself, it can still select an 274 appropriate body parser using this method. 275 */ 276 - (id<NGMimeBodyParser>)parser:(NGMimePartParser *)_parser 277 bodyParserForPart:(id<NGMimePart>)_part; 278 279 - (NGMimeType *)parser:(id)_parser 280 contentTypeOfPart:(id<NGMimePart>)_part; 281 282 @end /* NSObject(NGMimePartParserDelegate) */ 283 284 @interface NSObject(NGMimePartParser) 285 286 - (void)parser:(NGMimePartParser *)_parser 287 setOriginalHeaderFieldName:(NSString *)_name; 288 289 @end 290 291 @interface NSData(MIMEContentTransferEncoding) 292 293 - (NSData *)dataByApplyingMimeContentTransferEncoding:(NSString *)_enc; 294 295 @end 296 297 #endif /* __NGMime_NGMimePartParser_H__ */ 298