Documention for: simtpop.r
Created by: iho
on: 10-Oct-2003
Format: html
Downloaded on: 26-Jul-2024

This is from an email I sent to explain the working of the smtp rule, maybe it helps
someone to understand what's going on, otherwise feel free to ask me again ...

The smtp-rule works by pretending that you can look at the data sent to an smtp
server as being one continous string, say like:

  HELO Mailserver
  MAIL FROM me@mydomain
  RCPT TO you@yourdomain
  DATA
  Here comes the actual message text,
  preceded by the header text,
  and ended by a dot (".") on a line all by itself,
  like here:
  .
  RSET
  QUIT

and after this you are done with it.

Having this static file, you could create a parse rule like this:

parse client-commands [
  "HELO" thru newline (answer)
  "MAIL" thru newline (answer)
  ...
]

Of course, in reality, you won't get a continous file, because the client waits for 
answers from the server, before it sends the new data, and a reas from the port is 
not guaranteed to get the whole data sent by the client. That's what I'm dealing 
with in the rule ...

; a sub-rule that will get the next chunk of data from the connection to
; the client, as long as the connection is open, otherwise it sets the
; word 'get-or-end to point to a rule that just goes to the end of the
; string
get-data-rule: copy [
  (either not none? conn [
    append line copy conn
  ][
    get-or-end: copy end-rule
  ])
]

; the rule to advance to the end of the string
end-rule: [thru end]

smtp-rule: [

  (
; set get-or-end to the rule to get new data from the port
    get-or-end: copy get-data-rule
; we don't yet expect any "data" (actual message text)
    data-started: false
  )
; the following block will be run through multiple times, at
; least once for every command the client issues in a normal
; communication
  some [
; save away your current position
    here:
; this block contains the rules for the several elements of the
; client server communication
; each possible command is checked, along with the data it should contain,
; e.g. the "HELO" command ends with a newline
; if the whole command has been parsed, answer appropriately, otherwise
; check the next command.
; (continued at -2-)
    [
      "HELO" thru newline
                (answer "250 SiMTPop") |
      "MAIL" thru newline
                (answer "250 Ok MAIL FROM") |
      "RCPT" [thru "<" | thru ": " ] copy name to "@" thru newline
                (answer "250 Ok RCPT TO") |
; -3-
; the "DATA" rule needs some additional tweaking, because after the
; client told us that it wants to send us the data, it waits for the
; server to be ready to receive, but as the data may potentially be
; very large, this rule may be tried multiple times, so we must
; assure, that the server response is only send once per transaction.
; please read on at -4-
      "DATA" thru newline
                (if not data-started [answer "354 start mail input"]
                 data-started: true)
           copy mail thru "^/.^/"
                (save-mail name mail
                 data-started: false
                 answer "250 OK Mail recieved") |
      "RSET" thru newline
                (answer "250 OK RSET" data-started: false) |
; -4-
; we received the QUIT command, the client has completed its transaction,
; so we set get-or-end to the rule that will end this parse run, after
; we told our "good bye" to the client, of course
; finish this at -5-
      "QUIT" thru newline
                (answer "221 Good Bye" close conn get-or-end: copy end-rule) |
; -2-
; this rule steps in, if no command has been recogniced, first (which is
; specifically true at the begin of the parse process, because no data
; has yet been read). The parse
; "pointer" is reset to the position where we started to read, then the
; get-or-end rule is used, which right now contains a rule to read the
; next chunk of data from the client, because if we weren't able to
; recognize a valid command, then the last chunk we received did not
; contain all the data (Apart from possible errors which are not really
; checked).
; If the client closed the connection, it will change get-or-end to point
; to the rule to end the current parse/transaction.
; please read on at -3-
      :here get-or-end
; -5-
; OK, so the 'get-or-end word above now pointed to the 'end-rule, so we're
; done
    ]
  ]
]

I hope this was somewhat understable ...