diff options
| author | Diego Nehab <diego@tecgraf.puc-rio.br> | 2001-09-12 18:16:31 +0000 |
|---|---|---|
| committer | Diego Nehab <diego@tecgraf.puc-rio.br> | 2001-09-12 18:16:31 +0000 |
| commit | 480689a70217d2ec9bedf699166f05bb972e9448 (patch) | |
| tree | a4baebdd32ad0eeecf0f98ce4e6e97e5269612ae /src | |
| parent | 504ecdc0aaeb89dd16cfc8f058de3b03d869270e (diff) | |
| download | luasocket-480689a70217d2ec9bedf699166f05bb972e9448.tar.gz luasocket-480689a70217d2ec9bedf699166f05bb972e9448.tar.bz2 luasocket-480689a70217d2ec9bedf699166f05bb972e9448.zip | |
Updated for LuaSocket 1.4, following LTN7 etc.
Module is now automaticaly tested.
Diffstat (limited to 'src')
| -rw-r--r-- | src/smtp.lua | 303 |
1 files changed, 153 insertions, 150 deletions
diff --git a/src/smtp.lua b/src/smtp.lua index 6404e6c..7450792 100644 --- a/src/smtp.lua +++ b/src/smtp.lua | |||
| @@ -1,56 +1,91 @@ | |||
| 1 | ----------------------------------------------------------------------------- | 1 | ----------------------------------------------------------------------------- |
| 2 | -- Simple SMTP support for the Lua language using the LuaSocket toolkit. | 2 | -- SMTP support for the Lua language. |
| 3 | -- LuaSocket 1.4 toolkit | ||
| 3 | -- Author: Diego Nehab | 4 | -- Author: Diego Nehab |
| 4 | -- Date: 26/12/2000 | 5 | -- Date: 26/12/2000 |
| 5 | -- Conforming to: RFC 821 | 6 | -- Conforming to: RFC 821, LTN7 |
| 7 | -- RCS ID: $Id$ | ||
| 6 | ----------------------------------------------------------------------------- | 8 | ----------------------------------------------------------------------------- |
| 7 | 9 | ||
| 10 | local Public, Private = {}, {} | ||
| 11 | SMTP = Public | ||
| 12 | |||
| 8 | ----------------------------------------------------------------------------- | 13 | ----------------------------------------------------------------------------- |
| 9 | -- Program constants | 14 | -- Program constants |
| 10 | ----------------------------------------------------------------------------- | 15 | ----------------------------------------------------------------------------- |
| 11 | -- timeout in secconds before we give up waiting | 16 | -- timeout in secconds before we give up waiting |
| 12 | local TIMEOUT = 180 | 17 | Public.TIMEOUT = 180 |
| 13 | -- port used for connection | 18 | -- port used for connection |
| 14 | local PORT = 25 | 19 | Public.PORT = 25 |
| 15 | -- domain used in HELO command. If we are under a CGI, try to get from | 20 | -- domain used in HELO command and default sendmail |
| 16 | -- environment | 21 | -- If we are under a CGI, try to get from environment |
| 17 | local DOMAIN = getenv("SERVER_NAME") | 22 | Public.DOMAIN = getenv("SERVER_NAME") or "localhost" |
| 18 | if not DOMAIN then | 23 | -- default server used to send e-mails |
| 19 | DOMAIN = "localhost" | 24 | Public.SERVER = "localhost" |
| 20 | end | ||
| 21 | 25 | ||
| 22 | ----------------------------------------------------------------------------- | 26 | ----------------------------------------------------------------------------- |
| 23 | -- Tries to send DOS mode lines. Closes socket on error. | 27 | -- Tries to send data through socket. Closes socket on error. |
| 24 | -- Input | 28 | -- Input |
| 25 | -- sock: server socket | 29 | -- sock: server socket |
| 26 | -- line: string to be sent | 30 | -- data: string to be sent |
| 27 | -- Returns | 31 | -- Returns |
| 28 | -- err: message in case of error, nil if successfull | 32 | -- err: message in case of error, nil if successfull |
| 29 | ----------------------------------------------------------------------------- | 33 | ----------------------------------------------------------------------------- |
| 30 | local try_send = function(sock, line) | 34 | function Private.try_send(sock, data) |
| 31 | local err = sock:send(line .. "\r\n") | 35 | local err = sock:send(data) |
| 32 | if err then sock:close() end | 36 | if err then sock:close() end |
| 33 | return err | 37 | return err |
| 34 | end | 38 | end |
| 35 | 39 | ||
| 36 | ----------------------------------------------------------------------------- | 40 | ----------------------------------------------------------------------------- |
| 41 | -- Tries to get a pattern from the server and closes socket on error | ||
| 42 | -- sock: socket opened to the server | ||
| 43 | -- ...: pattern to receive | ||
| 44 | -- Returns | ||
| 45 | -- ...: received pattern | ||
| 46 | -- err: error message if any | ||
| 47 | ----------------------------------------------------------------------------- | ||
| 48 | function Private.try_receive(...) | ||
| 49 | local sock = arg[1] | ||
| 50 | local data, err = call(sock.receive, arg) | ||
| 51 | if err then sock:close() end | ||
| 52 | return data, err | ||
| 53 | end | ||
| 54 | |||
| 55 | ----------------------------------------------------------------------------- | ||
| 56 | -- Sends a command to the server (closes sock on error) | ||
| 57 | -- Input | ||
| 58 | -- sock: server socket | ||
| 59 | -- command: command to be sent | ||
| 60 | -- param: command parameters if any | ||
| 61 | -- Returns | ||
| 62 | -- err: error message if any | ||
| 63 | ----------------------------------------------------------------------------- | ||
| 64 | function Private.send_command(sock, command, param) | ||
| 65 | local line | ||
| 66 | if param then line = command .. " " .. param .. "\r\n" | ||
| 67 | else line = command .. "\r\n" end | ||
| 68 | return %Private.try_send(sock, line) | ||
| 69 | end | ||
| 70 | |||
| 71 | ----------------------------------------------------------------------------- | ||
| 37 | -- Gets command reply, (accepts multiple-line replies) | 72 | -- Gets command reply, (accepts multiple-line replies) |
| 38 | -- Input | 73 | -- Input |
| 39 | -- control: control connection socket | 74 | -- control: control openion socket |
| 40 | -- Returns | 75 | -- Returns |
| 41 | -- answer: whole server reply, nil if error | 76 | -- answer: whole server reply, nil if error |
| 42 | -- code: reply status code or error message | 77 | -- code: reply status code or error message |
| 43 | ----------------------------------------------------------------------------- | 78 | ----------------------------------------------------------------------------- |
| 44 | local get_answer = function(control) | 79 | function Private.get_answer(control) |
| 45 | local code, lastcode, sep | 80 | local code, lastcode, sep, _ |
| 46 | local line, err = control:receive() | 81 | local line, err = %Private.try_receive(control) |
| 47 | local answer = line | 82 | local answer = line |
| 48 | if err then return nil, err end | 83 | if err then return nil, err end |
| 49 | _,_, code, sep = strfind(line, "^(%d%d%d)(.)") | 84 | _,_, code, sep = strfind(line, "^(%d%d%d)(.)") |
| 50 | if not code or not sep then return nil, answer end | 85 | if not code or not sep then return nil, answer end |
| 51 | if sep == "-" then -- answer is multiline | 86 | if sep == "-" then -- answer is multiline |
| 52 | repeat | 87 | repeat |
| 53 | line, err = control:receive() | 88 | line, err = %Private.try_receive(control) |
| 54 | if err then return nil, err end | 89 | if err then return nil, err end |
| 55 | _,_, lastcode, sep = strfind(line, "^(%d%d%d)(.)") | 90 | _,_, lastcode, sep = strfind(line, "^(%d%d%d)(.)") |
| 56 | answer = answer .. "\n" .. line | 91 | answer = answer .. "\n" .. line |
| @@ -60,21 +95,18 @@ local get_answer = function(control) | |||
| 60 | end | 95 | end |
| 61 | 96 | ||
| 62 | ----------------------------------------------------------------------------- | 97 | ----------------------------------------------------------------------------- |
| 63 | -- Checks if a message reply code is correct. Closes control connection | 98 | -- Checks if a message reply code is correct. Closes control openion |
| 64 | -- if not. | 99 | -- if not. |
| 65 | -- Input | 100 | -- Input |
| 66 | -- control: control connection socket | 101 | -- control: control openion socket |
| 67 | -- success: table with successfull reply status code | 102 | -- success: table with successfull reply status code |
| 68 | -- Returns | 103 | -- Returns |
| 69 | -- code: reply code or nil in case of error | 104 | -- code: reply code or nil in case of error |
| 70 | -- answer: complete server answer or system error message | 105 | -- answer: complete server answer or system error message |
| 71 | ----------------------------------------------------------------------------- | 106 | ----------------------------------------------------------------------------- |
| 72 | local check_answer = function(control, success) | 107 | function Private.check_answer(control, success) |
| 73 | local answer, code = %get_answer(control) | 108 | local answer, code = %Private.get_answer(control) |
| 74 | if not answer then | 109 | if not answer then return nil, code end |
| 75 | control:close() | ||
| 76 | return nil, code | ||
| 77 | end | ||
| 78 | if type(success) ~= "table" then success = {success} end | 110 | if type(success) ~= "table" then success = {success} end |
| 79 | for i = 1, getn(success) do | 111 | for i = 1, getn(success) do |
| 80 | if code == success[i] then | 112 | if code == success[i] then |
| @@ -86,22 +118,6 @@ local check_answer = function(control, success) | |||
| 86 | end | 118 | end |
| 87 | 119 | ||
| 88 | ----------------------------------------------------------------------------- | 120 | ----------------------------------------------------------------------------- |
| 89 | -- Sends a command to the server (closes sock on error) | ||
| 90 | -- Input | ||
| 91 | -- sock: server socket | ||
| 92 | -- command: command to be sent | ||
| 93 | -- param: command parameters if any | ||
| 94 | -- Returns | ||
| 95 | -- err: error message if any | ||
| 96 | ----------------------------------------------------------------------------- | ||
| 97 | local send_command = function(sock, command, param) | ||
| 98 | local line | ||
| 99 | if param then line = command .. " " .. param | ||
| 100 | else line = command end | ||
| 101 | return %try_send(sock, line) | ||
| 102 | end | ||
| 103 | |||
| 104 | ----------------------------------------------------------------------------- | ||
| 105 | -- Sends initial client greeting | 121 | -- Sends initial client greeting |
| 106 | -- Input | 122 | -- Input |
| 107 | -- sock: server socket | 123 | -- sock: server socket |
| @@ -109,49 +125,24 @@ end | |||
| 109 | -- code: server code if ok, nil if error | 125 | -- code: server code if ok, nil if error |
| 110 | -- answer: complete server reply | 126 | -- answer: complete server reply |
| 111 | ----------------------------------------------------------------------------- | 127 | ----------------------------------------------------------------------------- |
| 112 | local send_helo = function(sock) | 128 | function Private.send_helo(sock) |
| 113 | local err = %send_command(sock, "HELO", %DOMAIN) | 129 | local err = %Private.send_command(sock, "HELO", %Public.DOMAIN) |
| 114 | if err then return nil, err end | 130 | if err then return nil, err end |
| 115 | return %check_answer(sock, 250) | 131 | return %Private.check_answer(sock, 250) |
| 116 | end | ||
| 117 | |||
| 118 | ----------------------------------------------------------------------------- | ||
| 119 | -- Sends mime headers | ||
| 120 | -- Input | ||
| 121 | -- sock: server socket | ||
| 122 | -- mime: table with mime headers to be sent | ||
| 123 | -- Returns | ||
| 124 | -- err: error message if any | ||
| 125 | ----------------------------------------------------------------------------- | ||
| 126 | local send_mime = function(sock, mime) | ||
| 127 | local err | ||
| 128 | mime = mime or {} | ||
| 129 | -- send all headers | ||
| 130 | for name,value in mime do | ||
| 131 | err = sock:send(name .. ": " .. value .. "\r\n") | ||
| 132 | if err then | ||
| 133 | sock:close() | ||
| 134 | return err | ||
| 135 | end | ||
| 136 | end | ||
| 137 | -- end mime part | ||
| 138 | err = sock:send("\r\n") | ||
| 139 | if err then sock:close() end | ||
| 140 | return err | ||
| 141 | end | 132 | end |
| 142 | 133 | ||
| 143 | ----------------------------------------------------------------------------- | 134 | ----------------------------------------------------------------------------- |
| 144 | -- Sends connection termination command | 135 | -- Sends openion termination command |
| 145 | -- Input | 136 | -- Input |
| 146 | -- sock: server socket | 137 | -- sock: server socket |
| 147 | -- Returns | 138 | -- Returns |
| 148 | -- code: server status code, nil if error | 139 | -- code: server status code, nil if error |
| 149 | -- answer: complete server reply or error message | 140 | -- answer: complete server reply or error message |
| 150 | ----------------------------------------------------------------------------- | 141 | ----------------------------------------------------------------------------- |
| 151 | local send_quit = function(sock) | 142 | function Private.send_quit(sock) |
| 152 | local err = %send_command(sock, "QUIT") | 143 | local err = %Private.send_command(sock, "QUIT") |
| 153 | if err then return nil, err end | 144 | if err then return nil, err end |
| 154 | local code, answer = %check_answer(sock, 221) | 145 | local code, answer = %Private.check_answer(sock, 221) |
| 155 | sock:close() | 146 | sock:close() |
| 156 | return code, answer | 147 | return code, answer |
| 157 | end | 148 | end |
| @@ -165,36 +156,55 @@ end | |||
| 165 | -- code: server status code, nil if error | 156 | -- code: server status code, nil if error |
| 166 | -- answer: complete server reply or error message | 157 | -- answer: complete server reply or error message |
| 167 | ----------------------------------------------------------------------------- | 158 | ----------------------------------------------------------------------------- |
| 168 | local send_mail = function(sock, sender) | 159 | function Private.send_mail(sock, sender) |
| 169 | local param = format("FROM:<%s>", sender) | 160 | local param = format("FROM:<%s>", sender or "") |
| 170 | local err = %send_command(sock, "MAIL", param) | 161 | local err = %Private.send_command(sock, "MAIL", param) |
| 171 | if err then return nil, err end | 162 | if err then return nil, err end |
| 172 | return %check_answer(sock, 250) | 163 | return %Private.check_answer(sock, 250) |
| 164 | end | ||
| 165 | |||
| 166 | ----------------------------------------------------------------------------- | ||
| 167 | -- Sends mime headers | ||
| 168 | -- Input | ||
| 169 | -- sock: server socket | ||
| 170 | -- headers: table with mime headers to be sent | ||
| 171 | -- Returns | ||
| 172 | -- err: error message if any | ||
| 173 | ----------------------------------------------------------------------------- | ||
| 174 | function Private.send_headers(sock, headers) | ||
| 175 | local err | ||
| 176 | -- send request headers | ||
| 177 | for i, v in headers or {} do | ||
| 178 | err = %Private.try_send(sock, i .. ": " .. v .. "\r\n") | ||
| 179 | if err then return err end | ||
| 180 | end | ||
| 181 | -- mark end of request headers | ||
| 182 | return %Private.try_send(sock, "\r\n") | ||
| 173 | end | 183 | end |
| 174 | 184 | ||
| 175 | ----------------------------------------------------------------------------- | 185 | ----------------------------------------------------------------------------- |
| 176 | -- Sends message mime headers and body | 186 | -- Sends message mime headers and body |
| 177 | -- Input | 187 | -- Input |
| 178 | -- sock: server socket | 188 | -- sock: server socket |
| 179 | -- mime: table containing all mime headers to be sent | 189 | -- headers: table containing all mime headers to be sent |
| 180 | -- body: message body | 190 | -- body: message body |
| 181 | -- Returns | 191 | -- Returns |
| 182 | -- code: server status code, nil if error | 192 | -- code: server status code, nil if error |
| 183 | -- answer: complete server reply or error message | 193 | -- answer: complete server reply or error message |
| 184 | ----------------------------------------------------------------------------- | 194 | ----------------------------------------------------------------------------- |
| 185 | local send_data = function (sock, mime, body) | 195 | function Private.send_data(sock, headers, body) |
| 186 | local err = %send_command(sock, "DATA") | 196 | local err = %Private.send_command(sock, "DATA") |
| 187 | if err then return nil, err end | 197 | if err then return nil, err end |
| 188 | local code, answer = %check_answer(sock, 354) | 198 | local code, answer = %Private.check_answer(sock, 354) |
| 189 | if not code then return nil, answer end | 199 | if not code then return nil, answer end |
| 190 | -- avoid premature end in message body | 200 | -- avoid premature end in message body |
| 191 | body = gsub(body or "", "\n%.", "\n%.%.") | 201 | body = gsub(body or "", "\n%.", "\n%.%.") |
| 192 | -- mark end of message body | 202 | -- mark end of message body |
| 193 | body = body .. "\r\n." | 203 | body = body .. "\r\n.\r\n" |
| 194 | err = %send_mime(sock, mime) | 204 | err = %Private.send_headers(sock, headers) |
| 195 | if err then return nil, err end | 205 | if err then return nil, err end |
| 196 | err = %try_send(sock, body) | 206 | err = %Private.try_send(sock, body) |
| 197 | return %check_answer(sock, 250) | 207 | return %Private.check_answer(sock, 250) |
| 198 | end | 208 | end |
| 199 | 209 | ||
| 200 | ----------------------------------------------------------------------------- | 210 | ----------------------------------------------------------------------------- |
| @@ -206,107 +216,100 @@ end | |||
| 206 | -- code: server status code, nil if error | 216 | -- code: server status code, nil if error |
| 207 | -- answer: complete server reply | 217 | -- answer: complete server reply |
| 208 | ----------------------------------------------------------------------------- | 218 | ----------------------------------------------------------------------------- |
| 209 | local send_rcpt = function(sock, rcpt) | 219 | function Private.send_rcpt(sock, rcpt) |
| 210 | local err, code, answer | 220 | local err |
| 221 | local code, answer = nil, "No recipient specified" | ||
| 211 | if type(rcpt) ~= "table" then rcpt = {rcpt} end | 222 | if type(rcpt) ~= "table" then rcpt = {rcpt} end |
| 212 | for i = 1, getn(rcpt) do | 223 | for i = 1, getn(rcpt) do |
| 213 | err = %send_command(sock, "RCPT", format("TO:<%s>", rcpt[i])) | 224 | err = %Private.send_command(sock, "RCPT", format("TO:<%s>", rcpt[i])) |
| 214 | if err then return nil, err end | 225 | if err then return nil, err end |
| 215 | code, answer = %check_answer(sock, {250, 251}) | 226 | code, answer = %Private.check_answer(sock, {250, 251}) |
| 216 | if not code then return code, answer end | 227 | if not code then return code, answer end |
| 217 | end | 228 | end |
| 218 | return code, answer | 229 | return code, answer |
| 219 | end | 230 | end |
| 220 | 231 | ||
| 221 | ----------------------------------------------------------------------------- | 232 | ----------------------------------------------------------------------------- |
| 222 | -- Connection oriented mail functions | 233 | -- Starts the connection and greets server |
| 234 | -- Input | ||
| 235 | -- parsed: parsed URL components | ||
| 236 | -- Returns | ||
| 237 | -- sock: socket connected to server | ||
| 238 | -- err: error message if any | ||
| 223 | ----------------------------------------------------------------------------- | 239 | ----------------------------------------------------------------------------- |
| 224 | function smtp_connect(server) | 240 | function Private.open(server) |
| 225 | local code, answer | 241 | local code, answer |
| 226 | -- connect to server | 242 | -- default server |
| 227 | local sock, err = connect(server, %PORT) | 243 | server = server or %Public.SERVER |
| 244 | -- connect to server and make sure we won't hang | ||
| 245 | local sock, err = connect(server, %Public.PORT) | ||
| 228 | if not sock then return nil, err end | 246 | if not sock then return nil, err end |
| 229 | sock:timeout(%TIMEOUT) | 247 | sock:timeout(%Public.TIMEOUT) |
| 230 | -- initial server greeting | 248 | -- initial server greeting |
| 231 | code, answer = %check_answer(sock, 220) | 249 | code, answer = %Private.check_answer(sock, 220) |
| 232 | if not code then return nil, answer end | 250 | if not code then return nil, answer end |
| 233 | -- HELO | 251 | -- HELO |
| 234 | code, answer = %send_helo(sock) | 252 | code, answer = %Private.send_helo(sock) |
| 235 | if not code then return nil, answer end | 253 | if not code then return nil, answer end |
| 236 | return sock | 254 | return sock |
| 237 | end | 255 | end |
| 238 | 256 | ||
| 239 | function smtp_send(sock, from, rcpt, mime, body) | 257 | ----------------------------------------------------------------------------- |
| 258 | -- Sends a message using an opened server | ||
| 259 | -- Input | ||
| 260 | -- sock: socket connected to server | ||
| 261 | -- message: a table with the following fields: | ||
| 262 | -- from: message sender's e-mail | ||
| 263 | -- rcpt: message recipient's e-mail | ||
| 264 | -- headers: message mime headers | ||
| 265 | -- body: messge body | ||
| 266 | -- Returns | ||
| 267 | -- code: server status code, nil if error | ||
| 268 | -- answer: complete server reply | ||
| 269 | ----------------------------------------------------------------------------- | ||
| 270 | function Private.send(sock, message) | ||
| 240 | local code, answer | 271 | local code, answer |
| 241 | 272 | ||
| 242 | code, answer = %send_mail(sock, from) | 273 | code, answer = %Private.send_mail(sock, message.from) |
| 243 | if not code then return nil, answer end | 274 | if not code then return nil, answer end |
| 244 | -- RCPT | 275 | -- RCPT |
| 245 | code, answer = %send_rcpt(sock, rcpt) | 276 | code, answer = %Private.send_rcpt(sock, message.rcpt) |
| 246 | if not code then return nil, answer end | 277 | if not code then return nil, answer end |
| 247 | -- DATA | 278 | -- DATA |
| 248 | return %send_data(sock, mime, body) | 279 | return %Private.send_data(sock, message.headers, message.body) |
| 249 | end | 280 | end |
| 250 | 281 | ||
| 251 | function smtp_close(sock) | 282 | ----------------------------------------------------------------------------- |
| 283 | -- Closes connection with server | ||
| 284 | -- Input | ||
| 285 | -- sock: socket connected to server | ||
| 286 | -- Returns | ||
| 287 | -- code: server status code, nil if error | ||
| 288 | -- answer: complete server reply | ||
| 289 | ----------------------------------------------------------------------------- | ||
| 290 | function Private.close(sock) | ||
| 252 | -- QUIT | 291 | -- QUIT |
| 253 | return %send_quit(sock) | 292 | return %Private.send_quit(sock) |
| 254 | end | 293 | end |
| 255 | 294 | ||
| 256 | ----------------------------------------------------------------------------- | 295 | ----------------------------------------------------------------------------- |
| 257 | -- Main mail function | 296 | -- Main mail function |
| 258 | -- Input | 297 | -- Input |
| 259 | -- from: message sender | 298 | -- message: a table with the following fields: |
| 260 | -- rcpt: table containing message recipients | 299 | -- from: message sender |
| 261 | -- mime: table containing mime headers | 300 | -- rcpt: table containing message recipients |
| 262 | -- body: message body | 301 | -- headers: table containing mime headers |
| 263 | -- server: smtp server to be used | 302 | -- body: message body |
| 303 | -- server: smtp server to be used | ||
| 264 | -- Returns | 304 | -- Returns |
| 265 | -- nil if successfull, error message in case of error | 305 | -- nil if successfull, error message in case of error |
| 266 | ----------------------------------------------------------------------------- | 306 | ----------------------------------------------------------------------------- |
| 267 | function smtp_mail(from, rcpt, mime, body, server) | 307 | function Public.mail(message) |
| 268 | local sock, err = smtp_connect(server) | 308 | local sock, err = %Private.open(message.server) |
| 269 | if not sock then return err end | 309 | if not sock then return err end |
| 270 | local code, answer = smtp_send(sock, from, rcpt, mime, body) | 310 | local code, answer = %Private.send(sock, message) |
| 271 | if not code then return answer end | 311 | if not code then return answer end |
| 272 | code, answer = smtp_close(sock) | 312 | code, answer = %Private.close(sock) |
| 273 | if code then return nil end | 313 | if code then return nil end |
| 274 | return answer | 314 | return answer |
| 275 | end | 315 | end |
| 276 | |||
| 277 | --=========================================================================== | ||
| 278 | -- Compatibility functions | ||
| 279 | --=========================================================================== | ||
| 280 | ----------------------------------------------------------------------------- | ||
| 281 | -- Converts a comma separated list into a Lua table with one entry for each | ||
| 282 | -- list element. | ||
| 283 | -- Input | ||
| 284 | -- str: string containing the list to be converted | ||
| 285 | -- tab: table to be filled with entries | ||
| 286 | -- Returns | ||
| 287 | -- a table t, where t.n is the number of elements with an entry t[i] | ||
| 288 | -- for each element | ||
| 289 | ----------------------------------------------------------------------------- | ||
| 290 | local fill = function(str, tab) | ||
| 291 | gsub(str, "([^%s,]+)", function (w) tinsert(%tab, w) end) | ||
| 292 | return tab | ||
| 293 | end | ||
| 294 | |||
| 295 | ----------------------------------------------------------------------------- | ||
| 296 | -- Client mail function, implementing CGILUA 3.2 interface | ||
| 297 | ----------------------------------------------------------------------------- | ||
| 298 | function mail(msg) | ||
| 299 | local rcpt = {} | ||
| 300 | local mime = {} | ||
| 301 | mime["Subject"] = msg.subject | ||
| 302 | mime["To"] = msg.to | ||
| 303 | mime["From"] = msg.from | ||
| 304 | %fill(msg.to, rcpt) | ||
| 305 | if msg.cc then | ||
| 306 | %fill(msg.cc, rcpt) | ||
| 307 | mime["Cc"] = msg.cc | ||
| 308 | end | ||
| 309 | if msg.bcc then %fill(msg.bcc, rcpt) end | ||
| 310 | rcpt.n = nil | ||
| 311 | return %smtp_mail(msg.from, rcpt, mime, msg.message, msg.mailserver) | ||
| 312 | end | ||
