Move to new Build System
This commit is contained in:
+13
-2
@@ -1,3 +1,14 @@
|
||||
*.o
|
||||
*.o.*
|
||||
*.d.*
|
||||
*.a.*
|
||||
.*.swp
|
||||
AlarmServer
|
||||
.AppleDouble
|
||||
.debug
|
||||
.gdbinit*
|
||||
gdb*
|
||||
core-*
|
||||
*-core
|
||||
core.*
|
||||
*.core
|
||||
AlarmServer*
|
||||
!AlarmServer.cc
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
[submodule "Makefiles"]
|
||||
path = Makefiles
|
||||
url = https://gogs.dierkse.nl/JDierkse/Makefiles.git
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../Makefile
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../Makefile
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../Libraries/Http
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../Libraries/Logging
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../Libraries/Utilities
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../Libraries/asio
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../Libraries/filesystem
|
||||
@@ -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
|
||||
@@ -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
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../Makefile
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
Symlink
+1
@@ -0,0 +1 @@
|
||||
../Makefile
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../Makefile
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
#include <string>
|
||||
|
||||
std::string base64_encode(unsigned char const* , unsigned int len);
|
||||
std::string base64_decode(std::string const& s);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user