beta-0.89.2
[luatex.git] / source / texk / web2c / luatexdir / luasocket / src / tp.lua
blob2ffe9a45818dc66555ca5f023dcde054e83cd6fe
1 -----------------------------------------------------------------------------
2 -- Unified SMTP/FTP subsystem
3 -- LuaSocket toolkit.
4 -- Author: Diego Nehab
5 -----------------------------------------------------------------------------
7 -----------------------------------------------------------------------------
8 -- Declare module and import dependencies
9 -----------------------------------------------------------------------------
10 local base = _G
11 local string = require("string")
12 local socket = require("socket")
13 local ltn12 = require("ltn12")
14 module("socket.tp")
16 -----------------------------------------------------------------------------
17 -- Program constants
18 -----------------------------------------------------------------------------
19 TIMEOUT = 60
21 -----------------------------------------------------------------------------
22 -- Implementation
23 -----------------------------------------------------------------------------
24 -- gets server reply (works for SMTP and FTP)
25 local function get_reply(c)
26 local code, current, sep
27 local line, err = c:receive()
28 local reply = line
29 if err then return nil, err end
30 code, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)"))
31 if not code then return nil, "invalid server reply" end
32 if sep == "-" then -- reply is multiline
33 repeat
34 line, err = c:receive()
35 if err then return nil, err end
36 current, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)"))
37 reply = reply .. "\n" .. line
38 -- reply ends with same code
39 until code == current and sep == " "
40 end
41 return code, reply
42 end
44 -- metatable for sock object
45 local metat = { __index = {} }
47 function metat.__index:check(ok)
48 local code, reply = get_reply(self.c)
49 if not code then return nil, reply end
50 if base.type(ok) ~= "function" then
51 if base.type(ok) == "table" then
52 for i, v in base.ipairs(ok) do
53 if string.find(code, v) then
54 return base.tonumber(code), reply
55 end
56 end
57 return nil, reply
58 else
59 if string.find(code, ok) then return base.tonumber(code), reply
60 else return nil, reply end
61 end
62 else return ok(base.tonumber(code), reply) end
63 end
65 function metat.__index:command(cmd, arg)
66 cmd = string.upper(cmd)
67 if arg then
68 return self.c:send(cmd .. " " .. arg.. "\r\n")
69 else
70 return self.c:send(cmd .. "\r\n")
71 end
72 end
74 function metat.__index:sink(snk, pat)
75 local chunk, err = c:receive(pat)
76 return snk(chunk, err)
77 end
79 function metat.__index:send(data)
80 return self.c:send(data)
81 end
83 function metat.__index:receive(pat)
84 return self.c:receive(pat)
85 end
87 function metat.__index:getfd()
88 return self.c:getfd()
89 end
91 function metat.__index:dirty()
92 return self.c:dirty()
93 end
95 function metat.__index:getcontrol()
96 return self.c
97 end
99 function metat.__index:source(source, step)
100 local sink = socket.sink("keep-open", self.c)
101 local ret, err = ltn12.pump.all(source, sink, step or ltn12.pump.step)
102 return ret, err
105 -- closes the underlying c
106 function metat.__index:close()
107 self.c:close()
108 return 1
111 -- connect with server and return c object
112 function connect(host, port, timeout, create)
113 local c, e = (create or socket.tcp)()
114 if not c then return nil, e end
115 c:settimeout(timeout or TIMEOUT)
116 local r, e = c:connect(host, port)
117 if not r then
118 c:close()
119 return nil, e
121 return base.setmetatable({c = c}, metat)