www.pudn.com > doc2pdf-0_7_1.rar > doc2pdf_smtp.cpp
///////////////////////////////////////////////////////////////////////////// // // Project: Doc2pdf // // File: doc2pdf_smtp.cpp // // Author(s): Matt Peterson// // Description: SMTP email sender // ///////////////////////////////////////////////////////////////////////////// #include "doc2pdf_smtp.h" #include "doc2pdf_log.h" #define DOC2PDF_SMTP_PORT 25 #define DOC2PDF_SMTP_BUFSIZE 4096 #define DOC2PDF_PART_BOUNDARY "--DoC2PdFbOuNdArY" #ifndef CRLF #define CRLF "\r\n" #endif #define DOC2PDF_TOO_LARGE_SUBJECT "DOC2PDF ERROR: Attachment too large. Can not be delivered" int Doc2pdfSmtpSender::AddressStringToList(const CString& str, CStringList& list) { int start; int end; CString listItem; list.RemoveAll(); start = str.Find(':',0) + 1; end = start; if(str.GetLength() > start) { while(end != 0 && end != -1) { do { end = str.Find(',',end); if(end >= 0) { listItem = str.Mid(start,end - start); } else { listItem = str.Mid(start,str.GetLength() - start); break; } end ++; }while(listItem.Find('@') == -1); if(listItem.ReverseFind(' ') >= 0) { listItem = listItem.Right(listItem.GetLength() - listItem.ReverseFind(' ') - 1); } if(listItem.Find('<') < 0) { listItem.Insert(0,'<'); listItem += ">"; } if(listItem.Find('@') !=-1) { listItem.MakeLower(); list.AddTail(listItem); } else { start = end; } start = end; } } return 0; } // Do MAIL TO for each address and remove my address // Returns zero on success int Doc2pdfSmtpSender::SendMailTo(Doc2pdfIO* io, CString& addresses) { POSITION pos; CStringList list; CString line; CString msg; AddressStringToList(addresses,list); addresses.Empty(); pos = list.GetHeadPosition(); while(pos) { /* Don't let our address be replied do */ /* Don't reply to bounced mail */ if(list.GetAt(pos).Find(m_MyAddress) < 0 && list.GetAt(pos).Find("mailer-daemon") < 0) { line = "RCPT TO: "; line += list.GetAt(pos); if(io->WriteLine(line) == 0) { /* Read the (hopefully 250 response) */ io->ReadLine(line); if(line.Left(3) != "250") { msg.Format("SMTP ERROR: \"rcpt to:%s\" returned: %s",list.GetAt(pos),(LPCSTR)line); theLog.Log(msg); } addresses += list.GetAt(pos); addresses += ","; } } list.GetNext(pos); } addresses.TrimRight(','); return 0; } // Send a multipart attachment // Returns zero on success int Doc2pdfSmtpSender::SendAttachment(Doc2pdfIO* io, Doc2pdfAttachment* attachment) { CString line; CString filename; CFile file; int count; void* buf; buf = malloc(DOC2PDF_SMTP_BUFSIZE); if(buf == NULL) { return -1; } if(attachment->m_Converted) { if(file.Open(attachment->m_Path,CFile::modeRead)) { filename = attachment->m_Name.Left(attachment->m_Name .ReverseFind('.')); filename += ".pdf"; line = CRLF "--"DOC2PDF_PART_BOUNDARY CRLF; line += "Content-Type: application/pdf; name=\""; line += filename; line += "\"" CRLF; line += "Content-Transfer-Encoding: base64" CRLF; line += "Content-Disposition: attachment; filename=\""; line += filename; line += "\"" CRLF; if(io->WriteLine(line)) { /* Problems passing sending */ goto END; } while((count = file.Read(buf,DOC2PDF_SMTP_BUFSIZE)) > 0) { if(io->Write(buf,count)) { break; } } file.Close(); } } END: free(buf); return 0; } int Doc2pdfSmtpSender::SendEmail(Doc2pdfIO* io, Doc2pdfEmail* email) { CString line; CString msg; POSITION pos; /*-----------*/ /* Mail From */ /*-----------*/ line.Format("MAIL FROM: %s",m_MyAddress); if(io->WriteLine(line)) { /* Problems doing MailFrom */ goto RESET; } io->ReadLine(line); if(line.Left(3) != "250") { /* Problems doing Mail From */ msg.Format("SMTP ERROR: \"mail from:\"%s returned: %s",m_MyAddress,(LPCSTR)line); theLog.Log(msg); goto RESET; } /*----------------------------------------*/ /* MAIL TO: for From or Reply-to recipients */ /*----------------------------------------*/ if(email->m_ReplyTo.GetLength() == 0) { SendMailTo(io, email->m_From); } else { SendMailTo(io, email->m_ReplyTo); } if(email->m_Attachments.GetCount()) { /*----------------------------*/ /* MAIL TO: for To recipients */ /*----------------------------*/ SendMailTo(io,email->m_To); /*----------------------------*/ /* MAIL TO: for To recipients */ /*----------------------------*/ SendMailTo(io,email->m_Cc); } /* Don't continue if there are no recipients */ if(email->m_From.GetLength() == 0 && email->m_To.GetLength() == 0 && email->m_Cc.GetLength() == 0) { goto RESET; } /*------*/ /* DATA */ /*------*/ line = "DATA"; if(io->WriteLine(line)) { /* Problems passing DATA */ goto RESET; } io->ReadLine(line); if(line.Left(3) != "354") { /* Problems with DATA */ line.Insert(0,"SMTP ERROR: writing envelope. MTA returned: "); theLog.Log(line); goto RESET; } line = "From: "; line += m_MyAddress; line += CRLF; line += "To: "; line += email->m_From; line += CRLF; line += "Cc: "; line += email->m_Cc; line += CRLF; line += "Subject: "; line += "Converted: "; if(email->m_Subject.GetLength() > 8) { email->m_Subject.Delete(0,8); // we don't want 2 "Subject:" } line += email->m_Subject; line += CRLF; line += "MIME-Version: 1.0" CRLF; line += "Content-Type: Multipart/Mixed; boundary=\""; line += DOC2PDF_PART_BOUNDARY "\"" CRLF CRLF; line += "This is a multipart MIME message" CRLF CRLF; line += "--" DOC2PDF_PART_BOUNDARY CRLF; line += "Content-Type: text/plain; charset=US-ASCII"; line += CRLF CRLF; line += email->m_Body; if(io->WriteLine(line)) { /* Problems with body */ goto RESET; } /*-------------*/ /* ATTACHMENTS */ /*-------------*/ pos = email->m_Attachments.GetHeadPosition(); while(pos) { SendAttachment(io, email->m_Attachments.GetAt(pos)); email->m_Attachments.GetNext(pos); } /* Last Boundary and . terminator */ line = CRLF "--" DOC2PDF_PART_BOUNDARY "--" CRLF CRLF; line += CRLF "."; if(io->WriteLine(line)) { /* Problems writing last boundary */ goto RESET; } io->ReadLine(line); if(line.Left(3) != "250") { /* Not a terminate data */ msg=line; msg.Insert(0,"SMTP ERROR: terminating message. MTA returned: "); theLog.Log(msg); #ifdef DEBUG /* Send back an informative little reply on message to large */ if(line.Left(3) == "552") { Doc2pdfEmail toolarge; toolarge.m_Body = email->m_Body; toolarge.m_From = email->m_From; toolarge.m_ReplyTo = email->m_ReplyTo; toolarge.m_Subject = DOC2PDF_TOO_LARGE_SUBJECT; SendEmail(io,&toolarge); } #endif } /* SUCCESS */ return 0; RESET: io->WriteLine("RSET"); io->ReadLine(line); return 0; } // Initialize this object int Doc2pdfSmtpSender::Init(const CString& smtphost, const CString myaddress) { m_SmtpHost = smtphost; m_MyAddress = myaddress; return 0; } // Returns number of emails sent int Doc2pdfSmtpSender::SendAllEmail(const Doc2pdfEmailList& emaillist) { Doc2pdfSocket sock; Doc2pdfIO* io; Doc2pdfEmail* email; Doc2pdfEmail eemail; POSITION pos; CString line; CString msg; int result = 0; /*------------------------*/ /* Connect to Smtp server */ /*------------------------*/ // Connect to the Pop3 host if(sock.Connect(m_SmtpHost,DOC2PDF_SMTP_PORT)) { // Could not connect // TODO: Log the fact that we could not connect return -1; } io = (Doc2pdfIO*)&sock; /*-----------------------------*/ /* Read Greeting and say Hello */ /*-----------------------------*/ io->ReadLine(line); if(line.Left(1) != "2") { /* Not a SMTP server */ theLog.Log("SMTP ERROR: Not an SMTP server. Check configuration"); result = -1; goto END; } line = "HELO there"; if(io->WriteLine(line)) { /* Write Error */ result = -1; goto END; } io->ReadLine(line); if(line.Left(3) != "250") { /* Not a SMTP server */ line.Insert(0,"SMTP ERROR: \"hello\" returned: "); theLog.Log(line); result = -1; goto END; } pos = emaillist.GetHeadPosition(); while(pos) { email = emaillist.GetAt(pos); if(SendEmail(io,email) == 0) { result ++; } emaillist.GetNext(pos); } END: /*-------------------*/ /* Free up resources */ /*-------------------*/ sock.Close(); return result; }