aboutsummaryrefslogtreecommitdiff
path: root/src/tp.lua
blob: e9e38a1107291b175ed12ae06ad0fe3a2390c8a2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
-----------------------------------------------------------------------------
-- 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

-- gets server reply (works for SMTP and FTP)
local function get_reply(control)
    local code, current, separator, _
    local line, err = control:receive()
    local reply = line
    if err then return nil, err end
    _, _, 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
            line, err = control:receive()
            if err then return nil, err end
            _,_, current, separator = string.find(line, "^(%d%d%d)(.?)")
            reply = reply .. "\n" .. line
        -- reply ends with same code
        until code == current and separator == " " 
    end
    return code, reply
end

-- metatable for sock object
local metat = { __index = {} }

function metat.__index:check(ok)
    local code, reply = get_reply(self.control)
    if not code then return nil, reply end
    if type(ok) ~= "function" then
        if type(ok) == "table" then 
            for i, v in ipairs(ok) do
                if string.find(code, v) then return tonumber(code), reply end
            end
            return nil, reply
        else
            if string.find(code, ok) then return tonumber(code), reply 
            else return nil, reply end
        end
    else return ok(tonumber(code), reply) end
end

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
end

function metat.__index:sink(snk, pat)
    local chunk, err = control:receive(pat)
    return snk(chunk, err)
end

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()
end

function metat.__index:getcontrol()
    return self.control
end

function metat.__index:source(src, instr)
    while true do
        local chunk, err = src()
        if not chunk then return not err, err end
        local ret, err = self.control:send(chunk)
        if not ret then return nil, err end
    end
end

-- closes the underlying control
function metat.__index:close()
    self.control:close()
	return 1
end

-- connect with server and return control object
function connect(host, port)
    local control, err = socket.connect(host, port)
    if not control then return nil, err end
    control:settimeout(TIMEOUT)
    return setmetatable({control = control}, metat)
end