mirror of
				https://github.com/lunarmodules/luasocket.git
				synced 2025-10-31 02:15:38 +01:00 
			
		
		
		
	Seems to be working.
This commit is contained in:
		| @@ -16,7 +16,7 @@ local function second(a, b) | |||||||
|     return b |     return b | ||||||
| end | end | ||||||
|  |  | ||||||
| local function skip(a, b, c) | local function shift(a, b, c) | ||||||
|     return b, c |     return b, c | ||||||
| end | end | ||||||
|  |  | ||||||
| @@ -69,7 +69,7 @@ function source.file(handle, io_err) | |||||||
|             if not chunk then handle:close() end |             if not chunk then handle:close() end | ||||||
|             return chunk |             return chunk | ||||||
|         end |         end | ||||||
|     else source.error(io_err or "unable to open file") end |     else return source.error(io_err or "unable to open file") end | ||||||
| end | end | ||||||
|  |  | ||||||
| -- turns a fancy source into a simple source | -- turns a fancy source into a simple source | ||||||
| @@ -114,6 +114,7 @@ function source.chain(src, f) | |||||||
|     local co = coroutine.create(function() |     local co = coroutine.create(function() | ||||||
|         while true do  |         while true do  | ||||||
|             local chunk, err = src() |             local chunk, err = src() | ||||||
|  |             if err then return nil, err end | ||||||
|             local filtered = f(chunk) |             local filtered = f(chunk) | ||||||
|             local done = chunk and "" |             local done = chunk and "" | ||||||
|             while true do |             while true do | ||||||
| @@ -121,11 +122,10 @@ function source.chain(src, f) | |||||||
|                 if filtered == done then break end |                 if filtered == done then break end | ||||||
|                 filtered = f(done) |                 filtered = f(done) | ||||||
|             end |             end | ||||||
|             if not chunk then return nil, err end |  | ||||||
|         end |         end | ||||||
|     end) |     end) | ||||||
|     return function() |     return function() | ||||||
|         return skip(coroutine.resume(co)) |         return shift(coroutine.resume(co)) | ||||||
|     end |     end | ||||||
| end | end | ||||||
|  |  | ||||||
| @@ -141,7 +141,7 @@ function source.cat(...) | |||||||
|         end |         end | ||||||
|     end) |     end) | ||||||
|     return source.simplify(function() |     return source.simplify(function() | ||||||
|         return second(coroutine.resume(co)) |         return shift(coroutine.resume(co)) | ||||||
|     end) |     end) | ||||||
| end | end | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										28
									
								
								src/mime.lua
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								src/mime.lua
									
									
									
									
									
								
							| @@ -6,9 +6,9 @@ setmetatable(mime, { __index = _G }) | |||||||
| setfenv(1, mime) | setfenv(1, mime) | ||||||
|  |  | ||||||
| -- encode, decode and wrap algorithm tables | -- encode, decode and wrap algorithm tables | ||||||
| local et = {} | encodet = {} | ||||||
| local dt = {} | decodet = {} | ||||||
| local wt = {} | wrapt = {} | ||||||
|  |  | ||||||
| -- creates a function that chooses a filter by name from a given table  | -- creates a function that chooses a filter by name from a given table  | ||||||
| local function choose(table) | local function choose(table) | ||||||
| @@ -20,40 +20,40 @@ local function choose(table) | |||||||
| end | end | ||||||
|  |  | ||||||
| -- define the encoding filters | -- define the encoding filters | ||||||
| et['base64'] = function() | encodet['base64'] = function() | ||||||
|     return ltn12.filter.cycle(b64, "") |     return ltn12.filter.cycle(b64, "") | ||||||
| end | end | ||||||
|  |  | ||||||
| et['quoted-printable'] = function(mode) | encodet['quoted-printable'] = function(mode) | ||||||
|     return ltn12.filter.cycle(qp, "",  |     return ltn12.filter.cycle(qp, "",  | ||||||
|         (mode == "binary") and "=0D=0A" or "\13\10") |         (mode == "binary") and "=0D=0A" or "\13\10") | ||||||
| end | end | ||||||
|  |  | ||||||
| -- define the decoding filters | -- define the decoding filters | ||||||
| dt['base64'] = function() | decodet['base64'] = function() | ||||||
|     return ltn12.filter.cycle(unb64, "") |     return ltn12.filter.cycle(unb64, "") | ||||||
| end | end | ||||||
|  |  | ||||||
| dt['quoted-printable'] = function() | decodet['quoted-printable'] = function() | ||||||
|     return ltn12.filter.cycle(unqp, "") |     return ltn12.filter.cycle(unqp, "") | ||||||
| end | end | ||||||
|  |  | ||||||
| -- define the line-wrap filters | -- define the line-wrap filters | ||||||
| wt['text'] = function(length) | wrapt['text'] = function(length) | ||||||
|     length = length or 76 |     length = length or 76 | ||||||
|     return ltn12.filter.cycle(wrp, length, length)  |     return ltn12.filter.cycle(wrp, length, length)  | ||||||
| end | end | ||||||
| wt['base64'] = wt['text'] | wrapt['base64'] = wrapt['text'] | ||||||
|  |  | ||||||
| wt['quoted-printable'] = function() | wrapt['quoted-printable'] = function() | ||||||
|     return ltn12.filter.cycle(qpwrp, 76, 76)  |     return ltn12.filter.cycle(qpwrp, 76, 76)  | ||||||
| end | end | ||||||
|  |  | ||||||
| -- function that choose the encoding, decoding or wrap algorithm | -- function that choose the encoding, decoding or wrap algorithm | ||||||
| encode = choose(et)  | encode = choose(encodet)  | ||||||
| decode = choose(dt) | decode = choose(decodet) | ||||||
| -- there is different because there is a default wrap filter | -- it's different because there is a default wrap filter | ||||||
| local cwt = choose(wt) | local cwt = choose(wrapt) | ||||||
| function wrap(mode_or_length, length) | function wrap(mode_or_length, length) | ||||||
|     if type(mode_or_length) ~= "string" then |     if type(mode_or_length) ~= "string" then | ||||||
|         length = mode_or_length |         length = mode_or_length | ||||||
|   | |||||||
							
								
								
									
										96
									
								
								src/smtp.lua
									
									
									
									
									
								
							
							
						
						
									
										96
									
								
								src/smtp.lua
									
									
									
									
									
								
							| @@ -10,23 +10,27 @@ socket.smtp = smtp | |||||||
| setmetatable(smtp, { __index = _G }) | setmetatable(smtp, { __index = _G }) | ||||||
| setfenv(1, smtp) | setfenv(1, smtp) | ||||||
|  |  | ||||||
|  | -- default server used to send e-mails | ||||||
|  | SERVER = "localhost" | ||||||
| -- default port | -- default port | ||||||
| PORT = 25  | PORT = 25  | ||||||
| -- domain used in HELO command and default sendmail  | -- domain used in HELO command and default sendmail  | ||||||
| -- If we are under a CGI, try to get from environment | -- If we are under a CGI, try to get from environment | ||||||
| DOMAIN = os.getenv("SERVER_NAME") or "localhost" | DOMAIN = os.getenv("SERVER_NAME") or "localhost" | ||||||
| -- default server used to send e-mails | -- default time zone (means we don't know) | ||||||
| SERVER = "localhost" | ZONE = "-0000" | ||||||
|  |  | ||||||
| function stuff() | function stuff() | ||||||
|     return ltn12.filter.cycle(dot, 2) |     return ltn12.filter.cycle(dot, 2) | ||||||
| end | end | ||||||
|  |  | ||||||
| local function skip(a, b, c) | local function shift(a, b, c) | ||||||
|     return b, c |     return b, c | ||||||
| end | end | ||||||
|  |  | ||||||
|  | -- send message or throw an exception | ||||||
| function psend(control, mailt)  | function psend(control, mailt)  | ||||||
|  |     socket.try(control:check("2..")) | ||||||
|     socket.try(control:command("EHLO", mailt.domain or DOMAIN)) |     socket.try(control:command("EHLO", mailt.domain or DOMAIN)) | ||||||
|     socket.try(control:check("2..")) |     socket.try(control:check("2..")) | ||||||
|     socket.try(control:command("MAIL", "FROM:" .. mailt.from)) |     socket.try(control:command("MAIL", "FROM:" .. mailt.from)) | ||||||
| @@ -34,11 +38,12 @@ function psend(control, mailt) | |||||||
|     if type(mailt.rcpt) == "table" then |     if type(mailt.rcpt) == "table" then | ||||||
|         for i,v in ipairs(mailt.rcpt) do |         for i,v in ipairs(mailt.rcpt) do | ||||||
|             socket.try(control:command("RCPT", "TO:" .. v)) |             socket.try(control:command("RCPT", "TO:" .. v)) | ||||||
|  |             socket.try(control:check("2..")) | ||||||
|         end |         end | ||||||
|     else |     else | ||||||
|         socket.try(control:command("RCPT", "TO:" .. mailt.rcpt)) |         socket.try(control:command("RCPT", "TO:" .. mailt.rcpt)) | ||||||
|     end |  | ||||||
|         socket.try(control:check("2..")) |         socket.try(control:check("2..")) | ||||||
|  |     end | ||||||
|     socket.try(control:command("DATA")) |     socket.try(control:command("DATA")) | ||||||
|     socket.try(control:check("3..")) |     socket.try(control:check("3..")) | ||||||
|     socket.try(control:source(ltn12.source.chain(mailt.source, stuff()))) |     socket.try(control:source(ltn12.source.chain(mailt.source, stuff()))) | ||||||
| @@ -48,6 +53,7 @@ function psend(control, mailt) | |||||||
|     socket.try(control:check("2..")) |     socket.try(control:check("2..")) | ||||||
| end | end | ||||||
|  |  | ||||||
|  | -- returns a hopefully unique mime boundary | ||||||
| local seqno = 0 | local seqno = 0 | ||||||
| local function newboundary() | local function newboundary() | ||||||
|     seqno = seqno + 1 |     seqno = seqno + 1 | ||||||
| @@ -55,18 +61,13 @@ local function newboundary() | |||||||
|         math.random(0, 99999), seqno) |         math.random(0, 99999), seqno) | ||||||
| end | end | ||||||
|  |  | ||||||
| local function sendmessage(mesgt) | -- sendmessage forward declaration | ||||||
|     -- send headers | local sendmessage | ||||||
|     if mesgt.headers then |  | ||||||
|         for i,v in pairs(mesgt.headers) do | -- yield multipart message body from a multipart message table | ||||||
|             coroutine.yield(i .. ':' .. v .. "\r\n") | local function sendmultipart(mesgt) | ||||||
|         end |  | ||||||
|     end |  | ||||||
|     -- deal with multipart |  | ||||||
|     if type(mesgt.body) == "table" then |  | ||||||
|     local bd = newboundary() |     local bd = newboundary() | ||||||
|     -- define boundary and finish headers |     -- define boundary and finish headers | ||||||
|         coroutine.yield('mime-version: 1.0\r\n')  |  | ||||||
|     coroutine.yield('content-type: multipart/mixed; boundary="' ..  |     coroutine.yield('content-type: multipart/mixed; boundary="' ..  | ||||||
|         bd .. '"\r\n\r\n') |         bd .. '"\r\n\r\n') | ||||||
|     -- send preamble |     -- send preamble | ||||||
| @@ -80,37 +81,78 @@ local function sendmessage(mesgt) | |||||||
|     coroutine.yield("\r\n--" .. bd .. "--\r\n\r\n") |     coroutine.yield("\r\n--" .. bd .. "--\r\n\r\n") | ||||||
|     -- send epilogue |     -- send epilogue | ||||||
|     if mesgt.body.epilogue then coroutine.yield(mesgt.body.epilogue) end |     if mesgt.body.epilogue then coroutine.yield(mesgt.body.epilogue) end | ||||||
|     -- deal with a source  | end | ||||||
|     elseif type(mesgt.body) == "function" then |  | ||||||
|  | -- yield message body from a source | ||||||
|  | local function sendsource(mesgt) | ||||||
|  |     -- set content-type if user didn't override | ||||||
|  |     if not mesgt.headers or not mesgt.headers["content-type"] then | ||||||
|  |         coroutine.yield('content-type: text/plain; charset="iso-88591"\r\n') | ||||||
|  |     end | ||||||
|     -- finish headers |     -- finish headers | ||||||
|     coroutine.yield("\r\n") |     coroutine.yield("\r\n") | ||||||
|  |     -- send body from source | ||||||
|     while true do  |     while true do  | ||||||
|         local chunk, err = mesgt.body() |         local chunk, err = mesgt.body() | ||||||
|             if err then return nil, err |         if err then coroutine.yield(nil, err) | ||||||
|         elseif chunk then coroutine.yield(chunk) |         elseif chunk then coroutine.yield(chunk) | ||||||
|         else break end |         else break end | ||||||
|     end |     end | ||||||
|     -- deal with a simple string | end | ||||||
|     else |  | ||||||
|  | -- yield message body from a string | ||||||
|  | local function sendstring(mesgt) | ||||||
|  |     -- set content-type if user didn't override | ||||||
|  |     if not mesgt.headers or not mesgt.headers["content-type"] then | ||||||
|  |         coroutine.yield('content-type: text/plain; charset="iso-88591"\r\n') | ||||||
|  |     end | ||||||
|     -- finish headers |     -- finish headers | ||||||
|     coroutine.yield("\r\n") |     coroutine.yield("\r\n") | ||||||
|  |     -- send body from string | ||||||
|     coroutine.yield(mesgt.body) |     coroutine.yield(mesgt.body) | ||||||
|  |  | ||||||
| end | end | ||||||
|  |  | ||||||
|  | -- yield the headers one by one | ||||||
|  | local function sendheaders(mesgt) | ||||||
|  |     if mesgt.headers then | ||||||
|  |         for i,v in pairs(mesgt.headers) do | ||||||
|  |             coroutine.yield(i .. ':' .. v .. "\r\n") | ||||||
|  |         end | ||||||
|  |     end | ||||||
|  | end | ||||||
|  |  | ||||||
|  | -- message source | ||||||
|  | function sendmessage(mesgt) | ||||||
|  |     sendheaders(mesgt) | ||||||
|  |     if type(mesgt.body) == "table" then sendmultipart(mesgt) | ||||||
|  |     elseif type(mesgt.body) == "function" then sendsource(mesgt) | ||||||
|  |     else sendstring(mesgt) end | ||||||
|  | end | ||||||
|  |  | ||||||
|  | -- set defaul headers | ||||||
|  | local function adjustheaders(mesgt) | ||||||
|  |     mesgt.headers = mesgt.headers or {} | ||||||
|  |     mesgt.headers["mime-version"] = "1.0"  | ||||||
|  |     mesgt.headers["date"] = mesgt.headers["date"] or  | ||||||
|  |         os.date("%a, %d %b %Y %H:%M:%S") .. (mesgt.zone or ZONE) | ||||||
|  |     mesgt.headers["x-mailer"] = mesgt.headers["x-mailer"] or socket.version | ||||||
| end | end | ||||||
|  |  | ||||||
| function message(mesgt) | function message(mesgt) | ||||||
|  |     adjustheaders(mesgt) | ||||||
|  |     -- create and return message source | ||||||
|     local co = coroutine.create(function() sendmessage(mesgt) end) |     local co = coroutine.create(function() sendmessage(mesgt) end) | ||||||
|     return function() return skip(coroutine.resume(co)) end |     return function() return shift(coroutine.resume(co)) end | ||||||
| end | end | ||||||
|  |  | ||||||
| function send(mailt) | function send(mailt) | ||||||
|     local control, err = socket.tp.connect(mailt.server or SERVER,  |     local c, e = socket.tp.connect(mailt.server or SERVER, mailt.port or PORT) | ||||||
|         mailt.port or PORT) |     if not c then return nil, e end | ||||||
|     if not control then return nil, err end |     local s, e = pcall(psend, c, mailt) | ||||||
|     local status, err = pcall(psend, control, mailt) |     c:close() | ||||||
|     control:close() |     if s then return true | ||||||
|     if status then return true |     else return nil, e end | ||||||
|     else return nil, err end |  | ||||||
| end | end | ||||||
|  |  | ||||||
| return smtp | return smtp | ||||||
|   | |||||||
| @@ -82,7 +82,7 @@ function metatable.__index:source(src, instr) | |||||||
|     while true do |     while true do | ||||||
|         local chunk, err = src() |         local chunk, err = src() | ||||||
|         if not chunk then return not err, err end |         if not chunk then return not err, err end | ||||||
|         local ret, err = try_sending(self.sock, chunk) |         local ret, err = self.sock:send(chunk) | ||||||
|         if not ret then return nil, err end |         if not ret then return nil, err end | ||||||
|     end |     end | ||||||
| end | end | ||||||
| @@ -95,7 +95,7 @@ end | |||||||
| -- connect with server and return sock object | -- connect with server and return sock object | ||||||
| function connect(host, port) | function connect(host, port) | ||||||
|     local sock, err = socket.connect(host, port) |     local sock, err = socket.connect(host, port) | ||||||
|     if not sock then return nil, message end |     if not sock then return nil, err end | ||||||
|     sock:settimeout(TIMEOUT) |     sock:settimeout(TIMEOUT) | ||||||
|     return setmetatable({sock = sock}, metatable) |     return setmetatable({sock = sock}, metatable) | ||||||
| end | end | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user