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