?? mailer_class.cpp.svn-base
字號:
#include <fstream>#include <sstream>#include <ctime>#include <cassert>#include "mailer_class.h"#include "base64.h"/* constructors */Mailer::Mailer(const char *TOaddress, const char *FROMaddress, const char *Subject, const std::vector<char> &Message, const char *Nameserver, unsigned short Port, bool MXLookup) : type(LOGIN), subject(Subject), server(getserveraddress(TOaddress)), nameserver(Nameserver), port(htons(Port)), lookupMXRecord(MXLookup), auth(false){ /* parse the email address into an address structure */ setsender(FROMaddress); // set from address addrecipient(TOaddress); // set to address setmessage(Message); // set message initNetworking(); // initialize connection}Mailer::Mailer(const char* TOaddress, const char* FROMaddress, const char* Subject, const char* Message, const char* Nameserver, unsigned short Port, bool MXLookup): type(LOGIN), subject(Subject), server(getserveraddress(TOaddress)), nameserver(Nameserver), port(htons(Port)), lookupMXRecord(MXLookup), auth(false) { /* parse the email addresses into an address structure. */ setsender(FROMaddress); // set from address addrecipient(TOaddress); // set to address setmessage(Message); // set message initNetworking(); // initialize connection}Mailer::Mailer(bool MXLookup, unsigned short Port) : type(LOGIN), port(htons(Port)), lookupMXRecord(MXLookup), auth(false) { initNetworking(); // initialize connection}Mailer::~Mailer() { } /* set the mail body */bool Mailer::setmessage(const std::string &newmessage){ /* check if we have an empty message */ if(!newmessage.length()) { return false; // this is an error } message.clear(); // erase the old message /* check if message is valid */ for(std::string::size_type i=0; i<newmessage.length(); ++i) { message.push_back(newmessage[i]); } /* check if we're RFC compliant */ checkRFCcompat(); return true;}bool Mailer::setmessage(const std::vector<char> &newmessage){ /* check if we have an empty message */ if(!newmessage.size()) { return false; } message = newmessage; // set the message /* check if we're RFC compliant */ checkRFCcompat(); return true;}/* set a HTML message */bool Mailer::setmessageHTML(const std::string &newmessage){ /* check if we have an empty message */ if(!newmessage.length()) { return false; } messageHTML.clear(); // erase old message /* is this message valid? */ for(std::string::size_type i=0; i<newmessage.length(); ++i) { messageHTML.push_back(newmessage[i]); } messageHTML = base64encode(messageHTML); // encode message return true;}bool Mailer::setmessageHTML(const std::vector<char> &newmessage){ /* check if we have an empty message */ if(!newmessage.size()) { return false; } messageHTML = base64encode(newmessage); // encode message return true;}/* set a message from an HTML file */bool Mailer::setmessageHTMLfile(const std::string &filename){ /* check if we have an empty message */ if(!filename.length()) { return false; } /* open file */ std::ifstream file(filename.c_str(), std::ios::binary | std::ios::in); /* could we open the file */ if(!file) { return false; } std::vector<char> filedata; /* read file data */ char c = file.get(); for( ; file.good(); c=file.get()) { if(file.bad()) { break; } filedata.push_back(c); } messageHTML = base64encode(filedata); // encode message return true;}/* check if all is RFC compliant */void Mailer::checkRFCcompat() { /* Check the line breaks. */ std::vector<char>::iterator it; for(it = message.begin(); it != message.end(); ++it) { /* look for \n add \r before if not there. Pretty lame but still. haven't thought of a better way yet. */ if(*it == '\n') { if(it == message.begin()) { it = message.insert(it, '\r'); ++it; // step past newline continue; } if((*(it -1) != '\r') ) { /* add a return before '\n' */ it = message.insert(it, '\r'); ++it; // step past newline } } } /* if we get a period on a line by itself * add another period to stop the server ending the mail prematurely. * ( suggested by david Irwin ) */ if(message.size() == 1) { if(*(message.begin()) == '.') { message.push_back('.'); } } else if(message.size() == 2) { if(*(message.begin()) == '.') { it = message.begin(); it = message.insert(it, '.'); } } else { if(*(message.begin()) == '.') { it = message.begin(); it = message.insert(it, '.'); } for(it = message.begin()+2; it != message.end(); ++it) { /* follow the rfc. Add '.' if the first character on a line is '.' */ if(*it == '\n') { if( ((it + 1) != message.end()) && (*(it +1) == '.') ) { it = message.insert(it + 1, '.'); ++it; // step past } } } } /* don't do anything if we are not longer than a 1000 characters */ if(message.size() < 1000) { return; } /* now we have checked line breaks check line lengths. */ int count(1); for(it = message.begin(); it < message.end(); ++it, ++count) { if(*it == '\r') { count = 0; // reset for a new line. ++it; // get past newline continue; } else if(count >= 998) { ++it; if(*it != ' ') { // we are not in a word!! /* it should never get to message.begin() because we start at least 998 chars into the message! * Also, assume a word isn't bigger than 997 chars! (seems reasonable) */ std::vector<char>::iterator pos = it; for(int j = 0; j < 997; ++j, --pos) { if(*pos == ' ') { it = ++pos; // get past the space. break; } } } if(it < message.end()) { it = message.insert(it, '\r'); } ++it; if(it < message.end()) { it = message.insert(it, '\n'); } count = 0; // reset for a new line. } } count=1; // reset the count if(messageHTML.size()) { for(it = messageHTML.begin(); it < messageHTML.end(); ++it, ++count) { if(*it == '\r') { count = 0; // reset for a new line. ++it; // get past newline continue; } else if(count >= 998) { ++it; if(*it != ' ') { // we are in a word!! /* it should never get to message.begin() because we * start at least 998 chars into the message! * Assume a word isn't bigger than 997 chars! (seems reasonable) */ std::vector<char>::iterator pos = it; for(int j = 0; j < 997; ++j, --pos) { if(*pos == ' ') { it = ++pos; // get past the space. break; } } } if(it < messageHTML.end()) { it = messageHTML.insert(it, '\r'); } ++it; if(it < messageHTML.end()) { it = messageHTML.insert(it, '\n'); } count = 0; // reset for a new line. } } }}/* set the subject line */bool Mailer::setsubject(const std::string& newSubject) { /* do we have a non-empty subject? */ if(!newSubject.length()) { return false; } subject = newSubject; // set subject return true;}/* set SMTP server */bool Mailer::setserver(const std::string& nameserver_or_smtpserver) { /* is a servername given? */ if(!nameserver_or_smtpserver.length()) { return false; } nameserver = nameserver_or_smtpserver; return true;}/* set FROM address */bool Mailer::setsender(const std::string& newsender) { /* do we have an empty sender? */ if(!newsender.length()) { return false; } /* parse and set sender address */ Address newaddress(parseaddress(newsender)); fromAddress = newaddress; return true;}/* set TO address */bool Mailer::addrecipient(const std::string& newrecipient, short recipient_type){ /* SMTP only allows 100 recipients max at a time. rfc821 */ if(recipients.size() >= 100) { // == would be fine, but let's be stupid safe return false; } if(newrecipient.length()) { /* If there are no recipients yet set the server address for MX queries */ if(!recipients.size()) { server = getserveraddress(newrecipient); } Address newaddress = parseaddress(newrecipient); if(recipient_type > Bcc || recipient_type < TO) { recipient_type = Bcc; // default to blind copy on error(hidden is better) } recipients.push_back(std::make_pair(newaddress, recipient_type)); return true; } return false;}/* remove a recipient from the list */bool Mailer::removerecipient(const std::string& recipient) { if(recipient.length()) { // there is something to remove std::vector<std::pair<Address, short> >::iterator it(recipients.begin()); for(; it < recipients.end(); ++it) { if((*it).first.address == recipient) { recipients.erase(it); return true; } } /* fall through as we did not find this recipient */ } return false;}/* clear all recipient from the list */void Mailer::clearrecipients() { recipients.clear();}/* clear all attachments from the list */void Mailer::clearattachments() { attachments.clear();}/* reset the program */void Mailer::reset() { recipients.clear(); // reset recipient list attachments.clear(); // reset attachment list server = ""; // reset SMTP server message.clear(); // reset message messageHTML.clear(); // reset HTML message returnstring = ""; // clear out any errors from previous use}/* convenience funtion */void Mailer::send() { operator()();}/* this is where we do all the work. */void Mailer::operator()() { returnstring = ""; // clear out any errors from previous use if(!recipients.size()) { // we need a recipient returnstring = "451 Requested action aborted: local error who am I mailing"; return; } if(!fromAddress.address.length()) { // we need a sender returnstring = "451 Requested action aborted: local error who am I"; return; } if(!nameserver.length()) { // no SMTP or nameserver given returnstring = "451 Requested action aborted: local error no SMTP/name server/smtp server"; return; } std::vector<SOCKADDR_IN> adds; /* lookup for a MX record */ if(lookupMXRecord) { if(!gethostaddresses(adds)) { /* error!! we are dead. */ returnstring = "451 Requested action aborted: No MX records ascertained"; return; } } else { // connect directly to an SMTP server. SOCKADDR_IN addr(nameserver, port, AF_INET); hostent* host = 0; if(addr) { host = gethostbyaddr(addr.get_sin_addr(), sizeof(addr.ADDR.sin_addr), AF_INET); } else { host = gethostbyname(nameserver.c_str()); } if(!host) { returnstring = "451 Requested action aborted: local error in processing"; return; // error!!! } std::copy(host->h_addr_list[0], host->h_addr_list[0] + host->h_length, addr. get_sin_addr()); adds.push_back(addr); } /* create the client socket */ SOCKET s; if(!Socket(s, AF_INET, SOCK_STREAM, 0)) { returnstring = "451 Requested action aborted: socket function error"; return; } if(!adds.size()) { // oops returnstring = "451 Requested action aborted: No MX records ascertained"; } const std::string OK("250"); const std::vector<char> smtpheader(makesmtpmessage()); const int buffsize(1024); char buff[buffsize] = ""; for(std::vector<SOCKADDR_IN>::const_iterator address = adds.begin(); address < adds.end(); ++address) { if(!Connect(s, *address)) { // connect to SMTP server returnstring = "554 Transaction failed: server connect error."; continue; } /* 220 the server line returned here */ int len1; if(!Recv(len1, s, buff, buffsize, 0)) { returnstring = "554 Transaction failed: server connect response error."; continue; } /* get our hostname to pass to the smtp server */ char hn[buffsize] = ""; if(gethostname(hn, buffsize)) { /* no local hostname!!! make one up */ strcpy(hn, "bitmailer"); } /* say hello to the server */ std::string commandline(std::string("EHLO ") + hn + std::string("\r\n")); if(!Send(len1, s, commandline.c_str(), commandline.length(), 0)) { returnstring = "554 Transaction failed: EHLO send"; continue; } /* check for error on EHLO */ if(!Recv(len1, s, buff, buffsize, 0)) { returnstring = "554 Transaction failed: EHLO receipt"; continue; } buff[len1] = '\0'; std::string greeting = returnstring = buff; if(returnstring.substr(0,3) != OK) { if(auth) { /* oops no ESMTP but using authentication no go bail out! */ returnstring = "554 possibly trying to use AUTH without ESMTP server, ERROR!"; continue; } /* maybe we only do non extended smtp, send HELO instead. */ commandline[0] = 'H'; commandline[1] = 'E'; if(!Send(len1, s, commandline.c_str(), commandline.length(), 0)) { returnstring = "554 Transaction failed: HELO send"; continue; } if(!Recv(len1, s, buff, buffsize, 0)) { returnstring = "554 Transaction failed: HELO receipt"; continue;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -