aboutsummaryrefslogtreecommitdiff
path: root/src/tp.lua
blob: 93652552f81a00e61671334bac57bd80f5fff546 (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
-----------------------------------------------------------------------------
-- 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
local function get_reply(sock)
    local code, current, separator, _
    local line, err = sock: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 = sock:receive()
            if err then return nil, err end
            _,_, current, separator = string.find(line, "^(%d%d%d)(.)")
            if not current or not separator then 
                return nil, "invalid server reply" 
            end
            reply = reply .. "\n" .. line
        -- reply ends with same code
        until code == current and separator == " " 
    end
    return code, reply
end

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

function metatable.__index:check(ok)
    local code, reply = get_reply(self.sock)
    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 code, reply end
            end
            return nil, reply
        else
            if string.find(code, ok) then return code, reply 
            else return nil, reply end
        end
    else return ok(code, reply) end
end

function metatable.__index:command(cmd, arg)
    if arg then return self.sock:send(cmd .. " " .. arg.. "\r\n")
    else return self.sock:send(cmd .. "\r\n") end
end

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

function metatable.__index:send(data)
    return self.sock:send(data)
end

function metatable.__index:receive(pat)
    return self.sock:receive(pat)
end

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

-- closes the underlying sock
function metatable.__index:close()
    self.sock:close()
end

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