1 /*
2  *  SMTP.cpp
3  *  OpenLieroX
4  *
5  *  Created by Albert Zeyer on 19.10.09.
6  *  Code under LGPL.
7  *
8  */
9 
10 #include "Networking.h"
11 #include "SMTP.h"
12 #include "Debug.h"
13 #include "Timer.h"
14 
15 struct SmtpClient::Handler {
16 	NetworkSocket sock;
17 };
18 
SmtpClient_wait(NetworkSocket & sock,const std::string & expectedstart)19 static bool SmtpClient_wait(NetworkSocket& sock, const std::string& expectedstart) {
20 	char c = 0;
21 	int r = 0;
22 	std::string line;
23 	while((r = sock.Read(&c, 1)) >= 0) {
24 		if(r == 0) {
25 			SDL_Delay(10);
26 			continue;
27 		}
28 
29 		if(c == '\n') break;
30 		line += c;
31 	}
32 	if(r < 0) {
33 		errors << "SMTP: error while waiting for " << expectedstart << endl;
34 		return false;
35 	}
36 
37 	if(!subStrEqual(line, expectedstart, expectedstart.size())) {
38 		errors << "SMTP: expected was " << expectedstart << " but we got '" << line << "'" << endl;
39 		return false;
40 	}
41 
42 	return true;
43 }
44 
writeOnSocket(NetworkSocket & sock,std::string buf)45 static bool writeOnSocket(NetworkSocket& sock, std::string buf) {
46 	while(buf.size() > 0) {
47 		int ret = sock.Write(buf);
48 		if(ret < 0) return false;
49 		buf.erase(0, ret);
50 	}
51 	return true;
52 }
53 
SmtpClient_write(NetworkSocket & sock,const std::string & line)54 static bool SmtpClient_write(NetworkSocket& sock, const std::string& line) {
55 	if(!writeOnSocket(sock, line + "\n")) {
56 		errors << "SMTP: error while writing " << line << endl;
57 		return false;
58 	}
59 	return true;
60 }
61 
SmtpClient_writeAndWait(NetworkSocket & sock,const std::string & line,const std::string & expectedanswer)62 static bool SmtpClient_writeAndWait(NetworkSocket& sock, const std::string& line, const std::string& expectedanswer) {
63 	if(!SmtpClient_write(sock, line)) return false;
64 	return SmtpClient_wait(sock, expectedanswer);
65 }
66 
connect()67 bool SmtpClient::connect() {
68 	if(intern) reset();
69 	intern = new Handler();
70 
71 	NetworkAddr addr, addr6;
72 	AbsTime dnsRequestTime = GetTime();
73 	if(!GetNetAddrFromNameAsync(host)) {
74 		errors << "SMTP: Error while starting name resolution for " << host << endl;
75 		return false;
76 	}
77 
78 	while(!IsNetAddrValid(addr)) {
79 		if((GetTime() - dnsRequestTime).seconds() >= DNS_TIMEOUT) {
80 			errors << "SMTP: DNS timeout while resolving " << host << endl;
81 			return false;
82 		}
83 		SDL_Delay(10);
84 		GetFromDnsCache(host, addr, addr6);
85 	}
86 
87 	std::string host_addr;
88 	NetAddrToString(addr, host_addr);
89 	//notes << "SMTP: resolved " << host << " to " << host_addr << endl;
90 
91 	if(!intern->sock.OpenReliable(0)) {
92 		errors << "SMTP: error while opening socket" << endl;
93 		return false;
94 	}
95 
96 	AbsTime connectingTime = GetTime();
97 	if(!intern->sock.Connect(addr)) {
98 		errors << "SMTP: error while trying to connect to " << host << endl;
99 		return false;
100 	}
101 
102 	while(!intern->sock.isReady()) {
103 		if((GetTime() - connectingTime).seconds() >= 10) {
104 			errors << "SMTP: connect timeout to " << host << endl;
105 			return false;
106 		}
107 		SDL_Delay(10);
108 	}
109 
110 	if(!SmtpClient_wait(intern->sock, "220 ")) return false;
111 	if(!SmtpClient_writeAndWait(intern->sock, "MAIL FROM:" + mailfrom, "250 ")) return false;
112 	for(std::list<std::string>::iterator i = mailrcpts.begin(); i != mailrcpts.end(); ++i)
113 		if(!SmtpClient_writeAndWait(intern->sock, "RCPT TO:" + *i, "250 ")) return false;
114 	if(!SmtpClient_writeAndWait(intern->sock, "DATA", "354 ")) return false;
115 	if(!SmtpClient_write(intern->sock, "From: " + mailfrom)) return false;
116 	for(std::list<std::string>::iterator i = mailrcpts.begin(); i != mailrcpts.end(); ++i)
117 		if(!SmtpClient_write(intern->sock, "To: " + *i)) return false;
118 	if(!SmtpClient_write(intern->sock, "Subject: " + subject)) return false;
119 	for(std::list<std::string>::iterator i = headers.begin(); i != headers.end(); ++i)
120 		if(!SmtpClient_write(intern->sock, *i)) return false;
121 	if(!SmtpClient_write(intern->sock, "")) return false;
122 
123 	return true;
124 }
125 
addText(const std::string & txt)126 bool SmtpClient::addText(const std::string& txt) {
127 	if(!intern || !intern->sock.isReady()) {
128 		errors << "SMTP addtext: socket not ready" << endl;
129 		return false;
130 	}
131 
132 	if(txt == "")
133 		return SmtpClient_write(intern->sock, "");
134 
135 	std::string line;
136 	for(std::string::const_iterator i = txt.begin(); i != txt.end(); ++i) {
137 		if(*i == '\n') {
138 			if(line != "" && line[0] == '.') line = " " + line; // to not end the mail
139 			if(!SmtpClient_write(intern->sock, line)) return false;
140 			line = "";
141 			continue;
142 		}
143 
144 		line += *i;
145 	}
146 
147 	if(line != "") {
148 		if(line[0] == '.') line = " " + line; // to not end the mail
149 		if(!SmtpClient_write(intern->sock, line)) return false;
150 	}
151 
152 	return true;
153 }
154 
close()155 bool SmtpClient::close() {
156 	if(!SmtpClient_writeAndWait(intern->sock, ".", "250 ")) return false;
157 	if(!SmtpClient_writeAndWait(intern->sock, "QUIT", "221 ")) return false;
158 	intern->sock.Close();
159 	return true;
160 }
161 
reset()162 void SmtpClient::reset() {
163 	if(intern) {
164 		delete intern;
165 		intern = NULL;
166 	}
167 }
168 
169