You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
146 lines
3.4 KiB
Lua
146 lines
3.4 KiB
Lua
-----------------------------------------------------------------------------
|
|
-- Unified SMTP/FTP subsystem
|
|
-- LuaSocket toolkit.
|
|
-- Author: Diego Nehab
|
|
-- RCS ID: $Id: tp.lua,v 1.22 2006/03/14 09:04:15 diego Exp $
|
|
-----------------------------------------------------------------------------
|
|
-- Author: duhoobo
|
|
-- ChangeLog:
|
|
-- * 2014/04/06 03:47:15 - simplified for lua-module-module
|
|
-----------------------------------------------------------------------------
|
|
|
|
|
|
local base = _G
|
|
local string = require("string")
|
|
|
|
local ltn12 = require("resty.smtp.ltn12")
|
|
local misc = require("resty.smtp.misc")
|
|
|
|
module("resty.smtp.tp")
|
|
|
|
|
|
-- gets server reply (works for SMTP and FTP)
|
|
local function get_reply(c)
|
|
local code, current, sep
|
|
local line, err = c:receive("*l")
|
|
local reply = line
|
|
|
|
if err then return nil, err end
|
|
|
|
code, sep = misc.skip(2, string.find(line, "^(%d%d%d)(.?)"))
|
|
|
|
if not code then return nil, "invalid server reply" end
|
|
if sep == "-" then -- reply is multiline
|
|
repeat
|
|
line, err = c:receive("*l")
|
|
|
|
if err then return nil, err end
|
|
|
|
current, sep = misc.skip(2, string.find(line, "^(%d%d%d)(.?)"))
|
|
reply = reply .. "\n" .. line
|
|
-- reply ends with same code
|
|
until code == current and sep == " "
|
|
end
|
|
|
|
return code, reply
|
|
end
|
|
|
|
|
|
-- metatable for sock object
|
|
local metat = {__index= {}}
|
|
|
|
|
|
function metat.__index:expect(check)
|
|
local code, reply = get_reply(self.c)
|
|
|
|
if not code then return nil, reply end
|
|
|
|
if base.type(check) ~= "function" then
|
|
if base.type(check) == "table" then
|
|
for i, v in base.ipairs(check) do
|
|
if string.find(code, v) then
|
|
return base.tonumber(code), reply
|
|
end
|
|
end
|
|
|
|
return nil, reply
|
|
|
|
else -- string
|
|
if string.find(code, check) then
|
|
return base.tonumber(code), reply
|
|
else return nil, reply end
|
|
end
|
|
|
|
else return check(base.tonumber(code), reply) end
|
|
end
|
|
|
|
|
|
function metat.__index:command(cmd, arg)
|
|
local request = cmd .. (arg and (" " .. arg) or "") .. "\r\n"
|
|
return self.c:send(request)
|
|
end
|
|
|
|
|
|
function metat.__index:sink(snk, pat)
|
|
local chunk, err = c:receive(pat)
|
|
return snk(chunk, err)
|
|
end
|
|
|
|
|
|
function metat.__index:send(data)
|
|
return self.c:send(data)
|
|
end
|
|
|
|
|
|
function metat.__index:receive(pat)
|
|
return self.c:receive(pat)
|
|
end
|
|
|
|
|
|
function metat.__index:source(source, step)
|
|
local sink = function(chunk, err)
|
|
if chunk then return self:send(chunk)
|
|
else return 1 end
|
|
end
|
|
|
|
return ltn12.pump.all(source, sink, step or ltn12.pump.step)
|
|
end
|
|
|
|
|
|
-- closes the underlying c
|
|
function metat.__index:close()
|
|
self.c:close()
|
|
return 1
|
|
end
|
|
|
|
|
|
-- connect with server and return c object
|
|
function connect(host, port, timeout, create, ssl)
|
|
local c, e = create()
|
|
if not c then return nil, e end
|
|
|
|
c:settimeout(timeout)
|
|
|
|
local r, e = c:connect(host, port)
|
|
if not r then
|
|
c:close()
|
|
return nil, e
|
|
end
|
|
|
|
if ssl.enable then
|
|
if not c.sslhandshake then
|
|
c:close()
|
|
return nil, "socket does not have ssl support"
|
|
end
|
|
|
|
local s, e = c:sslhandshake(nil, host, ssl.verify_cert)
|
|
if not s then
|
|
c:close()
|
|
return nil, "ssl handshake: " .. e
|
|
end
|
|
end
|
|
|
|
return base.setmetatable({c= c}, metat)
|
|
end
|
|
|