lua-users home
lua-l archive

Re: Homemade email system using LuaSocket and LuaPOP3

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On Mon, Sep 19, 2011 at 08:03:58PM +0200, Petite Abeille wrote:
> 
> On Sep 19, 2011, at 12:33 AM, Sean Conner wrote:
> 
> > I create three files per email, the body, and two for headers. 
> 
> How do you deal with multipart? Are they all bunches together in ,B?
> 
> 
That's easy to implement if you have already have a parser that gives 
a table `headers` and a string `body`, e.g. the one in stdlib which
is basically the same as the one on LuaWiki. See attachment. 
If the message is multipart, then `headers['content-type']` looks like this:
 multipart/mixed; boundary="_8b46a2bf-7207-48f7-b891-529cc7393c5c_"
That boundary, preceded "--", occurs on the lines that separate
the message into parts.
After that, it's recursive.
`lua5.1 mboxdemo.lua test.mbox` gives this output:
 This mailbox has 1 message
 message 1 has 5 parts
 part 1 has 2 parts
 1: length=965, text/plain; charset="iso-8859-1"
 2: length=2800, text/html; charset="iso-8859-1"
 2: length=551688, application/pdf
 3: length=960, text/plain
 4: length=143868, application/msword
 5: length=18325, image/pjpeg
Sorry, unlike the code, test.mbox contains copyrighted material.
For a reason that I still have to find, `lua5.2 mboxdemo.lua test.mbox`
does not work.
Dirk
local Public = {}
local strfind, strlower, gsub = string.find, string.lower, string.gsub
local strsub, tinsert = string.sub, table.insert
function Public.headers(headers_s)
 local headers = {}
 headers_s = "\n" .. headers_s .. "$$$:\n"
 local i, j = 1, 1
 local name, value, _
 while 1 do
 j = strfind(headers_s, "\n%S-:", i+1)
 if not j then break end
 _, _, name, value = strfind(strsub(headers_s, i+1, j-1), "(%S-):(.*)")
 value = gsub(value or "", "\r\n", "\n")
 value = gsub(value, "\n%s*", " ")
 name = strlower(name)
 if headers[name] then headers[name] = headers[name] .. ", " .. value
 else headers[name] = value end
 i, j = j, i
 end
 headers["$$$"] = nil
 return headers
end
function Public.body(body,cont)
 if cont==nil then return body end
 local boundary = cont:match('multipart.*boundary=(%b"")')
 if not boundary then return body end
 boundary = boundary:sub(2,-2)
 local k,l=0,0
 local b={}
 repeat 
	local l1 = l+1
	k,l=body:find(boundary,l1,true) 
 if not l then break end
	local next = Public.message(body:sub(l1,k-1))
	if next.body~="" then b[#b+1] = next end
	until false
 return b
 end
function Public.message(message_s)
 message_s = gsub(message_s, "^.-\n", "")
 local _, headers_s, body
 _, _, headers_s, body = strfind(message_s, "^(.-\n)\n(.*)")
 local headers = Public.headers(headers_s or "")
 body = Public.body(body or "",headers['content-type'])
 return { headers = headers, body = body }
end
function Public.mbox(mbox_s)
 local mbox = {}
 mbox_s = "\n" .. mbox_s .. "\nFrom "
 local i, j = 1, 1
 while 1 do
 j = strfind(mbox_s, "\nFrom ", i + 1)
 if not j then break end
 tinsert(mbox, Public.message(strsub(mbox_s, i + 1, j - 1)))
 i, j = j, i
 end
 return mbox
end
return Public
IMF = require "mboxparser"
mboxname = assert(arg[1]) 
mboxfile = assert(io.open(mboxname))
mbox = assert(IMF.mbox(mboxfile:read("*a")))
local label = function(j)
 return ({'mailbox','message','part'})[math.min(j,3)]
 end
local indent = function(j)
 local id=''
 for i=1,j do id=id..' ' end
 return id
 end
local plural = function(n) if n==1 then return "" else return "s" end end
function messageprint(message,tag,n)
 if #message>0 then
	if n then print	(("%s %i has %i %s"..plural(#message)):format(
	 label(tag),n,#message,label(tag+1)))
	else print (("This %s has %i %s"..plural(#message)):format(
	 label(tag),#message,label(tag+1))) 
	 end
	for j=1,#message do 
	 messageprint(message[j],tag,j)
	 end
	return
	end
 local body = message.body
 if type(body)=='string' then 
	 print(("%s%i: length=%i, %s"):format(
	 indent(tag-1),n,#body,message.headers['content-type'])) 
 else messageprint(body,tag+1,n) 
	end
 end 
 
messageprint(mbox,1) 

AltStyle によって変換されたページ (->オリジナル) /