2 Copyright (C) 2000-2005 SKYRIX Software AG
4 This file is part of SOPE.
6 SOPE is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with SOPE; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22 #include "NGMBoxReader.h"
23 #include "NGMimeMessageParser.h"
27 @implementation NGMBoxReader
33 static inline int __readByte(NGMBoxReader *self);
35 __appendByte(NGMBoxReader *self, NSMutableData *_data, IMP _readBytes, int _c);
37 + (id)readerForMBox:(NSString *)_path {
41 fs = [NGFileStream alloc]; /* to keep gcc 3.4 happy */
42 fs = [[fs initWithPath:_path] autorelease];
43 bs = [NGBufferedStream filterWithSource:fs];
45 [fs openInMode:NGFileReadOnly];
47 return [[(NGMBoxReader *)[self alloc] initWithSource:bs] autorelease];
50 + (id)mboxWithSource:(id<NGByteSequenceStream>)_in {
51 return [[(NGMBoxReader *)[self alloc] initWithSource:_in] autorelease];
55 return [self initWithSource:nil];
58 - (id)initWithSource:(id<NGByteSequenceStream>)_in {
59 if ((self = [super init])) {
60 self->source = [_in retain];
61 self->isEndOfStream = NO;
63 self->separator = @"From -";
66 [self->source respondsToSelector:@selector(methodForSelector:)]
67 ? [(NSObject *)self->source methodForSelector:@selector(readByte)]
74 [self->source release];
75 [self->lastDate release];
76 [self->separator release];
77 self->readByte = NULL;
81 - (id<NGMimePart>)nextMessage {
84 #define AppendBytes(_buf, _cnt) \
85 appendBytes(msgData, @selector(appendBytes:length:), _buf, _cnt)
87 #define AppendByte(_c) \
88 __appendByte(self, msgData, appendBytes, _c)
91 NSMutableData *msgData = nil;
92 IMP appendBytes = NULL;
94 const int bufLen = 256;
99 int sepLength = [self->separator length];
100 const char *sepStrbuf = NULL;
102 sepStrbuf = [self->separator cString];
104 msgData = [[NSMutableData allocWithZone:[self zone]]
105 initWithCapacity:4096];
107 appendBytes = [msgData methodForSelector:@selector(appendBytes:length:)];
110 if (self->isEndOfStream)
113 if (self->lastDate == nil) {
114 // start of MBox from-line length < 255
116 while (bufCnt < sepLength) { // parse form
117 c = __readByte(self);
120 if (strncmp(buf, sepStrbuf, sepLength) != 0) {
121 NSLog(@"WARNING: no %@ at begin of MBox %s", self->separator, buf);
124 while ((c = __readByte(self)) != '\n') { // parse date < 255
126 if (bufCnt >= bufLen) {
127 NSLog(@"WARNING: too long from-line");
131 if (buf[bufCnt - 1] == '\r')
132 self->lastDate = [[NSString allocWithZone:[self zone]] initWithCString:buf
135 self->lastDate = [[NSString allocWithZone:[self zone]] initWithCString:buf
142 AppendBytes(buf, bufCnt); // write buffer to data
144 if (c != '\n') { // no end of line
146 while ((c = __readByte(self)) != '\n') {
148 if (bufCnt >= bufLen) {
149 AppendBytes(buf, bufCnt);
154 AppendBytes(buf, bufCnt);
163 while ((c = __readByte(self)) != '\n' &&
164 bufCnt < sepLength) { // read oly until seperator length
171 } while (strncmp(buf, sepStrbuf, sepLength) != 0);
174 self->isEndOfStream = YES;
176 else { // read from-line
178 while ((c = __readByte(self)) != '\n') { // from-line is not longer
179 // than 255 ( I hope it :))
181 if (bufCnt >= bufLen) {
182 NSLog(@"WARNING: too long from-line");
186 [self->lastDate release];
187 self->lastDate = [[NSString alloc] initWithCString:buf length:bufCnt];
191 if ([msgData length] == 0) // end, no msg data
195 NGMimeMessageParser *parser = nil;
196 NGDataStream *stream = nil;
201 parser = [[NGMimeMessageParser alloc] init];
202 stream = [[NGDataStream alloc] initWithData:msgData];
205 part = [parser parsePartFromStream:stream];
210 fprintf(stderr, "mbox: failed to parse message:\n%s",
211 [[NSString stringWithCString:[msgData bytes]
212 length:[msgData length]] cString]);
215 [parser release]; parser = nil;
216 [stream release]; stream = nil;
217 [msgData release]; msgData = nil;
225 - (NSString *)description {
226 return [NSString stringWithFormat:@"<%@[0x%p] source=%@ endOfStream=%@",
227 NSStringFromClass([self class]), (unsigned)self,
228 self->source, self->isEndOfStream ? @"YES" : @"NO"];
234 static inline int __readByte(NGMBoxReader *self) {
235 return (self->readByte)
236 ? (int)self->readByte(self->source, @selector(readByte))
237 : [self->source readByte];
240 static inline void __appendByte(NGMBoxReader *self, NSMutableData *_data,
241 IMP _readBytes, int _c) {
242 unsigned char c = _c;
243 _readBytes(_data, @selector(appendBytes:length:), &c, 1);