// nullmailer -- a simple relay-only MTA // Copyright (C) 1999-2003 Bruce Guenter // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // You can contact me at . There is also a mailing list // available to discuss this package. To subscribe, send an email to // . #include "config.h" #include #include #include "errcodes.h" #include "fdbuf/fdbuf.h" #include "hostname.h" #include "itoa.h" #include "mystring/mystring.h" #include "netstring.h" #include "protocol.h" int port = 628; const char* cli_program = "qmqp"; const char* cli_help_prefix = "Send an emal message via QMQP\n"; class qmqp { fdibuf in; fdobuf out; public: qmqp(int fd); ~qmqp(); void send(fdibuf* msg, unsigned long size, const mystring& env); }; qmqp::qmqp(int fd) : in(fd), out(fd) { } qmqp::~qmqp() { } bool skip_envelope(fdibuf* msg) { if(!msg->rewind()) return false; mystring tmp; while(msg->getline(tmp)) if(!tmp) break; return msg; } void qmqp::send(fdibuf* msg, unsigned long size, const mystring& env) { if(!skip_envelope(msg)) protocol_fail(ERR_MSG_READ, "Error re-reading message"); unsigned long fullsize = strlen(itoa(size)) + 1 + size + 1 + env.length(); out << itoa(fullsize) << ":"; // Start the "outer" netstring out << itoa(size) << ":"; // Start the message netstring fdbuf_copy(*msg, out, true); // Send out the message out << "," // End the message netstring << env // The envelope is already encoded << ","; // End the "outer" netstring if(!out.flush()) protocol_fail(ERR_MSG_WRITE, "Error sending message to remote"); mystring response; if(!in.getnetstring(response)) protocol_fail(ERR_PROTO, "Response from remote was not a netstring"); switch(response[0]) { case 'K': protocol_succ(response.c_str()+1); break; case 'Z': protocol_fail(ERR_MSG_TEMPFAIL, response.c_str()+1); break; case 'D': protocol_fail(ERR_MSG_PERMFAIL, response.c_str()+1); break; default: protocol_fail(ERR_PROTO, "Invalid status byte in response"); } } bool compute_size(fdibuf* msg, unsigned long& size) { char buf[4096]; size = 0; while(msg->read(buf, 4096)) size += msg->last_count(); if(msg->eof()) size += msg->last_count(); return size > 0; } bool make_envelope(fdibuf* msg, mystring& env) { mystring tmp; while(msg->getline(tmp)) { if(!tmp) return true; env += str2net(tmp); } return false; } bool preload_data(fdibuf* msg, unsigned long& size, mystring& env) { return make_envelope(msg, env) && compute_size(msg, size); } static unsigned long msg_size; static mystring msg_envelope; void protocol_prep(fdibuf* in) { if(!preload_data(in, msg_size, msg_envelope)) protocol_fail(ERR_MSG_READ, "Error reading message"); } void protocol_send(fdibuf* in, int fd) { alarm(60*60); // Connection must close after an hour qmqp conn(fd); conn.send(in, msg_size, msg_envelope); }