email.cpp

Go to the documentation of this file.
00001 
00005 /* Copyright, 2001 Nevrax Ltd.
00006  *
00007  * This file is part of NEVRAX NeL Network Services.
00008  * NEVRAX NeL Network Services is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2, or (at your option)
00011  * any later version.
00012 
00013  * NEVRAX NeL Network Services is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00016  * General Public License for more details.
00017 
00018  * You should have received a copy of the GNU General Public License
00019  * along with NEVRAX NeL Network Services; see the file COPYING. If not, write to the
00020  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00021  * MA 02111-1307, USA.
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 /* Conversion table.  for base 64 */
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     '=' /* termination character */
00051 };
00052 
00053 /*
00054  * Encode the string S of length LENGTH to base64 format and place it
00055  * to STORE.  STORE will be 0-terminated, and must point to a writable
00056  * buffer of at least 1+BASE64_LENGTH(length) bytes.
00057  * where BASE64_LENGTH(len) = (4 * ((LENGTH + 2) / 3))
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     /* Transform the 3x8 bits to 4x6 bits, as required by base64.  */
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     /* Pad the result if necessary...  */
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     /* ...and zero-terminate it.  */
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         // we must skip the first line
00201         formatedBody = "\r\n";
00202 
00203         // replace \n with \r\n
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         // add attachment if any
00214         if (!attachedFile.empty())
00215         {
00216             string ext = CFile::getExtension(attachedFile);
00217 
00218             string mimepart;
00219 
00220             // mime header and main mail text
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             // mime attachment
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             // empty line to say that it s the end of the header
00269             formatedBody += "\r\n";
00270 
00271             static const size_t src_buf_size = 45;// This *MUST* be a multiple of 3
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                         /* write_size is always 60 until the last line */
00290                         write_size=(4 * ((size + 2) / 3));
00291                         /* pad with 0s so we can just encode extra bits */
00292                         memset(&src_buf[size], 0, src_buf_size - size);
00293                     }
00294                     /* Encode the buffer we just read in */
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         // debug, display what we send into a file
00306         //  {   FILE *fp = fopen (CFile::findNewFile("mail.txt").c_str(), "wb");
00307         //  fwrite (formatedBody.c_str(), 1, formatedBody.size(), fp);
00308         //  fclose (fp); }
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 } // NLNET

Generated on Thu Jan 7 08:26:35 2010 for NeL by  doxygen 1.6.1