1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

net: use mut and refs as receivers consistently (#8205)

This commit is contained in:
Delyan Angelov
2021-01-20 12:11:01 +02:00
committed by GitHub
parent 158aefc37f
commit d92f5c55ba
15 changed files with 236 additions and 206 deletions

View File

@ -12,14 +12,14 @@ import time
import io
const (
recv_size = 128
recv_size = 128
)
enum ReplyCode {
ready = 220
close = 221
auth_ok = 235
action_ok = 250
ready = 220
close = 221
auth_ok = 235
action_ok = 250
mail_start = 354
}
@ -39,7 +39,7 @@ pub:
password string
from string
pub mut:
is_open bool
is_open bool
}
pub struct Mail {
@ -54,15 +54,19 @@ pub struct Mail {
}
// new_client returns a new SMTP client and connects to it
pub fn new_client(config Client) ?Client {
mut c := config
c.reconnect()?
pub fn new_client(config Client) ?&Client {
mut c := &Client{
...config
}
c.reconnect() ?
return c
}
// reconnect reconnects to the SMTP server if the connection was closed
pub fn (mut c Client) reconnect() ? {
if c.is_open { return error('Already connected to server') }
if c.is_open {
return error('Already connected to server')
}
conn := net.dial_tcp('$c.server:$c.port') or { return error('Connecting to server failed') }
c.conn = conn
@ -76,29 +80,34 @@ pub fn (mut c Client) reconnect() ? {
}
// send sends an email
pub fn (c Client) send(config Mail) ? {
if !c.is_open { return error('Disconnected from server') }
pub fn (mut c Client) send(config Mail) ? {
if !c.is_open {
return error('Disconnected from server')
}
from := if config.from != '' { config.from } else { c.from }
c.send_mailfrom(from) or { return error('Sending mailfrom failed') }
c.send_mailto(config.to) or { return error('Sending mailto failed') }
c.send_data() or { return error('Sending mail data failed') }
c.send_body({ config | from: from }) or { return error('Sending mail body failed') }
c.send_body({
config |
from: from
}) or { return error('Sending mail body failed') }
}
// quit closes the connection to the server
pub fn (mut c Client) quit() ? {
c.send_str('QUIT\r\n')
c.expect_reply(.close)
c.conn.close()?
c.conn.close() ?
c.is_open = false
}
// expect_reply checks if the SMTP server replied with the expected reply code
fn (c Client) expect_reply(expected ReplyCode) ? {
bytes := io.read_all(reader: c.conn)?
fn (mut c Client) expect_reply(expected ReplyCode) ? {
bytes := io.read_all(reader: c.conn) ?
str := bytes.bytestr().trim_space()
$if smtp_debug? {
$if smtp_debug ? {
eprintln('\n\n[RECV]')
eprint(str)
}
@ -108,30 +117,32 @@ fn (c Client) expect_reply(expected ReplyCode) ? {
if ReplyCode(status) != expected {
return error('Received unexpected status code $status, expecting $expected')
}
} else { return error('Recieved unexpected SMTP data: $str') }
} else {
return error('Recieved unexpected SMTP data: $str')
}
}
[inline]
fn (c Client) send_str(s string) ? {
$if smtp_debug? {
fn (mut c Client) send_str(s string) ? {
$if smtp_debug ? {
eprintln('\n\n[SEND START]')
eprint(s.trim_space())
eprintln('\n[SEND END]')
}
c.conn.write(s.bytes())?
c.conn.write(s.bytes()) ?
}
[inline]
fn (c Client) send_ehlo() ? {
c.send_str('EHLO $c.server\r\n')?
c.expect_reply(.action_ok)?
fn (mut c Client) send_ehlo() ? {
c.send_str('EHLO $c.server\r\n') ?
c.expect_reply(.action_ok) ?
}
[inline]
fn (c Client) send_auth() ? {
fn (mut c Client) send_auth() ? {
if c.username.len == 0 {
return
}
}
mut sb := strings.new_builder(100)
sb.write_b(0)
sb.write(c.username)
@ -139,26 +150,26 @@ fn (c Client) send_auth() ? {
sb.write(c.password)
a := sb.str()
auth := 'AUTH PLAIN ${base64.encode(a)}\r\n'
c.send_str(auth)?
c.expect_reply(.auth_ok)?
c.send_str(auth) ?
c.expect_reply(.auth_ok) ?
}
fn (c Client) send_mailfrom(from string) ? {
c.send_str('MAIL FROM: <$from>\r\n')?
c.expect_reply(.action_ok)?
fn (mut c Client) send_mailfrom(from string) ? {
c.send_str('MAIL FROM: <$from>\r\n') ?
c.expect_reply(.action_ok) ?
}
fn (c Client) send_mailto(to string) ? {
c.send_str('RCPT TO: <$to>\r\n')?
c.expect_reply(.action_ok)?
fn (mut c Client) send_mailto(to string) ? {
c.send_str('RCPT TO: <$to>\r\n') ?
c.expect_reply(.action_ok) ?
}
fn (c Client) send_data() ? {
c.send_str('DATA\r\n')?
fn (mut c Client) send_data() ? {
c.send_str('DATA\r\n') ?
c.expect_reply(.mail_start)
}
fn (c Client) send_body(cfg Mail) ? {
fn (mut c Client) send_body(cfg Mail) ? {
is_html := cfg.body_type == .html
date := cfg.date.utc_string().trim_right(' UTC') // TODO
mut sb := strings.new_builder(200)
@ -174,6 +185,6 @@ fn (c Client) send_body(cfg Mail) ? {
sb.write('\r\n\r\n')
sb.write(cfg.body)
sb.write('\r\n.\r\n')
c.send_str(sb.str())?
c.expect_reply(.action_ok)?
c.send_str(sb.str()) ?
c.expect_reply(.action_ok) ?
}

View File

@ -3,7 +3,7 @@ import smtp
import time
// Used to test that a function call returns an error
fn fn_errors(c smtp.Client, m smtp.Mail) bool {
fn fn_errors(mut c smtp.Client, m smtp.Mail) bool {
c.send(m) or { return true }
return false
}
@ -14,7 +14,9 @@ fn fn_errors(c smtp.Client, m smtp.Mail) bool {
* Created by: nedimf (07/2020)
*/
fn test_smtp() {
$if !network ? { return }
$if !network ? {
return
}
client_cfg := smtp.Client{
server: 'smtp.mailtrap.io'
@ -32,20 +34,57 @@ fn test_smtp() {
body: 'Plain text'
}
mut client := smtp.new_client(client_cfg) or { assert false return }
mut client := smtp.new_client(client_cfg) or {
assert false
return
}
assert true
client.send(send_cfg) or { assert false return }
client.send(send_cfg) or {
assert false
return
}
assert true
// client.send({ send_cfg | body_type: .html, body: '<html><h1>HTML V email!</h1></html>' }) or { assert false return }
client.send({ send_cfg | from: 'alexander@vlang.io' }) or { assert false return }
client.send({ send_cfg | cc: 'alexander@vlang.io,joe@vlang.io', bcc: 'spytheman@vlang.io' }) or { assert false return }
client.send({ send_cfg | date: time.now().add_days(1000) }) or { assert false return }
client.send({
send_cfg |
from: 'alexander@vlang.io'
}) or {
assert false
return
}
client.send({
send_cfg |
cc: 'alexander@vlang.io,joe@vlang.io'
bcc: 'spytheman@vlang.io'
}) or {
assert false
return
}
client.send({
send_cfg |
date: time.now().add_days(1000)
}) or {
assert false
return
}
assert true
client.quit() or { assert false return }
client.quit() or {
assert false
return
}
assert true
// This call should return an error, since the connection is closed
if !fn_errors(client, send_cfg) { assert false return }
client.reconnect() or { assert false return }
client.send(send_cfg) or { assert false return }
if !fn_errors(mut client, send_cfg) {
assert false
return
}
client.reconnect() or {
assert false
return
}
client.send(send_cfg) or {
assert false
return
}
assert true
}