Implemented STARTTLS, also fixed most protocol related issues.

This commit is contained in:
Relintai 2023-09-18 13:41:01 +02:00
parent b42cfece18
commit 94bbe7acb5

View File

@ -1,19 +1,5 @@
extends Node extends Node
export(String) var server : String = "smtp.gmail.com"
export(int) var port : int = 465
export(String) var user : String = ""
export(String) var password : String = ""
export(String) var email_address : String = "mail.smtp.localhost"
export(String) var client_address : String = "client.example.com"
export(int) var max_retries : int = 5
export(int) var delay_time : int = 250
var _socket_original : StreamPeer = null
var _socket : StreamPeer = null
var _packet_in : String = ""
var _packet_out : String = ""
enum SMTPStatus { enum SMTPStatus {
OK, OK,
WAITING, WAITING,
@ -21,6 +7,28 @@ enum SMTPStatus {
UNHANDLED_REPONSE UNHANDLED_REPONSE
} }
enum AuthType {
PLAINTEXT,
STARTTLS,
SMTPS
}
export(String) var server : String = "smtp.gmail.com"
export(int) var port : int = 465
export(String) var user : String = ""
export(String) var password : String = ""
export(String) var email_address : String = ""
export(String) var email_address_name : String = ""
export(String) var client_address : String = "client.example.com"
export(int) var max_retries : int = 5
export(int) var delay_time : int = 250
export(AuthType) var auth_type : int = 0
var _socket_original : StreamPeer = null
var _socket : StreamPeer = null
var _packet_in : String = ""
var _packet_out : String = ""
var _current_status : int = 0 var _current_status : int = 0
var _thread : Thread = null var _thread : Thread = null
@ -48,24 +56,23 @@ func _thread_deliver(user_data):
r_code = open_socket() r_code = open_socket()
if r_code == OK: if r_code == OK:
r_code = wait_answer() r_code = wait_answer()
# if r_code == OK: # if r_code == OK:
# emit_signal("SMTP_connected") # emit_signal("SMTP_connected")
# r_code = send("ciao") # needed because some SMTP servers return error each first command # r_code = send("ciao") # needed because some SMTP servers return error each first command
if r_code == OK: if r_code == OK:
r_code = mail_hello() r_code = mail_hello()
if r_code == OK && auth_type == AuthType.STARTTLS:
r_code = mail_starttls()
if r_code == OK:
r_code = mail_hello()
if r_code == OK: if r_code == OK:
print("SMTP_working")
close_socket()
return
r_code = mail_auth() r_code = mail_auth()
if r_code == OK: if r_code == OK:
r_code = mail_from(address) r_code = mail_from(email_address)
if r_code == OK: if r_code == OK:
r_code = mail_to(address) r_code = mail_to(address)
if r_code == OK: if r_code == OK:
r_code = mail_data(data, address, subject) r_code = mail_data(data, subject)
if r_code == OK: if r_code == OK:
print("process OK") print("process OK")
if r_code == OK: if r_code == OK:
@ -81,13 +88,10 @@ func _thread_deliver(user_data):
func open_socket(): func open_socket():
var error : int var error : int
if _socket_original == null: if _socket == null:
_socket_original = StreamPeerTCP.new() _socket = StreamPeerTCP.new()
error = _socket_original.connect_to_host(server,port) error = _socket.connect_to_host(server,port)
_socket = StreamPeerSSL.new()
_socket.connect_to_stream(_socket_original, true, server)
display(["connecting server...",server,error]) display(["connecting server...",server,error])
if error > 0: if error > 0:
@ -95,7 +99,7 @@ func open_socket():
error=_socket.connect_to_host(ip,port) error=_socket.connect_to_host(ip,port)
display(["trying IP ...",ip,error]) display(["trying IP ...",ip,error])
for i in range(1,max_retries): for i in range(1, max_retries):
print("RETRIES" + str(_socket.get_status())) print("RETRIES" + str(_socket.get_status()))
# if _socket.get_status() == _socket.STATUS_ERROR: # if _socket.get_status() == _socket.STATUS_ERROR:
@ -115,7 +119,14 @@ func open_socket():
return error return error
func close_socket(): func close_socket():
_socket_original.disconnect_from_host() if !_socket_original:
_socket.disconnect_from_host()
else:
_socket.disconnect_from_stream()
_socket_original.disconnect_from_host()
_socket = null
_socket_original = null
func send(data1,data2=null,data3=null): func send(data1,data2=null,data3=null):
return send_only(data1,data2,data3) return send_only(data1,data2,data3)
@ -144,33 +155,48 @@ func wait_answer(succesful=""):
_packet_in = "" _packet_in = ""
OS.delay_msec(delay_time) OS.delay_msec(delay_time)
for i in range(1,max_retries): for i in range(max_retries):
_socket.poll() if _socket.has_method(@"poll"):
var bufLen = _socket.get_available_bytes() _socket.poll()
if bufLen > 0:
display(["bytes buffered",String(bufLen)]) var buf_len = _socket.get_available_bytes()
_packet_in=_packet_in + _socket.get_utf8_string(bufLen) if buf_len > 0:
display(["bytes buffered",String(buf_len)])
_packet_in = _packet_in + _socket.get_utf8_string(buf_len)
display(["receive",_packet_in]) display(["receive",_packet_in])
break break
else: else:
OS.delay_msec(delay_time) OS.delay_msec(delay_time)
# This will likely need a rework
if _packet_in != "": if _packet_in != "":
_current_status= SMTPStatus.OK _current_status = SMTPStatus.OK
if parse_packet_in(succesful) != OK: if parse_packet_in(succesful) != OK:
_current_status=SMTPStatus.UNHANDLED_REPONSE _current_status = SMTPStatus.UNHANDLED_REPONSE
else: else:
_current_status = SMTPStatus.NO_RESPONSE _current_status = SMTPStatus.NO_RESPONSE
return _current_status return _current_status
func parse_packet_in(strcompare): func parse_packet_in(strcompare : String):
if strcompare == "": if strcompare == "":
return OK return OK
if _packet_in.left(strcompare.length())==strcompare:
return OK var slicecount : int = _packet_in.get_slice_count("\r\n")
if slicecount <= 1:
if _packet_in.left(strcompare.length()) == strcompare:
return OK
else:
return FAILED
else: else:
return FAILED var ll : String = _packet_in.get_slice("\r\n", slicecount - 2)
if ll.left(strcompare.length()) == strcompare:
return OK
else:
return FAILED
func mail_hello(): func mail_hello():
var r_code : int = send("HELO", client_address) var r_code : int = send("HELO", client_address)
@ -179,6 +205,38 @@ func mail_hello():
r_code= wait_answer("250") r_code= wait_answer("250")
return r_code return r_code
func mail_starttls():
var r_code : int = send("STARTTLS")
r_code = wait_answer("220") #220 TLS go ahead
if r_code != OK:
return r_code
_socket_original = _socket
_socket = StreamPeerSSL.new()
_socket.connect_to_stream(_socket_original, true, server)
for i in range(max_retries):
print("STARTTLS RETRIES" + str(_socket.get_status()))
if _socket.get_status() == _socket.STATUS_ERROR:
display("Error while requesting connection")
return _socket.get_status()
# elif _socket.get_status() == _socket.STATUS_CONNECTING:
# d.display("connecting...")
# break
if _socket.get_status() == _socket.STATUS_CONNECTED:
display("STARTTLS connection up")
print("STARTTLS CONNECTED")
break
OS.delay_msec(delay_time)
return r_code
func mail_auth(): func mail_auth():
var r_code : int =send("AUTH LOGIN") var r_code : int =send("AUTH LOGIN")
r_code=wait_answer("334") r_code=wait_answer("334")
@ -212,20 +270,24 @@ func mail_to(data):
return r_code return r_code
func mail_data(data=null,from=null,subject=null): func mail_data(data=null,subject=null):
var corpo : String = "" var corpo : String = data
for i in data: corpo += "\r\n.\r\n"
corpo = corpo + i + "\r\n"
corpo=corpo + "." var r_code=send("DATA")
var r_code=send("DATA")
r_code=wait_answer("354") r_code=wait_answer("354")
# if r_code == OK and from != null: if r_code == OK:
# r_code=send("FROM: ",bracket(from)) r_code=send("FROM: ", email_address_name + " " + bracket(email_address))
#r_code =wait_answer("250")
if r_code == OK and subject != null: if r_code == OK and subject != null:
r_code=send("SUBJECT: ",subject) r_code=send("SUBJECT: ",subject)
#r_code =wait_answer("250")
if r_code == OK and data != null: if r_code == OK and data != null:
r_code=send(corpo) r_code=send(corpo)
r_code =wait_answer("250") #r_code =wait_answer("250")
r_code = wait_answer("250")
return r_code return r_code
func mail_quit(): func mail_quit():