summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/MailClient.h61
-rw-r--r--include/SocketClient.h55
-rw-r--r--lib/MailClient.cc263
-rw-r--r--lib/SocketClient.cc88
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;
+ }
+}