2004-03-16 07:42:53 +01:00
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
-- Unified SMTP/FTP subsystem
|
|
|
|
-- LuaSocket toolkit.
|
|
|
|
-- Author: Diego Nehab
|
|
|
|
-- Conforming to: RFC 2616, LTN7
|
|
|
|
-- RCS ID: $Id$
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
-- make sure LuaSocket is loaded
|
|
|
|
if not LUASOCKET_LIBNAME then error('module requires LuaSocket') end
|
|
|
|
-- get LuaSocket namespace
|
|
|
|
local socket = _G[LUASOCKET_LIBNAME]
|
|
|
|
if not socket then error('module requires LuaSocket') end
|
|
|
|
-- create namespace inside LuaSocket namespace
|
|
|
|
socket.tp = socket.tp or {}
|
|
|
|
-- make all module globals fall into namespace
|
|
|
|
setmetatable(socket.tp, { __index = _G })
|
|
|
|
setfenv(1, socket.tp)
|
|
|
|
|
|
|
|
TIMEOUT = 60
|
|
|
|
|
2004-05-25 07:27:44 +02:00
|
|
|
-- gets server reply (works for SMTP and FTP)
|
|
|
|
local function get_reply(control)
|
2004-03-16 07:42:53 +01:00
|
|
|
local code, current, separator, _
|
2004-05-25 07:27:44 +02:00
|
|
|
local line, err = control:receive()
|
2004-03-16 07:42:53 +01:00
|
|
|
local reply = line
|
2004-03-18 08:01:14 +01:00
|
|
|
if err then return nil, err end
|
2004-03-16 07:42:53 +01:00
|
|
|
_, _, code, separator = string.find(line, "^(%d%d%d)(.?)")
|
|
|
|
if not code then return nil, "invalid server reply" end
|
|
|
|
if separator == "-" then -- reply is multiline
|
|
|
|
repeat
|
2004-05-25 07:27:44 +02:00
|
|
|
line, err = control:receive()
|
2004-03-18 08:01:14 +01:00
|
|
|
if err then return nil, err end
|
2004-05-25 07:27:44 +02:00
|
|
|
_,_, current, separator = string.find(line, "^(%d%d%d)(.?)")
|
2004-03-16 07:42:53 +01:00
|
|
|
reply = reply .. "\n" .. line
|
|
|
|
-- reply ends with same code
|
|
|
|
until code == current and separator == " "
|
|
|
|
end
|
|
|
|
return code, reply
|
|
|
|
end
|
|
|
|
|
|
|
|
-- metatable for sock object
|
2004-05-25 07:27:44 +02:00
|
|
|
local metat = { __index = {} }
|
2004-03-16 07:42:53 +01:00
|
|
|
|
2004-05-25 07:27:44 +02:00
|
|
|
function metat.__index:check(ok)
|
|
|
|
local code, reply = get_reply(self.control)
|
2004-03-16 07:42:53 +01:00
|
|
|
if not code then return nil, reply end
|
|
|
|
if type(ok) ~= "function" then
|
2004-03-18 08:01:14 +01:00
|
|
|
if type(ok) == "table" then
|
|
|
|
for i, v in ipairs(ok) do
|
2004-05-25 07:27:44 +02:00
|
|
|
if string.find(code, v) then return tonumber(code), reply end
|
2004-03-18 08:01:14 +01:00
|
|
|
end
|
|
|
|
return nil, reply
|
|
|
|
else
|
2004-05-25 07:27:44 +02:00
|
|
|
if string.find(code, ok) then return tonumber(code), reply
|
2004-03-18 08:01:14 +01:00
|
|
|
else return nil, reply end
|
2004-03-16 07:42:53 +01:00
|
|
|
end
|
2004-05-25 07:27:44 +02:00
|
|
|
else return ok(tonumber(code), reply) end
|
2004-03-16 07:42:53 +01:00
|
|
|
end
|
|
|
|
|
2004-05-25 07:27:44 +02:00
|
|
|
function metat.__index:command(cmd, arg)
|
|
|
|
if arg then return self.control:send(cmd .. " " .. arg.. "\r\n")
|
|
|
|
else return self.control:send(cmd .. "\r\n") end
|
2004-03-16 07:42:53 +01:00
|
|
|
end
|
|
|
|
|
2004-05-25 07:27:44 +02:00
|
|
|
function metat.__index:sink(snk, pat)
|
|
|
|
local chunk, err = control:receive(pat)
|
2004-03-16 07:42:53 +01:00
|
|
|
return snk(chunk, err)
|
|
|
|
end
|
|
|
|
|
2004-05-25 07:27:44 +02:00
|
|
|
function metat.__index:send(data)
|
|
|
|
return self.control:send(data)
|
|
|
|
end
|
|
|
|
|
|
|
|
function metat.__index:receive(pat)
|
|
|
|
return self.control:receive(pat)
|
|
|
|
end
|
|
|
|
|
|
|
|
function metat.__index:getfd()
|
|
|
|
return self.control:getfd()
|
|
|
|
end
|
|
|
|
|
|
|
|
function metat.__index:dirty()
|
|
|
|
return self.control:dirty()
|
2004-03-18 08:01:14 +01:00
|
|
|
end
|
|
|
|
|
2004-05-25 07:27:44 +02:00
|
|
|
function metat.__index:getcontrol()
|
|
|
|
return self.control
|
2004-03-18 08:01:14 +01:00
|
|
|
end
|
|
|
|
|
2004-05-25 07:27:44 +02:00
|
|
|
function metat.__index:source(src, instr)
|
2004-03-16 07:42:53 +01:00
|
|
|
while true do
|
|
|
|
local chunk, err = src()
|
|
|
|
if not chunk then return not err, err end
|
2004-05-25 07:27:44 +02:00
|
|
|
local ret, err = self.control:send(chunk)
|
2004-03-16 07:42:53 +01:00
|
|
|
if not ret then return nil, err end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2004-05-25 07:27:44 +02:00
|
|
|
-- closes the underlying control
|
|
|
|
function metat.__index:close()
|
|
|
|
self.control:close()
|
|
|
|
return 1
|
2004-03-16 07:42:53 +01:00
|
|
|
end
|
|
|
|
|
2004-05-25 07:27:44 +02:00
|
|
|
-- connect with server and return control object
|
2004-03-16 07:42:53 +01:00
|
|
|
function connect(host, port)
|
2004-05-25 07:27:44 +02:00
|
|
|
local control, err = socket.connect(host, port)
|
|
|
|
if not control then return nil, err end
|
|
|
|
control:settimeout(TIMEOUT)
|
|
|
|
return setmetatable({control = control}, metat)
|
2004-03-16 07:42:53 +01:00
|
|
|
end
|