tp.lua 3.7 KB

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