2 Copyright (C) 2000-2006 SKYRIX Software AG
3 Copyright (C) 2006 Helge Hess
5 This file is part of SOPE.
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
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.
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
23 #include "NGMBoxReader.h"
24 #include "NGMimeMessageParser.h"
28 @implementation NGMBoxReader
34 static inline int __readByte(NGMBoxReader *self);
36 __appendByte(NGMBoxReader *self, NSMutableData *_data, IMP _readBytes, int _c);
38 + (id)readerForMBox:(NSString *)_path {
42 fs = [NGFileStream alloc]; /* to keep gcc 3.4 happy */
43 fs = [[fs initWithPath:_path] autorelease];
44 bs = [NGBufferedStream filterWithSource:fs];
46 [fs openInMode:NGFileReadOnly];
48 return [[(NGMBoxReader *)[self alloc] initWithSource:bs] autorelease];
51 + (id)mboxWithSource:(id<NGByteSequenceStream>)_in {
52 return [[(NGMBoxReader *)[self alloc] initWithSource:_in] autorelease];
56 return [self initWithSource:nil];
59 - (id)initWithSource:(id<NGByteSequenceStream>)_in {
60 if ((self = [super init])) {
61 self->source = [_in retain];
62 self->isEndOfStream = NO;
64 self->separator = @"From -";
67 [self->source respondsToSelector:@selector(methodForSelector:)]
68 ? (int(*)(id, SEL))[(NSObject *)self->source
69 methodForSelector:@selector(readByte)]
76 [self->source release];
77 [self->lastDate release];
78 [self->separator release];
79 self->readByte = NULL;
83 - (id<NGMimePart>)nextMessage {
86 #define AppendBytes(_buf, _cnt) \
87 appendBytes(msgData, @selector(appendBytes:length:), _buf, _cnt)
89 #define AppendByte(_c) \
90 __appendByte(self, msgData, appendBytes, _c)
93 NSMutableData *msgData = nil;
94 IMP appendBytes = NULL;
96 const int bufLen = 256;
101 int sepLength = [self->separator length];
102 const char *sepStrbuf = NULL;
104 sepStrbuf = [self->separator cString];
106 msgData = [[NSMutableData allocWithZone:[self zone]]
107 initWithCapacity:4096];
109 appendBytes = [msgData methodForSelector:@selector(appendBytes:length:)];
112 if (self->isEndOfStream)
115 if (self->lastDate == nil) {
116 // start of MBox from-line length < 255
118 while (bufCnt < sepLength) { // parse form
119 c = __readByte(self);
122 if (strncmp(buf, sepStrbuf, sepLength) != 0) {
123 NSLog(@"WARNING: no %@ at begin of MBox %s", self->separator, buf);
126 while ((c = __readByte(self)) != '\n') { // parse date < 255
128 if (bufCnt >= bufLen) {
129 NSLog(@"WARNING: too long from-line");
133 if (buf[bufCnt - 1] == '\r')
134 self->lastDate = [[NSString allocWithZone:[self zone]] initWithCString:buf
137 self->lastDate = [[NSString allocWithZone:[self zone]] initWithCString:buf
144 AppendBytes(buf, bufCnt); // write buffer to data
146 if (c != '\n') { // no end of line
148 while ((c = __readByte(self)) != '\n') {
150 if (bufCnt >= bufLen) {
151 AppendBytes(buf, bufCnt);
156 AppendBytes(buf, bufCnt);
165 while ((c = __readByte(self)) != '\n' &&
166 bufCnt < sepLength) { // read oly until seperator length
173 } while (strncmp(buf, sepStrbuf, sepLength) != 0);
176 self->isEndOfStream = YES;
178 else { // read from-line
180 while ((c = __readByte(self)) != '\n') { // from-line is not longer
181 // than 255 ( I hope it :))
183 if (bufCnt >= bufLen) {
184 NSLog(@"WARNING: too long from-line");
188 [self->lastDate release];
189 self->lastDate = [[NSString alloc] initWithCString:buf length:bufCnt];
193 if ([msgData length] == 0) // end, no msg data
197 NGMimeMessageParser *parser = nil;
198 NGDataStream *stream = nil;
203 parser = [[NGMimeMessageParser alloc] init];
204 stream = [[NGDataStream alloc] initWithData:msgData];
207 part = [parser parsePartFromStream:stream];
212 fprintf(stderr, "mbox: failed to parse message:\n%s",
213 [[NSString stringWithCString:[msgData bytes]
214 length:[msgData length]] cString]);
217 [parser release]; parser = nil;
218 [stream release]; stream = nil;
219 [msgData release]; msgData = nil;
227 - (NSString *)description {
228 return [NSString stringWithFormat:@"<%@[0x%p] source=%@ endOfStream=%@",
229 NSStringFromClass([self class]), self,
230 self->source, self->isEndOfStream ? @"YES" : @"NO"];
236 static inline int __readByte(NGMBoxReader *self) {
237 return (self->readByte)
238 ? self->readByte(self->source, @selector(readByte))
239 : [self->source readByte];
242 static inline void __appendByte(NGMBoxReader *self, NSMutableData *_data,
243 IMP _readBytes, int _c) {
244 unsigned char c = _c;
245 _readBytes(_data, @selector(appendBytes:length:), &c, 1);
248 @end /* NGMBoxReader */