On Tue, May 25, 2004 at 07:54:51PM +0200, Matthias Andree wrote:
Each module supports a few simple primitives:
- OPEN (connect to server, authenticate if required/requested)
- LIST (list all messages within mailbox, returning UID for each)
- FETCH (fetch a given message, and its envelope if available)
- DELETE
- PUT (store a message)
- CLOSE
This lacks the important primitives:
CAPABILITY (query capabilities of module)
BEGIN (might be implied by OPEN)
COMMIT (sometimes includes CLOSE, POP3, see below)
ABORT (or ROLLBACK)
We need whatever primitives the core module needs to do its job properly.
I think few if any mail protocols have useful COMMIT/ABORT semantics though.
SMTP, once you've done DATA and the final dot, is always commit. POP3 lets
you RSET, but the only thing that resets is the DELE state (although that's
the only thing you can actually change via POP3). I don't think IMAP has any
kind of rollback.
If it were me writing the core, I'd sequence the operations appropriately:
- FETCH message from A
- PUT message to B
- once B has confirmed successful PUT, then issue DELE to A
I think any CAPA/CAPABILITY/EHLO tests can be hidden behind the module API.
If a module doesn't support FETCH then it returns an empty list to LIST; it
appears that the mailbox is always empty. If it doesn't support PUT then
perhaps there's a flag needed, but otherwise, an attempt to write a message
via POP3 (say) will just fail.
And it lacks extensibility. We may not fancy any use for that now, but
we must be able to extend such an architecture.
Well, new primitives can be added if they're needed, and you could have a
flag to say whether primitive X is supported. If that's what you mean by
CAPABILITY then fine.
A mail transport takes place in transactions. How fine we cut this,
i. e. how large is one transaction, is a separate question, and as an
example, let's look at POP3:
primitive implementation
OPEN <-> USER-PASS sequence or AUTH
LIST <-> LIST
FETCH <-> RETR
DELETE <-> DELE
PUT not supported, yields error
ABORT <-> RSET (or drop connection)
COMMIT+CLOSE <-> QUIT
Exactly, although OPEN might also include STLS. For SMTP:
OPEN <-> EHLO/HELO [STARTTLS] [AUTH]
LIST <-> empty list
FETCH <-> not supported and won't be called anyway
DELETE <-> ditto
PUT <-> MAIL FROM, RCPT TO, DATA
ABORT <-> nope, too late!
COMMIT <-> null operation
CLOSE <-> QUIT
I guess if you are streaming from A to B, then abort can be 'drop
connection'. That means if a FETCH operation aborts, the corresponding PUT
can be aborted too. But I'd be inclined to spool to disk anyway.
Consider for example that it might be useful to have multiple sources and/or
multiple sinks.
copynew:
from pop3 (host=serverA user=foo pass=bar)
to smtp (host=127.0.0.1)
to smtp (host=serverB user=baz pass=baz)
Then each message detected as 'new' on serverA could be delivered to two
places. It's probably easier to fetch the whole message then deliver twice,
than to try and stream to two places simultaneously.
Cheers,
Brian.