00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "stdnet.h"
00025
00026 #include "nel/misc/report.h"
00027 #include "nel/misc/path.h"
00028
00029 #include "nel/net/tcp_sock.h"
00030 #include "nel/net/email.h"
00031
00032 using namespace std;
00033 using namespace NLMISC;
00034
00035
00036 namespace NLNET {
00037
00038 static string DefaultSMTPServer, DefaultFrom, DefaultTo;
00039
00040
00041 static char tbl[65] = {
00042 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
00043 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
00044 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
00045 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
00046 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
00047 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
00048 'w', 'x', 'y', 'z', '0', '1', '2', '3',
00049 '4', '5', '6', '7', '8', '9', '+', '/',
00050 '='
00051 };
00052
00053
00054
00055
00056
00057
00058
00059 static void uuencode (const char *s, const char *store, const int length)
00060 {
00061 int i;
00062 unsigned char *p = (unsigned char *)store;
00063 unsigned char *us = (unsigned char *)s;
00064
00065
00066 for (i = 0; i < length; i += 3) {
00067 *p++ = tbl[us[0] >> 2];
00068 *p++ = tbl[((us[0] & 3) << 4) + (us[1] >> 4)];
00069 *p++ = tbl[((us[1] & 0xf) << 2) + (us[2] >> 6)];
00070 *p++ = tbl[us[2] & 0x3f];
00071 us += 3;
00072 }
00073
00074 if (i == length + 1) {
00075 *(p - 1) = tbl[64];
00076 }
00077 else if (i == length + 2) {
00078 *(p - 1) = *(p - 2) = tbl[64];
00079 }
00080
00081 *p = '\0';
00082 }
00083
00084 bool sendEMailCommand (CTcpSock &sock, const std::string &command, uint32 code = 250)
00085 {
00086 string buffer = command + "\r\n";
00087 uint32 size = buffer.size();
00088 if(!command.empty())
00089 {
00090 if (sock.send ((uint8 *)buffer.c_str(), size) != CSock::Ok)
00091 {
00092 nlwarning ("EMAIL: Can't send data to the server");
00093 return false;
00094 }
00095 }
00096
00097 string res;
00098 char c;
00099 for(;;)
00100 {
00101 size = 1;
00102
00103 if (sock.receive((uint8*)&c, size, false) == CSock::Ok)
00104 {
00105 res += c;
00106 if (c == '\n')
00107 {
00108 uint32 c;
00109 fromString(res, c);
00110 if (c != code)
00111 {
00112 nlwarning ("EMAIL: EMail command '%s' returned '%s' instead of code %d on sock %s", command.substr(0, 20).c_str(), res.substr(0, res.size()-2).c_str(), code, sock.remoteAddr().asString().c_str());
00113 return false;
00114 }
00115 return true;
00116 }
00117 }
00118 else
00119 {
00120 nlwarning ("EMAIL: EMail connection closed before end of line, command '%s' returned '%s' on sock %s (code %d)", command.substr(0, 20).c_str(), res.c_str(), sock.remoteAddr().asString().c_str(), code);
00121 return false;
00122 }
00123 }
00124 }
00125
00126
00127 bool sendEmail (const string &smtpServer, const string &from, const string &to, const string &subject, const string &body, const string &attachedFile, bool onlyCheck)
00128 {
00129 bool ok = false;
00130 CTcpSock sock;
00131 uint i;
00132
00133 string formatedBody;
00134 string formatedFrom;
00135 string formatedTo;
00136 string formatedSMTPServer;
00137
00138 try
00139 {
00140
00141 if (smtpServer.empty())
00142 {
00143 if(DefaultSMTPServer.empty())
00144 {
00145 nlwarning ("EMAIL: Can't send email because no SMTPServer was provided");
00146 goto end;
00147 }
00148 else
00149 {
00150 formatedSMTPServer = DefaultSMTPServer;
00151 }
00152 }
00153 else
00154 {
00155 formatedSMTPServer = smtpServer;
00156 }
00157
00158 sock.connect(CInetAddress(formatedSMTPServer, 25));
00159
00160 if (!sock.connected())
00161 {
00162 nlwarning ("EMAIL: Can't connect to email server %s", formatedSMTPServer.c_str());
00163 goto end;
00164 }
00165
00166 if (to.empty())
00167 {
00168 if(DefaultTo.empty())
00169 {
00170 nlwarning ("EMAIL: Can't send email because no To was provided");
00171 goto end;
00172 }
00173 else
00174 {
00175 formatedTo = DefaultTo;
00176 }
00177 }
00178 else
00179 {
00180 formatedTo = to;
00181 }
00182
00183 if(from.empty())
00184 {
00185 if (DefaultFrom.empty())
00186 {
00187 formatedFrom = CInetAddress::localHost().hostName();
00188 formatedFrom += "@gnu.org";
00189 }
00190 else
00191 {
00192 formatedFrom = DefaultFrom;
00193 }
00194 }
00195 else
00196 {
00197 formatedFrom = from;
00198 }
00199
00200
00201 formatedBody = "\r\n";
00202
00203
00204 for (i = 0; i < body.size(); i++)
00205 {
00206 if (body[i] == '\n' && i > 0 && body[i-1] != '\r')
00207 {
00208 formatedBody += '\r';
00209 }
00210 formatedBody += body[i];
00211 }
00212
00213
00214 if (!attachedFile.empty())
00215 {
00216 string ext = CFile::getExtension(attachedFile);
00217
00218 string mimepart;
00219
00220
00221
00222 mimepart += "Mime-Version: 1.0\r\n";
00223 mimepart += "Content-Type: multipart/mixed;\r\n";
00224 mimepart += " boundary=\"Multipart_nel\"\r\n";
00225 mimepart += "\r\n";
00226 mimepart += "This is a multi-part message in MIME format.\r\n";
00227 mimepart += "\r\n";
00228 mimepart += "--Multipart_nel\r\n";
00229 mimepart += "Content-Type: text/plain; charset=us-ascii\r\n";
00230 mimepart += "Content-Transfer-Encoding: 7bit\r\n";
00231
00232 formatedBody = mimepart + formatedBody;
00233
00234
00235
00236 formatedBody += "--Multipart_nel\r\n";
00237 formatedBody += "Content-Disposition: attachment;\r\n";
00238
00239 string lext = toLower(ext);
00240 if(lext == "tga")
00241 {
00242 formatedBody += "Content-Type: image/x-targa;\r\n";
00243 }
00244 else if(lext == "bmp")
00245 {
00246 formatedBody += "Content-Type: image/bmp;\r\n";
00247 }
00248 else if(lext == "png")
00249 {
00250 formatedBody += "Content-Type: image/png;\r\n";
00251 }
00252 else if(lext == "jpg" || lext == "jpeg")
00253 {
00254 formatedBody += "Content-Type: image/jpeg;\r\n";
00255 }
00256 else if(lext == "dmp")
00257 {
00258 formatedBody += "Content-Type: application/octet-stream;\r\n";
00259 }
00260 else
00261 {
00262 formatedBody += "Content-Type: text/plain; charset=us-ascii\r\n";
00263 }
00264
00265 formatedBody += " name=\""+CFile::getFilename(attachedFile)+"\"\r\n";
00266 formatedBody += "Content-Transfer-Encoding: base64\r\n";
00267 formatedBody += " filename=\""+CFile::getFilename(attachedFile)+"\"\r\n";
00268
00269 formatedBody += "\r\n";
00270
00271 static const size_t src_buf_size = 45;
00272 static const size_t dst_buf_size = 4 * ((src_buf_size + 2) / 3);
00273 size_t write_size = dst_buf_size;
00274 char src_buf[src_buf_size + 1];
00275 char dst_buf[dst_buf_size + 1];
00276 size_t size;
00277
00278 FILE *src_stream = fopen (attachedFile.c_str(), "rb");
00279 if (src_stream == NULL)
00280 {
00281 nlwarning ("EMAIL: Can't attach file '%s' to the email because the file can't be open", attachedFile.c_str());
00282 }
00283 else
00284 {
00285 while ((size = fread(src_buf, 1, src_buf_size, src_stream)) > 0)
00286 {
00287 if (size != src_buf_size)
00288 {
00289
00290 write_size=(4 * ((size + 2) / 3));
00291
00292 memset(&src_buf[size], 0, src_buf_size - size);
00293 }
00294
00295 uuencode(src_buf, dst_buf, size);
00296
00297 formatedBody += dst_buf;
00298 formatedBody += "\r\n";
00299 }
00300 fclose (src_stream);
00301 }
00302 formatedBody += "--Multipart_nel--";
00303 }
00304
00305
00306
00307
00308
00309
00310 if(!sendEMailCommand (sock, "", 220)) goto end;
00311
00312 if(onlyCheck)
00313 {
00314 if(!sendEMailCommand (sock, "HELO localhost")) goto end;
00315 if(!sendEMailCommand (sock, "MAIL FROM: " + formatedFrom)) goto end;
00316 if(!sendEMailCommand (sock, "RCPT TO: " + formatedTo)) goto end;
00317 if(!sendEMailCommand (sock, "QUIT", 221)) goto end;
00318
00319 ok = true;
00320 }
00321 else
00322 {
00323 if(!sendEMailCommand (sock, "HELO localhost")) goto end;
00324 if(!sendEMailCommand (sock, "MAIL FROM: " + formatedFrom)) goto end;
00325 if(!sendEMailCommand (sock, "RCPT TO: " + formatedTo)) goto end;
00326 if(!sendEMailCommand (sock, "DATA", 354)) goto end;
00327
00328 string buffer =
00329 "From: " + formatedFrom + "\r\n"
00330 "To: " + formatedTo + "\r\n"
00331 "Subject: " + subject + "\r\n"
00332 + formatedBody + "\r\n.";
00333
00334 if(!sendEMailCommand (sock, buffer)) goto end;
00335 if(!sendEMailCommand (sock, "QUIT", 221)) goto end;
00336
00337 ok = true;
00338 }
00339 }
00340 catch (Exception &e)
00341 {
00342 nlwarning ("EMAIL: Can't send email: %s", e.what());
00343 goto end;
00344 }
00345
00346 end:
00347 if (sock.connected())
00348 sock.close ();
00349
00350 return ok;
00351 }
00352
00353 void setDefaultEmailParams (const std::string &smtpServer, const std::string &from, const std::string &to)
00354 {
00355 DefaultSMTPServer = smtpServer;
00356 DefaultFrom = from;
00357 DefaultTo = to;
00358 }
00359
00360 }