Move to new Build System

This commit is contained in:
2020-05-01 10:21:46 +02:00
parent 4ee3f56bd7
commit 1a464d85cf
51 changed files with 1088 additions and 1101 deletions
+13 -2
View File
@@ -1,3 +1,14 @@
*.o
*.o.*
*.d.*
*.a.*
.*.swp
AlarmServer
.AppleDouble
.debug
.gdbinit*
gdb*
core-*
*-core
core.*
*.core
AlarmServer*
!AlarmServer.cc
+3
View File
@@ -0,0 +1,3 @@
[submodule "Makefiles"]
path = Makefiles
url = https://gogs.dierkse.nl/JDierkse/Makefiles.git
+5 -5
View File
@@ -1,8 +1,9 @@
#include <iostream>
#include "MailServer/Server.h"
#include <asio.hpp>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include "server.h"
#include <iostream>
int main(int argc, char* argv[])
@@ -35,9 +36,9 @@ int main(int argc, char* argv[])
return 1;
}
boost::asio::io_service io_service;
asio::io_service io_service;
server s(io_service, port, path, url);
MailServer::Server s(io_service, port, path, url);
io_service.run();
}
@@ -46,4 +47,3 @@ int main(int argc, char* argv[])
std::cerr << "Exception: " << e.what() << std::endl;
}
}
+1
View File
@@ -0,0 +1 @@
../Makefile
+30 -26
View File
@@ -1,58 +1,60 @@
#include "inputImage.h"
#include "JpegImage.h"
namespace Image {
const static JOCTET EOI_BUFFER[1] = { JPEG_EOI };
inputImage::inputImage()
JpegImage::JpegImage()
{
}
void inputImage::setImageData(const std::string& data)
void JpegImage::SetImageData(const std::string& data)
{
decompressImage(data.c_str(), data.size());
DecompressImage(data.c_str(), data.size());
}
unsigned int inputImage::width() const
unsigned int JpegImage::Width() const
{
return m_width;
}
unsigned int inputImage::height() const
unsigned int JpegImage::Height() const
{
return m_height;
}
unsigned int inputImage::strideX() const
unsigned int JpegImage::StrideX() const
{
return m_strideX;
}
unsigned int inputImage::strideY() const
unsigned int JpegImage::StrideY() const
{
return m_strideY;
}
const std::vector<char>& inputImage::data() const
const std::vector<char>& JpegImage::Data() const
{
return m_data;
}
void inputImage::init_source(j_decompress_ptr pCinfo)
void JpegImage::InitSource(j_decompress_ptr pCinfo)
{
}
boolean inputImage::fill_input_buffer(j_decompress_ptr pCinfo)
boolean JpegImage::FillInputBuffer(j_decompress_ptr pCinfo)
{
source_mgr_ptr pSrc = reinterpret_cast<source_mgr_ptr>(pCinfo->src);
SourceMgrPtr pSrc = reinterpret_cast<SourceMgrPtr>(pCinfo->src);
pSrc->pub.next_input_byte = EOI_BUFFER;
pSrc->pub.bytes_in_buffer = 1;
return TRUE;
}
void inputImage::skip_input_data(j_decompress_ptr pCinfo, long numBytes)
void JpegImage::SkipInputData(j_decompress_ptr pCinfo, long numBytes)
{
source_mgr_ptr pSrc = reinterpret_cast<source_mgr_ptr>(pCinfo->src);
if (pSrc->pub.bytes_in_buffer < numBytes)
SourceMgrPtr pSrc = reinterpret_cast<SourceMgrPtr>(pCinfo->src);
if (pSrc->pub.bytes_in_buffer < static_cast<size_t>(numBytes))
{
pSrc->pub.next_input_byte = EOI_BUFFER;
pSrc->pub.bytes_in_buffer = 1;
@@ -64,22 +66,22 @@ void inputImage::skip_input_data(j_decompress_ptr pCinfo, long numBytes)
}
}
void inputImage::term_source(j_decompress_ptr pCinfo)
void JpegImage::TermSource(j_decompress_ptr pCinfo)
{
}
void inputImage::setSourceMgr(j_decompress_ptr pCinfo, const char* pData, size_t len) const
void JpegImage::SetSourceMgr(j_decompress_ptr pCinfo, const char* pData, size_t len) const
{
source_mgr_ptr pSrc;
SourceMgrPtr pSrc;
if (pCinfo->src == 0)
pCinfo->src = (struct jpeg_source_mgr *)(*pCinfo->mem->alloc_small)(reinterpret_cast<j_common_ptr>(pCinfo), JPOOL_PERMANENT, sizeof(source_mgr));
pCinfo->src = (struct jpeg_source_mgr *)(*pCinfo->mem->alloc_small)(reinterpret_cast<j_common_ptr>(pCinfo), JPOOL_PERMANENT, sizeof(SourceMgr));
pSrc = reinterpret_cast<source_mgr_ptr>(pCinfo->src);
pSrc->pub.init_source = inputImage::init_source;
pSrc->pub.fill_input_buffer = inputImage::fill_input_buffer;
pSrc->pub.skip_input_data = inputImage::skip_input_data;
pSrc = reinterpret_cast<SourceMgrPtr>(pCinfo->src);
pSrc->pub.init_source = JpegImage::InitSource;
pSrc->pub.fill_input_buffer = JpegImage::FillInputBuffer;
pSrc->pub.skip_input_data = JpegImage::SkipInputData;
pSrc->pub.resync_to_restart = jpeg_resync_to_restart;
pSrc->pub.term_source = inputImage::term_source;
pSrc->pub.term_source = JpegImage::TermSource;
pSrc->data = (const JOCTET *)pData;
pSrc->len = len;
@@ -87,7 +89,7 @@ void inputImage::setSourceMgr(j_decompress_ptr pCinfo, const char* pData, size_t
pSrc->pub.next_input_byte = pSrc->data;
}
void inputImage::decompressImage(const char* pData, size_t len)
void JpegImage::DecompressImage(const char* pData, size_t len)
{
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
@@ -95,7 +97,7 @@ void inputImage::decompressImage(const char* pData, size_t len)
jerr.trace_level = 0;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo);
setSourceMgr(&cinfo, pData, len);
SetSourceMgr(&cinfo, pData, len);
jpeg_read_header(&cinfo, TRUE);
jpeg_start_decompress(&cinfo);
@@ -118,3 +120,5 @@ void inputImage::decompressImage(const char* pData, size_t len)
jpeg_destroy_decompress(&cinfo);
}
} // namespace Image
+54
View File
@@ -0,0 +1,54 @@
#ifndef JPEGIMAGE_H
#define JPEGIMAGE_H
#include <string>
#include <vector>
#include <jpeglib.h>
namespace Image {
class JpegImage
{
public:
JpegImage();
void SetImageData(const std::string& data);
unsigned int Width() const;
unsigned int Height() const;
unsigned int StrideX() const;
unsigned int StrideY() const;
const std::vector<char>& Data() const;
private:
struct SourceMgr
{
struct jpeg_source_mgr pub;
const JOCTET *data;
size_t len;
};
typedef SourceMgr* SourceMgrPtr;
private:
static void InitSource(j_decompress_ptr pCinfo);
static boolean FillInputBuffer(j_decompress_ptr pCinfo);
static void SkipInputData(j_decompress_ptr pCinfo, long numBytes);
static void TermSource(j_decompress_ptr pCinfo);
void SetSourceMgr(j_decompress_ptr pCinfo, const char* pData, size_t len) const;
void DecompressImage(const char* pData, size_t len);
private:
unsigned int m_width;
unsigned int m_height;
unsigned int m_strideX;
unsigned int m_strideY;
std::vector<char> m_data;
};
} // namespace Image
#endif // JPEGIMAGE_H
@@ -1,8 +1,10 @@
#include <stdio.h>
#include "outputImage.h"
#include "JpegImageCollection.h"
outputImage::outputImage(const std::vector<inputImage>& images) :
namespace Image {
JpegImageCollection::JpegImageCollection(const std::vector<JpegImage>& images) :
m_width(0),
m_height(0),
m_strideX(0),
@@ -11,20 +13,20 @@ outputImage::outputImage(const std::vector<inputImage>& images) :
if (images.size() == 0)
return;
m_width = images[0].width();
m_strideX = images[0].strideX();
m_strideY = images[0].strideY();
m_width = images[0].Width();
m_strideX = images[0].StrideX();
m_strideY = images[0].StrideY();
size_t height = images[0].height();
size_t height = images[0].Height();
m_height = height * images.size();
m_imageData.resize(m_strideY * m_height);
std::vector<char>::iterator outIterator = m_imageData.begin();
for (std::vector<inputImage>::const_iterator it = images.begin(); it != images.end(); ++it)
outIterator = std::copy(it->data().begin(), it->data().end(), outIterator);
for (std::vector<JpegImage>::const_iterator it = images.begin(); it != images.end(); ++it)
outIterator = std::copy(it->Data().begin(), it->Data().end(), outIterator);
}
void outputImage::save(const std::string& fileName)
void JpegImageCollection::Save(const std::string& fileName)
{
if (m_width == 0 || m_height == 0 || m_strideX == 0 || m_strideY == 0)
return;
@@ -62,3 +64,4 @@ void outputImage::save(const std::string& fileName)
fclose(outFile);
}
} // namespace Image
@@ -3,15 +3,17 @@
#include <string>
#include <vector>
#include "inputImage.h"
#include "JpegImage.h"
class outputImage
namespace Image {
class JpegImageCollection
{
public:
outputImage(const std::vector<inputImage>& images);
JpegImageCollection(const std::vector<JpegImage>& images);
void save(const std::string& fileName);
void Save(const std::string& fileName);
private:
size_t m_width;
@@ -22,5 +24,6 @@ private:
std::vector<char> m_imageData;
};
#endif // OUTPUTIMAGE_H
} // namespace Image
#endif // OUTPUTIMAGE_H
+1
View File
@@ -0,0 +1 @@
../Makefile
+34
View File
@@ -0,0 +1,34 @@
#include "MimeImage.h"
#include "Util/Base64.h"
#include <StringAlgorithm.h>
#include <fstream>
namespace Image {
MimeImage::MimeImage()
{
}
MimeImage::MimeImage(const std::string& name) :
m_name(name)
{
}
void MimeImage::AppendData(const std::string& data)
{
if (data.empty())
return;
m_imageData.append(data);
}
const JpegImage& MimeImage::DecodeImageData()
{
StringAlgorithm::erase_all(m_imageData, '\r');
m_jpegImage.SetImageData(Util::Base64::Decode(m_imageData));
return m_jpegImage;
}
} // namespace Image
+26
View File
@@ -0,0 +1,26 @@
#ifndef MIMEIMAGE_H
#define MIMEIMAGE_H
#include "JpegImage.h"
namespace Image {
class MimeImage
{
public:
MimeImage();
MimeImage(const std::string& name);
void AppendData(const std::string& data);
const JpegImage& DecodeImageData();
private:
std::string m_name;
std::string m_imageData;
JpegImage m_jpegImage;
};
} // namespace Image
#endif // MIMEIMAGE_H
+1
View File
@@ -0,0 +1 @@
../../Libraries/Http
+1
View File
@@ -0,0 +1 @@
../../Libraries/Logging
+1
View File
@@ -0,0 +1 @@
../../Libraries/Utilities
+1
View File
@@ -0,0 +1 @@
../../Libraries/asio
+1
View File
@@ -0,0 +1 @@
../../Libraries/filesystem
+61
View File
@@ -0,0 +1,61 @@
#include "Connection.h"
#include <functional>
#include <sstream>
namespace MailServer {
Connection::Connection(asio::io_service& ioService, const Util::Context& context) :
m_ioService(ioService),
m_socket(ioService),
m_protocol(context)
{
}
asio::ip::tcp::socket& Connection::Socket()
{
return m_socket;
}
void Connection::Start()
{
StartWrite(m_protocol.OpenConnection(m_socket.remote_endpoint().address().to_string()).second);
}
void Connection::StartRead()
{
m_socket.async_read_some(asio::buffer(m_data), std::bind(&Connection::HandleRead, this, std::placeholders::_1, std::placeholders::_2));
}
void Connection::HandleRead(const asio::error_code& ec, std::size_t length)
{
if (!ec)
{
Protocol::Protocol::Result result = m_protocol.ProcessMessage(std::string(m_data.begin(), m_data.begin() + length));
if (result.second.size() > 0)
StartWrite(result.second);
else
StartRead();
if (result.first == Protocol::Protocol::State::Disconnected)
m_socket.close();
}
}
void Connection::StartWrite(const std::string& message)
{
std::copy(message.begin(), message.end(), m_data.data());
size_t length = message.size() + 1;
m_data[message.size()] = '\n';
asio::async_write(m_socket, asio::buffer(m_data, length), std::bind(&Connection::HandleWrite, this, std::placeholders::_1));
}
void Connection::HandleWrite(const asio::error_code& ec)
{
if (!ec)
StartRead();
}
} // namespace MailServer
+40
View File
@@ -0,0 +1,40 @@
#ifndef CONNECTION_H
#define CONNECTION_H
#include "Protocol/Protocol.h"
#include "Util/Util.h"
#include <asio.hpp>
#include <string>
namespace MailServer {
class Connection
{
public:
Connection(asio::io_service& ioService, const Util::Context& context);
asio::ip::tcp::socket& Socket();
void Start();
private:
Connection(const Connection&) = delete;
Connection& operator=(const Connection&) = delete;
private:
void StartRead();
void HandleRead(const asio::error_code& ec, std::size_t length);
void StartWrite(const std::string& message);
void HandleWrite(const asio::error_code& ec);
asio::io_service& m_ioService;
asio::ip::tcp::socket m_socket;
std::array<char, 1024> m_data;
Protocol::Protocol m_protocol;
};
} // namespace MailServer
#endif // CONNECTION_H
+1
View File
@@ -0,0 +1 @@
../Makefile
+219
View File
@@ -0,0 +1,219 @@
#include "Message.h"
#include "Image/JpegImageCollection.h"
#include "Util/Base64.h"
#include <Logging.h>
#include <StringAlgorithm.h>
#include <filesystem/path.h>
#include <sstream>
namespace MailServer {
Message::Message(const std::string& address, const Util::Context& context, const std::string& message) :
m_address(address),
m_context(context),
m_mimeBoundary("-_-InvalidBoundary-_-"),
m_contentEncoding("none"),
m_currentImage(0)
{
ProcessMessage(message);
}
std::string Decode(const std::string& data)
{
std::string result;
if (StringAlgorithm::istarts_with(data, "=?utf-8?"))
result = Util::Base64::Decode(std::string(data.begin() + 10, data.begin() + data.find_last_of('?')));
else
result = Util::Base64::Decode(data);
return result;
}
void Message::ProcessMessage(const std::string& message)
{
try
{
Message::State::type state = Message::State::Header;
std::string line;
std::istringstream stream(message);
while (std::getline(stream, line, '\r'))
{
StringAlgorithm::erase_all(line, '\n');
switch (state)
{
case State::Header:
state = ProcessHeaderLine(line);
break;
case State::Data:
state = ProcessDataLine(line);
break;
case State::MimeBoundary:
state = ProcessMimeBoundary(line);
break;
case State::Image:
state = ProcessImage(line);
break;
}
}
if (StringAlgorithm::contains(m_contentEncoding, "base64"))
{
std::string decoded = Decode(m_subject);
if (decoded.size() > 0)
m_subject = decoded;
}
std::stringstream ss;
ss << "From: " << m_sender << std::endl;
Logging::Log(Logging::Severity::Debug, ss.str());
ss.str("");
ss << "To: " << m_receiver << std::endl;
Logging::Log(Logging::Severity::Debug, ss.str());
ss.str("");
ss << "Subject: " << m_subject << std::endl;
Logging::Log(Logging::Severity::Debug, ss.str());
ss.str("");
ss << "Received " << m_images.size() << " Images" << std::endl;
Logging::Log(Logging::Severity::Info, ss.str());
Image::JpegImageCollection imageCollection(m_images);
filesystem::path path(m_context.path);
path = path.make_absolute();
path = path/filesystem::path(m_address);
if (!path.exists())
filesystem::create_directory(path);
std::string fileName(Util::getTimeString());
fileName.append(".jpg");
path = path/filesystem::path(fileName);
imageCollection.Save(path.str());
ss.str("");
ss << "Images Stored as " << path.str() << std::endl;
Logging::Log(Logging::Severity::Info, ss.str());
if (!m_context.url.empty())
{
std::stringstream url;
url << m_context.url << "?ip=" << m_address << "&file=" << fileName;
m_context.client.GetUrlContents(url.str());
}
}
catch (std::exception& e)
{
std::stringstream ss;
ss << "Message::ProcessMessage() - Error: " << e.what() << std::endl;
Logging::Log(Logging::Severity::Error, ss.str());
}
}
Message::State::type Message::ProcessHeaderLine(const std::string& line)
{
if (line.empty())
return Message::State::Data;
if (StringAlgorithm::istarts_with(line, "from:"))
{
m_sender = std::string(line.begin() + line.find_first_of(' ') + 1, line.end());
return Message::State::Header;
}
if (StringAlgorithm::istarts_with(line, "to:"))
{
m_receiver = std::string(line.begin() + line.find_first_of(' ') + 1, line.end());
return Message::State::Header;
}
if (StringAlgorithm::istarts_with(line, "subject:"))
{
m_subject = std::string(line.begin() + line.find_first_of(' ') + 1, line.end());
return Message::State::Header;
}
if (StringAlgorithm::istarts_with(line, "date"))
{
m_date = std::string(line.begin() + line.find_first_of(' ') + 1, line.end());
return Message::State::Header;
}
if (StringAlgorithm::istarts_with(line, "content-type:"))
{
m_contentType = std::string(line.begin() + line.find_first_of(' ') + 1, line.end());
return Message::State::Header;
}
if (StringAlgorithm::istarts_with(line, "boundary") || StringAlgorithm::istarts_with(line, "\tboundary") || StringAlgorithm::istarts_with(line, " boundary"))
{
m_mimeBoundary = std::string("--").append(std::string(line.begin() + line.find_first_of('"') + 1, line.begin() + line.find_last_of('"')));
return Message::State::Header;
}
if (StringAlgorithm::istarts_with(line, "content-transfer-encoding:"))
{
m_contentEncoding = std::string(line.begin() + line.find_first_of(' ') + 1, line.end());
return Message::State::Header;
}
return Message::State::Header;
}
Message::State::type Message::ProcessDataLine(const std::string& line)
{
if (StringAlgorithm::istarts_with(line, m_mimeBoundary))
{
m_contentType = "";
return Message::State::MimeBoundary;
}
return Message::State::Data;
}
Message::State::type Message::ProcessMimeBoundary(const std::string& line)
{
if (line.empty())
{
if (StringAlgorithm::istarts_with(m_contentType, "image/jpeg") || StringAlgorithm::istarts_with(m_contentType, "image/jpg"))
{
m_mimeImages.push_back(Image::MimeImage(m_imageName));
m_imageName = "";
return Message::State::Image;
}
return Message::State::Data;
}
if (StringAlgorithm::istarts_with(line, "content-type:"))
{
m_contentType = std::string(line.begin() + line.find_first_of(' ') + 1, line.end());
return Message::State::MimeBoundary;
}
if (StringAlgorithm::istarts_with(line, "name") || StringAlgorithm::istarts_with(line, "\tname"))
{
m_imageName = "image.jpg";
//m_imageName = Decode(std::string(line.begin() + line.find_first_of('"') + 1, line.begin() + line.find_last_of('"')));
return Message::State::MimeBoundary;
}
if (StringAlgorithm::istarts_with(line, "content-transfer-encoding:"))
{
m_contentEncoding = std::string(line.begin() + line.find_first_of(' ') + 1, line.end());
return Message::State::MimeBoundary;
}
return Message::State::MimeBoundary;
}
Message::State::type Message::ProcessImage(const std::string& line)
{
if (StringAlgorithm::istarts_with(line, m_mimeBoundary))
{
m_images.push_back(m_mimeImages[m_currentImage].DecodeImageData());
++m_currentImage;
m_contentType = "";
return Message::State::MimeBoundary;
}
m_mimeImages[m_currentImage].AppendData(line);
return Message::State::Image;
}
} // namespace MailServer
+60
View File
@@ -0,0 +1,60 @@
#ifndef MESSAGE_H
#define MESSAGE_H
#include "Image/MimeImage.h"
#include "Image/JpegImage.h"
#include "Util/Util.h"
#include <string>
#include <vector>
namespace MailServer {
class Message
{
public:
Message(const std::string& address, const Util::Context& context, const std::string& message);
private:
class State
{
public:
enum type
{
Header,
Data,
MimeBoundary,
Image
};
};
private:
void ProcessMessage(const std::string& message);
State::type ProcessHeaderLine(const std::string& line);
State::type ProcessDataLine(const std::string& line);
State::type ProcessMimeBoundary(const std::string& line);
State::type ProcessImage(const std::string& line);
private:
std::string m_address;
const Util::Context& m_context;
std::string m_sender;
std::string m_receiver;
std::string m_subject;
std::string m_date;
std::string m_mimeBoundary;
std::string m_contentType;
std::string m_contentEncoding;
size_t m_currentImage;
std::string m_imageName;
std::vector<Image::MimeImage> m_mimeImages;
std::vector<Image::JpegImage> m_images;
};
} // namespace MailServer
#endif // MESSAGE_H
+81
View File
@@ -0,0 +1,81 @@
#include "Server.h"
#include <Logging.h>
#include <functional>
#include <sstream>
#include <sys/wait.h>
namespace MailServer {
Server::Server(asio::io_service& ioService, unsigned short port, const std::string& path, const std::string& url) :
m_ioService(ioService),
m_signal(ioService, SIGCHLD),
m_acceptor(ioService, asio::ip::tcp::endpoint(asio::ip::tcp::v4(), port)),
m_socket(ioService)
{
m_context.path = path;
m_context.url = url;
StartSignalWait();
StartAccept();
}
void Server::StartSignalWait()
{
m_signal.async_wait(std::bind(&Server::HandleSignalWait, this));
}
void Server::HandleSignalWait()
{
// Only the parent process should check for this signal. We can determine
// whether we are in the parent by checking if the acceptor is still open.
if (m_acceptor.is_open())
{
// Reap completed child processes so that we don't end up with zombies.
int status = 0;
while (waitpid(-1, &status, WNOHANG) > 0) {}
StartSignalWait();
}
}
void Server::StartAccept()
{
m_connection.reset(new Connection(m_ioService, m_context));
m_acceptor.async_accept(m_connection->Socket(), std::bind(&Server::HandleAccept, this, std::placeholders::_1));
}
void Server::HandleAccept(const asio::error_code& ec)
{
if (!ec)
{
m_ioService.notify_fork(asio::io_service::fork_prepare);
if (fork() == 0)
{
m_ioService.notify_fork(asio::io_service::fork_child);
m_acceptor.close();
m_signal.cancel();
m_connection->Start();
}
else
{
m_ioService.notify_fork(asio::io_service::fork_parent);
m_connection.reset();
m_socket.close();
StartAccept();
}
}
else
{
std::stringstream ss;
ss << "Server::HandleAccept() - Error" << std::endl;
Logging::Log(Logging::Severity::Error, ss.str());
StartAccept();
}
}
} // namespace MailServer
+35
View File
@@ -0,0 +1,35 @@
#ifndef SERVER_H
#define SERVER_H
#include "Connection.h"
#include "Util/Util.h"
#include <asio.hpp>
#include <memory>
#include <string>
namespace MailServer {
class Server
{
public:
Server(asio::io_service& ioService, unsigned short port, const std::string& path, const std::string& url);
private:
void StartSignalWait();
void HandleSignalWait();
void StartAccept();
void HandleAccept(const asio::error_code& ec);
asio::io_service& m_ioService;
asio::signal_set m_signal;
asio::ip::tcp::acceptor m_acceptor;
asio::ip::tcp::socket m_socket;
std::shared_ptr<Connection> m_connection;
Util::Context m_context;
};
} // namespace MailServer
#endif // SERVER_H
-51
View File
@@ -1,51 +0,0 @@
CC := g++
CFLAGS := -O3
LFLAGS := -L/opt/lib -lpthread -lcrypto -lcurl -lboost_regex -lboost_filesystem -lboost_system -ljpeg
ifeq ($(BUILD),debug)
# Debug flags
CFLAGS += -O0 -g
endif
ifeq ($(BUILD),release)
# Optimization flags valid for Intel Atom (DS1813+)
CFLAGS += -march=prescott -mtune=pentium -mfpmath=sse -O3 -s -DNDEBUG
endif
%.o: %.cpp
$(CC) -c $(CFLAGS) $< -o $@
AlarmServer: main.cpp server.o connection.o protocol.o message.o mimeImage.o outputImage.o inputImage.o util.o httpClient.o base64.o
g++ -o AlarmServer main.cpp server.o connection.o protocol.o message.o mimeImage.o outputImage.o inputImage.o util.o httpClient.o base64.o $(LFLAGS) $(LDFLAGS) $(CFLAGS)
server.o: server.cpp server.h connection.h protocol.h util.h httpClient.h
connection.o: connection.cpp connection.h protocol.h util.h httpClient.h
protocol.o: protocol.cpp protocol.h util.h httpClient.h
message.o: message.cpp message.h mimeImage.h outputImage.h inputImage.h util.h httpClient.h base64.h
mimeImage.o: mimeImage.cpp mimeImage.h outputImage.h inputImage.h base64.h
outputImage.o: outputImage.cpp outputImage.h inputImage.h
inputImage.o: inputImage.cpp inputImage.h
util.o: util.cpp util.h httpClient.h
httpClient.o: httpClient.cpp httpClient.h
base64.o: base64.cpp base64.h
all: AlarmServer
debug:
make "BUILD=debug"
release:
make "BUILD=release"
clean:
-rm *.o AlarmServer
Symlink
+1
View File
@@ -0,0 +1 @@
Makefiles/Makefile
+22
View File
@@ -0,0 +1,22 @@
#
# Makefile.conf
#
LFLAGS += -lHttp
LFLAGS += -L$(ROOTPATH)/Libraries/Http/lib/$(ARCH)
CFLAGS += -I$(ROOTPATH)/Libraries/Http/include
LFLAGS += -lLogging
LFLAGS += -L$(ROOTPATH)/Libraries/Logging/lib/$(ARCH)
CFLAGS += -I$(ROOTPATH)/Libraries/Logging/include
LFLAGS += -lUtilities
LFLAGS += -L$(ROOTPATH)/Libraries/Utilities/lib/$(ARCH)
CFLAGS += -I$(ROOTPATH)/Libraries/Utilities/include
CFLAGS += -I$(ROOTPATH)/Libraries/asio/asio/include
CFLAGS += -I$(ROOTPATH)/Libraries/filesystem
LFLAGS += -lpthread -lcrypto -lcurl -ljpeg
CFLAGS += -I$(ROOTPATH) -I$(ROOTPATH)/Libraries
DEBUGDIR := .debug
+13
View File
@@ -0,0 +1,13 @@
#
# Makefile.target
#
AlarmServer.$(ARCH): $(OBJECTS) Application/AlarmServer.o.$(ARCH)
$(call build_target_arch,$@,$^)
AlarmServer:
$(call build_target,$@)
.DEFAULT_GOAL := AlarmServer
TARGETS += AlarmServer
Submodule
+1
Submodule Makefiles added at 5e113555eb
+1
View File
@@ -0,0 +1 @@
../Makefile
+113
View File
@@ -0,0 +1,113 @@
#include "Protocol.h"
#include "MailServer/Message.h"
#include <Logging.h>
#include <StringAlgorithm.h>
#include <sstream>
namespace Protocol {
Protocol::Protocol(const Util::Context& context) :
m_internalState(InternalState::None),
m_context(context)
{
}
Protocol::Result Protocol::OpenConnection(const std::string& address)
{
m_address = address;
m_internalState = InternalState::Connect;
std::stringstream ss;
ss << "Connection from " << address << std::endl;
Logging::Log(Logging::Severity::Info, ss.str());
return Answer(Protocol::State::Connected, "220 AlarmServer");
}
Protocol::Result Protocol::ProcessMessage(const std::string& message)
{
if (m_internalState == InternalState::Data)
{
AppendMessage(message);
if (StringAlgorithm::iends_with(message, ".\r\n"))
{
MailServer::Message msg(m_address, m_context, m_message);
m_internalState = InternalState::Helo;
return Answer(Protocol::State::Connected, "250 Ok");
}
return Answer(Protocol::State::Connected, "");
}
if (m_internalState == InternalState::Auth_login_user)
{
m_internalState = InternalState::Auth_login_pass;
return Answer(Protocol::State::Connected, "334 UGFzc3dvcmQ6");
}
if (m_internalState == InternalState::Auth_login_pass)
{
m_internalState = InternalState::Helo;
return Answer(Protocol::State::Connected, "235 2.7.0 Authentication successful");
}
if (StringAlgorithm::iequals(message, "quit\r\n"))
{
m_internalState = InternalState::Disconnect;
return Answer(Protocol::State::Disconnected, "221 Bye");
}
if (StringAlgorithm::istarts_with(message, "helo"))
{
m_internalState = InternalState::Helo;
return Answer(Protocol::State::Connected, "250-AlarmServer\r\n250 AUTH LOGIN");
}
if (StringAlgorithm::istarts_with(message, "ehlo"))
{
m_internalState = InternalState::Helo;
return Answer(Protocol::State::Connected, "250-AlarmServer\r\n250 AUTH LOGIN");
}
if (StringAlgorithm::istarts_with(message, "auth login"))
{
if (m_internalState != InternalState::Helo)
return Answer(Protocol::State::Connected, "503 Bad sequence of commands");
m_internalState = InternalState::Auth_login_user;
return Answer(Protocol::State::Connected, "334 VXNlcm5hbWU6");
}
if (StringAlgorithm::istarts_with(message, "mail from:"))
{
if (m_internalState != InternalState::Helo)
return Answer(Protocol::State::Connected, "503 Bad sequence of commands");
m_internalState = InternalState::Mail_from;
return Answer(Protocol::State::Connected, "250 Ok");
}
if (StringAlgorithm::istarts_with(message, "rcpt to:"))
{
if (m_internalState != InternalState::Mail_from)
return Answer(Protocol::State::Connected, "503 Bad sequence of commands");
m_internalState = InternalState::Rcpt_to;
return Answer(Protocol::State::Connected, "250 Ok");
}
if (StringAlgorithm::iequals(message, "data\r\n"))
{
if (m_internalState != InternalState::Rcpt_to)
return Answer(Protocol::State::Connected, "503 Bad sequence of commands");
m_internalState = InternalState::Data;
return Answer(Protocol::State::Connected, "354 Go ahead");
}
return Answer(Protocol::State::Connected, "502 Error");
}
Protocol::Result Protocol::Answer(Protocol::State::type state, std::string answer) const
{
return Result(state, answer);
}
void Protocol::AppendMessage(const std::string& message)
{
m_message.append(message);
m_message.append("\n");
}
} // namespace Protocol
+66
View File
@@ -0,0 +1,66 @@
#ifndef PROTOCOL_H
#define PROTOCOL_H
#include "Util/Util.h"
#include <string>
#include <utility>
namespace Protocol {
class Protocol
{
public:
class State
{
public:
enum type
{
Connected,
Disconnected
};
};
typedef std::pair<State::type, std::string> Result;
public:
explicit Protocol(const Util::Context& context);
Result OpenConnection(const std::string& address);
Result ProcessMessage(const std::string& message);
private:
class InternalState
{
public:
enum type
{
None,
Connect,
Helo,
Auth_login_user,
Auth_login_pass,
Mail_from,
Rcpt_to,
Data,
Mime_boundary,
Image_data,
Disconnect
};
};
private:
Result Answer(State::type state, std::string answer) const;
void AppendMessage(const std::string& message);
private:
InternalState::type m_internalState;
std::string m_address;
std::string m_message;
const Util::Context& m_context;
};
} // namespace Protocol
#endif // PROTOCOL_H
+136
View File
@@ -0,0 +1,136 @@
/*
base64.cpp and base64.h
Copyright (C) 2004-2008 René Nyffenegger
This source code is provided 'as-is', without any express or implied
warranty. In no event will the author be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this source code must not be misrepresented; you must not
claim that you wrote the original source code. If you use this source code
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original source code.
3. This notice may not be removed or altered from any source distribution.
René Nyffenegger rene.nyffenegger@adp-gmbh.ch
*/
#include "Base64.h"
namespace Util {
namespace Base64 {
static const std::string Base64Chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
static inline bool IsBase64(unsigned char c)
{
return (isalnum(c) || (c == '+') || (c == '/'));
}
std::string Encode(unsigned char const* bytes_to_encode, unsigned int in_len)
{
std::string ret;
int i = 0;
int j = 0;
unsigned char char_array_3[3];
unsigned char char_array_4[4];
while (in_len--)
{
char_array_3[i++] = *(bytes_to_encode++);
if (i == 3)
{
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for(i = 0; (i <4) ; i++)
ret += Base64Chars[char_array_4[i]];
i = 0;
}
}
if (i)
{
for(j = i; j < 3; j++)
char_array_3[j] = '\0';
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (j = 0; (j < i + 1); j++)
ret += Base64Chars[char_array_4[j]];
while((i++ < 3))
ret += '=';
}
return ret;
}
std::string Decode(std::string const& encoded_string)
{
int in_len = encoded_string.size();
int i = 0;
int j = 0;
int in_ = 0;
unsigned char char_array_4[4], char_array_3[3];
std::string ret;
while (in_len-- && ( encoded_string[in_] != '=') && IsBase64(encoded_string[in_]))
{
char_array_4[i++] = encoded_string[in_]; in_++;
if (i ==4)
{
for (i = 0; i <4; i++)
char_array_4[i] = Base64Chars.find(char_array_4[i]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (i = 0; (i < 3); i++)
ret += char_array_3[i];
i = 0;
}
}
if (i)
{
for (j = i; j <4; j++)
char_array_4[j] = 0;
for (j = 0; j <4; j++)
char_array_4[j] = Base64Chars.find(char_array_4[j]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (j = 0; (j < i - 1); j++)
ret += char_array_3[j];
}
return ret;
}
} // namespace Base64
} // namespace Util
+16
View File
@@ -0,0 +1,16 @@
#ifndef UTIL_BASE64_H
#define UTIL_BASE64_H
#include <string>
namespace Util {
namespace Base64 {
std::string Encode(unsigned char const* , unsigned int len);
std::string Decode(std::string const& s);
} // namespace Base64
} // namespace Util
#endif // UTIL_BASE64_H
+1
View File
@@ -0,0 +1 @@
../Makefile
+6 -1
View File
@@ -1,6 +1,9 @@
#include "Util.h"
#include <ctime>
#include <string>
#include "util.h"
namespace Util {
std::string getTimeString()
{
@@ -15,3 +18,5 @@ std::string getTimeString()
return std::string(buffer);
}
} // namespace Util
+22
View File
@@ -0,0 +1,22 @@
#ifndef UTIL_UTIL_H
#define UTIL_UTIL_H
#include <HttpClient.h>
#include <string>
namespace Util {
struct Context
{
public:
std::string path;
Http::HttpClient client;
std::string url;
};
std::string getTimeString();
} // namespace Util
#endif // UTIL_UTIL_H
-123
View File
@@ -1,123 +0,0 @@
/*
base64.cpp and base64.h
Copyright (C) 2004-2008 René Nyffenegger
This source code is provided 'as-is', without any express or implied
warranty. In no event will the author be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this source code must not be misrepresented; you must not
claim that you wrote the original source code. If you use this source code
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original source code.
3. This notice may not be removed or altered from any source distribution.
René Nyffenegger rene.nyffenegger@adp-gmbh.ch
*/
#include "base64.h"
static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
static inline bool is_base64(unsigned char c) {
return (isalnum(c) || (c == '+') || (c == '/'));
}
std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) {
std::string ret;
int i = 0;
int j = 0;
unsigned char char_array_3[3];
unsigned char char_array_4[4];
while (in_len--) {
char_array_3[i++] = *(bytes_to_encode++);
if (i == 3) {
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for(i = 0; (i <4) ; i++)
ret += base64_chars[char_array_4[i]];
i = 0;
}
}
if (i)
{
for(j = i; j < 3; j++)
char_array_3[j] = '\0';
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (j = 0; (j < i + 1); j++)
ret += base64_chars[char_array_4[j]];
while((i++ < 3))
ret += '=';
}
return ret;
}
std::string base64_decode(std::string const& encoded_string) {
int in_len = encoded_string.size();
int i = 0;
int j = 0;
int in_ = 0;
unsigned char char_array_4[4], char_array_3[3];
std::string ret;
while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
char_array_4[i++] = encoded_string[in_]; in_++;
if (i ==4) {
for (i = 0; i <4; i++)
char_array_4[i] = base64_chars.find(char_array_4[i]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (i = 0; (i < 3); i++)
ret += char_array_3[i];
i = 0;
}
}
if (i) {
for (j = i; j <4; j++)
char_array_4[j] = 0;
for (j = 0; j <4; j++)
char_array_4[j] = base64_chars.find(char_array_4[j]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
}
return ret;
}
-5
View File
@@ -1,5 +0,0 @@
#include <string>
std::string base64_encode(unsigned char const* , unsigned int len);
std::string base64_decode(std::string const& s);
-59
View File
@@ -1,59 +0,0 @@
#include <boost/asio/write.hpp>
#include <boost/bind.hpp>
#include "connection.h"
connection::connection(boost::asio::io_service& ioService, const context& context) :
m_ioService(ioService),
m_socket(ioService),
m_protocol(context)
{
}
boost::asio::ip::tcp::socket& connection::socket()
{
return m_socket;
}
void connection::start()
{
start_write(m_protocol.openConnection(m_socket.remote_endpoint().address().to_string()).second);
}
void connection::start_read()
{
m_socket.async_read_some(boost::asio::buffer(m_data), boost::bind(&connection::handle_read, this, _1, _2));
}
void connection::handle_read(const boost::system::error_code& ec, std::size_t length)
{
if (!ec)
{
protocol::result result = m_protocol.processMessage(std::string(m_data.begin(), m_data.begin() + length));
if (result.second.size() > 0)
start_write(result.second);
else
start_read();
if (result.first == protocol::state::disconnected)
m_socket.close();
}
}
void connection::start_write(const std::string& message)
{
std::copy(message.begin(), message.end(), m_data.data());
size_t length = message.size() + 1;
m_data[message.size()] = '\n';
boost::asio::async_write(m_socket, boost::asio::buffer(m_data, length), boost::bind(&connection::handle_write, this, _1));
}
void connection::handle_write(const boost::system::error_code& ec)
{
if (!ec)
start_read();
}
-37
View File
@@ -1,37 +0,0 @@
#ifndef CONNECTION_H
#define CONNECTION_H
#include <string>
#include <boost/noncopyable.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/signal_set.hpp>
#include <boost/array.hpp>
#include "protocol.h"
#include "util.h"
class connection : private boost::noncopyable
{
public:
connection(boost::asio::io_service& ioService, const context& context);
boost::asio::ip::tcp::socket& socket();
void start();
private:
void start_read();
void handle_read(const boost::system::error_code& ec, std::size_t length);
void start_write(const std::string& message);
void handle_write(const boost::system::error_code& ec);
boost::asio::io_service& m_ioService;
boost::asio::ip::tcp::socket m_socket;
boost::array<char, 1024> m_data;
protocol m_protocol;
};
#endif // CONNECTION_H
-57
View File
@@ -1,57 +0,0 @@
#include "httpClient.h"
httpClient::httpClient()
{
curl_global_init(CURL_GLOBAL_ALL);
m_userAgents.push_back("Opera/9.80 (X11; Linux i686; U; en) Presto/2.7.62 Version/11.00");
initialize_locks();
}
httpClient::~httpClient()
{
free_locks();
curl_global_cleanup();
}
std::string httpClient::GetUrlContents(const std::string& url) const
{
std::string buffer;
CURL* curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
curl_easy_setopt(curl, CURLOPT_USERAGENT, m_userAgents[rand() % m_userAgents.size()].c_str());
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
int code = 0;
curl_easy_perform(curl);
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code);
curl_easy_cleanup(curl);
if (code != 200)
{
std::stringstream error;
error << "Error encountered while retrieving " << url;
throw std::runtime_error(error.str());
}
return buffer;
}
size_t httpClient::WriteCallback(char* data, size_t size, size_t nmemb, std::string* writerData)
{
if (writerData == NULL)
return 0;
writerData->append(data, size * nmemb);
return size * nmemb;
}
-59
View File
@@ -1,59 +0,0 @@
#ifndef HTTPCLIENT_H
#define HTTPCLIENT_H
#include <string>
#include <vector>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <openssl/crypto.h>
#include <curl/curl.h>
static std::vector<boost::shared_ptr<boost::mutex> > g_mutexes;
static void lock_callback(int mode, int type, const char *file, int line)
{
if (mode & CRYPTO_LOCK)
g_mutexes[type]->lock();
else
g_mutexes[type]->unlock();
}
static unsigned long thread_id(void)
{
return (unsigned long)pthread_self();
}
static void initialize_locks(void)
{
g_mutexes.resize(CRYPTO_num_locks());
for (int i = 0; i < CRYPTO_num_locks(); ++i)
g_mutexes[i] = boost::shared_ptr<boost::mutex>(new boost::mutex());
CRYPTO_set_id_callback(thread_id);
CRYPTO_set_locking_callback(lock_callback);
}
static void free_locks(void)
{
CRYPTO_set_locking_callback(NULL);
}
class httpClient : boost::noncopyable
{
public:
httpClient();
~httpClient();
std::string GetUrlContents(const std::string& url) const;
private:
static size_t WriteCallback(char* data, size_t size, size_t nmemb, std::string* writerData);
private:
std::vector<std::string> m_userAgents;
};
#endif // HTTPCLIENT_H
-50
View File
@@ -1,50 +0,0 @@
#ifndef INPUTIMAGE_H
#define INPUTIMAGE_H
#include <string>
#include <vector>
#include <jpeglib.h>
class inputImage
{
public:
inputImage();
void setImageData(const std::string& data);
unsigned int width() const;
unsigned int height() const;
unsigned int strideX() const;
unsigned int strideY() const;
const std::vector<char>& data() const;
private:
struct source_mgr
{
struct jpeg_source_mgr pub;
const JOCTET *data;
size_t len;
};
typedef source_mgr* source_mgr_ptr;
private:
static void init_source(j_decompress_ptr pCinfo);
static boolean fill_input_buffer(j_decompress_ptr pCinfo);
static void skip_input_data(j_decompress_ptr pCinfo, long numBytes);
static void term_source(j_decompress_ptr pCinfo);
void setSourceMgr(j_decompress_ptr pCinfo, const char* pData, size_t len) const;
void decompressImage(const char* pData, size_t len);
private:
unsigned int m_width;
unsigned int m_height;
unsigned int m_strideX;
unsigned int m_strideY;
std::vector<char> m_data;
};
#endif // INPUTIMAGE_H
-199
View File
@@ -1,199 +0,0 @@
#include <sstream>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
#include "outputImage.h"
#include "base64.h"
#include "message.h"
message::message(const std::string& address, const context& context, const std::string& message) :
m_address(address),
m_context(context),
m_mimeBoundary("-_-InvalidBoundary-_-"),
m_contentEncoding("none"),
m_currentImage(0)
{
processMessage(message);
}
std::string Decode(const std::string& data)
{
std::string result;
if (boost::istarts_with(data, "=?utf-8?"))
result = base64_decode(std::string(data.begin() + 10, data.begin() + data.find_last_of('?')));
else
result = base64_decode(data);
return result;
}
void message::processMessage(const std::string& message)
{
try
{
std::cout << "message::processMessage enter" << std::endl;
message::state::type state = message::state::header;
std::string line;
std::istringstream stream(message);
while (std::getline(stream, line, '\r'))
{
boost::erase_all(line, "\n");
switch (state)
{
case state::header:
state = processHeaderLine(line);
break;
case state::data:
state = processDataLine(line);
break;
case state::mimeBoundary:
state = processMimeBoundary(line);
break;
case state::image:
state = processImage(line);
break;
}
}
if (boost::algorithm::contains(m_contentEncoding, "base64"))
{
std::string decoded = Decode(m_subject);
if (decoded.size() > 0)
m_subject = decoded;
}
outputImage image(m_images);
boost::filesystem::path path(m_context.path);
path = boost::filesystem::canonical(path);
path /= m_address;
if (!boost::filesystem::exists(path))
boost::filesystem::create_directory(path);
std::string fileName(getTimeString());
fileName.append(".jpg");
path /= fileName;
image.save(path.string());
if (!m_context.url.empty())
{
std::stringstream url;
url << m_context.url << "?ip=" << m_address << "&file=" << fileName;
m_context.client.GetUrlContents(url.str());
}
}
catch (std::exception& e)
{
std::cout << "Exception: " << e.what() << std::endl;
std::cerr << "Exception: " << e.what() << std::endl;
}
std::cout << "message::processMessage exit" << std::endl;
}
message::state::type message::processHeaderLine(const std::string& line)
{
if (line.empty())
return message::state::data;
if (boost::istarts_with(line, "from:"))
{
m_sender = std::string(line.begin() + line.find_first_of(' ') + 1, line.end());
return message::state::header;
}
if (boost::istarts_with(line, "to:"))
{
m_receiver = std::string(line.begin() + line.find_first_of(' ') + 1, line.end());
return message::state::header;
}
if (boost::istarts_with(line, "subject:"))
{
m_subject = std::string(line.begin() + line.find_first_of(' ') + 1, line.end());
return message::state::header;
}
if (boost::istarts_with(line, "date"))
{
m_date = std::string(line.begin() + line.find_first_of(' ') + 1, line.end());
return message::state::header;
}
if (boost::istarts_with(line, "content-type:"))
{
m_contentType = std::string(line.begin() + line.find_first_of(' ') + 1, line.end());
return message::state::header;
}
if (boost::istarts_with(line, "boundary") || boost::istarts_with(line, "\tboundary") || boost::istarts_with(line, " boundary"))
{
m_mimeBoundary = std::string("--").append(std::string(line.begin() + line.find_first_of('"') + 1, line.begin() + line.find_last_of('"')));
return message::state::header;
}
if (boost::istarts_with(line, "content-transfer-encoding:"))
{
m_contentEncoding = std::string(line.begin() + line.find_first_of(' ') + 1, line.end());
return message::state::header;
}
return message::state::header;
}
message::state::type message::processDataLine(const std::string& line)
{
if (boost::istarts_with(line, m_mimeBoundary))
{
m_contentType = "";
return message::state::mimeBoundary;
}
return message::state::data;
}
message::state::type message::processMimeBoundary(const std::string& line)
{
if (line.empty())
{
if (boost::istarts_with(m_contentType, "image/jpeg") || boost::istarts_with(m_contentType, "image/jpg"))
{
m_mimeImages.push_back(mimeImage(m_imageName));
m_imageName = "";
return message::state::image;
}
return message::state::data;
}
if (boost::istarts_with(line, "content-type:"))
{
m_contentType = std::string(line.begin() + line.find_first_of(' ') + 1, line.end());
return message::state::mimeBoundary;
}
if (boost::istarts_with(line, "name") || boost::istarts_with(line, "\tname"))
{
m_imageName = "image.jpg";
//m_imageName = Decode(std::string(line.begin() + line.find_first_of('"') + 1, line.begin() + line.find_last_of('"')));
return message::state::mimeBoundary;
}
if (boost::istarts_with(line, "content-transfer-encoding:"))
{
m_contentEncoding = std::string(line.begin() + line.find_first_of(' ') + 1, line.end());
return message::state::mimeBoundary;
}
return message::state::mimeBoundary;
}
message::state::type message::processImage(const std::string& line)
{
if (boost::istarts_with(line, m_mimeBoundary))
{
m_images.push_back(m_mimeImages[m_currentImage].decodeImageData());
++m_currentImage;
m_contentType = "";
return message::state::mimeBoundary;
}
m_mimeImages[m_currentImage].appendData(line);
return message::state::image;
}
-57
View File
@@ -1,57 +0,0 @@
#ifndef MESSAGE_H
#define MESSAGE_H
#include <string>
#include <vector>
#include "mimeImage.h"
#include "inputImage.h"
#include "util.h"
class message
{
public:
message(const std::string& address, const context& context, const std::string& message);
private:
class state
{
public:
enum type
{
header,
data,
mimeBoundary,
image
};
};
private:
void processMessage(const std::string& message);
state::type processHeaderLine(const std::string& line);
state::type processDataLine(const std::string& line);
state::type processMimeBoundary(const std::string& line);
state::type processImage(const std::string& line);
private:
std::string m_address;
const context& m_context;
std::string m_sender;
std::string m_receiver;
std::string m_subject;
std::string m_date;
std::string m_mimeBoundary;
std::string m_contentType;
std::string m_contentEncoding;
size_t m_currentImage;
std::string m_imageName;
std::vector<mimeImage> m_mimeImages;
std::vector<inputImage> m_images;
};
#endif // MESSAGE_H
-30
View File
@@ -1,30 +0,0 @@
#include <fstream>
#include <boost/algorithm/string.hpp>
#include "base64.h"
#include "mimeImage.h"
mimeImage::mimeImage()
{
}
mimeImage::mimeImage(const std::string& name) :
m_name(name)
{
}
void mimeImage::appendData(const std::string& data)
{
if (data.empty())
return;
m_imageData.append(data);
}
const inputImage& mimeImage::decodeImageData()
{
boost::erase_all(m_imageData, "\r");
m_inputImage.setImageData(base64_decode(m_imageData));
return m_inputImage;
}
-23
View File
@@ -1,23 +0,0 @@
#ifndef MIMEIMAGE_H
#define MIMEIMAGE_H
#include "inputImage.h"
class mimeImage
{
public:
mimeImage();
mimeImage(const std::string& name);
void appendData(const std::string& data);
const inputImage& decodeImageData();
private:
std::string m_name;
std::string m_imageData;
inputImage m_inputImage;
};
#endif // MIMEIMAGE_H
-112
View File
@@ -1,112 +0,0 @@
#include <iostream>
#include <boost/algorithm/string/predicate.hpp>
#include "message.h"
#include "protocol.h"
protocol::protocol(const context& context) :
m_internalState(internalState::none),
m_context(context)
{
}
protocol::result protocol::openConnection(const std::string& address)
{
m_address = address;
m_internalState = internalState::connect;
std::cout << "Connection from " << address << std::endl;
return answer(protocol::state::connected, "220 AlarmServer");
}
protocol::result protocol::processMessage(const std::string& message)
{
if (m_internalState == internalState::data)
{
appendMessage(message);
if (boost::iends_with(message, ".\r\n"))
{
std::cout << "-> " << " . " << std::endl;
::message msg(m_address, m_context, m_message);
std::cout << "-> " << " . " << std::endl;
m_internalState = internalState::helo;
std::cout << "-> " << " . " << std::endl;
return answer(protocol::state::connected, "250 Ok");
}
return answer(protocol::state::connected, "");
}
std::cout << "-> " << message << std::endl;
if (m_internalState == internalState::auth_login_user)
{
m_internalState = internalState::auth_login_pass;
return answer(protocol::state::connected, "334 UGFzc3dvcmQ6");
}
if (m_internalState == internalState::auth_login_pass)
{
m_internalState = internalState::helo;
return answer(protocol::state::connected, "235 2.7.0 Authentication successful");
}
if (boost::iequals(message, "quit\r\n"))
{
m_internalState = internalState::disconnect;
return answer(protocol::state::disconnected, "221 Bye");
}
if (boost::istarts_with(message, "helo"))
{
m_internalState = internalState::helo;
return answer(protocol::state::connected, "250-AlarmServer\r\n250 AUTH LOGIN");
}
if (boost::istarts_with(message, "ehlo"))
{
m_internalState = internalState::helo;
return answer(protocol::state::connected, "250-AlarmServer\r\n250 AUTH LOGIN");
}
if (boost::istarts_with(message, "auth login"))
{
if (m_internalState != internalState::helo)
return answer(protocol::state::connected, "503 Bad sequence of commands");
m_internalState = internalState::auth_login_user;
return answer(protocol::state::connected, "334 VXNlcm5hbWU6");
}
if (boost::istarts_with(message, "mail from:"))
{
if (m_internalState != internalState::helo)
return answer(protocol::state::connected, "503 Bad sequence of commands");
m_internalState = internalState::mail_from;
return answer(protocol::state::connected, "250 Ok");
}
if (boost::istarts_with(message, "rcpt to:"))
{
if (m_internalState != internalState::mail_from)
return answer(protocol::state::connected, "503 Bad sequence of commands");
m_internalState = internalState::rcpt_to;
return answer(protocol::state::connected, "250 Ok");
}
if (boost::iequals(message, "data\r\n"))
{
if (m_internalState != internalState::rcpt_to)
return answer(protocol::state::connected, "503 Bad sequence of commands");
m_internalState = internalState::data;
return answer(protocol::state::connected, "354 Go ahead");
}
return answer(protocol::state::connected, "502 Error");
}
protocol::result protocol::answer(protocol::state::type state, std::string answer) const
{
if (answer.size() > 0)
std::cout << "<- " << answer << std::endl;
return result(state, answer);
}
void protocol::appendMessage(const std::string& message)
{
m_message.append(message);
m_message.append("\n");
}
-63
View File
@@ -1,63 +0,0 @@
#ifndef PROTOCOL_H
#define PROTOCOL_H
#include <string>
#include <utility>
#include "util.h"
class protocol
{
public:
class state
{
public:
enum type
{
connected,
disconnected
};
};
typedef std::pair<state::type, std::string> result;
public:
explicit protocol(const context& context);
result openConnection(const std::string& address);
result processMessage(const std::string& message);
private:
class internalState
{
public:
enum type
{
none,
connect,
helo,
auth_login_user,
auth_login_pass,
mail_from,
rcpt_to,
data,
mime_oundary,
image_data,
disconnect
};
};
private:
result answer(state::type state, std::string answer) const;
void appendMessage(const std::string& message);
private:
internalState::type m_internalState;
std::string m_address;
std::string m_message;
const context& m_context;
};
#endif // PROTOCOL_H
-75
View File
@@ -1,75 +0,0 @@
#include <boost/bind.hpp>
#include <boost/make_shared.hpp>
#include <iostream>
#include <sys/wait.h>
#include "server.h"
server::server(boost::asio::io_service& ioService, unsigned short port, const std::string& path, const std::string& url) :
m_ioService(ioService),
m_signal(ioService, SIGCHLD),
m_acceptor(ioService, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)),
m_socket(ioService)
{
m_context.path = path;
m_context.url = url;
start_signal_wait();
start_accept();
}
void server::start_signal_wait()
{
m_signal.async_wait(boost::bind(&server::handle_signal_wait, this));
}
void server::handle_signal_wait()
{
// Only the parent process should check for this signal. We can determine
// whether we are in the parent by checking if the acceptor is still open.
if (m_acceptor.is_open())
{
// Reap completed child processes so that we don't end up with zombies.
int status = 0;
while (waitpid(-1, &status, WNOHANG) > 0) {}
start_signal_wait();
}
}
void server::start_accept()
{
m_connection.reset(new connection(m_ioService, m_context));
m_acceptor.async_accept(m_connection->socket(), boost::bind(&server::handle_accept, this, _1));
}
void server::handle_accept(const boost::system::error_code& ec)
{
if (!ec)
{
m_ioService.notify_fork(boost::asio::io_service::fork_prepare);
if (fork() == 0)
{
m_ioService.notify_fork(boost::asio::io_service::fork_child);
m_acceptor.close();
m_signal.cancel();
m_connection->start();
}
else
{
m_ioService.notify_fork(boost::asio::io_service::fork_parent);
m_connection.reset();
m_socket.close();
start_accept();
}
}
else
{
std::cout << "Accept error: " << ec.message() << std::endl;
start_accept();
}
}
-34
View File
@@ -1,34 +0,0 @@
#ifndef SERVER_H
#define SERVER_H
#include <string>
#include <boost/asio/io_service.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/signal_set.hpp>
#include <boost/shared_ptr.hpp>
#include "connection.h"
#include "util.h"
class server
{
public:
server(boost::asio::io_service& ioService, unsigned short port, const std::string& path, const std::string& url);
private:
void start_signal_wait();
void handle_signal_wait();
void start_accept();
void handle_accept(const boost::system::error_code& ec);
boost::asio::io_service& m_ioService;
boost::asio::signal_set m_signal;
boost::asio::ip::tcp::acceptor m_acceptor;
boost::asio::ip::tcp::socket m_socket;
boost::shared_ptr<connection> m_connection;
context m_context;
};
#endif // SERVER_H
-18
View File
@@ -1,18 +0,0 @@
#ifndef UTIL_H
#define UTIL_H
#include <string>
#include "httpClient.h"
struct context
{
public:
std::string path;
httpClient client;
std::string url;
};
std::string getTimeString();
#endif // UTIL_H