diff options
-rw-r--r-- | include/MailClient.h | 61 | ||||
-rw-r--r-- | include/SocketClient.h | 55 | ||||
-rw-r--r-- | lib/MailClient.cc | 263 | ||||
-rw-r--r-- | lib/SocketClient.cc | 88 |
4 files changed, 467 insertions, 0 deletions
diff --git a/include/MailClient.h b/include/MailClient.h new file mode 100644 index 0000000..60fc735 --- /dev/null +++ b/include/MailClient.h @@ -0,0 +1,61 @@ +/* + * Baltisot + * Copyright (C) 1999-2007 Nicolas "Pixel" Noble + * + * 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 + */ + +/* $Id: MailClient.h,v 1.1 2007-10-12 13:07:42 pixel Exp $ */ + +#ifndef __MAILCLIENT_H__ +#define __MAILCLIENT_H__ + +#include <vector> + +#include <Socket.h> +#include <BString.h> +#include <Task.h> +#include <Handle.h> +#include <SocketClient.h> +#include <Buffer.h> +#include <Exceptions.h> +#include <Variables.h> + +class MailClient : public SocketClient { + public: + typedef std::vector<String> strings_t; + MailClient(const String & smtp, const String & subject, const String & from, strings_t headers, strings_t tos, strings_t ccs, strings_t bccs, strings_t fakes, Handle * body); + virtual ~MailClient(); + + protected: + virtual int Do() throw (GeneralException); + + private: + int readCode(); + void writeEmail(Handle *); + String getEmail(const String &); + String getNext(); + + String smtp, subject, from; + strings_t headers, tos, ccs, bccs, fakes; + Handle * body; + + String msg; + + std::vector<String>::iterator ptr, end; + enum { RCPT_BEGIN, RCPT_TOS, RCPT_CCS, RCPT_BCCS, RCPT_END } cur_rcpt; +}; + +#endif diff --git a/include/SocketClient.h b/include/SocketClient.h new file mode 100644 index 0000000..9078517 --- /dev/null +++ b/include/SocketClient.h @@ -0,0 +1,55 @@ +/* + * Baltisot + * Copyright (C) 1999-2007 Nicolas "Pixel" Noble + * + * 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 + */ + +/* $Id: SocketClient.h,v 1.1 2007-10-12 13:07:42 pixel Exp $ */ + +#ifndef __SOCKETCLIENT_H__ +#define __SOCKETCLIENT_H__ + +#include <vector> + +#include <Socket.h> +#include <BString.h> +#include <Task.h> +#include <Handle.h> +#include <Buffer.h> +#include <Exceptions.h> +#include <Variables.h> + +extern timeval default_socket_timeout; + +class SocketClient : public Task { + public: + virtual ~SocketClient(); + String GetStatus(); + + protected: + SocketClient(const String & host, int port, timeval timeout = default_socket_timeout ); + void subDo() throw (GeneralException); + void SetStatus(const String &); + + Task * c; + String status; + Buffer b; + Socket s; + + timeval timeout; +}; + +#endif diff --git a/lib/MailClient.cc b/lib/MailClient.cc new file mode 100644 index 0000000..380c878 --- /dev/null +++ b/lib/MailClient.cc @@ -0,0 +1,263 @@ +/* + * Baltisot + * Copyright (C) 1999-2007 Nicolas "Pixel" Noble + * + * 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 + */ + +/* $Id: MailClient.cc,v 1.1 2007-10-12 13:07:42 pixel Exp $ */ + +#include <TaskMan.h> +#include <MailClient.h> +#include <BRegex.h> +#include <CopyJob.h> +#include <ReadJob.h> +#include <Variables.h> + +const timeval timeout = { 8, 0 }; + +MailClient::MailClient(const String & _smtp, const String & _subject, const String & _from, strings_t _headers, strings_t _tos, strings_t _ccs, strings_t _bccs, strings_t _fakes, Handle * _body) : SocketClient(_smtp, 25), smtp(_smtp), subject(_subject), from(_from), headers(_headers), tos(_tos), ccs(_ccs), bccs(_bccs), fakes(_fakes), body(_body), cur_rcpt(RCPT_BEGIN) { + SetStatus("Starting"); +} + +MailClient::~MailClient() { +} + +static Regex final_line("^[0-9]{3} "); + +int MailClient::readCode() { + do { + b >> msg; + } while (!final_line.Match(msg)); + + return msg.to_int(); +} + +String MailClient::getEmail(const String & recipient) { + int pos_1, pos_2; + + if ((pos_1 = recipient.strchr('<')) == -1) + return recipient; + + if ((pos_2 = recipient.strrchr('>')) == -1) + return recipient; + + return recipient.extract(pos_1 + 1, pos_2 - 1); +} + +void MailClient::writeEmail(Handle * out) { + String l; + + std::vector<String>::iterator i; + + (*out) << "Subject: " << subject << "\r\n"; + (*out) << "From: " << from << "\r\n"; + + for (i = headers.begin(); i != headers.end(); i++) { + (*out) << *i << "\r\n"; + } + + if (!fakes.empty()) { + (*out) << "To: "; + for (i = fakes.begin(); i != fakes.end(); i++) { + if (i != fakes.begin()) + (*out) << ";"; + (*out) << *i; + } + (*out) << "\r\n"; + } else { + if (!tos.empty()) { + (*out) << "To: "; + for (i = tos.begin(); i != tos.end(); i++) { + if (i != tos.begin()) + (*out) << ";"; + (*out) << *i; + } + (*out) << "\r\n"; + } + if (!ccs.empty()) { + (*out) << "To: "; + for (i = ccs.begin(); i != ccs.end(); i++) { + if (i != ccs.begin()) + (*out) << ";"; + (*out) << *i; + } + (*out) << "\r\n"; + } + if (!bccs.empty()) { + (*out) << "To: "; + for (i = bccs.begin(); i != bccs.end(); i++) { + if (i != bccs.begin()) + (*out) << ";"; + (*out) << *i; + } + (*out) << "\r\n"; + } + } + + (*out) << "\r\n"; + + while (!body->IsClosed()) { + (*body) >> l; + + if (l[0] == '.') + (*out) << "."; + + (*out) << l << "\r\n"; + } + (*out) << ".\r\n"; +} + +String MailClient::getNext() { + if (cur_rcpt == RCPT_BEGIN) { + ptr = tos.begin(); + end = tos.end(); + cur_rcpt = RCPT_TOS; + } + + while (ptr == end) { + switch (cur_rcpt) { + case RCPT_TOS: + cur_rcpt = RCPT_CCS; + ptr = ccs.begin(); + end = ccs.end(); + break; + case RCPT_CCS: + cur_rcpt = RCPT_BCCS; + ptr = bccs.begin(); + end = bccs.end(); + break; + case RCPT_BCCS: + cur_rcpt = RCPT_END; + return "**END**"; + } + } + + return *(ptr++); +} + +int MailClient::Do() throw (GeneralException) { + int code; + std::vector<String>::iterator i; + String n; + + subDo(); + switch (current) { + case 0: + WaitFor(c = new ReadJob(&s, &b, final_line)); + current = 1; + Suspend(TASK_ON_HOLD); + + case 1: + if (readCode() != 220) { + status = "Can not establish connection: " + msg; + return TASK_DONE; + } + + b << "EHLO foobar\r\n"; + WaitFor(c = new CopyJob(&b, &s)); + current = 2; + Suspend(TASK_ON_HOLD); + + case 2: + WaitFor(c = new ReadJob(&s, &b, final_line)); + current = 3; + Suspend(TASK_ON_HOLD); + + case 3: + if (readCode() != 250) { + status = "SMTP server rejected our EHLO: " + msg; + return TASK_DONE; + } + + b << "MAIL FROM: " << getEmail(from) << "\r\n"; + WaitFor(c = new CopyJob(&b, &s)); + current = 4; + Suspend(TASK_ON_HOLD); + + case 4: + WaitFor(c = new ReadJob(&s, &b, final_line)); + current = 5; + Suspend(TASK_ON_HOLD); + + case 5: + if (readCode() != 250) { + if (cur_rcpt == RCPT_BEGIN) { + status = "SMTP server rejected our MAIL FROM: " + msg; + return TASK_DONE; + // } else { // SMTP server rejecter one RCPT TO, nevermind it. + } + } + + n = getNext(); + + if (cur_rcpt != RCPT_END) { + b << "RCPT TO: " << n << "\r\n"; + WaitFor(c = new CopyJob(&b, &s)); + current = 4; + Suspend(TASK_ON_HOLD); + } + + b << "DATA\r\n"; + WaitFor(c = new CopyJob(&b, &s)); + current = 6; + Suspend(TASK_ON_HOLD); + + case 6: + WaitFor(c = new ReadJob(&s, &b, final_line)); + current = 7; + Suspend(TASK_ON_HOLD); + + case 7: + if (readCode() != 354) { + status = "SMTP rejected our DATA command: " + msg; + return TASK_DONE; + } + + writeEmail(&b); + WaitFor(c = new CopyJob(&b, &s)); + current = 8; + Suspend(TASK_ON_HOLD); + + case 8: + WaitFor(c = new ReadJob(&s, &b, final_line)); + current = 9; + Suspend(TASK_ON_HOLD); + + case 9: + if (readCode() != 250) { + status = "SMTP rejected our mail: " + msg; + return TASK_DONE; + } + + b << "QUIT\n\r"; + WaitFor(c = new CopyJob(&b, &s)); + current = 10; + Suspend(TASK_ON_HOLD); + + case 10: + WaitFor(c = new ReadJob(&s, &b, final_line)); + current = 11; + Suspend(TASK_ON_HOLD); + + case 11: + if (readCode() != 221) + status = "SMTP wasn't pleased by our QUIT command: " + msg; + + status = "Mail sent."; + + return TASK_DONE; + } +} diff --git a/lib/SocketClient.cc b/lib/SocketClient.cc new file mode 100644 index 0000000..a86629a --- /dev/null +++ b/lib/SocketClient.cc @@ -0,0 +1,88 @@ +/* + * Baltisot + * Copyright (C) 1999-2007 Nicolas "Pixel" Noble + * + * 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 + */ + +/* $Id: SocketClient.cc,v 1.1 2007-10-12 13:07:42 pixel Exp $ */ + +#include <TaskMan.h> +#include <SocketClient.h> +#include <BRegex.h> +#include <CopyJob.h> +#include <ReadJob.h> +#include <Variables.h> + +timeval default_socket_timeout = { 8, 0 }; + +SocketClient::SocketClient(const String & host, int port, timeval _timeout) : timeout(_timeout) { + s.SetNonBlock(); + s.Connect(host, 25); + + if (s.IsConnected()) { + SetBurst(); + } else { + WaitFor(timeout); + WaitFor(&s, W4_WRITING); + } +} + +SocketClient::~SocketClient() { +} + +String SocketClient::GetStatus() { + return status; +} + +void SocketClient::SetStatus(const String & _status) { + status = _status; +} + +void SocketClient::subDo() throw (GeneralException) { + switch (current) { + case 0: + if (s.IsConnecting() && (TaskMan::Event() == Task::EVT_HANDLE)) { + s.FinalizeConnect(); + } + if (TaskMan::Event() == Task::EVT_TIMEOUT) { + status = "Connection timeout"; + Suspend(TASK_DONE); + } + if (!s.IsConnected()) { + status = "Connection failed"; + Suspend(TASK_DONE); + } + RemoveTimeout(); + + WaitFor(timeout); + return; + + default: + if (c) + delete c; + + c = 0; + + if (TaskMan::Event() == Task::Task::EVT_TIMEOUT) { + status = "Connection timeout."; + Suspend(TASK_DONE); + } + RemoveTimeout(); + + WaitFor(timeout); + return; + } +} |