defCStringEncoding = [NSString defaultCStringEncoding];
debugOn = [ud boolForKey:@"ImapDebugEnabled"];
+ debugDataOn = [ud boolForKey:@"ImapDebugDataEnabled"];
UseMemoryMappedData = [ud boolForKey:@"NoMemoryMappedDataForImapBlobs"]?0:1;
Imap4MMDataBoundary = [ud integerForKey:@"Imap4MMDataBoundary"];
/* got header */
result = nil;
- _consume(self, 1);
+ _consume(self, 1); // '{'
if ((sizeNum = _parseUnsigned(self)) == nil) {
NSException *e;
- (NSString *)_parseQuotedString {
/* parse a quoted string, eg '"' */
- if (_la(self, 0) != '"')
- return nil;
- _consume(self, 1);
- return _parseUntil(self, '"');
+ if (_la(self, 0) == '"') {
+ _consume(self, 1);
+ return _parseUntil(self, '"');
+ }
+ return nil;
}
- (void)_consumeOptionalSpace {
if (_la(self, 0) == ' ') _consume(self, 1);
return YES;
}
-- (id)_parseQuotedStringOrNIL {
+- (NSString *)_parseQuotedStringOrNIL {
if (_la(self, 0) == '"')
return [self _parseQuotedString];
+ if (_matchesString(self, "NIL")) {
+ _consume(self, 3);
+ return (id)null;
+ }
+ return nil;
+}
+- (id)_parseQuotedStringOrDataOrNIL {
+ if (_la(self, 0) == '"')
+ return [self _parseQuotedString];
+ if (_la(self, 0) == '{')
+ return [self _parseData];
+
if (_matchesString(self, "NIL")) {
_consume(self, 3);
return null;
/* parse subject */
- if ((tmp = [self _parseQuotedStringOrNIL]))
+ if ((tmp = [self _parseQuotedStringOrDataOrNIL])) {
+ // TODO: that one is an issue, the client does know the requested charset
+ // but doesn't pass it down to the parser? Requiring the client to
+ // deal with NSData's is a bit overkill?
env->subject = [tmp isNotNull] ? [tmp copy] : nil;
- [self _consumeOptionalSpace];
-
+ [self _consumeOptionalSpace];
+ }
+ else {
+ [self logWithFormat:@"ERROR(%s): failed on subject(%c): %@",
+ __PRETTY_FUNCTION__, _la(self, 0), self->serverResponseDebug];
+ return nil;
+ }
+ [self logWithFormat:@"XX2: %c %@", _la(self, 0), self->serverResponseDebug];
+
/* parse addresses */
- if ((tmp = [self _parseEnvelopeAddressStructures]) != nil)
+ if ((tmp = [self _parseEnvelopeAddressStructures]) != nil) {
env->from = [tmp isNotNull] ? [[tmp lastObject] copy] : nil;
- [self _consumeOptionalSpace];
- if ((tmp = [self _parseEnvelopeAddressStructures]) != nil)
+ [self _consumeOptionalSpace];
+ }
+ else {
+ [self logWithFormat:@"ERROR(%s): failed on from.", __PRETTY_FUNCTION__];
+ return nil;
+ }
+ [self logWithFormat:@"XX3: %c %@", _la(self, 0), self->serverResponseDebug];
+ if ((tmp = [self _parseEnvelopeAddressStructures]) != nil) {
env->sender = [tmp isNotNull] ? [[tmp lastObject] copy] : nil;
- [self _consumeOptionalSpace];
- if ((tmp = [self _parseEnvelopeAddressStructures]) != nil)
+ [self _consumeOptionalSpace];
+ }
+ else {
+ [self logWithFormat:@"ERROR(%s): failed on sender.", __PRETTY_FUNCTION__];
+ return nil;
+ }
+ [self logWithFormat:@"XX3: %c %@", _la(self, 0), self->serverResponseDebug];
+ if ((tmp = [self _parseEnvelopeAddressStructures]) != nil) {
env->replyTo = [tmp isNotNull] ? [[tmp lastObject] copy] : nil;
- [self _consumeOptionalSpace];
+ [self _consumeOptionalSpace];
+ }
- if ((tmp = [self _parseEnvelopeAddressStructures]) != nil)
+ if ((tmp = [self _parseEnvelopeAddressStructures]) != nil) {
env->to = [tmp isNotNull] ? [tmp copy] : nil;
- [self _consumeOptionalSpace];
- if ((tmp = [self _parseEnvelopeAddressStructures]) != nil)
+ [self _consumeOptionalSpace];
+ }
+ if ((tmp = [self _parseEnvelopeAddressStructures]) != nil) {
env->cc = [tmp isNotNull] ? [tmp copy] : nil;
- [self _consumeOptionalSpace];
- if ((tmp = [self _parseEnvelopeAddressStructures]) != nil)
+ [self _consumeOptionalSpace];
+ }
+ if ((tmp = [self _parseEnvelopeAddressStructures]) != nil) {
env->bcc = [tmp isNotNull] ? [tmp copy] : nil;
- [self _consumeOptionalSpace];
-
- if ((tmp = [self _parseQuotedStringOrNIL]))
+ [self _consumeOptionalSpace];
+ }
+
+ if ((tmp = [self _parseQuotedStringOrNIL])) {
env->inReplyTo = [tmp isNotNull] ? [tmp copy] : nil;
- [self _consumeOptionalSpace];
- if ((tmp = [self _parseQuotedStringOrNIL]))
+ [self _consumeOptionalSpace];
+ }
+ if ((tmp = [self _parseQuotedStringOrNIL])) {
env->msgId = [tmp isNotNull] ? [tmp copy] : nil;
- [self _consumeOptionalSpace];
+ [self _consumeOptionalSpace];
+ }
- if (_la(self, 0) != ')')
- [self logWithFormat:@"WARNING: IMAP4 envelope not properly closed!"];
+ if (_la(self, 0) != ')') {
+ [self logWithFormat:@"WARNING: IMAP4 envelope not properly closed"
+ @" (c0=%c,c1=%c): %@",
+ _la(self, 0), _la(self, 1), self->serverResponseDebug];
+ }
else
_consume(self, 1);
_consume(self, 6); /* "FETCH " */
_consumeIfMatch(self, '(');
while (_la(self, 0) != ')') { /* until closing parent */
- NSString *key = nil;
+ NSString *key;
key = [_parseUntil(self, ' ') lowercaseString];
+ [self logWithFormat:@"PARSE KEY: %@", key];
if ([key hasPrefix:@"body["]) {
NSDictionary *content;
static NSString *_parseUntil(NGImap4ResponseParser *self, char _c) {
/*
- _parseUntil(self, char) consume the stop char
+ Note: this function consumes the stop char (_c)!
normalize \r\n constructions
*/
// TODO: optimize!
_consume(self, 1);
cnt++;
if (cnt == 1024) {
- if (str == nil)
+ if (str == nil) {
str = (NSMutableString *)
[NSMutableString stringWithCString:buf length:1024];
+ }
else {
NSString *s;