1local _M = {}
2
3if module then
4    mbox = _M
5end
6
7function _M.split_message(message_s)
8    local message = {}
9    message_s = string.gsub(message_s, "\r\n", "\n")
10    string.gsub(message_s, "^(.-\n)\n", function (h) message.headers = h end)
11    string.gsub(message_s, "^.-\n\n(.*)", function (b) message.body = b end)
12    if not message.body then
13        string.gsub(message_s, "^\n(.*)", function (b) message.body = b end)
14    end
15    if not message.headers and not message.body then
16        message.headers = message_s
17    end
18    return message.headers or "", message.body or ""
19end
20
21function _M.split_headers(headers_s)
22    local headers = {}
23    headers_s = string.gsub(headers_s, "\r\n", "\n")
24    headers_s = string.gsub(headers_s, "\n[ ]+", " ")
25    string.gsub("\n" .. headers_s, "\n([^\n]+)", function (h) table.insert(headers, h) end)
26    return headers
27end
28
29function _M.parse_header(header_s)
30    header_s = string.gsub(header_s, "\n[ ]+", " ")
31    header_s = string.gsub(header_s, "\n+", "")
32    local _, __, name, value = string.find(header_s, "([^%s:]-):%s*(.*)")
33    return name, value
34end
35
36function _M.parse_headers(headers_s)
37    local headers_t = _M.split_headers(headers_s)
38    local headers = {}
39    for i = 1, #headers_t do
40        local name, value = _M.parse_header(headers_t[i])
41        if name then
42            name = string.lower(name)
43            if headers[name] then
44                headers[name] = headers[name] .. ", " .. value
45            else headers[name] = value end
46        end
47    end
48    return headers
49end
50
51function _M.parse_from(from)
52    local _, __, name, address = string.find(from, "^%s*(.-)%s*%<(.-)%>")
53    if not address then
54        _, __, address = string.find(from, "%s*(.+)%s*")
55    end
56    name = name or ""
57    address = address or ""
58    if name == "" then name = address end
59    name = string.gsub(name, '"', "")
60    return name, address
61end
62
63function _M.split_mbox(mbox_s)
64    local mbox = {}
65    mbox_s = string.gsub(mbox_s, "\r\n", "\n") .."\n\nFrom \n"
66    local nj, i, j = 1, 1, 1
67    while 1 do
68        i, nj = string.find(mbox_s, "\n\nFrom .-\n", j)
69        if not i then break end
70        local message = string.sub(mbox_s, j, i-1)
71        table.insert(mbox, message)
72        j = nj+1
73    end
74    return mbox
75end
76
77function _M.parse(mbox_s)
78    local mbox = _M.split_mbox(mbox_s)
79    for i = 1, #mbox do
80        mbox[i] = _M.parse_message(mbox[i])
81    end
82    return mbox
83end
84
85function _M.parse_message(message_s)
86    local message = {}
87    message.headers, message.body = _M.split_message(message_s)
88    message.headers = _M.parse_headers(message.headers)
89    return message
90end
91
92return _M
93