module Mimestring:Low-level functions to parse and print mail and MIME messagessig..end
Mimestring contains a lot of functions to scan and print strings
formatted as MIME messages. For a higher-level view on this topic,
see the Netmime module.
Contents
val scan_header : ?downcase:bool ->
?unfold:bool ->
?strip:bool ->
string -> start_pos:int -> end_pos:int -> (string * string) list * intlet params, header_end_pos = scan_header s start_pos end_pos:
Scans the mail header that begins at position start_pos in the string
s and that must end somewhere before position end_pos. It is intended
that in end_pos the character position following the end of the body of
the MIME message is passed.
Returns the parameters of the header as (name,value) pairs (in
params), and in header_end_pos the position of the character following
directly after the header (i.e. after the blank line separating
the header from the body).
The following normalizations have already been applied:
downcase, unfold,
and strip control which normalizations are performed (and for
historic reasons, too, this is not what you would expect - backwards
compatibility can sometimes be a burden):
downcase, do (D); if not downcase, don't do (D).unfold, do (U); if not unfold, don't do (U).unfold || strip, do (S); if not unfold && not strip,
don't do (S)downcase, unfold, not strip.unfold not only removes CR/LF from the field value,
but also removes whitespace at the beginning and at the end of the
field value. strip causes not to remove CR/LF if it occurs
somewhere within the field value, but all whitespace (including
CR/LF) at the beginning of the field value and at the end of the
field value is still deleted. Note that if you only want (S)
you have to pass ~unfold:false and ~strip:true.
The rules to postprocess mail messages in MIME format are not applied (e.g. encoding transformations as indicated by RFC 2047).
The function fails if the header violates the header format strongly. (Some minor deviations are tolerated, e.g. it is sufficient to separate lines by only LF instead of CRLF.)
The Format of Mail Messages
Messages
consist of a header and a body; the first empty line separates both
parts. The header contains lines "param-name: param-value" where
the param-name must begin on column 0 of the line, and the ":"
separates the name and the value. So the format is roughly:
param1-name: param1-value
...
paramN-name: paramN-value
_
body
(Where "_" denotes an empty line.)
This function wants in start_pos the position of the first character of
param1-name in the string, and in end_pos the position of the character
following body. It returns as header_end_pos the position where
body begins. Furthermore, in params all parameters are returned the
function finds in the header.
Details
Note that parameter values are restricted; you cannot represent arbitrary strings. The following problems can arise:
:" and the
value.Furthermore, the transformations (D), (U), and (S) can be performed resulting in values that are simpler to process.
Compatibility
This function can parse all mail headers that conform to RFC 822 or RFC 2822.
But there may be still problems, as RFC 822 allows some crazy
representations that are actually not used in practice.
In particular, RFC 822 allows it to use backslashes to "indicate"
that a CRLF sequence is semantically meant as line break. As this
function normally deletes CRLFs, it is not possible to recognize such
indicators in the result of the function.
val read_header : ?downcase:bool ->
?unfold:bool ->
?strip:bool -> Netstream.in_obj_stream -> (string * string) listin_obj_stream is the first byte of the header. The function scans the
header and returns it. After that, the stream position is after
the header and the terminating empty line (i.e. at the beginning of
the message body).
The options downcase, unfold, and strip have the same meaning
as in scan_header.
Example
To read the mail message "file.txt":
let ch = Netchannels.input_channel (open_in "file.txt") in
let stream = Netstream.input_stream ch in
let header = read_header stream in
stream#close_in() (* no need to close ch *)
val write_header : ?soft_eol:string ->
?eol:string -> Netchannels.out_obj_channel -> (string * string) list -> unitout_obj_channel. The
empty line following the header is also written.
Exact output format:
write_value below for this.)
Example:ut_stream crdsign">-> unit
method want_another_block : unit -> unit
method window : Netbuffer.t
method window_at_eof : bool
method window_length : int
end
class input_stream :
?len:int ->
?block_size:int -> Netchannels.in_obj_channel -> in_obj_stream
class sub_stream :
?len:int -> ?delimiter:string -> Netstream.in_obj_stream -> in_obj_stream
val print_in_obj_stream :
Format.formatter -> Netstream.in_obj_stream -> unit
end