1 // src/SmtpClient.cc 2 // This file is part of libpbe; see http://decimail.org 3 // (C) 2004 Philip Endecott 4 5 // This program is free software; you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation; either version 2 of the License, or 8 // any later version. 9 // 10 // This program is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with this program; if not, write to the Free Software 17 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 #include "SmtpClient.hh" 19 20 #include "ip.hh" 21 #include "select.hh" 22 23 #include <syslog.h> 24 #include <unistd.h> 25 #include <stdio.h> 26 27 #ifdef __OpenBSD__ 28 // Is this really needed? 29 #include <sys/types.h> 30 #endif 31 32 using namespace std; 33 using namespace pbe; 34 35 report(ostream & s) const36 void SmtpError::report(ostream& s) const 37 { 38 s << msg; 39 } 40 41 SmtpClient(bool log)42 SmtpClient::SmtpClient(bool log): enable_log(log), connected(false) 43 {} 44 45 connect(string server_name,string domain,int port)46 void SmtpClient::connect(string server_name, string domain, int port) 47 { 48 fd = tcp_client_connect(server_name, port); 49 50 wait_for_reply(220,300); 51 send("EHLO "+domain); 52 wait_for_reply(250,300); 53 54 connected=true; 55 } 56 57 wait_for_reply(int expected_code,int timeout)58 void SmtpClient::wait_for_reply(int expected_code, int timeout) 59 { 60 if (select_rt(fd,timeout)==-1) { 61 throw SmtpError("Timeout"); 62 } 63 char buf[513]; 64 int n=0; 65 while (1) { 66 int c = read(fd,buf+n,sizeof(buf)-n); 67 buf[n+c+1]='\0'; 68 if (enable_log) { 69 syslog(LOG_MAIL|LOG_DEBUG,"SmtpClient:S: %s",buf); 70 } 71 if (c==-1) { 72 throw_ErrnoException("read()"); 73 } 74 n += c; 75 if (buf[n-1]=='\n') { 76 break; 77 } 78 if (n==sizeof(buf)) { 79 throw SmtpError("Command line did not terminate"); 80 } 81 } 82 int code; 83 int rc = sscanf(buf,"%d",&code); 84 if (rc!=1) { 85 throw SmtpError("No reply code at start of line"); 86 } 87 if (code != expected_code) { 88 throw SmtpError("Unexpected reply: \'"+string(buf)+"\'"); 89 } 90 } 91 92 send(string d)93 void SmtpClient::send(string d) 94 { 95 if (enable_log) { 96 syslog(LOG_MAIL|LOG_DEBUG,"SmtpClient:C: %s",d.c_str()); 97 } 98 d.append("\r\n"); 99 // ought to impose a timeout on these writes 100 const char* p = d.data(); 101 int n = d.length(); 102 int c = 0; 103 while(c<n) { 104 int rc = write(fd,p+c,n-c); 105 if (rc==-1) { 106 throw_ErrnoException("write()"); 107 } 108 c += rc; 109 } 110 } 111 112 send_msg(string sender,string recipient,string msg)113 void SmtpClient::send_msg(string sender, string recipient, string msg) 114 { 115 list<string> recipients; 116 recipients.push_back(recipient); 117 send_msg(sender, recipients, msg); 118 } 119 120 send_msg(string sender,const list<string> & recipients,string msg)121 void SmtpClient::send_msg(string sender, const list<string>& recipients, 122 string msg) 123 { 124 send("MAIL FROM:<"+sender+">"); 125 wait_for_reply(250,300); 126 for (list<string>::const_iterator i = recipients.begin(); 127 i != recipients.end(); ++i) { 128 send("RCPT TO:<"+*i+">"); 129 wait_for_reply(250,300); // could get 251 as well 130 } 131 send("DATA"); 132 wait_for_reply(354,120); 133 send(msg); 134 send("."); 135 wait_for_reply(250,600); 136 } 137 138 disconnect(void)139 void SmtpClient::disconnect(void) 140 { 141 send("QUIT"); 142 wait_for_reply(221,300); 143 int rc = close(fd); 144 if (rc==-1) { 145 throw_ErrnoException("close()"); 146 } 147 connected=false; 148 } 149