mailer_class.cpp.svn-base

来自「这是一个很好的参考代码」· SVN-BASE 代码 · 共 1,379 行 · 第 1/3 页

SVN-BASE
1,379
字号
#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 + =
减小字号Ctrl + -
显示快捷键?