On Tue, May 10, 2005 at 11:15:16PM +0200, Vladim�r Marek wrote:
> Hi,
> Sorry that this topic does not relate of LDAP but I would like to ask for
> some information about function blast() in qmail-smtpd.c (qmail - 1.03
> without any patches) file.
> I spent some hours with trying to understand how it works and some points are
> little bit unclear for me.
>
> There is a switch statement that seems really strange to me.
> Here it is:
> switch(state) {
> case 0:
> if (ch == '\n') straynewline();
> if (ch == '\r') { state = 4; continue; }
> break;
> case 1: /* \r\n */
> if (ch == '\n') straynewline();
> if (ch == '.') { state = 2; continue; }
> if (ch == '\r') { state = 4; continue; }
> state = 0;
> break;
> case 2: /* \r\n + . */
> if (ch == '\n') straynewline();
> if (ch == '\r') { state = 3; continue; }
> state = 0;
> break;
> case 3: /* \r\n + .\r */
> if (ch == '\n') return;
> put(".");
> put("\r");
> if (ch == '\r') { state = 4; continue; }
> state = 0;
> break;
> case 4: /* + \r */
> if (ch == '\n') { state = 1; break; }
> if (ch != '\r') { put("\r"); state = 0; }
> }
> I did not understand part of case 3 and 4. Specially: In case 3: why is
> it there put("."); put("\r"); if (ch == '\r') { state = 4; continue; }
> state = 0; I have a feeling that it is not possible to reach this part
> of code because of condition ch == 'n'. The ch hast to be 'n' and if
> not, something is wrong but I don't see any reason to add string ".\r"
> ... Why? Is it depend on RFC 821?
>
> In case 4: I have a feeling it is not possible that ch will be different
> from \n. If yes, again, something is wrong and I don't see any reason to
> add '\r' ... Why?
>
> Could you somebody to explain me, where I'm wrong? Or could you send me
> some link to the low level qmail documentation (if exists :-) )?
>
First of all state 0 is the default state (neither a \n nor a \r was
received lately). In state 0 there are three possible events.
1. \n -> this is an error because of a stray new line char.
2. \r -> could be a \r\n sequence, move to state 4 but do not
print anything to the mail file (qmail queues mails without \r)
3. any other char, stay in state 0 and queue the char
Now lets see state 4. In this state we know the previous char was a \r
Here we mostly expect a \n but from the rfc it is allowed to have a single
\r in the document. (I did not look at the RFC but the code does that.
Again multiple possibilities:
1. \n -> got a \r\n, move to state 1 and queue the \n
2. \r -> wow \r\r, queue a \r and stay in state 4 (as the last char read
was a \r.
3. any other char -> stray \r, queue \r and move back to state 0.
Now lets have a look at state 1. We just received a \r\n so we need to
check for a possible \r\n.\r\n sequence
1. \n -> stray newline, bomb out
2. . -> wow, this could be a \r\n.\r\n sequence move to state 2 without
queueing the char.
3. \r -> \r\n\r could be a empty line, move to state 4 without queueing
4. any other char, move to state 0
State 2:
\r\n. was previously received. Possibilities are:
1. \n -> ja ja we know stray newline
2. \r -> oh \r\n.\r now just a \n is missing to finish the mail
go to state 3 but don't queue a char.
3. any other char -> go to state 0 as usual, side-effect is that the
leading . got dropped. This is to handle \r\n..\r\n
Finnaly state 3. We know that a \r\n.\r was received so what is possible:
1. \n -> woohoo, mail finished, return
2. anything else -> damn it, somebody freaked us out. Just print the not
yet written . and \r and lets go on. In case the new char is a \r
we need to go to state 4 as usual else state 0 is were we go.
The comments in the case line, are the characters that where received
before and not queued (acctually that's not true because \n is queued but
\r and . are not).
The strange stuff is in state 2 and state 3. In state 2 the . is ignored
(. acts like an escape char here) but in state 3 . is prnted.
Honestly I do not have the time at the moment to look into the RFC to see
if this is correct or not. Mostly this whole \r handling looks strange but
I think it is needed for 8bit compliance.
--
:wq Claudio