I've come across some problems delivering into Cyrus 2.2.2-BETA (fresh cvs) via LMTP where local-parts of recipients contain quoted-string sections as per RFC 822 when using virtual domains. Specifically, Exim's ${quote:} function turns a local part of [EMAIL PROTECTED] to "+Folder.subfolder"@domain.com - which lmtpd then rejects:
220 foobar LMTP Cyrus v2.2.2-BETA ready LHLO foobar.mxtelecom.com 250-foobar ... 250 IGNOREQUOTA MAIL FROM:<[EMAIL PROTECTED]> 250 2.1.0 ok RCPT TO:<"matthew"@mxtelecom.com> 550-Mailbox unknown. Either there is no mailbox associated with this 550-name or you do not have authorization to see it. 550 5.1.1 User unknown
Looking at the process_recipient() code in lmtpengine.c, I'm not sure that the quote-string parsing has been updated fully to reflect virtual domains - so I've fiddled around and come up with a version based on the existing code, and also a complete rewrite. I enclose the latter as a patch here; it hasn't been rigorously tested (at all), but has fixed my particular problem. If anyone has interest in the other version, just say - any feedback & flames appreciated.
cheers,
M.
______________________________________________________________ Matthew Hodgson [EMAIL PROTECTED] Tel: +44 845 6667778 Systems Analyst, MX Telecom Ltd.
Index: lmtpengine.c =================================================================== RCS file: /cvs/src/cyrus/imap/lmtpengine.c,v retrieving revision 1.96 diff -u -r1.96 lmtpengine.c --- lmtpengine.c 10 Nov 2003 16:42:14 -0000 1.96 +++ lmtpengine.c 7 Jan 2004 19:04:54 -0000 @@ -754,6 +754,7 @@ char *dest; char *user; int r, sl; + int inusername, inquoted; address_data_t *ret = (address_data_t *) xmalloc(sizeof(address_data_t)); int forcedowncase = config_getswitch(IMAPOPT_LMTP_DOWNCASE_RCPT);
@@ -781,40 +782,30 @@ addr++; } - if (*addr == '\"') { - addr++; - while (*addr && *addr != '\"') { - if (*addr == '\\') addr++; - *dest++ = *addr++; - } - } - else { - if(forcedowncase) { - /* We should downcase the localpart up to the first + */ - while(*addr != '@' && *addr != '>' && *addr != '+') { - if(*addr == '\\') addr++; - *dest++ = TOLOWER(*addr++); - } - if (*addr == '+') { - while(*addr != '@' && *addr != '>') { - if(*addr == '\\') addr++; - *dest++ = *addr++; - } - } - while ((config_virtdomains || *addr != '@') && *addr != '>') { - if(*addr == '\\') addr++; - *dest++ = TOLOWER(*addr++); - } - } else { - /* Now finish the remainder of the localpart */ - while ((config_virtdomains || *addr != '@') && *addr != '>') { - if (*addr == '\\') addr++; - *dest++ = *addr++; - } - } + inusername = 1; + inquoted = 0; + + while(*addr && (inquoted || ((config_virtdomains || *addr != '@') && *addr != '>'))) { + if (*addr == '\\' && inquoted) addr++; + + if (*addr == '\"') { + inquoted = inquoted ? 0 : 1; + addr++; + } + if (*addr == '+' && inusername) { + inusername = 0; + } + + if (forcedowncase && inusername) { + *dest++ = TOLOWER(*addr++); + } + else { + *dest++ = *addr++; + } } + *dest = '\0'; - + r = verify_user(user, ignorequota ? -1 : msg->size, msg->authstate); if (r) { /* we lost */